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

feat(drive-abci)!: rotate quorums when all quorums members have had a chance to propose a block #1942

Merged
merged 2 commits into from
Jul 11, 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
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
Loading