Skip to content

fix: route getdata requests to the peer that sent the inv#527

Merged
xdustinface merged 1 commit intov0.42-devfrom
fix/getdata-peer-routing
Mar 17, 2026
Merged

fix: route getdata requests to the peer that sent the inv#527
xdustinface merged 1 commit intov0.42-devfrom
fix/getdata-peer-routing

Conversation

@xdustinface
Copy link
Copy Markdown
Collaborator

@xdustinface xdustinface commented Mar 12, 2026

We currently just randomly distribute getdata requests which leads to issues where we request inventory x, which we received from peer A, from peer B which doesn't have it (yet).

This is especially a problem in the coming mempool support PR.

This PR:

  • adds SendToPeer variant to NetworkRequest and adjusts request_inventory in RequestSender to accept a peer. The request processing falls back to distributed send if the target peer disconnects.
  • adjusts the instantsend and chainlock inv->getdata flows.

Summary by CodeRabbit

  • New Features

    • Send network messages directly to a specific peer with automatic fallback to distributed sending if that peer is unavailable.
    • Inventory requests now route via per-peer messaging so inventory queries target a chosen peer.
  • Tests

    • Improved test robustness by tightening pattern validation for network request handling.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 12, 2026

📝 Walkthrough

Walkthrough

Adds a per-peer send path: a new NetworkRequest::SendMessageToPeer(NetworkMessage, SocketAddr) and handler in the network manager that attempts a direct send to the specified peer (spawning a task), falling back to the existing distributed send when the peer is not connected. request_inventory now accepts a peer address.

Changes

Cohort / File(s) Summary
Network Request Handler
dash-spv/src/network/manager.rs
Adds handling for SendMessageToPeer that clones the manager, spawns an async task to send to a specific peer if connected, and falls back to distributed send; adds logging for send, fallback, and errors.
Network API & Helpers
dash-spv/src/network/mod.rs
Adds public enum variant SendMessageToPeer(NetworkMessage, SocketAddr) to NetworkRequest; introduces private send_message_to_peer helper; updates request_inventory signature to accept a peer_address and route via the helper.
Inventory Call Sites
dash-spv/src/sync/chainlock/sync_manager.rs, dash-spv/src/sync/instantsend/sync_manager.rs
Updates calls to request_inventory to pass msg.peer_address() as the second argument.
Tests / Filters
dash-spv/src/sync/filters/pipeline.rs
Makes a test pattern match more robust by guarding the expected SendMessage variant and panicking if the request variant differs.

Sequence Diagram(s)

sequenceDiagram
    actor Requester
    participant NetworkManager
    participant PeerConn as PeerConnection
    participant Distrib as DistributedSend

    Requester->>NetworkManager: NetworkRequest::SendMessageToPeer(msg, addr)
    NetworkManager->>PeerConn: check connection(addr)
    alt peer connected
        NetworkManager->>PeerConn: send(msg) (spawned task)
        PeerConn-->>NetworkManager: send result / ok or error
    else peer disconnected
        NetworkManager->>Distrib: DistributedSend(msg)
        Distrib-->>NetworkManager: broadcast result
    end
    NetworkManager-->>Requester: ack / log outcome
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped a message, swift and neat,
To one brave peer across the street,
If doors were closed I sent aloud,
A fallback shout to reach the crowd —
Thump thump 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing peer-targeted routing for getdata requests to match the peer that sent the inv, which is the core objective and primary implementation focus of this PR.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/getdata-peer-routing
📝 Coding Plan for PR comments
  • Generate coding plan

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
dash-spv/src/network/mod.rs (1)

45-90: ⚠️ Potential issue | 🟠 Major

Please add coverage for the new targeted request path.

