Skip to content
Bitcoin Roots

v29.4-roots.1 · Commit 3: [PATCH 03/13] policy: restore conservative relay and network controls

src/net_processing.cpp

Before: src/net_processing.cpp · After: src/net_processing.cpp

File metadata
index 049812763716697b645ba5d4a6bb873e0a4511ae..de81fb24b3225c9422fbf56db9516c5669ca1f14 100644

Download original patch · Release notes

Diff rows 1–400 of 417. Line numbers refer to the original before/after files.

+ Added− RemovedUnmarked lines are context.

Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.

src/net_processing.cpp CHANGED
@@ -10,6 +10,7 @@
10
  #include <blockencodings.h>
11
  #include <blockfilter.h>
12
  #include <chainparams.h>
 
13
  #include <consensus/amount.h>
14
  #include <consensus/validation.h>
15
  #include <deploymentstatus.h>
@@ -137,7 +138,7 @@ static constexpr auto INBOUND_INVENTORY_BROADCAST_INTERVAL{5s};
137
  static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
138
  /** Maximum rate of inventory items to send per second.
139
  * Limits the impact of low-fee transaction floods. */
140
- static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND = 7;
141
  /** Target number of tx inventory items to send per transmission. */
142
  static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
143
  /** Maximum number of inventory items to send per transmission. */
@@ -500,7 +501,7 @@ public:
500
  /** Implement PeerManager */
501
  void StartScheduledTasks(CScheduler& scheduler) override;
502
  void CheckForStaleTipAndEvictPeers() override;
503
- std::optional<std::string> FetchBlock(NodeId peer_id, const CBlockIndex& block_index) override
504
  EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
505
  bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
506
  std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
@@ -777,7 +778,7 @@ private:
777
 
778
  uint32_t GetFetchFlags(const Peer& peer) const;
779
 
780
- std::atomic<std::chrono::microseconds> m_next_inv_to_inbounds{0us};
781
 
782
  /** Number of nodes with fSyncStarted. */
783
  int nSyncStarted GUARDED_BY(cs_main) = 0;
@@ -807,12 +808,14 @@ private:
807
 
808
  /**
809
  * For sending `inv`s to inbound peers, we use a single (exponentially
810
- * distributed) timer for all peers. If we used a separate timer for each
811
  * peer, a spy node could make multiple inbound connections to us to
812
- * accurately determine when we received the transaction (and potentially
813
- * determine the transaction's origin). */
 
814
  std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
815
- std::chrono::seconds average_interval) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
 
816
 
817
 
818
  // All of the following cache a recent block, and are protected by m_most_recent_block_mutex
@@ -849,6 +852,9 @@ private:
849
  /** Have we requested this block from an outbound peer */
850
  bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex);
851
 
 
 
 
852
  /** Remove this block from our tracked requested blocks. Called if:
853
  * - the block has been received from a peer
854
  * - the request for the block has timed out
@@ -939,7 +945,7 @@ private:
939
  /** Number of peers from which we're downloading blocks. */
940
  int m_peers_downloading_from GUARDED_BY(cs_main) = 0;
941
 
942
- void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
943
 
944
  /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
945
  * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
@@ -947,6 +953,7 @@ private:
947
  std::vector<CTransactionRef> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex);
948
  /** Offset into vExtraTxnForCompact to insert the next tx */
949
  size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0;
 
950
 
951
  /** Check whether the last unknown block a peer advertised is not yet known. */
952
  void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
@@ -1111,15 +1118,15 @@ static bool CanServeWitnesses(const Peer& peer)
1111
  }
1112
 
1113
  std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1114
- std::chrono::seconds average_interval)
 
1115
  {
1116
- if (m_next_inv_to_inbounds.load() < now) {
1117
- // If this function were called from multiple threads simultaneously
1118
- // it would possible that both update the next send variable, and return a different result to their caller.
1119
- // This is not possible in practice as only the net processing thread invokes this function.
1120
- m_next_inv_to_inbounds = now + m_rng.rand_exp_duration(average_interval);
1121
  }
1122
- return m_next_inv_to_inbounds;
1123
  }
1124
 
1125
  bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
@@ -1138,6 +1145,16 @@ bool PeerManagerImpl::IsBlockRequestedFromOutbound(const uint256& hash)
1138
  return false;
1139
  }
1140
 
 
 
 
 
 
 
 
 
 
 
1141
  void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
