Skip to content

fix: penalize oversized notfound messages#7348

Open
thepastaclaw wants to merge 4 commits into
dashpay:developfrom
thepastaclaw:fix/notfound-oversized-penalty
Open

fix: penalize oversized notfound messages#7348
thepastaclaw wants to merge 4 commits into
dashpay:developfrom
thepastaclaw:fix/notfound-oversized-penalty

Conversation

@thepastaclaw

Copy link
Copy Markdown

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:

    ./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

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • 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)

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 922caf3c-3b1f-403b-96eb-986ce26c11a2

📥 Commits

Reviewing files that changed from the base of the PR and between 641f39b and 56666e9.

📒 Files selected for processing (1)
  • test/functional/p2p_tx_download.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/functional/p2p_tx_download.py

Walkthrough

This PR adds a defensive validation layer to NOTFOUND message processing. PeerManagerImpl now reads the incoming NOTFOUND vInv and rejects it immediately (Misbehaving score 10) if its size exceeds MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER; otherwise it proceeds with the existing per-inventory cleanup for known types. A functional test sends an oversized NOTFOUND and asserts the misbehavior log entry.

Sequence Diagram(s)

sequenceDiagram
  participant RemotePeer
  participant PeerManager
  participant Node
  RemotePeer->>PeerManager: SEND msg_notfound (vInv)
  PeerManager->>PeerManager: read vInv and compute size
  alt size > MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER
    PeerManager->>Node: Misbehaving(peer, score=10)
    Note right of PeerManager: return early
  else size within limits
    PeerManager->>PeerManager: iterate vInv, erase m_object_in_flight/announced entries
    PeerManager->>RemotePeer: continue normal processing
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • UdjinM6
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: penalize oversized notfound messages' directly and clearly summarizes the main change: adding penalty/misbehavior scoring for oversized notfound inventory messages.
Description check ✅ Passed The description comprehensively explains the issue, the solution implemented, testing approach, and breaking changes—all directly related to the changeset of penalizing oversized notfound messages.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/functional/p2p_tx_download.py (1)

147-149: ⚡ Quick win

Avoid hardcoded oversized-count literals in this test.

+ 17 and "notfound message size = 117" bake in current protocol limits. Derive both from named constants so this stays valid if limits change.

Suggested refactor
     def test_oversized_notfound(self):
         self.log.info('Check that oversized notfound increases misbehavior score')
-        invs = [CInv(t=1, h=i) for i in range(MAX_GETDATA_IN_FLIGHT + 17)]
-        with self.nodes[0].assert_debug_log(["Misbehaving", "notfound message size = 117"]):
+        oversized_count = MAX_GETDATA_IN_FLIGHT + 17  # 1 above current C++ notfound limit path
+        invs = [CInv(t=1, h=i) for i in range(oversized_count)]
+        with self.nodes[0].assert_debug_log(["Misbehaving", f"notfound message size = {oversized_count}"]):
             self.nodes[0].p2ps[0].send_message(msg_notfound(vec=invs))
             self.nodes[0].p2ps[0].sync_with_ping()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/p2p_tx_download.py` around lines 147 - 149, Replace the
hardcoded "+ 17" and "117" by deriving both values from named constants and the
actual serialized message size: introduce a small named constant (e.g.
EXTRA_NOTFOUND_INV_COUNT) and build invs as CInv(t=1, h=i) for i in
range(MAX_GETDATA_IN_FLIGHT + EXTRA_NOTFOUND_INV_COUNT); then compute the
expected debug string dynamically from the serialized notfound message (e.g.
expected = f"notfound message size = {len(msg_notfound(vec=invs).serialize())}"
or equivalent) and use that in self.nodes[0].assert_debug_log instead of the
literal "notfound message size = 117", keeping references to CInv,
MAX_GETDATA_IN_FLIGHT, msg_notfound and assert_debug_log to locate the changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/functional/p2p_tx_download.py`:
- Around line 147-149: Replace the hardcoded "+ 17" and "117" by deriving both
values from named constants and the actual serialized message size: introduce a
small named constant (e.g. EXTRA_NOTFOUND_INV_COUNT) and build invs as CInv(t=1,
h=i) for i in range(MAX_GETDATA_IN_FLIGHT + EXTRA_NOTFOUND_INV_COUNT); then
compute the expected debug string dynamically from the serialized notfound
message (e.g. expected = f"notfound message size =
{len(msg_notfound(vec=invs).serialize())}" or equivalent) and use that in
self.nodes[0].assert_debug_log instead of the literal "notfound message size =
117", keeping references to CInv, MAX_GETDATA_IN_FLIGHT, msg_notfound and
assert_debug_log to locate the changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 2220f6ad-bdbd-40da-920c-3278cc73bb3b

📥 Commits

Reviewing files that changed from the base of the PR and between 317917a and 641f39b.

📒 Files selected for processing (2)
  • src/net_processing.cpp
  • test/functional/p2p_tx_download.py

@thepastaclaw

Copy link
Copy Markdown
Author

Addressed CodeRabbit nitpick in follow-up commit: introduced named NOTFOUND-size constants and derived the oversized test count/assertion from those constants instead of hardcoded literals. Validation: test/functional/p2p_tx_download.py --timeout-factor=2.

@thepastaclaw

Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@thepastaclaw

Copy link
Copy Markdown
Author

CI follow-up: the only red check is linux64_multiprocess-test / Test source, and its GitHub check annotation says the hosted runner lost communication with the server. I could not fetch test failure logs, and gh run rerun --failed is blocked for my account because rerun requires repo admin rights. This looks like runner infrastructure rather than a code/test failure; maintainer rerun needed.

@thepastaclaw

Copy link
Copy Markdown
Author

CI is green after the CI-only empty rerun commit 3d6d17ea62. There is no code diff from the previously reviewed head, so the existing CodeRabbit/automation review remains applicable. Marking ready for review.

@thepastaclaw thepastaclaw marked this pull request as ready for review June 10, 2026 02:30
@thepastaclaw

thepastaclaw commented Jun 10, 2026

Copy link
Copy Markdown
Author

✅ Review complete (commit 3d6d17e)

@thepastaclaw thepastaclaw left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Small, focused fix that moves NOTFOUND deserialization out of cs_main and applies a misbehavior penalty when vInv exceeds the per-peer in-flight budget. Logic and lock ordering are correct, and the functional test exercises the new path. One minor consistency observation: the chosen penalty (10) is half of what sibling inventory-vector oversize checks use (20).

💬 1 nitpick(s)

Comment thread src/net_processing.cpp
Comment on lines +5469 to +5471
if (vInv.size() > MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
Misbehaving(pfrom.GetId(), 10, strprintf("notfound message size = %u", vInv.size()));
return;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💬 Nitpick: Misbehavior score of 10 is inconsistent with peer inventory-size penalties elsewhere

All other inventory-vector oversize checks in this file use a score of 20: inv (line 4294), getdata (line 4401), and headers (line 5107). Bitcoin Core's equivalent change for notfound (PR bitcoin#19606) also uses 20. The PR's stated goal is to match the defensive treatment used for other inventory-vector messages, so a value of 10 is asymmetric without an explicit rationale. Either align with the existing pattern, or add a brief comment explaining why notfound warrants a lower penalty.

Suggested change
if (vInv.size() > MAX_PEER_OBJECT_IN_FLIGHT + MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
Misbehaving(pfrom.GetId(), 10, strprintf("notfound message size = %u", vInv.size()));
return;
Misbehaving(pfrom.GetId(), 20, strprintf("notfound message size = %u", vInv.size()));

source: ['claude']

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant