diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs index 323918cf39..50ad933c42 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs @@ -3,6 +3,7 @@ use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorumsV0Methods; use std::collections::BTreeMap; use crate::platform_types::validator_set::v0::{ValidatorSetV0, ValidatorSetV0Getters}; @@ -37,13 +38,15 @@ where ) -> Result<(), Error> { let _span = tracing::span!(Level::TRACE, "update_quorum_info", core_block_height).entered(); + let last_committed_core_height = block_platform_state.last_committed_core_height(); + if start_from_scratch { tracing::debug!("update quorum info from scratch up to {core_block_height}"); - } else if core_block_height != block_platform_state.last_committed_core_height() { + } else if core_block_height != last_committed_core_height { tracing::debug!( - previous_core_block_height = block_platform_state.last_committed_core_height(), + previous_core_block_height = last_committed_core_height, "update quorum info from {} to {}", - block_platform_state.last_committed_core_height(), + last_committed_core_height, core_block_height ); } else { @@ -173,26 +176,27 @@ where if validator_set_quorum_type == chain_lock_quorum_type { // Remove validator_sets entries that are no longer valid for the core block height if removed_a_validator_set || added_a_validator_set { - let chain_lock_validating_quorums = block_platform_state + let quorums = block_platform_state .validator_sets() .iter() .map(|(quorum_hash, validator_set)| { (*quorum_hash, validator_set.threshold_public_key().clone()) }) .collect(); - let previous_quorums = block_platform_state - .replace_chain_lock_validating_quorums(chain_lock_validating_quorums); - tracing::trace!("updated chain lock validating quorums to current validator set",); - // the only case where there will be no platform_state is init chain where we + + tracing::trace!("updated chain lock validating quorums to current validator set"); + if platform_state.is_some() { - block_platform_state.set_previous_chain_lock_validating_quorums( - block_platform_state.last_committed_core_height(), - core_block_height, - block_platform_state - .previous_height_chain_lock_validating_quorums() - .map(|(_, previous_change_height, _, _)| *previous_change_height), - previous_quorums, - ); + // we already have state, so we update last and previous quorums + block_platform_state + .chain_lock_validating_quorums_mut() + .rotate_quorums(quorums, last_committed_core_height, core_block_height); + } else { + // the only case where there will be no platform_state is init chain, + // so there is no previous quorums to update + block_platform_state + .chain_lock_validating_quorums_mut() + .set_current_quorums(quorums) } } } else { @@ -216,6 +220,7 @@ where // Remove chain_lock_validating_quorums entries that are no longer valid for the core block height block_platform_state .chain_lock_validating_quorums_mut() + .current_quorums_mut() .retain(|quorum_hash, _| { let retain = chain_lock_quorums_list.contains_key::(quorum_hash); if !retain { @@ -237,6 +242,7 @@ where .filter(|(key, _)| { !block_platform_state .chain_lock_validating_quorums() + .current_quorums() .contains_key::(key) }) .map(|(key, _)| { @@ -280,21 +286,22 @@ where // Add new validator_sets entries block_platform_state .chain_lock_validating_quorums_mut() + .current_quorums_mut() .extend(new_chain_lock_quorums); } if added_a_chain_lock_validating_quorum || removed_a_chain_lock_validating_quorum { if let Some(old_state) = platform_state { let previous_chain_lock_validating_quorums = - old_state.chain_lock_validating_quorums().clone(); - block_platform_state.set_previous_chain_lock_validating_quorums( - block_platform_state.last_committed_core_height(), - core_block_height, - block_platform_state - .previous_height_chain_lock_validating_quorums() - .map(|(_, previous_change_height, _, _)| *previous_change_height), - previous_chain_lock_validating_quorums, - ); + old_state.chain_lock_validating_quorums().current_quorums(); + + block_platform_state + .chain_lock_validating_quorums_mut() + .set_previous_past_quorums( + previous_chain_lock_validating_quorums.clone(), + last_committed_core_height, + core_block_height, + ); } } } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs index 903617642b..d0f7b60af8 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs @@ -9,8 +9,10 @@ use crate::platform_types::platform::Platform; use crate::rpc::core::CoreRPCLike; +use crate::error::execution::ExecutionError; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorumsV0Methods; use dpp::version::PlatformVersion; const CHAIN_LOCK_REQUEST_ID_PREFIX: &str = "clsig"; @@ -61,55 +63,9 @@ where return Ok(None); // the chain lock is too far in the future or the past to verify locally } - let (probable_quorums, second_to_check_quorums, should_be_verifiable) = if let Some(( - previous_quorum_height, - change_quorum_height, - previous_quorums_change_height, - previous_quorums, - )) = - platform_state.previous_height_chain_lock_validating_quorums() - { - if chain_lock_height > 8 && verification_height >= *change_quorum_height { - // in this case we are sure that we should be targeting the current quorum - // We updated core chain lock height from 100 to 105, new chain lock comes in for block 114 - // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 106 (new chain lock verification height 114 - 8) - // We are sure that we should use current quorums - // If we have - // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 105 (new chain lock verification height 113 - 8) - // We should also use current quorums, this is because at 105 we are sure new chain lock validating quorums are active - (platform_state.chain_lock_validating_quorums(), None, true) - } else if chain_lock_height > 8 && verification_height <= *previous_quorum_height { - let should_be_verifiable = previous_quorums_change_height - .map(|previous_quorums_change_height| { - verification_height > previous_quorums_change_height - }) - .unwrap_or(false); - // In this case the quorums were changed recently meaning that we should use the previous quorums to verify the chain lock - // We updated core chain lock height from 100 to 105, new chain lock comes in for block 106 - // -------- 98 (new chain lock verification height 106 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) - // We are sure that we should use previous quorums - // If we have - // -------- 100 (new chain lock verification height 108 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) - // We should also use previous quorums, this is because at 100 we are sure the old quorum set was active - (previous_quorums, None, should_be_verifiable) - } else { - let should_be_verifiable = previous_quorums_change_height - .map(|previous_quorums_change_height| { - verification_height > previous_quorums_change_height - }) - .unwrap_or(false); - // we are in between, so we don't actually know if it was the old one or the new one to be used. - // ------- 100 (previous_quorum_height) ------ 104 (new chain lock verification height 112 - 8) -------105 (change_quorum_height) - // we should just try both, starting with the current quorums - ( - platform_state.chain_lock_validating_quorums(), - Some(previous_quorums), - should_be_verifiable, - ) - } - } else { - (platform_state.chain_lock_validating_quorums(), None, false) - }; + let mut selected_quorum_sets = platform_state + .chain_lock_validating_quorums() + .select_quorums(chain_lock_height, verification_height); // From DIP 8: https://github.com/dashpay/dips/blob/master/dip-0008.md#finalization-of-signed-blocks // The request id is SHA256("clsig", blockHeight) and the message hash is the block hash of the previously successful attempt. @@ -130,6 +86,11 @@ where ); // Based on the deterministic masternode list at the given height, a quorum must be selected that was active at the time this block was mined + let probable_quorums = selected_quorum_sets.next().ok_or_else(|| { + Error::Execution(ExecutionError::CorruptedCodeExecution( + "at lest one set of quorums must be selected", + )) + })?; let quorum = Platform::::choose_quorum( self.config.chain_lock_quorum_type(), @@ -172,7 +133,7 @@ where if !chain_lock_verified { // We should also check the other quorum, as there could be the situation where the core height wasn't updated every block. - if let Some(second_to_check_quorums) = second_to_check_quorums { + if let Some(second_to_check_quorums) = selected_quorum_sets.next() { let quorum = Platform::::choose_quorum( self.config.chain_lock_quorum_type(), second_to_check_quorums, @@ -215,7 +176,8 @@ where ); } } else if platform_state - .previous_height_chain_lock_validating_quorums() + .chain_lock_validating_quorums() + .previous_past_quorums() .is_none() { // we don't have old quorums, this means our node is very new. @@ -223,7 +185,7 @@ where "we had no previous quorums locally, we should validate through core", ); return Ok(None); - } else if !should_be_verifiable { + } else if !selected_quorum_sets.should_be_verifiable { tracing::debug!( "we were in a situation where it would be possible we didn't have all quorums and we couldn't verify locally, we should validate through core", ); diff --git a/packages/rs-drive-abci/src/platform_types/mod.rs b/packages/rs-drive-abci/src/platform_types/mod.rs index 7602529bab..66a86cbbee 100644 --- a/packages/rs-drive-abci/src/platform_types/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/mod.rs @@ -47,6 +47,8 @@ pub mod platform; pub mod platform_state; /// Required identity public key set for system identities pub mod required_identity_public_key_set; +/// Signature verification quorums +pub mod signature_verification_quorums; /// The state transition execution result as part of the block execution outcome pub mod state_transitions_processing_result; /// System identity public keys @@ -56,8 +58,7 @@ pub mod system_identity_public_keys; pub mod validator; /// Quorum methods pub mod validator_set; -/// Withdrawal types -pub mod withdrawal; - /// Verify chain lock result pub mod verify_chain_lock_result; +/// Withdrawal types +pub mod withdrawal; diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index b5d5b88ec7..be67bdb11e 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -21,8 +21,8 @@ use dpp::ProtocolError; use indexmap::IndexMap; use crate::error::execution::ExecutionError; +use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorums; use dpp::block::block_info::BlockInfo; -use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; use dpp::util::hash::hash_double; use std::collections::BTreeMap; @@ -316,7 +316,7 @@ impl PlatformStateV0Methods for PlatformState { } } - fn chain_lock_validating_quorums(&self) -> &BTreeMap { + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums { match self { PlatformState::V0(v0) => &v0.chain_lock_validating_quorums, } @@ -382,41 +382,12 @@ impl PlatformStateV0Methods for PlatformState { } } - fn set_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ) { + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums) { match self { PlatformState::V0(v0) => v0.set_chain_lock_validating_quorums(quorums), } } - fn replace_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ) -> BTreeMap { - match self { - PlatformState::V0(v0) => v0.replace_chain_lock_validating_quorums(quorums), - } - } - - fn set_previous_chain_lock_validating_quorums( - &mut self, - previous_core_height: u32, - change_core_height: u32, - previous_quorums_change_height: Option, - quorums: BTreeMap, - ) { - match self { - PlatformState::V0(v0) => v0.set_previous_chain_lock_validating_quorums( - previous_core_height, - change_core_height, - previous_quorums_change_height, - quorums, - ), - } - } - fn set_full_masternode_list(&mut self, list: BTreeMap) { match self { PlatformState::V0(v0) => v0.set_full_masternode_list(list), @@ -471,40 +442,12 @@ impl PlatformStateV0Methods for PlatformState { } } - fn chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut BTreeMap { + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums { match self { PlatformState::V0(v0) => v0.chain_lock_validating_quorums_mut(), } } - fn previous_height_chain_lock_validating_quorums( - &self, - ) -> Option<&( - u32, - u32, - Option, - BTreeMap, - )> { - match self { - PlatformState::V0(v0) => v0.previous_height_chain_lock_validating_quorums(), - } - } - - fn previous_height_chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut Option<( - u32, - u32, - Option, - BTreeMap, - )> { - match self { - PlatformState::V0(v0) => v0.previous_height_chain_lock_validating_quorums_mut(), - } - } - fn full_masternode_list_mut(&mut self) -> &mut BTreeMap { match self { PlatformState::V0(v0) => v0.full_masternode_list_mut(), diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs index 224bd39ecd..4a9da76867 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs @@ -17,9 +17,9 @@ use crate::platform_types::masternode::Masternode; use crate::platform_types::validator_set::ValidatorSet; use dpp::block::block_info::{BlockInfo, DEFAULT_BLOCK_INFO}; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; -use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; use dpp::version::{PlatformVersion, TryIntoPlatformVersioned}; +use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorums; use itertools::Itertools; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; @@ -45,23 +45,7 @@ pub struct PlatformStateV0 { pub validator_sets: IndexMap, /// The current quorums used for validating chain locks (400 60 for mainnet) - pub chain_lock_validating_quorums: BTreeMap, - - /// The slightly old quorums used for validating chain locks, it's important to keep - /// these because validation of signatures happens for the quorums that are 8 blocks before the - /// height written in the chain lock (400 60 for mainnet) - /// The first u32 is the core height at which these chain lock validating quorums were last active - /// The second u32 is the core height we are changing at. - /// The third u32 is the core height the previous chain lock validating quorums became active. - /// Keeping all three is important for verifying the chain locks, as we can detect edge cases where we - /// must check a chain lock with both the previous height chain lock validating quorums and the - /// current ones - pub previous_height_chain_lock_validating_quorums: Option<( - u32, - u32, - Option, - BTreeMap, - )>, + pub chain_lock_validating_quorums: SignatureVerificationQuorums, /// current full masternode list pub full_masternode_list: BTreeMap, @@ -101,6 +85,10 @@ impl Debug for PlatformStateV0 { .field("full_masternode_list", &self.full_masternode_list) .field("hpmn_masternode_list", &self.hpmn_masternode_list) .field("initialization_information", &self.genesis_block_info) + .field( + "chain_lock_validating_quorums", + &self.chain_lock_validating_quorums, + ) .finish() } } @@ -135,13 +123,7 @@ pub struct PlatformStateForSavingV0 { pub validator_sets: Vec<(Bytes32, ValidatorSet)>, /// The 400 60 quorums used for validating chain locks - #[bincode(with_serde)] - pub chain_lock_validating_quorums: Vec<(Bytes32, ThresholdBlsPublicKey)>, - - /// The quorums used for validating chain locks from a slightly previous height. - #[bincode(with_serde)] - pub previous_height_chain_lock_validating_quorums: - Option<(u32, u32, Option, Vec<(Bytes32, ThresholdBlsPublicKey)>)>, + pub chain_lock_validating_quorums: SignatureVerificationQuorums, /// current full masternode list pub full_masternode_list: BTreeMap, @@ -172,31 +154,7 @@ impl TryFrom for PlatformStateForSavingV0 { .into_iter() .map(|(k, v)| (k.to_byte_array().into(), v)) .collect(), - chain_lock_validating_quorums: value - .chain_lock_validating_quorums - .into_iter() - .map(|(k, v)| (k.to_byte_array().into(), v)) - .collect(), - previous_height_chain_lock_validating_quorums: value - .previous_height_chain_lock_validating_quorums - .map( - |( - previous_height, - change_height, - previous_quorums_change_height, - inner_value, - )| { - ( - previous_height, - change_height, - previous_quorums_change_height, - inner_value - .into_iter() - .map(|(k, v)| (k.to_byte_array().into(), v)) - .collect(), - ) - }, - ), + chain_lock_validating_quorums: value.chain_lock_validating_quorums, full_masternode_list: value .full_masternode_list .into_iter() @@ -239,31 +197,7 @@ impl From for PlatformStateV0 { .into_iter() .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v)) .collect(), - chain_lock_validating_quorums: value - .chain_lock_validating_quorums - .into_iter() - .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v)) - .collect(), - previous_height_chain_lock_validating_quorums: value - .previous_height_chain_lock_validating_quorums - .map( - |( - previous_height, - change_height, - previous_quorums_change_height, - inner_value, - )| { - ( - previous_height, - change_height, - previous_quorums_change_height, - inner_value - .into_iter() - .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v)) - .collect(), - ) - }, - ), + chain_lock_validating_quorums: value.chain_lock_validating_quorums, full_masternode_list: value .full_masternode_list .into_iter() @@ -284,6 +218,9 @@ impl PlatformStateV0 { current_protocol_version_in_consensus: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, ) -> PlatformStateV0 { + let platform_version = PlatformVersion::get(current_protocol_version_in_consensus) + .expect("invalid protocol version"); + PlatformStateV0 { last_committed_block_info: None, current_protocol_version_in_consensus, @@ -291,8 +228,8 @@ impl PlatformStateV0 { current_validator_set_quorum_hash: QuorumHash::all_zeros(), next_validator_set_quorum_hash: None, validator_sets: Default::default(), - chain_lock_validating_quorums: Default::default(), - previous_height_chain_lock_validating_quorums: None, + chain_lock_validating_quorums: + SignatureVerificationQuorums::default_for_platform_version(platform_version), full_masternode_list: Default::default(), hpmn_masternode_list: Default::default(), genesis_block_info: None, @@ -347,7 +284,7 @@ pub trait PlatformStateV0Methods { fn validator_sets(&self) -> &IndexMap; /// Returns the current 400 60 quorums used to validate chain locks. - fn chain_lock_validating_quorums(&self) -> &BTreeMap; + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums; /// Returns the full list of masternodes. fn full_masternode_list(&self) -> &BTreeMap; @@ -380,25 +317,7 @@ pub trait PlatformStateV0Methods { fn set_validator_sets(&mut self, sets: IndexMap); /// Sets the current chain lock validating quorums. - fn set_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ); - - /// Sets the current chain lock validating quorums and returns the old value. - fn replace_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ) -> BTreeMap; - - /// Sets the previous chain lock validating quorums. - fn set_previous_chain_lock_validating_quorums( - &mut self, - previous_core_height: u32, - change_core_height: u32, - previous_quorums_change_height: Option, - quorums: BTreeMap, - ); + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums); /// Sets the full masternode list. fn set_full_masternode_list(&mut self, list: BTreeMap); @@ -427,19 +346,7 @@ pub trait PlatformStateV0Methods { fn validator_sets_mut(&mut self) -> &mut IndexMap; /// Returns a mutable reference to the current chain lock validating quorums. - fn chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut BTreeMap; - - /// Returns a mutable reference to the previous chain lock validating quorums. - fn previous_height_chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut Option<( - u32, - u32, - Option, - BTreeMap, - )>; + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums; /// Returns a mutable reference to the full masternode list. fn full_masternode_list_mut(&mut self) -> &mut BTreeMap; @@ -451,16 +358,6 @@ pub trait PlatformStateV0Methods { fn last_committed_block_epoch_ref(&self) -> &Epoch; /// The last block id hash fn last_committed_block_id_hash(&self) -> [u8; 32]; - - /// The previous height chain lock validating quorums - fn previous_height_chain_lock_validating_quorums( - &self, - ) -> Option<&( - u32, - u32, - Option, - BTreeMap, - )>; } impl PlatformStateV0Methods for PlatformStateV0 { @@ -603,7 +500,7 @@ impl PlatformStateV0Methods for PlatformStateV0 { } /// Returns the current 400 60 quorums used to validate chain locks. - fn chain_lock_validating_quorums(&self) -> &BTreeMap { + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums { &self.chain_lock_validating_quorums } @@ -664,37 +561,10 @@ impl PlatformStateV0Methods for PlatformStateV0 { } /// Sets the current chain lock validating quorums. - fn set_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ) { + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums) { self.chain_lock_validating_quorums = quorums; } - /// Swaps the current chain lock validating quorums and returns the old one - fn replace_chain_lock_validating_quorums( - &mut self, - quorums: BTreeMap, - ) -> BTreeMap { - std::mem::replace(&mut self.chain_lock_validating_quorums, quorums) - } - - /// Sets the previous chain lock validating quorums. - fn set_previous_chain_lock_validating_quorums( - &mut self, - previous_core_height: u32, - change_core_height: u32, - previous_quorums_change_height: Option, - quorums: BTreeMap, - ) { - self.previous_height_chain_lock_validating_quorums = Some(( - previous_core_height, - change_core_height, - previous_quorums_change_height, - quorums, - )); - } - /// Sets the full masternode list. fn set_full_masternode_list(&mut self, list: BTreeMap) { self.full_masternode_list = list; @@ -734,23 +604,10 @@ impl PlatformStateV0Methods for PlatformStateV0 { &mut self.validator_sets } - fn chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut BTreeMap { + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums { &mut self.chain_lock_validating_quorums } - fn previous_height_chain_lock_validating_quorums_mut( - &mut self, - ) -> &mut Option<( - u32, - u32, - Option, - BTreeMap, - )> { - &mut self.previous_height_chain_lock_validating_quorums - } - fn full_masternode_list_mut(&mut self) -> &mut BTreeMap { &mut self.full_masternode_list } @@ -773,15 +630,4 @@ impl PlatformStateV0Methods for PlatformStateV0 { .map(|block_info| *block_info.block_id_hash()) .unwrap_or_default() } - - fn previous_height_chain_lock_validating_quorums( - &self, - ) -> Option<&( - u32, - u32, - Option, - BTreeMap, - )> { - self.previous_height_chain_lock_validating_quorums.as_ref() - } } diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs new file mode 100644 index 0000000000..4ad03aebc3 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs @@ -0,0 +1,91 @@ +mod v0; + +use crate::platform_types::signature_verification_quorums::v0::{ + PreviousPastQuorums, SelectedVerificationQuorumSets, +}; +use bincode::{Decode, Encode}; +use derive_more::From; +use dpp::version::PlatformVersion; +pub use v0::{ + QuorumKeysByQuorumHash, SignatureVerificationQuorumsV0, SignatureVerificationQuorumsV0Methods, +}; + +/// Quorums with keys for signature verification +#[derive(Debug, Clone, Encode, Decode, From)] +pub enum SignatureVerificationQuorums { + /// Version 0 of the signature verification quorums + V0(SignatureVerificationQuorumsV0), +} + +impl SignatureVerificationQuorums { + /// Create a default SignatureVerificationQuorums + pub fn default_for_platform_version(platform_version: &PlatformVersion) -> Self { + // TODO: default for platform version + + SignatureVerificationQuorumsV0::default().into() + } +} + +impl SignatureVerificationQuorumsV0Methods for SignatureVerificationQuorums { + fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash) { + match self { + Self::V0(v0) => v0.set_current_quorums(quorums), + } + } + + fn current_quorums(&self) -> &QuorumKeysByQuorumHash { + match self { + Self::V0(v0) => v0.current_quorums(), + } + } + + fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash { + match self { + Self::V0(v0) => v0.current_quorums_mut(), + } + } + + fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums> { + match self { + Self::V0(v0) => v0.previous_past_quorums(), + } + } + + fn rotate_quorums( + &mut self, + quorums: QuorumKeysByQuorumHash, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + match self { + Self::V0(v0) => { + v0.rotate_quorums(quorums, last_active_core_height, updated_at_core_height) + } + } + } + + fn set_previous_past_quorums( + &mut self, + previous_quorums: QuorumKeysByQuorumHash, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + match self { + Self::V0(v0) => v0.set_previous_past_quorums( + previous_quorums, + last_active_core_height, + updated_at_core_height, + ), + } + } + + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedVerificationQuorumSets { + match self { + Self::V0(v0) => v0.select_quorums(signing_height, verification_height), + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs new file mode 100644 index 0000000000..6ab87f6f6b --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs @@ -0,0 +1,198 @@ +use bincode::{Decode, Encode}; +use dpp::dashcore::QuorumHash; +use std::collections::{BTreeMap, VecDeque}; + +pub use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; + +/// Quorum key per hash +pub type QuorumKeysByQuorumHash = BTreeMap; + +/// Previously obtained quorums and heights. Required for signature verification +#[derive(Debug, Clone, Encode, Decode, Default)] +pub struct PreviousPastQuorums { + /// The quorum keys by quorum hash + #[bincode(with_serde)] + quorums: QuorumKeysByQuorumHash, + + /// The core height at which these quorums were last active + active_core_height: u32, + + /// The core height when the quorums were changed + updated_at_core_height: u32, + + /// The core height the previous chain lock validating quorums became active + previous_change_height: Option, +} + +/// Quorums with keys for signature verification +#[derive(Debug, Clone, Encode, Decode, Default)] +pub struct SignatureVerificationQuorumsV0 { + /// Current quorums + #[bincode(with_serde)] + current_quorums: QuorumKeysByQuorumHash, + + /// The slightly old quorums used for validating chain locks (or instant locks), it's important to keep + /// these because validation of signatures happens for the quorums that are 8 blocks before the + /// height written in the chain lock. The same for instant locks + previous: Option, +} + +/// The trait defines methods for the signature verification quorums structure v0 +pub trait SignatureVerificationQuorumsV0Methods { + /// Set last quorum keys + fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash); + + /// Current quorum keys by quorum hash + fn current_quorums(&self) -> &QuorumKeysByQuorumHash; + + /// The current quorums keys mutable + fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash; + + /// Previous quorums + fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums>; + + /// Set last quorums keys and update previous quorums + fn rotate_quorums( + &mut self, + quorums: QuorumKeysByQuorumHash, + last_active_core_height: u32, + updated_at_core_height: u32, + ); + + /// Set previous quorums + fn set_previous_past_quorums( + &mut self, + previous_quorums: QuorumKeysByQuorumHash, + last_active_core_height: u32, + updated_at_core_height: u32, + ); + + /// Select quorum sets for signature verification + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedVerificationQuorumSets; +} + +pub struct SelectedVerificationQuorumSets<'q> { + pub quorum_sets: VecDeque<&'q QuorumKeysByQuorumHash>, + pub should_be_verifiable: bool, +} + +impl<'q> Iterator for SelectedVerificationQuorumSets<'q> { + type Item = &'q QuorumKeysByQuorumHash; + + fn next(&mut self) -> Option { + self.quorum_sets.pop_front() + } +} + +impl SignatureVerificationQuorumsV0Methods for SignatureVerificationQuorumsV0 { + fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash) { + self.current_quorums = quorums; + } + + fn current_quorums(&self) -> &QuorumKeysByQuorumHash { + &self.current_quorums + } + + fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash { + &mut self.current_quorums + } + + fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums> { + self.previous.as_ref() + } + + fn rotate_quorums( + &mut self, + quorums: QuorumKeysByQuorumHash, + last_active_height: u32, + updated_at_core_height: u32, + ) { + let previous_quorums = std::mem::replace(&mut self.current_quorums, quorums); + + self.set_previous_past_quorums( + previous_quorums, + last_active_height, + updated_at_core_height, + ); + } + + fn set_previous_past_quorums( + &mut self, + previous_quorums: QuorumKeysByQuorumHash, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + self.previous = Some(PreviousPastQuorums { + quorums: previous_quorums, + active_core_height: last_active_core_height, + updated_at_core_height, + previous_change_height: self + .previous + .as_ref() + .map(|previous| previous.updated_at_core_height), + }); + } + + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedVerificationQuorumSets { + let mut quorums = VecDeque::new(); + let mut should_be_verifiable = false; + + if let Some(previous) = &self.previous { + let previous_quorum_height = previous.active_core_height; + let change_quorum_height = previous.updated_at_core_height; + let previous_quorums_change_height = previous.previous_change_height; + + if signing_height > 8 && verification_height >= change_quorum_height { + // in this case we are sure that we should be targeting the current quorum + // We updated core chain lock height from 100 to 105, new chain lock comes in for block 114 + // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 106 (new chain lock verification height 114 - 8) + // We are sure that we should use current quorums + // If we have + // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 105 (new chain lock verification height 113 - 8) + // We should also use current quorums, this is because at 105 we are sure new chain lock validating quorums are active + quorums.push_back(&self.current_quorums); + should_be_verifiable = true; + } else if signing_height > 8 && verification_height <= previous_quorum_height { + should_be_verifiable = previous_quorums_change_height + .map(|previous_quorums_change_height| { + verification_height > previous_quorums_change_height + }) + .unwrap_or(false); + // In this case the quorums were changed recently meaning that we should use the previous quorums to verify the chain lock + // We updated core chain lock height from 100 to 105, new chain lock comes in for block 106 + // -------- 98 (new chain lock verification height 106 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) + // We are sure that we should use previous quorums + // If we have + // -------- 100 (new chain lock verification height 108 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) + // We should also use previous quorums, this is because at 100 we are sure the old quorum set was active + quorums.push_back(&previous.quorums); + } else { + should_be_verifiable = previous_quorums_change_height + .map(|previous_quorums_change_height| { + verification_height > previous_quorums_change_height + }) + .unwrap_or(false); + // we are in between, so we don't actually know if it was the old one or the new one to be used. + // ------- 100 (previous_quorum_height) ------ 104 (new chain lock verification height 112 - 8) -------105 (change_quorum_height) + // we should just try both, starting with the current quorums + quorums.push_back(&self.current_quorums); + quorums.push_back(&previous.quorums); + } + } else { + quorums.push_back(&self.current_quorums); + } + + SelectedVerificationQuorumSets { + quorum_sets: quorums, + should_be_verifiable, + } + } +}