diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index 29bd8cb979..b7afba54df 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -30,6 +30,7 @@ impl Block { &self, previous_block: &Block, current_state_root: N::StateRoot, + previous_committee_lookback: &Committee, current_committee_lookback: &Committee, current_puzzle: &CoinbasePuzzle, current_epoch_challenge: &EpochChallenge, @@ -46,7 +47,12 @@ impl Block { expected_timestamp, expected_existing_solution_ids, expected_existing_transaction_ids, - ) = self.verify_authority(previous_block.round(), previous_block.height(), current_committee_lookback)?; + ) = self.verify_authority( + previous_block.round(), + previous_block.height(), + previous_committee_lookback, + current_committee_lookback, + )?; // Ensure the block solutions are correct. let ( @@ -143,6 +149,7 @@ impl Block { &self, previous_round: u64, previous_height: u32, + previous_committee_lookback: &Committee, current_committee_lookback: &Committee, ) -> Result<(u64, u32, i64, Vec>, Vec)> { // Note: Do not remove this. This ensures that all blocks after genesis are quorum blocks. @@ -223,7 +230,7 @@ impl Block { // Beacon blocks do not have a timestamp check. Authority::Beacon(..) => self.timestamp(), // Quorum blocks use the weighted median timestamp from the subdag. - Authority::Quorum(subdag) => subdag.timestamp(current_committee_lookback), + Authority::Quorum(subdag) => subdag.timestamp(previous_committee_lookback), }; // Return success. diff --git a/ledger/src/advance.rs b/ledger/src/advance.rs index 2c15ae0dc4..62a2775832 100644 --- a/ledger/src/advance.rs +++ b/ledger/src/advance.rs @@ -240,15 +240,25 @@ impl> Ledger { // Determine the timestamp for the next block. let next_timestamp = match subdag { Some(subdag) => { - // Get the committee lookback round. - let committee_lookback_round = - subdag.anchor_round().saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE); - // Retrieve the committee lookback. - let committee_lookback = self - .get_committee_for_round(committee_lookback_round)? - .ok_or(anyhow!("Failed to fetch committee for round {committee_lookback_round}"))?; + // Retrieve the previous committee lookback. + let previous_committee_lookback = { + // Calculate the penultimate round, which is the round before the anchor round. + let penultimate_round = subdag.anchor_round().saturating_sub(1); + // Get the round number for the previous committee. Note, we subtract 2 from odd rounds, + // because committees are updated in even rounds. + let previous_penultimate_round = match penultimate_round % 2 == 0 { + true => penultimate_round.saturating_sub(1), + false => penultimate_round.saturating_sub(2), + }; + // Get the previous committee lookback round. + let penultimate_committee_lookback_round = + previous_penultimate_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE); + // Output the previous committee lookback. + self.get_committee_for_round(penultimate_committee_lookback_round)? + .ok_or(anyhow!("Failed to fetch committee for round {penultimate_committee_lookback_round}"))? + }; // Return the timestamp for the given committee lookback. - subdag.timestamp(&committee_lookback) + subdag.timestamp(&previous_committee_lookback) } None => OffsetDateTime::now_utc().unix_timestamp(), }; diff --git a/ledger/src/check_next_block.rs b/ledger/src/check_next_block.rs index 3f282f660b..c23797f8d4 100644 --- a/ledger/src/check_next_block.rs +++ b/ledger/src/check_next_block.rs @@ -82,23 +82,44 @@ impl> Ledger { let ratified_finalize_operations = self.vm.check_speculate(state, block.ratifications(), block.solutions(), block.transactions())?; - // Get the round number for the previous committee. Note, we subtract 2 from odd rounds, - // because committees are updated in even rounds. - let previous_round = match block.round() % 2 == 0 { - true => block.round().saturating_sub(1), - false => block.round().saturating_sub(2), - }; - // Get the committee lookback round. - let committee_lookback_round = previous_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE); // Retrieve the committee lookback. - let committee_lookback = self - .get_committee_for_round(committee_lookback_round)? - .ok_or(anyhow!("Failed to fetch committee for round {committee_lookback_round}"))?; + let committee_lookback = { + // Determine the round number for the previous committee. Note, we subtract 2 from odd rounds, + // because committees are updated in even rounds. + let previous_round = match block.round() % 2 == 0 { + true => block.round().saturating_sub(1), + false => block.round().saturating_sub(2), + }; + // Determine the committee lookback round. + let committee_lookback_round = previous_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE); + // Output the committee lookback. + self.get_committee_for_round(committee_lookback_round)? + .ok_or(anyhow!("Failed to fetch committee for round {committee_lookback_round}"))? + }; + + // Retrieve the previous committee lookback. + let previous_committee_lookback = { + // Calculate the penultimate round, which is the round before the anchor round. + let penultimate_round = block.round().saturating_sub(1); + // Determine the round number for the previous committee. Note, we subtract 2 from odd rounds, + // because committees are updated in even rounds. + let previous_penultimate_round = match penultimate_round % 2 == 0 { + true => penultimate_round.saturating_sub(1), + false => penultimate_round.saturating_sub(2), + }; + // Determine the previous committee lookback round. + let penultimate_committee_lookback_round = + previous_penultimate_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE); + // Output the previous committee lookback. + self.get_committee_for_round(penultimate_committee_lookback_round)? + .ok_or(anyhow!("Failed to fetch committee for round {penultimate_committee_lookback_round}"))? + }; // Ensure the block is correct. let (expected_existing_solution_ids, expected_existing_transaction_ids) = block.verify( &self.latest_block(), self.latest_state_root(), + &previous_committee_lookback, &committee_lookback, self.coinbase_puzzle(), &self.latest_epoch_challenge()?,