Skip to content

Commit a457fea

Browse files
authored
refactor: minor masternode list improvements based on #51 review (#54)
* refactor: use `BlockHash` instead of byte array * refactor: remove unnecessary vector allocation and sorting * refactor: use Hash primitive * refactor: introduce `MasternodeListBuilder` * refactor: use macros for encoding/decoding traits * refactor: remove unused struct * refactor: remove unused methods * refactor: add helper methods for MN list builder * refactor: remove unused import
1 parent 7b30e02 commit a457fea

File tree

13 files changed

+97
-187
lines changed

13 files changed

+97
-187
lines changed

dash/src/network/message_sml.rs

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -64,56 +64,7 @@ pub struct MnListDiff {
6464
pub quorums_chainlock_signatures: Vec<QuorumCLSigObject>,
6565
}
6666

67-
impl Encodable for MnListDiff {
68-
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
69-
let mut len = 0;
70-
len += self.version.consensus_encode(w)?;
71-
len += self.base_block_hash.consensus_encode(w)?;
72-
len += self.block_hash.consensus_encode(w)?;
73-
len += self.total_transactions.consensus_encode(w)?;
74-
len += self.merkle_hashes.consensus_encode(w)?;
75-
len += self.merkle_flags.consensus_encode(w)?;
76-
len += self.coinbase_tx.consensus_encode(w)?;
77-
len += self.deleted_masternodes.consensus_encode(w)?;
78-
len += self.new_masternodes.consensus_encode(w)?;
79-
len += self.deleted_quorums.consensus_encode(w)?;
80-
len += self.new_quorums.consensus_encode(w)?;
81-
len += self.quorums_chainlock_signatures.consensus_encode(w)?;
82-
Ok(len)
83-
}
84-
}
85-
86-
impl Decodable for MnListDiff {
87-
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
88-
let version = u16::consensus_decode(r)?;
89-
let base_block_hash = BlockHash::consensus_decode(r)?;
90-
let block_hash = BlockHash::consensus_decode(r)?;
91-
let total_transactions = u32::consensus_decode(r)?;
92-
let merkle_hashes = Vec::<MerkleRootMasternodeList>::consensus_decode(r)?;
93-
let merkle_flags = Vec::<u8>::consensus_decode(r)?;
94-
let coinbase_tx = Transaction::consensus_decode(r)?;
95-
let deleted_masternodes = Vec::<ProTxHash>::consensus_decode(r)?;
96-
let new_masternodes = Vec::<MasternodeListEntry>::consensus_decode(r)?;
97-
let deleted_quorums = Vec::<DeletedQuorum>::consensus_decode(r)?;
98-
let new_quorums = Vec::<QuorumEntry>::consensus_decode(r)?;
99-
let quorums_chainlock_signatures = Vec::<QuorumCLSigObject>::consensus_decode(r)?;
100-
101-
Ok(MnListDiff {
102-
version,
103-
base_block_hash,
104-
block_hash,
105-
total_transactions,
106-
merkle_hashes,
107-
merkle_flags,
108-
coinbase_tx,
109-
deleted_masternodes,
110-
new_masternodes,
111-
deleted_quorums,
112-
new_quorums,
113-
quorums_chainlock_signatures,
114-
})
115-
}
116-
}
67+
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);
11768

11869
#[derive(PartialEq, Eq, Clone, Debug)]
11970
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
@@ -131,7 +82,6 @@ impl_consensus_encoding!(QuorumCLSigObject, signature, index_set);
13182
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
13283
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
13384
pub struct DeletedQuorum {
134-
// TODO: Make it enum
13585
pub llmq_type: LLMQType,
13686
pub quorum_hash: QuorumHash,
13787
}

dash/src/sml/llmq_entry_verification.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use core::fmt::{Display, Formatter};
22

33
#[cfg(feature = "bincode")]
44
use bincode::{Decode, Encode};
5-
5+
use crate::BlockHash;
66
use crate::prelude::CoreBlockHeight;
77
use crate::sml::quorum_validation_error::QuorumValidationError;
88

