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. The two line-number columns refer to before and after.

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