Skip to content

Commit ec197ed

Browse files
more work on rotation
1 parent fa73e8e commit ec197ed

File tree

15 files changed

+363
-353
lines changed

15 files changed

+363
-353
lines changed

dash/src/network/message_qrinfo.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use core::fmt::{Display, Formatter};
22
use std::{fmt, io};
3+
use bincode::{Decode, Encode};
34
use crate::BlockHash;
45
use crate::consensus::{encode, Decodable, Encodable};
56
use crate::consensus::encode::{read_compact_size, read_fixed_bitset, write_fixed_bitset};
@@ -149,6 +150,7 @@ impl Decodable for QRInfo {
149150
/// - `mn_skip_list_size`: A compact-size unsigned integer representing the number of skip list entries.
150151
/// - `mn_skip_list`: An array of 4-byte signed integers, one per skip list entry.
151152
#[derive(PartialEq, Eq, Clone, Debug)]
153+
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
152154
pub struct QuorumSnapshot {
153155
pub skip_list_mode: MNSkipListMode,
154156
pub active_quorum_members: Vec<bool>, // Bitset, length = (active_quorum_members_count + 7) / 8
@@ -206,6 +208,7 @@ impl Decodable for QuorumSnapshot {
206208

207209
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
208210
#[repr(u32)]
211+
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
209212
pub enum MNSkipListMode {
210213
/// Mode 0: No skipping – the skip list is empty.
211214
NoSkipping = 0,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
2+
pub struct LLMQIndexedHash {
3+
pub index: u32,
4+
pub hash: [u8; 32],
5+
}
6+
7+
impl LLMQIndexedHash {
8+
pub fn new(hash: [u8; 32], index: u32) -> Self {
9+
LLMQIndexedHash { index, hash }
10+
}
11+
}
12+
13+
impl From<([u8; 32], usize)> for LLMQIndexedHash {
14+
fn from(value: ([u8; 32], usize)) -> Self {
15+
Self::new(value.0, value.1 as u32)
16+
}
17+
}
18+
impl From<([u8; 32], u32)> for LLMQIndexedHash {
19+
fn from(value: ([u8; 32], u32)) -> Self {
20+
Self::new(value.0, value.1)
21+
}
22+
}

dash/src/sml/llmq_type/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod network;
22
pub mod rotation;
3+
pub(crate) mod llmq_indexed_hash;
34

45
use std::fmt::{Display, Formatter};
56
use std::io;

dash/src/sml/llmq_type/rotation.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@ pub enum LLMQQuarterType {
99
}
1010

1111
#[derive(Clone, Copy)]
12-
pub enum LLMQQuarterReconstructionType<'a> {
12+
pub enum LLMQQuarterReconstructionType<'a: 'b, 'b> {
1313
Snapshot,
1414
New {
15-
previous_quarters: [&'a Vec<Vec<QualifiedMasternodeListEntry>>; 3],
15+
previous_quarters: [&'b Vec<Vec<&'a QualifiedMasternodeListEntry>>; 3],
1616
skip_removed_masternodes: bool,
1717
}
1818
}
1919

20-
pub enum LLMQQuarterUsageType {
20+
pub enum LLMQQuarterUsageType<'a> {
2121
Snapshot(QuorumSnapshot),
22-
New(Vec<Vec<QualifiedMasternodeListEntry>>)
22+
New(Vec<Vec<&'a QualifiedMasternodeListEntry>>)
2323
}

dash/src/sml/masternode_list/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod from_diff;
99
mod apply_diff;
1010
mod scores_for_quorum;
1111
mod rotation;
12+
mod valid_members_in_rotated_quorum;
1213

1314
use std::collections::BTreeMap;
1415
#[cfg(feature = "bincode")]

dash/src/sml/masternode_list/rotated_quorums_info.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use crate::sml::masternode_list::MasternodeList;
22
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
33

44
impl MasternodeList {
5-
pub fn usage_info(&self, previous_quarters: [&Vec<Vec<QualifiedMasternodeListEntry>>; 3], skip_removed_masternodes: bool, quorum_count: usize) -> (Vec<QualifiedMasternodeListEntry>, Vec<QualifiedMasternodeListEntry>, Vec<Vec<QualifiedMasternodeListEntry>>) {
6-
let mut used_at_h_masternodes = Vec::<QualifiedMasternodeListEntry>::new();
7-
let mut used_at_h_indexed_masternodes = vec![Vec::<QualifiedMasternodeListEntry>::new(); quorum_count];
5+
pub fn usage_info<'a>(&'a self, previous_quarters: [&Vec<Vec<&'a QualifiedMasternodeListEntry>>; 3], skip_removed_masternodes: bool, quorum_count: usize) -> (Vec<&'a QualifiedMasternodeListEntry>, Vec<&'a QualifiedMasternodeListEntry>, Vec<Vec<&'a QualifiedMasternodeListEntry>>) {
6+
let mut used_at_h_masternodes = Vec::<&QualifiedMasternodeListEntry>::new();
7+
let mut used_at_h_indexed_masternodes = vec![Vec::<&QualifiedMasternodeListEntry>::new(); quorum_count];
88
for i in 0..quorum_count {
99
// for quarters h - c, h -2c, h -3c
1010
for quarter in &previous_quarters {
@@ -14,10 +14,10 @@ impl MasternodeList {
1414
if (!skip_removed_masternodes || self.has_masternode(&hash)) &&
1515
self.has_valid_masternode(&hash) {
1616
if !used_at_h_masternodes.iter().any(|m| m.masternode_list_entry.pro_reg_tx_hash == hash) {
17-
used_at_h_masternodes.push(node.clone());
17+
used_at_h_masternodes.push(node);
1818
}
1919
if !used_at_h_indexed_masternodes[i].iter().any(|m| m.masternode_list_entry.pro_reg_tx_hash == hash) {
20-
used_at_h_indexed_masternodes[i].push(node.clone());
20+
used_at_h_indexed_masternodes[i].push(node);
2121
}
2222
}
2323
}
@@ -26,7 +26,6 @@ impl MasternodeList {
2626
}
2727
let unused_at_h_masternodes = self.masternodes.values()
2828
.filter(|mn| mn.masternode_list_entry.is_valid && !used_at_h_masternodes.iter().any(|node| mn.masternode_list_entry.pro_reg_tx_hash == node.masternode_list_entry.pro_reg_tx_hash))
29-
.cloned()
3029
.collect();
3130
(used_at_h_masternodes, unused_at_h_masternodes, used_at_h_indexed_masternodes)
3231

Lines changed: 0 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +0,0 @@
1-
use std::collections::BTreeMap;
2-
use crate::BlockHash;
3-
use crate::prelude::CoreBlockHeight;
4-
use crate::sml::llmq_type::{LLMQParams, LLMQType};
5-
use crate::sml::llmq_type::rotation::LLMQQuarterReconstructionType;
6-
use crate::sml::masternode_list::MasternodeList;
7-
use crate::sml::masternode_list_entry::MasternodeListEntry;
8-
use crate::sml::quorum_validation_error::QuorumValidationError;
9-
10-
impl MasternodeList {
11-
fn rotate_members(
12-
&self,
13-
cycle_base_height: u32,
14-
llmq_params: LLMQParams,
15-
skip_removed_masternodes: bool,
16-
// cache: &Arc<RwLock<MasternodeProcessorCache>>
17-
// cached_mn_lists: &BTreeMap<UInt256, MasternodeList>,
18-
// cached_llmq_snapshots: &BTreeMap<UInt256, LLMQSnapshot>,
19-
// cached_cl_signatures: &BTreeMap<UInt256, UInt768>,
20-
// unknown_mn_lists: &mut Vec<UInt256>,
21-
) -> Result<Vec<Vec<MasternodeListEntry>>, QuorumValidationError> {
22-
let num_quorums = llmq_params.signing_active_quorum_count as usize;
23-
let cycle_length = llmq_params.dkg_params.interval;
24-
let work_block_height_for_index = |index: u32| (cycle_base_height - index * cycle_length) - 8;
25-
// Reconstruct quorum members at h - 3c from snapshot
26-
let q_h_m_3c = self.quorum_quarter_members_by_reconstruction_type(LLMQQuarterReconstructionType::Snapshot, &llmq_params, work_block_height_for_index(3))?;
27-
// Reconstruct quorum members at h - 2c from snapshot
28-
let q_h_m_2c = self.quorum_quarter_members_by_reconstruction_type(LLMQQuarterReconstructionType::Snapshot, &llmq_params, work_block_height_for_index(2))?;
29-
// Reconstruct quorum members at h - c from snapshot
30-
let q_h_m_c = self.quorum_quarter_members_by_reconstruction_type(LLMQQuarterReconstructionType::Snapshot, &llmq_params, work_block_height_for_index(1))?;
31-
// Determine quorum members at new index
32-
let reconstruction_type = LLMQQuarterReconstructionType::New { previous_quarters: [&q_h_m_c, &q_h_m_2c, &q_h_m_3c], skip_removed_masternodes };
33-
let quarter_new = self.quorum_quarter_members_by_reconstruction_type(reconstruction_type, &llmq_params, work_block_height_for_index(0))?;
34-
let mut quorum_members =
35-
Vec::<Vec<MasternodeListEntry>>::with_capacity(num_quorums);
36-
(0..num_quorums).for_each(|index| {
37-
add_quorum_members_from_quarter(&mut quorum_members, &q_h_m_3c, index);
38-
add_quorum_members_from_quarter(&mut quorum_members, &q_h_m_2c, index);
39-
add_quorum_members_from_quarter(&mut quorum_members, &q_h_m_c, index);
40-
add_quorum_members_from_quarter(&mut quorum_members, &quarter_new, index);
41-
});
42-
Ok(quorum_members)
43-
}
44-
45-
/// Determine masternodes which is responsible for signing at this quorum index
46-
#[allow(clippy::too_many_arguments)]
47-
pub fn get_rotated_masternodes_for_quorum(
48-
&self,
49-
llmq_type: LLMQType,
50-
block_hash: BlockHash,
51-
block_height: CoreBlockHeight,
52-
skip_removed_masternodes: bool,
53-
) -> Result<Vec<MasternodeListEntry>, CoreProviderError> {
54-
let mut llmq_members_lock = self.cache.llmq_members.write().unwrap();
55-
let cached_members_of_llmq_type_opt = llmq_members_lock.get_mut(&llmq_type);
56-
if cached_members_of_llmq_type_opt.is_some() {
57-
if let Some(cached_members) = cached_members_of_llmq_type_opt.as_ref().unwrap().get(&block_hash).cloned() {
58-
drop(llmq_members_lock);
59-
return Ok(cached_members);
60-
}
61-
} else {
62-
llmq_members_lock.insert(llmq_type.clone(), BTreeMap::new());
63-
}
64-
65-
let cached_members_of_llmq_type = llmq_members_lock.get_mut(&llmq_type).unwrap();
66-
let llmq_params = llmq_type.params();
67-
let quorum_index = block_height % llmq_params.dkg_params.interval;
68-
let cycle_base_height = block_height - quorum_index;
69-
let cycle_base_hash = self.provider.lookup_block_hash_by_height(cycle_base_height);
70-
let mut llmq_indexed_members_lock = self.cache.llmq_indexed_members.write().unwrap();
71-
if let Some(map_by_type_indexed) = llmq_indexed_members_lock.get(&llmq_type) {
72-
let indexed_hash = LLMQIndexedHash::from((cycle_base_hash, quorum_index));
73-
if let Some(cached_members) = map_by_type_indexed.get(&indexed_hash).cloned() {
74-
cached_members_of_llmq_type.insert(block_hash, cached_members.clone());
75-
drop(llmq_members_lock);
76-
drop(llmq_indexed_members_lock);
77-
return Ok(cached_members);
78-
}
79-
} else {
80-
llmq_indexed_members_lock.insert(llmq_type.clone(), BTreeMap::new());
81-
}
82-
drop(llmq_indexed_members_lock);
83-
let rotated_members = self.rotate_members(cycle_base_height, llmq_params, skip_removed_masternodes)?;
84-
let result = if let Some(rotated_members_at_index) = rotated_members.get(quorum_index as usize) {
85-
cached_members_of_llmq_type.insert(block_hash, rotated_members_at_index.clone());
86-
Ok(rotated_members_at_index.clone())
87-
} else {
88-
Err(CoreProviderError::NullResult(format!("No rotated_members for llmq index {} ({})", quorum_index, block_hash.to_hex())))
89-
};
90-
drop(llmq_members_lock);
91-
92-
self.cache.write_llmq_indexed_members(|lock| {
93-
lock.get_mut(&llmq_type)
94-
.unwrap()
95-
.extend(rotated_members.into_iter()
96-
.enumerate()
97-
.map(|(index, members)|
98-
(LLMQIndexedHash::from((cycle_base_hash, index)), members)));
99-
});
100-
result
101-
}
102-
}
Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,71 @@
11
use std::collections::BTreeMap;
22
use crate::hash_types::{QuorumModifierHash, ScoreHash};
33
use crate::Network;
4+
use crate::network::message_qrinfo::QuorumSnapshot;
45
use crate::sml::masternode_list::MasternodeList;
56
use crate::sml::masternode_list_entry::MasternodeType;
67
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
78
use crate::sml::quorum_entry::qualified_quorum_entry::QualifiedQuorumEntry;
89
use crate::sml::quorum_entry::quorum_modifier_type::LLMQModifierType;
910

1011
impl MasternodeList {
11-
pub fn valid_masternodes_for_quorum<T>(
12-
&self,
12+
pub fn valid_masternodes_for_quorum<'a, T>(
13+
&'a self,
1314
quorum: &QualifiedQuorumEntry,
1415
quorum_modifier: LLMQModifierType,
1516
network: Network,
1617
) -> T
17-
where T: FromIterator<QualifiedMasternodeListEntry> {
18+
where T: FromIterator<&'a QualifiedMasternodeListEntry> {
1819
let llmq_type = quorum.quorum_entry.llmq_type;
1920
let hpmn_only = llmq_type == network.platform_type();
2021
let quorum_modifier = quorum_modifier.build_llmq_hash();
2122
let score_dictionary = self.scores_for_quorum(quorum_modifier, hpmn_only);
2223
score_dictionary.into_values().rev().take(llmq_type.size() as usize).collect()
2324
}
2425

25-
pub fn scores_for_quorum(
26-
&self,
26+
pub fn used_and_unused_masternodes_for_quorum<'a>(
27+
&'a self,
28+
quorum: &QualifiedQuorumEntry,
29+
quorum_modifier: LLMQModifierType,
30+
quorum_snapshot: &QuorumSnapshot,
31+
network: Network,
32+
) -> (Vec<&'a QualifiedMasternodeListEntry>, Vec<&'a QualifiedMasternodeListEntry>)
33+
{
34+
let llmq_type = quorum.quorum_entry.llmq_type;
35+
let hpmn_only = llmq_type == network.platform_type();
36+
let quorum_modifier = quorum_modifier.build_llmq_hash();
37+
let score_dictionary = self.scores_for_quorum(quorum_modifier, hpmn_only);
38+
let masternode_entry_list: Vec<&QualifiedMasternodeListEntry> = score_dictionary.into_values().rev().collect();
39+
let mut i = 0;
40+
masternode_entry_list.into_iter().partition(|(_)| {
41+
let used = quorum_snapshot.active_quorum_members.get(i).copied().unwrap_or_default();
42+
i += 1;
43+
used
44+
})
45+
}
46+
47+
pub fn scores_for_quorum_for_masternodes<'a, T>(
48+
entries: T,
2749
quorum_modifier: QuorumModifierHash,
2850
hpmn_only: bool,
29-
) -> BTreeMap<ScoreHash, QualifiedMasternodeListEntry> {
30-
self.masternodes.values().filter_map(|entry| {
51+
) -> BTreeMap<ScoreHash, &'a QualifiedMasternodeListEntry>
52+
where
53+
T: IntoIterator<Item = &'a QualifiedMasternodeListEntry> {
54+
entries.into_iter().filter_map(|entry| {
3155
if !hpmn_only || matches!(entry.masternode_list_entry.mn_type, MasternodeType::HighPerformance{..}) {
3256
entry.score(quorum_modifier)
33-
.map(|score| (score, entry.clone()))
57+
.map(|score| (score, entry))
3458
} else {
3559
None
3660
}
3761
}).collect()
3862
}
63+
64+
pub fn scores_for_quorum(
65+
&self,
66+
quorum_modifier: QuorumModifierHash,
67+
hpmn_only: bool,
68+
) -> BTreeMap<ScoreHash, &QualifiedMasternodeListEntry> {
69+
Self::scores_for_quorum_for_masternodes(self.masternodes.values(), quorum_modifier, hpmn_only)
70+
}
3971
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::collections::BTreeMap;
2+
use crate::BlockHash;
3+
use crate::prelude::CoreBlockHeight;
4+
use crate::sml::llmq_type::llmq_indexed_hash::LLMQIndexedHash;
5+
use crate::sml::llmq_type::LLMQType;
6+
use crate::sml::masternode_list::MasternodeList;
7+
use crate::sml::masternode_list_entry::MasternodeListEntry;
8+
use crate::sml::masternode_list_entry::qualified_masternode_list_entry::QualifiedMasternodeListEntry;
9+
use crate::sml::quorum_validation_error::QuorumValidationError;
10+
11+
impl MasternodeList {
12+
13+
}

dash/src/sml/masternode_list_engine/mod.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(feature = "quorum_validation")]
22
mod validation;
3-
mod rotation;
3+
mod rotated_quorum_construction;
4+
mod non_rotated_quorum_construction;
45

56
use std::collections::{BTreeMap, BTreeSet};
67
#[cfg(feature = "bincode")]
@@ -9,6 +10,7 @@ use bincode::{Decode, Encode};
910
use serde::{Deserialize, Serialize};
1011
use crate::{BlockHash, Network, QuorumHash};
1112
use crate::bls_sig_utils::BLSSignature;
13+
use crate::network::message_qrinfo::QuorumSnapshot;
1214
use crate::network::message_sml::MnListDiff;
1315
use crate::prelude::CoreBlockHeight;
1416
use crate::sml::error::SmlError;
@@ -27,6 +29,7 @@ pub struct MasternodeListEngine {
2729
pub block_heights : BTreeMap<BlockHash, CoreBlockHeight>,
2830
pub masternode_lists : BTreeMap<CoreBlockHeight, MasternodeList>,
2931
pub known_chain_locks: BTreeMap<BlockHash, BLSSignature>,
32+
pub known_snapshots: BTreeMap<BlockHash, QuorumSnapshot>,
3033
pub network: Network,
3134
}
3235

@@ -40,6 +43,7 @@ impl MasternodeListEngine {
4043
block_heights: [(base_block_hash, 0), (block_hash, block_height)].into(),
4144
masternode_lists: [(block_height, masternode_list)].into(),
4245
known_chain_locks: Default::default(),
46+
known_snapshots: Default::default(),
4347
network,
4448
})
4549
}
@@ -66,21 +70,6 @@ impl MasternodeListEngine {
6670
.unwrap_or_default()
6771
}
6872

69-
pub fn masternode_list_and_height_for_block_hash_8_blocks_ago(
70-
&self,
71-
block_hash: &BlockHash,
72-
) -> Result<(&MasternodeList, CoreBlockHeight), QuorumValidationError> {
73-
if let Some(height) = self.block_heights.get(block_hash) {
74-
if let Some(masternode_list) = self.masternode_lists.get(&(height.saturating_sub(8))) {
75-
Ok((masternode_list, height.saturating_sub(8)))
76-
} else {
77-
Err(QuorumValidationError::RequiredMasternodeListNotPresent(height.saturating_sub(8)))
78-
}
79-
} else {
80-
Err(QuorumValidationError::RequiredBlockNotPresent(*block_hash))
81-
}
82-
}
83-
8473
pub fn masternode_list_for_block_hash(&self, block_hash: &BlockHash) -> Option<&MasternodeList> {
8574
self.block_heights.get(block_hash).and_then(|height| self.masternode_lists.get(height))
8675
}

0 commit comments

Comments
 (0)