Skip to content

Conversation

@lklimek
Copy link
Contributor

@lklimek lklimek commented Oct 6, 2025

Issue being fixed or feature implemented

For testing of DAPI, we need some tool

What was done?

Created dapi-grpc/examples/dap-cli

How Has This Been Tested?

On local devnet

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 added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • Adds a dapi-cli tool for interacting with DAPI over gRPC.
    • Core: fetch block hash by height, stream transactions (optionally hashes-only), subscribe to chain locks, monitor masternode updates, view masternode status.
    • Platform: get identity by public-key-hash (with proofs), get status, view protocol upgrade/state and vote status, broadcast & wait for state transitions, monitor transitions.
    • Configurable verbosity via CLI flag.
  • Chores

    • Adds CLI example to project config and updates package metadata and dev-dependencies.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 6, 2025

Walkthrough

Adds a new dapi-cli example under packages/dapi-grpc with a Clap/Tokio-based CLI for Core and Platform gRPC endpoints, many subcommands (core: block hash, transactions, masternode, chain locks; platform: identity, protocol, state transitions), centralized error types, and dev-dependency/Cargo metadata updates.

Changes

Cohort / File(s) Summary of Changes
Cargo metadata
packages/dapi-grpc/Cargo.toml
Adds [[example]] name = "dapi-cli" (path examples/dapi-cli/main.rs); adds a [dev-dependencies] block for many crates (dashcore, serde, tokio, ciborium, clap, tracing, etc.); updates package.metadata.cargo-machete.ignored to ["platform-version","futures-core","getrandom","tonic-prost-build"].
CLI entrypoint & errors
packages/dapi-grpc/examples/dapi-cli/main.rs, packages/dapi-grpc/examples/dapi-cli/error.rs
New async binary with global URL and verbosity options, tracing init, Clap routing; introduces CliResult and CliError enum with conversions and mapped error kinds.
Core command router
packages/dapi-grpc/examples/dapi-cli/core/mod.rs
Adds CoreCommand enum and dispatcher; exposes core submodules.
Core subcommands
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs, .../transactions.rs, .../masternode.rs, .../masternode_status.rs, .../chainlocks.rs
New command modules implementing gRPC flows: GetBlock (block hash + pretty JSON), streaming TransactionsWithProofs, Masternode list stream decoding, Masternode status lookup, and ChainLocks header subscription — each with a public Command struct and run async function.
Platform router
packages/dapi-grpc/examples/dapi-cli/platform/mod.rs
Adds PlatformCommand enum and dispatcher; exposes identity, protocol, and state_transition submodules.
Platform identity
packages/dapi-grpc/examples/dapi-cli/platform/identity.rs
Adds identity-by-public-key-hash command with optional proof, request/response handling, metadata and proof printing.
Platform protocol
packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs
Adds commands for protocol upgrade state, upgrade vote status, and get_status; builds versioned requests, decodes optional hex inputs, prints metadata/entries/proofs.
State transition router
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs
Adds StateTransitionCommand enum (Monitor, Workflow) and dispatcher.
State transition monitor
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs
Implements waiting for a state transition result by hash with optional proof; prints metadata, proof, or error information; exposes printer helpers.
State transition workflow
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs
Implements broadcast of hex-encoded state transition, computes SHA-256 hash, broadcasts, waits for result with timeout and optional proof, and prints outcomes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant CLI as dapi-cli
  participant Core as CoreClient (gRPC)
  participant Plat as PlatformClient (gRPC)
  Note over CLI: parse args, init tracing
  U->>CLI: run --url <addr> <Core|Platform> <subcommand>
  alt Core subcommand
    CLI->>Core: unary or streaming request (GetBlock/Transactions...)
    Core-->>CLI: response / stream
    CLI-->>U: formatted output / logs
  else Platform subcommand
    CLI->>Plat: unary or streaming request (GetStatus/Identity/StateTransition...)
    Plat-->>CLI: response / stream
    CLI-->>U: formatted output / proofs / logs
  end
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant CLI as dapi-cli (workflow)
  participant Plat as PlatformClient
  rect rgba(230,245,255,0.6)
  Note over CLI: Broadcast + Await Result (Workflow)
  U->>CLI: workflow --state-transition <HEX> --prove --timeout <s>
  CLI->>CLI: decode hex -> sha256(hash)
  CLI->>Plat: broadcastStateTransition(data)
  Plat-->>CLI: ack
  CLI->>Plat: waitForStateTransitionResult(hash, prove)
  alt Result::Proof
    Plat-->>CLI: Result(V0.Proof)
    CLI-->>U: print metadata + proof
  else Result::Error
    Plat-->>CLI: Result(V0.Error)
    CLI-->>U: print metadata + error
  else Result::None
    Plat-->>CLI: Result(V0.None)
    CLI-->>U: log no-result
  end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

