From 47700d64687194f339df6424159787acf4382379 Mon Sep 17 00:00:00 2001 From: thephez Date: Mon, 18 Aug 2025 12:51:58 -0400 Subject: [PATCH 1/4] fix(wasm-sdk): return actual network protocol version in getStatus Previously returned SDK's configured version (10) instead of network's actual protocol version (9). Now extracts protocol version from ExtendedEpochInfo to provide accurate, provable network data. --- packages/wasm-sdk/src/queries/system.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/wasm-sdk/src/queries/system.rs b/packages/wasm-sdk/src/queries/system.rs index e34d781fd7..baab87b73d 100644 --- a/packages/wasm-sdk/src/queries/system.rs +++ b/packages/wasm-sdk/src/queries/system.rs @@ -8,7 +8,7 @@ use dash_sdk::dpp::core_types::validator_set::v0::ValidatorSetV0Getters; #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct PlatformStatus { - version: u32, + version: Option, network: String, block_height: Option, core_height: Option, @@ -74,22 +74,23 @@ pub async fn get_status(sdk: &WasmSdk) -> Result { _ => "unknown", }.to_string(); - // Try to fetch current epoch info to get block heights - let (block_height, core_height) = match ExtendedEpochInfo::fetch_current(sdk.as_ref()).await { + // Try to fetch current epoch info to get block heights and protocol version + let (block_height, core_height, protocol_version) = match ExtendedEpochInfo::fetch_current(sdk.as_ref()).await { Ok(epoch_info) => { - // Extract heights from epoch info + // Extract heights and protocol version from epoch info let platform_height = Some(epoch_info.first_block_height()); let core_height = Some(epoch_info.first_core_block_height() as u64); - (platform_height, core_height) + let protocol_version = Some(epoch_info.protocol_version()); + (platform_height, core_height, protocol_version) } - Err(_) => { - // If we can't fetch epoch info, heights remain None - (None, None) + Err(_e) => { + // If we can't fetch epoch info, we don't know the current network state + (None, None, None) } }; let status = PlatformStatus { - version: sdk.version(), + version: protocol_version, network: network_str, block_height, core_height, From 2aeea0ff45eae0396aad64a3956370172b9d8481 Mon Sep 17 00:00:00 2001 From: thephez Date: Mon, 18 Aug 2025 16:28:30 -0400 Subject: [PATCH 2/4] feat(wasm-sdk): replace getStatus with gRPC endpoint implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace ExtendedEpochInfo-based getStatus with direct gRPC call to platform getStatus endpoint. Returns comprehensive status including version info, node details, chain state, network info, sync progress, and timestamps. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/wasm-sdk/src/queries/system.rs | 283 +++++++++++++++++++++--- 1 file changed, 247 insertions(+), 36 deletions(-) diff --git a/packages/wasm-sdk/src/queries/system.rs b/packages/wasm-sdk/src/queries/system.rs index baab87b73d..90d0d8999d 100644 --- a/packages/wasm-sdk/src/queries/system.rs +++ b/packages/wasm-sdk/src/queries/system.rs @@ -5,13 +5,103 @@ use serde::{Serialize, Deserialize}; use serde::ser::Serialize as _; use dash_sdk::dpp::core_types::validator_set::v0::ValidatorSetV0Getters; +// Response structures for the gRPC getStatus endpoint #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] -struct PlatformStatus { - version: Option, - network: String, - block_height: Option, - core_height: Option, +struct StatusResponse { + version: StatusVersion, + node: StatusNode, + chain: StatusChain, + network: StatusNetwork, + state_sync: StatusStateSync, + time: StatusTime, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusVersion { + software: StatusSoftware, + protocol: StatusProtocol, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusSoftware { + dapi: String, + drive: Option, + tenderdash: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusProtocol { + tenderdash: StatusTenderdashProtocol, + drive: StatusDriveProtocol, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusTenderdashProtocol { + p2p: u32, + block: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusDriveProtocol { + latest: u32, + current: u32, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusNode { + id: String, + pro_tx_hash: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusChain { + catching_up: bool, + latest_block_hash: String, + latest_app_hash: String, + latest_block_height: String, + earliest_block_hash: String, + earliest_app_hash: String, + earliest_block_height: String, + max_peer_block_height: String, + core_chain_locked_height: Option, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusNetwork { + chain_id: String, + peers_count: u32, + listening: bool, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusStateSync { + total_synced_time: String, + remaining_time: String, + total_snapshots: u32, + chunk_process_avg_time: String, + snapshot_height: String, + snapshot_chunks_count: String, + backfilled_blocks: String, + backfill_blocks_total: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +struct StatusTime { + local: String, + block: Option, + genesis: Option, + epoch: Option, } #[derive(Serialize, Deserialize, Debug)] @@ -61,39 +151,160 @@ struct PathElement { #[wasm_bindgen] pub async fn get_status(sdk: &WasmSdk) -> Result { - use dash_sdk::platform::fetch_current_no_parameters::FetchCurrent; - use dash_sdk::dpp::block::extended_epoch_info::ExtendedEpochInfo; - use dash_sdk::dpp::block::extended_epoch_info::v0::ExtendedEpochInfoV0Getters; - - // Get the network from SDK - let network_str = match sdk.network { - dash_sdk::dpp::dashcore::Network::Dash => "mainnet", - dash_sdk::dpp::dashcore::Network::Testnet => "testnet", - dash_sdk::dpp::dashcore::Network::Devnet => "devnet", - dash_sdk::dpp::dashcore::Network::Regtest => "regtest", - _ => "unknown", - }.to_string(); - - // Try to fetch current epoch info to get block heights and protocol version - let (block_height, core_height, protocol_version) = match ExtendedEpochInfo::fetch_current(sdk.as_ref()).await { - Ok(epoch_info) => { - // Extract heights and protocol version from epoch info - let platform_height = Some(epoch_info.first_block_height()); - let core_height = Some(epoch_info.first_core_block_height() as u64); - let protocol_version = Some(epoch_info.protocol_version()); - (platform_height, core_height, protocol_version) - } - Err(_e) => { - // If we can't fetch epoch info, we don't know the current network state - (None, None, None) - } + use dapi_grpc::platform::v0::get_status_request::{Version, GetStatusRequestV0}; + use dapi_grpc::platform::v0::GetStatusRequest; + use dash_sdk::RequestSettings; + use rs_dapi_client::DapiRequestExecutor; + + // Create the gRPC request + let request = GetStatusRequest { + version: Some(Version::V0(GetStatusRequestV0 {})), }; - let status = PlatformStatus { - version: protocol_version, - network: network_str, - block_height, - core_height, + // Execute the request + let response = sdk + .as_ref() + .execute(request, RequestSettings::default()) + .await + .map_err(|e| JsError::new(&format!("Failed to get status: {}", e)))?; + + // Parse the response + use dapi_grpc::platform::v0::get_status_response::Version as ResponseVersion; + + let v0_response = match response.inner.version { + Some(ResponseVersion::V0(v0)) => v0, + None => return Err(JsError::new("No version in GetStatus response")), + }; + + // Map the response to our StatusResponse structure + let status = StatusResponse { + version: StatusVersion { + software: StatusSoftware { + dapi: v0_response.version.as_ref() + .map(|v| v.software.as_ref()) + .flatten() + .map(|s| s.dapi.clone()) + .unwrap_or_else(|| "unknown".to_string()), + drive: v0_response.version.as_ref() + .and_then(|v| v.software.as_ref()) + .and_then(|s| s.drive.clone()), + tenderdash: v0_response.version.as_ref() + .and_then(|v| v.software.as_ref()) + .and_then(|s| s.tenderdash.clone()), + }, + protocol: StatusProtocol { + tenderdash: StatusTenderdashProtocol { + p2p: v0_response.version.as_ref() + .and_then(|v| v.protocol.as_ref()) + .and_then(|p| p.tenderdash.as_ref()) + .map(|t| t.p2p) + .unwrap_or(0), + block: v0_response.version.as_ref() + .and_then(|v| v.protocol.as_ref()) + .and_then(|p| p.tenderdash.as_ref()) + .map(|t| t.block) + .unwrap_or(0), + }, + drive: StatusDriveProtocol { + latest: v0_response.version.as_ref() + .and_then(|v| v.protocol.as_ref()) + .and_then(|p| p.drive.as_ref()) + .map(|d| d.latest) + .unwrap_or(0), + current: v0_response.version.as_ref() + .and_then(|v| v.protocol.as_ref()) + .and_then(|p| p.drive.as_ref()) + .map(|d| d.current) + .unwrap_or(0), + }, + }, + }, + node: StatusNode { + id: v0_response.node.as_ref() + .map(|n| hex::encode(&n.id)) + .unwrap_or_else(|| "unknown".to_string()), + pro_tx_hash: v0_response.node.as_ref() + .and_then(|n| n.pro_tx_hash.as_ref()) + .map(|hash| hex::encode(hash)), + }, + chain: StatusChain { + catching_up: v0_response.chain.as_ref() + .map(|c| c.catching_up) + .unwrap_or(false), + latest_block_hash: v0_response.chain.as_ref() + .map(|c| hex::encode(&c.latest_block_hash)) + .unwrap_or_else(|| "unknown".to_string()), + latest_app_hash: v0_response.chain.as_ref() + .map(|c| hex::encode(&c.latest_app_hash)) + .unwrap_or_else(|| "unknown".to_string()), + latest_block_height: v0_response.chain.as_ref() + .map(|c| c.latest_block_height.to_string()) + .unwrap_or_else(|| "0".to_string()), + earliest_block_hash: v0_response.chain.as_ref() + .map(|c| hex::encode(&c.earliest_block_hash)) + .unwrap_or_else(|| "unknown".to_string()), + earliest_app_hash: v0_response.chain.as_ref() + .map(|c| hex::encode(&c.earliest_app_hash)) + .unwrap_or_else(|| "unknown".to_string()), + earliest_block_height: v0_response.chain.as_ref() + .map(|c| c.earliest_block_height.to_string()) + .unwrap_or_else(|| "0".to_string()), + max_peer_block_height: v0_response.chain.as_ref() + .map(|c| c.max_peer_block_height.to_string()) + .unwrap_or_else(|| "0".to_string()), + core_chain_locked_height: v0_response.chain.as_ref() + .and_then(|c| c.core_chain_locked_height), + }, + network: StatusNetwork { + chain_id: v0_response.network.as_ref() + .map(|n| n.chain_id.clone()) + .unwrap_or_else(|| "unknown".to_string()), + peers_count: v0_response.network.as_ref() + .map(|n| n.peers_count) + .unwrap_or(0), + listening: v0_response.network.as_ref() + .map(|n| n.listening) + .unwrap_or(false), + }, + state_sync: StatusStateSync { + total_synced_time: v0_response.state_sync.as_ref() + .map(|s| s.total_synced_time.to_string()) + .unwrap_or_else(|| "0".to_string()), + remaining_time: v0_response.state_sync.as_ref() + .map(|s| s.remaining_time.to_string()) + .unwrap_or_else(|| "0".to_string()), + total_snapshots: v0_response.state_sync.as_ref() + .map(|s| s.total_snapshots) + .unwrap_or(0), + chunk_process_avg_time: v0_response.state_sync.as_ref() + .map(|s| s.chunk_process_avg_time.to_string()) + .unwrap_or_else(|| "0".to_string()), + snapshot_height: v0_response.state_sync.as_ref() + .map(|s| s.snapshot_height.to_string()) + .unwrap_or_else(|| "0".to_string()), + snapshot_chunks_count: v0_response.state_sync.as_ref() + .map(|s| s.snapshot_chunks_count.to_string()) + .unwrap_or_else(|| "0".to_string()), + backfilled_blocks: v0_response.state_sync.as_ref() + .map(|s| s.backfilled_blocks.to_string()) + .unwrap_or_else(|| "0".to_string()), + backfill_blocks_total: v0_response.state_sync.as_ref() + .map(|s| s.backfill_blocks_total.to_string()) + .unwrap_or_else(|| "0".to_string()), + }, + time: StatusTime { + local: v0_response.time.as_ref() + .map(|t| t.local.to_string()) + .unwrap_or_else(|| "0".to_string()), + block: v0_response.time.as_ref() + .and_then(|t| t.block) + .map(|b| b.to_string()), + genesis: v0_response.time.as_ref() + .and_then(|t| t.genesis) + .map(|g| g.to_string()), + epoch: v0_response.time.as_ref() + .and_then(|t| t.epoch), + }, }; serde_wasm_bindgen::to_value(&status) From c467b7c319620671339bab27ad9a2e8066c940da Mon Sep 17 00:00:00 2001 From: thephez Date: Mon, 18 Aug 2025 16:54:12 -0400 Subject: [PATCH 3/4] feat(wasm-sdk): add proof support indicators to UI and API definitions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add visual indicators for queries that don't support cryptographic proof verification, improving user understanding of query capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- packages/wasm-sdk/api-definitions.json | 5 +++++ packages/wasm-sdk/index.html | 21 +++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/packages/wasm-sdk/api-definitions.json b/packages/wasm-sdk/api-definitions.json index 67e39c11d6..4e959b3c52 100644 --- a/packages/wasm-sdk/api-definitions.json +++ b/packages/wasm-sdk/api-definitions.json @@ -848,6 +848,7 @@ "getEvonodesProposedEpochBlocksByIds": { "label": "Get Evonodes Proposed Epoch Blocks by IDs", "description": "Get proposed blocks by evonode IDs", + "supportsProof": false, "inputs": [ { "name": "epoch", @@ -867,6 +868,7 @@ "getEvonodesProposedEpochBlocksByRange": { "label": "Get Evonodes Proposed Epoch Blocks by Range", "description": "Get proposed blocks by range", + "supportsProof": false, "inputs": [ { "name": "epoch", @@ -1121,11 +1123,13 @@ "getStatus": { "label": "Get Status", "description": "Get system status", + "supportsProof": false, "inputs": [] }, "getCurrentQuorumsInfo": { "label": "Get Current Quorums Info", "description": "Get information about current quorums", + "supportsProof": false, "inputs": [] }, "getPrefundedSpecializedBalance": { @@ -1167,6 +1171,7 @@ "waitForStateTransitionResult": { "label": "Wait for State Transition Result", "description": "Internal query to wait for and retrieve the result of a previously submitted state transition", + "supportsProof": false, "inputs": [ { "name": "stateTransitionHash", diff --git a/packages/wasm-sdk/index.html b/packages/wasm-sdk/index.html index 93f8083832..a830f4dbad 100644 --- a/packages/wasm-sdk/index.html +++ b/packages/wasm-sdk/index.html @@ -161,6 +161,10 @@

