Skip to content
Merged
806 changes: 682 additions & 124 deletions dash-spv/src/sml_engine.rs

Large diffs are not rendered by default.

7 changes: 4 additions & 3 deletions dash-spv/src/sml_engine/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<H: BlockHeaderStorage> MasternodeListEngine<H> {

let mut below_floor = BTreeSet::new();
for cycle_hash in self.rotated_quorums_per_cycle.keys() {
if self.height_of(cycle_hash).await.is_some_and(|height| height < floor) {
if self.height_if_known(cycle_hash).await.is_some_and(|height| height < floor) {
below_floor.insert(*cycle_hash);
}
}
Expand All @@ -85,7 +85,8 @@ impl<H: BlockHeaderStorage> MasternodeListEngine<H> {
/// chain has dropped them for another branch: the lists above it, and the
/// rotated cycles whose base block left the chain or whose mining window
/// ends above it, since their commitments may have been mined on the
/// dropped branch.
/// dropped branch. A cycle whose base block cannot be read goes too:
/// nothing shows it was mined below `height`.
pub(crate) async fn truncate_above(&mut self, height: CoreBlockHeight) {
if let Some(above) = height.checked_add(1) {
self.masternode_lists.split_off(&above);
Expand All @@ -95,7 +96,7 @@ impl<H: BlockHeaderStorage> MasternodeListEngine<H> {
let mut dropped = BTreeSet::new();
for cycle_hash in self.rotated_quorums_per_cycle.keys() {
let mined_below = self
.height_of(cycle_hash)
.height_if_known(cycle_hash)
.await
.is_some_and(|base| base.saturating_add(mining_window_end) <= height);
if !mined_below {
Expand Down
2 changes: 1 addition & 1 deletion dash-spv/src/sml_engine/rotated_quorum_construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ impl<H: BlockHeaderStorage> MasternodeListEngine<H> {
quorum_hash,
index,
};
let Some(height) = self.height_of(&quorum_hash).await else {
let Some(height) = self.height_if_known(&quorum_hash).await else {
members.push(Err(QuorumValidationError::RequiredBlockNotPresent(
quorum_hash,
"rotated quorum height".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion dash-spv/src/sml_engine/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl<H: BlockHeaderStorage> MasternodeListEngine<H> {
) -> Result<(), QuorumValidationError> {
quorum.quorum_entry.validate_structure()?;
let quorum_hash = quorum.quorum_entry.quorum_hash;
let height = self.height_of(&quorum_hash).await.ok_or_else(|| {
let height = self.height_if_known(&quorum_hash).await.ok_or_else(|| {
QuorumValidationError::RequiredBlockNotPresent(quorum_hash, "quorum height".to_string())
})?;
let work_height = height.saturating_sub(QUORUM_MEMBER_LIST_OFFSET);
Expand Down
18 changes: 12 additions & 6 deletions dash-spv/src/storage/masternode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ impl<H: BlockHeaderStorage> MessageLog<H> {
};
let mut newest_base = None;
for base in message.base_hashes() {
newest_base = newest_base.max(engine.height_of(&base).await);
newest_base = newest_base.max(engine.height_if_known(&base).await);
}
plan.push((newest_base.unwrap_or(height), height, kind, path));
}
Expand All @@ -201,8 +201,8 @@ impl<H: BlockHeaderStorage> MessageLog<H> {
for (_, height, kind, path) in plan {
if let Some(message) = self.read_entry(height, kind, path).await {
match message.apply(&mut engine).await {
true => applied += 1,
false => tracing::warn!("Masternode message at {height} does not apply"),
Ok(()) => applied += 1,
Err(e) => tracing::warn!("Masternode message at {height} does not apply: {e}"),
}
}
visit(&engine);
Expand Down Expand Up @@ -272,10 +272,16 @@ impl<H: BlockHeaderStorage> MessageLog<H> {
}

impl Message {
async fn apply<H: BlockHeaderStorage>(self, engine: &mut MasternodeListEngine<H>) -> bool {
/// Feeds the message to `engine`, failing with why it was not taken.
async fn apply<H: BlockHeaderStorage>(
self,
engine: &mut MasternodeListEngine<H>,
) -> Result<(), String> {
match self {
Message::QrInfo(qr_info) => engine.feed_qr_info(*qr_info).await.is_ok(),
Message::Diff(diff) => engine.apply_diff(*diff).await.is_ok(),
Message::QrInfo(qr_info) => {
engine.feed_qr_info(*qr_info).await.map(drop).map_err(|e| e.to_string())
}
Message::Diff(diff) => engine.apply_diff(*diff).await.map_err(|e| e.to_string()),
}
}

Expand Down
6 changes: 3 additions & 3 deletions dash-spv/src/sync/masternodes/sync_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ impl<H: BlockHeaderStorage> SyncManager for MasternodesManager<H> {
}
};

let request_pairs = engine.missing_work_block_list_requests().await;
let tip_height = engine.height_of(&qr_info.mn_list_diff_tip.block_hash).await;
let request_pairs = engine.readable_missing_work_block_list_requests().await;
let tip_height = engine.height_if_known(&qr_info.mn_list_diff_tip.block_hash).await;
drop(engine);

if let Some(height) = tip_height {
Expand Down Expand Up @@ -191,7 +191,7 @@ impl<H: BlockHeaderStorage> SyncManager for MasternodesManager<H> {
tracing::debug!("Processing MnListDiff message for {}", diff.block_hash);

let mut engine = self.engine.write().await;
let Some(target_height) = engine.height_of(&diff.block_hash).await else {
let Some(target_height) = engine.height_if_known(&diff.block_hash).await else {
drop(engine);
tracing::warn!(
"Height not found for MnListDiff block {}, requeuing for retry",
Expand Down
2 changes: 1 addition & 1 deletion dash-spv/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ pub use wallet::{

pub(crate) use node::DashCoreConfig;

pub use crate::sml_engine::{MasternodeListEngine, WORK_DIFF_DEPTH};
pub use crate::sml_engine::{FeedError, MasternodeListEngine, WORK_DIFF_DEPTH};

/// Storage types for tests and benches that open the client's storage directly.
pub use crate::storage::{
Expand Down
5 changes: 3 additions & 2 deletions dash-spv/tests/dashd_masternode/tests_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ async fn test_masternode_list_sync_with_quorum_rotation() {
let engine = client_handle.engine.read().await;
let mut max_cycle = 0;
for cycle_hash in engine.rotated_quorums_per_cycle().keys() {
max_cycle = max_cycle.max(engine.height_of(cycle_hash).await.unwrap_or(0));
let height = engine.height_of(cycle_hash).await.expect("the headers read");
max_cycle = max_cycle.max(height.unwrap_or(0));
}
max_cycle
};
Expand Down Expand Up @@ -443,7 +444,7 @@ async fn test_rotated_quorums_stored_when_sync_starts_post_dkg() {
assert_all_rotated_quorums_verified(&engine);
let mut heights: Vec<u32> = Vec::new();
for cycle_hash in engine.rotated_quorums_per_cycle().keys() {
heights.extend(engine.height_of(cycle_hash).await);
heights.extend(engine.height_of(cycle_hash).await.expect("the headers read"));
}
heights.sort_unstable();
heights.dedup();
Expand Down
Loading