Skip to content

Commit 6a051f5

Browse files
Merge #7348: fix: penalize oversized notfound messages
a97b7b4 fix: align oversized notfound penalty (PastaClaw) a43a27f test: avoid hardcoded oversized notfound count (PastaClaw) f84962b fix: penalize oversized notfound messages (PastaClaw) Pull request description: # fix: penalize oversized notfound messages ## Issue being fixed or feature implemented Oversized `notfound` inventory vectors were ignored after deserialization. This change gives them a small misbehavior score, matching the defensive treatment used for other inventory-vector messages, and avoids holding `cs_main` while deserializing the vector. ## What was done? - Deserialize `notfound` inventory vectors before taking `cs_main`. - Return early with a small misbehavior score when a `notfound` vector exceeds the maximum outstanding object/block request count. - Add functional coverage for the oversized `notfound` path. ## How Has This Been Tested? Environment: macOS 15.6 arm64, local Dash Core autotools build from this branch. - `git diff --check` - Local build configured with: ```bash ./configure --without-gui --disable-bench --disable-fuzz-binary \ --disable-tests --disable-wallet ``` - `make -j8 src/dashd src/dash-cli` - Initial parallel build hit a generated dependency-file race while building `dash-cli`; `dashd` linked successfully. - `make -j1 src/dash-cli` - `test/functional/p2p_tx_download.py --cachedir=/tmp/dash_func_cache_notfound` ## Breaking Changes None. ## Checklist - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [ ] I have assigned this pull request to a milestone *(for repository code-owners and collaborators only)* ACKs for top commit: UdjinM6: utACK a97b7b4 Tree-SHA512: 35ff6b0b9e12e377e5600f4b0b2caee9582d0b4022dad04727fab54599807a5659c1837e43d30205386be34ce4dda33d4d9f687101ce67e8a694fb1a614d3914
2 parents 11f524b + a97b7b4 commit 6a051f5

2 files changed

Lines changed: 29 additions & 16 deletions

File tree

src/net_processing.cpp

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5451,24 +5451,27 @@ void PeerManagerImpl::ProcessMessage(
54515451
}
54525452
if (msg_type == NetMsgType::NOTFOUND) {
54535453
// Remove the NOTFOUND transactions from the peer
5454-
LOCK(cs_main);
5455-
CNodeState *state = State(pfrom.GetId());
54565454
std::vector<CInv> vInv;
54575455
vRecv >> vInv;
5458-
if (vInv.size() <= MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
5459-
for (CInv &inv : vInv) {
5460-
if (inv.IsKnownType()) {
5461-
// If we receive a NOTFOUND message for a txid we requested, erase
5462-
// it from our data structures for this peer.
5463-
auto in_flight_it = state->m_object_download.m_object_in_flight.find(inv);
5464-
if (in_flight_it == state->m_object_download.m_object_in_flight.end()) {
5465-
// Skip any further work if this is a spurious NOTFOUND
5466-
// message.
5467-
continue;
5468-
}
5469-
state->m_object_download.m_object_in_flight.erase(in_flight_it);
5470-
state->m_object_download.m_object_announced.erase(inv);
5456+
if (vInv.size() > MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
5457+
Misbehaving(pfrom.GetId(), 20, strprintf("notfound message size = %u", vInv.size()));
5458+
return;
5459+
}
5460+
5461+
LOCK(cs_main);
5462+
CNodeState *state = State(pfrom.GetId());
5463+
for (CInv &inv : vInv) {
5464+
if (inv.IsKnownType()) {
5465+
// If we receive a NOTFOUND message for a txid we requested, erase
5466+
// it from our data structures for this peer.
5467+
auto in_flight_it = state->m_object_download.m_object_in_flight.find(inv);
5468+
if (in_flight_it == state->m_object_download.m_object_in_flight.end()) {
5469+
// Skip any further work if this is a spurious NOTFOUND
5470+
// message.
5471+
continue;
54715472
}
5473+
state->m_object_download.m_object_in_flight.erase(in_flight_it);
5474+
state->m_object_download.m_object_announced.erase(inv);
54725475
}
54735476
}
54745477
return;

test/functional/p2p_tx_download.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ def on_getdata(self, message):
4040
MAX_GETDATA_RANDOM_DELAY = 2 # seconds
4141
INBOUND_PEER_TX_DELAY = 2 # seconds
4242
MAX_GETDATA_IN_FLIGHT = 100
43+
MAX_BLOCKS_IN_TRANSIT_PER_PEER = 16
44+
MAX_NOTFOUND_SIZE = MAX_GETDATA_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER
4345
TX_EXPIRY_INTERVAL = GETDATA_TX_INTERVAL * 10
4446

4547
# Python test constants
@@ -142,13 +144,21 @@ def test_spurious_notfound(self):
142144
self.log.info('Check that spurious notfound is ignored')
143145
self.nodes[0].p2ps[0].send_message(msg_notfound(vec=[CInv(1, 1)]))
144146

147+
def test_oversized_notfound(self):
148+
self.log.info('Check that oversized notfound increases misbehavior score')
149+
oversized_notfound_count = MAX_NOTFOUND_SIZE + 1
150+
invs = [CInv(t=1, h=i) for i in range(oversized_notfound_count)]
151+
with self.nodes[0].assert_debug_log(["Misbehaving", f"notfound message size = {oversized_notfound_count}"]):
152+
self.nodes[0].p2ps[0].send_message(msg_notfound(vec=invs))
153+
self.nodes[0].p2ps[0].sync_with_ping()
154+
145155
def run_test(self):
146156
self.wallet = MiniWallet(self.nodes[0])
147157
self.wallet.rescan_utxos()
148158

149159
# Run each test against new bitcoind instances, as setting mocktimes has long-term effects on when
150160
# the next trickle relay event happens.
151-
for test in [self.test_spurious_notfound, self.test_in_flight_max, self.test_inv_block, self.test_tx_requests]:
161+
for test in [self.test_spurious_notfound, self.test_oversized_notfound, self.test_in_flight_max, self.test_inv_block, self.test_tx_requests]:
152162
self.stop_nodes()
153163
self.start_nodes()
154164
self.connect_nodes(1, 0)

0 commit comments

Comments
 (0)