diff --git a/crates/sui-benchmark/src/benchmark/validator_preparer.rs b/crates/sui-benchmark/src/benchmark/validator_preparer.rs index a20d4e1ba9b3d..72d4dbd8416d3 100644 --- a/crates/sui-benchmark/src/benchmark/validator_preparer.rs +++ b/crates/sui-benchmark/src/benchmark/validator_preparer.rs @@ -278,12 +278,14 @@ fn make_authority_state( // manually. // opts.set_manual_wal_flush(true); - let store = Arc::new(AuthorityStore::open(&path.join("store"), Some(opts))); - let epoch_store = Arc::new(EpochStore::new(path.join("epochs"))); + let store = Arc::new(AuthorityStore::open( + &path.join("store"), + Some(opts.clone()), + )); + let epoch_store = Arc::new(EpochStore::new(path.join("epochs"), committee, Some(opts))); ( Runtime::new().unwrap().block_on(async { AuthorityState::new( - committee.clone(), *pubx, Arc::pin(secx), store.clone(), diff --git a/crates/sui-benchmark/src/bin/stress.rs b/crates/sui-benchmark/src/bin/stress.rs index 2fde013d5eb40..558def67802c5 100644 --- a/crates/sui-benchmark/src/bin/stress.rs +++ b/crates/sui-benchmark/src/bin/stress.rs @@ -43,6 +43,7 @@ use sui_benchmark::workloads::workload::CombinationWorkload; use sui_benchmark::workloads::workload::Payload; use sui_benchmark::workloads::workload::Workload; use sui_core::authority_client::NetworkAuthorityClient; +use sui_core::epoch::epoch_store::EpochStore; use sui_quorum_driver::QuorumDriverHandler; use sui_sdk::crypto::FileBasedKeystore; use sui_types::crypto::EncodeDecodeBase64; @@ -118,7 +119,7 @@ struct Opts { pub client_metric_port: u16, /// Number of followers to run. This also stresses the follower logic in validators #[clap(long, default_value = "0", global = true)] - pub num_folowers: u64, + pub num_followers: u64, /// Whether or no to download TXes during follow #[clap(long, global = true)] pub download_txes: bool, @@ -131,7 +132,7 @@ pub enum OptWorkloadSpec { // Allow the ability to mix shared object and // single owner transactions in the benchmarking // framework. Currently, only shared counter - // and transfer obejct transaction types are + // and transfer object transaction types are // supported but there will be more in future. Also // there is no dependency between individual // transactions such that they can all be executed @@ -559,7 +560,7 @@ async fn main() -> Result<()> { let mut follower_handles = vec![]; // Start the followers if any - for idx in 0..opts.num_folowers { + for idx in 0..opts.num_followers { // Kick off a task which follows all authorities and discards the data for (name, auth_client) in auth_clients.clone() { follower_handles.push(tokio::task::spawn(async move { @@ -599,8 +600,10 @@ async fn main() -> Result<()> { let committee = GatewayState::make_committee(&config)?; let authority_clients = GatewayState::make_authority_clients(&config); let registry = prometheus::Registry::new(); + let epoch_store = Arc::new(EpochStore::new_for_testing(&committee)); let aggregator = AuthorityAggregator::new( committee, + epoch_store, authority_clients, AuthAggMetrics::new(®istry), SafeClientMetrics::new(®istry), @@ -658,8 +661,10 @@ async fn main() -> Result<()> { .parse() .unwrap(), ); + let epoch_store = Arc::new(EpochStore::new_for_testing(&committee)); let aggregator = AuthorityAggregator::new( committee, + epoch_store, authority_clients, AuthAggMetrics::new(®istry), SafeClientMetrics::new(®istry), diff --git a/crates/sui-core/src/authority.rs b/crates/sui-core/src/authority.rs index b7d83b40b8c29..0fa32d8d581fe 100644 --- a/crates/sui-core/src/authority.rs +++ b/crates/sui-core/src/authority.rs @@ -306,7 +306,7 @@ pub struct AuthorityState { /// The checkpoint store pub checkpoints: Option>>, - pub(crate) epoch_store: Arc, + epoch_store: Arc, // Structures needed for handling batching and notifications. /// The sender to notify of new transactions @@ -346,6 +346,10 @@ impl AuthorityState { self.committee.load().epoch } + pub fn epoch_store(&self) -> &Arc { + &self.epoch_store + } + async fn handle_transaction_impl( &self, transaction: Transaction, @@ -1017,7 +1021,6 @@ impl AuthorityState { // TODO: This function takes both committee and genesis as parameter. // Technically genesis already contains committee information. Could consider merging them. pub async fn new( - genesis_committee: Committee, name: AuthorityName, secret: StableSyncAuthoritySigner, store: Arc, @@ -1046,18 +1049,11 @@ impl AuthorityState { .expect("Cannot bulk insert genesis objects"); } - let committee = if epoch_store.database_is_empty() { - epoch_store - .init_genesis_epoch(genesis_committee.clone()) - .expect("Init genesis epoch data must not fail"); - genesis_committee - } else { - epoch_store - .get_latest_authenticated_epoch() - .epoch_info() - .committee() - .clone() - }; + let committee = epoch_store + .get_latest_authenticated_epoch() + .epoch_info() + .committee() + .clone(); let event_handler = event_store.map(|es| Arc::new(EventHandler::new(store.clone(), es))); @@ -1134,6 +1130,7 @@ impl AuthorityState { state } + // TODO: Technically genesis_committee can be derived from genesis. pub async fn new_for_testing( genesis_committee: Committee, key: &AuthorityKeyPair, @@ -1172,10 +1169,13 @@ impl AuthorityState { .expect("No issues"); } - let epochs = Arc::new(EpochStore::new(path.join("epochs"))); + let epochs = Arc::new(EpochStore::new( + path.join("epochs"), + &genesis_committee, + None, + )); AuthorityState::new( - genesis_committee.clone(), secret.public().into(), secret.clone(), store, diff --git a/crates/sui-core/src/authority_active/gossip/configurable_batch_action_client.rs b/crates/sui-core/src/authority_active/gossip/configurable_batch_action_client.rs index 5181730252be0..803d821eac866 100644 --- a/crates/sui-core/src/authority_active/gossip/configurable_batch_action_client.rs +++ b/crates/sui-core/src/authority_active/gossip/configurable_batch_action_client.rs @@ -6,6 +6,7 @@ use crate::authority::AuthorityState; use crate::authority_aggregator::authority_aggregator_tests::*; use crate::authority_aggregator::{AuthAggMetrics, AuthorityAggregator}; use crate::authority_client::{AuthorityAPI, BatchInfoResponseItemStream}; +use crate::epoch::epoch_store::EpochStore; use crate::safe_client::SafeClient; use async_trait::async_trait; use std::borrow::Borrow; @@ -238,9 +239,10 @@ pub async fn init_configurable_authorities( } states.push(client.state.clone()); names.push(authority_name); + let epoch_store = client.state.epoch_store().clone(); clients.push(SafeClient::new( client, - committee.clone(), + epoch_store, authority_name, SafeClientMetrics::new_for_tests(), )); @@ -319,8 +321,10 @@ pub async fn init_configurable_authorities( .into_iter() .map(|(name, client)| (name, client.authority_client().clone())) .collect(); + let epoch_store = Arc::new(EpochStore::new_for_testing(&committee)); let net = AuthorityAggregator::new( committee, + epoch_store, authority_clients, AuthAggMetrics::new_for_tests(), SafeClientMetrics::new_for_tests(), diff --git a/crates/sui-core/src/authority_aggregator.rs b/crates/sui-core/src/authority_aggregator.rs index dce6242d9c329..d1756f18b4986 100644 --- a/crates/sui-core/src/authority_aggregator.rs +++ b/crates/sui-core/src/authority_aggregator.rs @@ -27,11 +27,13 @@ use prometheus::{ }; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::string::ToString; +use std::sync::Arc; use std::time::Duration; use sui_types::committee::StakeUnit; use tokio::sync::mpsc::Receiver; use tokio::time::{sleep, timeout}; +use crate::epoch::epoch_store::EpochStore; use sui_types::messages_checkpoint::CheckpointSequenceNumber; use tap::TapFallible; @@ -157,12 +159,14 @@ pub struct AuthorityAggregator { impl AuthorityAggregator { pub fn new( committee: Committee, + epoch_store: Arc, authority_clients: BTreeMap, metrics: AuthAggMetrics, safe_client_metrics: SafeClientMetrics, ) -> Self { Self::new_with_timeouts( committee, + epoch_store, authority_clients, metrics, safe_client_metrics, @@ -172,19 +176,25 @@ impl AuthorityAggregator { pub fn new_with_timeouts( committee: Committee, + epoch_store: Arc, authority_clients: BTreeMap, metrics: AuthAggMetrics, safe_client_metrics: SafeClientMetrics, timeouts: TimeoutConfig, ) -> Self { Self { - committee: committee.clone(), + committee, authority_clients: authority_clients .into_iter() .map(|(name, api)| { ( name, - SafeClient::new(api, committee.clone(), name, safe_client_metrics.clone()), + SafeClient::new( + api, + epoch_store.clone(), + name, + safe_client_metrics.clone(), + ), ) }) .collect(), diff --git a/crates/sui-core/src/checkpoints/tests/checkpoint_tests.rs b/crates/sui-core/src/checkpoints/tests/checkpoint_tests.rs index af206960778fa..0a656507df8b8 100644 --- a/crates/sui-core/src/checkpoints/tests/checkpoint_tests.rs +++ b/crates/sui-core/src/checkpoints/tests/checkpoint_tests.rs @@ -27,6 +27,7 @@ use sui_types::{ }; use crate::authority_aggregator::AuthAggMetrics; +use crate::epoch::epoch_store::EpochStore; use parking_lot::Mutex; pub struct TestCausalOrderPendCertNoop; @@ -1668,6 +1669,7 @@ pub async fn checkpoint_tests_setup( // Now make an authority aggregator let aggregator = AuthorityAggregator::new( committee.clone(), + Arc::new(EpochStore::new_for_testing(&committee)), authorities .iter() .map(|a| { diff --git a/crates/sui-core/src/epoch/epoch_store.rs b/crates/sui-core/src/epoch/epoch_store.rs index 4ebb1c287eb38..aefcc4ce19ba8 100644 --- a/crates/sui-core/src/epoch/epoch_store.rs +++ b/crates/sui-core/src/epoch/epoch_store.rs @@ -1,7 +1,9 @@ // Copyright (c) 2022, Mysten Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +use rocksdb::Options; use std::path::PathBuf; +use sui_types::base_types::ObjectID; use sui_types::committee::{Committee, EpochId}; use sui_types::error::SuiResult; use sui_types::messages::{AuthenticatedEpoch, GenesisEpoch}; @@ -19,12 +21,21 @@ pub struct EpochStore { } impl EpochStore { - pub fn new(path: PathBuf) -> Self { - Self::open_tables_read_write(path, None) + pub fn new(path: PathBuf, genesis_committee: &Committee, db_options: Option) -> Self { + let epoch_store = Self::open_tables_read_write(path, db_options); + if epoch_store.database_is_empty() { + epoch_store + .init_genesis_epoch(genesis_committee.clone()) + .expect("Init genesis epoch data must not fail"); + } + epoch_store } - pub fn database_is_empty(&self) -> bool { - self.epochs.iter().next().is_none() + pub fn new_for_testing(genesis_committee: &Committee) -> Self { + let dir = std::env::temp_dir(); + let path = dir.join(format!("DB_{:?}", ObjectID::random())); + std::fs::create_dir(&path).unwrap(); + Self::new(path, genesis_committee, None) } pub fn init_genesis_epoch(&self, genesis_committee: Committee) -> SuiResult { @@ -51,4 +62,8 @@ impl EpochStore { .unwrap() .1 } + + fn database_is_empty(&self) -> bool { + self.epochs.iter().next().is_none() + } } diff --git a/crates/sui-core/src/epoch/reconfiguration.rs b/crates/sui-core/src/epoch/reconfiguration.rs index ff5e638a6e17d..d0c030c812e19 100644 --- a/crates/sui-core/src/epoch/reconfiguration.rs +++ b/crates/sui-core/src/epoch/reconfiguration.rs @@ -134,18 +134,20 @@ where } // Reconnect the network if we have an type of AuthorityClient that has a network. - if A::needs_network_recreation() { - self.recreate_network(sui_system_state, new_committee)?; + let new_clients = if A::needs_network_recreation() { + self.recreate_network(sui_system_state)? } else { - // update the authorities with the new committee - let new_net = Arc::new(AuthorityAggregator::new( - new_committee, - self.net.load().clone_inner_clients(), - self.net.load().metrics.clone(), - self.net.load().safe_client_metrics.clone(), - )); - self.net.store(new_net); - } + self.net.load().clone_inner_clients() + }; + // Replace the clients in the authority aggregator with new clients. + let new_net = Arc::new(AuthorityAggregator::new( + new_committee, + self.state.epoch_store().clone(), + new_clients, + self.net.load().metrics.clone(), + self.net.load().safe_client_metrics.clone(), + )); + self.net.store(new_net); // TODO: Update all committee in all components safely, // potentially restart narwhal committee/consensus adapter, @@ -207,8 +209,7 @@ where pub fn recreate_network( &self, sui_system_state: SuiSystemState, - new_committee: Committee, - ) -> SuiResult { + ) -> SuiResult> { let mut new_clients = BTreeMap::new(); let next_epoch_validators = sui_system_state.validators.next_epoch_validators; @@ -266,16 +267,7 @@ where ); new_clients.insert(public_key_bytes, client); } - - // Replace the clients in the authority aggregator with new clients. - let new_net = Arc::new(AuthorityAggregator::new( - new_committee, - new_clients, - self.net.load().metrics.clone(), - self.net.load().safe_client_metrics.clone(), - )); - self.net.store(new_net); - Ok(()) + Ok(new_clients) } async fn wait_for_epoch_cert( diff --git a/crates/sui-core/src/epoch/tests/reconfiguration_tests.rs b/crates/sui-core/src/epoch/tests/reconfiguration_tests.rs index d5a76b0cf795f..afb7f293696c8 100644 --- a/crates/sui-core/src/epoch/tests/reconfiguration_tests.rs +++ b/crates/sui-core/src/epoch/tests/reconfiguration_tests.rs @@ -42,7 +42,7 @@ async fn test_start_epoch_change() { let state = states[0].clone(); // Check that we initialized the genesis epoch. - let init_epoch = state.epoch_store.get_latest_authenticated_epoch(); + let init_epoch = state.epoch_store().get_latest_authenticated_epoch(); assert!(matches!(init_epoch, AuthenticatedEpoch::Genesis(..))); assert_eq!(init_epoch.epoch(), 0); @@ -220,7 +220,7 @@ async fn test_finish_epoch_change() { for active in actives { assert_eq!(active.state.epoch(), 1); assert_eq!(active.net.load().committee.epoch, 1); - let latest_epoch = active.state.epoch_store.get_latest_authenticated_epoch(); + let latest_epoch = active.state.epoch_store().get_latest_authenticated_epoch(); assert_eq!(latest_epoch.epoch(), 1); assert!(matches!(latest_epoch, AuthenticatedEpoch::Certified(..))); assert_eq!(latest_epoch.epoch_info().epoch(), 1); diff --git a/crates/sui-core/src/gateway_state.rs b/crates/sui-core/src/gateway_state.rs index 7c54c8a06c250..bef6cf350f7ba 100644 --- a/crates/sui-core/src/gateway_state.rs +++ b/crates/sui-core/src/gateway_state.rs @@ -57,6 +57,7 @@ use sui_json_rpc_types::{ }; use sui_types::error::SuiError::ConflictingTransaction; +use crate::epoch::epoch_store::EpochStore; use tap::TapFallible; #[cfg(test)] @@ -176,7 +177,7 @@ pub struct GatewayState { impl GatewayState { /// Create a new manager which stores its managed addresses at `path` pub fn new( - path: &Path, + base_path: &Path, committee: Committee, authority_clients: BTreeMap, prometheus_registry: &Registry, @@ -184,10 +185,13 @@ impl GatewayState { let gateway_metrics = GatewayMetrics::new(prometheus_registry); let auth_agg_metrics = AuthAggMetrics::new(prometheus_registry); let safe_client_metrics = SafeClientMetrics::new(&prometheus::Registry::new()); + let gateway_store = Arc::new(GatewayStore::open(&base_path.join("store"), None)); + let epoch_store = Arc::new(EpochStore::new(base_path.join("epochs"), &committee, None)); Self::new_with_authorities( - path, + gateway_store, AuthorityAggregator::new( committee, + epoch_store, authority_clients, auth_agg_metrics, safe_client_metrics, @@ -197,18 +201,17 @@ impl GatewayState { } pub fn new_with_authorities( - path: &Path, + gateway_store: Arc, authorities: AuthorityAggregator, metrics: GatewayMetrics, ) -> SuiResult { - let store = Arc::new(GatewayStore::open(path, None)); - let next_tx_seq_number = AtomicU64::new(store.next_sequence_number()?); + let next_tx_seq_number = AtomicU64::new(gateway_store.next_sequence_number()?); Ok(Self { - store: store.clone(), + store: gateway_store.clone(), authorities, next_tx_seq_number, metrics, - module_cache: SyncModuleCache::new(ResolverWrapper(store)), + module_cache: SyncModuleCache::new(ResolverWrapper(gateway_store)), }) } diff --git a/crates/sui-core/src/safe_client.rs b/crates/sui-core/src/safe_client.rs index 90ce817d080fa..de21dd5c70689 100644 --- a/crates/sui-core/src/safe_client.rs +++ b/crates/sui-core/src/safe_client.rs @@ -3,12 +3,14 @@ // SPDX-License-Identifier: Apache-2.0 use crate::authority_client::{AuthorityAPI, BatchInfoResponseItemStream}; +use crate::epoch::epoch_store::EpochStore; use futures::StreamExt; use prometheus::core::{GenericCounter, GenericGauge}; use prometheus::{ register_int_counter_vec_with_registry, register_int_gauge_vec_with_registry, IntCounterVec, IntGaugeVec, }; +use std::sync::Arc; use sui_types::batch::{AuthorityBatch, SignedBatch, TxSequenceNumber, UpdateItem}; use sui_types::crypto::AuthorityPublicKeyBytes; use sui_types::messages_checkpoint::{ @@ -77,7 +79,7 @@ impl SafeClientMetrics { #[derive(Clone)] pub struct SafeClient { authority_client: C, - committee: Committee, + epoch_store: Arc, address: AuthorityPublicKeyBytes, metrics_total_requests_handle_transaction_and_effects_info_request: @@ -101,7 +103,7 @@ pub struct SafeClient { impl SafeClient { pub fn new( authority_client: C, - committee: Committee, + epoch_store: Arc, address: AuthorityPublicKeyBytes, safe_client_metrics: SafeClientMetrics, ) -> Self { @@ -145,7 +147,7 @@ impl SafeClient { Self { authority_client, - committee, + epoch_store, address, metrics_total_requests_handle_transaction_and_effects_info_request, @@ -170,6 +172,16 @@ impl SafeClient { &mut self.authority_client } + fn get_committee(&self, epoch_id: &EpochId) -> SuiResult { + match self.epoch_store.get_authenticated_epoch(epoch_id)? { + Some(epoch_info) => Ok(epoch_info.into_epoch_info().into_committee()), + None => Err(SuiError::InvalidAuthenticatedEpoch(format!( + "Epoch info not found in the store for epoch {:?}", + epoch_id + ))), + } + } + // Here we centralize all checks for transaction info responses fn check_transaction_response( &self, @@ -177,9 +189,11 @@ impl SafeClient { effects_digest: Option<&TransactionEffectsDigest>, response: &TransactionInfoResponse, ) -> SuiResult { + let mut committee = None; if let Some(signed_transaction) = &response.signed_transaction { + committee = Some(self.get_committee(&signed_transaction.auth_sign_info.epoch)?); // Check the transaction signature - signed_transaction.verify(&self.committee)?; + signed_transaction.verify(committee.as_ref().unwrap())?; // Check it has the right signer fp_ensure!( signed_transaction.auth_sign_info.authority == self.address, @@ -199,8 +213,11 @@ impl SafeClient { } if let Some(certificate) = &response.certified_transaction { + if committee.is_none() { + committee = Some(self.get_committee(&certificate.auth_sign_info.epoch)?); + } // Check signatures and quorum - certificate.verify(&self.committee)?; + certificate.verify(committee.as_ref().unwrap())?; // Check it's the right transaction fp_ensure!( certificate.digest() == digest, @@ -212,8 +229,11 @@ impl SafeClient { } if let Some(signed_effects) = &response.signed_effects { + if committee.is_none() { + committee = Some(self.get_committee(&signed_effects.auth_signature.epoch)?); + } // Check signature - signed_effects.verify(&self.committee)?; + signed_effects.verify(committee.as_ref().unwrap())?; // Check it has the right signer fp_ensure!( signed_effects.auth_signature.authority == self.address, @@ -253,7 +273,7 @@ impl SafeClient { ) -> SuiResult { // If we get a certificate make sure it is a valid certificate if let Some(certificate) = &response.parent_certificate { - certificate.verify(&self.committee)?; + certificate.verify(&self.get_committee(&certificate.auth_sign_info.epoch)?)?; } // Check the right object ID and version is returned @@ -318,7 +338,10 @@ impl SafeClient { }; if let Some(signed_transaction) = &object_and_lock.lock { - signed_transaction.verify(&self.committee)?; + // We cannot reuse the committee fetched above since they may not be from the same + // epoch. + signed_transaction + .verify(&self.get_committee(&signed_transaction.auth_sign_info.epoch)?)?; // Check it has the right signer fp_ensure!( signed_transaction.auth_sign_info.authority == self.address, @@ -344,7 +367,7 @@ impl SafeClient { )>, ) -> SuiResult { // check the signature of the batch - signed_batch.verify(&self.committee)?; + signed_batch.verify(&self.get_committee(&signed_batch.auth_sig().epoch)?)?; // ensure transactions enclosed match requested range @@ -562,9 +585,6 @@ where request: &CheckpointRequest, response: &CheckpointResponse, ) -> SuiResult { - // Verify signatures - response.verify(&self.committee)?; - // Verify response data was correct for request match &request.request_type { CheckpointRequestType::AuthenticatedCheckpoint(seq) => { @@ -572,7 +592,15 @@ where { // Checks that the sequence number is correct. self.verify_checkpoint_sequence(*seq, checkpoint)?; - self.verify_contents_exist(request.detail, checkpoint, &response.detail) + self.verify_contents_exist(request.detail, checkpoint, &response.detail)?; + // Verify signature. + match checkpoint { + Some(c) => { + let epoch_id = c.summary().epoch; + c.verify(&self.get_committee(&epoch_id)?, response.detail.as_ref()) + } + None => Ok(()), + } } else { Err(SuiError::from( "Invalid AuthorityCheckpointInfo type in the response", @@ -582,9 +610,25 @@ where CheckpointRequestType::CheckpointProposal => { if let AuthorityCheckpointInfo::CheckpointProposal { proposal, - prev_cert: _, + prev_cert, } = &response.info { + // Verify signature. + if let Some(signed_proposal) = proposal { + let committee = + self.get_committee(&signed_proposal.auth_signature.epoch)?; + signed_proposal.verify(&committee, response.detail.as_ref())?; + if signed_proposal.summary.sequence_number > 0 { + let cert = prev_cert.as_ref().ok_or_else(|| { + SuiError::from("No checkpoint cert provided along with proposal") + })?; + cert.verify(&committee, None)?; + fp_ensure!( + signed_proposal.summary.sequence_number - 1 == cert.summary.sequence_number, + SuiError::from("Checkpoint proposal sequence number inconsistent with previous cert") + ); + } + } self.verify_contents_exist(request.detail, proposal, &response.detail) } else { Err(SuiError::from( @@ -704,17 +748,12 @@ where ); Ok(()) } - (_, Some(AuthenticatedEpoch::Genesis(_))) => { - // TODO: Verify the epoch data using genesis committee - Ok(()) + (_, Some(AuthenticatedEpoch::Genesis(g))) => g.verify(&self.get_committee(&0)?), + (_, Some(AuthenticatedEpoch::Signed(s))) => { + s.verify(&self.get_committee(&s.auth_sign_info.epoch)?) } - (_, Some(AuthenticatedEpoch::Signed(_))) => { - // TODO: Verify the epoch data using previous committee - Ok(()) - } - (_, Some(AuthenticatedEpoch::Certified(_))) => { - // TODO: Verify the epoch data using previous committee - Ok(()) + (_, Some(AuthenticatedEpoch::Certified(c))) => { + c.verify(&self.get_committee(&c.auth_sign_info.epoch)?) } } } diff --git a/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs b/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs index ef1de7d312494..cf47560f0ffbf 100644 --- a/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs +++ b/crates/sui-core/src/unit_tests/authority_aggregator_tests.rs @@ -85,9 +85,11 @@ pub async fn init_local_authorities_with_genesis( serial_authority_request_timeout: Duration::from_secs(1), serial_authority_request_interval: Duration::from_secs(1), }; + let epoch_store = Arc::new(EpochStore::new_for_testing(&committee)); ( AuthorityAggregator::new_with_timeouts( committee, + epoch_store, clients, AuthAggMetrics::new_for_tests(), SafeClientMetrics::new_for_tests(), @@ -983,9 +985,11 @@ async fn test_quorum_once_with_timeout() { } let committee = Committee::new(0, authorities).unwrap(); + let epoch_store = Arc::new(EpochStore::new_for_testing(&committee)); let agg = AuthorityAggregator::new_with_timeouts( committee, + epoch_store, clients, AuthAggMetrics::new_for_tests(), SafeClientMetrics::new_for_tests(), diff --git a/crates/sui-core/src/unit_tests/batch_tests.rs b/crates/sui-core/src/unit_tests/batch_tests.rs index 16ac7c7c4d37a..930d9a19aeb07 100644 --- a/crates/sui-core/src/unit_tests/batch_tests.rs +++ b/crates/sui-core/src/unit_tests/batch_tests.rs @@ -59,9 +59,8 @@ pub(crate) async fn init_state( let dir = env::temp_dir(); let epoch_path = dir.join(format!("DB_{:?}", ObjectID::random())); fs::create_dir(&epoch_path).unwrap(); - let epoch_store = Arc::new(EpochStore::new(epoch_path)); + let epoch_store = Arc::new(EpochStore::new(epoch_path, &committee, None)); AuthorityState::new( - committee, authority_key.public().into(), Arc::pin(authority_key), store, @@ -767,12 +766,13 @@ async fn test_safe_batch_stream() { // Create an authority let store = Arc::new(AuthorityStore::open(&path.join("store"), None)); let state = init_state(committee.clone(), authority_key, store).await; + let epoch_store = state.epoch_store().clone(); // Happy path: let auth_client = TrustworthyAuthorityClient::new(state); let safe_client = SafeClient::new( auth_client, - committee.clone(), + epoch_store, public_key_bytes, SafeClientMetrics::new_for_tests(), ); @@ -808,11 +808,12 @@ async fn test_safe_batch_stream() { let (_, authority_key): (_, AuthorityKeyPair) = get_key_pair(); let state_b = AuthorityState::new_for_testing(committee.clone(), &authority_key, None, None, None).await; + let epoch_store = state_b.epoch_store().clone(); let auth_client_from_byzantine = ByzantineAuthorityClient::new(state_b); let public_key_bytes_b = authority_key.public().into(); let safe_client_from_byzantine = SafeClient::new( auth_client_from_byzantine, - committee.clone(), + epoch_store, public_key_bytes_b, SafeClientMetrics::new_for_tests(), ); diff --git a/crates/sui-core/src/unit_tests/gateway_state_tests.rs b/crates/sui-core/src/unit_tests/gateway_state_tests.rs index 20143410eb3e0..04ac5adc74547 100644 --- a/crates/sui-core/src/unit_tests/gateway_state_tests.rs +++ b/crates/sui-core/src/unit_tests/gateway_state_tests.rs @@ -31,9 +31,13 @@ async fn create_gateway_state(genesis_objects: Vec) -> GatewayState Committee { + self.committee + } + pub fn first_checkpoint(&self) -> &CheckpointSequenceNumber { &self.first_checkpoint } @@ -1857,7 +1861,7 @@ impl GenesisEpoch { } } - pub fn verify(&self, genesis_committee: Committee) -> SuiResult { + pub fn verify(&self, genesis_committee: &Committee) -> SuiResult { fp_ensure!( self.epoch_info.first_checkpoint == 0, SuiError::InvalidAuthenticatedEpoch( @@ -1869,7 +1873,7 @@ impl GenesisEpoch { SuiError::InvalidAuthenticatedEpoch("Genesis epoch must be epoch 0".to_string()) ); fp_ensure!( - self.epoch_info.committee == genesis_committee, + &self.epoch_info.committee == genesis_committee, SuiError::InvalidAuthenticatedEpoch("Genesis epoch committee mismatch".to_string()) ); Ok(()) @@ -1978,6 +1982,14 @@ impl AuthenticatedEpoch { Self::Genesis(g) => &g.epoch_info, } } + + pub fn into_epoch_info(self) -> EpochInfo { + match self { + Self::Signed(s) => s.epoch_info, + Self::Certified(c) => c.epoch_info, + Self::Genesis(g) => g.epoch_info, + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/sui-types/src/messages_checkpoint.rs b/crates/sui-types/src/messages_checkpoint.rs index 1b4d36adf22c8..3c5a53e087b33 100644 --- a/crates/sui-types/src/messages_checkpoint.rs +++ b/crates/sui-types/src/messages_checkpoint.rs @@ -123,38 +123,6 @@ pub struct CheckpointResponse { pub detail: Option, } -impl CheckpointResponse { - pub fn verify(&self, committee: &Committee) -> SuiResult { - match &self.info { - AuthorityCheckpointInfo::AuthenticatedCheckpoint(ckpt) => { - if let Some(ckpt) = ckpt { - ckpt.verify(committee, self.detail.as_ref())?; - } - Ok(()) - } - AuthorityCheckpointInfo::CheckpointProposal { - proposal, - prev_cert, - } => { - if let Some(p) = proposal { - p.verify(committee, self.detail.as_ref())?; - if p.summary.sequence_number > 0 { - let cert = prev_cert.as_ref().ok_or_else(|| { - SuiError::from("No checkpoint cert provided along with proposal") - })?; - cert.verify(committee, None)?; - fp_ensure!( - p.summary.sequence_number - 1 == cert.summary.sequence_number, - SuiError::from("Checkpoint proposal sequence number inconsistent with previous cert") - ); - } - } - Ok(()) - } - } - } -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub enum AuthorityCheckpointInfo { AuthenticatedCheckpoint(Option), diff --git a/crates/sui/tests/checkpoints_tests.rs b/crates/sui/tests/checkpoints_tests.rs index 756d91a2d12a4..01bcde80707cd 100644 --- a/crates/sui/tests/checkpoints_tests.rs +++ b/crates/sui/tests/checkpoints_tests.rs @@ -195,7 +195,7 @@ async fn end_to_end() { let handles = spawn_test_authorities(input_objects, &configs).await; // Make an authority's aggregator. - let aggregator = test_authority_aggregator(&configs); + let aggregator = test_authority_aggregator(&configs, handles[0].state().epoch_store().clone()); spawn_checkpoint_processes(&aggregator, &handles).await; @@ -219,7 +219,7 @@ async fn end_to_end_with_one_byzantine() { let (_first, rest) = handles[..].split_at(1); // Make an authority's aggregator. - let aggregator = test_authority_aggregator(&configs); + let aggregator = test_authority_aggregator(&configs, handles[0].state().epoch_store().clone()); // one authority does not participate in checkpointing spawn_checkpoint_processes(&aggregator, rest).await; @@ -248,7 +248,7 @@ async fn checkpoint_with_shared_objects() { let handles = spawn_test_authorities(initialization_objects, &configs).await; // Make an authority's aggregator. - let aggregator = test_authority_aggregator(&configs); + let aggregator = test_authority_aggregator(&configs, handles[0].state().epoch_store().clone()); spawn_checkpoint_processes(&aggregator, &handles).await; diff --git a/crates/sui/tests/quorum_driver_tests.rs b/crates/sui/tests/quorum_driver_tests.rs index edfe352833e11..91ded97b47554 100644 --- a/crates/sui/tests/quorum_driver_tests.rs +++ b/crates/sui/tests/quorum_driver_tests.rs @@ -26,7 +26,7 @@ async fn setup() -> ( let mut gas_objects = test_gas_objects(); let configs = test_authority_configs(); let handles = spawn_test_authorities(gas_objects.clone(), &configs).await; - let clients = test_authority_aggregator(&configs); + let clients = test_authority_aggregator(&configs, handles[0].state().epoch_store().clone()); let (sender, keypair) = test_account_keys().pop().unwrap(); let tx = make_transfer_sui_transaction( gas_objects.pop().unwrap().compute_object_reference(), diff --git a/crates/sui/tests/shared_objects_tests.rs b/crates/sui/tests/shared_objects_tests.rs index 94dcd64e7f25a..f45921a6abf8c 100644 --- a/crates/sui/tests/shared_objects_tests.rs +++ b/crates/sui/tests/shared_objects_tests.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use std::sync::Arc; +use sui_core::authority::GatewayStore; use sui_core::authority_client::AuthorityAPI; use sui_core::gateway_state::{GatewayAPI, GatewayMetrics, GatewayState}; use sui_types::messages::{ @@ -366,11 +367,12 @@ async fn shared_object_on_gateway() { // Get the authority configs and spawn them. Note that it is important to not drop // the handles (or the authorities will stop). let configs = test_authority_configs(); - let _handles = spawn_test_authorities(gas_objects.clone(), &configs).await; - let clients = test_authority_aggregator(&configs); + let handles = spawn_test_authorities(gas_objects.clone(), &configs).await; + let clients = test_authority_aggregator(&configs, handles[0].state().epoch_store().clone()); let path = tempfile::tempdir().unwrap().into_path(); + let gateway_store = Arc::new(GatewayStore::open(&path.join("store"), None)); let gateway = Arc::new( - GatewayState::new_with_authorities(&path, clients, GatewayMetrics::new_for_tests()) + GatewayState::new_with_authorities(gateway_store, clients, GatewayMetrics::new_for_tests()) .unwrap(), ); diff --git a/crates/test-utils/src/authority.rs b/crates/test-utils/src/authority.rs index 353089f2658a4..f67d51f557068 100644 --- a/crates/test-utils/src/authority.rs +++ b/crates/test-utils/src/authority.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::sync::Arc; use std::time::Duration; use sui_config::{NetworkConfig, ValidatorInfo}; +use sui_core::epoch::epoch_store::EpochStore; use sui_core::{ authority_active::{ checkpoint_driver::{CheckpointMetrics, CheckpointProcessControl}, @@ -96,6 +97,7 @@ pub async fn spawn_checkpoint_processes( /// Create a test authority aggregator. pub fn test_authority_aggregator( config: &NetworkConfig, + epoch_store: Arc, ) -> AuthorityAggregator { let validators_info = config.validator_set(); let committee = Committee::new(0, ValidatorInfo::voting_rights(validators_info)).unwrap(); @@ -111,6 +113,7 @@ pub fn test_authority_aggregator( let registry = prometheus::Registry::new(); AuthorityAggregator::new( committee, + epoch_store, clients, AuthAggMetrics::new(®istry), SafeClientMetrics::new(®istry),