Skip to content

Commit

Permalink
refactor(drive): encapsulate chain lock validation quorum logic (#1868)
Browse files Browse the repository at this point in the history
Co-authored-by: QuantumExplorer <[email protected]>
  • Loading branch information
shumkov and QuantumExplorer authored Jun 14, 2024
1 parent 2c9368a commit 75398b7
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 315 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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::<QuorumHash>(quorum_hash);
if !retain {
Expand All @@ -237,6 +242,7 @@ where
.filter(|(key, _)| {
!block_platform_state
.chain_lock_validating_quorums()
.current_quorums()
.contains_key::<QuorumHash>(key)
})
.map(|(key, _)| {
Expand Down Expand Up @@ -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,
);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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.
Expand All @@ -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::<C>::choose_quorum(
self.config.chain_lock_quorum_type(),
Expand Down Expand Up @@ -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::<C>::choose_quorum(
self.config.chain_lock_quorum_type(),
second_to_check_quorums,
Expand Down Expand Up @@ -215,15 +176,16 @@ 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.
tracing::debug!(
"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",
);
Expand Down
7 changes: 4 additions & 3 deletions packages/rs-drive-abci/src/platform_types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
65 changes: 4 additions & 61 deletions packages/rs-drive-abci/src/platform_types/platform_state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -316,7 +316,7 @@ impl PlatformStateV0Methods for PlatformState {
}
}

fn chain_lock_validating_quorums(&self) -> &BTreeMap<QuorumHash, ThresholdBlsPublicKey> {
fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums {
match self {
PlatformState::V0(v0) => &v0.chain_lock_validating_quorums,
}
Expand Down Expand Up @@ -382,41 +382,12 @@ impl PlatformStateV0Methods for PlatformState {
}
}

fn set_chain_lock_validating_quorums(
&mut self,
quorums: BTreeMap<QuorumHash, ThresholdBlsPublicKey>,
) {
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<QuorumHash, ThresholdBlsPublicKey>,
) -> BTreeMap<QuorumHash, ThresholdBlsPublicKey> {
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<u32>,
quorums: BTreeMap<QuorumHash, ThresholdBlsPublicKey>,
) {
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<ProTxHash, MasternodeListItem>) {
match self {
PlatformState::V0(v0) => v0.set_full_masternode_list(list),
Expand Down Expand Up @@ -471,40 +442,12 @@ impl PlatformStateV0Methods for PlatformState {
}
}

fn chain_lock_validating_quorums_mut(
&mut self,
) -> &mut BTreeMap<QuorumHash, ThresholdBlsPublicKey> {
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<u32>,
BTreeMap<QuorumHash, ThresholdBlsPublicKey>,
)> {
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<u32>,
BTreeMap<QuorumHash, ThresholdBlsPublicKey>,
)> {
match self {
PlatformState::V0(v0) => v0.previous_height_chain_lock_validating_quorums_mut(),
}
}

fn full_masternode_list_mut(&mut self) -> &mut BTreeMap<ProTxHash, MasternodeListItem> {
match self {
PlatformState::V0(v0) => v0.full_masternode_list_mut(),
Expand Down
Loading

0 comments on commit 75398b7

Please sign in to comment.