1142
  {
1143
  auto range = mapBlocksInFlight.equal_range(hash);
@@ -1529,6 +1546,9 @@ void PeerManagerImpl::InitializeNode(const CNode& node, ServiceFlags our_service
1529
  if (NetPermissions::HasFlag(node.m_permission_flags, NetPermissionFlags::BloomFilter)) {
1530
  our_services = static_cast<ServiceFlags>(our_services | NODE_BLOOM);
1531
  }
 
 
 
1532
 
1533
  PeerRef peer = std::make_shared<Peer>(nodeid, our_services, node.IsInboundConn());
1534
  {
@@ -1676,6 +1696,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
1676
  if (queue.pindex)
1677
  stats.vHeightInFlight.push_back(queue.pindex->nHeight);
1678
  }
 
1679
  }
1680
 
1681
  PeerRef peer = GetPeerRef(nodeid);
@@ -1712,6 +1733,7 @@ bool PeerManagerImpl::GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) c
1712
  }
1713
  }
1714
  stats.time_offset = peer->m_time_offset;
 
1715
 
1716
  return true;
1717
  }
@@ -1730,14 +1752,27 @@ PeerManagerInfo PeerManagerImpl::GetInfo() const
1730
  };
1731
  }
1732
 
1733
- void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx)
1734
  {
1735
  if (m_opts.max_extra_txs <= 0)
1736
  return;
1737
  if (!vExtraTxnForCompact.size())
1738
  vExtraTxnForCompact.resize(m_opts.max_extra_txs);
1739
- vExtraTxnForCompact[vExtraTxnForCompactIt] = tx;
 
 
 
 
 
 
1740
  vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
 
 
 
 
 
 
 
1741
  }
1742
 
1743
  void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)
@@ -1753,10 +1788,23 @@ void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)
1753
  );
1754
  }
1755
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1756
  void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
1757
  bool via_compact_block, const std::string& message)
1758
  {
1759
- PeerRef peer{GetPeerRef(nodeid)};
1760
  switch (state.GetResult()) {
1761
  case BlockValidationResult::BLOCK_RESULT_UNSET:
1762
  break;
@@ -1768,7 +1816,7 @@ void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
1768
  case BlockValidationResult::BLOCK_CONSENSUS:
1769
  case BlockValidationResult::BLOCK_MUTATED:
1770
  if (!via_compact_block) {
1771
- if (peer) Misbehaving(*peer, message);
1772
  return;
1773
  }
1774
  break;
@@ -1776,8 +1824,8 @@ void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
1776
  {
1777
  // Discourage outbound (but not inbound) peers if on an invalid chain.
1778
  // Exempt HB compact block peers. Manual connections are always protected from discouragement.
1779
- if (peer && !via_compact_block && !peer->m_is_inbound) {
1780
- if (peer) Misbehaving(*peer, message);
1781
  return;
1782
  }
1783
  break;
@@ -1785,11 +1833,11 @@ void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidati
1785
  case BlockValidationResult::BLOCK_INVALID_HEADER:
1786
  case BlockValidationResult::BLOCK_CHECKPOINT:
1787
  case BlockValidationResult::BLOCK_INVALID_PREV:
1788
- if (peer) Misbehaving(*peer, message);
1789
  return;
1790
  // Conflicting (but not necessarily invalid) data or different policy:
1791
  case BlockValidationResult::BLOCK_MISSING_PREV:
1792
- if (peer) Misbehaving(*peer, message);
1793
  return;
1794
  case BlockValidationResult::BLOCK_TIME_FUTURE:
1795
  break;
@@ -1808,7 +1856,7 @@ bool PeerManagerImpl::BlockRequestAllowed(const CBlockIndex* pindex)
1808
  (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
1809
  }
1810
 
1811
- std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)
1812
  {
1813
  if (m_chainman.m_blockman.LoadingBlocks()) return "Loading blocks ...";
1814
 
@@ -1821,14 +1869,18 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
1821
 
1822
  LOCK(cs_main);
1823
 
1824
- // Forget about all prior requests
1825
- RemoveBlockRequest(block_index.GetBlockHash(), std::nullopt);
1826
 
1827
- // Mark block as in-flight
1828
- if (!BlockRequested(peer_id, block_index)) return "Already requested from this peer";
 
 
 
 
 
 
1829
 
1830
  // Construct message to request the block
1831
- const uint256& hash{block_index.GetBlockHash()};
1832
  std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)};
1833
 
1834
  // Send block request message to the peer
@@ -1844,6 +1896,12 @@ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const CBl
1844
  return std::nullopt;
1845
  }
1846
 
 
 
 
 
 
 
1847
  std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrman,
1848
  BanMan* banman, ChainstateManager& chainman,
1849
  CTxMemPool& pool, node::Warnings& warnings, Options opts)
@@ -1851,11 +1909,12 @@ std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrm
1851
  return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts);
1852
  }
1853
 
 
1854
  PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
1855
  BanMan* banman, ChainstateManager& chainman,
1856
  CTxMemPool& pool, node::Warnings& warnings, Options opts)
1857
  : m_rng{opts.deterministic_rng},
1858
- m_fee_filter_rounder{CFeeRate{DEFAULT_MIN_RELAY_TX_FEE}, m_rng},
1859
  m_chainparams(chainman.GetParams()),
1860
  m_connman(connman),
1861
  m_addrman(addrman),
@@ -2208,7 +2267,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2208
  }
2209
  // disconnect node in case we have reached the outbound limit for serving historical blocks
2210
  if (m_connman.OutboundTargetReached(true) &&
2211
- (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk()) &&
2212
  !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
2213
  ) {
2214
  LogDebug(BCLog::NET, "historical block serving limit reached, %s\n", pfrom.DisconnectMsg(fLogIPs));
@@ -2271,7 +2330,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2271
  MakeAndPushMessage(pfrom, NetMsgType::BLOCK, TX_NO_WITNESS(*pblock));
2272
  } else if (inv.IsMsgWitnessBlk()) {
2273
  MakeAndPushMessage(pfrom, NetMsgType::BLOCK, TX_WITH_WITNESS(*pblock));
2274
- } else if (inv.IsMsgFilteredBlk()) {
2275
  bool sendMerkleBlock = false;
2276
  CMerkleBlock merkleBlock;
2277
  if (auto tx_relay = peer.GetTxRelay(); tx_relay != nullptr) {
@@ -2289,9 +2348,10 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
2289
  // they must either disconnect and retry or request the full block.
2290
  // Thus, the protocol spec specified allows for us to provide duplicate txn here,
2291
  // however we MUST always provide at least what the remote peer needs
 
2292
  typedef std::pair<unsigned int, uint256> PairType;
2293
  for (PairType& pair : merkleBlock.vMatchedTxn)
2294
- MakeAndPushMessage(pfrom, NetMsgType::TX, TX_NO_WITNESS(*pblock->vtx[pair.first]));
2295
  }
2296
  // else
2297
  // no response
@@ -2492,6 +2552,10 @@ void PeerManagerImpl::HandleUnconnectingHeaders(CNode& pfrom, Peer& peer,
2492
  // eventually get the headers - even from a different peer -
2493
  // we can use this peer to download.
2494
  WITH_LOCK(cs_main, UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()));
 
 
 
 
2495
  }
2496
 
2497
  bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const
