diff options
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r-- | src/net_processing.cpp | 168 |
1 files changed, 83 insertions, 85 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0fad012257..0e222bdfa4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -25,9 +25,9 @@ #include <tinyformat.h> #include <txmempool.h> #include <ui_interface.h> -#include <util.h> -#include <utilmoneystr.h> -#include <utilstrencodings.h> +#include <util/system.h> +#include <util/moneystr.h> +#include <util/strencodings.h> #include <memory> @@ -70,7 +70,7 @@ struct COrphanTx { NodeId fromPeer; int64_t nTimeExpire; }; -static CCriticalSection g_cs_orphans; +CCriticalSection g_cs_orphans; std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); void EraseOrphansFor(NodeId peer); @@ -442,7 +442,7 @@ static void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) EXCLUSIV * lNodesAnnouncingHeaderAndIDs, and keeping that list under a certain size by * removing the first element if necessary. */ -static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) +static void MaybeSetPeerAsAnnouncingHeaderAndIDs(NodeId nodeid, CConnman* connman) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); CNodeState* nodestate = State(nodeid); @@ -566,7 +566,7 @@ static void FindNextBlocksToDownload(NodeId nodeid, unsigned int count, std::vec return; } if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) { - if (pindex->nChainTx) + if (pindex->HaveTxsDownloaded()) state->pindexLastCommonBlock = pindex; } else if (mapBlocksInFlight.count(pindex->GetBlockHash()) == 0) { // The block is not already downloaded, and not yet in flight. @@ -779,10 +779,11 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans) nNextSweep = nMinExpTime + ORPHAN_TX_EXPIRE_INTERVAL; if (nErased > 0) LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx due to expiration\n", nErased); } + FastRandomContext rng; while (mapOrphanTransactions.size() > nMaxOrphans) { // Evict a random orphan: - uint256 randomhash = GetRandHash(); + uint256 randomhash = rng.rand256(); std::map<uint256, COrphanTx>::iterator it = mapOrphanTransactions.lower_bound(randomhash); if (it == mapOrphanTransactions.end()) it = mapOrphanTransactions.begin(); @@ -831,7 +832,7 @@ void Misbehaving(NodeId pnode, int howmuch, const std::string& message) EXCLUSIV // active chain if they are no more than a month older (both in time, and in // best equivalent proof of work) than the best header chain we know about and // we fully-validated them at some point. -static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) +static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); if (chainActive.Contains(pindex)) return true; @@ -882,7 +883,7 @@ void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pb // Erase orphan transactions included or precluded by this block if (vOrphanErase.size()) { int nErased = 0; - for (uint256 &orphanHash : vOrphanErase) { + for (const uint256& orphanHash : vOrphanErase) { nErased += EraseOrphanTx(orphanHash); } LogPrint(BCLog::MEMPOOL, "Erased %d orphan tx included or conflicted by block\n", nErased); @@ -1124,7 +1125,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c LOCK(cs_main); const CBlockIndex* pindex = LookupBlockIndex(inv.hash); if (pindex) { - if (pindex->nChainTx && !pindex->IsValid(BLOCK_VALID_SCRIPTS) && + if (pindex->HaveTxsDownloaded() && !pindex->IsValid(BLOCK_VALID_SCRIPTS) && pindex->IsValid(BLOCK_VALID_TREE)) { // If we have the block and all of its parents, but have not yet validated it, // we might be in the middle of connecting it (ie in the unlock of cs_main @@ -1260,7 +1261,7 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c } } -void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) +void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main) { AssertLockNotHeld(cs_main); @@ -1618,8 +1619,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - else if (strCommand == NetMsgType::VERSION) - { + if (strCommand == NetMsgType::VERSION) { // Each connection can only send one version message if (pfrom->nVersion != 0) { @@ -1793,9 +1793,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } - - else if (pfrom->nVersion == 0) - { + if (pfrom->nVersion == 0) { // Must have a version message before anything else LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); @@ -1839,18 +1837,17 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK, nCMPCTBLOCKVersion)); } pfrom->fSuccessfullyConnected = true; + return true; } - else if (!pfrom->fSuccessfullyConnected) - { + if (!pfrom->fSuccessfullyConnected) { // Must have a verack message before anything else LOCK(cs_main); Misbehaving(pfrom->GetId(), 1); return false; } - else if (strCommand == NetMsgType::ADDR) - { + if (strCommand == NetMsgType::ADDR) { std::vector<CAddress> vAddr; vRecv >> vAddr; @@ -1897,16 +1894,16 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->fGetAddr = false; if (pfrom->fOneShot) pfrom->fDisconnect = true; + return true; } - else if (strCommand == NetMsgType::SENDHEADERS) - { + if (strCommand == NetMsgType::SENDHEADERS) { LOCK(cs_main); State(pfrom->GetId())->fPreferHeaders = true; + return true; } - else if (strCommand == NetMsgType::SENDCMPCT) - { + if (strCommand == NetMsgType::SENDCMPCT) { bool fAnnounceUsingCMPCTBLOCK = false; uint64_t nCMPCTBLOCKVersion = 0; vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion; @@ -1926,11 +1923,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr State(pfrom->GetId())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1); } } + return true; } - - else if (strCommand == NetMsgType::INV) - { + if (strCommand == NetMsgType::INV) { std::vector<CInv> vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) @@ -1984,11 +1980,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } } + return true; } - - else if (strCommand == NetMsgType::GETDATA) - { + if (strCommand == NetMsgType::GETDATA) { std::vector<CInv> vInv; vRecv >> vInv; if (vInv.size() > MAX_INV_SZ) @@ -2006,11 +2001,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->vRecvGetData.insert(pfrom->vRecvGetData.end(), vInv.begin(), vInv.end()); ProcessGetData(pfrom, chainparams, connman, interruptMsgProc); + return true; } - - else if (strCommand == NetMsgType::GETBLOCKS) - { + if (strCommand == NetMsgType::GETBLOCKS) { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; @@ -2075,11 +2069,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr break; } } + return true; } - - else if (strCommand == NetMsgType::GETBLOCKTXN) - { + if (strCommand == NetMsgType::GETBLOCKTXN) { BlockTransactionsRequest req; vRecv >> req; @@ -2125,11 +2118,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr assert(ret); SendBlockTransactions(block, req, pfrom, connman); + return true; } - - else if (strCommand == NetMsgType::GETHEADERS) - { + if (strCommand == NetMsgType::GETHEADERS) { CBlockLocator locator; uint256 hashStop; vRecv >> locator >> hashStop; @@ -2193,11 +2185,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // in the SendMessages logic. nodestate->pindexBestHeaderSent = pindex ? pindex : chainActive.Tip(); connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::HEADERS, vHeaders)); + return true; } - - else if (strCommand == NetMsgType::TX) - { + if (strCommand == NetMsgType::TX) { // Stop processing the transaction early if // We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off if (!fRelayTxes && (!pfrom->fWhitelisted || !gArgs.GetBoolArg("-whitelistrelay", DEFAULT_WHITELISTRELAY))) @@ -2298,7 +2289,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } } - for (uint256 hash : vEraseQueue) + for (const uint256& hash : vEraseQueue) EraseOrphanTx(hash); } else if (fMissingInputs) @@ -2367,6 +2358,23 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr for (const CTransactionRef& removedTx : lRemovedTxn) AddToCompactExtraTransactions(removedTx); + // If a tx has been detected by recentRejects, we will have reached + // this point and the tx will have been ignored. Because we haven't run + // the tx through AcceptToMemoryPool, we won't have computed a DoS + // score for it or determined exactly why we consider it invalid. + // + // This means we won't penalize any peer subsequently relaying a DoSy + // tx (even if we penalized the first peer who gave it to us) because + // we have to account for recentRejects showing false positives. In + // other words, we shouldn't penalize a peer if we aren't *sure* they + // submitted a DoSy tx. + // + // Note that recentRejects doesn't just record DoSy or invalid + // transactions, but any tx not accepted by the mempool, which may be + // due to node policy (vs. consensus). So we can't blanket penalize a + // peer simply for relaying a tx that our recentRejects has caught, + // regardless of false positives. + int nDoS = 0; if (state.IsInvalid(nDoS)) { @@ -2381,10 +2389,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr Misbehaving(pfrom->GetId(), nDoS); } } + return true; } - - else if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::CMPCTBLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { CBlockHeaderAndShortTxIDs cmpctblock; vRecv >> cmpctblock; @@ -2602,10 +2610,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr MarkBlockAsReceived(pblock->GetHash()); } } - + return true; } - else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing { BlockTransactions resp; vRecv >> resp; @@ -2677,10 +2685,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr mapBlockSource.erase(pblock->GetHash()); } } + return true; } - - else if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing + if (strCommand == NetMsgType::HEADERS && !fImporting && !fReindex) // Ignore headers received while importing { std::vector<CBlockHeader> headers; @@ -2705,7 +2713,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return ProcessHeadersMessage(pfrom, connman, headers, chainparams, should_punish); } - else if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing + if (strCommand == NetMsgType::BLOCK && !fImporting && !fReindex) // Ignore blocks received while importing { std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); vRecv >> *pblock; @@ -2731,11 +2739,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); mapBlockSource.erase(pblock->GetHash()); } + return true; } - - else if (strCommand == NetMsgType::GETADDR) - { + if (strCommand == NetMsgType::GETADDR) { // This asymmetric behavior for inbound and outbound connections was introduced // to prevent a fingerprinting attack: an attacker can send specific fake addresses // to users' AddrMan and later request them by sending getaddr messages. @@ -2759,11 +2766,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr FastRandomContext insecure_rand; for (const CAddress &addr : vAddr) pfrom->PushAddress(addr, insecure_rand); + return true; } - - else if (strCommand == NetMsgType::MEMPOOL) - { + if (strCommand == NetMsgType::MEMPOOL) { if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->fWhitelisted) { LogPrint(BCLog::NET, "mempool request with bloom filters disabled, disconnect peer=%d\n", pfrom->GetId()); @@ -2780,11 +2786,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(pfrom->cs_inventory); pfrom->fSendMempool = true; + return true; } - - else if (strCommand == NetMsgType::PING) - { + if (strCommand == NetMsgType::PING) { if (pfrom->nVersion > BIP0031_VERSION) { uint64_t nonce = 0; @@ -2802,11 +2807,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // return very quickly. connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::PONG, nonce)); } + return true; } - - else if (strCommand == NetMsgType::PONG) - { + if (strCommand == NetMsgType::PONG) { int64_t pingUsecEnd = nTimeReceived; uint64_t nonce = 0; size_t nAvail = vRecv.in_avail(); @@ -2859,11 +2863,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (bPingFinished) { pfrom->nPingNonceSent = 0; } + return true; } - - else if (strCommand == NetMsgType::FILTERLOAD) - { + if (strCommand == NetMsgType::FILTERLOAD) { CBloomFilter filter; vRecv >> filter; @@ -2880,11 +2883,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->pfilter->UpdateEmptyFull(); pfrom->fRelayTxes = true; } + return true; } - - else if (strCommand == NetMsgType::FILTERADD) - { + if (strCommand == NetMsgType::FILTERADD) { std::vector<unsigned char> vData; vRecv >> vData; @@ -2905,19 +2907,19 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LOCK(cs_main); Misbehaving(pfrom->GetId(), 100); } + return true; } - - else if (strCommand == NetMsgType::FILTERCLEAR) - { + if (strCommand == NetMsgType::FILTERCLEAR) { LOCK(pfrom->cs_filter); if (pfrom->GetLocalServices() & NODE_BLOOM) { pfrom->pfilter.reset(new CBloomFilter()); } pfrom->fRelayTxes = true; + return true; } - else if (strCommand == NetMsgType::FEEFILTER) { + if (strCommand == NetMsgType::FEEFILTER) { CAmount newFeeFilter = 0; vRecv >> newFeeFilter; if (MoneyRange(newFeeFilter)) { @@ -2927,24 +2929,21 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom->GetId()); } + return true; } - else if (strCommand == NetMsgType::NOTFOUND) { + if (strCommand == NetMsgType::NOTFOUND) { // We do not care about the NOTFOUND message, but logging an Unknown Command // message would be undesirable as we transmit it ourselves. + return true; } - else { - // Ignore unknown commands for extensibility - LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId()); - } - - - + // Ignore unknown commands for extensibility + LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId()); return true; } -static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) +static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { AssertLockHeld(cs_main); CNodeState &state = *State(pnode->GetId()); @@ -3163,8 +3162,6 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) NodeId worst_peer = -1; int64_t oldest_block_announcement = std::numeric_limits<int64_t>::max(); - LOCK(cs_main); - connman->ForEachNode([&](CNode* pnode) { AssertLockHeld(cs_main); @@ -3212,6 +3209,8 @@ void PeerLogicValidation::EvictExtraOutboundPeers(int64_t time_in_seconds) void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params &consensusParams) { + LOCK(cs_main); + if (connman == nullptr) return; int64_t time_in_seconds = GetTime(); @@ -3219,10 +3218,9 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params EvictExtraOutboundPeers(time_in_seconds); if (time_in_seconds > m_stale_tip_check_time) { - LOCK(cs_main); // Check whether our tip is stale, and if so, allow using an extra // outbound peer - if (TipMayBeStale(consensusParams)) { + if (!fImporting && !fReindex && connman->GetNetworkActive() && connman->GetUseAddrmanOutgoing() && TipMayBeStale(consensusParams)) { LogPrintf("Potential stale tip detected, will try using extra outbound peer (last tip update: %d seconds ago)\n", time_in_seconds - g_last_tip_update); connman->SetTryNewOutboundPeer(true); } else if (connman->GetTryNewOutboundPeer()) { |