aboutsummaryrefslogtreecommitdiff
path: root/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.cpp')
-rw-r--r--src/main.cpp198
1 files changed, 101 insertions, 97 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 263421aea..05442057e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -233,7 +233,7 @@ namespace {
int nPeersWithValidatedDownloads = 0;
/** Relay map, protected by cs_main. */
- typedef std::map<uint256, std::shared_ptr<const CTransaction>> MapRelay;
+ typedef std::map<uint256, CTransactionRef> MapRelay;
MapRelay mapRelay;
/** Expiration-time ordered list of (expire time, relay map entry) pairs, protected by cs_main). */
std::deque<std::pair<int64_t, MapRelay::iterator>> vRelayExpiration;
@@ -529,12 +529,11 @@ void MaybeSetPeerAsAnnouncingHeaderAndIDs(const CNodeState* nodestate, CNode* pf
if (lNodesAnnouncingHeaderAndIDs.size() >= 3) {
// As per BIP152, we only get 3 of our peers to announce
// blocks using compact encodings.
- bool found = connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
+ connman.ForNode(lNodesAnnouncingHeaderAndIDs.front(), [&connman, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion](CNode* pnodeStop){
connman.PushMessage(pnodeStop, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
return true;
});
- if(found)
- lNodesAnnouncingHeaderAndIDs.pop_front();
+ lNodesAnnouncingHeaderAndIDs.pop_front();
}
fAnnounceUsingCMPCTBLOCK = true;
connman.PushMessage(pfrom, NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion);
@@ -1639,7 +1638,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
LOCK(cs_main);
- std::shared_ptr<const CTransaction> ptx = mempool.get(hash);
+ CTransactionRef ptx = mempool.get(hash);
if (ptx)
{
txOut = *ptx;
@@ -1682,9 +1681,9 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::P
if (pindexSlow) {
CBlock block;
if (ReadBlockFromDisk(block, pindexSlow, consensusParams)) {
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- if (tx.GetHash() == hash) {
- txOut = tx;
+ for (const auto& tx : block.vtx) {
+ if (tx->GetHash() == hash) {
+ txOut = *tx;
hashBlock = pindexSlow->GetBlockHash();
return true;
}
@@ -2223,7 +2222,7 @@ bool DisconnectBlock(const CBlock& block, CValidationState& state, const CBlockI
// undo transactions in reverse order
for (int i = block.vtx.size() - 1; i >= 0; i--) {
- const CTransaction &tx = block.vtx[i];
+ const CTransaction &tx = *(block.vtx[i]);
uint256 hash = tx.GetHash();
// Check that all outputs are available and match the outputs in the block itself
@@ -2417,8 +2416,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || !(pindexBIP34height->GetBlockHash() == chainparams.GetConsensus().BIP34Hash));
if (fEnforceBIP30) {
- BOOST_FOREACH(const CTransaction& tx, block.vtx) {
- const CCoins* coins = view.AccessCoins(tx.GetHash());
+ for (const auto& tx : block.vtx) {
+ const CCoins* coins = view.AccessCoins(tx->GetHash());
if (coins && !coins->IsPruned())
return state.DoS(100, error("ConnectBlock(): tried to overwrite transaction"),
REJECT_INVALID, "bad-txns-BIP30");
@@ -2461,7 +2460,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
- std::vector<uint256> vOrphanErase;
std::vector<int> prevheights;
CAmount nFees = 0;
int nInputs = 0;
@@ -2474,7 +2472,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
txdata.reserve(block.vtx.size()); // Required so that pointers to individual PrecomputedTransactionData don't get invalidated
for (unsigned int i = 0; i < block.vtx.size(); i++)
{
- const CTransaction &tx = block.vtx[i];
+ const CTransaction &tx = *(block.vtx[i]);
nInputs += tx.vin.size();
@@ -2492,17 +2490,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
prevheights[j] = view.AccessCoins(tx.vin[j].prevout.hash)->nHeight;
}
- // Which orphan pool entries must we evict?
- for (size_t j = 0; j < tx.vin.size(); j++) {
- auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
- if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
- for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
- const CTransaction& orphanTx = (*mi)->second.tx;
- const uint256& orphanHash = orphanTx.GetHash();
- vOrphanErase.push_back(orphanHash);
- }
- }
-
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) {
return state.DoS(100, error("%s: contains a non-BIP68-final transaction", __func__),
REJECT_INVALID, "bad-txns-nonfinal");
@@ -2544,10 +2531,10 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), 0.001 * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * 0.000001);
CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus());
- if (block.vtx[0].GetValueOut() > blockReward)
+ if (block.vtx[0]->GetValueOut() > blockReward)
return state.DoS(100,
error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)",
- block.vtx[0].GetValueOut(), blockReward),
+ block.vtx[0]->GetValueOut(), blockReward),
REJECT_INVALID, "bad-cb-amount");
if (!control.Wait())
@@ -2590,16 +2577,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
GetMainSignals().UpdatedTransaction(hashPrevBestCoinBase);
- hashPrevBestCoinBase = block.vtx[0].GetHash();
+ hashPrevBestCoinBase = block.vtx[0]->GetHash();
- // Erase orphan transactions include or precluded by this block
- if (vOrphanErase.size()) {
- int nErased = 0;
- BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) {
- nErased += EraseOrphanTx(orphanHash);
- }
- LogPrint("mempool", "Erased %d orphan tx included or conflicted by block\n", nErased);
- }
int64_t nTime6 = GetTimeMicros(); nTimeCallbacks += nTime6 - nTime5;
LogPrint("bench", " - Callbacks: %.2fms [%.2fs]\n", 0.001 * (nTime6 - nTime5), nTimeCallbacks * 0.000001);
@@ -2807,7 +2786,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
if (!fBare) {
// Resurrect mempool transactions from the disconnected block.
std::vector<uint256> vHashUpdate;
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
+ for (const auto& it : block.vtx) {
+ const CTransaction& tx = *it;
// ignore validation errors in resurrected transactions
CValidationState stateDummy;
if (tx.IsCoinBase() || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, true)) {
@@ -2828,8 +2808,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
UpdateTip(pindexDelete->pprev, chainparams);
// Let wallets know transactions went from 1-confirmed to
// 0-confirmed or conflicted:
- BOOST_FOREACH(const CTransaction &tx, block.vtx) {
- GetMainSignals().SyncTransaction(tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
+ for (const auto& tx : block.vtx) {
+ GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
return true;
}
@@ -2844,7 +2824,7 @@ static int64_t nTimePostConnect = 0;
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
* corresponding to pindexNew, to bypass loading it again from disk.
*/
-bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<std::shared_ptr<const CTransaction>> &txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>> &txChanged)
+bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const CBlock* pblock, std::vector<CTransactionRef> &txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>> &txChanged)
{
assert(pindexNew->pprev == chainActive.Tip());
// Read block from disk.
@@ -2884,7 +2864,7 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
// Update chainActive & related variables.
UpdateTip(pindexNew, chainparams);
- for(unsigned int i=0; i < pblock->vtx.size(); i++)
+ for (unsigned int i=0; i < pblock->vtx.size(); i++)
txChanged.emplace_back(pblock->vtx[i], pindexNew, i);
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
@@ -2967,7 +2947,7 @@ static void PruneBlockIndexCandidates() {
* Try to make some progress towards making pindexMostWork the active block.
* pblock is either NULL or a pointer to a CBlock corresponding to pindexMostWork.
*/
-static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<std::shared_ptr<const CTransaction>>& txConflicted, std::vector<std::tuple<CTransaction,CBlockIndex*,int>>& txChanged)
+static bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const CBlock* pblock, bool& fInvalidFound, std::vector<CTransactionRef>& txConflicted, std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>>& txChanged)
{
AssertLockHeld(cs_main);
const CBlockIndex *pindexOldTip = chainActive.Tip();
@@ -3068,7 +3048,7 @@ static void NotifyHeaderTip() {
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, const CBlock *pblock) {
CBlockIndex *pindexMostWork = NULL;
CBlockIndex *pindexNewTip = NULL;
- std::vector<std::tuple<CTransaction,CBlockIndex*,int>> txChanged;
+ std::vector<std::tuple<CTransactionRef,CBlockIndex*,int>> txChanged;
if (pblock)
txChanged.reserve(pblock->vtx.size());
do {
@@ -3078,7 +3058,7 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
break;
const CBlockIndex *pindexFork;
- std::vector<std::shared_ptr<const CTransaction>> txConflicted;
+ std::vector<CTransactionRef> txConflicted;
bool fInitialDownload;
{
LOCK(cs_main);
@@ -3109,13 +3089,13 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
// throw all transactions though the signal-interface
// while _not_ holding the cs_main lock
- for(std::shared_ptr<const CTransaction> tx : txConflicted)
+ for (const auto& tx : txConflicted)
{
GetMainSignals().SyncTransaction(*tx, pindexNewTip, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
}
// ... and about transactions that got confirmed:
- for(unsigned int i = 0; i < txChanged.size(); i++)
- GetMainSignals().SyncTransaction(std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i]));
+ for (unsigned int i = 0; i < txChanged.size(); i++)
+ GetMainSignals().SyncTransaction(*std::get<0>(txChanged[i]), std::get<1>(txChanged[i]), std::get<2>(txChanged[i]));
// Notify external listeners about the new tip.
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
@@ -3201,6 +3181,7 @@ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, C
InvalidChainFound(pindex);
mempool.removeForReorg(pcoinsTip, chainActive.Tip()->nHeight + 1, STANDARD_LOCKTIME_VERIFY_FLAGS);
+ uiInterface.NotifyBlockTip(IsInitialBlockDownload(), pindex->pprev);
return true;
}
@@ -3454,22 +3435,22 @@ bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::P
return state.DoS(100, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed");
// First transaction must be coinbase, the rest must not be
- if (block.vtx.empty() || !block.vtx[0].IsCoinBase())
+ if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase");
for (unsigned int i = 1; i < block.vtx.size(); i++)
- if (block.vtx[i].IsCoinBase())
+ if (block.vtx[i]->IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple", false, "more than one coinbase");
// Check transactions
for (const auto& tx : block.vtx)
- if (!CheckTransaction(tx, state, false))
+ if (!CheckTransaction(*tx, state, false))
return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(),
- strprintf("Transaction check failed (tx hash %s) %s", tx.GetHash().ToString(), state.GetDebugMessage()));
+ strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));
unsigned int nSigOps = 0;
for (const auto& tx : block.vtx)
{
- nSigOps += GetLegacySigOpCount(tx);
+ nSigOps += GetLegacySigOpCount(*tx);
}
if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false, "out-of-bounds SigOpCount");
@@ -3505,8 +3486,8 @@ bool IsWitnessEnabled(const CBlockIndex* pindexPrev, const Consensus::Params& pa
static int GetWitnessCommitmentIndex(const CBlock& block)
{
int commitpos = -1;
- for (size_t o = 0; o < block.vtx[0].vout.size(); o++) {
- if (block.vtx[0].vout[o].scriptPubKey.size() >= 38 && block.vtx[0].vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0].vout[o].scriptPubKey[1] == 0x24 && block.vtx[0].vout[o].scriptPubKey[2] == 0xaa && block.vtx[0].vout[o].scriptPubKey[3] == 0x21 && block.vtx[0].vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0].vout[o].scriptPubKey[5] == 0xed) {
+ for (size_t o = 0; o < block.vtx[0]->vout.size(); o++) {
+ if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN && block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa && block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 && block.vtx[0]->vout[o].scriptPubKey[5] == 0xed) {
commitpos = o;
}
}
@@ -3517,10 +3498,12 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
{
int commitpos = GetWitnessCommitmentIndex(block);
static const std::vector<unsigned char> nonce(32, 0x00);
- if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0].wit.IsEmpty()) {
- block.vtx[0].wit.vtxinwit.resize(1);
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.resize(1);
- block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0] = nonce;
+ if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && block.vtx[0]->wit.IsEmpty()) {
+ CMutableTransaction tx(*block.vtx[0]);
+ tx.wit.vtxinwit.resize(1);
+ tx.wit.vtxinwit[0].scriptWitness.stack.resize(1);
+ tx.wit.vtxinwit[0].scriptWitness.stack[0] = nonce;
+ block.vtx[0] = MakeTransactionRef(std::move(tx));
}
}
@@ -3530,7 +3513,7 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
int commitpos = GetWitnessCommitmentIndex(block);
bool fHaveWitness = false;
for (size_t t = 1; t < block.vtx.size(); t++) {
- if (!block.vtx[t].wit.IsNull()) {
+ if (!block.vtx[t]->wit.IsNull()) {
fHaveWitness = true;
break;
}
@@ -3551,8 +3534,8 @@ std::vector<unsigned char> GenerateCoinbaseCommitment(CBlock& block, const CBloc
out.scriptPubKey[5] = 0xed;
memcpy(&out.scriptPubKey[6], witnessroot.begin(), 32);
commitment = std::vector<unsigned char>(out.scriptPubKey.begin(), out.scriptPubKey.end());
- const_cast<std::vector<CTxOut>*>(&block.vtx[0].vout)->push_back(out);
- block.vtx[0].UpdateHash();
+ const_cast<std::vector<CTxOut>*>(&block.vtx[0]->vout)->push_back(out);
+ block.vtx[0]->UpdateHash();
}
}
UpdateUncommittedBlockStructures(block, pindexPrev, consensusParams);
@@ -3601,7 +3584,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
// Check that all transactions are finalized
for (const auto& tx : block.vtx) {
- if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) {
+ if (!IsFinalTx(*tx, nHeight, nLockTimeCutoff)) {
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, "non-final transaction");
}
}
@@ -3610,8 +3593,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
if (nHeight >= consensusParams.BIP34Height)
{
CScript expect = CScript() << nHeight;
- if (block.vtx[0].vin[0].scriptSig.size() < expect.size() ||
- !std::equal(expect.begin(), expect.end(), block.vtx[0].vin[0].scriptSig.begin())) {
+ if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
+ !std::equal(expect.begin(), expect.end(), block.vtx[0]->vin[0].scriptSig.begin())) {
return state.DoS(100, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase");
}
}
@@ -3633,11 +3616,11 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
// The malleation check is ignored; as the transaction tree itself
// already does not permit it, it is impossible to trigger in the
// witness tree.
- if (block.vtx[0].wit.vtxinwit.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
+ if (block.vtx[0]->wit.vtxinwit.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack.size() != 1 || block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0].size() != 32) {
return state.DoS(100, false, REJECT_INVALID, "bad-witness-nonce-size", true, strprintf("%s : invalid witness nonce size", __func__));
}
- CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0].wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
- if (memcmp(hashWitness.begin(), &block.vtx[0].vout[commitpos].scriptPubKey[6], 32)) {
+ CHash256().Write(hashWitness.begin(), 32).Write(&block.vtx[0]->wit.vtxinwit[0].scriptWitness.stack[0][0], 32).Finalize(hashWitness.begin());
+ if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) {
return state.DoS(100, false, REJECT_INVALID, "bad-witness-merkle-match", true, strprintf("%s : witness merkle commitment mismatch", __func__));
}
fHaveWitness = true;
@@ -3647,7 +3630,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co
// No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam
if (!fHaveWitness) {
for (size_t i = 0; i < block.vtx.size(); i++) {
- if (!block.vtx[i].wit.IsNull()) {
+ if (!block.vtx[i]->wit.IsNull()) {
return state.DoS(100, false, REJECT_INVALID, "unexpected-witness", true, strprintf("%s : unexpected witness data found", __func__));
}
}
@@ -4744,6 +4727,34 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanI
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
}
+void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock) {
+ if (nPosInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK)
+ return;
+
+ LOCK(cs_main);
+
+ std::vector<uint256> vOrphanErase;
+ // Which orphan pool entries must we evict?
+ for (size_t j = 0; j < tx.vin.size(); j++) {
+ auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
+ if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
+ for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
+ const CTransaction& orphanTx = (*mi)->second.tx;
+ const uint256& orphanHash = orphanTx.GetHash();
+ vOrphanErase.push_back(orphanHash);
+ }
+ }
+
+ // Erase orphan transactions include or precluded by this block
+ if (vOrphanErase.size()) {
+ int nErased = 0;
+ BOOST_FOREACH(uint256 &orphanHash, vOrphanErase) {
+ nErased += EraseOrphanTx(orphanHash);
+ }
+ LogPrint("mempool", "Erased %d orphan tx included or conflicted by block\n", nErased);
+ }
+}
+
void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) {
const int nNewHeight = pindexNew->nHeight;
connman->SetBestHeight(nNewHeight);
@@ -4844,26 +4855,35 @@ static void RelayTransaction(const CTransaction& tx, CConnman& connman)
static void RelayAddress(const CAddress& addr, bool fReachable, CConnman& connman)
{
- int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
+ unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
// Relay to a limited number of other nodes
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the addrKnowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- std::multimap<uint64_t, CNode*> mapMix;
const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
FastRandomContext insecure_rand;
- auto sortfunc = [&mapMix, &hasher](CNode* pnode) {
+ std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
+ assert(nRelayNodes <= best.size());
+
+ auto sortfunc = [&best, &hasher, nRelayNodes](CNode* pnode) {
if (pnode->nVersion >= CADDR_TIME_VERSION) {
uint64_t hashKey = CSipHasher(hasher).Write(pnode->id).Finalize();
- mapMix.emplace(hashKey, pnode);
+ for (unsigned int i = 0; i < nRelayNodes; i++) {
+ if (hashKey > best[i].first) {
+ std::copy(best.begin() + i, best.begin() + nRelayNodes - 1, best.begin() + i + 1);
+ best[i] = std::make_pair(hashKey, pnode);
+ break;
+ }
+ }
}
};
- auto pushfunc = [&addr, &mapMix, &nRelayNodes, &insecure_rand] {
- for (auto mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
- mi->second->PushAddress(addr, insecure_rand);
+ auto pushfunc = [&addr, &best, nRelayNodes, &insecure_rand] {
+ for (unsigned int i = 0; i < nRelayNodes && best[i].first != 0; i++) {
+ best[i].second->PushAddress(addr, insecure_rand);
+ }
};
connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
@@ -4953,7 +4973,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// however we MUST always provide at least what the remote peer needs
typedef std::pair<unsigned int, uint256> PairType;
BOOST_FOREACH(PairType& pair, merkleBlock.vMatchedTxn)
- connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, block.vtx[pair.first]);
+ connman.PushMessageWithFlag(pfrom, SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::TX, *block.vtx[pair.first]);
}
// else
// no response
@@ -5367,28 +5387,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom->GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
- // First request the headers preceding the announced block. In the normal fully-synced
- // case where a new block is announced that succeeds the current tip (no reorganization),
- // there are no such headers.
- // Secondly, and only when we are close to being synced, we request the announced block directly,
- // to avoid an extra round-trip. Note that we must *first* ask for the headers, so by the
- // time the block arrives, the header chain leading up to it is already validated. Not
- // doing this will result in the received block being rejected as an orphan in case it is
- // not a direct successor.
+ // We used to request the full block here, but since headers-announcements are now the
+ // primary method of announcement on the network, and since, in the case that a node
+ // fell back to inv we probably have a reorg which we should get the headers for first,
+ // we now only provide a getheaders response here. When we receive the headers, we will
+ // then ask for the blocks we need.
connman.PushMessage(pfrom, NetMsgType::GETHEADERS, chainActive.GetLocator(pindexBestHeader), inv.hash);
- CNodeState *nodestate = State(pfrom->GetId());
- if (CanDirectFetch(chainparams.GetConsensus()) &&
- nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
- (!IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus()) || State(pfrom->GetId())->fHaveWitness)) {
- inv.type |= nFetchFlags;
- if (nodestate->fSupportsDesiredCmpctVersion)
- vToFetch.push_back(CInv(MSG_CMPCT_BLOCK, inv.hash));
- else
- vToFetch.push_back(inv);
- // Mark block as in flight already, even though the actual "getdata" message only goes out
- // later (within the same cs_main lock, though).
- MarkBlockAsInFlight(pfrom->GetId(), inv.hash, chainparams.GetConsensus());
- }
LogPrint("net", "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->id);
}
}
@@ -6964,7 +6968,7 @@ bool SendMessages(CNode* pto, CConnman& connman)
// Message: feefilter
//
// We don't want white listed peers to filter txs to us if we have -whitelistforcerelay
- if (pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
+ if (!pto->fDisconnect && pto->nVersion >= FEEFILTER_VERSION && GetBoolArg("-feefilter", DEFAULT_FEEFILTER) &&
!(pto->fWhitelisted && GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY))) {
CAmount currentFilter = mempool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFeePerK();
int64_t timeNow = GetTimeMicros();