Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ZKS-02] Introduce committee lookback #2336

Merged
merged 5 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions ledger/block/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ impl<N: Network> Block<N> {
&self,
previous_block: &Block<N>,
current_state_root: N::StateRoot,
current_committee: &Committee<N>,
current_committee_lookback: &Committee<N>,
current_puzzle: &CoinbasePuzzle<N>,
current_epoch_challenge: &EpochChallenge<N>,
current_timestamp: i64,
Expand All @@ -46,7 +46,7 @@ impl<N: Network> Block<N> {
expected_timestamp,
expected_existing_solution_ids,
expected_existing_transaction_ids,
) = self.verify_authority(previous_block.round(), previous_block.height(), current_committee)?;
) = self.verify_authority(previous_block.round(), previous_block.height(), current_committee_lookback)?;

// Ensure the block solutions are correct.
let (
Expand Down Expand Up @@ -143,7 +143,7 @@ impl<N: Network> Block<N> {
&self,
previous_round: u64,
previous_height: u32,
current_committee: &Committee<N>,
current_committee_lookback: &Committee<N>,
) -> Result<(u64, u32, i64, Vec<PuzzleCommitment<N>>, Vec<N::TransactionID>)> {
// Note: Do not remove this. This ensures that all blocks after genesis are quorum blocks.
#[cfg(not(any(test, feature = "test")))]
Expand All @@ -170,12 +170,13 @@ impl<N: Network> Block<N> {
subdag.anchor_round()
}
};
// Ensure the block round is at least the starting round of the committee.
// Ensure the block round minus the committee lookback range is at least the starting round of the committee lookback.
ensure!(
expected_round >= current_committee.starting_round(),
"Block {} has an invalid round (found '{expected_round}', expected at least '{}')",
expected_height,
current_committee.starting_round()
expected_round.saturating_sub(Committee::<N>::COMMITTEE_LOOKBACK_RANGE)
>= current_committee_lookback.starting_round(),
"Block {expected_height} has an invalid round (found '{}', expected at least '{}')",
expected_round.saturating_sub(Committee::<N>::COMMITTEE_LOOKBACK_RANGE),
current_committee_lookback.starting_round()
);

// Ensure the block authority is correct.
Expand All @@ -186,7 +187,7 @@ impl<N: Network> Block<N> {
let signer = signature.to_address();
// Ensure the block is signed by a committee member.
ensure!(
current_committee.members().contains_key(&signer),
current_committee_lookback.members().contains_key(&signer),
"Beacon block {expected_height} has a signer not in the committee (found '{signer}')",
);
// Ensure the signature is valid.
Expand All @@ -199,7 +200,7 @@ impl<N: Network> Block<N> {
}
Authority::Quorum(subdag) => {
// Compute the expected leader.
let expected_leader = current_committee.get_leader(expected_round)?;
let expected_leader = current_committee_lookback.get_leader(expected_round)?;
// Ensure the block is authored by the expected leader.
ensure!(
subdag.leader_address() == expected_leader,
Expand All @@ -222,7 +223,7 @@ impl<N: Network> Block<N> {
// 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),
Authority::Quorum(subdag) => subdag.timestamp(current_committee_lookback),
};

// Return success.
Expand Down
2 changes: 2 additions & 0 deletions ledger/committee/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub struct Committee<N: Network> {
}

impl<N: Network> Committee<N> {
/// The committee lookback range.
pub const COMMITTEE_LOOKBACK_RANGE: u64 = BatchHeader::<N>::MAX_GC_ROUNDS as u64;
/// The maximum number of members that may be in a committee.
pub const MAX_COMMITTEE_SIZE: u16 = BatchHeader::<N>::MAX_CERTIFICATES;

Expand Down
15 changes: 14 additions & 1 deletion ledger/src/check_next_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,24 @@ impl<N: Network, C: ConsensusStorage<N>> Ledger<N, C> {
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 {
Copy link
Contributor Author

@raychu86 raychu86 Feb 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, we can just subtract 1, because block rounds are always even.

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::<N>::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}"))?;

// Ensure the block is correct.
let (expected_existing_solution_ids, expected_existing_transaction_ids) = block.verify(
&self.latest_block(),
self.latest_state_root(),
&self.latest_committee()?,
&committee_lookback,
self.coinbase_puzzle(),
&self.latest_epoch_challenge()?,
OffsetDateTime::now_utc().unix_timestamp(),
Expand Down