@@ -2948,8 +3012,9 @@ std::optional<node::PackageToValidate> PeerManagerImpl::ProcessInvalidTx(NodeId
2948
 
2949
  const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
2950
 
2951
- if (add_extra_compact_tx && RecursiveDynamicUsage(*ptx) < 100000) {
2952
- AddToCompactExtraTransactions(ptx);
 
2953
  }
2954
  for (const Txid& parent_txid : unique_parents) {
2955
  if (peer) AddKnownTx(*peer, parent_txid);
@@ -2975,7 +3040,8 @@ void PeerManagerImpl::ProcessValidTx(NodeId nodeid, const CTransactionRef& tx, c
2975
  RelayTransaction(tx->GetHash(), tx->GetWitnessHash());
2976
 
2977
  for (const CTransactionRef& removedTx : replaced_transactions) {
2978
- AddToCompactExtraTransactions(removedTx);
 
2979
  }
2980
  }
2981
 
@@ -3405,7 +3471,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3405
  if (!vRecv.empty()) {
3406
  std::string strSubVer;
3407
  vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
3408
- cleanSubVer = SanitizeString(strSubVer);
3409
  }
3410
  if (!vRecv.empty()) {
3411
  vRecv >> starting_height;
@@ -3434,6 +3500,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3434
  // Change version
3435
  const int greatest_common_version = std::min(nVersion, PROTOCOL_VERSION);
3436
  pfrom.SetCommonVersion(greatest_common_version);
 
 
 
 
3437
  pfrom.nVersion = nVersion;
3438
 
3439
  if (greatest_common_version >= WTXID_RELAY_VERSION) {
@@ -3452,10 +3522,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3452
  pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices);
3453
  peer->m_their_services = nServices;
3454
  pfrom.SetAddrLocal(addrMe);
3455
- {
3456
- LOCK(pfrom.m_subver_mutex);
3457
- pfrom.cleanSubVer = cleanSubVer;
3458
- }
3459
  peer->m_starting_height = starting_height;
3460
 
3461
  // Only initialize the Peer::TxRelay m_relay_txs data structure if:
@@ -3541,10 +3607,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3541
  }
3542
 
3543
  const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
3544
- LogDebug(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s\n",
3545
- cleanSubVer, pfrom.nVersion,
3546
  peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(),
3547
- pfrom.LogIP(fLogIPs), (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
 
3548
 
3549
  peer->m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();
3550
  if (!pfrom.IsInboundConn()) {
@@ -3584,11 +3651,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3584
  // can be triggered by an attacker at high rate.
3585
  if (!pfrom.IsInboundConn() || LogAcceptCategory(BCLog::NET, BCLog::Level::Debug)) {
3586
  const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
3587
- LogPrintf("New %s %s peer connected: version: %d, blocks=%d, peer=%d%s%s\n",
3588
  pfrom.ConnectionTypeAsString(),
3589
  TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),
3590
  pfrom.nVersion.load(), peer->m_starting_height,
3591
- pfrom.GetId(), pfrom.LogIP(fLogIPs),
 
3592
  (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
3593
  }
3594
 
@@ -4871,13 +4939,13 @@ bool PeerManagerImpl::MaybeDiscourageAndDisconnect(CNode& pnode, Peer& peer)
4871
 
4872
  if (pnode.HasPermission(NetPermissionFlags::NoBan)) {
4873
  // We never disconnect or discourage peers for bad behavior if they have NetPermissionFlags::NoBan permission
4874
- LogPrintf("Warning: not punishing noban peer %d!\n", peer.m_id);
4875
  return false;
4876
  }
4877
 
4878
  if (pnode.IsManualConn()) {
4879
  // We never disconnect or discourage manual peers for bad behavior
4880
- LogPrintf("Warning: not punishing manually connected peer %d!\n", peer.m_id);
4881
  return false;
 
10
  #include <blockencodings.h>
11
  #include <blockfilter.h>
12
  #include <chainparams.h>
13
+ #include <common/args.h>
14
  #include <consensus/amount.h>
15
  #include <consensus/validation.h>
16
  #include <deploymentstatus.h>
 
138
  static constexpr auto OUTBOUND_INVENTORY_BROADCAST_INTERVAL{2s};
139
  /** Maximum rate of inventory items to send per second.
140
  * Limits the impact of low-fee transaction floods. */
141
+ static constexpr unsigned int INVENTORY_BROADCAST_PER_SECOND{14};
142
  /** Target number of tx inventory items to send per transmission. */
143
  static constexpr unsigned int INVENTORY_BROADCAST_TARGET = INVENTORY_BROADCAST_PER_SECOND * count_seconds(INBOUND_INVENTORY_BROADCAST_INTERVAL);
144
  /** Maximum number of inventory items to send per transmission. */
 
501
  /** Implement PeerManager */
502
  void StartScheduledTasks(CScheduler& scheduler) override;
503
  void CheckForStaleTipAndEvictPeers() override;
504
+ std::optional<std::string> FetchBlock(NodeId peer_id, const uint256& hash, const CBlockIndex* block_index) override
505
  EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
506
  bool GetNodeStateStats(NodeId nodeid, CNodeStateStats& stats) const override EXCLUSIVE_LOCKS_REQUIRED(!m_peer_mutex);
507
  std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() override EXCLUSIVE_LOCKS_REQUIRED(!m_tx_download_mutex);
 
778
 
779
  uint32_t GetFetchFlags(const Peer& peer) const;
780
 
781
+ std::map<uint64_t, std::chrono::microseconds> m_next_inv_to_inbounds_per_network_key GUARDED_BY(g_msgproc_mutex);
782
 
783
  /** Number of nodes with fSyncStarted. */
784
  int nSyncStarted GUARDED_BY(cs_main) = 0;
 
808
 
809
  /**
810
  * For sending `inv`s to inbound peers, we use a single (exponentially
811
+ * distributed) timer for all peers with the same network key. If we used a separate timer for each
812
  * peer, a spy node could make multiple inbound connections to us to
813
+ * accurately determine when we received a transaction (and potentially
814
+ * determine the transaction's origin). Each network key has its own timer
815
+ * to make fingerprinting harder. */
816
  std::chrono::microseconds NextInvToInbounds(std::chrono::microseconds now,
817
+ std::chrono::seconds average_interval,
818
+ uint64_t network_key) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
819
 
820
 
821
  // All of the following cache a recent block, and are protected by m_most_recent_block_mutex
 
852
  /** Have we requested this block from an outbound peer */
853
  bool IsBlockRequestedFromOutbound(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main, !m_peer_mutex);
854
 
855
+ /** Have we requested this block from a specific peer */
856
+ bool IsBlockRequestedFromPeer(const uint256& hash, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
857
+
858
  /** Remove this block from our tracked requested blocks. Called if:
859
  * - the block has been received from a peer
860
  * - the request for the block has timed out
 
945
  /** Number of peers from which we're downloading blocks. */
946
  int m_peers_downloading_from GUARDED_BY(cs_main) = 0;
947
 
948
+ void AddToCompactExtraTransactions(const CTransactionRef& tx, size_t tx_dynamic_usage) EXCLUSIVE_LOCKS_REQUIRED(g_msgproc_mutex);
949
 
950
  /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
951
  * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
 
953
  std::vector<CTransactionRef> vExtraTxnForCompact GUARDED_BY(g_msgproc_mutex);
954
  /** Offset into vExtraTxnForCompact to insert the next tx */
955
  size_t vExtraTxnForCompactIt GUARDED_BY(g_msgproc_mutex) = 0;
956
+ size_t blockreconstructionextratxn_memusage{0};
957
 
958
  /** Check whether the last unknown block a peer advertised is not yet known. */
959
  void ProcessBlockAvailability(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
 
1118
  }
1119
 
1120
  std::chrono::microseconds PeerManagerImpl::NextInvToInbounds(std::chrono::microseconds now,
1121
+ std::chrono::seconds average_interval,
1122
+ uint64_t network_key)
1123
  {
1124
+ auto [it, inserted] = m_next_inv_to_inbounds_per_network_key.try_emplace(network_key, 0us);
1125
+ auto& timer{it->second};
1126
+ if (timer < now) {
1127
+ timer = now + m_rng.rand_exp_duration(average_interval);
 
1128
  }
1129
+ return timer;
1130
  }
1131
 
1132
  bool PeerManagerImpl::IsBlockRequested(const uint256& hash)
 
1145
  return false;
1146
  }
1147
 
1148
+ bool PeerManagerImpl::IsBlockRequestedFromPeer(const uint256& hash, NodeId peer)
1149
+ {
1150
+ for (auto range = mapBlocksInFlight.equal_range(hash); range.first != range.second; range.first++) {
1151
+ auto [nodeid, block_it] = range.first->second;
1152
+ if (nodeid == peer) return true;
1153
+ }
1154
+
1155
+ return false;
1156
+ }
1157
+
1158
  void PeerManagerImpl::RemoveBlockRequest(const uint256& hash, std::optional<NodeId> from_peer)
1159
  {
1160
  auto range = mapBlocksInFlight.equal_range(hash);
 
1546
  if (NetPermissions::HasFlag(node.m_permission_flags, NetPermissionFlags::BloomFilter)) {
1547
  our_services = static_cast<ServiceFlags>(our_services | NODE_BLOOM);
1548
  }
1549
+ if (NetPermissions::HasFlag(node.m_permission_flags, NetPermissionFlags::BlockFilters)) {
1550
+ our_services = static_cast<ServiceFlags>(our_services | NODE_COMPACT_FILTERS);
1551
+ }
1552
 
1553
  PeerRef peer = std::make_shared<Peer>(nodeid, our_services, node.IsInboundConn());
1554
  {
 
1696
  if (queue.pindex)
1697
  stats.vHeightInFlight.push_back(queue.pindex->nHeight);
1698
  }
1699
+ stats.m_last_block_announcement = NodeSeconds{std::chrono::seconds{state->m_last_block_announcement}};
1700
  }
1701
 
1702
  PeerRef peer = GetPeerRef(nodeid);
 
1733
  }
1734
  }
1735
  stats.time_offset = peer->m_time_offset;
1736
+ stats.m_misbehavior_score = WITH_LOCK(peer->m_misbehavior_mutex, return peer->m_should_discourage) ? 100 : 0;
1737
 
1738
  return true;
1739
  }
 
1752
  };
1753
  }
1754
 
1755
+ void PeerManagerImpl::AddToCompactExtraTransactions(const CTransactionRef& tx, const size_t tx_dynamic_usage)
1756
  {
1757
  if (m_opts.max_extra_txs <= 0)
1758
  return;
1759
  if (!vExtraTxnForCompact.size())
1760
  vExtraTxnForCompact.resize(m_opts.max_extra_txs);
1761
+
1762
+ {
1763
+ auto& entry = vExtraTxnForCompact[vExtraTxnForCompactIt];
1764
+ if (entry) blockreconstructionextratxn_memusage -= RecursiveDynamicUsage(*entry);
1765
+ entry = tx;
1766
+ blockreconstructionextratxn_memusage += tx_dynamic_usage;
1767
+ }
1768
  vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
1769
+
1770
+ while (blockreconstructionextratxn_memusage > m_opts.max_extra_txs_size) {
1771
+ auto& entry = vExtraTxnForCompact[vExtraTxnForCompactIt];
1772
+ if (entry) blockreconstructionextratxn_memusage -= RecursiveDynamicUsage(*entry);
1773
+ entry.reset();
1774
+ vExtraTxnForCompactIt = (vExtraTxnForCompactIt + 1) % m_opts.max_extra_txs;
1775
+ }
1776
  }
1777
 
1778
  void PeerManagerImpl::Misbehaving(Peer& peer, const std::string& message)
 
1788
  );
1789
  }
