Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(drive): encapsulate chain lock validation quorum logic #1868

Merged
merged 3 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading