Skip to content
Merged
6 changes: 3 additions & 3 deletions dash/src/sml/llmq_entry_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use core::fmt::{Display, Formatter};

#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};

use crate::BlockHash;
use crate::prelude::CoreBlockHeight;
use crate::sml::quorum_validation_error::QuorumValidationError;

Expand All @@ -13,7 +13,7 @@ use crate::sml::quorum_validation_error::QuorumValidationError;
pub enum LLMQEntryVerificationSkipStatus {
NotMarkedForVerification,
MissedList(CoreBlockHeight),
UnknownBlock([u8; 32]),
UnknownBlock(BlockHash),
OtherContext(String),
}

Expand All @@ -27,7 +27,7 @@ impl Display for LLMQEntryVerificationSkipStatus {
format!("MissedList({})", block_height)
}
LLMQEntryVerificationSkipStatus::UnknownBlock(block_hash) => {
format!("UnknownBlock({})", hex::encode(block_hash))
format!("UnknownBlock({})", block_hash)
}
LLMQEntryVerificationSkipStatus::OtherContext(message) => {
format!("OtherContext({message})")
Expand Down
11 changes: 6 additions & 5 deletions dash/src/sml/masternode_list/apply_diff.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::network::message_sml::MnListDiff;
use crate::prelude::CoreBlockHeight;
use crate::sml::error::SmlError;
use crate::sml::masternode_list::MasternodeList;
use crate::sml::masternode_list::{MasternodeList, MasternodeListBuilder};

impl MasternodeList {
/// Applies an `MnListDiff` to update the current masternode list.
Expand Down Expand Up @@ -76,12 +76,13 @@ impl MasternodeList {
}

// Create and return the new MasternodeList
Ok(MasternodeList::new(
let builder = MasternodeListBuilder::new(
updated_masternodes,
updated_quorums,
diff.block_hash,
diff_end_height,
true, // Assume quorums are active
))
diff_end_height,
);

Ok(builder.build())
}
}
66 changes: 66 additions & 0 deletions dash/src/sml/masternode_list/builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use std::collections::BTreeMap;
use crate::{BlockHash, ProTxHash, QuorumHash};
use crate::hash_types::{MerkleRootMasternodeList, MerkleRootQuorums};
use crate::sml::llmq_type::LLMQType;
use crate::sml::masternode_list::MasternodeList;
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
use crate::sml::quorum_entry::qualified_quorum_entry::QualifiedQuorumEntry;

pub struct MasternodeListBuilder {
pub block_hash: BlockHash,
pub block_height: u32,
pub masternode_merkle_root: Option<MerkleRootMasternodeList>,
pub llmq_merkle_root: Option<MerkleRootQuorums>,
pub masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
pub quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
}

impl MasternodeListBuilder {
pub fn empty(block_hash: BlockHash, block_height: u32) -> Self {
Self::new(BTreeMap::default(), BTreeMap::new(), block_hash, block_height)
}

pub fn new(
masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
block_hash: BlockHash,
block_height: u32,
) -> Self {
Self {
quorums,
block_hash,
block_height,
masternode_merkle_root: None,
llmq_merkle_root: None,
masternodes,
}
}

pub fn with_merkle_roots(
mut self,
masternode_merkle_root: MerkleRootMasternodeList,
llmq_merkle_root: Option<MerkleRootQuorums>,
) -> Self {
self.masternode_merkle_root = Some(masternode_merkle_root);
self.llmq_merkle_root = llmq_merkle_root;
self
}

pub fn build(self) -> MasternodeList {
let mut list = MasternodeList {
block_hash: self.block_hash,
known_height: self.block_height,
masternode_merkle_root: self.masternode_merkle_root,
llmq_merkle_root: self.llmq_merkle_root,
masternodes: self.masternodes,
quorums: self.quorums,
};

if self.masternode_merkle_root.is_none() {
list.masternode_merkle_root = list.calculate_masternodes_merkle_root(self.block_height);
list.llmq_merkle_root = list.calculate_llmq_merkle_root();
}

list
}
}
6 changes: 1 addition & 5 deletions dash/src/sml/masternode_list/masternode_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,7 @@ impl MasternodeList {
}

