Skip to content

Commit

Permalink
feat(drive-abci)!: rotate quorums when all quorums members have had a…
Browse files Browse the repository at this point in the history
… chance to propose a block (#1942)
  • Loading branch information
QuantumExplorer authored Jul 11, 2024
1 parent 729d555 commit 85920d7
Show file tree
Hide file tree
Showing 22 changed files with 341 additions and 216 deletions.
7 changes: 7 additions & 0 deletions packages/rs-dpp/src/block/extended_block_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ impl ExtendedBlockInfoV0Getters for ExtendedBlockInfo {
}
}

fn proposer_pro_tx_hash(&self) -> &[u8; 32] {
match self {
ExtendedBlockInfo::V0(v0) => &v0.proposer_pro_tx_hash,
}
}

fn block_id_hash(&self) -> &[u8; 32] {
match self {
ExtendedBlockInfo::V0(v0) => &v0.block_id_hash,
Expand Down Expand Up @@ -146,6 +152,7 @@ mod tests {
app_hash: [1; 32],
quorum_hash: [2; 32],
block_id_hash: [3; 32],
proposer_pro_tx_hash: [4; 32],
signature: [3; 96],
round: 1,
}
Expand Down
9 changes: 9 additions & 0 deletions packages/rs-dpp/src/block/extended_block_info/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ pub struct ExtendedBlockInfoV0 {
pub quorum_hash: [u8; 32],
/// The block id hash
pub block_id_hash: [u8; 32],
/// The proposer pro_tx_hash
pub proposer_pro_tx_hash: [u8; 32],
/// Signature
#[serde(with = "signature_serializer")]
pub signature: [u8; 96],
Expand All @@ -37,6 +39,9 @@ pub trait ExtendedBlockInfoV0Getters {

/// Returns the quorum hash.
fn quorum_hash(&self) -> &[u8; 32];
/// Proposer pro tx hash.
fn proposer_pro_tx_hash(&self) -> &[u8; 32];
/// The block id hash
fn block_id_hash(&self) -> &[u8; 32];

/// Returns the signature.
Expand Down Expand Up @@ -85,6 +90,10 @@ impl ExtendedBlockInfoV0Getters for ExtendedBlockInfoV0 {
&self.quorum_hash
}

fn proposer_pro_tx_hash(&self) -> &[u8; 32] {
&self.proposer_pro_tx_hash
}

fn block_id_hash(&self) -> &[u8; 32] {
&self.block_id_hash
}
Expand Down
22 changes: 6 additions & 16 deletions packages/rs-drive-abci/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,6 @@ pub struct ExecutionConfig {
#[serde(default = "ExecutionConfig::default_verify_sum_trees")]
pub verify_sum_trees: bool,

// TODO: Move to ValidatorSetConfig
/// How often should quorums change?
#[serde(
default = "ExecutionConfig::default_validator_set_rotation_block_count",
deserialize_with = "from_str_or_number"
)]
pub validator_set_rotation_block_count: u32,

/// How long in seconds should an epoch last
/// It might last a lot longer if the chain is halted
#[serde(
Expand Down Expand Up @@ -567,10 +559,6 @@ impl ExecutionConfig {
true
}

fn default_validator_set_rotation_block_count() -> u32 {
15
}

fn default_epoch_time_length_s() -> u64 {
788400
}
Expand Down Expand Up @@ -618,8 +606,6 @@ impl Default for ExecutionConfig {
Self {
use_document_triggers: ExecutionConfig::default_use_document_triggers(),
verify_sum_trees: ExecutionConfig::default_verify_sum_trees(),
validator_set_rotation_block_count:
ExecutionConfig::default_validator_set_rotation_block_count(),
epoch_time_length_s: ExecutionConfig::default_epoch_time_length_s(),
}
}
Expand Down Expand Up @@ -763,6 +749,8 @@ impl PlatformConfig {
pub struct PlatformTestConfig {
/// Block signing
pub block_signing: bool,
/// Storing of platform state
pub store_platform_state: bool,
/// Block signature verification
pub block_commit_signature_verification: bool,
/// Disable instant lock signature verification
Expand All @@ -772,11 +760,12 @@ pub struct PlatformTestConfig {
#[cfg(feature = "testing-config")]
impl PlatformTestConfig {
/// Much faster config for tests
pub fn default_with_no_block_signing() -> Self {
pub fn default_minimal_verifications() -> Self {
Self {
block_signing: false,
store_platform_state: false,
block_commit_signature_verification: false,
disable_instant_lock_signature_verification: false,
disable_instant_lock_signature_verification: true,
}
}
}
Expand All @@ -786,6 +775,7 @@ impl Default for PlatformTestConfig {
fn default() -> Self {
Self {
block_signing: true,
store_platform_state: true,
block_commit_signature_verification: true,
disable_instant_lock_signature_verification: false,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ where
app_hash: block_header.app_hash,
quorum_hash: current_quorum_hash,
block_id_hash,
proposer_pro_tx_hash: block_header.proposer_pro_tx_hash,
signature: commit_info.block_signature,
round,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ where
.set_app_hash(Some(root_hash));

let validator_set_update = self.validator_set_update(
block_proposal.proposer_pro_tx_hash,
last_committed_platform_state,
&mut block_execution_context,
platform_version,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ where
///
pub fn validator_set_update(
&self,
proposer_pro_tx_hash: [u8; 32],
platform_state: &PlatformState,
block_execution_context: &mut BlockExecutionContext,
platform_version: &PlatformVersion,
Expand All @@ -46,7 +47,11 @@ where
.block_end
.validator_set_update
{
0 => self.validator_set_update_v0(platform_state, block_execution_context),
0 => self.validator_set_update_v0(
proposer_pro_tx_hash,
platform_state,
block_execution_context,
),
version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch {
method: "validator_set_update".to_string(),
known_versions: vec![0],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ use crate::execution::types::block_execution_context::v0::{
BlockExecutionContextV0Getters, BlockExecutionContextV0MutableGetters,
};
use crate::execution::types::block_execution_context::BlockExecutionContext;
use crate::execution::types::block_state_info::v0::BlockStateInfoV0Getters;
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::validator_set::v0::ValidatorSetV0Getters;
use crate::rpc::core::CoreRPCLike;
use itertools::Itertools;

use dpp::dashcore::hashes::Hash;
use tenderdash_abci::proto::abci::ValidatorSetUpdate;

impl<C> Platform<C>
Expand All @@ -23,28 +23,73 @@ where
#[inline(always)]
pub(super) fn validator_set_update_v0(
&self,
proposer_pro_tx_hash: [u8; 32],
platform_state: &PlatformState,
block_execution_context: &mut BlockExecutionContext,
) -> Result<Option<ValidatorSetUpdate>, Error> {
let mut perform_rotation = false;

if block_execution_context.block_state_info().height()
% self.config.execution.validator_set_rotation_block_count as u64
== 0
{
tracing::debug!(
method = "validator_set_update_v0",
"rotation: previous quorum finished members. quorum rotation expected"
);
perform_rotation = true;
}
// we also need to perform a rotation if the validator set is being removed
if block_execution_context
if let Some(validator_set) = block_execution_context
.block_platform_state()
.validator_sets()
.get(&platform_state.current_validator_set_quorum_hash())
.is_none()
{
if let Some((last_member_pro_tx_hash, _)) = validator_set.members().last_key_value() {
// we should also perform a rotation if the validator set went through all quorum members
// this means we are at the last member of the quorum
if last_member_pro_tx_hash.as_byte_array() == &proposer_pro_tx_hash {
tracing::debug!(
method = "validator_set_update_v0",
"rotation: quorum finished as we hit last member {} of quorum {}. All known quorums are: [{}]. quorum rotation expected",
hex::encode(proposer_pro_tx_hash),
hex::encode(platform_state.current_validator_set_quorum_hash().as_byte_array()),
block_execution_context
.block_platform_state()
.validator_sets()
.keys()
.map(hex::encode).collect::<Vec<_>>().join(" | "),
);
perform_rotation = true;
}
} else {
// the validator set has no members, very weird, but let's just perform a rotation
tracing::debug!(
method = "validator_set_update_v0",
"rotation: validator set has no members",
);
perform_rotation = true;
}

// We should also perform a rotation if there are more than one quorum in the system
// and that the new proposer is on the same quorum and the last proposer but is before
// them in the list of proposers.
// This only works if Tenderdash goes through proposers properly
if &platform_state.last_committed_quorum_hash()
== platform_state
.current_validator_set_quorum_hash()
.as_byte_array()
&& platform_state.last_committed_block_proposer_pro_tx_hash() > proposer_pro_tx_hash
&& platform_state.validator_sets().len() > 1
{
// 1 - We haven't changed quorums
// 2 - The new proposer is before the old proposer
// 3 - There are more than one quorum in the system
tracing::debug!(
method = "validator_set_update_v0",
"rotation: quorum finished as we hit last an earlier member {} than last block proposer {} for quorum {}. All known quorums are: [{}]. quorum rotation expected",
hex::encode(proposer_pro_tx_hash),
hex::encode(block_execution_context.block_platform_state().last_committed_block_proposer_pro_tx_hash()),
hex::encode(platform_state.current_validator_set_quorum_hash().as_byte_array()),
block_execution_context
.block_platform_state()
.validator_sets()
.keys()
.map(hex::encode).collect::<Vec<_>>().join(" | "),
);
perform_rotation = true;
}
} else {
// we also need to perform a rotation if the validator set is being removed
tracing::debug!(
method = "validator_set_update_v0",
"rotation: new quorums not containing current quorum current {:?}, {}. quorum rotation expected˚",
Expand All @@ -58,7 +103,7 @@ where
perform_rotation = true;
}

//todo: perform a rotation if quorum health is low
//todo: (maybe) perform a rotation if quorum health is low

if perform_rotation {
// get the index of the previous quorum
Expand All @@ -76,7 +121,7 @@ where
0 => Err(Error::Execution(ExecutionError::CorruptedCachedState(
"no current quorums".to_string(),
))),
1 => Ok(None),
1 => Ok(None), // no rotation as we are the only quorum
count => {
let start_index = index;
index = (index + 1) % count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ impl<C> Platform<C> {
transaction: TransactionArg,
platform_version: &PlatformVersion,
) -> Result<(), Error> {
#[cfg(feature = "testing-config")]
{
if self.config.testing_configs.store_platform_state {
self.drive
.store_platform_state_bytes(
&state.serialize_to_bytes()?,
transaction,
platform_version,
)
.map_err(Error::Drive)?;
}
}
#[cfg(not(feature = "testing-config"))]
self.drive
.store_platform_state_bytes(&state.serialize_to_bytes()?, transaction, platform_version)
.map_err(Error::Drive)?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ mod tests {
},
execution: ExecutionConfig {
verify_sum_trees: true,
validator_set_rotation_block_count: 25,

..Default::default()
},
block_spacing_ms: 300,
testing_configs: PlatformTestConfig::default_with_no_block_signing(),
testing_configs: PlatformTestConfig::default_minimal_verifications(),
..Default::default()
};
let platform = TestPlatformBuilder::new()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ mod test {
app_hash: platform.drive.grove.root_hash(None).unwrap().unwrap(),
quorum_hash: [0u8; 32],
block_id_hash: [0u8; 32],
proposer_pro_tx_hash: [0u8; 32],
signature: [0u8; 96],
round: 0,
}
Expand Down Expand Up @@ -345,6 +346,7 @@ mod test {
app_hash: platform.drive.grove.root_hash(None).unwrap().unwrap(),
quorum_hash: [0u8; 32],
block_id_hash: [0u8; 32],
proposer_pro_tx_hash: [0u8; 32],
signature: [0u8; 96],
round: 0,
}
Expand Down
Loading

0 comments on commit 85920d7

Please sign in to comment.