diff options
author | Pieter Wuille <pieter.wuille@gmail.com> | 2018-07-13 20:07:19 -0700 |
---|---|---|
committer | Pieter Wuille <pieter.wuille@gmail.com> | 2018-07-13 20:10:55 -0700 |
commit | 1e90862f5d0b5f7dcc18fb018b2bbaa323dcca1d (patch) | |
tree | 83d3b0dad997332f1cf68cdbe41b2be4a09142a9 | |
parent | ad552a54c56a420be84b47154882c3e4c76f9bdd (diff) | |
parent | 3339ba28e95aaaa355b7d33a69cffca7ab29b3fd (diff) |
Merge #13417: [net] Tighten scope in net_processing
3339ba28e9 Make g_enable_bip61 a member variable of PeerLogicValidation (Jesse Cohen)
6690a28606 Restrict as much as possible in net_processing to translation unit (Jesse Cohen)
1d4df02b7e [move-only] Move things only referenced in net_processing out of header file (Jesse Cohen)
02bbc05310 Rescope g_enable_bip61 to net_processing (Jesse Cohen)
Pull request description:
As part of a larger effort to decouple net_processing and validation a bit, these are a bunch of simple scope cleanups. I've moved things out of the header file that are only referenced in net_processing and added static (or anonymous namespace) modifiers to everything possible in net_processing.
There are a handful of functions which could be static except that they are exposed for the sake of unit testing - these are explicitly commented. There has been some discussion of a compile time annotation, but no conclusion has been reached on that yet.
This is somewhat related to other prs #12934 #13413 #13407 and will be followed by prs that reduce reliance on cs_main to synchronize data structures which are translation unit local to net_processing
Tree-SHA512: 46c9660ee4e06653feb42ba92189565b0aea17aac2375c20747c0d091054c63829cbf66d2daddf65682b58ce1d6922e23aefea051a7f2c8abbb6db253a609082
-rw-r--r-- | src/init.cpp | 4 | ||||
-rw-r--r-- | src/net_processing.cpp | 111 | ||||
-rw-r--r-- | src/net_processing.h | 30 | ||||
-rw-r--r-- | src/test/denialofservice_tests.cpp | 2 | ||||
-rw-r--r-- | src/test/test_bitcoin.cpp | 2 |
5 files changed, 76 insertions, 73 deletions
diff --git a/src/init.cpp b/src/init.cpp index 66b0b65eb4..fe4fba8cdf 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1122,8 +1122,6 @@ bool AppInitParameterInteraction() if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); - g_enable_bip61 = gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61); - if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) return InitError("rpcserialversion must be non-negative."); @@ -1308,7 +1306,7 @@ bool AppInitMain() g_connman = std::unique_ptr<CConnman>(new CConnman(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()))); CConnman& connman = *g_connman; - peerLogic.reset(new PeerLogicValidation(&connman, scheduler)); + peerLogic.reset(new PeerLogicValidation(&connman, scheduler, gArgs.GetBoolArg("-enablebip61", DEFAULT_ENABLE_BIP61))); RegisterValidationInterface(peerLogic.get()); // sanitize comments per BIP-0014, format user agent and check total size diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 2f3a604064..0bc508980e 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -35,17 +35,34 @@ # error "Bitcoin cannot be compiled without assertions." #endif -std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block -bool g_enable_bip61 = DEFAULT_ENABLE_BIP61; - -struct IteratorComparator -{ - template<typename I> - bool operator()(const I& a, const I& b) const - { - return &(*a) < &(*b); - } -}; +/** Expiration time for orphan transactions in seconds */ +static constexpr int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; +/** Minimum time between orphan transactions expire time checks in seconds */ +static constexpr int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; +/** Headers download timeout expressed in microseconds + * Timeout = base + per_header * (expected number of headers) */ +static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes +static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header +/** Protect at least this many outbound peers from disconnection due to slow/ + * behind headers chain. + */ +static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4; +/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */ +static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes +/** How frequently to check for stale tips, in seconds */ +static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes +/** How frequently to check for extra outbound peers and disconnect, in seconds */ +static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45; +/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */ +static constexpr int64_t MINIMUM_CONNECT_TIME = 30; +/** SHA256("main address relay")[0:8] */ +static constexpr uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; +/// Age after which a stale block will no longer be served if requested as +/// protection against fingerprinting. Set to one month, denominated in seconds. +static constexpr int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60; +/// Age after which a block is considered historical for purposes of rate +/// limiting block relay. Set to one week, denominated in seconds. +static constexpr int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60; struct COrphanTx { // When modifying, adapt the copy of this definition in tests/DoS_tests. @@ -55,21 +72,11 @@ struct COrphanTx { }; static CCriticalSection g_cs_orphans; std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans); -std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); -void EraseOrphansFor(NodeId peer); - -static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; -static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); -static const uint64_t RANDOMIZER_ID_ADDRESS_RELAY = 0x3cac0035b5866b90ULL; // SHA256("main address relay")[0:8] - -/// Age after which a stale block will no longer be served if requested as -/// protection against fingerprinting. Set to one month, denominated in seconds. -static const int STALE_RELAY_AGE_LIMIT = 30 * 24 * 60 * 60; +void EraseOrphansFor(NodeId peer); -/// Age after which a block is considered historical for purposes of rate -/// limiting block relay. Set to one week, denominated in seconds. -static const int HISTORICAL_BLOCK_AGE = 7 * 24 * 60 * 60; +/** Increase a node's misbehavior score. */ +void Misbehaving(NodeId nodeid, int howmuch, const std::string& message=""); // Internal stuff namespace { @@ -137,10 +144,24 @@ namespace { 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; + + std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block + + struct IteratorComparator + { + template<typename I> + bool operator()(const I& a, const I& b) const + { + return &(*a) < &(*b); + } + }; + std::map<COutPoint, std::set<std::map<uint256, COrphanTx>::iterator, IteratorComparator>> mapOrphanTransactionsByPrev GUARDED_BY(g_cs_orphans); + + static size_t vExtraTxnForCompactIt GUARDED_BY(g_cs_orphans) = 0; + static std::vector<std::pair<uint256, CTransactionRef>> vExtraTxnForCompact GUARDED_BY(g_cs_orphans); } // namespace namespace { - struct CBlockReject { unsigned char chRejectCode; std::string strRejectReason; @@ -267,10 +288,10 @@ struct CNodeState { }; /** Map maintaining per-node state. Requires cs_main. */ -std::map<NodeId, CNodeState> mapNodeState; +static std::map<NodeId, CNodeState> mapNodeState; // Requires cs_main. -CNodeState *State(NodeId pnode) { +static CNodeState *State(NodeId pnode) { std::map<NodeId, CNodeState>::iterator it = mapNodeState.find(pnode); if (it == mapNodeState.end()) return nullptr; @@ -809,7 +830,9 @@ static bool BlockRequestAllowed(const CBlockIndex* pindex, const Consensus::Para (GetBlockProofEquivalentTime(*pindexBestHeader, *pindex, *pindexBestHeader, consensusParams) < STALE_RELAY_AGE_LIMIT); } -PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler) : connman(connmanIn), m_stale_tip_check_time(0) { +PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, CScheduler &scheduler, bool enable_bip61) + : connman(connmanIn), m_stale_tip_check_time(0), m_enable_bip61(enable_bip61) { + // Initialize global variables that cannot be constructed at startup. recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); @@ -866,7 +889,7 @@ static uint256 most_recent_block_hash; static bool fWitnessesPresentInMostRecentCompactBlock; /** - * Maintain state about the best-seen block and fast-announce a compact block + * Maintain state about the best-seen block and fast-announce a compact block * to compatible peers. */ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) { @@ -911,7 +934,7 @@ void PeerLogicValidation::NewPoWValidBlock(const CBlockIndex *pindex, const std: } /** - * Update our best height and announce any block hashes which weren't previously + * Update our best height and announce any block hashes which weren't previously * in chainActive to our peers. */ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) { @@ -947,7 +970,7 @@ void PeerLogicValidation::UpdatedBlockTip(const CBlockIndex *pindexNew, const CB } /** - * Handle invalid block rejection and consequent peer banning, maintain which + * Handle invalid block rejection and consequent peer banning, maintain which * peers announce compact blocks. */ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationState& state) { @@ -1534,7 +1557,7 @@ bool static ProcessHeadersMessage(CNode *pfrom, CConnman *connman, const std::ve return true; } -bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc) +bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CConnman* connman, const std::atomic<bool>& interruptMsgProc, bool enable_bip61) { LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId()); if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0) @@ -1588,7 +1611,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // Each connection can only send one version message if (pfrom->nVersion != 0) { - if (g_enable_bip61) { + if (enable_bip61) { connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_DUPLICATE, std::string("Duplicate version message"))); } LOCK(cs_main); @@ -1619,7 +1642,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!pfrom->fInbound && !pfrom->fFeeler && !pfrom->m_manual_connection && !HasAllDesirableServiceFlags(nServices)) { LogPrint(BCLog::NET, "peer=%d does not offer the expected services (%08x offered, %08x expected); disconnecting\n", pfrom->GetId(), nServices, GetDesirableServiceFlags(nServices)); - if (g_enable_bip61) { + if (enable_bip61) { connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_NONSTANDARD, strprintf("Expected to offer services %08x", GetDesirableServiceFlags(nServices)))); } @@ -1642,7 +1665,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr { // disconnect from peers older than this proto version LogPrint(BCLog::NET, "peer=%d using obsolete version %i; disconnecting\n", pfrom->GetId(), nVersion); - if (g_enable_bip61) { + if (enable_bip61) { connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, strprintf("Version must be %d or greater", MIN_PEER_PROTO_VERSION))); } @@ -2340,7 +2363,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr LogPrint(BCLog::MEMPOOLREJ, "%s from peer=%d was not accepted: %s\n", tx.GetHash().ToString(), pfrom->GetId(), FormatStateMessage(state)); - if (g_enable_bip61 && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) { // Never send AcceptToMemoryPool's internal codes over P2P + if (enable_bip61 && state.GetRejectCode() > 0 && state.GetRejectCode() < REJECT_INTERNAL) { // Never send AcceptToMemoryPool's internal codes over P2P connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), inv.hash)); } @@ -2525,7 +2548,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr } // cs_main if (fProcessBLOCKTXN) - return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc); + return ProcessMessage(pfrom, NetMsgType::BLOCKTXN, blockTxnMsg, nTimeReceived, chainparams, connman, interruptMsgProc, enable_bip61); if (fRevertToHeaderProcessing) { // Headers received from HB compact block peers are permitted to be @@ -2911,12 +2934,12 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return true; } -static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman) +static bool SendRejectsAndCheckIfBanned(CNode* pnode, CConnman* connman, bool enable_bip61) { AssertLockHeld(cs_main); CNodeState &state = *State(pnode->GetId()); - if (g_enable_bip61) { + if (enable_bip61) { for (const CBlockReject& reject : state.rejects) { connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, std::string(NetMsgType::BLOCK), reject.chRejectCode, reject.strRejectReason, reject.hashBlock)); } @@ -3018,7 +3041,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter bool fRet = false; try { - fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc); + fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.nTime, chainparams, connman, interruptMsgProc, m_enable_bip61); if (interruptMsgProc) return false; if (!pfrom->vRecvGetData.empty()) @@ -3026,7 +3049,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter } catch (const std::ios_base::failure& e) { - if (g_enable_bip61) { + if (m_enable_bip61) { connman->PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_MALFORMED, std::string("error parsing message"))); } if (strstr(e.what(), "end of data")) @@ -3060,7 +3083,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter } LOCK(cs_main); - SendRejectsAndCheckIfBanned(pfrom, connman); + SendRejectsAndCheckIfBanned(pfrom, connman, m_enable_bip61); return fMoreWork; } @@ -3195,6 +3218,7 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params } } +namespace { class CompareInvMempoolOrder { CTxMemPool *mp; @@ -3211,6 +3235,7 @@ public: return mp->CompareDepthAndScore(*b, *a); } }; +} bool PeerLogicValidation::SendMessages(CNode* pto) { @@ -3256,7 +3281,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto) if (!lockMain) return true; - if (SendRejectsAndCheckIfBanned(pto, connman)) + if (SendRejectsAndCheckIfBanned(pto, connman, m_enable_bip61)) return true; CNodeState &state = *State(pto->GetId()); diff --git a/src/net_processing.h b/src/net_processing.h index 0d97b316eb..4dab0ada2b 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -12,40 +12,17 @@ /** Default for -maxorphantx, maximum number of orphan transactions kept in memory */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; -/** Expiration time for orphan transactions in seconds */ -static const int64_t ORPHAN_TX_EXPIRE_TIME = 20 * 60; -/** Minimum time between orphan transactions expire time checks in seconds */ -static const int64_t ORPHAN_TX_EXPIRE_INTERVAL = 5 * 60; /** Default number of orphan+recently-replaced txn to keep around for block reconstruction */ static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; -/** Headers download timeout expressed in microseconds - * Timeout = base + per_header * (expected number of headers) */ -static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_BASE = 15 * 60 * 1000000; // 15 minutes -static constexpr int64_t HEADERS_DOWNLOAD_TIMEOUT_PER_HEADER = 1000; // 1ms/header -/** Protect at least this many outbound peers from disconnection due to slow/ - * behind headers chain. - */ -static constexpr int32_t MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT = 4; -/** Timeout for (unprotected) outbound peers to sync to our chainwork, in seconds */ -static constexpr int64_t CHAIN_SYNC_TIMEOUT = 20 * 60; // 20 minutes -/** How frequently to check for stale tips, in seconds */ -static constexpr int64_t STALE_CHECK_INTERVAL = 10 * 60; // 10 minutes -/** How frequently to check for extra outbound peers and disconnect, in seconds */ -static constexpr int64_t EXTRA_PEER_CHECK_INTERVAL = 45; -/** Minimum time an outbound-peer-eviction candidate must be connected for, in order to evict, in seconds */ -static constexpr int64_t MINIMUM_CONNECT_TIME = 30; - /** Default for BIP61 (sending reject messages) */ static constexpr bool DEFAULT_ENABLE_BIP61 = true; -/** Enable BIP61 (sending reject messages) */ -extern bool g_enable_bip61; class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface { private: CConnman* const connman; public: - explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler); + explicit PeerLogicValidation(CConnman* connman, CScheduler &scheduler, bool enable_bip61); /** * Overridden from CValidationInterface. @@ -92,6 +69,9 @@ public: private: int64_t m_stale_tip_check_time; //! Next time to check for stale tip + + /** Enable BIP61 (sending reject messages) */ + const bool m_enable_bip61; }; struct CNodeStateStats { @@ -103,7 +83,5 @@ struct CNodeStateStats { /** Get statistics from node state */ bool GetNodeStateStats(NodeId nodeid, CNodeStateStats &stats); -/** Increase a node's misbehavior score. */ -void Misbehaving(NodeId nodeid, int howmuch, const std::string& message=""); #endif // BITCOIN_NET_PROCESSING_H diff --git a/src/test/denialofservice_tests.cpp b/src/test/denialofservice_tests.cpp index cc871726fd..49037adb9a 100644 --- a/src/test/denialofservice_tests.cpp +++ b/src/test/denialofservice_tests.cpp @@ -24,6 +24,8 @@ extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer); extern void EraseOrphansFor(NodeId peer); extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans); +extern void Misbehaving(NodeId nodeid, int howmuch, const std::string& message=""); + struct COrphanTx { CTransactionRef tx; NodeId fromPeer; diff --git a/src/test/test_bitcoin.cpp b/src/test/test_bitcoin.cpp index 6ede65c23a..b35b21335e 100644 --- a/src/test/test_bitcoin.cpp +++ b/src/test/test_bitcoin.cpp @@ -107,7 +107,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha threadGroup.create_thread(&ThreadScriptCheck); g_connman = std::unique_ptr<CConnman>(new CConnman(0x1337, 0x1337)); // Deterministic randomness for tests. connman = g_connman.get(); - peerLogic.reset(new PeerLogicValidation(connman, scheduler)); + peerLogic.reset(new PeerLogicValidation(connman, scheduler, /*enable_bip61=*/true)); } TestingSetup::~TestingSetup() |