From fdb39a71b061a4f99a5aa38e040fb087fa419f5b Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:11:11 -0800 Subject: [PATCH 1/8] Resolve merge --- console/network/src/lib.rs | 3 +++ ledger/block/src/verify.rs | 21 +++++++++++---------- ledger/src/check_next_block.rs | 6 +++++- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/console/network/src/lib.rs b/console/network/src/lib.rs index 717946cba2..cf5e33488e 100644 --- a/console/network/src/lib.rs +++ b/console/network/src/lib.rs @@ -156,6 +156,9 @@ pub trait Network: /// The maximum number of outputs per transition. const MAX_OUTPUTS: usize = 16; + /// The committee round lag. + const COMMITTEE_ROUND_LAG: u64 = 50; + /// The state root type. type StateRoot: Bech32ID>; /// The block hash type. diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index 1cb990077b..30d51de02f 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -30,7 +30,7 @@ impl Block { &self, previous_block: &Block, current_state_root: N::StateRoot, - current_committee: &Committee, + committee_with_lag: &Committee, current_puzzle: &CoinbasePuzzle, current_epoch_challenge: &EpochChallenge, current_timestamp: i64, @@ -41,7 +41,7 @@ impl Block { // Ensure the block authority is correct. let (expected_round, expected_height, expected_timestamp, expected_existing_transaction_ids) = - self.verify_authority(previous_block.round(), previous_block.height(), current_committee)?; + self.verify_authority(previous_block.round(), previous_block.height(), committee_with_lag)?; // Ensure the block solutions are correct. let ( @@ -138,8 +138,9 @@ impl Block { &self, previous_round: u64, previous_height: u32, - current_committee: &Committee, + committee_with_lag: &Committee, ) -> Result<(u64, u32, i64, Vec)> { + // Note: Do not remove this. This ensures that all blocks after genesis are quorum blocks. #[cfg(not(any(test, feature = "test")))] ensure!(self.authority.is_quorum(), "The next block must be a quorum block"); @@ -164,12 +165,12 @@ impl Block { subdag.anchor_round() } }; - // Ensure the block round is at least the starting round of the committee. + // Ensure the block round minus the committee round lag is at least the starting round of the committee with lag. 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(N::COMMITTEE_ROUND_LAG) >= committee_with_lag.starting_round(), + "Block {expected_height} has an invalid round (found '{}', expected at least '{}')", + expected_round.saturating_sub(N::COMMITTEE_ROUND_LAG), + committee_with_lag.starting_round() ); // Ensure the block authority is correct. @@ -180,7 +181,7 @@ impl Block { let signer = signature.to_address(); // Ensure the block is signed by a committee member. ensure!( - current_committee.members().contains_key(&signer), + committee_with_lag.members().contains_key(&signer), "Beacon block {expected_height} has a signer not in the committee (found '{signer}')", ); // Ensure the signature is valid. @@ -193,7 +194,7 @@ impl Block { } Authority::Quorum(subdag) => { // Compute the expected leader. - let expected_leader = current_committee.get_leader(expected_round)?; + let expected_leader = committee_with_lag.get_leader(expected_round)?; // Ensure the block is authored by the expected leader. ensure!( subdag.leader_address() == expected_leader, diff --git a/ledger/src/check_next_block.rs b/ledger/src/check_next_block.rs index 4ac3ed0355..ce20890bfb 100644 --- a/ledger/src/check_next_block.rs +++ b/ledger/src/check_next_block.rs @@ -85,10 +85,14 @@ impl> Ledger { self.vm.check_speculate(state, block.ratifications(), block.solutions(), block.transactions())?; // Ensure the block is correct. + let round_with_lag = self.latest_round().saturating_sub(N::COMMITTEE_ROUND_LAG); + let committee_with_lag = self + .get_committee_for_round(round_with_lag)? + .ok_or(anyhow!("Failed to fetch committee for round {round_with_lag}"))?; let expected_existing_transaction_ids = block.verify( &self.latest_block(), self.latest_state_root(), - &self.latest_committee()?, + &committee_with_lag, self.coinbase_puzzle(), &self.latest_epoch_challenge()?, OffsetDateTime::now_utc().unix_timestamp(), From b3db2946f2a299fedae997c458092536f7cfc1e5 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Wed, 7 Feb 2024 14:57:02 -0800 Subject: [PATCH 2/8] Update COMMITTEE_ROUND_LAG to match the MAX_GC_ROUNDS --- console/network/src/lib.rs | 2 +- ledger/narwhal/batch-header/src/lib.rs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/console/network/src/lib.rs b/console/network/src/lib.rs index cf5e33488e..a1ac9afac4 100644 --- a/console/network/src/lib.rs +++ b/console/network/src/lib.rs @@ -157,7 +157,7 @@ pub trait Network: const MAX_OUTPUTS: usize = 16; /// The committee round lag. - const COMMITTEE_ROUND_LAG: u64 = 50; + const COMMITTEE_ROUND_LAG: u64 = 100; /// The state root type. type StateRoot: Bech32ID>; diff --git a/ledger/narwhal/batch-header/src/lib.rs b/ledger/narwhal/batch-header/src/lib.rs index 473641b003..f18df43fe8 100644 --- a/ledger/narwhal/batch-header/src/lib.rs +++ b/ledger/narwhal/batch-header/src/lib.rs @@ -318,3 +318,19 @@ pub mod test_helpers { sample } } + +#[cfg(test)] +mod tests { + use super::*; + + type CurrentNetwork = console::network::Testnet3; + + #[test] + fn test_max_gc_rounds() { + assert_eq!( + BatchHeader::::MAX_GC_ROUNDS as u64, + ::COMMITTEE_ROUND_LAG, + "The max GC rounds should be equal to the committee round lag" + ); + } +} From 89d04bdf6d39e596da9374184f3ce1cdb3de3038 Mon Sep 17 00:00:00 2001 From: raychu86 <14917648+raychu86@users.noreply.github.com> Date: Wed, 7 Feb 2024 16:16:25 -0800 Subject: [PATCH 3/8] Resolve pick --- ledger/src/check_next_block.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/ledger/src/check_next_block.rs b/ledger/src/check_next_block.rs index ce20890bfb..55f982c9e5 100644 --- a/ledger/src/check_next_block.rs +++ b/ledger/src/check_next_block.rs @@ -84,15 +84,24 @@ 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 previous round with lag. + let previous_round_with_lag = previous_round.saturating_sub(N::COMMITTEE_ROUND_LAG); + // Retrieve the previous committee with lag. + let previous_committee_with_lag = self + .get_committee_for_round(previous_round_with_lag)? + .ok_or(anyhow!("Failed to fetch committee for round {previous_round_with_lag}"))?; + // Ensure the block is correct. - let round_with_lag = self.latest_round().saturating_sub(N::COMMITTEE_ROUND_LAG); - let committee_with_lag = self - .get_committee_for_round(round_with_lag)? - .ok_or(anyhow!("Failed to fetch committee for round {round_with_lag}"))?; let expected_existing_transaction_ids = block.verify( &self.latest_block(), self.latest_state_root(), - &committee_with_lag, + &previous_committee_with_lag, self.coinbase_puzzle(), &self.latest_epoch_challenge()?, OffsetDateTime::now_utc().unix_timestamp(), From b66d6c388e0b79f31d0721a1d718a7f21e8c8156 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:20:18 -0800 Subject: [PATCH 4/8] Resolve pick --- console/network/src/lib.rs | 4 ++-- ledger/block/src/verify.rs | 17 +++++++++-------- ledger/committee/src/lib.rs | 9 +++++++++ ledger/narwhal/batch-header/src/lib.rs | 16 ---------------- ledger/src/check_next_block.rs | 14 +++++++------- 5 files changed, 27 insertions(+), 33 deletions(-) diff --git a/console/network/src/lib.rs b/console/network/src/lib.rs index a1ac9afac4..c7e07e422d 100644 --- a/console/network/src/lib.rs +++ b/console/network/src/lib.rs @@ -156,8 +156,8 @@ pub trait Network: /// The maximum number of outputs per transition. const MAX_OUTPUTS: usize = 16; - /// The committee round lag. - const COMMITTEE_ROUND_LAG: u64 = 100; + /// The committee lookback range. + const COMMITTEE_LOOKBACK_RANGE: u64 = 100; /// The state root type. type StateRoot: Bech32ID>; diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index 30d51de02f..57c7007516 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -30,7 +30,7 @@ impl Block { &self, previous_block: &Block, current_state_root: N::StateRoot, - committee_with_lag: &Committee, + current_committee_lookback: &Committee, current_puzzle: &CoinbasePuzzle, current_epoch_challenge: &EpochChallenge, current_timestamp: i64, @@ -41,7 +41,7 @@ impl Block { // Ensure the block authority is correct. let (expected_round, expected_height, expected_timestamp, expected_existing_transaction_ids) = - self.verify_authority(previous_block.round(), previous_block.height(), committee_with_lag)?; + self.verify_authority(previous_block.round(), previous_block.height(), current_committee_lookback)?; // Ensure the block solutions are correct. let ( @@ -138,6 +138,7 @@ impl Block { &self, previous_round: u64, previous_height: u32, + current_committee_lookback: &Committee, committee_with_lag: &Committee, ) -> Result<(u64, u32, i64, Vec)> { // Note: Do not remove this. This ensures that all blocks after genesis are quorum blocks. @@ -165,12 +166,12 @@ impl Block { subdag.anchor_round() } }; - // Ensure the block round minus the committee round lag is at least the starting round of the committee with lag. + // Ensure the block round minus the committee lookback range is at least the starting round of the committee lookback. ensure!( - expected_round.saturating_sub(N::COMMITTEE_ROUND_LAG) >= committee_with_lag.starting_round(), + expected_round.saturating_sub(N::COMMITTEE_LOOKBACK_RANGE) >= current_committee_lookback.starting_round(), "Block {expected_height} has an invalid round (found '{}', expected at least '{}')", - expected_round.saturating_sub(N::COMMITTEE_ROUND_LAG), - committee_with_lag.starting_round() + expected_round.saturating_sub(N::COMMITTEE_LOOKBACK_RANGE), + current_committee_lookback.starting_round() ); // Ensure the block authority is correct. @@ -181,7 +182,7 @@ impl Block { let signer = signature.to_address(); // Ensure the block is signed by a committee member. ensure!( - committee_with_lag.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. @@ -194,7 +195,7 @@ impl Block { } Authority::Quorum(subdag) => { // Compute the expected leader. - let expected_leader = committee_with_lag.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, diff --git a/ledger/committee/src/lib.rs b/ledger/committee/src/lib.rs index 9ba7843dcd..691fa76dd0 100644 --- a/ledger/committee/src/lib.rs +++ b/ledger/committee/src/lib.rs @@ -417,4 +417,13 @@ mod tests { ledger_narwhal_batch_header::BatchHeader::::MAX_CERTIFICATES ); } + + #[test] + fn test_committee_lookback_range() { + assert_eq!( + BatchHeader::::MAX_GC_ROUNDS as u64, + ::COMMITTEE_LOOKBACK_RANGE, + "The max GC rounds should be equal to the committee lookback range" + ); + } } diff --git a/ledger/narwhal/batch-header/src/lib.rs b/ledger/narwhal/batch-header/src/lib.rs index f18df43fe8..473641b003 100644 --- a/ledger/narwhal/batch-header/src/lib.rs +++ b/ledger/narwhal/batch-header/src/lib.rs @@ -318,19 +318,3 @@ pub mod test_helpers { sample } } - -#[cfg(test)] -mod tests { - use super::*; - - type CurrentNetwork = console::network::Testnet3; - - #[test] - fn test_max_gc_rounds() { - assert_eq!( - BatchHeader::::MAX_GC_ROUNDS as u64, - ::COMMITTEE_ROUND_LAG, - "The max GC rounds should be equal to the committee round lag" - ); - } -} diff --git a/ledger/src/check_next_block.rs b/ledger/src/check_next_block.rs index 55f982c9e5..c32e715032 100644 --- a/ledger/src/check_next_block.rs +++ b/ledger/src/check_next_block.rs @@ -90,18 +90,18 @@ impl> Ledger { true => block.round().saturating_sub(1), false => block.round().saturating_sub(2), }; - // Get the previous round with lag. - let previous_round_with_lag = previous_round.saturating_sub(N::COMMITTEE_ROUND_LAG); - // Retrieve the previous committee with lag. - let previous_committee_with_lag = self - .get_committee_for_round(previous_round_with_lag)? - .ok_or(anyhow!("Failed to fetch committee for round {previous_round_with_lag}"))?; + // Get the committee lookback round. + let committee_lookback_round = previous_round.saturating_sub(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_transaction_ids = block.verify( &self.latest_block(), self.latest_state_root(), - &previous_committee_with_lag, + &committee_lookback, self.coinbase_puzzle(), &self.latest_epoch_challenge()?, OffsetDateTime::now_utc().unix_timestamp(), From 43ab0d4e8354a3d161b801e4c5a5d197bcbc6601 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:23:30 -0800 Subject: [PATCH 5/8] Update constant usage --- console/network/src/lib.rs | 3 --- ledger/block/src/verify.rs | 5 +++-- ledger/committee/src/lib.rs | 11 ++--------- ledger/src/check_next_block.rs | 2 +- 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/console/network/src/lib.rs b/console/network/src/lib.rs index c7e07e422d..717946cba2 100644 --- a/console/network/src/lib.rs +++ b/console/network/src/lib.rs @@ -156,9 +156,6 @@ pub trait Network: /// The maximum number of outputs per transition. const MAX_OUTPUTS: usize = 16; - /// The committee lookback range. - const COMMITTEE_LOOKBACK_RANGE: u64 = 100; - /// The state root type. type StateRoot: Bech32ID>; /// The block hash type. diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index 57c7007516..82115e6643 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -168,9 +168,10 @@ impl Block { }; // Ensure the block round minus the committee lookback range is at least the starting round of the committee lookback. ensure!( - expected_round.saturating_sub(N::COMMITTEE_LOOKBACK_RANGE) >= current_committee_lookback.starting_round(), + expected_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE) + >= current_committee_lookback.starting_round(), "Block {expected_height} has an invalid round (found '{}', expected at least '{}')", - expected_round.saturating_sub(N::COMMITTEE_LOOKBACK_RANGE), + expected_round.saturating_sub(Committee::::COMMITTEE_LOOKBACK_RANGE), current_committee_lookback.starting_round() ); diff --git a/ledger/committee/src/lib.rs b/ledger/committee/src/lib.rs index 691fa76dd0..4cc1bee59c 100644 --- a/ledger/committee/src/lib.rs +++ b/ledger/committee/src/lib.rs @@ -47,6 +47,8 @@ pub struct Committee { } impl Committee { + /// The committee lookback range. + pub const COMMITTEE_LOOKBACK_RANGE: u64 = BatchHeader::::MAX_GC_ROUNDS as u64; /// The maximum number of members that may be in a committee. pub const MAX_COMMITTEE_SIZE: u16 = 200; @@ -417,13 +419,4 @@ mod tests { ledger_narwhal_batch_header::BatchHeader::::MAX_CERTIFICATES ); } - - #[test] - fn test_committee_lookback_range() { - assert_eq!( - BatchHeader::::MAX_GC_ROUNDS as u64, - ::COMMITTEE_LOOKBACK_RANGE, - "The max GC rounds should be equal to the committee lookback range" - ); - } } diff --git a/ledger/src/check_next_block.rs b/ledger/src/check_next_block.rs index c32e715032..53a1817c53 100644 --- a/ledger/src/check_next_block.rs +++ b/ledger/src/check_next_block.rs @@ -91,7 +91,7 @@ impl> Ledger { false => block.round().saturating_sub(2), }; // Get the committee lookback round. - let committee_lookback_round = previous_round.saturating_sub(N::COMMITTEE_LOOKBACK_RANGE); + 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)? From 81d7c11f3d51d31ceb0628ae81cc8c2ad00a3287 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Sat, 10 Feb 2024 17:01:32 -0800 Subject: [PATCH 6/8] Update for compatibility --- ledger/block/src/verify.rs | 1 - ledger/committee/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index 82115e6643..ef9c5e62d4 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -139,7 +139,6 @@ impl Block { previous_round: u64, previous_height: u32, current_committee_lookback: &Committee, - committee_with_lag: &Committee, ) -> Result<(u64, u32, i64, Vec)> { // Note: Do not remove this. This ensures that all blocks after genesis are quorum blocks. #[cfg(not(any(test, feature = "test")))] diff --git a/ledger/committee/src/lib.rs b/ledger/committee/src/lib.rs index 4cc1bee59c..a933632d89 100644 --- a/ledger/committee/src/lib.rs +++ b/ledger/committee/src/lib.rs @@ -48,7 +48,7 @@ pub struct Committee { impl Committee { /// The committee lookback range. - pub const COMMITTEE_LOOKBACK_RANGE: u64 = BatchHeader::::MAX_GC_ROUNDS as u64; + pub const COMMITTEE_LOOKBACK_RANGE: u64 = 50; /// The maximum number of members that may be in a committee. pub const MAX_COMMITTEE_SIZE: u16 = 200; From 0f33c8e842fc44113f4b6da1393181fbd314dad8 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Sat, 10 Feb 2024 19:13:21 -0800 Subject: [PATCH 7/8] Add conditional on aborted --- ledger/block/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ledger/block/src/lib.rs b/ledger/block/src/lib.rs index fd9dae34ce..e0212e70b3 100644 --- a/ledger/block/src/lib.rs +++ b/ledger/block/src/lib.rs @@ -126,7 +126,10 @@ impl Block { aborted_transaction_ids: Vec, ) -> Result { // Ensure the block contains transactions. - ensure!(!transactions.is_empty(), "Cannot create a block with zero transactions"); + ensure!( + !transactions.is_empty() || !aborted_transaction_ids.is_empty(), + "Cannot create a block with zero transactions" + ); // Ensure the number of transactions is within the allowed range. if transactions.len() > Transactions::::MAX_TRANSACTIONS { From 94d113519b90441172d4caab022b622535b3bb3a Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Sat, 10 Feb 2024 22:25:28 -0800 Subject: [PATCH 8/8] Resolve merge for testnet3 --- ledger/block/src/lib.rs | 6 ------ ledger/block/src/verify.rs | 3 --- 2 files changed, 9 deletions(-) diff --git a/ledger/block/src/lib.rs b/ledger/block/src/lib.rs index e0212e70b3..7cbadc0885 100644 --- a/ledger/block/src/lib.rs +++ b/ledger/block/src/lib.rs @@ -125,12 +125,6 @@ impl Block { transactions: Transactions, aborted_transaction_ids: Vec, ) -> Result { - // Ensure the block contains transactions. - ensure!( - !transactions.is_empty() || !aborted_transaction_ids.is_empty(), - "Cannot create a block with zero transactions" - ); - // Ensure the number of transactions is within the allowed range. if transactions.len() > Transactions::::MAX_TRANSACTIONS { bail!( diff --git a/ledger/block/src/verify.rs b/ledger/block/src/verify.rs index ef9c5e62d4..40d681efa9 100644 --- a/ledger/block/src/verify.rs +++ b/ledger/block/src/verify.rs @@ -389,9 +389,6 @@ impl Block { fn verify_transactions(&self) -> Result<()> { let height = self.height(); - // Ensure there are transactions. - ensure!(!self.transactions.is_empty(), "Block {height} must contain at least 1 transaction"); - // Ensure the number of transactions is within the allowed range. if self.transactions.len() > Transactions::::MAX_TRANSACTIONS { bail!(