Thump-thump, I hop to greet the new CLI,
Streams and proofs and hashes leap high.
I nibble logs, decode a hex delight,
Broadcast, await — then thump in the night.
A carrot for every clean, printed line 🥕

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "test(dapi): dapi-cli example in dapi-grpc" directly and accurately describes the primary change in the changeset. The title clearly identifies that a new dapi-cli example tool is being added to the dapi-grpc package, which aligns with the PR objectives to provide a testing tool for DAPI. The title is concise, specific, and avoids vague terminology or noise. While the title doesn't enumerate all the individual CLI subcommands (Core, Platform, StateTransition workflows, etc.), it appropriately summarizes the main deliverable at a high level, which is the addition of the example tool itself.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch test/dapi-cli

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
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: 2

🧹 Nitpick comments (10)
packages/dapi-grpc/Cargo.toml (2)

81-84: Gate the example on required features

Add required-features so dapi-cli only builds when these features are enabled (avoids breakage with --no-default-features).

 [[example]]
 name = "dapi-cli"
 path = "examples/dapi-cli/main.rs"
+required-features = ["core", "platform", "client"]

85-100: Align serde/serde_json versions across deps to reduce duplicates

Dev-deps use newer serde/serde_json than main deps. Align to a single workspace version to cut compile units and avoid subtle mismatches.

Please verify with cargo tree -d to confirm no duplicate serde/serde_json versions are pulled in for the example.

packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (1)

14-21: Add connect and RPC timeouts on the gRPC Endpoint

Prevents hangs on bad endpoints and improves UX for the CLI.

-    let channel = Channel::from_shared(url.to_string())
-        .map_err(|source| CliError::InvalidUrl {
-            url: url.to_string(),
-            source: Box::new(source),
-        })?
-        .connect()
-        .await?;
+    let channel = Channel::from_shared(url.to_string())
+        .map_err(|source| CliError::InvalidUrl {
+            url: url.to_string(),
+            source: Box::new(source),
+        })?
+        .connect_timeout(std::time::Duration::from_secs(5))
+        .timeout(std::time::Duration::from_secs(10))
+        .connect()
+        .await?;
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs (1)

46-51: Harden connection with Endpoint timeouts

Set connect and overall RPC timeouts to avoid indefinite waits on misconfigured URLs.

-    let channel = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
-        url: url.to_string(),
-        source: Box::new(source),
-    })?;
-    let mut client = PlatformClient::connect(channel).await?;
+    let endpoint = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
+        url: url.to_string(),
+        source: Box::new(source),
+    })?
+    .connect_timeout(Duration::from_secs(5))
+    .timeout(Duration::from_secs(30));
+    let mut client = PlatformClient::connect(endpoint).await?;
packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (1)

25-37: Optional: add tracing instrumentation on dispatcher.

Helps correlate which subcommand ran and with what URL.