This introduces new routing behavior, but the provided changes only update an unrelated pipeline test. At minimum, I'd add one unit test proving request_inventory() enqueues NetworkRequest::SendMessageToPeer, and one network-level test covering the fallback path when the target peer disappears. As per coding guidelines, "Write unit tests for new functionality in Rust code" and "Write integration tests for network operations in Rust code".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@dash-spv/src/network/mod.rs` around lines 45 - 90, Add tests covering the new
targeted request path: (1) a unit test for RequestSender::request_inventory that
creates an mpsc::unbounded_channel, constructs a RequestSender, calls
request_inventory(..., peer_address) and asserts the receiver gets
NetworkRequest::SendMessageToPeer(NetworkMessage::GetData(...), peer_address)
(use pattern matching to validate message payload and address); (2) a
network-level/integration test that simulates the target peer disappearing
(e.g., drop or unregister the peer in the test network harness) and then
verifies the fallback behavior (expect either a broadcast
NetworkRequest::SendMessage(NetworkMessage::GetData(...)) or whatever fallback
SendMessage variant your code should emit) by observing messages on the network
receiver; place the unit test alongside other RequestSender tests and the
integration test in the network tests suite so both send_message_to_peer and
request_inventory flows are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dash-spv/src/network/manager.rs`:
- Around line 794-807: The SendMessageToPeer branch only falls back when
get_peer() returns None, but if the peer disconnects during
send_message_to_peer() the error is logged and the message is dropped; change
the logic in the NetworkRequest::SendMessageToPeer handler (the async block that
calls get_peer, send_message_to_peer, and send_distributed) to treat
send_message_to_peer() errors caused by peer disconnect as a trigger to call
send_distributed(msg). Specifically, after calling
this.send_message_to_peer(&peer_address, &peer, msg).await, inspect the Err
variant and if it indicates the peer disconnected (or any send failure that
should cause redistribution) call this.send_distributed(msg).await before
logging final failure; ensure any ChainLock-related state like
requested_chainlocks is updated/cleared as currently done when using distributed
sends so the hash is not left stuck.

---

Outside diff comments:
In `@dash-spv/src/network/mod.rs`:
- Around line 45-90: Add tests covering the new targeted request path: (1) a
unit test for RequestSender::request_inventory that creates an
mpsc::unbounded_channel, constructs a RequestSender, calls
request_inventory(..., peer_address) and asserts the receiver gets
NetworkRequest::SendMessageToPeer(NetworkMessage::GetData(...), peer_address)
(use pattern matching to validate message payload and address); (2) a
network-level/integration test that simulates the target peer disappearing
(e.g., drop or unregister the peer in the test network harness) and then
verifies the fallback behavior (expect either a broadcast
NetworkRequest::SendMessage(NetworkMessage::GetData(...)) or whatever fallback
SendMessage variant your code should emit) by observing messages on the network
receiver; place the unit test alongside other RequestSender tests and the
integration test in the network tests suite so both send_message_to_peer and
request_inventory flows are covered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c56685ec-ebf8-4a51-bc6a-81349a010f27

📥 Commits

Reviewing files that changed from the base of the PR and between d9d55ef and b7d2809.

📒 Files selected for processing (5)
  • dash-spv/src/network/manager.rs
  • dash-spv/src/network/mod.rs
  • dash-spv/src/sync/chainlock/sync_manager.rs
  • dash-spv/src/sync/filters/pipeline.rs
  • dash-spv/src/sync/instantsend/sync_manager.rs

Comment thread dash-spv/src/network/manager.rs
We currently just randomly distribute `getdata` requests which leads to issues where we request inventory `x`, which we received from peer `A`, from peer `B` which doesn't have it (yet).

This PR:
- adds `SendMessageToPeer` variant to `NetworkRequest` and adjusts `request_inventory` in `RequestSender` to accept a `peer`. The request processing falls back to distributed send if the target peer disconnects.
- adjusts the `instantsend` and `chainlock` `inv`->`getdata` flows.
@xdustinface xdustinface force-pushed the fix/getdata-peer-routing branch from b7d2809 to 7b304f9 Compare March 12, 2026 16:34
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@dash-spv/src/network/manager.rs`:
- Around line 797-817: The retry path currently calls send_distributed after
send_message_to_peer fails or the peer is missing, but send_distributed rebuilds
candidates from the full pool and can pick the same stale peer; add a new helper
(e.g., build_distributed_candidates_excluding) that mirrors how send_distributed
builds its candidate list but filters out the original peer_address before
selection, then update the failure branches (the Err branch in the
send_message_to_peer match and the None branch) to call this new helper or a
wrapper that invokes send_distributed with the filtered candidate list so the
failed peer is excluded from the fallback retry.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f9b757cb-2ef4-49d6-a981-41936e3f8f2f

📥 Commits

Reviewing files that changed from the base of the PR and between b7d2809 and 7b304f9.

📒 Files selected for processing (5)
  • dash-spv/src/network/manager.rs
  • dash-spv/src/network/mod.rs
  • dash-spv/src/sync/chainlock/sync_manager.rs
  • dash-spv/src/sync/filters/pipeline.rs
  • dash-spv/src/sync/instantsend/sync_manager.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • dash-spv/src/sync/filters/pipeline.rs
  • dash-spv/src/sync/chainlock/sync_manager.rs