Query Parameters

+ + @@ -4171,6 +4175,7 @@

Results

document.getElementById('queryType').style.display = 'none'; document.getElementById('queryInputs').style.display = 'none'; document.getElementById('proofToggleContainer').style.display = 'none'; + document.getElementById('noProofInfoContainer').style.display = 'none'; document.getElementById('executeQuery').style.display = 'none'; document.getElementById('queryDescription').style.display = 'none'; }); @@ -4190,6 +4195,7 @@

Results

// Hide inputs and button queryInputs.style.display = 'none'; document.getElementById('proofToggleContainer').style.display = 'none'; + document.getElementById('noProofInfoContainer').style.display = 'none'; executeButton.style.display = 'none'; queryDescription.style.display = 'none'; @@ -4364,12 +4370,22 @@

Results

queryInputs.style.display = 'block'; executeButton.style.display = 'block'; - // Show proof toggle for queries only + // Show proof toggle for queries that support proofs const proofToggleContainer = document.getElementById('proofToggleContainer'); + const noProofInfoContainer = document.getElementById('noProofInfoContainer'); if (operationType === 'queries') { - proofToggleContainer.style.display = 'block'; + // Check if query supports proof (defaults to true if not specified) + const supportsProof = definition?.supportsProof !== false; + if (supportsProof) { + proofToggleContainer.style.display = 'block'; + noProofInfoContainer.style.display = 'none'; + } else { + proofToggleContainer.style.display = 'none'; + noProofInfoContainer.style.display = 'block'; + } } else { proofToggleContainer.style.display = 'none'; + noProofInfoContainer.style.display = 'none'; } // Update button text based on operation type @@ -4454,6 +4470,7 @@