@@ -13,7 +13,7 @@ use crate::sml::quorum_validation_error::QuorumValidationError;
1313
pub enum LLMQEntryVerificationSkipStatus {
1414
NotMarkedForVerification,
1515
MissedList(CoreBlockHeight),
16-
UnknownBlock([u8; 32]),
16+
UnknownBlock(BlockHash),
1717
OtherContext(String),
1818
}
1919

@@ -27,7 +27,7 @@ impl Display for LLMQEntryVerificationSkipStatus {
2727
format!("MissedList({})", block_height)
2828
}
2929
LLMQEntryVerificationSkipStatus::UnknownBlock(block_hash) => {
30-
format!("UnknownBlock({})", hex::encode(block_hash))
30+
format!("UnknownBlock({})", block_hash)
3131
}
3232
LLMQEntryVerificationSkipStatus::OtherContext(message) => {
3333
format!("OtherContext({message})")

dash/src/sml/llmq_type/llmq_indexed_hash.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

dash/src/sml/llmq_type/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
pub(crate) mod llmq_indexed_hash;
21
mod network;
32
pub mod rotation;
43

dash/src/sml/masternode_list/apply_diff.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,13 @@ impl MasternodeList {
7676
}
7777

7878
// Create and return the new MasternodeList
79-
Ok(MasternodeList::new(
79+
let builder = MasternodeList::build(
8080
updated_masternodes,
8181
updated_quorums,
8282
diff.block_hash,
8383
diff_end_height,
84-
true, // Assume quorums are active
85-
))
84+
);
85+
86+
Ok(builder.build())
8687
}
8788
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
use crate::hash_types::{MerkleRootMasternodeList, MerkleRootQuorums};
2+
use crate::sml::llmq_type::LLMQType;
3+
use crate::sml::masternode_list::MasternodeList;
4+
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
5+
use crate::sml::quorum_entry::qualified_quorum_entry::QualifiedQuorumEntry;
6+
use crate::{BlockHash, ProTxHash, QuorumHash};
7+
use std::collections::BTreeMap;
8+
9+
pub struct MasternodeListBuilder {
10+
pub block_hash: BlockHash,
11+
pub block_height: u32,
12+
pub masternode_merkle_root: Option<MerkleRootMasternodeList>,
13+
pub llmq_merkle_root: Option<MerkleRootQuorums>,
14+
pub masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
15+
pub quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
16+
}
17+
18+
impl MasternodeListBuilder {
19+
pub fn new(
20+
masternodes: BTreeMap<ProTxHash, QualifiedMasternodeListEntry>,
21+
quorums: BTreeMap<LLMQType, BTreeMap<QuorumHash, QualifiedQuorumEntry>>,
22+
block_hash: BlockHash,
23+
block_height: u32,
24+
) -> Self {
25+
Self {
26+
quorums,
27+
block_hash,
28+
block_height,
29+
masternode_merkle_root: None,
30+
llmq_merkle_root: None,
31+
masternodes,
32+
}
33+
}
34+
35+
pub fn with_merkle_roots(
36+
mut self,
37+
masternode_merkle_root: MerkleRootMasternodeList,
38+
llmq_merkle_root: Option<MerkleRootQuorums>,
39+
) -> Self {
40+
self.masternode_merkle_root = Some(masternode_merkle_root);
41+
self.llmq_merkle_root = llmq_merkle_root;
42+
self
43+
}
44+
45+
pub fn build(self) -> MasternodeList {
46+
let mut list = MasternodeList {
47+
block_hash: self.block_hash,
48+
known_height: self.block_height,
49+
masternode_merkle_root: self.masternode_merkle_root,
50+
llmq_merkle_root: self.llmq_merkle_root,
51+
masternodes: self.masternodes,
52+
quorums: self.quorums,
53+
};
54+
55+
if self.masternode_merkle_root.is_none() {
56+
list.masternode_merkle_root = list.calculate_masternodes_merkle_root(self.block_height);
57+
list.llmq_merkle_root = list.calculate_llmq_merkle_root();
58+
}
59+
60+
list
61+
}
62+
}

