Skip to content

Commit 7539c5f

Browse files
fix: use masternode_lists_around_height for quorum lookups (#407)
* fix(dash-spv): use list around height for quorums * chore(dash-spv): remove unused mut * fix(dash-spv-ffi): use list around height for quorums * fix: use only lists at or before height * fix(dash-spv-ffi): make cbindgen-friendly
1 parent b5a7c0a commit 7539c5f

2 files changed

Lines changed: 86 additions & 80 deletions

File tree

dash-spv-ffi/src/platform_integration.rs

Lines changed: 42 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -115,58 +115,56 @@ pub unsafe extern "C" fn ffi_dash_spv_get_quorum_public_key(
115115
}
116116
};
117117

118-
// Lock the engine for reading
119118
let engine_guard = engine.blocking_read();
119+
let (before, _after) = engine_guard.masternode_lists_around_height(core_chain_locked_height);
120+
let ml = match before {
121+
Some(ml) => ml,
122+
None => {
123+
return FFIResult::error(
124+
FFIErrorCode::ValidationError,
125+
&format!(
126+
"No masternode list found at or before height {}",
127+
core_chain_locked_height
128+
),
129+
);
130+
}
131+
};
120132

121-
// Use the global quorum status index for efficient lookup
122-
match engine_guard
123-
.quorum_statuses
124-
.get(&llmq_type)
125-
.and_then(|type_map| type_map.get(&quorum_hash))
126-
{
127-
Some((heights, public_key, _status)) => {
128-
// Check if the requested height is one of the heights where this quorum exists
129-
if !heights.contains(&core_chain_locked_height) {
130-
// Quorum exists but not at requested height - provide helpful info
131-
let height_list: Vec<u32> = heights.iter().copied().collect();
132-
return FFIResult::error(
133-
FFIErrorCode::ValidationError,
134-
&format!(
135-
"Quorum type {} with hash {:x} exists but not at height {}. Available at heights: {:?}",
136-
quorum_type, quorum_hash, core_chain_locked_height, height_list
137-
),
133+
let list_height = ml.known_height;
134+
match ml.quorums.get(&llmq_type) {
135+
Some(quorums) => match quorums.get(&quorum_hash) {
136+
Some(quorum) => {
137+
let pubkey_bytes: &[u8; 48] = quorum.quorum_entry.quorum_public_key.as_ref();
138+
std::ptr::copy_nonoverlapping(
139+
pubkey_bytes.as_ptr(),
140+
out_pubkey,
141+
QUORUM_PUBKEY_SIZE,
138142
);
139-
}
140-
141-
// Get the public key's canonical 48-byte representation safely
142-
let pubkey_bytes: &[u8; 48] = public_key.as_ref();
143-
std::ptr::copy_nonoverlapping(pubkey_bytes.as_ptr(), out_pubkey, QUORUM_PUBKEY_SIZE);
144143

145-
// Return success
146-
FFIResult {
147-
error_code: 0,
148-
error_message: ptr::null(),
144+
FFIResult {
145+
error_code: 0,
146+
error_message: ptr::null(),
147+
}
149148
}
150-
}
151-
None => {
152-
// Quorum not found in global index - provide diagnostic info
153-
let total_lists = engine_guard.masternode_lists.len();
154-
let (min_height, max_height) = if total_lists > 0 {
155-
let min = engine_guard.masternode_lists.keys().min().copied().unwrap_or(0);
156-
let max = engine_guard.masternode_lists.keys().max().copied().unwrap_or(0);
157-
(min, max)
158-
} else {
159-
(0, 0)
160-
};
161-
162-
FFIResult::error(
149+
None => FFIResult::error(
163150
FFIErrorCode::ValidationError,
164151
&format!(
165-
"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.",
166-
quorum_type, quorum_hash, total_lists, min_height, max_height
152+
"Quorum not found: type {} at list height {} (requested {}) with hash {:x} (masternode list exists with {} quorums of this type)",
153+
quorum_type,
154+
list_height,
155+
core_chain_locked_height,
156+
quorum_hash,
157+
quorums.len()
167158
),
168-
)
169-
}
159+
),
160+
},
161+
None => FFIResult::error(
162+
FFIErrorCode::ValidationError,
163+
&format!(
164+
"No quorums of type {} found at list height {} (requested {})",
165+
quorum_type, list_height, core_chain_locked_height
166+
),
167+
),
170168
}
171169
}
172170

dash-spv/src/client/queries.rs

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -67,48 +67,56 @@ impl<W: WalletInterface, N: NetworkManager, S: StorageManager> DashSpvClient<W,
6767
) -> Result<QualifiedQuorumEntry> {
6868
let masternode_engine = self.masternode_list_engine()?;
6969
let masternode_engine_guard = masternode_engine.read().await;
70-
// First check if we have the masternode list at this height
71-
match masternode_engine_guard.masternode_lists.get(&height) {
72-
Some(ml) => {
73-
// We have the masternode list, now look for the quorum
74-
match ml.quorums.get(&quorum_type) {
75-
Some(quorums) => match quorums.get(&quorum_hash) {
76-
Some(quorum) => {
77-
tracing::debug!(
78-
"Found quorum type {} at height {} with hash {}",
79-
quorum_type,
80-
height,
81-
hex::encode(quorum_hash)
82-
);
83-
Ok(quorum.clone())
84-
}
85-
None => {
86-
let message = format!("Quorum not found: type {} at height {} with hash {} (masternode list exists with {} quorums of this type)",
87-
quorum_type,
88-
height,
89-
hex::encode(quorum_hash),
90-
quorums.len());
91-
tracing::warn!(message);
92-
Err(SpvError::QuorumLookupError(message))
93-
}
94-
},
70+
let (before, _after) = masternode_engine_guard.masternode_lists_around_height(height);
71+
if let Some(ml) = before {
72+
let list_height = ml.known_height;
73+
match ml.quorums.get(&quorum_type) {
74+
Some(quorums) => match quorums.get(&quorum_hash) {
75+
Some(quorum) => {
76+
tracing::debug!(
77+
"Found quorum type {} at list height {} (requested {}) with hash {}",
78+
quorum_type,
79+
list_height,
80+
height,
81+
hex::encode(quorum_hash)
82+
);
83+
return Ok(quorum.clone());
84+
}
9585
None => {
96-
tracing::warn!(
97-
"No quorums of type {} found at height {} (masternode list exists)",
86+
let message = format!(
87+
"Quorum not found: type {} at list height {} (requested {}) with hash {} (masternode list exists with {} quorums of this type)",
9888
quorum_type,
99-
height
89+
list_height,
90+
height,
91+
hex::encode(quorum_hash),
92+
quorums.len()
10093
);
101-
Err(SpvError::QuorumLookupError(format!(
102-
"No quorums of type {} found at height {}",
103-
quorum_type, height
104-
)))
94+
tracing::warn!(message);
95+
return Err(SpvError::QuorumLookupError(message));
10596
}
97+
},
98+
None => {
99+
tracing::warn!(
100+
"No quorums of type {} found at list height {} (requested {}) (masternode list exists)",
101+
quorum_type,
102+
list_height,
103+
height
104+
);
105+
return Err(SpvError::QuorumLookupError(format!(
106+
"No quorums of type {} found at list height {} (requested {})",
107+
quorum_type, list_height, height
108+
)));
106109
}
107110
}
108-
None => Err(SpvError::QuorumLookupError(format!(
109-
"No masternode list found at height {}",
110-
height
111-
))),
112111
}
112+
113+
tracing::warn!(
114+
"No masternode list found at or before height {} - cannot retrieve quorum",
115+
height
116+
);
117+
Err(SpvError::QuorumLookupError(format!(
118+
"No masternode list found at or before height {}",
119+
height
120+
)))
113121
}
114122
}

0 commit comments

Comments
 (0)