Results

} else { queryInputs.style.display = 'none'; document.getElementById('proofToggleContainer').style.display = 'none'; + document.getElementById('noProofInfoContainer').style.display = 'none'; executeButton.style.display = 'none'; queryDescription.style.display = 'none'; } From 17e483bf1f0a95eb2c4e180d5d52dedc8d313ebc Mon Sep 17 00:00:00 2001 From: thephez Date: Tue, 19 Aug 2025 09:33:59 -0400 Subject: [PATCH 4/4] test: update getStatus test criteria for more fields --- .../wasm-sdk/test/ui-automation/tests/query-execution.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/wasm-sdk/test/ui-automation/tests/query-execution.spec.js b/packages/wasm-sdk/test/ui-automation/tests/query-execution.spec.js index 4cc8d7661e..3b6dc6ecb8 100644 --- a/packages/wasm-sdk/test/ui-automation/tests/query-execution.spec.js +++ b/packages/wasm-sdk/test/ui-automation/tests/query-execution.spec.js @@ -496,7 +496,9 @@ test.describe('WASM SDK Query Execution Tests', () => { needsParameters: false, validateFn: (result) => { expect(result).toBeDefined(); - expect(result).toContain('version'); + expect(Object.keys(JSON.parse(result))).toEqual(expect.arrayContaining([ + 'version', 'node', 'chain', 'network', 'stateSync', 'time' + ])); } }, {