aboutsummaryrefslogtreecommitdiff
path: root/src/net_processing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/net_processing.cpp')
-rw-r--r--src/net_processing.cpp413
1 files changed, 294 insertions, 119 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index ab430cbe1..6d85b4683 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -8,9 +8,11 @@
#include <addrman.h>
#include <banman.h>
#include <blockencodings.h>
+#include <blockfilter.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <hash.h>
+#include <index/blockfilterindex.h>
#include <validation.h>
#include <merkleblock.h>
#include <netmessagemaker.h>
@@ -64,6 +66,12 @@ 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;
+/** Time between pings automatically sent out for latency probing and keepalive (in seconds). */
+static const int PING_INTERVAL = 2 * 60;
+/** The maximum number of entries in a locator */
+static const unsigned int MAX_LOCATOR_SZ = 101;
+/** The maximum number of entries in an 'inv' protocol message */
+static const unsigned int MAX_INV_SZ = 50000;
/** Maximum number of in-flight transactions from a peer */
static constexpr int32_t MAX_PEER_TX_IN_FLIGHT = 100;
/** Maximum number of announced transactions from a peer */
@@ -80,7 +88,49 @@ static_assert(INBOUND_PEER_TX_DELAY >= MAX_GETDATA_RANDOM_DELAY,
"To preserve security, MAX_GETDATA_RANDOM_DELAY should not exceed INBOUND_PEER_DELAY");
/** Limit to avoid sending big packets. Not used in processing incoming GETDATA for compatibility */
static const unsigned int MAX_GETDATA_SZ = 1000;
-
+/** Number of blocks that can be requested at any given time from a single peer. */
+static const int MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16;
+/** Timeout in seconds during which a peer must stall block download progress before being disconnected. */
+static const unsigned int BLOCK_STALLING_TIMEOUT = 2;
+/** Number of headers sent in one getheaders result. We rely on the assumption that if a peer sends
+ * less than this number, we reached its tip. Changing this value is a protocol upgrade. */
+static const unsigned int MAX_HEADERS_RESULTS = 2000;
+/** Maximum depth of blocks we're willing to serve as compact blocks to peers
+ * when requested. For older blocks, a regular BLOCK response will be sent. */
+static const int MAX_CMPCTBLOCK_DEPTH = 5;
+/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */
+static const int MAX_BLOCKTXN_DEPTH = 10;
+/** Size of the "block download window": how far ahead of our current height do we fetch?
+ * Larger windows tolerate larger download speed differences between peer, but increase the potential
+ * degree of disordering of blocks on disk (which make reindexing and pruning harder). We'll probably
+ * want to make this a per-peer adaptive value at some point. */
+static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
+/** Block download timeout base, expressed in millionths of the block interval (i.e. 10 min) */
+static const int64_t BLOCK_DOWNLOAD_TIMEOUT_BASE = 1000000;
+/** Additional block download timeout per parallel downloading peer (i.e. 5 min) */
+static const int64_t BLOCK_DOWNLOAD_TIMEOUT_PER_PEER = 500000;
+/** Maximum number of headers to announce when relaying blocks with headers message.*/
+static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8;
+/** Maximum number of unconnecting headers announcements before DoS score */
+static const int MAX_UNCONNECTING_HEADERS = 10;
+/** Minimum blocks required to signal NODE_NETWORK_LIMITED */
+static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288;
+/** Average delay between local address broadcasts */
+static constexpr std::chrono::hours AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL{24};
+/** Average delay between peer address broadcasts */
+static constexpr std::chrono::seconds 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;
+/** Interval between compact filter checkpoints. See BIP 157. */
+static constexpr int CFCHECKPT_INTERVAL = 1000;
struct COrphanTx {
// When modifying, adapt the copy of this definition in tests/DoS_tests.
@@ -97,21 +147,6 @@ void EraseOrphansFor(NodeId peer);
/** Increase a node's misbehavior score. */
void Misbehaving(NodeId nodeid, int howmuch, const std::string& message="") EXCLUSIVE_LOCKS_REQUIRED(cs_main);
-/** 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 {
/** Number of nodes with fSyncStarted. */
@@ -779,6 +814,19 @@ void PeerLogicValidation::InitializeNode(CNode *pnode) {
PushNodeVersion(pnode, connman, GetTime());
}
+void PeerLogicValidation::ReattemptInitialBroadcast(CScheduler& scheduler) const
+{
+ std::set<uint256> unbroadcast_txids = m_mempool.GetUnbroadcastTxs();
+
+ for (const uint256& txid : unbroadcast_txids) {
+ RelayTransaction(txid, *connman);
+ }
+
+ // schedule next run for 10-15 minutes in the future
+ const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5});
+ scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
+}
+
void PeerLogicValidation::FinalizeNode(NodeId nodeid, bool& fUpdateConnectionTime) {
fUpdateConnectionTime = false;
LOCK(cs_main);
@@ -1128,6 +1176,10 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn, BanMan* banman, CS
// timer.
static_assert(EXTRA_PEER_CHECK_INTERVAL < STALE_CHECK_INTERVAL, "peer eviction timer should be less than stale tip check timer");
scheduler.scheduleEvery([this, consensusParams] { this->CheckForStaleTipAndEvictPeers(consensusParams); }, std::chrono::seconds{EXTRA_PEER_CHECK_INTERVAL});
+
+ // schedule next run for 10-15 minutes in the future
+ const std::chrono::milliseconds delta = std::chrono::minutes{10} + GetRandMillis(std::chrono::minutes{5});
+ scheduler.scheduleFromNow([&] { ReattemptInitialBroadcast(scheduler); }, delta);
}
/**
@@ -1365,7 +1417,7 @@ void RelayTransaction(const uint256& txid, const CConnman& connman)
});
}
-static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman)
+static void RelayAddress(const CAddress& addr, bool fReachable, const CConnman& connman)
{
unsigned int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
@@ -1373,7 +1425,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connma
// Use deterministic randomness to send to the same nodes for 24 hours
// at a time so the m_addr_knowns of the chosen nodes prevent repeats
uint64_t hashAddr = addr.GetHash();
- const CSipHasher hasher = connman->GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24*60*60));
+ const CSipHasher hasher = connman.GetDeterministicRandomizer(RANDOMIZER_ID_ADDRESS_RELAY).Write(hashAddr << 32).Write((GetTime() + hashAddr) / (24 * 60 * 60));
FastRandomContext insecure_rand;
std::array<std::pair<uint64_t, CNode*>,2> best{{{0, nullptr}, {0, nullptr}}};
@@ -1398,7 +1450,7 @@ static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connma
}
};
- connman->ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
+ connman.ForEachNodeThen(std::move(sortfunc), std::move(pushfunc));
}
void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, const CInv& inv, CConnman* connman)
@@ -1556,7 +1608,38 @@ void static ProcessGetBlockData(CNode* pfrom, const CChainParams& chainparams, c
}
}
-void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, const CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
+//! Determine whether or not a peer can request a transaction, and return it (or nullptr if not found or not allowed).
+CTransactionRef static FindTxForGetData(CNode* peer, const uint256& txid, const std::chrono::seconds mempool_req, const std::chrono::seconds longlived_mempool_time) LOCKS_EXCLUDED(cs_main)
+{
+ // Check if the requested transaction is so recent that we're just
+ // about to announce it to the peer; if so, they certainly shouldn't
+ // know we already have it.
+ {
+ LOCK(peer->m_tx_relay->cs_tx_inventory);
+ if (peer->m_tx_relay->setInventoryTxToSend.count(txid)) return {};
+ }
+
+ {
+ LOCK(cs_main);
+ // Look up transaction in relay pool
+ auto mi = mapRelay.find(txid);
+ if (mi != mapRelay.end()) return mi->second;
+ }
+
+ auto txinfo = mempool.info(txid);
+ if (txinfo.tx) {
+ // To protect privacy, do not answer getdata using the mempool when
+ // that TX couldn't have been INVed in reply to a MEMPOOL request,
+ // or when it's too recent to have expired from mapRelay.
+ if ((mempool_req.count() && txinfo.m_time <= mempool_req) || txinfo.m_time <= longlived_mempool_time) {
+ return txinfo.tx;
+ }
+ }
+
+ return {};
+}
+
+void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnman* connman, CTxMemPool& mempool, const std::atomic<bool>& interruptMsgProc) LOCKS_EXCLUDED(cs_main)
{
AssertLockNotHeld(cs_main);
@@ -1564,66 +1647,49 @@ void static ProcessGetData(CNode* pfrom, const CChainParams& chainparams, CConnm
std::vector<CInv> vNotFound;
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
- // Note that if we receive a getdata for a MSG_TX or MSG_WITNESS_TX from a
- // block-relay-only outbound peer, we will stop processing further getdata
- // messages from this peer (likely resulting in our peer eventually
- // disconnecting us).
- if (pfrom->m_tx_relay != nullptr) {
- // mempool entries added before this time have likely expired from mapRelay
- const std::chrono::seconds longlived_mempool_time = GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME;
- const std::chrono::seconds mempool_req = pfrom->m_tx_relay->m_last_mempool_req.load();
+ // mempool entries added before this time have likely expired from mapRelay
+ const std::chrono::seconds longlived_mempool_time = GetTime<std::chrono::seconds>() - RELAY_TX_CACHE_TIME;
+ // Get last mempool request time
+ const std::chrono::seconds mempool_req = pfrom->m_tx_relay != nullptr ? pfrom->m_tx_relay->m_last_mempool_req.load()
+ : std::chrono::seconds::min();
- LOCK(cs_main);
+ // Process as many TX items from the front of the getdata queue as
+ // possible, since they're common and it's efficient to batch process
+ // them.
+ while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
+ if (interruptMsgProc) return;
+ // The send buffer provides backpressure. If there's no space in
+ // the buffer, pause processing until the next call.
+ if (pfrom->fPauseSend) break;
- while (it != pfrom->vRecvGetData.end() && (it->type == MSG_TX || it->type == MSG_WITNESS_TX)) {
- if (interruptMsgProc)
- return;
- // Don't bother if send buffer is too full to respond anyway
- if (pfrom->fPauseSend)
- break;
+ const CInv &inv = *it++;
- const CInv &inv = *it;
- it++;
+ if (pfrom->m_tx_relay == nullptr) {
+ // Ignore GETDATA requests for transactions from blocks-only peers.
+ continue;
+ }
- // Send stream from relay memory
- bool push = false;
- auto mi = mapRelay.find(inv.hash);
+ CTransactionRef tx = FindTxForGetData(pfrom, inv.hash, mempool_req, longlived_mempool_time);
+ if (tx) {
int nSendFlags = (inv.type == MSG_TX ? SERIALIZE_TRANSACTION_NO_WITNESS : 0);
- if (mi != mapRelay.end()) {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *mi->second));
- push = true;
- } else {
- auto txinfo = mempool.info(inv.hash);
- // To protect privacy, do not answer getdata using the mempool when
- // that TX couldn't have been INVed in reply to a MEMPOOL request,
- // or when it's too recent to have expired from mapRelay.
- if (txinfo.tx && (
- (mempool_req.count() && txinfo.m_time <= mempool_req)
- || (txinfo.m_time <= longlived_mempool_time)))
- {
- connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *txinfo.tx));
- push = true;
- }
- }
- if (!push) {
- vNotFound.push_back(inv);
- }
+ connman->PushMessage(pfrom, msgMaker.Make(nSendFlags, NetMsgType::TX, *tx));
+ mempool.RemoveUnbroadcastTx(inv.hash);
+ } else {
+ vNotFound.push_back(inv);
}
- } // release cs_main
+ }
+ // Only process one BLOCK item per call, since they're uncommon and can be
+ // expensive to process.
if (it != pfrom->vRecvGetData.end() && !pfrom->fPauseSend) {
- const CInv &inv = *it;
+ 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);
}
+ // else: If the first item on the queue is an unknown type, we erase it
+ // and continue processing the queue on the next call.
}
- // Unknown types in the GetData stay in vRecvGetData and block any future
- // message from this peer, see vRecvGetData check in ProcessMessages().
- // Depending on future p2p changes, we might either drop unknown getdata on
- // the floor or disconnect the peer.
-
pfrom->vRecvGetData.erase(pfrom->vRecvGetData.begin(), it);
if (!vNotFound.empty()) {
@@ -1911,9 +1977,110 @@ void static ProcessOrphanTx(CConnman* connman, CTxMemPool& mempool, std::set<uin
}
}
-bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc)
+/**
+ * Validation logic for compact filters request handling.
+ *
+ * May disconnect from the peer in the case of a bad request.
+ *
+ * @param[in] pfrom The peer that we received the request from
+ * @param[in] chain_params Chain parameters
+ * @param[in] filter_type The filter type the request is for. Must be basic filters.
+ * @param[in] stop_hash The stop_hash for the request
+ * @param[out] stop_index The CBlockIndex for the stop_hash block, if the request can be serviced.
+ * @param[out] filter_index The filter index, if the request can be serviced.
+ * @return True if the request can be serviced.
+ */
+static bool PrepareBlockFilterRequest(CNode* pfrom, const CChainParams& chain_params,
+ BlockFilterType filter_type,
+ const uint256& stop_hash,
+ const CBlockIndex*& stop_index,
+ const BlockFilterIndex*& filter_index)
+{
+ const bool supported_filter_type =
+ (filter_type == BlockFilterType::BASIC &&
+ gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS));
+ if (!supported_filter_type) {
+ LogPrint(BCLog::NET, "peer %d requested unsupported block filter type: %d\n",
+ pfrom->GetId(), static_cast<uint8_t>(filter_type));
+ pfrom->fDisconnect = true;
+ return false;
+ }
+
+ {
+ LOCK(cs_main);
+ stop_index = LookupBlockIndex(stop_hash);
+
+ // Check that the stop block exists and the peer would be allowed to fetch it.
+ if (!stop_index || !BlockRequestAllowed(stop_index, chain_params.GetConsensus())) {
+ LogPrint(BCLog::NET, "peer %d requested invalid block hash: %s\n",
+ pfrom->GetId(), stop_hash.ToString());
+ pfrom->fDisconnect = true;
+ return false;
+ }
+ }
+
+ filter_index = GetBlockFilterIndex(filter_type);
+ if (!filter_index) {
+ LogPrint(BCLog::NET, "Filter index for supported type %s not found\n", BlockFilterTypeName(filter_type));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Handle a getcfcheckpt request.
+ *
+ * May disconnect from the peer in the case of a bad request.
+ *
+ * @param[in] pfrom The peer that we received the request from
+ * @param[in] vRecv The raw message received
+ * @param[in] chain_params Chain parameters
+ * @param[in] connman Pointer to the connection manager
+ */
+static void ProcessGetCFCheckPt(CNode* pfrom, CDataStream& vRecv, const CChainParams& chain_params,
+ CConnman* connman)
+{
+ uint8_t filter_type_ser;
+ uint256 stop_hash;
+
+ vRecv >> filter_type_ser >> stop_hash;
+
+ const BlockFilterType filter_type = static_cast<BlockFilterType>(filter_type_ser);
+
+ const CBlockIndex* stop_index;
+ const BlockFilterIndex* filter_index;
+ if (!PrepareBlockFilterRequest(pfrom, chain_params, filter_type, stop_hash,
+ stop_index, filter_index)) {
+ return;
+ }
+
+ std::vector<uint256> headers(stop_index->nHeight / CFCHECKPT_INTERVAL);
+
+ // Populate headers.
+ const CBlockIndex* block_index = stop_index;
+ for (int i = headers.size() - 1; i >= 0; i--) {
+ int height = (i + 1) * CFCHECKPT_INTERVAL;
+ block_index = block_index->GetAncestor(height);
+
+ if (!filter_index->LookupFilterHeader(block_index, headers[i])) {
+ LogPrint(BCLog::NET, "Failed to find block filter header in index: filter_type=%s, block_hash=%s\n",
+ BlockFilterTypeName(filter_type), block_index->GetBlockHash().ToString());
+ return;
+ }
+ }
+
+ CSerializedNetMsg msg = CNetMsgMaker(pfrom->GetSendVersion())
+ .Make(NetMsgType::CFCHECKPT,
+ filter_type_ser,
+ stop_index->GetBlockHash(),
+ headers);
+ connman->PushMessage(pfrom, std::move(msg));
+}
+
+bool ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, int64_t nTimeReceived, const CChainParams& chainparams, CTxMemPool& mempool, CConnman* connman, BanMan* banman, const std::atomic<bool>& interruptMsgProc)
{
- LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(strCommand), vRecv.size(), pfrom->GetId());
+ LogPrint(BCLog::NET, "received: %s (%u bytes) peer=%d\n", SanitizeString(msg_type), vRecv.size(), pfrom->GetId());
if (gArgs.IsArgSet("-dropmessagestest") && GetRand(gArgs.GetArg("-dropmessagestest", 0)) == 0)
{
LogPrintf("dropmessagestest DROPPING RECV MESSAGE\n");
@@ -1922,8 +2089,8 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
if (!(pfrom->GetLocalServices() & NODE_BLOOM) &&
- (strCommand == NetMsgType::FILTERLOAD ||
- strCommand == NetMsgType::FILTERADD))
+ (msg_type == NetMsgType::FILTERLOAD ||
+ msg_type == NetMsgType::FILTERADD))
{
if (pfrom->nVersion >= NO_BLOOM_VERSION) {
LOCK(cs_main);
@@ -1935,7 +2102,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
}
}
- if (strCommand == NetMsgType::VERSION) {
+ if (msg_type == NetMsgType::VERSION) {
// Each connection can only send one version message
if (pfrom->nVersion != 0)
{
@@ -2107,7 +2274,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
// At this point, the outgoing message serialization version can't change.
const CNetMsgMaker msgMaker(pfrom->GetSendVersion());
- if (strCommand == NetMsgType::VERACK)
+ if (msg_type == NetMsgType::VERACK)
{
pfrom->SetRecvVersion(std::min(pfrom->nVersion.load(), PROTOCOL_VERSION));
@@ -2152,7 +2319,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return false;
}
- if (strCommand == NetMsgType::ADDR) {
+ if (msg_type == NetMsgType::ADDR) {
std::vector<CAddress> vAddr;
vRecv >> vAddr;
@@ -2192,7 +2359,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
{
// Relay to a limited number of other nodes
- RelayAddress(addr, fReachable, connman);
+ RelayAddress(addr, fReachable, *connman);
}
// Do not store addresses outside our network
if (fReachable)
@@ -2206,13 +2373,13 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::SENDHEADERS) {
+ if (msg_type == NetMsgType::SENDHEADERS) {
LOCK(cs_main);
State(pfrom->GetId())->fPreferHeaders = true;
return true;
}
- if (strCommand == NetMsgType::SENDCMPCT) {
+ if (msg_type == NetMsgType::SENDCMPCT) {
bool fAnnounceUsingCMPCTBLOCK = false;
uint64_t nCMPCTBLOCKVersion = 0;
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
@@ -2235,7 +2402,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::INV) {
+ if (msg_type == NetMsgType::INV) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -2257,6 +2424,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
uint32_t nFetchFlags = GetFetchFlags(pfrom);
const auto current_time = GetTime<std::chrono::microseconds>();
+ uint256* best_block{nullptr};
for (CInv &inv : vInv)
{
@@ -2273,17 +2441,14 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
if (inv.type == MSG_BLOCK) {
UpdateBlockAvailability(pfrom->GetId(), inv.hash);
if (!fAlreadyHave && !fImporting && !fReindex && !mapBlocksInFlight.count(inv.hash)) {
- // 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, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), inv.hash));
- LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, inv.hash.ToString(), pfrom->GetId());
+ // Headers-first is the primary method of announcement on
+ // the network. If a node fell back to sending blocks by inv,
+ // it's probably for a re-org. The final block hash
+ // provided should be the highest, so send a getheaders and
+ // then fetch the blocks we need to catch up.
+ best_block = &inv.hash;
}
- }
- else
- {
+ } else {
pfrom->AddInventoryKnown(inv);
if (fBlocksOnly) {
LogPrint(BCLog::NET, "transaction (%s) inv sent in violation of protocol, disconnecting peer=%d\n", inv.hash.ToString(), pfrom->GetId());
@@ -2294,10 +2459,16 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
}
}
}
+
+ if (best_block != nullptr) {
+ connman->PushMessage(pfrom, msgMaker.Make(NetMsgType::GETHEADERS, ::ChainActive().GetLocator(pindexBestHeader), *best_block));
+ LogPrint(BCLog::NET, "getheaders (%d) %s to peer=%d\n", pindexBestHeader->nHeight, best_block->ToString(), pfrom->GetId());
+ }
+
return true;
}
- if (strCommand == NetMsgType::GETDATA) {
+ if (msg_type == NetMsgType::GETDATA) {
std::vector<CInv> vInv;
vRecv >> vInv;
if (vInv.size() > MAX_INV_SZ)
@@ -2318,7 +2489,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::GETBLOCKS) {
+ if (msg_type == NetMsgType::GETBLOCKS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2386,7 +2557,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::GETBLOCKTXN) {
+ if (msg_type == NetMsgType::GETBLOCKTXN) {
BlockTransactionsRequest req;
vRecv >> req;
@@ -2435,7 +2606,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::GETHEADERS) {
+ if (msg_type == NetMsgType::GETHEADERS) {
CBlockLocator locator;
uint256 hashStop;
vRecv >> locator >> hashStop;
@@ -2502,7 +2673,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::TX) {
+ if (msg_type == NetMsgType::TX) {
// Stop processing the transaction early if
// We are in blocks only mode and peer is either not whitelisted or whitelistrelay is off
// or if this peer is supposed to be a block-relay-only peer
@@ -2644,7 +2815,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::CMPCTBLOCK)
+ if (msg_type == NetMsgType::CMPCTBLOCK)
{
// Ignore cmpctblock received while importing
if (fImporting || fReindex) {
@@ -2865,7 +3036,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::BLOCKTXN)
+ if (msg_type == NetMsgType::BLOCKTXN)
{
// Ignore blocktxn received while importing
if (fImporting || fReindex) {
@@ -2947,7 +3118,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::HEADERS)
+ if (msg_type == NetMsgType::HEADERS)
{
// Ignore headers received while importing
if (fImporting || fReindex) {
@@ -2973,7 +3144,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return ProcessHeadersMessage(pfrom, connman, mempool, headers, chainparams, /*via_compact_block=*/false);
}
- if (strCommand == NetMsgType::BLOCK)
+ if (msg_type == NetMsgType::BLOCK)
{
// Ignore block received while importing
if (fImporting || fReindex) {
@@ -3009,7 +3180,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::GETADDR) {
+ if (msg_type == 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.
@@ -3043,7 +3214,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::MEMPOOL) {
+ if (msg_type == NetMsgType::MEMPOOL) {
if (!(pfrom->GetLocalServices() & NODE_BLOOM) && !pfrom->HasPermission(PF_MEMPOOL))
{
if (!pfrom->HasPermission(PF_NOBAN))
@@ -3071,7 +3242,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::PING) {
+ if (msg_type == NetMsgType::PING) {
if (pfrom->nVersion > BIP0031_VERSION)
{
uint64_t nonce = 0;
@@ -3092,7 +3263,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::PONG) {
+ if (msg_type == NetMsgType::PONG) {
int64_t pingUsecEnd = nTimeReceived;
uint64_t nonce = 0;
size_t nAvail = vRecv.in_avail();
@@ -3148,7 +3319,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::FILTERLOAD) {
+ if (msg_type == NetMsgType::FILTERLOAD) {
CBloomFilter filter;
vRecv >> filter;
@@ -3162,13 +3333,12 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
{
LOCK(pfrom->m_tx_relay->cs_filter);
pfrom->m_tx_relay->pfilter.reset(new CBloomFilter(filter));
- pfrom->m_tx_relay->pfilter->UpdateEmptyFull();
pfrom->m_tx_relay->fRelayTxes = true;
}
return true;
}
- if (strCommand == NetMsgType::FILTERADD) {
+ if (msg_type == NetMsgType::FILTERADD) {
std::vector<unsigned char> vData;
vRecv >> vData;
@@ -3192,19 +3362,19 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::FILTERCLEAR) {
+ if (msg_type == NetMsgType::FILTERCLEAR) {
if (pfrom->m_tx_relay == nullptr) {
return true;
}
LOCK(pfrom->m_tx_relay->cs_filter);
if (pfrom->GetLocalServices() & NODE_BLOOM) {
- pfrom->m_tx_relay->pfilter.reset(new CBloomFilter());
+ pfrom->m_tx_relay->pfilter = nullptr;
}
pfrom->m_tx_relay->fRelayTxes = true;
return true;
}
- if (strCommand == NetMsgType::FEEFILTER) {
+ if (msg_type == NetMsgType::FEEFILTER) {
CAmount newFeeFilter = 0;
vRecv >> newFeeFilter;
if (MoneyRange(newFeeFilter)) {
@@ -3217,7 +3387,12 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
return true;
}
- if (strCommand == NetMsgType::NOTFOUND) {
+ if (msg_type == NetMsgType::GETCFCHECKPT) {
+ ProcessGetCFCheckPt(pfrom, vRecv, chainparams, connman);
+ return true;
+ }
+
+ if (msg_type == NetMsgType::NOTFOUND) {
// Remove the NOTFOUND transactions from the peer
LOCK(cs_main);
CNodeState *state = State(pfrom->GetId());
@@ -3243,7 +3418,7 @@ bool ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vR
}
// Ignore unknown commands for extensibility
- LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(strCommand), pfrom->GetId());
+ LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom->GetId());
return true;
}
@@ -3338,7 +3513,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(msg.m_command), pfrom->GetId());
return fMoreWork;
}
- const std::string& strCommand = msg.m_command;
+ const std::string& msg_type = msg.m_command;
// Message size
unsigned int nMessageSize = msg.m_message_size;
@@ -3348,7 +3523,7 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
if (!msg.m_valid_checksum)
{
LogPrint(BCLog::NET, "%s(%s, %u bytes): CHECKSUM ERROR peer=%d\n", __func__,
- SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ SanitizeString(msg_type), nMessageSize, pfrom->GetId());
return fMoreWork;
}
@@ -3356,19 +3531,19 @@ bool PeerLogicValidation::ProcessMessages(CNode* pfrom, std::atomic<bool>& inter
bool fRet = false;
try
{
- fRet = ProcessMessage(pfrom, strCommand, vRecv, msg.m_time, chainparams, m_mempool, connman, m_banman, interruptMsgProc);
+ fRet = ProcessMessage(pfrom, msg_type, vRecv, msg.m_time, chainparams, m_mempool, connman, m_banman, interruptMsgProc);
if (interruptMsgProc)
return false;
if (!pfrom->vRecvGetData.empty())
fMoreWork = true;
} catch (const std::exception& e) {
- LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(strCommand), nMessageSize, e.what(), typeid(e).name());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Exception '%s' (%s) caught\n", __func__, SanitizeString(msg_type), nMessageSize, e.what(), typeid(e).name());
} catch (...) {
- LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(strCommand), nMessageSize);
+ LogPrint(BCLog::NET, "%s(%s, %u bytes): Unknown exception caught\n", __func__, SanitizeString(msg_type), nMessageSize);
}
if (!fRet) {
- LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(strCommand), nMessageSize, pfrom->GetId());
+ LogPrint(BCLog::NET, "%s(%s, %u bytes) FAILED peer=%d\n", __func__, SanitizeString(msg_type), nMessageSize, pfrom->GetId());
}
LOCK(cs_main);
@@ -3583,16 +3758,16 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
int64_t nNow = GetTimeMicros();
auto current_time = GetTime<std::chrono::microseconds>();
- if (pto->IsAddrRelayPeer() && !::ChainstateActive().IsInitialBlockDownload() && pto->nNextLocalAddrSend < nNow) {
+ if (pto->IsAddrRelayPeer() && !::ChainstateActive().IsInitialBlockDownload() && pto->m_next_local_addr_send < current_time) {
AdvertiseLocal(pto);
- pto->nNextLocalAddrSend = PoissonNextSend(nNow, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
+ pto->m_next_local_addr_send = PoissonNextSend(current_time, AVG_LOCAL_ADDRESS_BROADCAST_INTERVAL);
}
//
// Message: addr
//
- if (pto->IsAddrRelayPeer() && pto->nNextAddrSend < nNow) {
- pto->nNextAddrSend = PoissonNextSend(nNow, AVG_ADDRESS_BROADCAST_INTERVAL);
+ if (pto->IsAddrRelayPeer() && pto->m_next_addr_send < current_time) {
+ pto->m_next_addr_send = PoissonNextSend(current_time, AVG_ADDRESS_BROADCAST_INTERVAL);
std::vector<CAddress> vAddr;
vAddr.reserve(pto->vAddrToSend.size());
assert(pto->m_addr_known);