+#[tracing::instrument(name = "platform_cli", skip(url), fields(url))]
 pub async fn run(url: &str, command: PlatformCommand) -> CliResult<()> {
packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (5)

36-41: DRY: factor client creation into a helper.

Client/channel setup is duplicated in 3 places. Centralize to reduce copy/paste and keep connection logic consistent. Also aligns with tonic best practices to encapsulate transport setup.

Apply these diffs:

@@
-    let channel = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
-        url: url.to_string(),
-        source: Box::new(source),
-    })?;
-    let mut client = PlatformClient::connect(channel).await?;
+    let mut client = platform_client(url).await?;
@@
-    let channel = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
-        url: url.to_string(),
-        source: Box::new(source),
-    })?;
-    let mut client = PlatformClient::connect(channel).await?;
+    let mut client = platform_client(url).await?;
@@
-    let channel = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
-        url: url.to_string(),
-        source: Box::new(source),
-    })?;
-    let mut client = PlatformClient::connect(channel).await?;
+    let mut client = platform_client(url).await?;

Add this helper in this module:

async fn platform_client(url: &str) -> CliResult<PlatformClient<Channel>> {
    let channel = Channel::from_shared(url.to_string()).map_err(|source| CliError::InvalidUrl {
        url: url.to_string(),
        source: Box::new(source),
    })?;
    let client = PlatformClient::connect(channel).await?;
    Ok(client)
}

Based on learnings (tonic 0.14.x patterns).

Also applies to: 112-117, 168-174


103-111: Hex UX: support 0x prefix and trim whitespace.

Makes input more forgiving without changing semantics.