1790
 
1791
+ static void HandleDoSPunishment(CConnman& connman, NodeId node_id, const int nDoS, const char * const what_is_it) {
1792
+ // We never actually DoS ban for invalid blocks, merely disconnect nodes if we're relying on them as a primary node
1793
+ const std::string msg = strprintf("peer=%d got DoS score %d on invalid %s", node_id, nDoS, what_is_it);
1794
+ connman.ForNode(node_id, [msg](CNode* node) {
1795
+ if (node->PunishInvalidBlocks()) {
1796
+ LogDebug(BCLog::NET, "%s; simply disconnecting\n", msg);
1797
+ node->fDisconnect = true;
1798
+ } else {
1799
+ LogDebug(BCLog::NET, "%s; tolerating\n", msg);
1800
+ }
1801
+ return true;
1802
+ });
1803
+ }
1804
+
1805
  void PeerManagerImpl::MaybePunishNodeForBlock(NodeId nodeid, const BlockValidationState& state,
1806
  bool via_compact_block, const std::string& message)
1807
  {
 
1808
  switch (state.GetResult()) {
1809
  case BlockValidationResult::BLOCK_RESULT_UNSET:
1810
  break;
 
1816
  case BlockValidationResult::BLOCK_CONSENSUS:
1817
  case BlockValidationResult::BLOCK_MUTATED:
1818
  if (!via_compact_block) {
1819
+ HandleDoSPunishment(m_connman, nodeid, 100, "block");
1820
  return;
1821
  }
1822
  break;
 
1824
  {
1825
  // Discourage outbound (but not inbound) peers if on an invalid chain.
1826
  // Exempt HB compact block peers. Manual connections are always protected from discouragement.
1827
+ if (!via_compact_block) {
1828
+ HandleDoSPunishment(m_connman, nodeid, 100, "block");
1829
  return;
1830
  }
1831
  break;
 
1833
  case BlockValidationResult::BLOCK_INVALID_HEADER:
1834
  case BlockValidationResult::BLOCK_CHECKPOINT:
1835
  case BlockValidationResult::BLOCK_INVALID_PREV:
1836
+ HandleDoSPunishment(m_connman, nodeid, 100, "block header");
1837
  return;
1838
  // Conflicting (but not necessarily invalid) data or different policy:
1839
  case BlockValidationResult::BLOCK_MISSING_PREV:
1840
+ HandleDoSPunishment(m_connman, nodeid, 100, "block header");
1841
  return;
1842
  case BlockValidationResult::BLOCK_TIME_FUTURE:
1843
  break;
 
1856
  (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_chainparams.GetConsensus()) < STALE_RELAY_AGE_LIMIT);
1857
  }
1858
 
1859
+ std::optional<std::string> PeerManagerImpl::FetchBlock(NodeId peer_id, const uint256& hash, const CBlockIndex* block_index)
1860
  {
1861
  if (m_chainman.m_blockman.LoadingBlocks()) return "Loading blocks ...";
1862
 
 
1869
 
1870
  LOCK(cs_main);
1871
 
1872
+ if (IsBlockRequestedFromPeer(hash, peer_id)) return "Already requested from this peer";
 
1873
 
1874
+ // Mark block as in-flight unless we don't have the header.
1875
+ if (block_index != nullptr) {
1876
+ // Forget about all prior requests
1877
+ RemoveBlockRequest(hash, std::nullopt);
1878
+
1879
+ // Mark block as in-flight
1880
+ Assume(BlockRequested(peer_id, *block_index));
1881
+ }
1882
 
1883
  // Construct message to request the block
 
1884
  std::vector<CInv> invs{CInv(MSG_BLOCK | MSG_WITNESS_FLAG, hash)};
1885
 
1886
  // Send block request message to the peer
 
1896
  return std::nullopt;
1897
  }
1898
 
1899
+ std::optional<std::string> PeerManager::FetchBlock(NodeId peer_id, const CBlockIndex& block_index)
1900
+ {
1901
+ const uint256& hash{block_index.GetBlockHash()};
1902
+ return FetchBlock(peer_id, hash, &block_index);
1903
+ }
1904
+
1905
  std::unique_ptr<PeerManager> PeerManager::make(CConnman& connman, AddrMan& addrman,
1906
  BanMan* banman, ChainstateManager& chainman,
1907
  CTxMemPool& pool, node::Warnings& warnings, Options opts)
 
1909
  return std::make_unique<PeerManagerImpl>(connman, addrman, banman, chainman, pool, warnings, opts);
1910
  }
