Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 42 additions & 44 deletions dash-spv-ffi/src/platform_integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,58 +115,56 @@ 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 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
),
);
}
};

// 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<u32> = 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
),
),
}
}

Expand Down
80 changes: 44 additions & 36 deletions dash-spv/src/client/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,49 +68,57 @@ impl<W: WalletInterface, N: NetworkManager, S: StorageManager> DashSpvClient<W,
) -> Result<QualifiedQuorumEntry> {
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 ============
Expand Down
Loading