diff --git a/consensus/config/src/committee.rs b/consensus/config/src/committee.rs index 0d941a3aa39fd..3eda129f2aaab 100644 --- a/consensus/config/src/committee.rs +++ b/consensus/config/src/committee.rs @@ -68,6 +68,10 @@ impl Committee { self.total_stake } + pub fn n_percent_stake_threshold(&self, n: u64) -> Stake { + self.total_stake * n / 100 + } + pub fn quorum_threshold(&self) -> Stake { self.quorum_threshold } diff --git a/consensus/core/src/ancestor.rs b/consensus/core/src/ancestor.rs new file mode 100644 index 0000000000000..0ef06c639a7bb --- /dev/null +++ b/consensus/core/src/ancestor.rs @@ -0,0 +1,381 @@ +// Copyright (c) Mysten Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +use std::sync::Arc; + +use consensus_config::AuthorityIndex; +use tracing::info; + +use crate::{context::Context, leader_scoring::ReputationScores, round_prober::QuorumRound}; + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub(crate) enum AncestorState { + Include, + Exclude(u64), +} + +#[derive(Clone)] +struct AncestorInfo { + state: AncestorState, + // This will be set to the count of either the quorum round update count or + // the score update count for which the EXCLUDE or INCLUDE state are locked + // in respectively. + lock_expiry_count: u32, +} + +impl AncestorInfo { + fn new() -> Self { + Self { + state: AncestorState::Include, + lock_expiry_count: 0, + } + } + + fn is_locked( + &self, + propagation_score_update_count: u32, + quorum_round_update_count: u32, + ) -> bool { + match self.state { + AncestorState::Include => self.lock_expiry_count > propagation_score_update_count, + AncestorState::Exclude(_) => self.lock_expiry_count > quorum_round_update_count, + } + } + + fn set_lock(&mut self, future_count: u32) { + self.lock_expiry_count = future_count; + } +} + +pub(crate) struct AncestorStateManager { + context: Arc, + state_map: Vec, + propagation_score_update_count: u32, + quorum_round_update_count: u32, + pub(crate) quorum_round_per_authority: Vec, + pub(crate) propagation_scores: ReputationScores, +} + +impl AncestorStateManager { + // Number of quorum round updates for which an ancestor is locked in the EXCLUDE state + // Chose 10 updates as that should be ~50 seconds of waiting with the current round prober + // interval of 5s + #[cfg(not(test))] + const STATE_LOCK_QUORUM_ROUND_UPDATES: u32 = 10; + #[cfg(test)] + const STATE_LOCK_QUORUM_ROUND_UPDATES: u32 = 1; + + // Number of propagation score updates for which an ancestor is locked in the INCLUDE state + // Chose 2 leader schedule updates (~300 commits per schedule) which should be ~30-90 seconds + // depending on the round rate for the authority to improve scores. + #[cfg(not(test))] + const STATE_LOCK_SCORE_UPDATES: u32 = 2; + #[cfg(test)] + const STATE_LOCK_SCORE_UPDATES: u32 = 1; + + // Exclusion threshold is based on reputation scores + const EXCLUSION_THRESHOLD_PERCENTAGE: u64 = 10; + + // Inclusion threshold is based on network quorum round + const INCLUSION_THRESHOLD_PERCENTAGE: u64 = 90; + + pub(crate) fn new(context: Arc, propagation_scores: ReputationScores) -> Self { + let state_map = vec![AncestorInfo::new(); context.committee.size()]; + + let quorum_round_per_authority = vec![(0, 0); context.committee.size()]; + Self { + context, + state_map, + propagation_score_update_count: 0, + quorum_round_update_count: 0, + propagation_scores, + quorum_round_per_authority, + } + } + + pub(crate) fn set_quorum_round_per_authority(&mut self, quorum_rounds: Vec) { + self.quorum_round_per_authority = quorum_rounds; + self.quorum_round_update_count += 1; + } + + pub(crate) fn set_propagation_scores(&mut self, scores: ReputationScores) { + self.propagation_scores = scores; + self.propagation_score_update_count += 1; + } + + pub(crate) fn get_ancestor_states(&self) -> Vec { + self.state_map.iter().map(|info| info.state).collect() + } + + pub(crate) fn get_inclusion_stake_threshold(&self) -> u64 { + self.context + .committee + .n_percent_stake_threshold(Self::INCLUSION_THRESHOLD_PERCENTAGE) + } + + /// Updates the state of all ancestors based on the latest scores and quorum rounds + pub(crate) fn update_all_ancestors_state(&mut self) { + let propagation_scores_by_authority = self + .propagation_scores + .scores_per_authority + .clone() + .into_iter() + .enumerate() + .map(|(idx, score)| { + ( + self.context + .committee + .to_authority_index(idx) + .expect("Index should be valid"), + score, + ) + }) + .collect::>(); + + // If round prober has not run yet and we don't have network quorum round, + // it is okay because network_low_quorum_round will be zero and we will + // include all ancestors until we get more information. + let network_low_quorum_round = self.calculate_network_low_quorum_round(); + + // If propagation scores are not ready because the first 300 commits have not + // happened, this is okay as we will only start excluding ancestors after that + // point in time. + for (authority_id, score) in propagation_scores_by_authority { + let (authority_low_quorum_round, _high) = self.quorum_round_per_authority[authority_id]; + + self.update_state( + authority_id, + score, + authority_low_quorum_round, + network_low_quorum_round, + ); + } + } + + /// Updates the state of the given authority based on current scores and quorum rounds. + fn update_state( + &mut self, + authority_id: AuthorityIndex, + propagation_score: u64, + authority_low_quorum_round: u32, + network_low_quorum_round: u32, + ) { + let block_hostname = &self.context.committee.authority(authority_id).hostname; + let mut ancestor_info = self.state_map[authority_id].clone(); + + if ancestor_info.is_locked( + self.propagation_score_update_count, + self.quorum_round_update_count, + ) { + // If still locked, we won't make any state changes. + return; + } + + let low_score_threshold = + (self.propagation_scores.highest_score() * Self::EXCLUSION_THRESHOLD_PERCENTAGE) / 100; + + match ancestor_info.state { + // Check conditions to switch to EXCLUDE state + AncestorState::Include => { + if propagation_score <= low_score_threshold { + ancestor_info.state = AncestorState::Exclude(propagation_score); + ancestor_info.set_lock( + self.quorum_round_update_count + Self::STATE_LOCK_QUORUM_ROUND_UPDATES, + ); + info!( + "Authority {authority_id} moved to EXCLUDE state with score {propagation_score} <= threshold of {low_score_threshold} and locked for {:?} quorum round updates", + Self::STATE_LOCK_QUORUM_ROUND_UPDATES + ); + self.context + .metrics + .node_metrics + .ancestor_state_change_by_authority + .with_label_values(&[block_hostname, "exclude"]) + .inc(); + } + } + // Check conditions to switch back to INCLUDE state + AncestorState::Exclude(_) => { + // It should not be possible for the scores to get over the threshold + // until the node is back in the INCLUDE state, but adding just in case. + if propagation_score > low_score_threshold + || authority_low_quorum_round >= (network_low_quorum_round) + { + ancestor_info.state = AncestorState::Include; + ancestor_info.set_lock( + self.propagation_score_update_count + Self::STATE_LOCK_SCORE_UPDATES, + ); + info!( + "Authority {authority_id} moved to INCLUDE state with {propagation_score} > threshold of {low_score_threshold} or {authority_low_quorum_round} >= {network_low_quorum_round} and locked for {:?} score updates.", + Self::STATE_LOCK_SCORE_UPDATES + ); + self.context + .metrics + .node_metrics + .ancestor_state_change_by_authority + .with_label_values(&[block_hostname, "include"]) + .inc(); + } + } + } + + // If any updates were made to state ensure they are persisted. + self.state_map[authority_id] = ancestor_info; + } + + /// Calculate the network's quorum round from authorities by inclusion stake + /// threshold, where quorum round is the highest round a block has been seen + /// by a percentage (inclusion threshold) of authorities. + fn calculate_network_low_quorum_round(&self) -> u32 { + let committee = &self.context.committee; + let inclusion_stake_threshold = self.get_inclusion_stake_threshold(); + let mut low_quorum_rounds_with_stake = self + .quorum_round_per_authority + .iter() + .zip(committee.authorities()) + .map(|((low, _high), (_, authority))| (*low, authority.stake)) + .collect::>(); + low_quorum_rounds_with_stake.sort(); + + let mut total_stake = 0; + let mut network_low_quorum_round = 0; + + for (round, stake) in low_quorum_rounds_with_stake.iter().rev() { + let reached_quorum_before = total_stake >= inclusion_stake_threshold; + total_stake += stake; + if !reached_quorum_before && total_stake >= inclusion_stake_threshold { + network_low_quorum_round = *round; + break; + } + } + + network_low_quorum_round + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::leader_scoring::ReputationScores; + + #[tokio::test] + async fn test_calculate_network_low_quorum_round() { + telemetry_subscribers::init_for_testing(); + let context = Arc::new(Context::new_for_test(4).0); + + let scores = ReputationScores::new((1..=300).into(), vec![1, 2, 4, 3]); + let mut ancestor_state_manager = AncestorStateManager::new(context, scores); + + // Quorum rounds are not set yet, so we should calculate a network quorum + // round of 0 to start. + let network_low_quorum_round = ancestor_state_manager.calculate_network_low_quorum_round(); + assert_eq!(network_low_quorum_round, 0); + + let quorum_rounds = vec![(225, 229), (225, 300), (229, 300), (229, 300)]; + ancestor_state_manager.set_quorum_round_per_authority(quorum_rounds); + + let network_low_quorum_round = ancestor_state_manager.calculate_network_low_quorum_round(); + assert_eq!(network_low_quorum_round, 225); + } + + // Test all state transitions + // Default all INCLUDE -> EXCLUDE + // EXCLUDE -> INCLUDE (Blocked due to lock) + // EXCLUDE -> INCLUDE (Pass due to lock expired) + // INCLUDE -> EXCLUDE (Blocked due to lock) + // INCLUDE -> EXCLUDE (Pass due to lock expired) + #[tokio::test] + async fn test_update_all_ancestor_state() { + telemetry_subscribers::init_for_testing(); + let context = Arc::new(Context::new_for_test(4).0); + + let scores = ReputationScores::new((1..=300).into(), vec![1, 2, 4, 3]); + let mut ancestor_state_manager = AncestorStateManager::new(context, scores); + + let quorum_rounds = vec![(225, 229), (225, 300), (229, 300), (229, 300)]; + ancestor_state_manager.set_quorum_round_per_authority(quorum_rounds); + ancestor_state_manager.update_all_ancestors_state(); + + // Score threshold for exclude is (4 * 10) / 100 = 0 + // No ancestors should be excluded in with this threshold + let state_map = ancestor_state_manager.get_ancestor_states(); + for state in state_map.iter() { + assert_eq!(*state, AncestorState::Include); + } + + let scores = ReputationScores::new((1..=300).into(), vec![10, 10, 100, 100]); + ancestor_state_manager.set_propagation_scores(scores); + ancestor_state_manager.update_all_ancestors_state(); + + // Score threshold for exclude is (100 * 10) / 100 = 10 + // 2 authorities should be excluded in with this threshold + let state_map = ancestor_state_manager.get_ancestor_states(); + for (authority, state) in state_map.iter().enumerate() { + if (0..=1).contains(&authority) { + assert_eq!(*state, AncestorState::Exclude(10)); + } else { + assert_eq!(*state, AncestorState::Include); + } + } + + ancestor_state_manager.update_all_ancestors_state(); + + // 2 authorities should still be excluded with these scores and no new + // quorum round updates have been set to expire the locks. + let state_map = ancestor_state_manager.get_ancestor_states(); + for (authority, state) in state_map.iter().enumerate() { + if (0..=1).contains(&authority) { + assert_eq!(*state, AncestorState::Exclude(10)); + } else { + assert_eq!(*state, AncestorState::Include); + } + } + + // Updating the quorum rounds will expire the lock as we only need 1 + // quorum round update for tests. + let quorum_rounds = vec![(229, 300), (225, 300), (229, 300), (229, 300)]; + ancestor_state_manager.set_quorum_round_per_authority(quorum_rounds); + ancestor_state_manager.update_all_ancestors_state(); + + // Authority 0 should now be included again because low quorum round is + // at the network low quorum round of 229. Authority 1's quorum round is + // too low and will remain excluded. + let state_map = ancestor_state_manager.get_ancestor_states(); + for (authority, state) in state_map.iter().enumerate() { + if authority == 1 { + assert_eq!(*state, AncestorState::Exclude(10)); + } else { + assert_eq!(*state, AncestorState::Include); + } + } + + let quorum_rounds = vec![(229, 300), (229, 300), (229, 300), (229, 300)]; + ancestor_state_manager.set_quorum_round_per_authority(quorum_rounds); + ancestor_state_manager.update_all_ancestors_state(); + + // Ancestor 1 can transtion to the INCLUDE state. Ancestor 0 is still locked + // in the INCLUDE state until a score update is performed which is why + // even though the scores are still low it has not moved to the EXCLUDE + // state. + let state_map = ancestor_state_manager.get_ancestor_states(); + for state in state_map.iter() { + assert_eq!(*state, AncestorState::Include); + } + + // Updating the scores will expire the lock as we only need 1 update for tests. + let scores = ReputationScores::new((1..=300).into(), vec![100, 10, 100, 100]); + ancestor_state_manager.set_propagation_scores(scores); + ancestor_state_manager.update_all_ancestors_state(); + + // Ancestor 1 can transition to EXCLUDE state now that the lock expired + // and its scores are below the threshold. + let state_map = ancestor_state_manager.get_ancestor_states(); + for (authority, state) in state_map.iter().enumerate() { + if authority == 1 { + assert_eq!(*state, AncestorState::Exclude(10)); + } else { + assert_eq!(*state, AncestorState::Include); + } + } + } +} diff --git a/consensus/core/src/core.rs b/consensus/core/src/core.rs index a1ff274e6722c..e1f45dc8ed247 100644 --- a/consensus/core/src/core.rs +++ b/consensus/core/src/core.rs @@ -16,9 +16,10 @@ use tokio::{ sync::{broadcast, watch}, time::Instant, }; -use tracing::{debug, info, warn}; +use tracing::{debug, info, trace, warn}; use crate::{ + ancestor::{AncestorState, AncestorStateManager}, block::{ Block, BlockAPI, BlockRef, BlockTimestampMs, BlockV1, Round, SignedBlock, Slot, VerifiedBlock, GENESIS_ROUND, @@ -98,6 +99,11 @@ pub(crate) struct Core { /// This is currently being used to avoid equivocations during a node recovering from amnesia. When value is None it means that /// the last block sync mechanism is enabled, but it hasn't been initialised yet. last_known_proposed_round: Option, + // The ancestor state manager will keep track of the quality of the authorities + // based on the distribution of their blocks to the network. It will use this + // information to decide whether to include that authority block in the next + // proposal or not. + ancestor_state_manager: AncestorStateManager, } impl Core { @@ -152,6 +158,13 @@ impl Core { Some(0) }; + let propagation_scores = leader_schedule + .leader_swap_table + .read() + .reputation_scores + .clone(); + let ancestor_state_manager = AncestorStateManager::new(context.clone(), propagation_scores); + Self { context: context.clone(), threshold_clock: ThresholdClock::new(0, context.clone()), @@ -169,6 +182,7 @@ impl Core { block_signer, dag_state, last_known_proposed_round: min_propose_round, + ancestor_state_manager, } .recover() } @@ -370,6 +384,43 @@ impl Core { } } + // TODO: produce the block for the clock_round. As the threshold clock can advance many rounds at once (ex + // because we synchronized a bulk of blocks) we can decide here whether we want to produce blocks per round + // or just the latest one. From earlier experiments I saw only benefit on proposing for the penultimate round + // only when the validator was supposed to be the leader of the round - so we bring down the missed leaders. + // Probably proposing for all the intermediate rounds might not make much sense. + + // Determine the ancestors to be included in proposal. + // Smart ancestor selection requires distributed scoring to be enabled. + let ancestors = if self + .context + .protocol_config + .consensus_distributed_vote_scoring_strategy() + && self + .context + .protocol_config + .consensus_smart_ancestor_selection() + { + let ancestors = self.smart_ancestors_to_propose(clock_round, !force); + + // If we did not find enough good ancestors to propose, continue to wait before proposing. + if ancestors.is_empty() { + assert!( + !force, + "Ancestors should have been returned if force is true!" + ); + return None; + } + ancestors + } else { + self.ancestors_to_propose(clock_round) + }; + + // Update the last included ancestor block refs + for ancestor in &ancestors { + self.last_included_ancestors[ancestor.author()] = Some(ancestor.reference()); + } + let leader_authority = &self .context .committee @@ -392,14 +443,6 @@ impl Core { .with_label_values(&[leader_authority]) .inc(); - // TODO: produce the block for the clock_round. As the threshold clock can advance many rounds at once (ex - // because we synchronized a bulk of blocks) we can decide here whether we want to produce blocks per round - // or just the latest one. From earlier experiments I saw only benefit on proposing for the penultimate round - // only when the validator was supposed to be the leader of the round - so we bring down the missed leaders. - // Probably proposing for all the intermediate rounds might not make much sense. - - // Determine the ancestors to be included in proposal - let ancestors = self.ancestors_to_propose(clock_round); self.context .metrics .node_metrics @@ -496,7 +539,7 @@ impl Core { // Now acknowledge the transactions for their inclusion to block ack_transactions(verified_block.reference()); - info!("Created block {:?}", verified_block); + info!("Created block {verified_block:?} for round {clock_round}"); self.context .metrics @@ -540,6 +583,15 @@ impl Core { { self.leader_schedule .update_leader_schedule_v2(&self.dag_state); + + let propagation_scores = self + .leader_schedule + .leader_swap_table + .read() + .reputation_scores + .clone(); + self.ancestor_state_manager + .set_propagation_scores(propagation_scores); } else { self.leader_schedule .update_leader_schedule_v1(&self.dag_state); @@ -631,13 +683,16 @@ impl Core { self.subscriber_exists = exists; } - /// Sets the delay by round for propagating blocks to a quorum. - // TODO: Will set the quorum round per authority in ancestor state manager. + /// Sets the delay by round for propagating blocks to a quorum and the + /// quorum round per authority for ancestor state manager. pub(crate) fn set_propagation_delay_and_quorum_rounds( &mut self, delay: Round, - _quorum_rounds: Vec, + quorum_rounds: Vec, ) { + info!("Quorum round per authority in ancestor state manager set to: {quorum_rounds:?}"); + self.ancestor_state_manager + .set_quorum_round_per_authority(quorum_rounds); info!("Propagation round delay set to: {delay}"); self.propagation_delay = delay; } @@ -743,11 +798,6 @@ impl Core { ) .collect::>(); - // Update the last included ancestor block refs - for ancestor in &ancestors { - self.last_included_ancestors[ancestor.author()] = Some(ancestor.reference()); - } - // TODO: this is for temporary sanity check - we might want to remove later on let mut quorum = StakeAggregator::::new(); for ancestor in ancestors @@ -761,6 +811,142 @@ impl Core { ancestors } + /// Retrieves the next ancestors to propose to form a block at `clock_round` round. + /// If smart selection is enabled then this will try to select the best ancestors + /// based on the propagation scores of the authorities. + fn smart_ancestors_to_propose( + &mut self, + clock_round: Round, + smart_select: bool, + ) -> Vec { + let _s = self + .context + .metrics + .node_metrics + .scope_processing_time + .with_label_values(&["Core::smart_ancestors_to_propose"]) + .start_timer(); + + // Now take the ancestors before the clock_round (excluded) for each authority. + let ancestors = self + .dag_state + .read() + .get_last_cached_block_per_authority(clock_round); + + assert_eq!( + ancestors.len(), + self.context.committee.size(), + "Fatal error, number of returned ancestors don't match committee size." + ); + + // Ensure ancestor state is up to date before selecting for proposal. + self.ancestor_state_manager.update_all_ancestors_state(); + let ancestor_state_map = self.ancestor_state_manager.get_ancestor_states(); + + let quorum_round = clock_round.saturating_sub(1); + + let mut temp_excluded_ancestors = Vec::new(); + + // Propose only ancestors of higher rounds than what has already been proposed. + // And always include own last proposed block first among ancestors. + // Start by only including the high scoring ancestors. Low scoring ancestors + // will be included in a second pass below. + let included_ancestors = iter::once(self.last_proposed_block.clone()) + .chain( + ancestors + .into_iter() + .filter(|ancestor| ancestor.author() != self.context.own_index) + .flat_map(|ancestor| { + + let ancestor_state = ancestor_state_map[ancestor.author()]; + + match ancestor_state { + AncestorState::Include => { + trace!("Found ancestor {ancestor} with INCLUDE state for round {clock_round}"); + } + AncestorState::Exclude(score) => { + trace!("Added ancestor {ancestor} with EXCLUDE state with score {score} to temporary excluded ancestors for round {clock_round}"); + temp_excluded_ancestors.push((score, ancestor)); + return None; + } + } + + if let Some(last_block_ref) = + self.last_included_ancestors[ancestor.author()] + { + return (last_block_ref.round < ancestor.round()).then_some(ancestor); + } + Some(ancestor) + }), + ) + .collect::>(); + + let mut parent_round_quorum = StakeAggregator::::new(); + + // Check total stake of high scoring parent round ancestors + for ancestor in included_ancestors + .iter() + .filter(|a| a.round() == quorum_round) + { + parent_round_quorum.add(ancestor.author(), &self.context.committee); + } + + if smart_select && !parent_round_quorum.reached_threshold(&self.context.committee) { + self.context.metrics.node_metrics.smart_selection_wait.inc(); + debug!("Only found {} stake of good ancestors to include for round {clock_round}, will wait for more.", parent_round_quorum.stake()); + return vec![]; + } + + // Sort scores descending so we can include the best of the temp excluded + // ancestors first until we reach the threshold. + temp_excluded_ancestors.sort_by(|a, b| b.0.cmp(&a.0)); + + let mut ancestors_to_propose = included_ancestors; + let mut excluded_ancestors = Vec::new(); + + for (score, ancestor) in temp_excluded_ancestors.into_iter() { + let block_hostname = &self.context.committee.authority(ancestor.author()).hostname; + if !parent_round_quorum.reached_threshold(&self.context.committee) + && ancestor.round() == quorum_round + { + debug!("Including temporarily excluded strong link ancestor {ancestor} with score {score} to propose for round {clock_round}"); + parent_round_quorum.add(ancestor.author(), &self.context.committee); + ancestors_to_propose.push(ancestor); + self.context + .metrics + .node_metrics + .included_excluded_proposal_ancestors_count_by_authority + .with_label_values(&[block_hostname, "strong"]) + .inc(); + } else { + excluded_ancestors.push((score, ancestor)); + } + } + + assert!(parent_round_quorum.reached_threshold(&self.context.committee), "Fatal error, quorum not reached for parent round when proposing for round {clock_round}. Possible mismatch between DagState and Core."); + + for (score, ancestor) in excluded_ancestors.iter() { + let excluded_author = ancestor.author(); + let block_hostname = &self.context.committee.authority(excluded_author).hostname; + + trace!("Excluded low score ancestor {ancestor} with score {score} to propose for round {clock_round}"); + self.context + .metrics + .node_metrics + .excluded_proposal_ancestors_count_by_authority + .with_label_values(&[block_hostname]) + .inc(); + } + + info!( + "Included {} ancestors & excluded {} ancestors for proposal in round {clock_round}", + ancestors_to_propose.len(), + excluded_ancestors.len() + ); + + ancestors_to_propose + } + /// Checks whether all the leaders of the round exist. /// TODO: we can leverage some additional signal here in order to more cleverly manipulate later the leader timeout /// Ex if we already have one leader - the first in order - we might don't want to wait as much. @@ -1608,6 +1794,269 @@ mod test { } } + #[tokio::test(flavor = "current_thread", start_paused = true)] + async fn test_core_try_new_block_with_leader_timeout_and_low_scoring_authority() { + telemetry_subscribers::init_for_testing(); + + // Since we run the test with started_paused = true, any time-dependent operations using Tokio's time + // facilities, such as tokio::time::sleep or tokio::time::Instant, will not advance. So practically each + // Core's clock will have initialised potentially with different values but it never advances. + // To ensure that blocks won't get rejected by cores we'll need to manually wait for the time + // diff before processing them. By calling the `tokio::time::sleep` we implicitly also advance the + // tokio clock. + async fn wait_blocks(blocks: &[VerifiedBlock], context: &Context) { + // Simulate the time wait before processing a block to ensure that block.timestamp <= now + let now = context.clock.timestamp_utc_ms(); + let max_timestamp = blocks + .iter() + .max_by_key(|block| block.timestamp_ms() as BlockTimestampMs) + .map(|block| block.timestamp_ms()) + .unwrap_or(0); + + let wait_time = Duration::from_millis(max_timestamp.saturating_sub(now)); + sleep(wait_time).await; + } + + let (context, _) = Context::new_for_test(4); + + // Create the cores for all authorities + let mut all_cores = create_cores(context, vec![1, 1, 1, 1]); + let (_last_core, cores) = all_cores.split_last_mut().unwrap(); + + // Create blocks for rounds 1..=30 from all Cores except last Core of authority 3. + let mut last_round_blocks = Vec::::new(); + for round in 1..=30 { + let mut this_round_blocks = Vec::new(); + + for core_fixture in cores.iter_mut() { + wait_blocks(&last_round_blocks, &core_fixture.core.context).await; + + core_fixture + .core + .add_blocks(last_round_blocks.clone()) + .unwrap(); + + // Only when round > 1 and using non-genesis parents. + if let Some(r) = last_round_blocks.first().map(|b| b.round()) { + assert_eq!(round - 1, r); + if core_fixture.core.last_proposed_round() == r { + // Force propose new block regardless of min round delay. + core_fixture + .core + .try_propose(true) + .unwrap() + .unwrap_or_else(|| { + panic!("Block should have been proposed for round {}", round) + }); + } + } + + assert_eq!(core_fixture.core.last_proposed_round(), round); + + this_round_blocks.push(core_fixture.core.last_proposed_block.clone()); + } + + last_round_blocks = this_round_blocks; + } + + // Now produce blocks for all Cores + for round in 31..=40 { + let mut this_round_blocks = Vec::new(); + + for core_fixture in all_cores.iter_mut() { + wait_blocks(&last_round_blocks, &core_fixture.core.context).await; + + core_fixture + .core + .add_blocks(last_round_blocks.clone()) + .unwrap(); + + // Only when round > 1 and using non-genesis parents. + if let Some(r) = last_round_blocks.first().map(|b| b.round()) { + assert_eq!(round - 1, r); + if core_fixture.core.last_proposed_round() == r { + // Force propose new block regardless of min round delay. + core_fixture + .core + .try_propose(true) + .unwrap() + .unwrap_or_else(|| { + panic!("Block should have been proposed for round {}", round) + }); + } + } + + this_round_blocks.push(core_fixture.core.last_proposed_block.clone()); + + for block in this_round_blocks.iter() { + if block.author() != AuthorityIndex::new_for_test(3) { + // Assert blocks created include only 3 ancestors per block as one + // should be excluded + assert_eq!(block.ancestors().len(), 3); + } else { + // Authority 3 is the low scoring authority so it will still include + // its own blocks. + assert_eq!(block.ancestors().len(), 4); + } + } + } + + last_round_blocks = this_round_blocks; + } + } + + #[tokio::test] + async fn test_smart_ancestor_selection() { + telemetry_subscribers::init_for_testing(); + let (context, mut key_pairs) = Context::new_for_test(7); + let context = Arc::new(context.with_parameters(Parameters { + sync_last_known_own_block_timeout: Duration::from_millis(2_000), + ..Default::default() + })); + + let store = Arc::new(MemStore::new()); + let dag_state = Arc::new(RwLock::new(DagState::new(context.clone(), store.clone()))); + + let block_manager = BlockManager::new( + context.clone(), + dag_state.clone(), + Arc::new(NoopBlockVerifier), + ); + let leader_schedule = Arc::new( + LeaderSchedule::from_store(context.clone(), dag_state.clone()) + .with_num_commits_per_schedule(10), + ); + + let (_transaction_client, tx_receiver) = TransactionClient::new(context.clone()); + let transaction_consumer = TransactionConsumer::new(tx_receiver, context.clone()); + let (signals, signal_receivers) = CoreSignals::new(context.clone()); + // Need at least one subscriber to the block broadcast channel. + let _block_receiver = signal_receivers.block_broadcast_receiver(); + + let (commit_consumer, _commit_receiver, _transaction_receiver) = CommitConsumer::new(0); + let commit_observer = CommitObserver::new( + context.clone(), + commit_consumer, + dag_state.clone(), + store.clone(), + leader_schedule.clone(), + ); + + let mut core = Core::new( + context.clone(), + leader_schedule, + transaction_consumer, + block_manager, + true, + commit_observer, + signals, + key_pairs.remove(context.own_index.value()).1, + dag_state.clone(), + true, + ); + + // No new block should have been produced + assert_eq!( + core.last_proposed_round(), + GENESIS_ROUND, + "No block should have been created other than genesis" + ); + + // Trying to explicitly propose a block will not produce anything + assert!(core.try_propose(true).unwrap().is_none()); + + // Create blocks for the whole network but not for authority 1 + let mut builder = DagBuilder::new(context.clone()); + builder + .layers(1..=12) + .authorities(vec![AuthorityIndex::new_for_test(1)]) + .skip_block() + .build(); + let blocks = builder.blocks(1..=12); + // Process all the blocks + assert!(core.add_blocks(blocks).unwrap().is_empty()); + core.set_last_known_proposed_round(12); + + let block = core.try_propose(true).expect("No error").unwrap(); + assert_eq!(block.round(), 13); + assert_eq!(block.ancestors().len(), 7); + + // Build blocks for rest of the network other than own index + builder + .layers(13..=14) + .authorities(vec![AuthorityIndex::new_for_test(0)]) + .skip_block() + .build(); + let blocks = builder.blocks(13..=14); + assert!(core.add_blocks(blocks).unwrap().is_empty()); + + // We now have triggered a leader schedule change so we should have + // one EXCLUDE ancestor when we go to select ancestors for the next proposal + let block = core.try_propose(true).expect("No error").unwrap(); + assert_eq!(block.round(), 15); + assert_eq!(block.ancestors().len(), 6); + + // Build blocks for a quorum of the network including the EXCLUDE ancestor + // which will trigger smart select and we will not propose a block + builder + .layer(15) + .authorities(vec![ + AuthorityIndex::new_for_test(0), + AuthorityIndex::new_for_test(5), + AuthorityIndex::new_for_test(6), + ]) + .skip_block() + .build(); + let blocks = builder.blocks(15..=15); + // Wait for min round delay to allow blocks to be proposed. + sleep(context.parameters.min_round_delay).await; + // Smart select should be triggered and no block should be proposed. + assert!(core.add_blocks(blocks).unwrap().is_empty()); + assert_eq!(core.last_proposed_block().round(), 15); + + builder + .layer(15) + .authorities(vec![ + AuthorityIndex::new_for_test(0), + AuthorityIndex::new_for_test(1), + AuthorityIndex::new_for_test(2), + AuthorityIndex::new_for_test(3), + AuthorityIndex::new_for_test(4), + ]) + .skip_block() + .build(); + let blocks = builder.blocks(15..=15); + // Have enough ancestor blocks to propose now. + assert!(core.add_blocks(blocks).unwrap().is_empty()); + assert_eq!(core.last_proposed_block().round(), 16); + + // Build blocks for a quorum of the network including the EXCLUDE ancestor + // which will trigger smart select and we will not propose a block. + // This time we will force propose by hitting the leader timeout after which + // should cause us to include this EXCLUDE ancestor. + builder + .layer(16) + .authorities(vec![ + AuthorityIndex::new_for_test(0), + AuthorityIndex::new_for_test(5), + AuthorityIndex::new_for_test(6), + ]) + .skip_block() + .build(); + let blocks = builder.blocks(16..=16); + // Wait for leader timeout to force blocks to be proposed. + sleep(context.parameters.min_round_delay).await; + // Smart select should be triggered and no block should be proposed. + assert!(core.add_blocks(blocks).unwrap().is_empty()); + assert_eq!(core.last_proposed_block().round(), 16); + + // Simulate a leader timeout and a force proposal where we will include + // one EXCLUDE ancestor when we go to select ancestors for the next proposal + let block = core.try_propose(true).expect("No error").unwrap(); + assert_eq!(block.round(), 17); + assert_eq!(block.ancestors().len(), 5); + } + #[tokio::test] async fn test_core_set_subscriber_exists() { telemetry_subscribers::init_for_testing(); @@ -1673,7 +2122,7 @@ mod test { } #[tokio::test] - async fn test_core_set_propagation_delay() { + async fn test_core_set_propagation_delay_per_authority() { // TODO: create helper to avoid the duplicated code here. telemetry_subscribers::init_for_testing(); let (context, mut key_pairs) = Context::new_for_test(4); diff --git a/consensus/core/src/dag_state.rs b/consensus/core/src/dag_state.rs index 83aada9cb05a7..1fc9a30a872e3 100644 --- a/consensus/core/src/dag_state.rs +++ b/consensus/core/src/dag_state.rs @@ -920,7 +920,7 @@ impl DagState { } pub(crate) fn calculate_scoring_subdag_scores(&self) -> ReputationScores { - self.scoring_subdag.calculate_scores() + self.scoring_subdag.calculate_distributed_vote_scores() } pub(crate) fn scoring_subdag_commit_range(&self) -> CommitIndex { diff --git a/consensus/core/src/leader_scoring.rs b/consensus/core/src/leader_scoring.rs index 7136daf7c5e30..51ab0a5e4aa2e 100644 --- a/consensus/core/src/leader_scoring.rs +++ b/consensus/core/src/leader_scoring.rs @@ -129,6 +129,10 @@ impl ReputationScores { } } + pub(crate) fn highest_score(&self) -> u64 { + *self.scores_per_authority.iter().max().unwrap_or(&0) + } + // Returns the authorities index with score tuples. pub(crate) fn authorities_by_score(&self, context: Arc) -> Vec<(AuthorityIndex, u64)> { self.scores_per_authority @@ -258,17 +262,9 @@ impl ScoringSubdag { } // Iterate through votes and calculate scores for each authority based on - // scoring strategy that is used. (Vote or CertifiedVote) - pub(crate) fn calculate_scores(&self) -> ReputationScores { - let _s = self - .context - .metrics - .node_metrics - .scope_processing_time - .with_label_values(&["ScoringSubdag::calculate_scores"]) - .start_timer(); - - let scores_per_authority = self.score_distributed_votes(); + // distributed vote scoring strategy. + pub(crate) fn calculate_distributed_vote_scores(&self) -> ReputationScores { + let scores_per_authority = self.distributed_votes_scores(); // TODO: Normalize scores ReputationScores::new( @@ -283,7 +279,15 @@ impl ScoringSubdag { /// Instead of only giving one point for each vote that is included in 2f+1 /// blocks. We give a score equal to the amount of stake of all blocks that /// included the vote. - fn score_distributed_votes(&self) -> Vec { + fn distributed_votes_scores(&self) -> Vec { + let _s = self + .context + .metrics + .node_metrics + .scope_processing_time + .with_label_values(&["ScoringSubdag::score_distributed_votes"]) + .start_timer(); + let num_authorities = self.context.committee.size(); let mut scores_per_authority = vec![0_u64; num_authorities]; @@ -299,29 +303,6 @@ impl ScoringSubdag { scores_per_authority } - /// This scoring strategy gives points equal to the amount of stake in blocks - /// that include the authority's vote, if that amount of total_stake > 2f+1. - /// We consider this a certified vote. - // TODO: This will be used for ancestor selection - #[allow(unused)] - fn score_certified_votes(&self) -> Vec { - let num_authorities = self.context.committee.size(); - let mut scores_per_authority = vec![0_u64; num_authorities]; - - for (vote, stake_agg) in self.votes.iter() { - let authority = vote.author; - if stake_agg.reached_threshold(&self.context.committee) { - let stake = stake_agg.stake(); - tracing::trace!( - "[{}] scores +{stake} reputation for {authority}!", - self.context.own_index, - ); - scores_per_authority[authority.value()] += stake; - } - } - scores_per_authority - } - pub(crate) fn scored_subdags_count(&self) -> usize { if let Some(commit_range) = &self.commit_range { commit_range.size() @@ -555,41 +536,11 @@ mod tests { scoring_subdag.add_subdags(vec![sub_dag]); } - let scores = scoring_subdag.calculate_scores(); + let scores = scoring_subdag.calculate_distributed_vote_scores(); assert_eq!(scores.scores_per_authority, vec![5, 5, 5, 5]); assert_eq!(scores.commit_range, (1..=4).into()); } - #[tokio::test] - async fn test_certified_vote_scoring_subdag() { - telemetry_subscribers::init_for_testing(); - let context = Arc::new(Context::new_for_test(4).0); - - // Populate fully connected test blocks for round 0 ~ 3, authorities 0 ~ 3. - let mut dag_builder = DagBuilder::new(context.clone()); - dag_builder.layers(1..=3).build(); - // Build round 4 but with just the leader block - dag_builder - .layer(4) - .authorities(vec![ - AuthorityIndex::new_for_test(1), - AuthorityIndex::new_for_test(2), - AuthorityIndex::new_for_test(3), - ]) - .skip_block() - .build(); - - let mut scoring_subdag = ScoringSubdag::new(context.clone()); - - for (sub_dag, _commit) in dag_builder.get_sub_dag_and_commits(1..=4) { - scoring_subdag.add_subdags(vec![sub_dag]); - } - - let scores_per_authority = scoring_subdag.score_certified_votes(); - assert_eq!(scores_per_authority, vec![4, 4, 4, 4]); - assert_eq!(scoring_subdag.commit_range.unwrap(), (1..=4).into()); - } - // TODO: Remove all tests below this when DistributedVoteScoring is enabled. #[tokio::test] async fn test_reputation_score_calculator() { diff --git a/consensus/core/src/lib.rs b/consensus/core/src/lib.rs index 36b980311f5d7..7cee617d64c35 100644 --- a/consensus/core/src/lib.rs +++ b/consensus/core/src/lib.rs @@ -1,6 +1,7 @@ // Copyright (c) Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +mod ancestor; mod authority_node; mod authority_service; mod base_committer; diff --git a/consensus/core/src/metrics.rs b/consensus/core/src/metrics.rs index 11d303f3cf65a..da29cfae33201 100644 --- a/consensus/core/src/metrics.rs +++ b/consensus/core/src/metrics.rs @@ -141,6 +141,10 @@ pub(crate) struct NodeMetrics { pub(crate) commit_round_advancement_interval: Histogram, pub(crate) last_decided_leader_round: IntGauge, pub(crate) leader_timeout_total: IntCounterVec, + pub(crate) smart_selection_wait: IntCounter, + pub(crate) ancestor_state_change_by_authority: IntCounterVec, + pub(crate) excluded_proposal_ancestors_count_by_authority: IntCounterVec, + pub(crate) included_excluded_proposal_ancestors_count_by_authority: IntCounterVec, pub(crate) missing_blocks_total: IntCounter, pub(crate) missing_blocks_after_fetch_total: IntCounter, pub(crate) num_of_bad_nodes: IntGauge, @@ -441,6 +445,29 @@ impl NodeMetrics { &["timeout_type"], registry, ).unwrap(), + smart_selection_wait: register_int_counter_with_registry!( + "smart_selection_wait", + "Number of times we waited for smart ancestor selection.", + registry, + ).unwrap(), + ancestor_state_change_by_authority: register_int_counter_vec_with_registry!( + "ancestor_state_change_by_authority", + "The total number of times an ancestor state changed to EXCLUDE or INCLUDE.", + &["authority", "state"], + registry, + ).unwrap(), + excluded_proposal_ancestors_count_by_authority: register_int_counter_vec_with_registry!( + "excluded_proposal_ancestors_count_by_authority", + "Total number of excluded ancestors per authority during proposal.", + &["authority"], + registry, + ).unwrap(), + included_excluded_proposal_ancestors_count_by_authority: register_int_counter_vec_with_registry!( + "included_excluded_proposal_ancestors_count_by_authority", + "Total number of ancestors per authority with 'excluded' status that got included in proposal. Either weak or strong type.", + &["authority", "type"], + registry, + ).unwrap(), missing_blocks_total: register_int_counter_with_registry!( "missing_blocks_total", "Total cumulative number of missing blocks", diff --git a/consensus/core/src/round_prober.rs b/consensus/core/src/round_prober.rs index a80ffe148f1f9..3ce8b04dc8ede 100644 --- a/consensus/core/src/round_prober.rs +++ b/consensus/core/src/round_prober.rs @@ -238,7 +238,7 @@ impl RoundProber { .set_propagation_delay_and_quorum_rounds(propagation_delay, quorum_rounds.clone()) { tracing::warn!( - "Failed to set propagation delay {propagation_delay} on Core: {:?}", + "Failed to set propagation delay and quorum rounds {quorum_rounds:?} on Core: {:?}", e ); } diff --git a/crates/sui-open-rpc/spec/openrpc.json b/crates/sui-open-rpc/spec/openrpc.json index 4d46fb1412964..f33a0c653b67b 100644 --- a/crates/sui-open-rpc/spec/openrpc.json +++ b/crates/sui-open-rpc/spec/openrpc.json @@ -1293,7 +1293,7 @@ "name": "Result", "value": { "minSupportedProtocolVersion": "1", - "maxSupportedProtocolVersion": "68", + "maxSupportedProtocolVersion": "69", "protocolVersion": "6", "featureFlags": { "accept_zklogin_in_multisig": false, @@ -1307,6 +1307,7 @@ "consensus_distributed_vote_scoring_strategy": false, "consensus_order_end_of_epoch_last": true, "consensus_round_prober": false, + "consensus_smart_ancestor_selection": false, "disable_invariant_violation_check_in_swap_loc": false, "disallow_adding_abilities_on_upgrade": false, "disallow_change_struct_type_params_on_upgrade": false, diff --git a/crates/sui-protocol-config/src/lib.rs b/crates/sui-protocol-config/src/lib.rs index 0a37adc961e5d..4c5c10ed76dd2 100644 --- a/crates/sui-protocol-config/src/lib.rs +++ b/crates/sui-protocol-config/src/lib.rs @@ -18,7 +18,7 @@ use tracing::{info, warn}; /// The minimum and maximum protocol versions supported by this build. const MIN_PROTOCOL_VERSION: u64 = 1; -const MAX_PROTOCOL_VERSION: u64 = 68; +const MAX_PROTOCOL_VERSION: u64 = 69; // Record history of protocol version allocations here: // @@ -195,6 +195,7 @@ const MAX_PROTOCOL_VERSION: u64 = 68; // Enable gas based congestion control with overage. // Further reduce minimum number of random beacon shares. // Disallow adding new modules in `deps-only` packages. +// Version 69: Enable smart ancestor selection in devnet. #[derive(Copy, Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)] pub struct ProtocolVersion(u64); @@ -564,6 +565,10 @@ struct FeatureFlags { #[serde(skip_serializing_if = "is_false")] disallow_new_modules_in_deps_only_packages: bool, + + // Use smart ancestor selection in consensus. + #[serde(skip_serializing_if = "is_false")] + consensus_smart_ancestor_selection: bool, } fn is_false(b: &bool) -> bool { @@ -1674,6 +1679,10 @@ impl ProtocolConfig { self.feature_flags .disallow_new_modules_in_deps_only_packages } + + pub fn consensus_smart_ancestor_selection(&self) -> bool { + self.feature_flags.consensus_smart_ancestor_selection + } } #[cfg(not(msim))] @@ -2943,6 +2952,12 @@ impl ProtocolConfig { // Sets number of rounds allowed for fastpath voting in consensus. cfg.consensus_voting_rounds = Some(40); } + 69 => { + if chain != Chain::Mainnet && chain != Chain::Testnet { + // Enable smart ancestor selection for devnet + cfg.feature_flags.consensus_smart_ancestor_selection = true; + } + } // Use this template when making changes: // // // modify an existing constant. diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_69.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_69.snap new file mode 100644 index 0000000000000..a3327178304ee --- /dev/null +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Mainnet_version_69.snap @@ -0,0 +1,340 @@ +--- +source: crates/sui-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 69 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + bridge: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true + per_object_congestion_control_mode: TotalGasBudgetWithCap + consensus_choice: Mysticeti + consensus_network: Tonic + zklogin_max_epoch_upper_bound_delta: 30 + mysticeti_leader_scoring_and_schedule: true + reshare_at_same_initial_version: true + resolve_abort_locations_to_package_id: true + mysticeti_use_committed_subdag_digest: true + record_consensus_determined_version_assignments_in_prologue: true + fresh_vm_on_framework_upgrade: true + prepend_prologue_tx_in_consensus_commit_in_checkpoints: true + mysticeti_num_leaders_per_round: 1 + soft_bundle: true + enable_coin_deny_list_v2: true + rethrow_serialization_type_layout_errors: true + consensus_distributed_vote_scoring_strategy: true + consensus_round_prober: true + validate_identifier_inputs: true + relocate_event_module: true + disallow_new_modules_in_deps_only_packages: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 7 +min_move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +max_meter_ticks_per_package: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +max_type_to_layout_nodes: 512 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +config_read_setting_impl_cost_base: 100 +config_read_setting_impl_cost_per_byte: 40 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +group_ops_bls12381_g1_to_uncompressed_g1_cost: 26 +group_ops_bls12381_uncompressed_g1_to_g1_cost: 52 +group_ops_bls12381_uncompressed_g1_sum_base_cost: 26 +group_ops_bls12381_uncompressed_g1_sum_cost_per_term: 13 +group_ops_bls12381_uncompressed_g1_sum_max_terms: 2000 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +bcs_per_byte_serialized_cost: 2 +bcs_legacy_min_output_size_cost: 1 +bcs_failure_cost: 52 +hash_sha2_256_base_cost: 52 +hash_sha2_256_per_byte_cost: 2 +hash_sha2_256_legacy_min_input_len_cost: 1 +hash_sha3_256_base_cost: 52 +hash_sha3_256_per_byte_cost: 2 +hash_sha3_256_legacy_min_input_len_cost: 1 +type_name_get_base_cost: 52 +type_name_get_per_byte_cost: 2 +string_check_utf8_base_cost: 52 +string_check_utf8_per_byte_cost: 2 +string_is_char_boundary_base_cost: 52 +string_sub_string_base_cost: 52 +string_sub_string_per_byte_cost: 2 +string_index_of_base_cost: 52 +string_index_of_per_byte_pattern_cost: 2 +string_index_of_per_byte_searched_cost: 2 +vector_empty_base_cost: 52 +vector_length_base_cost: 52 +vector_push_back_base_cost: 52 +vector_push_back_legacy_per_abstract_memory_unit_cost: 2 +vector_borrow_base_cost: 52 +vector_pop_back_base_cost: 52 +vector_destroy_empty_base_cost: 52 +vector_swap_base_cost: 52 +debug_print_base_cost: 52 +debug_print_stack_trace_base_cost: 52 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 500 +random_beacon_dkg_timeout_round: 3000 +random_beacon_min_round_interval_ms: 500 +random_beacon_dkg_version: 1 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 524288 +consensus_max_num_transactions_in_block: 512 +consensus_voting_rounds: 40 +max_accumulated_txn_cost_per_object_in_narwhal_commit: 40 +max_deferral_rounds_for_congestion_control: 10 +max_txn_cost_overage_per_object_in_commit: 18446744073709551615 +min_checkpoint_interval_ms: 200 +checkpoint_summary_version_specific_data: 1 +max_soft_bundle_size: 5 +bridge_should_try_to_finalize_committee: true +max_accumulated_txn_cost_per_object_in_mysticeti_commit: 18500000 +max_accumulated_randomness_txn_cost_per_object_in_mysticeti_commit: 3700000 +gas_budget_based_txn_cost_cap_factor: 400000 +gas_budget_based_txn_cost_absolute_cap_commit_count: 50 + diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_69.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_69.snap new file mode 100644 index 0000000000000..a3327178304ee --- /dev/null +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__Testnet_version_69.snap @@ -0,0 +1,340 @@ +--- +source: crates/sui-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 69 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + bridge: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + reject_mutable_random_on_entry_functions: true + per_object_congestion_control_mode: TotalGasBudgetWithCap + consensus_choice: Mysticeti + consensus_network: Tonic + zklogin_max_epoch_upper_bound_delta: 30 + mysticeti_leader_scoring_and_schedule: true + reshare_at_same_initial_version: true + resolve_abort_locations_to_package_id: true + mysticeti_use_committed_subdag_digest: true + record_consensus_determined_version_assignments_in_prologue: true + fresh_vm_on_framework_upgrade: true + prepend_prologue_tx_in_consensus_commit_in_checkpoints: true + mysticeti_num_leaders_per_round: 1 + soft_bundle: true + enable_coin_deny_list_v2: true + rethrow_serialization_type_layout_errors: true + consensus_distributed_vote_scoring_strategy: true + consensus_round_prober: true + validate_identifier_inputs: true + relocate_event_module: true + disallow_new_modules_in_deps_only_packages: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 7 +min_move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +max_meter_ticks_per_package: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +max_type_to_layout_nodes: 512 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +config_read_setting_impl_cost_base: 100 +config_read_setting_impl_cost_per_byte: 40 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +group_ops_bls12381_g1_to_uncompressed_g1_cost: 26 +group_ops_bls12381_uncompressed_g1_to_g1_cost: 52 +group_ops_bls12381_uncompressed_g1_sum_base_cost: 26 +group_ops_bls12381_uncompressed_g1_sum_cost_per_term: 13 +group_ops_bls12381_uncompressed_g1_sum_max_terms: 2000 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +bcs_per_byte_serialized_cost: 2 +bcs_legacy_min_output_size_cost: 1 +bcs_failure_cost: 52 +hash_sha2_256_base_cost: 52 +hash_sha2_256_per_byte_cost: 2 +hash_sha2_256_legacy_min_input_len_cost: 1 +hash_sha3_256_base_cost: 52 +hash_sha3_256_per_byte_cost: 2 +hash_sha3_256_legacy_min_input_len_cost: 1 +type_name_get_base_cost: 52 +type_name_get_per_byte_cost: 2 +string_check_utf8_base_cost: 52 +string_check_utf8_per_byte_cost: 2 +string_is_char_boundary_base_cost: 52 +string_sub_string_base_cost: 52 +string_sub_string_per_byte_cost: 2 +string_index_of_base_cost: 52 +string_index_of_per_byte_pattern_cost: 2 +string_index_of_per_byte_searched_cost: 2 +vector_empty_base_cost: 52 +vector_length_base_cost: 52 +vector_push_back_base_cost: 52 +vector_push_back_legacy_per_abstract_memory_unit_cost: 2 +vector_borrow_base_cost: 52 +vector_pop_back_base_cost: 52 +vector_destroy_empty_base_cost: 52 +vector_swap_base_cost: 52 +debug_print_base_cost: 52 +debug_print_stack_trace_base_cost: 52 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 500 +random_beacon_dkg_timeout_round: 3000 +random_beacon_min_round_interval_ms: 500 +random_beacon_dkg_version: 1 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 524288 +consensus_max_num_transactions_in_block: 512 +consensus_voting_rounds: 40 +max_accumulated_txn_cost_per_object_in_narwhal_commit: 40 +max_deferral_rounds_for_congestion_control: 10 +max_txn_cost_overage_per_object_in_commit: 18446744073709551615 +min_checkpoint_interval_ms: 200 +checkpoint_summary_version_specific_data: 1 +max_soft_bundle_size: 5 +bridge_should_try_to_finalize_committee: true +max_accumulated_txn_cost_per_object_in_mysticeti_commit: 18500000 +max_accumulated_randomness_txn_cost_per_object_in_mysticeti_commit: 3700000 +gas_budget_based_txn_cost_cap_factor: 400000 +gas_budget_based_txn_cost_absolute_cap_commit_count: 50 + diff --git a/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_69.snap b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_69.snap new file mode 100644 index 0000000000000..ccca747ea3a97 --- /dev/null +++ b/crates/sui-protocol-config/src/snapshots/sui_protocol_config__test__version_69.snap @@ -0,0 +1,352 @@ +--- +source: crates/sui-protocol-config/src/lib.rs +expression: "ProtocolConfig::get_for_version(cur, *chain_id)" +--- +version: 69 +feature_flags: + package_upgrades: true + commit_root_state_digest: true + advance_epoch_start_time_in_safe_mode: true + loaded_child_objects_fixed: true + missing_type_is_compatibility_error: true + scoring_decision_with_validity_cutoff: true + consensus_order_end_of_epoch_last: true + disallow_adding_abilities_on_upgrade: true + disable_invariant_violation_check_in_swap_loc: true + advance_to_highest_supported_protocol_version: true + ban_entry_init: true + package_digest_hash_module: true + disallow_change_struct_type_params_on_upgrade: true + no_extraneous_module_bytes: true + narwhal_versioned_metadata: true + zklogin_auth: true + consensus_transaction_ordering: ByGasPrice + simplified_unwrap_then_delete: true + upgraded_multisig_supported: true + txn_base_cost_as_multiplier: true + shared_object_deletion: true + narwhal_new_leader_election_schedule: true + loaded_child_object_format: true + enable_jwk_consensus_updates: true + end_of_epoch_transaction_supported: true + simple_conservation_checks: true + loaded_child_object_format_type: true + receive_objects: true + random_beacon: true + bridge: true + enable_effects_v2: true + narwhal_certificate_v2: true + verify_legacy_zklogin_address: true + recompute_has_public_transfer_in_execution: true + accept_zklogin_in_multisig: true + include_consensus_digest_in_prologue: true + hardened_otw_check: true + allow_receiving_object_id: true + enable_poseidon: true + enable_coin_deny_list: true + enable_group_ops_native_functions: true + enable_group_ops_native_function_msm: true + reject_mutable_random_on_entry_functions: true + per_object_congestion_control_mode: TotalGasBudgetWithCap + consensus_choice: Mysticeti + consensus_network: Tonic + zklogin_max_epoch_upper_bound_delta: 30 + mysticeti_leader_scoring_and_schedule: true + reshare_at_same_initial_version: true + resolve_abort_locations_to_package_id: true + mysticeti_use_committed_subdag_digest: true + enable_vdf: true + record_consensus_determined_version_assignments_in_prologue: true + fresh_vm_on_framework_upgrade: true + prepend_prologue_tx_in_consensus_commit_in_checkpoints: true + mysticeti_num_leaders_per_round: 1 + soft_bundle: true + enable_coin_deny_list_v2: true + passkey_auth: true + authority_capabilities_v2: true + rethrow_serialization_type_layout_errors: true + consensus_distributed_vote_scoring_strategy: true + consensus_round_prober: true + validate_identifier_inputs: true + mysticeti_fastpath: true + relocate_event_module: true + uncompressed_g1_group_elements: true + disallow_new_modules_in_deps_only_packages: true + consensus_smart_ancestor_selection: true +max_tx_size_bytes: 131072 +max_input_objects: 2048 +max_size_written_objects: 5000000 +max_size_written_objects_system_tx: 50000000 +max_serialized_tx_effects_size_bytes: 524288 +max_serialized_tx_effects_size_bytes_system_tx: 8388608 +max_gas_payment_objects: 256 +max_modules_in_publish: 64 +max_package_dependencies: 32 +max_arguments: 512 +max_type_arguments: 16 +max_type_argument_depth: 16 +max_pure_argument_size: 16384 +max_programmable_tx_commands: 1024 +move_binary_format_version: 7 +min_move_binary_format_version: 6 +binary_module_handles: 100 +binary_struct_handles: 300 +binary_function_handles: 1500 +binary_function_instantiations: 750 +binary_signatures: 1000 +binary_constant_pool: 4000 +binary_identifiers: 10000 +binary_address_identifiers: 100 +binary_struct_defs: 200 +binary_struct_def_instantiations: 100 +binary_function_defs: 1000 +binary_field_handles: 500 +binary_field_instantiations: 250 +binary_friend_decls: 100 +max_move_object_size: 256000 +max_move_package_size: 102400 +max_publish_or_upgrade_per_ptb: 5 +max_tx_gas: 50000000000 +max_gas_price: 100000 +max_gas_computation_bucket: 5000000 +gas_rounding_step: 1000 +max_loop_depth: 5 +max_generic_instantiation_length: 32 +max_function_parameters: 128 +max_basic_blocks: 1024 +max_value_stack_size: 1024 +max_type_nodes: 256 +max_push_size: 10000 +max_struct_definitions: 200 +max_function_definitions: 1000 +max_fields_in_struct: 32 +max_dependency_depth: 100 +max_num_event_emit: 1024 +max_num_new_move_object_ids: 2048 +max_num_new_move_object_ids_system_tx: 32768 +max_num_deleted_move_object_ids: 2048 +max_num_deleted_move_object_ids_system_tx: 32768 +max_num_transferred_move_object_ids: 2048 +max_num_transferred_move_object_ids_system_tx: 32768 +max_event_emit_size: 256000 +max_event_emit_size_total: 65536000 +max_move_vector_len: 262144 +max_move_identifier_len: 128 +max_move_value_depth: 128 +max_back_edges_per_function: 10000 +max_back_edges_per_module: 10000 +max_verifier_meter_ticks_per_function: 16000000 +max_meter_ticks_per_module: 16000000 +max_meter_ticks_per_package: 16000000 +object_runtime_max_num_cached_objects: 1000 +object_runtime_max_num_cached_objects_system_tx: 16000 +object_runtime_max_num_store_entries: 1000 +object_runtime_max_num_store_entries_system_tx: 16000 +base_tx_cost_fixed: 1000 +package_publish_cost_fixed: 1000 +base_tx_cost_per_byte: 0 +package_publish_cost_per_byte: 80 +obj_access_cost_read_per_byte: 15 +obj_access_cost_mutate_per_byte: 40 +obj_access_cost_delete_per_byte: 40 +obj_access_cost_verify_per_byte: 200 +max_type_to_layout_nodes: 512 +gas_model_version: 8 +obj_data_cost_refundable: 100 +obj_metadata_cost_non_refundable: 50 +storage_rebate_rate: 9900 +storage_fund_reinvest_rate: 500 +reward_slashing_rate: 10000 +storage_gas_price: 76 +max_transactions_per_checkpoint: 10000 +max_checkpoint_size_bytes: 31457280 +buffer_stake_for_protocol_upgrade_bps: 5000 +address_from_bytes_cost_base: 52 +address_to_u256_cost_base: 52 +address_from_u256_cost_base: 52 +config_read_setting_impl_cost_base: 100 +config_read_setting_impl_cost_per_byte: 40 +dynamic_field_hash_type_and_key_cost_base: 100 +dynamic_field_hash_type_and_key_type_cost_per_byte: 2 +dynamic_field_hash_type_and_key_value_cost_per_byte: 2 +dynamic_field_hash_type_and_key_type_tag_cost_per_byte: 2 +dynamic_field_add_child_object_cost_base: 100 +dynamic_field_add_child_object_type_cost_per_byte: 10 +dynamic_field_add_child_object_value_cost_per_byte: 10 +dynamic_field_add_child_object_struct_tag_cost_per_byte: 10 +dynamic_field_borrow_child_object_cost_base: 100 +dynamic_field_borrow_child_object_child_ref_cost_per_byte: 10 +dynamic_field_borrow_child_object_type_cost_per_byte: 10 +dynamic_field_remove_child_object_cost_base: 100 +dynamic_field_remove_child_object_child_cost_per_byte: 2 +dynamic_field_remove_child_object_type_cost_per_byte: 2 +dynamic_field_has_child_object_cost_base: 100 +dynamic_field_has_child_object_with_ty_cost_base: 100 +dynamic_field_has_child_object_with_ty_type_cost_per_byte: 2 +dynamic_field_has_child_object_with_ty_type_tag_cost_per_byte: 2 +event_emit_cost_base: 52 +event_emit_value_size_derivation_cost_per_byte: 2 +event_emit_tag_size_derivation_cost_per_byte: 5 +event_emit_output_cost_per_byte: 10 +object_borrow_uid_cost_base: 52 +object_delete_impl_cost_base: 52 +object_record_new_uid_cost_base: 52 +transfer_transfer_internal_cost_base: 52 +transfer_freeze_object_cost_base: 52 +transfer_share_object_cost_base: 52 +transfer_receive_object_cost_base: 52 +tx_context_derive_id_cost_base: 52 +types_is_one_time_witness_cost_base: 52 +types_is_one_time_witness_type_tag_cost_per_byte: 2 +types_is_one_time_witness_type_cost_per_byte: 2 +validator_validate_metadata_cost_base: 52 +validator_validate_metadata_data_cost_per_byte: 2 +crypto_invalid_arguments_cost: 100 +bls12381_bls12381_min_sig_verify_cost_base: 52 +bls12381_bls12381_min_sig_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_sig_verify_msg_cost_per_block: 2 +bls12381_bls12381_min_pk_verify_cost_base: 52 +bls12381_bls12381_min_pk_verify_msg_cost_per_byte: 2 +bls12381_bls12381_min_pk_verify_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_keccak256_cost_base: 52 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_k1_ecrecover_sha256_cost_base: 52 +ecdsa_k1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_k1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_k1_decompress_pubkey_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_cost_base: 52 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_k1_secp256k1_verify_sha256_cost_base: 52 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_k1_secp256k1_verify_sha256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_keccak256_cost_base: 52 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_keccak256_msg_cost_per_block: 2 +ecdsa_r1_ecrecover_sha256_cost_base: 52 +ecdsa_r1_ecrecover_sha256_msg_cost_per_byte: 2 +ecdsa_r1_ecrecover_sha256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_keccak256_cost_base: 52 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_keccak256_msg_cost_per_block: 2 +ecdsa_r1_secp256r1_verify_sha256_cost_base: 52 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_byte: 2 +ecdsa_r1_secp256r1_verify_sha256_msg_cost_per_block: 2 +ecvrf_ecvrf_verify_cost_base: 52 +ecvrf_ecvrf_verify_alpha_string_cost_per_byte: 2 +ecvrf_ecvrf_verify_alpha_string_cost_per_block: 2 +ed25519_ed25519_verify_cost_base: 52 +ed25519_ed25519_verify_msg_cost_per_byte: 2 +ed25519_ed25519_verify_msg_cost_per_block: 2 +groth16_prepare_verifying_key_bls12381_cost_base: 52 +groth16_prepare_verifying_key_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_base: 52 +groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_bn254_cost_base: 52 +groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: 2 +groth16_verify_groth16_proof_internal_public_input_cost_per_byte: 2 +hash_blake2b256_cost_base: 52 +hash_blake2b256_data_cost_per_byte: 2 +hash_blake2b256_data_cost_per_block: 2 +hash_keccak256_cost_base: 52 +hash_keccak256_data_cost_per_byte: 2 +hash_keccak256_data_cost_per_block: 2 +poseidon_bn254_cost_base: 260 +poseidon_bn254_cost_per_block: 10 +group_ops_bls12381_decode_scalar_cost: 52 +group_ops_bls12381_decode_g1_cost: 52 +group_ops_bls12381_decode_g2_cost: 52 +group_ops_bls12381_decode_gt_cost: 52 +group_ops_bls12381_scalar_add_cost: 52 +group_ops_bls12381_g1_add_cost: 52 +group_ops_bls12381_g2_add_cost: 52 +group_ops_bls12381_gt_add_cost: 52 +group_ops_bls12381_scalar_sub_cost: 52 +group_ops_bls12381_g1_sub_cost: 52 +group_ops_bls12381_g2_sub_cost: 52 +group_ops_bls12381_gt_sub_cost: 52 +group_ops_bls12381_scalar_mul_cost: 52 +group_ops_bls12381_g1_mul_cost: 52 +group_ops_bls12381_g2_mul_cost: 52 +group_ops_bls12381_gt_mul_cost: 52 +group_ops_bls12381_scalar_div_cost: 52 +group_ops_bls12381_g1_div_cost: 52 +group_ops_bls12381_g2_div_cost: 52 +group_ops_bls12381_gt_div_cost: 52 +group_ops_bls12381_g1_hash_to_base_cost: 52 +group_ops_bls12381_g2_hash_to_base_cost: 52 +group_ops_bls12381_g1_hash_to_cost_per_byte: 2 +group_ops_bls12381_g2_hash_to_cost_per_byte: 2 +group_ops_bls12381_g1_msm_base_cost: 52 +group_ops_bls12381_g2_msm_base_cost: 52 +group_ops_bls12381_g1_msm_base_cost_per_input: 52 +group_ops_bls12381_g2_msm_base_cost_per_input: 52 +group_ops_bls12381_msm_max_len: 32 +group_ops_bls12381_pairing_cost: 52 +group_ops_bls12381_g1_to_uncompressed_g1_cost: 26 +group_ops_bls12381_uncompressed_g1_to_g1_cost: 52 +group_ops_bls12381_uncompressed_g1_sum_base_cost: 26 +group_ops_bls12381_uncompressed_g1_sum_cost_per_term: 13 +group_ops_bls12381_uncompressed_g1_sum_max_terms: 2000 +hmac_hmac_sha3_256_cost_base: 52 +hmac_hmac_sha3_256_input_cost_per_byte: 2 +hmac_hmac_sha3_256_input_cost_per_block: 2 +check_zklogin_id_cost_base: 200 +check_zklogin_issuer_cost_base: 200 +vdf_verify_vdf_cost: 1500 +vdf_hash_to_input_cost: 100 +bcs_per_byte_serialized_cost: 2 +bcs_legacy_min_output_size_cost: 1 +bcs_failure_cost: 52 +hash_sha2_256_base_cost: 52 +hash_sha2_256_per_byte_cost: 2 +hash_sha2_256_legacy_min_input_len_cost: 1 +hash_sha3_256_base_cost: 52 +hash_sha3_256_per_byte_cost: 2 +hash_sha3_256_legacy_min_input_len_cost: 1 +type_name_get_base_cost: 52 +type_name_get_per_byte_cost: 2 +string_check_utf8_base_cost: 52 +string_check_utf8_per_byte_cost: 2 +string_is_char_boundary_base_cost: 52 +string_sub_string_base_cost: 52 +string_sub_string_per_byte_cost: 2 +string_index_of_base_cost: 52 +string_index_of_per_byte_pattern_cost: 2 +string_index_of_per_byte_searched_cost: 2 +vector_empty_base_cost: 52 +vector_length_base_cost: 52 +vector_push_back_base_cost: 52 +vector_push_back_legacy_per_abstract_memory_unit_cost: 2 +vector_borrow_base_cost: 52 +vector_pop_back_base_cost: 52 +vector_destroy_empty_base_cost: 52 +vector_swap_base_cost: 52 +debug_print_base_cost: 52 +debug_print_stack_trace_base_cost: 52 +execution_version: 3 +consensus_bad_nodes_stake_threshold: 20 +max_jwk_votes_per_validator_per_epoch: 240 +max_age_of_jwk_in_epochs: 1 +random_beacon_reduction_allowed_delta: 800 +random_beacon_reduction_lower_bound: 500 +random_beacon_dkg_timeout_round: 3000 +random_beacon_min_round_interval_ms: 500 +random_beacon_dkg_version: 1 +consensus_max_transaction_size_bytes: 262144 +consensus_max_transactions_in_block_bytes: 524288 +consensus_max_num_transactions_in_block: 512 +consensus_voting_rounds: 40 +max_accumulated_txn_cost_per_object_in_narwhal_commit: 40 +max_deferral_rounds_for_congestion_control: 10 +max_txn_cost_overage_per_object_in_commit: 18446744073709551615 +min_checkpoint_interval_ms: 200 +checkpoint_summary_version_specific_data: 1 +max_soft_bundle_size: 5 +bridge_should_try_to_finalize_committee: true +max_accumulated_txn_cost_per_object_in_mysticeti_commit: 18500000 +max_accumulated_randomness_txn_cost_per_object_in_mysticeti_commit: 3700000 +gas_budget_based_txn_cost_cap_factor: 400000 +gas_budget_based_txn_cost_absolute_cap_commit_count: 50 + diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap index 2fcba9da75085..7a81890461ed6 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap +++ b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__genesis_config_snapshot_matches.snap @@ -6,7 +6,7 @@ ssfn_config_info: ~ validator_config_info: ~ parameters: chain_start_timestamp_ms: 0 - protocol_version: 68 + protocol_version: 69 allow_insertion_of_extra_objects: true epoch_duration_ms: 86400000 stake_subsidy_start_epoch: 0 diff --git a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap index 7e39140036125..ce61493c555c6 100644 --- a/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap +++ b/crates/sui-swarm-config/tests/snapshots/snapshot_tests__populated_genesis_snapshot_matches-2.snap @@ -3,7 +3,7 @@ source: crates/sui-swarm-config/tests/snapshot_tests.rs expression: genesis.sui_system_object().into_genesis_version_for_tooling() --- epoch: 0 -protocol_version: 68 +protocol_version: 69 system_state_version: 1 validators: total_stake: 20000000000000000 @@ -240,13 +240,13 @@ validators: next_epoch_worker_address: ~ extra_fields: id: - id: "0x2f1c192f30b36b0d0a47520ff814ace58ce8a73580c9bf86c0fc729781351bcc" + id: "0x0ab85bf1aef18aad179ca34f4d95e34dd60dd1b2bda18d558e7b0bfe14ba8b77" size: 0 voting_power: 10000 - operation_cap_id: "0x0e83ac0a1c9938e12a692c734f8f38dfe5858076b17611402d46afcd5887ba8e" + operation_cap_id: "0x2fd0e88948443e54727efb6d1756d8c39735a421dac7bb92be690abe205b5bfa" gas_price: 1000 staking_pool: - id: "0x222477b804c11404854c3c14cf29a2840472651c91d8870e07ae852a98c0a2e3" + id: "0xdcc39ac807721ee62f3fe0a6c697cbd93389f79b1a6717a95ccd28dca27821c8" activation_epoch: 0 deactivation_epoch: ~ sui_balance: 20000000000000000 @@ -254,14 +254,14 @@ validators: value: 0 pool_token_balance: 20000000000000000 exchange_rates: - id: "0xf532945be4e9eb7ef597867c6dee34dc1d89f55f711d084bc6aa01c7c99ea179" + id: "0xaa706539eb8876b6c6a9b335c8d0ab1275d0a08a8ad29a6e6da68891e59298e4" size: 1 pending_stake: 0 pending_total_sui_withdraw: 0 pending_pool_token_withdraw: 0 extra_fields: id: - id: "0x4b5abcdcefc7404834889f2890b2b626ab85c15a20b19130b56cbee9bbe2b0af" + id: "0x651bc7aee334c01c02043e8caa326beaf7cf3fee5f099dda61cd39a971b1a0e6" size: 0 commission_rate: 200 next_epoch_stake: 20000000000000000 @@ -269,27 +269,27 @@ validators: next_epoch_commission_rate: 200 extra_fields: id: - id: "0xeb9ab0c31391cb533e672f2aa1a919f474a988620c5eac625dab9e28e15a7661" + id: "0x3e9b72b2ab6660a2fd11af8d5f44925fccdb0fd793ec425f6438a1b149f8e3ea" size: 0 pending_active_validators: contents: - id: "0x1e0beb565adb7f908bce1bb65d14b5da4c6e4e0ff281e91e4c79fd7a20947d35" + id: "0xd93aaac7fc3ff26d6f2336ad8f11c15f2e51a0623715fce08742faa1caabdc65" size: 0 pending_removals: [] staking_pool_mappings: - id: "0xabce5d04c1673e4e317e5c0f78bc346c4960d25473e095c9fb668ac32f5e216d" + id: "0xffabe0c370cf34f726bb6132f97dbc7bf7f77c4b5322797f786cbc73b0c0d125" size: 1 inactive_validators: - id: "0x9069998be467d392b0a8ce1f598a353c415729af75bb2ebafbe66d26114ad52f" + id: "0x3d3953f69d3dcb19cbaad3c5372084f72a9290916c5faf5f8f241cb5d5e6c94b" size: 0 validator_candidates: - id: "0x68667de51bea6086d3fd60059841df6da32a6fd475ad52ad10597797ec6a3ca9" + id: "0x66528ea16da7d7286671c3f187a1e68e0acd4fc13ffe45a0e5de12d2e2a825ec" size: 0 at_risk_validators: contents: [] extra_fields: id: - id: "0xfc98b9ca99540332ff24894fd810f83a85e726542c2119bc1325d350b0399434" + id: "0x1dff1b20ab0c400d5e48019f10ded46bdb08927f2e22fa4ced77ee6829b3c618" size: 0 storage_fund: total_object_storage_rebates: @@ -306,7 +306,7 @@ parameters: validator_low_stake_grace_period: 7 extra_fields: id: - id: "0x16212fe3db87d96453a048041166f3f491c06f00c45a4efe181bf7708c292d3f" + id: "0x3730cc216e9af079f9f8955b07b50366ee726b2d95dd102c4420e0e5102ce558" size: 0 reference_gas_price: 1000 validator_report_records: @@ -320,7 +320,7 @@ stake_subsidy: stake_subsidy_decrease_rate: 1000 extra_fields: id: - id: "0x3110ada5ccc4394928c0116629587c1ad110099430f19ea183d799689eb5a8df" + id: "0xdf3d8018bba72f99aee8cfcb7af644e0edbbd86cb02732cf4bd2f3bbc8b45a25" size: 0 safe_mode: false safe_mode_storage_rewards: @@ -332,6 +332,6 @@ safe_mode_non_refundable_storage_fee: 0 epoch_start_timestamp_ms: 10 extra_fields: id: - id: "0x34587a89960874da16d01bb778a02f7603278b0da8ec9258668982948f9b9535" + id: "0xbb67e32883f2542fb09119328da10c216ae19f663b64f024a724ca8c508502fa" size: 0