From 6f2393c7f563a4f70c3f36713ea912a2dae9b07c Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 2 Feb 2026 18:50:58 -0600 Subject: [PATCH 1/5] fix(dash-spv): use list around height for quorums --- dash-spv/src/client/queries.rs | 81 +++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/dash-spv/src/client/queries.rs b/dash-spv/src/client/queries.rs index 7cd8f9979..78f8ae77b 100644 --- a/dash-spv/src/client/queries.rs +++ b/dash-spv/src/client/queries.rs @@ -68,49 +68,58 @@ impl DashSpvClient Result { let masternode_engine = self.masternode_list_engine()?; let masternode_engine_guard = masternode_engine.read().await; - // First check if we have the masternode list at this height - match masternode_engine_guard.masternode_lists.get(&height) { - Some(ml) => { - // We have the masternode list, now look for the quorum - match ml.quorums.get(&quorum_type) { - Some(quorums) => match quorums.get(&quorum_hash) { - Some(quorum) => { - tracing::debug!( - "Found quorum type {} at height {} with hash {}", - quorum_type, - height, - hex::encode(quorum_hash) - ); - Ok(quorum.clone()) - } - None => { - let message = format!("Quorum not found: type {} at height {} with hash {} (masternode list exists with {} quorums of this type)", - quorum_type, - height, - hex::encode(quorum_hash), - quorums.len()); - tracing::warn!(message); - Err(SpvError::QuorumLookupError(message)) - } - }, + let (before, _after) = masternode_engine_guard.masternode_lists_around_height(height); + + if let Some(ml) = before { + let list_height = ml.known_height; + match ml.quorums.get(&quorum_type) { + Some(quorums) => match quorums.get(&quorum_hash) { + Some(quorum) => { + tracing::debug!( + "Found quorum type {} at list height {} (requested {}) with hash {}", + quorum_type, + list_height, + height, + hex::encode(quorum_hash) + ); + return Ok(quorum.clone()); + } None => { - tracing::warn!( - "No quorums of type {} found at height {} (masternode list exists)", + let message = format!( + "Quorum not found: type {} at list height {} (requested {}) with hash {} (masternode list exists with {} quorums of this type)", quorum_type, - height + list_height, + height, + hex::encode(quorum_hash), + quorums.len() ); - Err(SpvError::QuorumLookupError(format!( - "No quorums of type {} found at height {}", - quorum_type, height - ))) + tracing::warn!(message); + return Err(SpvError::QuorumLookupError(message)); } + }, + None => { + tracing::warn!( + "No quorums of type {} found at list height {} (requested {}) (masternode list exists)", + quorum_type, + list_height, + height + ); + return Err(SpvError::QuorumLookupError(format!( + "No quorums of type {} found at list height {} (requested {})", + quorum_type, list_height, height + ))); } } - None => Err(SpvError::QuorumLookupError(format!( - "No masternode list found at height {}", - height - ))), } + + tracing::warn!( + "No masternode list found at or before height {} - cannot retrieve quorum", + height + ); + Err(SpvError::QuorumLookupError(format!( + "No masternode list found at or before height {}", + height + ))) } // ============ Balance Queries ============ From 818c813b3743e8bd7ee64cebbfc5f4dfb0b011ca Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 2 Feb 2026 18:51:54 -0600 Subject: [PATCH 2/5] chore(dash-spv): remove unused mut --- dash-spv/src/client/queries.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/dash-spv/src/client/queries.rs b/dash-spv/src/client/queries.rs index 78f8ae77b..8e2545581 100644 --- a/dash-spv/src/client/queries.rs +++ b/dash-spv/src/client/queries.rs @@ -69,7 +69,6 @@ impl DashSpvClient Date: Mon, 2 Feb 2026 18:55:38 -0600 Subject: [PATCH 3/5] fix(dash-spv-ffi): use list around height for quorums --- dash-spv-ffi/src/platform_integration.rs | 83 +++++++++++------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/dash-spv-ffi/src/platform_integration.rs b/dash-spv-ffi/src/platform_integration.rs index b868c8fb2..fb515849d 100644 --- a/dash-spv-ffi/src/platform_integration.rs +++ b/dash-spv-ffi/src/platform_integration.rs @@ -115,58 +115,53 @@ pub unsafe extern "C" fn ffi_dash_spv_get_quorum_public_key( } }; - // Lock the engine for reading let engine_guard = engine.blocking_read(); + let (before, _after) = engine_guard.masternode_lists_around_height(core_chain_locked_height); + let Some(ml) = before else { + return FFIResult::error( + FFIErrorCode::ValidationError, + &format!( + "No masternode list found at or before height {}", + core_chain_locked_height + ), + ); + }; - // Use the global quorum status index for efficient lookup - match engine_guard - .quorum_statuses - .get(&llmq_type) - .and_then(|type_map| type_map.get(&quorum_hash)) - { - Some((heights, public_key, _status)) => { - // Check if the requested height is one of the heights where this quorum exists - if !heights.contains(&core_chain_locked_height) { - // Quorum exists but not at requested height - provide helpful info - let height_list: Vec = heights.iter().copied().collect(); - return FFIResult::error( - FFIErrorCode::ValidationError, - &format!( - "Quorum type {} with hash {:x} exists but not at height {}. Available at heights: {:?}", - quorum_type, quorum_hash, core_chain_locked_height, height_list - ), + let list_height = ml.known_height; + match ml.quorums.get(&llmq_type) { + Some(quorums) => match quorums.get(&quorum_hash) { + Some(quorum) => { + let pubkey_bytes: &[u8; 48] = quorum.quorum_entry.quorum_public_key.as_ref(); + std::ptr::copy_nonoverlapping( + pubkey_bytes.as_ptr(), + out_pubkey, + QUORUM_PUBKEY_SIZE, ); - } - - // Get the public key's canonical 48-byte representation safely - let pubkey_bytes: &[u8; 48] = public_key.as_ref(); - std::ptr::copy_nonoverlapping(pubkey_bytes.as_ptr(), out_pubkey, QUORUM_PUBKEY_SIZE); - // Return success - FFIResult { - error_code: 0, - error_message: ptr::null(), + FFIResult { + error_code: 0, + error_message: ptr::null(), + } } - } - None => { - // Quorum not found in global index - provide diagnostic info - let total_lists = engine_guard.masternode_lists.len(); - let (min_height, max_height) = if total_lists > 0 { - let min = engine_guard.masternode_lists.keys().min().copied().unwrap_or(0); - let max = engine_guard.masternode_lists.keys().max().copied().unwrap_or(0); - (min, max) - } else { - (0, 0) - }; - - FFIResult::error( + None => FFIResult::error( FFIErrorCode::ValidationError, &format!( - "Quorum not found: type={}, hash={:x}. Core SDK has {} masternode lists ranging from height {} to {}. The quorum may not exist or the Core SDK may still be syncing.", - quorum_type, quorum_hash, total_lists, min_height, max_height + "Quorum not found: type {} at list height {} (requested {}) with hash {:x} (masternode list exists with {} quorums of this type)", + quorum_type, + list_height, + core_chain_locked_height, + quorum_hash, + quorums.len() ), - ) - } + ), + }, + None => FFIResult::error( + FFIErrorCode::ValidationError, + &format!( + "No quorums of type {} found at list height {} (requested {})", + quorum_type, list_height, core_chain_locked_height + ), + ), } } From 31309e4536c376c7f0ca66e46428ec2eb112fe9e Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 2 Feb 2026 18:56:46 -0600 Subject: [PATCH 4/5] fix: use only lists at or before height --- dash-spv-ffi/src/platform_integration.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/dash-spv-ffi/src/platform_integration.rs b/dash-spv-ffi/src/platform_integration.rs index fb515849d..5df24d46f 100644 --- a/dash-spv-ffi/src/platform_integration.rs +++ b/dash-spv-ffi/src/platform_integration.rs @@ -125,7 +125,6 @@ pub unsafe extern "C" fn ffi_dash_spv_get_quorum_public_key( core_chain_locked_height ), ); - }; let list_height = ml.known_height; match ml.quorums.get(&llmq_type) { From eb617f7958b0e9525fc5dd24047d29a128f6f687 Mon Sep 17 00:00:00 2001 From: pasta Date: Mon, 2 Feb 2026 20:28:10 -0600 Subject: [PATCH 5/5] fix(dash-spv-ffi): make cbindgen-friendly --- dash-spv-ffi/src/platform_integration.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/dash-spv-ffi/src/platform_integration.rs b/dash-spv-ffi/src/platform_integration.rs index 5df24d46f..288ea8a34 100644 --- a/dash-spv-ffi/src/platform_integration.rs +++ b/dash-spv-ffi/src/platform_integration.rs @@ -117,14 +117,18 @@ pub unsafe extern "C" fn ffi_dash_spv_get_quorum_public_key( let engine_guard = engine.blocking_read(); let (before, _after) = engine_guard.masternode_lists_around_height(core_chain_locked_height); - let Some(ml) = before else { - return FFIResult::error( - FFIErrorCode::ValidationError, - &format!( - "No masternode list found at or before height {}", - core_chain_locked_height - ), - ); + let ml = match before { + Some(ml) => ml, + None => { + return FFIResult::error( + FFIErrorCode::ValidationError, + &format!( + "No masternode list found at or before height {}", + core_chain_locked_height + ), + ); + } + }; let list_height = ml.known_height; match ml.quorums.get(&llmq_type) {