dash/src/sml/masternode_list/debug_helpers.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ impl MasternodeList {
3131
self.known_height,
3232
hex::encode(self.block_hash),
3333
self.masternode_merkle_root.map_or("None".to_string(), hex::encode),
34-
self.masternode_count(),
34+
self.masternodes.len(),
3535
self.llmq_merkle_root.map_or("None".to_string(), hex::encode),
3636
self.quorums_short_description()
3737
)

dash/src/sml/masternode_list/masternode_helpers.rs

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
1-
use std::cmp::Ordering;
21
use std::net::IpAddr;
3-
4-
use hashes::Hash;
5-
62
use crate::ProTxHash;
73
use crate::sml::masternode_list::MasternodeList;
8-
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
94

105
impl MasternodeList {
11-
pub fn masternode_for(
12-
&self,
13-
pro_reg_tx_hash: &ProTxHash,
14-
) -> Option<&QualifiedMasternodeListEntry> {
15-
self.masternodes.get(pro_reg_tx_hash)
16-
}
17-
186
pub fn has_valid_masternode(&self, pro_reg_tx_hash: &ProTxHash) -> bool {
197
self.masternodes
208
.get(pro_reg_tx_hash)
219
.map_or(false, |node| node.masternode_list_entry.is_valid)
2210
}
2311

24-
pub fn has_masternode(&self, pro_reg_tx_hash: &ProTxHash) -> bool {
25-
self.masternodes.get(pro_reg_tx_hash).is_some()
26-
}
2712
pub fn has_masternode_at_location(&self, address: [u8; 16], port: u16) -> bool {
2813
self.masternodes.values().any(|node| {
2914
match node.masternode_list_entry.service_address.ip() {
@@ -40,50 +25,10 @@ impl MasternodeList {
4025
}
4126
})
4227
}
43-
pub fn masternode_count(&self) -> usize { self.masternodes.len() }
44-
45-
pub fn masternode_by_pro_reg_tx_hash(
46-
&self,
47-
registration_hash: &ProTxHash,
48-
) -> Option<QualifiedMasternodeListEntry> {
49-
self.masternodes.get(registration_hash).cloned()
50-
}
5128

52-
pub fn reversed_pro_reg_tx_hashes_cloned(&self) -> Vec<ProTxHash> {
53-
self.masternodes.keys().cloned().collect()
54-
}
5529
pub fn reversed_pro_reg_tx_hashes(&self) -> Vec<&ProTxHash> {
5630
self.masternodes.keys().collect()
5731
}
58-
59-
pub fn sorted_reversed_pro_reg_tx_hashes(&self) -> Vec<&ProTxHash> {
60-
let mut hashes = self.reversed_pro_reg_tx_hashes();
61-
hashes.sort_by(|&s1, &s2| s2.reverse().cmp(&s1.reverse()));
62-
hashes
63-
}
64-
65-
pub fn provider_tx_ordered_hashes(&self) -> Vec<ProTxHash> {
66-
let mut vec = Vec::from_iter(self.masternodes.keys().cloned());
67-
vec.sort_by(|hash1, hash2| {
68-
if reverse_cmp_sup(hash1.to_byte_array(), hash2.to_byte_array()) {
69-
Ordering::Greater
70-
} else {
71-
Ordering::Less
72-
}
73-
});
74-
vec
75-
}
76-
pub fn compare_provider_tx_ordered_hashes(&self, list: MasternodeList) -> bool {
77-
self.provider_tx_ordered_hashes().eq(&list.provider_tx_ordered_hashes())
78-
}
79-
80-
pub fn compare_masternodes(&self, list: MasternodeList) -> bool {
81-
let mut vec1 = Vec::from_iter(self.masternodes.values());
82-
vec1.sort();
83-
let mut vec2 = Vec::from_iter(list.masternodes.values());
84-
vec2.sort();
85-
vec1.eq(&vec2)
86-
}
8732
}
8833

8934
pub fn reverse_cmp_sup(lhs: [u8; 32], rhs: [u8; 32]) -> bool {

dash/src/sml/masternode_list/merkle_roots.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::transaction::special_transaction::TransactionPayload;
2020
/// - `Some([u8; 32])`: The computed Merkle root if at least one hash is provided.
2121
/// - `None`: If the input vector is empty.
2222
#[inline]
23-
pub fn merkle_root_from_hashes(hashes: Vec<[u8; 32]>) -> Option<[u8; 32]> {
23+
pub fn merkle_root_from_hashes(hashes: Vec<sha256d::Hash>) -> Option<sha256d::Hash> {
2424
let length = hashes.len();
2525
let mut level = hashes;
2626
match length {
@@ -29,12 +29,12 @@ pub fn merkle_root_from_hashes(hashes: Vec<[u8; 32]>) -> Option<[u8; 32]> {
2929
while level.len() != 1 {
3030
let len = level.len();
3131
let mut higher_level =
32-
Vec::<[u8; 32]>::with_capacity((0.5 * len as f64).ceil() as usize);
32+
Vec::<sha256d::Hash>::with_capacity((0.5 * len as f64).ceil() as usize);
3333
for pair in level.chunks(2) {
3434
let mut buffer = Vec::with_capacity(64);
35-
buffer.extend_from_slice(&pair[0]);
36-
buffer.extend_from_slice(pair.get(1).unwrap_or(&pair[0]));
37-
higher_level.push(sha256d::Hash::hash(&buffer).to_byte_array());
35+
buffer.extend_from_slice(pair[0].as_byte_array());
36+
buffer.extend_from_slice(pair.get(1).unwrap_or(&pair[0]).as_byte_array());
37+
higher_level.push(sha256d::Hash::hash(&buffer));
3838
}
3939
level = higher_level;
4040
}
@@ -126,7 +126,7 @@ impl MasternodeList {
126126
) -> Option<MerkleRootMasternodeList> {
127127
self.hashes_for_merkle_root(block_height)
128128
.and_then(merkle_root_from_hashes)
129-
.map(|hash| MerkleRootMasternodeList::from_byte_array(hash))
129+
.map(MerkleRootMasternodeList::from_raw_hash)
130130
}
131131

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

146146
/// Retrieves the list of hashes required to compute the masternode list Merkle root.
@@ -154,21 +154,16 @@ impl MasternodeList {
154154
///
155155
/// # Returns
156156
///
157-
/// - `Some(Vec<[u8; 32]>)`: A sorted list of masternode entry hashes.
157+
/// - `Some(Vec<sha256d::Hash>)`: A sorted list of masternode entry hashes.
158158
/// - `None`: If the block height is invalid (`u32::MAX`).
159-
pub fn hashes_for_merkle_root(&self, block_height: u32) -> Option<Vec<[u8; 32]>> {
159+
pub fn hashes_for_merkle_root(&self, block_height: u32) -> Option<Vec<sha256d::Hash>> {
160160
(block_height != u32::MAX).then_some({
161161
let mut pro_tx_hashes = self.reversed_pro_reg_tx_hashes();
162162
pro_tx_hashes.sort_by(|&s1, &s2| s1.reverse().cmp(&s2.reverse()));
163163
pro_tx_hashes
164164
.into_iter()
165165
.map(|hash| self.masternodes[hash].entry_hash)
166166
.collect::<Vec<_>>()
167-
//this was the following: (with entry_hash_at)
168-
// pro_tx_hashes
169-
// .into_iter()
170-
// .map(|hash| (&self.masternodes[hash]).entry_hash_at(block_height))
171-
// .collect::<Vec<_>>()
172167
})
173168
}
174169

@@ -180,11 +175,11 @@ impl MasternodeList {
180175
/// # Returns
181176
///
182177
/// - `Vec<[u8; 32]>`: A sorted list of quorum commitment hashes.
183-
pub fn hashes_for_quorum_merkle_root(&self) -> Vec<[u8; 32]> {
178+
pub fn hashes_for_quorum_merkle_root(&self) -> Vec<sha256d::Hash> {
184179
let mut llmq_commitment_hashes = self
185180
.quorums
186181
.values()
187-
.flat_map(|q_map| q_map.values().map(|entry| entry.entry_hash.to_byte_array()))
182+
.flat_map(|q_map| q_map.values().map(|entry| entry.entry_hash.to_raw_hash()))
188183
.collect::<Vec<_>>();
189184
llmq_commitment_hashes.sort();
190185
llmq_commitment_hashes

0 commit comments

Comments
 (0)