pub fn compare_masternodes(&self, list: MasternodeList) -> bool {
let mut vec1 = Vec::from_iter(self.masternodes.values());
vec1.sort();
let mut vec2 = Vec::from_iter(list.masternodes.values());
vec2.sort();
vec1.eq(&vec2)
self.masternodes.values().eq(list.masternodes.values())
}
}

Expand Down
22 changes: 11 additions & 11 deletions dash/src/sml/masternode_list/merkle_roots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::transaction::special_transaction::TransactionPayload;
/// - `Some([u8; 32])`: The computed Merkle root if at least one hash is provided.
/// - `None`: If the input vector is empty.
#[inline]
pub fn merkle_root_from_hashes(hashes: Vec<[u8; 32]>) -> Option<[u8; 32]> {
pub fn merkle_root_from_hashes(hashes: Vec<sha256d::Hash>) -> Option<sha256d::Hash> {
let length = hashes.len();
let mut level = hashes;
match length {
Expand All @@ -29,12 +29,12 @@ pub fn merkle_root_from_hashes(hashes: Vec<[u8; 32]>) -> Option<[u8; 32]> {
while level.len() != 1 {
let len = level.len();
let mut higher_level =
Vec::<[u8; 32]>::with_capacity((0.5 * len as f64).ceil() as usize);
Vec::<sha256d::Hash>::with_capacity((0.5 * len as f64).ceil() as usize);
for pair in level.chunks(2) {
let mut buffer = Vec::with_capacity(64);
buffer.extend_from_slice(&pair[0]);
buffer.extend_from_slice(pair.get(1).unwrap_or(&pair[0]));
higher_level.push(sha256d::Hash::hash(&buffer).to_byte_array());
buffer.extend_from_slice(pair[0].as_byte_array());
buffer.extend_from_slice(pair.get(1).unwrap_or(&pair[0]).as_byte_array());
higher_level.push(sha256d::Hash::hash(&buffer));
}
level = higher_level;
}
Expand Down Expand Up @@ -126,7 +126,7 @@ impl MasternodeList {
) -> Option<MerkleRootMasternodeList> {
self.hashes_for_merkle_root(block_height)
.and_then(merkle_root_from_hashes)
.map(|hash| MerkleRootMasternodeList::from_byte_array(hash))
.map(MerkleRootMasternodeList::from_raw_hash)
}

/// Computes the Merkle root for the LLMQ (Long-Living Masternode Quorum) list.
Expand All @@ -140,7 +140,7 @@ impl MasternodeList {
/// - `None`: If no quorum commitment hashes are available.
pub fn calculate_llmq_merkle_root(&self) -> Option<MerkleRootQuorums> {
merkle_root_from_hashes(self.hashes_for_quorum_merkle_root())
.map(|hash| MerkleRootQuorums::from_byte_array(hash))
.map(MerkleRootQuorums::from_raw_hash)
}

/// Retrieves the list of hashes required to compute the masternode list Merkle root.
Expand All @@ -154,9 +154,9 @@ impl MasternodeList {
///
/// # Returns
///
/// - `Some(Vec<[u8; 32]>)`: A sorted list of masternode entry hashes.
/// - `Some(Vec<sha256d::Hash>)`: A sorted list of masternode entry hashes.
/// - `None`: If the block height is invalid (`u32::MAX`).
pub fn hashes_for_merkle_root(&self, block_height: u32) -> Option<Vec<[u8; 32]>> {
pub fn hashes_for_merkle_root(&self, block_height: u32) -> Option<Vec<sha256d::Hash>> {
(block_height != u32::MAX).then_some({
let mut pro_tx_hashes = self.reversed_pro_reg_tx_hashes();
pro_tx_hashes.sort_by(|&s1, &s2| s1.reverse().cmp(&s2.reverse()));
Expand All @@ -180,11 +180,11 @@ impl MasternodeList {
/// # Returns
///
/// - `Vec<[u8; 32]>`: A sorted list of quorum commitment hashes.
pub fn hashes_for_quorum_merkle_root(&self) -> Vec<[u8; 32]> {
pub fn hashes_for_quorum_merkle_root(&self) -> Vec<sha256d::Hash> {
let mut llmq_commitment_hashes = self
.quorums
.values()
.flat_map(|q_map| q_map.values().map(|entry| entry.entry_hash.to_byte_array()))
.flat_map(|q_map| q_map.values().map(|entry| entry.entry_hash.to_raw_hash()))
.collect::<Vec<_>>();
llmq_commitment_hashes.sort();
llmq_commitment_hashes
Expand Down
47 changes: 3 additions & 44 deletions dash/src/sml/masternode_list/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ mod peer_addresses;
mod quorum_helpers;
mod rotated_quorums_info;
mod scores_for_quorum;
mod builder;

use std::collections::BTreeMap;

pub use builder::MasternodeListBuilder;

#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};

Expand All @@ -34,47 +37,3 @@ pub struct MasternodeList {
pub masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
pub quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
}

impl MasternodeList {
pub fn empty(block_hash: BlockHash, block_height: u32, quorums_active: bool) -> Self {
Self::new(BTreeMap::default(), BTreeMap::new(), block_hash, block_height, quorums_active)
}
pub fn new(
masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
block_hash: BlockHash,
block_height: u32,
quorums_active: bool,
) -> Self {
let mut list = Self {
quorums,
block_hash,
known_height: block_height,
masternode_merkle_root: None,
llmq_merkle_root: None,
masternodes,
};
list.masternode_merkle_root = list.calculate_masternodes_merkle_root(block_height);
if quorums_active {
list.llmq_merkle_root = list.calculate_llmq_merkle_root();
}
list
}
pub fn with_merkle_roots(
masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
block_hash: BlockHash,
block_height: u32,
masternode_merkle_root: MerkleRootMasternodeList,
llmq_merkle_root: Option<MerkleRootQuorums>,
) -> Self {
Self {
quorums,
block_hash,
known_height: block_height,
masternode_merkle_root: Some(masternode_merkle_root),
llmq_merkle_root,
masternodes,
}
}
}
6 changes: 3 additions & 3 deletions dash/src/sml/masternode_list_entry/hash.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use hashes::{Hash, sha256d};
use hashes::{sha256d, Hash};

use crate::consensus::Encodable;
use crate::sml::masternode_list_entry::MasternodeListEntry;

impl MasternodeListEntry {
pub fn calculate_entry_hash(&self) -> [u8; 32] {
pub fn calculate_entry_hash(&self) -> sha256d::Hash {
let mut writer = Vec::new();

self.consensus_encode(&mut writer).expect("encoding failed");
sha256d::Hash::hash(&writer).to_byte_array()
sha256d::Hash::hash(&writer)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::cmp::Ordering;

#[cfg(feature = "bincode")]
use bincode::{Decode, Encode};
use hashes::Hash;
use hashes::{sha256d, Hash};

use crate::hash_types::ConfirmedHashHashedWithProRegTx;
use crate::sml::masternode_list_entry::MasternodeListEntry;
Expand All @@ -18,7 +18,7 @@ pub struct QualifiedMasternodeListEntry {
/// The underlying masternode list entry
pub masternode_list_entry: MasternodeListEntry,
/// The computed entry hash
pub entry_hash: [u8; 32],
pub entry_hash: sha256d::Hash,
/// The confirmed hash hashed with the pro_reg_tx if the confirmed hash is set
pub confirmed_hash_hashed_with_pro_reg_tx: Option<ConfirmedHashHashedWithProRegTx>,
}
Expand Down
2 changes: 1 addition & 1 deletion dash/src/sml/quorum_entry/qualified_quorum_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl QualifiedQuorumEntry {
match result {
Err(QuorumValidationError::RequiredBlockNotPresent(block_hash)) => {
self.verified = LLMQEntryVerificationStatus::Skipped(
LLMQEntryVerificationSkipStatus::UnknownBlock(block_hash.to_byte_array()),
LLMQEntryVerificationSkipStatus::UnknownBlock(block_hash),
);
}
Err(QuorumValidationError::RequiredMasternodeListNotPresent(block_height)) => {
Expand Down
Loading