diff options
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r-- | src/net_processing.cpp | 162 |
1 files changed, 94 insertions, 68 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp index de456e87f4..5267f96f70 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -11,7 +11,6 @@ #include <chainparams.h> #include <consensus/validation.h> #include <hash.h> -#include <init.h> #include <validation.h> #include <merkleblock.h> #include <netmessagemaker.h> @@ -36,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. @@ -56,21 +72,26 @@ 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=""); + +/** Average delay between local address broadcasts in seconds. */ +static constexpr unsigned int AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL = 24 * 60 * 60; +/** Average delay between peer address broadcasts in seconds. */ +static const unsigned int AVG_ADDRESS_BROADCAST_INTERVAL = 30; +/** Average delay between trickled inventory transmissions in seconds. + * Blocks and whitelisted receivers bypass this, outbound peers get half this delay. */ +static const unsigned int INVENTORY_BROADCAST_INTERVAL = 5; +/** Maximum number of inventory items to send per transmission. + * Limits the impact of low-fee transaction floods. */ +static constexpr unsigned int INVENTORY_BROADCAST_MAX = 7 * INVENTORY_BROADCAST_INTERVAL; +/** Average delay between feefilter broadcasts in seconds. */ +static constexpr unsigned int AVG_FEEFILTER_BROADCAST_INTERVAL = 10 * 60; +/** Maximum feefilter broadcast delay after significant change. */ +static constexpr unsigned int MAX_FEEFILTER_CHANGE_DELAY = 5 * 60; // Internal stuff namespace { @@ -138,10 +159,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; @@ -268,10 +303,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; @@ -665,10 +700,10 @@ bool AddOrphanTx(const CTransactionRef& tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRE // large transaction with a missing parent then we assume // it will rebroadcast it later, after the parent transaction(s) // have been mined or received. - // 100 orphans, each of which is at most 99,999 bytes big is + // 100 orphans, each of which is at most 100,000 bytes big is // at most 10 megabytes of orphans and somewhat more byprev index (in the worst case): unsigned int sz = GetTransactionWeight(*tx); - if (sz >= MAX_STANDARD_TX_WEIGHT) + if (sz > MAX_STANDARD_TX_WEIGHT) { LogPrint(BCLog::MEMPOOL, "ignoring large orphan tx (size: %u, hash: %s)\n", sz, hash.ToString()); return false; @@ -810,7 +845,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)); @@ -867,7 +904,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) { @@ -912,7 +949,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) { @@ -948,7 +985,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) { @@ -1071,7 +1108,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connma connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc)); } -void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman, const std::atomic<bool>& interruptMsgProc) +void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman) { bool send = false; std::shared_ptr<const CBlock> a_recent_block; @@ -1265,9 +1302,6 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm if (!push) { vNotFound.push_back(inv); } - - // Track requests for our stuff. - GetMainSignals().Inventory(inv.hash); } } // release cs_main @@ -1275,7 +1309,7 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm const CInv &inv = *it; if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK || inv.type == MSG_WITNESS_BLOCK) { it++; - ProcessGetBlockData(pfrom, chainparams, inv, connman, interruptMsgProc); + ProcessGetBlockData(pfrom, chainparams, inv, connman); } } @@ -1538,7 +1572,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) @@ -1592,7 +1626,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); @@ -1623,7 +1657,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)))); } @@ -1631,22 +1665,11 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr return false; } - if (nServices & ((1 << 7) | (1 << 5))) { - if (GetTime() < 1533096000) { - // Immediately disconnect peers that use service bits 6 or 8 until August 1st, 2018 - // These bits have been used as a flag to indicate that a node is running incompatible - // consensus rules instead of changing the network magic, so we're stuck disconnecting - // based on these service bits, at least for a while. - pfrom->fDisconnect = true; - return false; - } - } - if (nVersion < MIN_PEER_PROTO_VERSION) { // 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))); } @@ -1966,9 +1989,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->AskFor(inv); } } - - // Track requests for our stuff - GetMainSignals().Inventory(inv.hash); } } @@ -2347,7 +2367,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)); } @@ -2532,7 +2552,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 @@ -2918,12 +2938,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)); } @@ -3025,7 +3045,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()) @@ -3033,7 +3053,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")) @@ -3067,7 +3087,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter } LOCK(cs_main); - SendRejectsAndCheckIfBanned(pfrom, connman); + SendRejectsAndCheckIfBanned(pfrom, connman, m_enable_bip61); return fMoreWork; } @@ -3202,6 +3222,7 @@ void PeerLogicValidation::CheckForStaleTipAndEvictPeers(const Consensus::Params } } +namespace { class CompareInvMempoolOrder { CTxMemPool *mp; @@ -3218,8 +3239,9 @@ public: return mp->CompareDepthAndScore(*b, *a); } }; +} -bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptMsgProc) +bool PeerLogicValidation::SendMessages(CNode* pto) { const Consensus::Params& consensusParams = Params().GetConsensus(); { @@ -3263,7 +3285,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM if (!lockMain) return true; - if (SendRejectsAndCheckIfBanned(pto, connman)) + if (SendRejectsAndCheckIfBanned(pto, connman, m_enable_bip61)) return true; CNodeState &state = *State(pto->GetId()); @@ -3497,8 +3519,12 @@ bool PeerLogicValidation::SendMessages(CNode* pto, std::atomic<bool>& interruptM bool fSendTrickle = pto->fWhitelisted; if (pto->nNextInvSend < nNow) { fSendTrickle = true; - // Use half the delay for outbound peers, as there is less privacy concern for them. - pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> !pto->fInbound); + if (pto->fInbound) { + pto->nNextInvSend = connman->PoissonNextSendInbound(nNow, INVENTORY_BROADCAST_INTERVAL); + } else { + // Use half the delay for outbound peers, as there is less privacy concern for them. + pto->nNextInvSend = PoissonNextSend(nNow, INVENTORY_BROADCAST_INTERVAL >> 1); + } } // Time to send but the peer has requested we not relay transactions. |