1911
 
1912
+ static_assert(CORE_INCREMENTAL_RELAY_FEE < DEFAULT_INCREMENTAL_RELAY_FEE, "Trinary logic for m_fee_filter_rounder is based on assumption that CORE_INCREMENTAL_RELAY_FEE is less than DEFAULT_INCREMENTAL_RELAY_FEE");
1913
  PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman,
1914
  BanMan* banman, ChainstateManager& chainman,
1915
  CTxMemPool& pool, node::Warnings& warnings, Options opts)
1916
  : m_rng{opts.deterministic_rng},
1917
+ m_fee_filter_rounder{CFeeRate{pool.m_opts.incremental_relay_feerate.GetFeePerK() < DEFAULT_INCREMENTAL_RELAY_FEE ? CORE_INCREMENTAL_RELAY_FEE : DEFAULT_INCREMENTAL_RELAY_FEE}, m_rng},
1918
  m_chainparams(chainman.GetParams()),
1919
  m_connman(connman),
1920
  m_addrman(addrman),
 
2267
  }
2268
  // disconnect node in case we have reached the outbound limit for serving historical blocks
2269
  if (m_connman.OutboundTargetReached(true) &&
2270
+ (((m_chainman.m_best_header != nullptr) && (m_chainman.m_best_header->GetBlockTime() - pindex->GetBlockTime() > HISTORICAL_BLOCK_AGE)) || inv.IsMsgFilteredBlk() || inv.IsMsgFilteredWitnessBlk()) &&
2271
  !pfrom.HasPermission(NetPermissionFlags::Download) // nodes with the download permission may exceed target
2272
  ) {
2273
  LogDebug(BCLog::NET, "historical block serving limit reached, %s\n", pfrom.DisconnectMsg(fLogIPs));
 
2330
  MakeAndPushMessage(pfrom, NetMsgType::BLOCK, TX_NO_WITNESS(*pblock));
2331
  } else if (inv.IsMsgWitnessBlk()) {
2332
  MakeAndPushMessage(pfrom, NetMsgType::BLOCK, TX_WITH_WITNESS(*pblock));
2333
+ } else if (inv.IsMsgFilteredBlk() || inv.IsMsgFilteredWitnessBlk()) {
2334
  bool sendMerkleBlock = false;
2335
  CMerkleBlock merkleBlock;
2336
  if (auto tx_relay = peer.GetTxRelay(); tx_relay != nullptr) {
 
2348
  // they must either disconnect and retry or request the full block.
2349
  // Thus, the protocol spec specified allows for us to provide duplicate txn here,
2350
  // however we MUST always provide at least what the remote peer needs
2351
+ const auto maybe_with_witness = (inv.IsMsgFilteredWitnessBlk() ? TX_WITH_WITNESS : TX_NO_WITNESS);
2352
  typedef std::pair<unsigned int, uint256> PairType;
2353
  for (PairType& pair : merkleBlock.vMatchedTxn)
2354
+ MakeAndPushMessage(pfrom, NetMsgType::TX, maybe_with_witness(*pblock->vtx[pair.first]));
2355
  }
2356
  // else
2357
  // no response
 
2552
  // eventually get the headers - even from a different peer -
2553
  // we can use this peer to download.
2554
  WITH_LOCK(cs_main, UpdateBlockAvailability(pfrom.GetId(), headers.back().GetHash()));
2555
+
2556
+ if (pfrom.PunishInvalidBlocks()) {
2557
+ pfrom.fDisconnect = true;
2558
+ }
2559
  }