-    let start_pro_tx_hash = if let Some(ref hash) = cmd.start_pro_tx_hash {
-        hex::decode(hash).map_err(|source| CliError::InvalidHash {
+    let start_pro_tx_hash = if let Some(ref hash) = cmd.start_pro_tx_hash {
+        let raw = hash.trim();
+        let hex_str = raw
+            .strip_prefix("0x")
+            .or_else(|| raw.strip_prefix("0X"))
+            .unwrap_or(raw);
+        hex::decode(hex_str).map_err(|source| CliError::InvalidHash {
             hash: hash.clone(),
             source,
         })?
     } else {
         Vec::new()
     };

26-27: Redundant default on boolean flags.

Booleans default to false; default_value_t = false can be dropped for brevity.

-    #[arg(long, default_value_t = false)]
+    #[arg(long)]
     pub prove: bool,

Also applies to: 92-93


89-90: Optional: bound count via clap value_parser.

Prevents excessively large requests; 0 still allowed for “server default.”

-    #[arg(long, default_value_t = 0)]
+    #[arg(long, default_value_t = 0, value_parser = clap::value_parser!(u32).range(0..=1000))]
     pub count: u32,

192-205: Deduplicate printing helpers across modules.

print_metadata and print_proof duplicate implementations in identity.rs. Extract to a shared helper (e.g., platform::pretty) and reuse.

Example new module (packages/dapi-grpc/examples/dapi-cli/platform/pretty.rs):

pub fn print_metadata(metadata: Option<&dapi_grpc::platform::v0::ResponseMetadata>) {
    if let Some(meta) = metadata {
        println!("ℹ️  Metadata:");
        println!("    height: {}", meta.height);
        println!("    core_chain_locked_height: {}", meta.core_chain_locked_height);
        println!("    epoch: {}", meta.epoch);
        println!("    protocol_version: {}", meta.protocol_version);
        println!("    chain_id: {}", meta.chain_id);
        println!("    time_ms: {}", meta.time_ms);
    }
}

pub fn print_proof(proof: &dapi_grpc::platform::v0::Proof) {
    println!("🔐 Proof received:");
    println!("    quorum_hash: {}", hex::encode_upper(&proof.quorum_hash));
    println!("    signature bytes: {}", proof.signature.len());
    println!("    grovedb_proof bytes: {}", proof.grovedb_proof.len());
    println!("    round: {}", proof.round);
}

Then:

use crate::platform::pretty::{print_metadata, print_proof};

And remove local duplicates here and in identity.rs.

Also applies to: 307-313

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6f9d9e and 1202c41.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • packages/dapi-grpc/Cargo.toml (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/masternode.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/core/transactions.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/error.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/main.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs (1 hunks)
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/dapi-grpc/examples/dapi-cli/core/masternode.rs
  • packages/dapi-grpc/examples/dapi-cli/core/mod.rs
  • packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs
  • packages/dapi-grpc/examples/dapi-cli/core/transactions.rs
  • packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs
  • packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/mod.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs
  • packages/dapi-grpc/examples/dapi-cli/platform/identity.rs
  • packages/dapi-grpc/examples/dapi-cli/main.rs
  • packages/dapi-grpc/examples/dapi-cli/error.rs
🧬 Code graph analysis (14)
packages/dapi-grpc/examples/dapi-cli/core/masternode.rs (5)
packages/wasm-drive-verify/src/voting/verify_contests_proof.rs (1)
  • ciborium (54-54)
packages/dapi-grpc/clients/core/v0/web/core_pb_service.d.ts (1)
  • CoreClient (139-209)
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1)
  • run (15-58)
packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (1)
  • run (18-83)
packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (1)
  • run (13-44)
packages/dapi-grpc/examples/dapi-cli/core/mod.rs (5)
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1)
  • run (15-58)
packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (1)
  • run (18-83)
packages/dapi-grpc/examples/dapi-cli/core/masternode.rs (1)
  • run (15-56)
packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (1)
  • run (13-44)
packages/dapi-grpc/examples/dapi-cli/core/transactions.rs (1)
  • run (22-115)
packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (3)
packages/dapi-grpc/clients/core/v0/web/core_pb_service.d.ts (1)
  • CoreClient (139-209)
packages/dapi-grpc/clients/core/v0/web/core_pb.d.ts (2)
  • BlockHeadersWithChainLocksRequest (511-536)
  • BlockHeaders (589-605)
packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1)
  • run (25-33)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs (3)
packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (1)
  • run (25-37)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs (1)
  • run (26-73)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs (1)
  • run (34-108)
packages/dapi-grpc/examples/dapi-cli/core/transactions.rs (3)
packages/dapi-grpc/clients/core/v0/web/core_pb_service.d.ts (1)
  • CoreClient (139-209)
packages/dapi-grpc/clients/core/v0/web/core_pb.d.ts (3)
  • TransactionsWithProofsRequest (653-686)
  • RawTransactions (782-798)
  • InstantSendLockMessages (806-822)
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1)
  • run (15-58)
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (3)
packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (1)
  • run (18-83)
packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (1)
  • run (13-44)
packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1)
  • run (25-33)
packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (2)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (10)
  • GetStatusResponseV0 (5548-5587)
  • GetStatusRequest (5482-5497)
  • GetProtocolVersionUpgradeStateRequest (3034-3049)
  • GetProtocolVersionUpgradeVoteStatusRequest (3197-3212)
  • GetProtocolVersionUpgradeStateRequestV0 (3056-3068)
  • Versions (3138-3152)
  • GetProtocolVersionUpgradeVoteStatusRequestV0 (3219-3239)
  • VersionSignals (3311-3325)
  • GetStatusRequestV0 (5504-5513)
  • ResponseMetadata (57-84)
packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (2)
  • print_metadata (90-103)
  • print_proof (105-111)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs (1)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs (4)
  • print_error_info (110-117)
  • print_proof_info (92-108)
  • print_response_metadata (75-90)
  • run (26-73)
packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs (3)
packages/dapi-grpc/clients/core/v0/web/core_pb_service.d.ts (1)
  • CoreClient (139-209)
packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1)
  • run (15-58)
packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1)
  • run (25-33)
packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (3)
packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (1)
  • run (31-35)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs (1)
  • run (16-21)
packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (3)
  • run_get_status (168-190)
  • run_upgrade_state (30-81)
  • run_upgrade_vote_status (96-166)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs (2)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (4)
  • WaitForStateTransitionResultRequestV0 (2769-2786)
  • WaitForStateTransitionResultRequest (2747-2762)
  • ResponseMetadata (57-84)
  • StateTransitionBroadcastError (97-117)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/workflow.rs (1)
  • run (34-108)
packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (2)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (3)
  • GetIdentityByPublicKeyHashRequestV0 (2459-2476)
  • GetIdentityByPublicKeyHashRequest (2437-2452)
  • ResponseMetadata (57-84)
packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (2)
  • print_metadata (192-205)
  • print_proof (307-313)
packages/dapi-grpc/examples/dapi-cli/main.rs (4)
packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1)
  • run (25-33)
packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (1)
  • run (31-35)
packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (1)
  • run (25-37)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs (1)
  • run (16-21)
packages/dapi-grpc/examples/dapi-cli/error.rs (1)
packages/wasm-drive-verify/src/voting/verify_contests_proof.rs (1)
  • ciborium (54-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: Rust packages (dapi-grpc) / Check each feature
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Unused dependencies
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build JS packages / Build JS
🔇 Additional comments (11)
packages/dapi-grpc/examples/dapi-cli/platform/state_transition/mod.rs (1)

8-21: State transition routing looks solid

Enum + dispatcher are clear; matches other modules. No issues.

packages/dapi-grpc/examples/dapi-cli/main.rs (1)

37-48: Tracing init is pragmatic

Env filter + verbosity mapping is fine for a CLI. No issues.

packages/dapi-grpc/examples/dapi-cli/core/block_hash.rs (1)

1-58: LGTM!

The block hash command implementation is well-structured with proper error handling, logging, and output formatting. The height validation, channel creation, and gRPC interaction patterns are consistent with other core commands in the CLI.

packages/dapi-grpc/examples/dapi-cli/core/chainlocks.rs (1)

1-83: LGTM!

The chain locks streaming command is well-implemented with clear user feedback, proper stream handling, and consistent error management. The use of count: 0 for unlimited streaming is appropriate, and the response variant handling is comprehensive.

packages/dapi-grpc/examples/dapi-cli/core/transactions.rs (1)

1-126: LGTM!

The transactions streaming command handles both full payloads and hash-only modes effectively. The stream processing logic is comprehensive, covering all response variants, and the hash_preview helper provides useful output for debugging.

packages/dapi-grpc/examples/dapi-cli/platform/identity.rs (1)

1-88: LGTM!

The identity command implementation properly handles hex decoding, channel creation, and response processing. The error handling and output formatting are appropriate for the CLI use case.

packages/dapi-grpc/examples/dapi-cli/core/masternode.rs (1)

1-158: LGTM!

The masternode streaming command is well-structured with proper CBOR deserialization, error handling that allows the stream to continue on decode failures, and comprehensive data structures that capture all relevant diff information. The summary output provides useful insights into masternode list changes.

packages/dapi-grpc/examples/dapi-cli/error.rs (1)

1-43: LGTM!

The CLI error surface is comprehensive and well-structured using thiserror. The error variants cover all necessary failure modes (URL validation, transport, CBOR decoding, state transitions, etc.) with appropriate context fields. The type alias CliResult<T> provides a convenient shorthand for consistency across the CLI.

packages/dapi-grpc/examples/dapi-cli/core/mod.rs (1)

1-33: LGTM!

The core module organization is clean and follows standard Rust CLI patterns. The CoreCommand enum provides a clear command structure, and the dispatch function properly routes to the appropriate submodule handlers.

packages/dapi-grpc/examples/dapi-cli/platform/state_transition/monitor.rs (1)

1-117: LGTM!

The state transition monitoring command is well-implemented with proper error handling and comprehensive output for both success and error cases. The helper functions are appropriately scoped with pub(super) for module-level sharing. The use of structured logging (info!, warn!) instead of println! provides better observability compared to other commands.

packages/dapi-grpc/examples/dapi-cli/platform/mod.rs (1)

9-23: Clap subcommand wiring looks correct.

Enum variants map cleanly: subcommand enums for Identity/StateTransition and Args structs for Protocol*.

Comment on lines +29 to +34
let status = GrpcStatus::try_from(response.status).unwrap_or(GrpcStatus::Unknown);
let pro_tx_hash = if response.pro_tx_hash.is_empty() {
"<unset>".to_string()
} else {
hex::encode(response.pro_tx_hash)
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Fix enum conversion: use from_i32, not try_from

Prost enums expose from_i32; TryFrom isn’t implemented by default and will not compile.

-    let status = GrpcStatus::try_from(response.status).unwrap_or(GrpcStatus::Unknown);
+    let status = GrpcStatus::from_i32(response.status).unwrap_or(GrpcStatus::Unknown);

🏁 Script executed:

#!/bin/bash
# Scan for similar enum conversions that may not compile
rg -nP --type=rust -C2 '\b::try_from\s*\(\s*response\.\w+\s*\)' examples

Length of output: 48


#!/bin/bash
# Rescan for enum conversions in Rust .rs files across the repo
rg -nP --type=rust -C2 'try_from\s*\(\s*response\.' --glob '*.rs' .

-->


🏁 Script executed:

#!/bin/bash
# Locate and preview imports in masternode_status.rs
echo "File path(s):"
fd -t f masternode_status.rs .
echo "---- File preview ----"
sed -n '1,50p' $(fd -t f masternode_status.rs .)

Length of output: 1716


Replace enum conversion: use from_i32, not try_from
Prost-generated enums provide from_i32; TryFrom<i32> isn’t implemented by default and will not compile.

-    let status = GrpcStatus::try_from(response.status).unwrap_or(GrpcStatus::Unknown);
+    let status = GrpcStatus::from_i32(response.status).unwrap_or(GrpcStatus::Unknown);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let status = GrpcStatus::try_from(response.status).unwrap_or(GrpcStatus::Unknown);
let pro_tx_hash = if response.pro_tx_hash.is_empty() {
"<unset>".to_string()
} else {
hex::encode(response.pro_tx_hash)
};
let status = GrpcStatus::from_i32(response.status).unwrap_or(GrpcStatus::Unknown);
let pro_tx_hash = if response.pro_tx_hash.is_empty() {
"<unset>".to_string()
} else {
hex::encode(response.pro_tx_hash)
};
🤖 Prompt for AI Agents
In packages/dapi-grpc/examples/dapi-cli/core/masternode_status.rs around lines
29 to 34, the code uses GrpcStatus::try_from(response.status) which won't
compile because prost enums expose from_i32 rather than TryFrom; replace the
conversion with
GrpcStatus::from_i32(response.status).unwrap_or(GrpcStatus::Unknown) (or
equivalent handling of the Option) so the integer status is converted via
from_i32 and defaults to Unknown when unrecognized.

Comment on lines +90 to +111
fn print_metadata(metadata: Option<&dapi_grpc::platform::v0::ResponseMetadata>) {
if let Some(meta) = metadata {
println!("ℹ️ Metadata:");
println!(" height: {}", meta.height);
println!(
" core_chain_locked_height: {}",
meta.core_chain_locked_height
);
println!(" epoch: {}", meta.epoch);
println!(" protocol_version: {}", meta.protocol_version);
println!(" chain_id: {}", meta.chain_id);
println!(" time_ms: {}", meta.time_ms);
}
}

fn print_proof(proof: &dapi_grpc::platform::v0::Proof) {
println!("🔐 Proof received:");
println!(" quorum_hash: {}", hex::encode_upper(&proof.quorum_hash));
println!(" signature bytes: {}", proof.signature.len());
println!(" grovedb_proof bytes: {}", proof.grovedb_proof.len());
println!(" round: {}", proof.round);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Extract duplicated helper functions to a shared module.

The print_metadata and print_proof functions are duplicated from packages/dapi-grpc/examples/dapi-cli/platform/protocol.rs (lines 191-204 and 306-312). To maintain DRY principles and ensure consistency, extract these helpers into a shared module within the platform directory.

Consider creating a shared helpers.rs or display.rs module in the platform directory:

Create packages/dapi-grpc/examples/dapi-cli/platform/helpers.rs:

use dapi_grpc::platform::v0::{Proof, ResponseMetadata};

pub fn print_metadata(metadata: Option<&ResponseMetadata>) {
    if let Some(meta) = metadata {
        println!("ℹ️  Metadata:");
        println!("    height: {}", meta.height);
        println!(
            "    core_chain_locked_height: {}",
            meta.core_chain_locked_height
        );
        println!("    epoch: {}", meta.epoch);
        println!("    protocol_version: {}", meta.protocol_version);
        println!("    chain_id: {}", meta.chain_id);
        println!("    time_ms: {}", meta.time_ms);
    }
}

pub fn print_proof(proof: &Proof) {
    println!("🔐 Proof received:");
    println!("    quorum_hash: {}", hex::encode_upper(&proof.quorum_hash));
    println!("    signature bytes: {}", proof.signature.len());
    println!("    grovedb_proof bytes: {}", proof.grovedb_proof.len());
    println!("    round: {}", proof.round);
}

Then update both identity.rs and protocol.rs to use:

use super::helpers::{print_metadata, print_proof};
🤖 Prompt for AI Agents
In packages/dapi-grpc/examples/dapi-cli/platform/identity.rs around lines 90-111
the print_metadata and print_proof helpers are duplicated from protocol.rs;
extract these two functions into a new shared module file
packages/dapi-grpc/examples/dapi-cli/platform/helpers.rs (exporting pub fn
print_metadata and pub fn print_proof with the same signatures and required
uses), remove the duplicate functions from identity.rs and protocol.rs, add a
mod declaration so the new helpers module is visible (e.g., mod helpers; or
adjust existing module layout), and import the functions where needed with use
super::helpers::{print_metadata, print_proof}; ensure any required imports
(dapi_grpc::platform::v0::{Proof, ResponseMetadata} and hex) are in the helpers
module.

Copy link
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: 0

🧹 Nitpick comments (1)
packages/dapi-grpc/Cargo.toml (1)

85-99: Verify serde version discrepancy between main and dev dependencies.

The dev-dependencies section specifies serde 1.0.228, while the main dependencies (line 46) use 1.0.219. Both are patch versions and shouldn't introduce breaking changes, but consider aligning them for consistency and simpler version management.

Additionally, dashcore is pinned to a specific git revision. This is acceptable for dev-only dependencies, but ensure the revision remains available in the upstream repository.

Consider updating the serde dev-dependency to match the main dependency version:

-serde = { version = "1.0.228", features = ["derive"] }
+serde = { version = "1.0.219", features = ["derive"] }

Alternatively, if 1.0.228 is intentional (e.g., to test forward compatibility), add a comment explaining the version choice.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1202c41 and 0b3806c.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • packages/dapi-grpc/Cargo.toml (1 hunks)
🔇 Additional comments (2)
packages/dapi-grpc/Cargo.toml (2)

81-83: Example configuration looks good.

The new dapi-cli example block follows standard conventions with a clear path reference to the entry point.


101-102: Cargo-machete ignored list updated appropriately.

The changes to the ignored list reflect the new build structure: adding getrandom (indirect tokio dependency) and tonic-prost-build (build-dependency), while removing serde_bytes and dapi-grpc-macros (no longer required by the example). This keeps cargo-machete checks aligned with actual dependency usage.

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