Comment thread dash-spv/src/network/manager.rs
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 12, 2026

Codecov Report

❌ Patch coverage is 2.77778% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.86%. Comparing base (d9d55ef) to head (7b304f9).
⚠️ Report is 23 commits behind head on v0.42-dev.

Files with missing lines Patch % Lines
dash-spv/src/network/manager.rs 0.00% 19 Missing ⚠️
dash-spv/src/network/mod.rs 0.00% 15 Missing ⚠️
dash-spv/src/sync/filters/pipeline.rs 50.00% 1 Missing ⚠️
Additional details and impacted files
@@              Coverage Diff              @@
##           v0.42-dev     #527      +/-   ##
=============================================
- Coverage      66.92%   66.86%   -0.07%     
=============================================
  Files            313      313              
  Lines          64729    64762      +33     
=============================================
- Hits           43322    43303      -19     
- Misses         21407    21459      +52     
Flag Coverage Δ *Carryforward flag
core 75.02% <ø> (ø)
dash-network 75.00% <ø> (ø) Carriedforward from d9d55ef
dash-network-ffi 34.76% <ø> (ø) Carriedforward from d9d55ef
dash-spv 68.27% <ø> (+<0.01%) ⬆️ Carriedforward from d9d55ef
dash-spv-ffi 34.76% <ø> (ø) Carriedforward from d9d55ef
dashcore 75.00% <ø> (ø) Carriedforward from d9d55ef
dashcore-private 75.00% <ø> (ø) Carriedforward from d9d55ef
dashcore-rpc 19.92% <ø> (ø) Carriedforward from d9d55ef
dashcore-rpc-json 19.92% <ø> (ø) Carriedforward from d9d55ef
dashcore_hashes 75.00% <ø> (ø) Carriedforward from d9d55ef
ffi 36.38% <ø> (-0.02%) ⬇️
key-wallet 65.65% <ø> (ø) Carriedforward from d9d55ef
key-wallet-ffi 34.76% <ø> (ø) Carriedforward from d9d55ef
key-wallet-manager 65.65% <ø> (ø) Carriedforward from d9d55ef
rpc 19.92% <ø> (ø)
spv 80.81% <2.77%> (-0.28%) ⬇️
wallet 65.68% <ø> (ø)

*This pull request uses carry forward flags. Click here to find out more.

Files with missing lines Coverage Δ
dash-spv/src/sync/chainlock/sync_manager.rs 48.38% <ø> (ø)
dash-spv/src/sync/instantsend/sync_manager.rs 57.69% <ø> (ø)
dash-spv/src/sync/filters/pipeline.rs 97.65% <50.00%> (-0.17%) ⬇️
dash-spv/src/network/mod.rs 49.36% <0.00%> (-9.73%) ⬇️
dash-spv/src/network/manager.rs 57.22% <0.00%> (-0.95%) ⬇️

... and 15 files with indirect coverage changes

@xdustinface xdustinface requested a review from ZocoLini March 12, 2026 17:37
"Target peer {} disconnected, falling back to distributed send",
peer_address
);
this.send_distributed(fallback_msg).await
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In the SendMessage branch we are using the following logic:

let result = match &msg {
                                        // Distribute across peers for parallel sync
                                        NetworkMessage::GetCFHeaders(_)
                                        | NetworkMessage::GetCFilters(_)
                                        | NetworkMessage::GetData(_)
                                        | NetworkMessage::GetMnListD(_)
                                        | NetworkMessage::GetQRInfo(_)
                                        | NetworkMessage::GetHeaders(_)
                                        | NetworkMessage::GetHeaders2(_) => {
                                            this.send_distributed(msg).await
                                        }
                                        _ => {
                                            this.send_to_single_peer(msg).await
                                        }

more specifically, the Inv message triggers the send_to_single_peer path but you are calling send_distributed

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yeah but there is no reason for the other messages to be sent "to a single peer" instead of following the same round robin distribution. There are still few things that im working on cleaning up here. Its okay like this for now.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure this is correct either... if we ask to send to a peer, but the peer doesn't exist, it seems weird to send to the network.

Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Looking

Copy link
Copy Markdown
Member

@QuantumExplorer QuantumExplorer left a comment

Choose a reason for hiding this comment

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

Added a comment.

@xdustinface xdustinface merged commit 0c0920c into v0.42-dev Mar 17, 2026
59 checks passed
@xdustinface xdustinface deleted the fix/getdata-peer-routing branch March 17, 2026 11:37
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.

3 participants