2560
 
2561
  bool PeerManagerImpl::CheckHeadersAreContinuous(const std::vector<CBlockHeader>& headers) const
 
3012
 
3013
  const auto& [add_extra_compact_tx, unique_parents, package_to_validate] = m_txdownloadman.MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
3014
 
3015
+ const size_t tx_dynamic_usage{RecursiveDynamicUsage(*ptx)};
3016
+ if (add_extra_compact_tx && tx_dynamic_usage < BLOCK_RECONSTRUCTION_EXTRA_TXN_PER_TXN_SIZE_LIMIT) {
3017
+ AddToCompactExtraTransactions(ptx, tx_dynamic_usage);
3018
  }
3019
  for (const Txid& parent_txid : unique_parents) {
3020
  if (peer) AddKnownTx(*peer, parent_txid);
 
3040
  RelayTransaction(tx->GetHash(), tx->GetWitnessHash());
3041
 
3042
  for (const CTransactionRef& removedTx : replaced_transactions) {
3043
+ const size_t tx_dynamic_usage{RecursiveDynamicUsage(*removedTx)};
3044
+ AddToCompactExtraTransactions(removedTx, tx_dynamic_usage);
3045
  }
3046
  }
3047
 
 
3471
  if (!vRecv.empty()) {
3472
  std::string strSubVer;
3473
  vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH);
3474
+ cleanSubVer = SanitizeString(strSubVer, SAFE_CHARS_PRINTABLE);
3475
  }
3476
  if (!vRecv.empty()) {
3477
  vRecv >> starting_height;
 
3500
  // Change version
3501
  const int greatest_common_version = std::min(nVersion, PROTOCOL_VERSION);
3502
  pfrom.SetCommonVersion(greatest_common_version);
3503
+ {
3504
+ LOCK(pfrom.m_subver_mutex);
3505
+ pfrom.cleanSubVer = cleanSubVer;
3506
+ }
3507
  pfrom.nVersion = nVersion;
3508
 
3509
  if (greatest_common_version >= WTXID_RELAY_VERSION) {
 
3522
  pfrom.m_has_all_wanted_services = HasAllDesirableServiceFlags(nServices);
3523
  peer->m_their_services = nServices;
3524
  pfrom.SetAddrLocal(addrMe);
 
 
 
 
3525
  peer->m_starting_height = starting_height;
3526
 
3527
  // Only initialize the Peer::TxRelay m_relay_txs data structure if:
 
3607
  }
3608
 
3609
  const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
3610
+ LogDebug(BCLog::NET, "receive version message: %s: version %d, blocks=%d, us=%s, txrelay=%d, peer=%d%s%s%s\n",
3611
+ SanitizeString(cleanSubVer, SAFE_CHARS_DEFAULT, true), pfrom.nVersion,
3612
  peer->m_starting_height, addrMe.ToStringAddrPort(), fRelay, pfrom.GetId(),
3613
+ fLogIPs ? "," : "", pfrom.LogIP(fLogIPs),
3614
+ (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
3615
 
3616
  peer->m_time_offset = NodeSeconds{std::chrono::seconds{nTime}} - Now<NodeSeconds>();
3617
  if (!pfrom.IsInboundConn()) {
 
3651
  // can be triggered by an attacker at high rate.
3652
  if (!pfrom.IsInboundConn() || LogAcceptCategory(BCLog::NET, BCLog::Level::Debug)) {
3653
  const auto mapped_as{m_connman.GetMappedAS(pfrom.addr)};
3654
+ LogPrintf("New %s %s peer connected: version: %d, blocks=%d, peer=%d%s%s%s\n",
3655
  pfrom.ConnectionTypeAsString(),
3656
  TransportTypeAsString(pfrom.m_transport->GetInfo().transport_type),
3657
  pfrom.nVersion.load(), peer->m_starting_height,
3658
+ pfrom.GetId(),
3659
+ fLogIPs ? "," : "", pfrom.LogIP(fLogIPs),
3660
  (mapped_as ? strprintf(", mapped_as=%d", mapped_as) : ""));
3661
  }
3662
 
 
4939
 
4940
  if (pnode.HasPermission(NetPermissionFlags::NoBan)) {
4941
  // We never disconnect or discourage peers for bad behavior if they have NetPermissionFlags::NoBan permission
4942
+ LogWarning("Not punishing noban peer %d!", peer.m_id);
4943
  return false;
4944
  }
4945
 
4946
  if (pnode.IsManualConn()) {
4947
  // We never disconnect or discourage manual peers for bad behavior
4948
+ LogWarning("Not punishing manually connected peer %d!", peer.m_id);
4949
  return false;