diff --git a/dan_layer/consensus/src/consensus_constants.rs b/dan_layer/consensus/src/consensus_constants.rs index 16787f3a4..f671d6047 100644 --- a/dan_layer/consensus/src/consensus_constants.rs +++ b/dan_layer/consensus/src/consensus_constants.rs @@ -33,7 +33,13 @@ pub struct ConsensusConstants { pub max_base_layer_blocks_behind: u64, pub num_preshards: NumPreshards, pub pacemaker_block_time: Duration, + /// The number of missed proposals before a SuspendNode proposal is sent pub missed_proposal_suspend_threshold: u64, + /// The maximum number of missed proposals to count. If a peer is offline, gets suspended and comes online, their + /// missed proposal count is decremented for each block that they participate in. Once this reaches zero, the node + /// is considered online and will be reinstated. This cap essentially gives the maximum number of rounds until they + /// will be reinstated once they resume participation in consensus. + pub missed_proposal_count_cap: u64, pub max_block_size: usize, /// The value that fees are divided by to determine the amount of fees to burn. 0 means no fees are burned. pub fee_exhaust_divisor: u64, @@ -48,7 +54,8 @@ impl ConsensusConstants { max_base_layer_blocks_behind: 5, num_preshards: NumPreshards::P256, pacemaker_block_time: Duration::from_secs(10), - missed_proposal_suspend_threshold: 2, + missed_proposal_suspend_threshold: 5, + missed_proposal_count_cap: 5, max_block_size: 500, fee_exhaust_divisor: 20, // 5% } diff --git a/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs b/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs index c689ed28f..9e17eb5c0 100644 --- a/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs +++ b/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs @@ -1752,7 +1752,7 @@ where TConsensusSpec: ConsensusSpec local_committee_info: &CommitteeInfo, ) -> Result, HotStuffError> { if block.is_dummy() { - block.increment_leader_failure_count(tx)?; + block.increment_leader_failure_count(tx, self.config.consensus_constants.missed_proposal_count_cap)?; // Nothing to do here for empty dummy blocks. Just mark the block as committed. block.commit_diff(tx, BlockDiff::empty(*block.id()))?; diff --git a/dan_layer/consensus_tests/src/support/harness.rs b/dan_layer/consensus_tests/src/support/harness.rs index ab97309eb..833619951 100644 --- a/dan_layer/consensus_tests/src/support/harness.rs +++ b/dan_layer/consensus_tests/src/support/harness.rs @@ -529,7 +529,8 @@ impl TestBuilder { max_base_layer_blocks_behind: 5, num_preshards: TEST_NUM_PRESHARDS, pacemaker_block_time: Duration::from_secs(10), - missed_proposal_suspend_threshold: 2, + missed_proposal_suspend_threshold: 5, + missed_proposal_count_cap: 5, max_block_size: 500, fee_exhaust_divisor: 20, }, diff --git a/dan_layer/storage/src/consensus_models/block.rs b/dan_layer/storage/src/consensus_models/block.rs index 42abe1fca..13cbbbe55 100644 --- a/dan_layer/storage/src/consensus_models/block.rs +++ b/dan_layer/storage/src/consensus_models/block.rs @@ -1108,13 +1108,14 @@ impl Block { pub fn increment_leader_failure_count( &self, tx: &mut TTx, + max_missed_proposal_cap: u64, ) -> Result<(), StorageError> { tx.validator_epoch_stats_updates( self.epoch(), iter::once( ValidatorStatsUpdate::new(self.proposed_by()) .add_missed_proposal() - .set_max_missed_proposals_cap(5), + .set_max_missed_proposals_cap(max_missed_proposal_cap), ), ) }