diff --git a/dash/src/network/message_sml.rs b/dash/src/network/message_sml.rs index d90926bea..78530af2a 100644 --- a/dash/src/network/message_sml.rs +++ b/dash/src/network/message_sml.rs @@ -64,56 +64,7 @@ pub struct MnListDiff { pub quorums_chainlock_signatures: Vec, } -impl Encodable for MnListDiff { - fn consensus_encode(&self, w: &mut W) -> Result { - let mut len = 0; - len += self.version.consensus_encode(w)?; - len += self.base_block_hash.consensus_encode(w)?; - len += self.block_hash.consensus_encode(w)?; - len += self.total_transactions.consensus_encode(w)?; - len += self.merkle_hashes.consensus_encode(w)?; - len += self.merkle_flags.consensus_encode(w)?; - len += self.coinbase_tx.consensus_encode(w)?; - len += self.deleted_masternodes.consensus_encode(w)?; - len += self.new_masternodes.consensus_encode(w)?; - len += self.deleted_quorums.consensus_encode(w)?; - len += self.new_quorums.consensus_encode(w)?; - len += self.quorums_chainlock_signatures.consensus_encode(w)?; - Ok(len) - } -} - -impl Decodable for MnListDiff { - fn consensus_decode(r: &mut R) -> Result { - let version = u16::consensus_decode(r)?; - let base_block_hash = BlockHash::consensus_decode(r)?; - let block_hash = BlockHash::consensus_decode(r)?; - let total_transactions = u32::consensus_decode(r)?; - let merkle_hashes = Vec::::consensus_decode(r)?; - let merkle_flags = Vec::::consensus_decode(r)?; - let coinbase_tx = Transaction::consensus_decode(r)?; - let deleted_masternodes = Vec::::consensus_decode(r)?; - let new_masternodes = Vec::::consensus_decode(r)?; - let deleted_quorums = Vec::::consensus_decode(r)?; - let new_quorums = Vec::::consensus_decode(r)?; - let quorums_chainlock_signatures = Vec::::consensus_decode(r)?; - - Ok(MnListDiff { - version, - base_block_hash, - block_hash, - total_transactions, - merkle_hashes, - merkle_flags, - coinbase_tx, - deleted_masternodes, - new_masternodes, - deleted_quorums, - new_quorums, - quorums_chainlock_signatures, - }) - } -} +impl_consensus_encoding!(MnListDiff, version, base_block_hash, block_hash, total_transactions, merkle_hashes, merkle_flags, coinbase_tx, deleted_masternodes, new_masternodes, deleted_quorums, new_quorums, quorums_chainlock_signatures); #[derive(PartialEq, Eq, Clone, Debug)] #[cfg_attr(feature = "bincode", derive(Encode, Decode))] @@ -131,7 +82,6 @@ impl_consensus_encoding!(QuorumCLSigObject, signature, index_set); #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", serde(crate = "actual_serde"))] pub struct DeletedQuorum { - // TODO: Make it enum pub llmq_type: LLMQType, pub quorum_hash: QuorumHash, } diff --git a/dash/src/sml/llmq_entry_verification.rs b/dash/src/sml/llmq_entry_verification.rs index c238d871e..71dd6a924 100644 --- a/dash/src/sml/llmq_entry_verification.rs +++ b/dash/src/sml/llmq_entry_verification.rs @@ -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; @@ -13,7 +13,7 @@ use crate::sml::quorum_validation_error::QuorumValidationError; pub enum LLMQEntryVerificationSkipStatus { NotMarkedForVerification, MissedList(CoreBlockHeight), - UnknownBlock([u8; 32]), + UnknownBlock(BlockHash), OtherContext(String), } @@ -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})") diff --git a/dash/src/sml/llmq_type/llmq_indexed_hash.rs b/dash/src/sml/llmq_type/llmq_indexed_hash.rs deleted file mode 100644 index 94f864944..000000000 --- a/dash/src/sml/llmq_type/llmq_indexed_hash.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub struct LLMQIndexedHash { - pub index: u32, - pub hash: [u8; 32], -} - -impl LLMQIndexedHash { - pub fn new(hash: [u8; 32], index: u32) -> Self { LLMQIndexedHash { index, hash } } -} - -impl From<([u8; 32], usize)> for LLMQIndexedHash { - fn from(value: ([u8; 32], usize)) -> Self { Self::new(value.0, value.1 as u32) } -} -impl From<([u8; 32], u32)> for LLMQIndexedHash { - fn from(value: ([u8; 32], u32)) -> Self { Self::new(value.0, value.1) } -} diff --git a/dash/src/sml/llmq_type/mod.rs b/dash/src/sml/llmq_type/mod.rs index 282b62f7c..03bda3520 100644 --- a/dash/src/sml/llmq_type/mod.rs +++ b/dash/src/sml/llmq_type/mod.rs @@ -1,4 +1,3 @@ -pub(crate) mod llmq_indexed_hash; mod network; pub mod rotation; diff --git a/dash/src/sml/masternode_list/apply_diff.rs b/dash/src/sml/masternode_list/apply_diff.rs index 178469632..761f3c9f2 100644 --- a/dash/src/sml/masternode_list/apply_diff.rs +++ b/dash/src/sml/masternode_list/apply_diff.rs @@ -76,12 +76,13 @@ impl MasternodeList { } // Create and return the new MasternodeList - Ok(MasternodeList::new( + let builder = MasternodeList::build( updated_masternodes, updated_quorums, diff.block_hash, diff_end_height, - true, // Assume quorums are active - )) + ); + + Ok(builder.build()) } } diff --git a/dash/src/sml/masternode_list/builder.rs b/dash/src/sml/masternode_list/builder.rs new file mode 100644 index 000000000..fd4a913e8 --- /dev/null +++ b/dash/src/sml/masternode_list/builder.rs @@ -0,0 +1,62 @@ +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; +use crate::{BlockHash, ProTxHash, QuorumHash}; +use std::collections::BTreeMap; + +pub struct MasternodeListBuilder { + pub block_hash: BlockHash, + pub block_height: u32, + pub masternode_merkle_root: Option, + pub llmq_merkle_root: Option, + pub masternodes: BTreeMap, + pub quorums: BTreeMap>, +} + +impl MasternodeListBuilder { + pub fn new( + masternodes: BTreeMap, + quorums: BTreeMap>, + 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, + ) -> 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 + } +} diff --git a/dash/src/sml/masternode_list/debug_helpers.rs b/dash/src/sml/masternode_list/debug_helpers.rs index f175f3034..7a0ee23ec 100644 --- a/dash/src/sml/masternode_list/debug_helpers.rs +++ b/dash/src/sml/masternode_list/debug_helpers.rs @@ -31,7 +31,7 @@ impl MasternodeList { self.known_height, hex::encode(self.block_hash), self.masternode_merkle_root.map_or("None".to_string(), hex::encode), - self.masternode_count(), + self.masternodes.len(), self.llmq_merkle_root.map_or("None".to_string(), hex::encode), self.quorums_short_description() ) diff --git a/dash/src/sml/masternode_list/masternode_helpers.rs b/dash/src/sml/masternode_list/masternode_helpers.rs index c9e1bbe99..9cb8a8ea3 100644 --- a/dash/src/sml/masternode_list/masternode_helpers.rs +++ b/dash/src/sml/masternode_list/masternode_helpers.rs @@ -1,29 +1,14 @@ -use std::cmp::Ordering; use std::net::IpAddr; - -use hashes::Hash; - use crate::ProTxHash; use crate::sml::masternode_list::MasternodeList; -use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry; impl MasternodeList { - pub fn masternode_for( - &self, - pro_reg_tx_hash: &ProTxHash, - ) -> Option<&QualifiedMasternodeListEntry> { - self.masternodes.get(pro_reg_tx_hash) - } - pub fn has_valid_masternode(&self, pro_reg_tx_hash: &ProTxHash) -> bool { self.masternodes .get(pro_reg_tx_hash) .map_or(false, |node| node.masternode_list_entry.is_valid) } - pub fn has_masternode(&self, pro_reg_tx_hash: &ProTxHash) -> bool { - self.masternodes.get(pro_reg_tx_hash).is_some() - } pub fn has_masternode_at_location(&self, address: [u8; 16], port: u16) -> bool { self.masternodes.values().any(|node| { match node.masternode_list_entry.service_address.ip() { @@ -40,50 +25,10 @@ impl MasternodeList { } }) } - pub fn masternode_count(&self) -> usize { self.masternodes.len() } - - pub fn masternode_by_pro_reg_tx_hash( - &self, - registration_hash: &ProTxHash, - ) -> Option { - self.masternodes.get(registration_hash).cloned() - } - pub fn reversed_pro_reg_tx_hashes_cloned(&self) -> Vec { - self.masternodes.keys().cloned().collect() - } pub fn reversed_pro_reg_tx_hashes(&self) -> Vec<&ProTxHash> { self.masternodes.keys().collect() } - - pub fn sorted_reversed_pro_reg_tx_hashes(&self) -> Vec<&ProTxHash> { - let mut hashes = self.reversed_pro_reg_tx_hashes(); - hashes.sort_by(|&s1, &s2| s2.reverse().cmp(&s1.reverse())); - hashes - } - - pub fn provider_tx_ordered_hashes(&self) -> Vec { - let mut vec = Vec::from_iter(self.masternodes.keys().cloned()); - vec.sort_by(|hash1, hash2| { - if reverse_cmp_sup(hash1.to_byte_array(), hash2.to_byte_array()) { - Ordering::Greater - } else { - Ordering::Less - } - }); - vec - } - pub fn compare_provider_tx_ordered_hashes(&self, list: MasternodeList) -> bool { - self.provider_tx_ordered_hashes().eq(&list.provider_tx_ordered_hashes()) - } - - 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) - } } pub fn reverse_cmp_sup(lhs: [u8; 32], rhs: [u8; 32]) -> bool { diff --git a/dash/src/sml/masternode_list/merkle_roots.rs b/dash/src/sml/masternode_list/merkle_roots.rs index 6b5dabd79..a484d65ac 100644 --- a/dash/src/sml/masternode_list/merkle_roots.rs +++ b/dash/src/sml/masternode_list/merkle_roots.rs @@ -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) -> Option { let length = hashes.len(); let mut level = hashes; match length { @@ -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::::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; } @@ -126,7 +126,7 @@ impl MasternodeList { ) -> Option { 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. @@ -140,7 +140,7 @@ impl MasternodeList { /// - `None`: If no quorum commitment hashes are available. pub fn calculate_llmq_merkle_root(&self) -> Option { 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. @@ -154,9 +154,9 @@ impl MasternodeList { /// /// # Returns /// - /// - `Some(Vec<[u8; 32]>)`: A sorted list of masternode entry hashes. + /// - `Some(Vec)`: 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> { + pub fn hashes_for_merkle_root(&self, block_height: u32) -> Option> { (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())); @@ -164,11 +164,6 @@ impl MasternodeList { .into_iter() .map(|hash| self.masternodes[hash].entry_hash) .collect::>() - //this was the following: (with entry_hash_at) - // pro_tx_hashes - // .into_iter() - // .map(|hash| (&self.masternodes[hash]).entry_hash_at(block_height)) - // .collect::>() }) } @@ -180,11 +175,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 { 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::>(); llmq_commitment_hashes.sort(); llmq_commitment_hashes diff --git a/dash/src/sml/masternode_list/mod.rs b/dash/src/sml/masternode_list/mod.rs index 014ee7c15..8b7e5345a 100644 --- a/dash/src/sml/masternode_list/mod.rs +++ b/dash/src/sml/masternode_list/mod.rs @@ -1,4 +1,5 @@ mod apply_diff; +mod builder; mod debug_helpers; pub mod from_diff; mod is_lock_methods; @@ -11,6 +12,8 @@ mod scores_for_quorum; use std::collections::BTreeMap; +pub use builder::MasternodeListBuilder; + #[cfg(feature = "bincode")] use bincode::{Decode, Encode}; @@ -36,45 +39,16 @@ pub struct MasternodeList { } 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 empty(block_hash: BlockHash, block_height: u32) -> Self { + Self::build(BTreeMap::default(), BTreeMap::new(), block_hash, block_height).build() } - pub fn new( - masternodes: BTreeMap, - quorums: BTreeMap>, - 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( + + pub fn build( masternodes: BTreeMap, quorums: BTreeMap>, block_hash: BlockHash, block_height: u32, - masternode_merkle_root: MerkleRootMasternodeList, - llmq_merkle_root: Option, - ) -> Self { - Self { - quorums, - block_hash, - known_height: block_height, - masternode_merkle_root: Some(masternode_merkle_root), - llmq_merkle_root, - masternodes, - } + ) -> MasternodeListBuilder { + MasternodeListBuilder::new(masternodes, quorums, block_hash, block_height) } } diff --git a/dash/src/sml/masternode_list_entry/hash.rs b/dash/src/sml/masternode_list_entry/hash.rs index 6ac7f3eb9..69ae1b909 100644 --- a/dash/src/sml/masternode_list_entry/hash.rs +++ b/dash/src/sml/masternode_list_entry/hash.rs @@ -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) } } diff --git a/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs b/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs index ada167b8b..449e343c5 100644 --- a/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs +++ b/dash/src/sml/masternode_list_entry/qualified_masternode_list_entry.rs @@ -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; @@ -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, } diff --git a/dash/src/sml/quorum_entry/qualified_quorum_entry.rs b/dash/src/sml/quorum_entry/qualified_quorum_entry.rs index 66bbb67bc..1c885b90a 100644 --- a/dash/src/sml/quorum_entry/qualified_quorum_entry.rs +++ b/dash/src/sml/quorum_entry/qualified_quorum_entry.rs @@ -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)) => {