-
Notifications
You must be signed in to change notification settings - Fork 7
feat: Introduce DashSpvClientInterface
#214
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis change introduces a command-driven architecture for the Dash SPV client, replacing signal-based shutdown with cancellation tokens and channel-based commands. A new Changes
Sequence Diagram(s)sequenceDiagram
participant App as Application
participant Client as DashSpvClient
participant Monitor as monitor_network<br/>(select loop)
participant Cmd as Command Handler
participant Net as Network/Messages
Note over App,Net: Old Flow (signal-based)
App->>Client: sync_to_tip()
Client->>Monitor: monitor_network()
rect rgb(200, 220, 255)
Monitor->>Net: Poll messages
Net-->>Monitor: Process
end
App->>+App: Ctrl-C received
App->>Client: stop()
Client-->>Monitor: Abort
Note over App,Net: New Flow (command-driven)
App->>App: Create shutdown_token<br/>& command_receiver
App->>+Client: run(command_receiver,<br/>shutdown_token)
Client->>Monitor: monitor_network(receiver, token)
rect rgb(240, 240, 240)
loop Select on multiplex
alt Command available
Monitor->>Cmd: Dequeue command
Cmd->>Cmd: handle_command()
rect rgb(220, 240, 220)
Cmd->>Monitor: Process & respond
end
else Cancellation signaled
Monitor->>Monitor: Token cancelled
Monitor-->>Client: Return
else Network message
Monitor->>Net: Process message
end
end
end
App->>App: Signal shutdown_token
Monitor-->>Client: Exit loop
Client-->>App: Return Result
Estimated Code Review Effort🎯 3 (Moderate) | ⏱️ ~40 minutes Areas requiring extra attention:
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
It works and generally LGTM. I'm able to access the MasternodeListEngine for quorum lookups in DET during and after sync. |
2340750 to
c586be9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (2)
dash-spv-ffi/src/client.rs (1)
889-895: Consider whether the unused command channel overhead is necessary in the FFI path.The FFI synchronization path creates an unbounded channel but never uses the
_command_sender. While this aligns with the newmonitor_networkAPI signature and prepares for future command support, it introduces unnecessary channel allocation overhead for a feature not yet used in the FFI layer.Consider one of these approaches:
- Document the intent: Add a comment explaining this prepares for future command-based FFI APIs
- Defer the change: Keep the old FFI monitor_network signature until commands are actually needed
- Accept the overhead: The unbounded channel allocation is minimal and acceptable for API consistency
Since this is a "Chill" review and the overhead is minimal, this is fine as-is if it simplifies the API surface.
dash-spv/src/main.rs (1)
633-633: Unused command sender creates unnecessary channel overhead.The
_command_senderis created but never used in the main CLI application. While this matches the newrun()API signature and prepares for future command-based interactions, it allocates an unbounded channel that serves no purpose currently.This is acceptable for API consistency, but consider documenting the intent:
+// Command channel for future interactive commands (sender currently unused) let (_command_sender, command_receiver) = tokio::sync::mpsc::unbounded_channel();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (11)
dash-spv-ffi/src/client.rs(1 hunks)dash-spv-ffi/src/error.rs(2 hunks)dash-spv/examples/filter_sync.rs(2 hunks)dash-spv/examples/simple_sync.rs(2 hunks)dash-spv/examples/spv_with_wallet.rs(2 hunks)dash-spv/src/client/interface.rs(1 hunks)dash-spv/src/client/mod.rs(1 hunks)dash-spv/src/client/queries.rs(4 hunks)dash-spv/src/client/sync_coordinator.rs(3 hunks)dash-spv/src/error.rs(2 hunks)dash-spv/src/main.rs(2 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T16:01:37.609Z
Learning: The mempool tracking infrastructure (UnconfirmedTransaction, MempoolState, configuration, and mempool_filter.rs) is fully implemented and integrated in the Dash SPV client as of this PR, including client logic, FFI APIs, and tests.
📚 Learning: 2025-06-26T16:01:37.609Z
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T16:01:37.609Z
Learning: The mempool tracking infrastructure (UnconfirmedTransaction, MempoolState, configuration, and mempool_filter.rs) is fully implemented and integrated in the Dash SPV client as of this PR, including client logic, FFI APIs, and tests.
Applied to files:
dash-spv/src/main.rsdash-spv/examples/filter_sync.rsdash-spv/examples/spv_with_wallet.rsdash-spv-ffi/src/client.rsdash-spv/src/client/sync_coordinator.rsdash-spv/src/client/interface.rs
📚 Learning: 2025-02-25T06:19:32.230Z
Learnt from: QuantumExplorer
Repo: dashpay/rust-dashcore PR: 51
File: dash/src/sml/masternode_list_entry/hash.rs:7-12
Timestamp: 2025-02-25T06:19:32.230Z
Learning: The `consensus_encode` method on `MasternodeListEntry` writing to a `Vec` buffer cannot fail, so using `.expect()` is appropriate rather than propagating the error with the `?` operator.
Applied to files:
dash-spv/src/client/queries.rs
📚 Learning: 2025-06-26T15:54:02.509Z
Learnt from: DCG-Claude
Repo: dashpay/rust-dashcore PR: 0
File: :0-0
Timestamp: 2025-06-26T15:54:02.509Z
Learning: The `StorageManager` trait in `dash-spv/src/storage/mod.rs` uses `&mut self` methods but is also `Send + Sync`, and implementations often use interior mutability for concurrency. This can be confusing, so explicit documentation should clarify thread-safety expectations and the rationale for the API design.
Applied to files:
dash-spv/src/client/interface.rs
🧬 Code graph analysis (4)
dash-spv/examples/filter_sync.rs (1)
dash-spv/src/network/manager.rs (1)
new(78-128)
dash-spv/src/client/queries.rs (1)
dash-spv/src/sync/sequential/manager.rs (1)
masternode_list_engine(202-206)
dash-spv/examples/spv_with_wallet.rs (2)
dash-spv/src/client/interface.rs (1)
new(56-60)dash-spv/src/network/manager.rs (1)
new(78-128)
dash-spv/src/client/interface.rs (3)
dash-spv-ffi/src/broadcast.rs (1)
dashcore(29-29)key-wallet/src/derivation.rs (1)
derive(88-90)dash-spv-ffi/src/client.rs (1)
new(81-85)
🔇 Additional comments (10)
dash-spv/src/client/queries.rs (3)
13-13: LGTM: Type safety improvements.The introduction of
LLMQTypeandQuorumHashsemantic types improves type safety over rawu8and&[u8; 32]types.Also applies to: 17-17
97-128: LGTM: Comprehensive error handling.The error handling provides detailed context for all failure cases (missing quorum, missing quorum type, missing masternode list) with appropriate logging and
SpvError::QuorumLookupErrormessages.
75-94: The clone operation is appropriate given the API design and usage pattern.The function's change from
Option<&QualifiedQuorumEntry>toResult<QualifiedQuorumEntry>is well-justified:
- API Design: Returning
Resultprovides better error context thanOption, which is essential when a quorum isn't found.- Ownership Requirements: The single call site (
sync_coordinator.rs:611) sends the result through a channel, requiring owned data regardless. Cloning is unavoidable in this pattern.- Call Frequency: Not in a hot path—called once per message in an async handler, not in tight validation loops.
While
QualifiedQuorumEntrycontains variable-sized data (vectors for signers/valid_members) and large signatures, the performance impact is negligible given the non-critical call context. The design trade-off (owned data for cleaner async/error handling) is sound.dash-spv/src/client/sync_coordinator.rs (4)
15-15: LGTM: Command-based interface integration.The updated
monitor_networksignature properly integrates the command receiver and cancellation token for the new command-based architecture.Also applies to: 23-24, 71-75
484-567: LGTM: Well-structured event loop multiplexing.The
tokio::select!block properly multiplexes command handling, network message processing, timeouts, and cancellation. The comprehensive error handling with categorization (Network, Storage, Validation errors) and continue-on-error semantics ensures resilience.
573-601: LGTM: Clean lifecycle management.The
runmethod provides clean lifecycle management by:
- Spawning the client monitoring task with the command receiver
- Spawning a separate shutdown signal handler
- Properly joining tasks and handling errors
- Ensuring
stop()is called on completion
603-621: LGTM: Clean command handler implementation.The
handle_commandmethod properly processes commands and returns results via the oneshot channel. The error context in theChannelFailureincludes all command parameters for debugging.dash-spv/src/client/interface.rs (3)
8-14: LGTM: Clean error handling abstraction.The type aliases and
receivehelper function provide a clean abstraction for mapping oneshot channel errors toSpvError::ChannelFailurewith context.
16-48: LGTM: Well-designed command pattern.The
DashSpvClientCommandenum and its implementations provide a clean command pattern:
- Encapsulates request parameters and response channel
sendmethod with proper error handlingDisplayimplementation for logging (correctly excludes the sender)
50-78: LGTM: Clean async interface with intentional public field.The
DashSpvClientInterfaceprovides a clean async interface for client queries. Thecommand_senderfield is marked public, which allows direct access if needed. If you prefer encapsulation, consider making it private and providing an accessor method, but the current design is acceptable for this use case.
This introduces a new interface for command based access to
DashSpvClientdata from within different threads without the need of any arcs/locks but instead via async channels.This was implemented as a more general alternative for #200 so for now it only contains
DashSpvClientInterface:: get_quorum_by_height.Example:
Summary by CodeRabbit
New Features
Bug Fixes
API Changes
✏️ Tip: You can customize this high-level summary in your review settings.