From 2455ec2fb26563904ab068e1551d5dd7e072f7ee Mon Sep 17 00:00:00 2001 From: Julian Eager Date: Tue, 10 Dec 2024 15:07:04 +0800 Subject: [PATCH] refactor: disentangle test genesis and epoch config building (#12554) closes #12548 Any inputs before I start to update the tests? --- core/chain-configs/src/test_genesis.rs | 505 ++++++++++++------ core/primitives/src/shard_layout.rs | 8 + integration-tests/src/test_loop/builder.rs | 2 +- .../test_loop/tests/bandwidth_scheduler.rs | 40 +- .../tests/chunk_validator_kickout.rs | 42 +- .../src/test_loop/tests/congestion_control.rs | 50 +- .../congestion_control_genesis_bootstrap.rs | 32 +- .../contract_distribution_cross_shard.rs | 47 +- .../tests/contract_distribution_simple.rs | 44 +- .../test_loop/tests/create_delete_account.rs | 27 +- .../src/test_loop/tests/epoch_sync.rs | 46 +- .../test_loop/tests/fix_min_stake_ratio.rs | 16 +- .../test_loop/tests/fix_stake_threshold.rs | 18 +- .../src/test_loop/tests/in_memory_tries.rs | 43 +- .../tests/multinode_stateless_validators.rs | 41 +- .../tests/multinode_test_loop_example.rs | 42 +- .../src/test_loop/tests/protocol_upgrade.rs | 22 +- .../test_loop/tests/reject_outdated_blocks.rs | 17 +- .../src/test_loop/tests/resharding_v3.rs | 15 +- .../tests/simple_test_loop_example.rs | 23 +- .../src/test_loop/tests/state_sync.rs | 60 ++- .../src/test_loop/tests/syncing.rs | 42 +- .../tests/view_requests_to_archival_node.rs | 31 +- .../src/test_loop/utils/setups.rs | 51 +- .../tests/client/features/in_memory_tries.rs | 117 ++-- 25 files changed, 801 insertions(+), 580 deletions(-) diff --git a/core/chain-configs/src/test_genesis.rs b/core/chain-configs/src/test_genesis.rs index 25503d0a40b..085c1653e8f 100644 --- a/core/chain-configs/src/test_genesis.rs +++ b/core/chain-configs/src/test_genesis.rs @@ -14,11 +14,35 @@ use near_primitives::types::{ }; use near_primitives::utils::from_timestamp; use near_primitives::version::PROTOCOL_VERSION; -use near_time::Clock; +use near_time::{Clock, FakeClock}; use num_rational::Rational32; use crate::{Genesis, GenesisConfig, GenesisContents, GenesisRecords}; +/// Builder for constructing `EpochConfig` for testing. +/// +/// Defaults +/// * single shard +/// * single block and chunk producer +/// * epoch_length: 5 +/// * block_producer_kickout_threshold: 0 +/// * chunk_producer_kickout_threshold: 0 +/// * chunk_validator_only_kickout_threshold: 0 +#[derive(Debug, Clone, Default)] +pub struct TestEpochConfigBuilder { + epoch_length: Option, + shard_layout: Option, + validators_spec: Option, + target_validator_mandates_per_shard: Option, + block_producer_kickout_threshold: Option, + chunk_producer_kickout_threshold: Option, + chunk_validator_only_kickout_threshold: Option, + // validator selection + minimum_stake_ratio: Option, + minimum_validators_per_shard: Option, + shuffle_shard_assignment_for_chunk_producers: Option, +} + /// A builder for constructing a valid genesis for testing. /// /// The philosophy is that this can be used to generate a genesis that is @@ -36,19 +60,21 @@ pub struct TestGenesisBuilder { genesis_time: Option>, protocol_version: Option, genesis_height: Option, + // TODO: remove when epoch length is no longer controlled by genesis epoch_length: Option, min_max_gas_price: Option<(Balance, Balance)>, gas_limit: Option, transaction_validity_period: Option, - validators: Option, + validators_spec: Option, protocol_treasury_account: Option, max_inflation_rate: Option, user_accounts: Vec, - epoch_config: Option, + // TODO: remove when shard layout is no longer controlled by genesis + shard_layout: Option, } #[derive(Debug, Clone)] -enum ValidatorsSpec { +pub enum ValidatorsSpec { DesiredRoles { block_and_chunk_producers: Vec, chunk_validators_only: Vec, @@ -68,229 +94,292 @@ struct UserAccount { access_keys: Vec, } -impl TestGenesisBuilder { +impl TestEpochConfigBuilder { pub fn new() -> Self { Default::default() } - pub fn epoch_config_mut(&mut self) -> &mut EpochConfig { - if self.epoch_config.is_none() { - let mut epoch_config = Genesis::test_epoch_config(1, ShardLayout::single_shard(), 100); - epoch_config.block_producer_kickout_threshold = 0; - epoch_config.chunk_producer_kickout_threshold = 0; - epoch_config.chunk_validator_only_kickout_threshold = 0; - self.epoch_config = Some(epoch_config); - } - self.epoch_config.as_mut().unwrap() - } - - pub fn chain_id(&mut self, chain_id: String) -> &mut Self { - self.chain_id = Some(chain_id); + pub fn epoch_length(mut self, epoch_length: BlockHeightDelta) -> Self { + self.epoch_length = Some(epoch_length); self } - pub fn genesis_time(&mut self, genesis_time: chrono::DateTime) -> &mut Self { - self.genesis_time = Some(genesis_time); + pub fn shard_layout(mut self, shard_layout: ShardLayout) -> Self { + self.shard_layout = Some(shard_layout); self } - pub fn genesis_time_from_clock(&mut self, clock: &Clock) -> &mut Self { - self.genesis_time = Some(from_timestamp(clock.now_utc().unix_timestamp_nanos() as u64)); + pub fn validators_spec(mut self, validators_spec: ValidatorsSpec) -> Self { + self.validators_spec = Some(validators_spec); self } - pub fn protocol_version(&mut self, protocol_version: ProtocolVersion) -> &mut Self { - self.protocol_version = Some(protocol_version); + pub fn minimum_stake_ratio(mut self, minimum_stake_ratio: Rational32) -> Self { + self.minimum_stake_ratio = Some(minimum_stake_ratio); self } - pub fn protocol_version_latest(&mut self) -> &mut Self { - self.protocol_version = Some(PROTOCOL_VERSION); + pub fn minimum_validators_per_shard(mut self, minimum_validators_per_shard: NumSeats) -> Self { + self.minimum_validators_per_shard = Some(minimum_validators_per_shard); self } - pub fn genesis_height(&mut self, genesis_height: BlockHeight) -> &mut Self { - self.genesis_height = Some(genesis_height); + pub fn target_validator_mandates_per_shard( + mut self, + target_validator_mandates_per_shard: NumSeats, + ) -> Self { + self.target_validator_mandates_per_shard = Some(target_validator_mandates_per_shard); self } - pub fn epoch_length(&mut self, epoch_length: BlockHeightDelta) -> &mut Self { - self.epoch_length = Some(epoch_length); + pub fn shuffle_shard_assignment_for_chunk_producers(mut self, shuffle: bool) -> Self { + self.shuffle_shard_assignment_for_chunk_producers = Some(shuffle); self } - pub fn shard_layout_single(&mut self) -> &mut Self { - self.epoch_config_mut().shard_layout = ShardLayout::single_shard(); + // Validators with performance below 80% are kicked out, similarly to + // mainnet as of 28 Jun 2024. + pub fn kickouts_standard_80_percent(mut self) -> Self { + self.block_producer_kickout_threshold = Some(80); + self.chunk_producer_kickout_threshold = Some(80); + self.chunk_validator_only_kickout_threshold = Some(80); self } - pub fn shard_layout_simple_v1(&mut self, boundary_accounts: &[&str]) -> &mut Self { - let boundary_accounts = boundary_accounts.iter().map(|a| a.parse().unwrap()).collect(); - self.epoch_config_mut().shard_layout = - ShardLayout::multi_shard_custom(boundary_accounts, 1); + // Only chunk validator-only nodes can be kicked out. + pub fn kickouts_for_chunk_validators_only(mut self) -> Self { + self.block_producer_kickout_threshold = Some(0); + self.chunk_producer_kickout_threshold = Some(0); + self.chunk_validator_only_kickout_threshold = Some(50); self } - // TODO(#11265): move this and relevant methods to epoch config builder. - // In dynamic resharding world, shard layout will not be static. - pub fn shard_layout(&mut self, shard_layout: ShardLayout) -> &mut Self { - self.epoch_config_mut().shard_layout = shard_layout; - self + pub fn build(self) -> EpochConfig { + let epoch_length = self.epoch_length.unwrap_or_else(|| { + let default = 5; + tracing::warn!( + "Epoch config epoch_length not explicitly set, defaulting to {:?}.", + default + ); + default + }); + let shard_layout = self.shard_layout.unwrap_or_else(|| { + let default = ShardLayout::single_shard(); + tracing::warn!( + "Epoch config shard_layout not explicitly set, defaulting to {:?}.", + default + ); + default + }); + let validators_spec = self.validators_spec.unwrap_or_else(|| { + let default = ValidatorsSpec::DesiredRoles { + block_and_chunk_producers: vec!["validator0".to_string()], + chunk_validators_only: vec![], + }; + tracing::warn!( + "Epoch config validators_spec not explicitly set, defaulting to {:?}.", + default + ); + default + }); + + let DerivedValidatorSetup { + validators: _, + num_block_producer_seats, + num_chunk_producer_seats, + num_chunk_validator_seats, + } = derive_validator_setup(validators_spec); + + let mut epoch_config = + Genesis::test_epoch_config(num_block_producer_seats, shard_layout, epoch_length); + epoch_config.block_producer_kickout_threshold = 0; + epoch_config.chunk_producer_kickout_threshold = 0; + epoch_config.chunk_validator_only_kickout_threshold = 0; + epoch_config.validator_selection_config.num_chunk_producer_seats = num_chunk_producer_seats; + epoch_config.validator_selection_config.num_chunk_validator_seats = + num_chunk_validator_seats; + + if let Some(target_validator_mandates_per_shard) = self.target_validator_mandates_per_shard + { + epoch_config.target_validator_mandates_per_shard = target_validator_mandates_per_shard; + } else { + tracing::warn!( + "Epoch config target_validator_mandates_per_shard not explicitly set, defaulting to {:?}.", + epoch_config.target_validator_mandates_per_shard + ); + } + if let Some(block_producer_kickout_threshold) = self.block_producer_kickout_threshold { + epoch_config.block_producer_kickout_threshold = block_producer_kickout_threshold; + } else { + tracing::warn!( + "Epoch config block_producer_kickout_threshold not explicitly set, defaulting to {:?}.", + epoch_config.block_producer_kickout_threshold + ); + } + if let Some(chunk_producer_kickout_threshold) = self.chunk_producer_kickout_threshold { + epoch_config.chunk_producer_kickout_threshold = chunk_producer_kickout_threshold; + } else { + tracing::warn!( + "Epoch config chunk_producer_kickout_threshold not explicitly set, defaulting to {:?}.", + epoch_config.chunk_producer_kickout_threshold + ); + } + if let Some(chunk_validator_only_kickout_threshold) = + self.chunk_validator_only_kickout_threshold + { + epoch_config.chunk_validator_only_kickout_threshold = + chunk_validator_only_kickout_threshold; + } else { + tracing::warn!( + "Epoch config chunk_validator_only_kickout_threshold not explicitly set, defaulting to {:?}.", + epoch_config.chunk_validator_only_kickout_threshold + ); + } + if let Some(minimum_stake_ratio) = self.minimum_stake_ratio { + epoch_config.validator_selection_config.minimum_stake_ratio = minimum_stake_ratio; + } else { + tracing::warn!( + "Epoch config minimum_stake_ratio not explicitly set, defaulting to {:?}.", + epoch_config.validator_selection_config.minimum_stake_ratio + ); + } + if let Some(minimum_validators_per_shard) = self.minimum_validators_per_shard { + epoch_config.validator_selection_config.minimum_validators_per_shard = + minimum_validators_per_shard; + } else { + tracing::warn!( + "Epoch config minimum_validators_per_shard not explicitly set, defaulting to {:?}.", + epoch_config.validator_selection_config.minimum_validators_per_shard + ); + } + if let Some(shuffle_shard_assignment_for_chunk_producers) = + self.shuffle_shard_assignment_for_chunk_producers + { + epoch_config.validator_selection_config.shuffle_shard_assignment_for_chunk_producers = + shuffle_shard_assignment_for_chunk_producers; + } else { + tracing::warn!( + "Epoch config shuffle_shard_assignment_for_chunk_producers not explicitly set, defaulting to {:?}.", + epoch_config.validator_selection_config.shuffle_shard_assignment_for_chunk_producers + ); + } + + epoch_config } +} - pub fn gas_prices(&mut self, min: Balance, max: Balance) -> &mut Self { - self.min_max_gas_price = Some((min, max)); - self +impl TestGenesisBuilder { + pub fn new() -> Self { + Default::default() } - pub fn gas_prices_free(&mut self) -> &mut Self { - self.min_max_gas_price = Some((0, 0)); + pub fn chain_id(mut self, chain_id: String) -> Self { + self.chain_id = Some(chain_id); self } - pub fn gas_limit(&mut self, gas_limit: Gas) -> &mut Self { - self.gas_limit = Some(gas_limit); + pub fn genesis_time(mut self, genesis_time: chrono::DateTime) -> Self { + self.genesis_time = Some(genesis_time); self } - pub fn gas_limit_one_petagas(&mut self) -> &mut Self { - self.gas_limit = Some(1_000_000_000_000_000); + pub fn genesis_time_from_clock(mut self, clock: &Clock) -> Self { + self.genesis_time = Some(from_timestamp(clock.now_utc().unix_timestamp_nanos() as u64)); self } - pub fn transaction_validity_period( - &mut self, - transaction_validity_period: NumBlocks, - ) -> &mut Self { - self.transaction_validity_period = Some(transaction_validity_period); + pub fn protocol_version(mut self, protocol_version: ProtocolVersion) -> Self { + self.protocol_version = Some(protocol_version); self } - /// Specifies that we want the validators to be exactly the specified accounts. - /// This will generate a reasonable set of parameters so that the given - /// validators are selected as specified. - pub fn validators_desired_roles( - &mut self, - block_and_chunk_producers: &[&str], - chunk_validators_only: &[&str], - ) -> &mut Self { - self.validators = Some(ValidatorsSpec::DesiredRoles { - block_and_chunk_producers: block_and_chunk_producers - .iter() - .map(|s| s.to_string()) - .collect(), - chunk_validators_only: chunk_validators_only.iter().map(|s| s.to_string()).collect(), - }); + pub fn genesis_height(mut self, genesis_height: BlockHeight) -> Self { + self.genesis_height = Some(genesis_height); self } - /// Specifies the validator fields directly, relying on the validator selection - /// algorithm to determine which validators are selected as block or chunk - /// producers. - pub fn validators_raw( - &mut self, - validators: Vec, - num_block_producer_seats: NumSeats, - num_chunk_producer_seats: NumSeats, - num_chunk_validator_only_seats: NumSeats, - ) -> &mut Self { - let num_chunk_validator_seats = - std::cmp::max(num_block_producer_seats, num_chunk_producer_seats) - + num_chunk_validator_only_seats; - self.validators = Some(ValidatorsSpec::Raw { - validators, - num_block_producer_seats, - num_chunk_producer_seats, - num_chunk_validator_seats, - }); + pub fn epoch_length(mut self, epoch_length: BlockHeightDelta) -> Self { + self.epoch_length = Some(epoch_length); self } - pub fn minimum_stake_ratio(&mut self, minimum_stake_ratio: Rational32) -> &mut Self { - self.epoch_config_mut().validator_selection_config.minimum_stake_ratio = - minimum_stake_ratio; + pub fn shard_layout(mut self, shard_layout: ShardLayout) -> Self { + self.shard_layout = Some(shard_layout); self } - pub fn max_inflation_rate(&mut self, max_inflation_rate: Rational32) -> &mut Self { - self.max_inflation_rate = Some(max_inflation_rate); + pub fn gas_prices(mut self, min: Balance, max: Balance) -> Self { + self.min_max_gas_price = Some((min, max)); self } - pub fn minimum_validators_per_shard( - &mut self, - minimum_validators_per_shard: NumSeats, - ) -> &mut Self { - self.epoch_config_mut().validator_selection_config.minimum_validators_per_shard = - minimum_validators_per_shard; + pub fn gas_prices_free(mut self) -> Self { + self.min_max_gas_price = Some((0, 0)); self } - pub fn target_validator_mandates_per_shard( - &mut self, - target_validator_mandates_per_shard: NumSeats, - ) -> &mut Self { - self.epoch_config_mut().target_validator_mandates_per_shard = - target_validator_mandates_per_shard; + pub fn gas_limit(mut self, gas_limit: Gas) -> Self { + self.gas_limit = Some(gas_limit); self } - /// Specifies the protocol treasury account. If not specified, this will - /// pick an arbitrary account name and ensure that it is included in the - /// genesis records. - pub fn protocol_treasury_account(&mut self, protocol_treasury_account: String) -> &mut Self { - self.protocol_treasury_account = Some(protocol_treasury_account); + pub fn gas_limit_one_petagas(mut self) -> Self { + self.gas_limit = Some(1_000_000_000_000_000); self } - pub fn shuffle_shard_assignment_for_chunk_producers(&mut self, shuffle: bool) -> &mut Self { - self.epoch_config_mut() - .validator_selection_config - .shuffle_shard_assignment_for_chunk_producers = shuffle; + pub fn transaction_validity_period(mut self, transaction_validity_period: NumBlocks) -> Self { + self.transaction_validity_period = Some(transaction_validity_period); self } - pub fn kickouts_disabled(&mut self) -> &mut Self { - let epoch_config = self.epoch_config_mut(); - epoch_config.block_producer_kickout_threshold = 0; - epoch_config.chunk_producer_kickout_threshold = 0; - epoch_config.chunk_validator_only_kickout_threshold = 0; + pub fn validators_spec(mut self, validators: ValidatorsSpec) -> Self { + self.validators_spec = Some(validators); self } - /// Validators with performance below 80% are kicked out, similarly to - /// mainnet as of 28 Jun 2024. - pub fn kickouts_standard_80_percent(&mut self) -> &mut Self { - let epoch_config = self.epoch_config_mut(); - epoch_config.block_producer_kickout_threshold = 80; - epoch_config.chunk_producer_kickout_threshold = 80; - epoch_config.chunk_validator_only_kickout_threshold = 80; + pub fn max_inflation_rate(mut self, max_inflation_rate: Rational32) -> Self { + self.max_inflation_rate = Some(max_inflation_rate); self } - /// Only chunk validator-only nodes can be kicked out. - pub fn kickouts_for_chunk_validators_only(&mut self) -> &mut Self { - let epoch_config = self.epoch_config_mut(); - epoch_config.block_producer_kickout_threshold = 0; - epoch_config.chunk_producer_kickout_threshold = 0; - epoch_config.chunk_validator_only_kickout_threshold = 50; + /// Specifies the protocol treasury account. If not specified, this will + /// pick an arbitrary account name and ensure that it is included in the + /// genesis records. + pub fn protocol_treasury_account(mut self, protocol_treasury_account: String) -> Self { + self.protocol_treasury_account = Some(protocol_treasury_account); self } pub fn add_user_account_simple( - &mut self, + mut self, account_id: AccountId, - balance: Balance, - ) -> &mut Self { + initial_balance: Balance, + ) -> Self { self.user_accounts.push(UserAccount { - balance, + balance: initial_balance, access_keys: vec![create_user_test_signer(&account_id).public_key()], account_id, }); self } - pub fn build(mut self) -> (Genesis, EpochConfigStore) { + pub fn add_user_accounts_simple( + mut self, + accounts: &Vec, + initial_balance: Balance, + ) -> Self { + for account_id in accounts { + self.user_accounts.push(UserAccount { + balance: initial_balance, + access_keys: vec![create_user_test_signer(account_id).public_key()], + account_id: account_id.clone(), + }); + } + self + } + + pub fn build(self) -> Genesis { let chain_id = self.chain_id.clone().unwrap_or_else(|| { let default = "test".to_string(); tracing::warn!("Genesis chain_id not explicitly set, defaulting to {:?}.", default); @@ -301,7 +390,7 @@ impl TestGenesisBuilder { tracing::warn!("Genesis protocol_version not explicitly set, defaulting to latest protocol version {:?}.", default); default }); - let validator_specs = self.validators.clone().unwrap_or_else(|| { + let validators_spec = self.validators_spec.clone().unwrap_or_else(|| { let default = ValidatorsSpec::DesiredRoles { block_and_chunk_producers: vec!["validator0".to_string()], chunk_validators_only: vec![], @@ -317,22 +406,11 @@ impl TestGenesisBuilder { tracing::warn!("Genesis epoch_length not explicitly set, defaulting to {:?}.", default); default }); - - let derived_validator_setup = derive_validator_setup(validator_specs); - - let mut epoch_config = self.epoch_config_mut().clone(); - epoch_config.num_block_producer_seats = derived_validator_setup.num_block_producer_seats; - epoch_config.validator_selection_config.num_chunk_producer_seats = - derived_validator_setup.num_chunk_producer_seats; - epoch_config.validator_selection_config.num_chunk_validator_seats = - derived_validator_setup.num_chunk_validator_seats; - let epoch_config_store = EpochConfigStore::test(BTreeMap::from_iter(vec![( - protocol_version, - Arc::new(epoch_config), - )])); - let shard_layout = - epoch_config_store.get_config(protocol_version).as_ref().shard_layout.clone(); - + let shard_layout = self.shard_layout.clone().unwrap_or_else(|| { + let default = ShardLayout::single_shard(); + tracing::warn!("Genesis shard_layout not explicitly set, defaulting to {:?}.", default); + default + }); let genesis_time = self.genesis_time.unwrap_or_else(|| { let default = chrono::Utc::now(); tracing::warn!( @@ -407,7 +485,7 @@ impl TestGenesisBuilder { // that the protocol treasury account is included too. We will use all // of this to generate the genesis records and also calculate the // total supply. - let mut user_accounts = self.user_accounts.clone(); + let mut user_accounts = self.user_accounts; if user_accounts.iter().all(|account| &account.account_id != &protocol_treasury_account) { tracing::warn!( "Protocol treasury account {:?} not found in user accounts; @@ -421,9 +499,16 @@ impl TestGenesisBuilder { }); } + let DerivedValidatorSetup { + validators, + num_block_producer_seats, + num_chunk_producer_seats, + num_chunk_validator_seats, + } = derive_validator_setup(validators_spec); + let mut total_supply = 0; let mut validator_stake: HashMap = HashMap::new(); - for validator in &derived_validator_setup.validators { + for validator in &validators { total_supply += validator.amount; validator_stake.insert(validator.account_id.clone(), validator.amount); } @@ -483,30 +568,65 @@ impl TestGenesisBuilder { protocol_reward_rate: Rational32::new(0, 1), total_supply, max_kickout_stake_perc: 100, - validators: derived_validator_setup.validators, + validators, shard_layout: shard_layout.clone(), - num_block_producer_seats: derived_validator_setup.num_block_producer_seats, + num_block_producer_seats, num_block_producer_seats_per_shard: shard_layout .shard_ids() - .map(|_| derived_validator_setup.num_block_producer_seats) + .map(|_| num_block_producer_seats) .collect(), num_chunk_only_producer_seats: 0, minimum_stake_divisor: 10, max_inflation_rate, protocol_upgrade_stake_threshold: Rational32::new(8, 10), - num_chunk_producer_seats: derived_validator_setup.num_chunk_producer_seats, - num_chunk_validator_seats: derived_validator_setup.num_chunk_validator_seats, + num_chunk_producer_seats, + num_chunk_validator_seats, chunk_producer_assignment_changes_limit: 5, ..Default::default() }; - ( - Genesis { - config: genesis_config, - contents: GenesisContents::Records { records: GenesisRecords(records) }, - }, - epoch_config_store, - ) + Genesis { + config: genesis_config, + contents: GenesisContents::Records { records: GenesisRecords(records) }, + } + } +} + +impl ValidatorsSpec { + /// Specifies that we want the validators to be exactly the specified accounts. + /// This will generate a reasonable set of parameters so that the given + /// validators are selected as specified. + pub fn desired_roles( + block_and_chunk_producers: &[&str], + chunk_validators_only: &[&str], + ) -> Self { + ValidatorsSpec::DesiredRoles { + block_and_chunk_producers: block_and_chunk_producers + .iter() + .map(|s| s.to_string()) + .collect(), + chunk_validators_only: chunk_validators_only.iter().map(|s| s.to_string()).collect(), + } + } + + /// Specifies the validator fields directly, relying on the validator selection + /// algorithm to determine which validators are selected as block or chunk + /// producers. + pub fn raw( + validators: Vec, + num_block_producer_seats: NumSeats, + num_chunk_producer_seats: NumSeats, + num_chunk_validator_only_seats: NumSeats, + ) -> Self { + let num_chunk_validator_seats = + std::cmp::max(num_block_producer_seats, num_chunk_producer_seats) + + num_chunk_validator_only_seats; + ValidatorsSpec::Raw { + validators, + num_block_producer_seats, + num_chunk_producer_seats, + num_chunk_validator_seats, + } } } @@ -565,3 +685,50 @@ fn derive_validator_setup(specs: ValidatorsSpec) -> DerivedValidatorSetup { }, } } + +pub struct GenesisAndEpochConfigParams<'a> { + pub epoch_length: BlockHeightDelta, + pub protocol_version: ProtocolVersion, + pub shard_layout: ShardLayout, + pub validators_spec: ValidatorsSpec, + pub accounts: &'a Vec, +} + +/// Handy factory for building test genesis and epoch config store. Use it if it is enough to have +/// one epoch config for your test. Otherwise, just use builders directly. +pub fn build_genesis_and_epoch_config_store<'a>( + params: GenesisAndEpochConfigParams<'a>, + customize_genesis_builder: impl FnOnce(TestGenesisBuilder) -> TestGenesisBuilder, + customize_epoch_config_builder: impl FnOnce(TestEpochConfigBuilder) -> TestEpochConfigBuilder, +) -> (Genesis, EpochConfigStore) { + let GenesisAndEpochConfigParams { + epoch_length, + protocol_version, + shard_layout, + validators_spec, + accounts, + } = params; + + let genesis_builder = TestGenesisBuilder::new() + .genesis_time_from_clock(&FakeClock::default().clock()) + .protocol_version(protocol_version) + .epoch_length(epoch_length) + .shard_layout(shard_layout.clone()) + .validators_spec(validators_spec.clone()) + .add_user_accounts_simple(accounts, 1_000_000 * ONE_NEAR) + .gas_prices_free() + .gas_limit_one_petagas(); + let epoch_config_builder = TestEpochConfigBuilder::new() + .epoch_length(epoch_length) + .shard_layout(shard_layout) + .validators_spec(validators_spec); + let genesis_builder = customize_genesis_builder(genesis_builder); + let epoch_config_builder = customize_epoch_config_builder(epoch_config_builder); + + let genesis = genesis_builder.build(); + let epoch_config = epoch_config_builder.build(); + let epoch_config_store = + EpochConfigStore::test(BTreeMap::from([(protocol_version, Arc::new(epoch_config))])); + + (genesis, epoch_config_store) +} diff --git a/core/primitives/src/shard_layout.rs b/core/primitives/src/shard_layout.rs index 065515ffdf5..ff91304d68c 100644 --- a/core/primitives/src/shard_layout.rs +++ b/core/primitives/src/shard_layout.rs @@ -391,6 +391,14 @@ impl ShardLayout { }) } + /// Test-only helper to create a simple multi-shard ShardLayout with the provided boundaries. + /// The shard ids are deterministic but arbitrary in order to test the non-contiguous ShardIds. + pub fn simple_v1(boundary_accounts: &[&str]) -> ShardLayout { + // TODO these test methods should go into a different namespace + let boundary_accounts = boundary_accounts.iter().map(|a| a.parse().unwrap()).collect(); + Self::multi_shard_custom(boundary_accounts, 1) + } + /// Return a V0 Shardlayout #[deprecated(note = "Use multi_shard() instead")] pub fn v0(num_shards: NumShards, version: ShardVersion) -> Self { diff --git a/integration-tests/src/test_loop/builder.rs b/integration-tests/src/test_loop/builder.rs index 813b4762f67..b868d5edd10 100644 --- a/integration-tests/src/test_loop/builder.rs +++ b/integration-tests/src/test_loop/builder.rs @@ -1,5 +1,6 @@ use std::collections::{HashMap, HashSet}; use std::sync::{Arc, Mutex}; +use tempfile::TempDir; use near_async::futures::FutureSpawner; use near_async::messaging::{noop, IntoMultiSender, IntoSender, LateBoundSender}; @@ -40,7 +41,6 @@ use near_store::{ShardUId, Store, StoreConfig, TrieConfig}; use near_vm_runner::logic::ProtocolVersion; use near_vm_runner::{ContractRuntimeCache, FilesystemContractRuntimeCache}; use nearcore::state_sync::StateSyncDumper; -use tempfile::TempDir; use super::env::{ClientToShardsManagerSender, TestData, TestLoopChunksStorage, TestLoopEnv}; use super::utils::network::{chunk_endorsement_dropper, chunk_endorsement_dropper_by_hash}; diff --git a/integration-tests/src/test_loop/tests/bandwidth_scheduler.rs b/integration-tests/src/test_loop/tests/bandwidth_scheduler.rs index b7540fefe4b..a95b771ed34 100644 --- a/integration-tests/src/test_loop/tests/bandwidth_scheduler.rs +++ b/integration-tests/src/test_loop/tests/bandwidth_scheduler.rs @@ -11,7 +11,9 @@ use near_async::test_loop::sender::TestLoopSender; use near_async::test_loop::TestLoopV2; use near_async::time::Duration; use near_chain::ChainStoreAccess; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::client_actor::ClientActorInner; use near_client::Client; use near_crypto::Signer; @@ -44,7 +46,7 @@ use testlib::bandwidth_scheduler::get_random_receipt_size_for_test; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::{TestData, TestLoopEnv}; use crate::test_loop::utils::transactions::{run_txs_parallel, TransactionRunner}; -use crate::test_loop::utils::{ONE_NEAR, TGAS}; +use crate::test_loop::utils::TGAS; /// 1 node, 3 shards /// Lots of transactions which generate congestion and buffered cross-shard receipts. @@ -85,24 +87,22 @@ fn slow_test_bandwidth_scheduler_request_generation() { all_accounts.extend(workload_accounts.clone()); all_accounts.push(node_account.clone()); - let builder = TestLoopBuilder::new(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_limit_one_petagas() - .shard_layout(shard_layout) - .transaction_validity_period(1000) - .epoch_length(10000) - .validators_desired_roles(&[node_account.as_str()], &[]); - for account in all_accounts { - genesis_builder.add_user_account_simple(account.clone(), 100_000_0000 * ONE_NEAR); - } - - let (genesis, epoch_config_store) = genesis_builder.build(); - - let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder + let epoch_length = 10000; + let validators_spec = ValidatorsSpec::desired_roles(&[node_account.as_str()], &[]); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &all_accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| epoch_config_builder, + ); + + let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = TestLoopBuilder::new() .genesis(genesis) .epoch_config_store(epoch_config_store) .clients(vec![node_account]) diff --git a/integration-tests/src/test_loop/tests/chunk_validator_kickout.rs b/integration-tests/src/test_loop/tests/chunk_validator_kickout.rs index c0f90fe6794..3486e5f0d2d 100644 --- a/integration-tests/src/test_loop/tests/chunk_validator_kickout.rs +++ b/integration-tests/src/test_loop/tests/chunk_validator_kickout.rs @@ -1,13 +1,16 @@ use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::validators::get_epoch_all_validators; -use crate::test_loop::utils::ONE_NEAR; use itertools::Itertools; use near_async::test_loop::data::TestLoopData; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; const NUM_ACCOUNTS: usize = 8; const NUM_PRODUCER_ACCOUNTS: usize = 6; @@ -34,7 +37,6 @@ impl TestCase { fn run_test_chunk_validator_kickout(accounts: Vec, test_case: TestCase) { init_test_logger(); - let initial_balance = 10000 * ONE_NEAR; let epoch_length = 10; let clients = accounts.iter().cloned().collect_vec(); let accounts_str = accounts.iter().map(|a| a.as_str()).collect_vec(); @@ -71,20 +73,26 @@ fn run_test_chunk_validator_kickout(accounts: Vec, test_case: TestCas None }; - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .shard_layout_simple_v1(&["account2", "account4", "account6"]) - .epoch_length(epoch_length) - // Select 6 block&chunk producers and 2 chunk validators. - .validators_desired_roles(block_and_chunk_producers, chunk_validators_only) - // Set up config to kick out only chunk validators for low performance. - .kickouts_for_chunk_validators_only() - .target_validator_mandates_per_shard(num_validator_mandates_per_shard); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let shard_layout = ShardLayout::simple_v1(&["account2", "account4", "account6"]); + let validators_spec = + ValidatorsSpec::desired_roles(block_and_chunk_producers, chunk_validators_only); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder, + |epoch_config_builder| { + epoch_config_builder + // Set up config to kick out only chunk validators for low performance. + .kickouts_for_chunk_validators_only() + .target_validator_mandates_per_shard(num_validator_mandates_per_shard) + }, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/congestion_control.rs b/integration-tests/src/test_loop/tests/congestion_control.rs index ad2200e3649..57c11454ab3 100644 --- a/integration-tests/src/test_loop/tests/congestion_control.rs +++ b/integration-tests/src/test_loop/tests/congestion_control.rs @@ -4,17 +4,21 @@ use itertools::Itertools; use near_async::test_loop::data::{TestLoopData, TestLoopDataHandle}; use near_async::test_loop::TestLoopV2; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::client_actor::ClientActorInner; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::{AccountId, BlockHeight}; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::{TestData, TestLoopEnv}; use crate::test_loop::utils::transactions::{ call_contract, check_txs, deploy_contract, make_accounts, }; -use crate::test_loop::utils::{ONE_NEAR, TGAS}; +use crate::test_loop::utils::TGAS; const NUM_ACCOUNTS: usize = 100; const NUM_PRODUCERS: usize = 2; @@ -60,7 +64,6 @@ fn test_congestion_control_simple() { } fn setup(accounts: &Vec) -> (TestLoopEnv, AccountId) { - let initial_balance = 10000 * ONE_NEAR; let clients = accounts.iter().take(NUM_CLIENTS).cloned().collect_vec(); // split the clients into producers, validators, and rpc nodes @@ -74,26 +77,29 @@ fn setup(accounts: &Vec) -> (TestLoopEnv, AccountId) { let validators = validators.iter().map(|account| account.as_str()).collect_vec(); let [rpc_id] = rpcs else { panic!("Expected exactly one rpc node") }; - let builder = TestLoopBuilder::new(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(1000) - .epoch_length(10) - .validators_desired_roles(&producers, &validators) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = ValidatorsSpec::desired_roles(&producers, &validators); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); - let env = - builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); + let env = TestLoopBuilder::new() + .genesis(genesis) + .epoch_config_store(epoch_config_store) + .clients(clients) + .build(); (env, rpc_id.clone()) } diff --git a/integration-tests/src/test_loop/tests/congestion_control_genesis_bootstrap.rs b/integration-tests/src/test_loop/tests/congestion_control_genesis_bootstrap.rs index 7fb2a09cfb1..7a9f84c3e75 100644 --- a/integration-tests/src/test_loop/tests/congestion_control_genesis_bootstrap.rs +++ b/integration-tests/src/test_loop/tests/congestion_control_genesis_bootstrap.rs @@ -1,14 +1,16 @@ use near_async::time::Duration; use near_chain::ChainStoreAccess; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::Client; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; use near_primitives::version::{ProtocolFeature, PROTOCOL_VERSION}; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; -use crate::test_loop::utils::ONE_NEAR; const NUM_SHARDS: usize = 4; @@ -25,23 +27,25 @@ fn test_congestion_control_genesis_bootstrap() { let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = ["test0", "test1"]; let clients: Vec = accounts.iter().map(|account| account.parse().unwrap()).collect(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .validators_desired_roles(&accounts[0..1], &accounts[1..2]) - .minimum_validators_per_shard(1); + let epoch_length = 100; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = ValidatorsSpec::desired_roles(&accounts[0..1], &accounts[1..2]); - for i in 0..clients.len() { - genesis_builder.add_user_account_simple(clients[i].clone(), initial_balance); - } + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &clients, + }, + |genesis_builder| genesis_builder, + |epoch_config_builder| epoch_config_builder.minimum_validators_per_shard(1), + ); - let (genesis, epoch_config_store) = genesis_builder.build(); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder .genesis(genesis) .epoch_config_store(epoch_config_store) diff --git a/integration-tests/src/test_loop/tests/contract_distribution_cross_shard.rs b/integration-tests/src/test_loop/tests/contract_distribution_cross_shard.rs index a6b5463f724..ae37fabd066 100644 --- a/integration-tests/src/test_loop/tests/contract_distribution_cross_shard.rs +++ b/integration-tests/src/test_loop/tests/contract_distribution_cross_shard.rs @@ -1,8 +1,12 @@ use itertools::Itertools; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use near_vm_runner::ContractCode; use crate::test_loop::builder::TestLoopBuilder; @@ -11,10 +15,10 @@ use crate::test_loop::utils::contract_distribution::{ assert_all_chunk_endorsements_received, clear_compiled_contract_caches, run_until_caches_contain_contract, }; +use crate::test_loop::utils::get_head_height; use crate::test_loop::utils::transactions::{ call_contract, check_txs, deploy_contract, make_accounts, }; -use crate::test_loop::utils::{get_head_height, ONE_NEAR}; const EPOCH_LENGTH: u64 = 10; const GENESIS_HEIGHT: u64 = 1000; @@ -73,7 +77,6 @@ fn test_contract_distribution_cross_shard() { fn setup(accounts: &Vec) -> (TestLoopEnv, AccountId) { let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; // All block_and_chunk_producers will be both block and chunk validators. let block_and_chunk_producers = (0..NUM_BLOCK_AND_CHUNK_PRODUCERS).map(|idx| accounts[idx].as_str()).collect_vec(); @@ -85,23 +88,27 @@ fn setup(accounts: &Vec) -> (TestLoopEnv, AccountId) { let clients = accounts.iter().take(NUM_VALIDATORS + NUM_RPC).cloned().collect_vec(); let rpc_id = accounts[NUM_VALIDATORS].clone(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(GENESIS_HEIGHT) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account4"]) - .transaction_validity_period(1000) - .epoch_length(EPOCH_LENGTH) - .validators_desired_roles(&block_and_chunk_producers, &chunk_validators_only) - .shuffle_shard_assignment_for_chunk_producers(true) - .minimum_validators_per_shard(2); - for account in accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let shard_layout = ShardLayout::simple_v1(&["account4"]); + let validators_spec = + ValidatorsSpec::desired_roles(&block_and_chunk_producers, &chunk_validators_only); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length: EPOCH_LENGTH, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| { + genesis_builder.genesis_height(GENESIS_HEIGHT).transaction_validity_period(1000) + }, + |epoch_config_builder| { + epoch_config_builder + .shuffle_shard_assignment_for_chunk_producers(true) + .minimum_validators_per_shard(2) + }, + ); let env = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/contract_distribution_simple.rs b/integration-tests/src/test_loop/tests/contract_distribution_simple.rs index d0c33b4a16e..edfc01e0cbf 100644 --- a/integration-tests/src/test_loop/tests/contract_distribution_simple.rs +++ b/integration-tests/src/test_loop/tests/contract_distribution_simple.rs @@ -1,8 +1,12 @@ use itertools::Itertools; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use near_vm_runner::ContractCode; use crate::test_loop::builder::TestLoopBuilder; @@ -11,10 +15,10 @@ use crate::test_loop::utils::contract_distribution::{ assert_all_chunk_endorsements_received, clear_compiled_contract_caches, run_until_caches_contain_contract, }; +use crate::test_loop::utils::get_head_height; use crate::test_loop::utils::transactions::{ do_call_contract, do_delete_account, do_deploy_contract, make_account, make_accounts, }; -use crate::test_loop::utils::{get_head_height, ONE_NEAR}; const EPOCH_LENGTH: u64 = 10; const GENESIS_HEIGHT: u64 = 1000; @@ -212,7 +216,6 @@ fn test_contract_distribution_deply_and_call_multiple_contracts() { fn setup(accounts: &Vec) -> TestLoopEnv { let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; // All block_and_chunk_producers will be both block and chunk validators. let block_and_chunk_producers = (0..NUM_BLOCK_AND_CHUNK_PRODUCERS).map(|idx| accounts[idx].as_str()).collect_vec(); @@ -223,22 +226,25 @@ fn setup(accounts: &Vec) -> TestLoopEnv { let clients = accounts.iter().take(NUM_VALIDATORS).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(GENESIS_HEIGHT) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_single() - .transaction_validity_period(1000) - .epoch_length(EPOCH_LENGTH) - .validators_desired_roles(&block_and_chunk_producers, &chunk_validators_only) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let shard_layout = ShardLayout::single_shard(); + let validators_spec = + ValidatorsSpec::desired_roles(&block_and_chunk_producers, &chunk_validators_only); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length: EPOCH_LENGTH, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| { + genesis_builder.genesis_height(GENESIS_HEIGHT).transaction_validity_period(1000) + }, + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); let env = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/create_delete_account.rs b/integration-tests/src/test_loop/tests/create_delete_account.rs index 336eee380ee..e3a55cc3089 100644 --- a/integration-tests/src/test_loop/tests/create_delete_account.rs +++ b/integration-tests/src/test_loop/tests/create_delete_account.rs @@ -1,10 +1,14 @@ use itertools::Itertools; use near_async::futures::{DelayedActionRunner, DelayedActionRunnerExt}; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::client_actor::ClientActorInner; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; @@ -59,7 +63,6 @@ fn test_create_delete_account() { init_test_logger(); let builder = TestLoopBuilder::new(); - let initial_balance = 1_000_000 * ONE_NEAR; let epoch_length = 5; let accounts = (0..5).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); @@ -74,15 +77,17 @@ fn test_create_delete_account() { assert!(tmp.is_empty()); // Build test environment. - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .epoch_length(epoch_length) - .validators_desired_roles(&producers, &validators); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout: ShardLayout::single_shard(), + validators_spec: ValidatorsSpec::desired_roles(&producers, &validators), + accounts: &accounts, + }, + |genesis_builder| genesis_builder, + |epoch_config_builder| epoch_config_builder, + ); let mut env = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/epoch_sync.rs b/integration-tests/src/test_loop/tests/epoch_sync.rs index 58ea84e5a57..6752794052e 100644 --- a/integration-tests/src/test_loop/tests/epoch_sync.rs +++ b/integration-tests/src/test_loop/tests/epoch_sync.rs @@ -1,18 +1,21 @@ use itertools::Itertools; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_chain_configs::{Genesis, GenesisConfig}; use near_client::test_utils::test_loop::ClientQueries; use near_o11y::testonly::init_test_logger; use near_primitives::epoch_manager::EpochConfigStore; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::{AccountId, BlockHeightDelta}; +use near_primitives::version::PROTOCOL_VERSION; use near_store::{DBCol, Store}; use tempfile::TempDir; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::transactions::{execute_money_transfers, BalanceMismatchError}; -use crate::test_loop::utils::ONE_NEAR; use near_async::messaging::CanSend; use near_chain::{ChainStore, ChainStoreAccess}; use near_client::sync::epoch::EpochSync; @@ -40,27 +43,32 @@ fn setup_initial_blockchain( ) -> TestNetworkSetup { let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let clients = accounts.iter().take(num_clients).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(transaction_validity_period) - .epoch_length(10) - .validators_desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = + ValidatorsSpec::desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| { + genesis_builder + .genesis_height(10000) + .transaction_validity_period(transaction_validity_period) + }, + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder .genesis(genesis.clone()) diff --git a/integration-tests/src/test_loop/tests/fix_min_stake_ratio.rs b/integration-tests/src/test_loop/tests/fix_min_stake_ratio.rs index cf9b7921a3e..4bc77b452f2 100644 --- a/integration-tests/src/test_loop/tests/fix_min_stake_ratio.rs +++ b/integration-tests/src/test_loop/tests/fix_min_stake_ratio.rs @@ -6,7 +6,7 @@ use itertools::Itertools; use near_async::messaging::SendAsync; use near_async::test_loop::data::TestLoopData; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{TestGenesisBuilder, ValidatorsSpec}; use near_network::client::ProcessTxRequest; use near_o11y::testonly::init_test_logger; use near_primitives::epoch_manager::EpochConfigStore; @@ -70,22 +70,20 @@ fn slow_test_fix_min_stake_ratio() { let shard_layout = epoch_config_store.get_config(genesis_protocol_version).as_ref().shard_layout.clone(); + let validators_spec = ValidatorsSpec::raw(validators, 1, 1, 2); // Create chain with version before FixMinStakeRatio was enabled. // Check that the small validator is not included in the validator set. - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .genesis_time_from_clock(&builder.clock()) .shard_layout(shard_layout) .protocol_version(genesis_protocol_version) .epoch_length(epoch_length) - .validators_raw(validators, 1, 1, 2) + .validators_spec(validators_spec) // Disable validator rewards. - .max_inflation_rate(Rational32::new(0, 1)); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, _) = genesis_builder.build(); + .max_inflation_rate(Rational32::new(0, 1)) + .add_user_accounts_simple(&accounts, initial_balance) + .build(); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/fix_stake_threshold.rs b/integration-tests/src/test_loop/tests/fix_stake_threshold.rs index 237ad758a36..89c25b43e50 100644 --- a/integration-tests/src/test_loop/tests/fix_stake_threshold.rs +++ b/integration-tests/src/test_loop/tests/fix_stake_threshold.rs @@ -6,6 +6,7 @@ use itertools::Itertools; use near_async::test_loop::data::TestLoopData; use near_async::time::Duration; use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::ValidatorsSpec; use near_o11y::testonly::init_test_logger; use near_primitives::epoch_manager::EpochConfigStore; use near_primitives::num_rational::Rational32; @@ -22,7 +23,7 @@ fn slow_test_fix_validator_stake_threshold() { let test_loop_builder = TestLoopBuilder::new(); let epoch_config_store = EpochConfigStore::for_chain_id("mainnet", None).unwrap(); let epoch_length = 10; - + let initial_balance = 1_000_000 * ONE_NEAR; let accounts = (0..6).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let clients = accounts.iter().cloned().collect_vec(); @@ -43,20 +44,17 @@ fn slow_test_fix_validator_stake_threshold() { amount: 100_000 * ONE_NEAR, }, ]; + let validators_spec = ValidatorsSpec::raw(validators, 3, 3, 3); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .protocol_version(protocol_version) .genesis_time_from_clock(&test_loop_builder.clock()) .shard_layout(epoch_config_store.get_config(protocol_version).shard_layout.clone()) .epoch_length(epoch_length) - .validators_raw(validators, 3, 3, 3) - .max_inflation_rate(Rational32::new(0, 1)); - let initial_balance = 1_000_000 * ONE_NEAR; - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, _) = genesis_builder.build(); + .validators_spec(validators_spec) + .max_inflation_rate(Rational32::new(0, 1)) + .add_user_accounts_simple(&accounts, initial_balance) + .build(); let TestLoopEnv { mut test_loop, datas: node_data, tempdir } = test_loop_builder .genesis(genesis) diff --git a/integration-tests/src/test_loop/tests/in_memory_tries.rs b/integration-tests/src/test_loop/tests/in_memory_tries.rs index d5294500585..0c27cbb2429 100644 --- a/integration-tests/src/test_loop/tests/in_memory_tries.rs +++ b/integration-tests/src/test_loop/tests/in_memory_tries.rs @@ -1,14 +1,17 @@ use itertools::Itertools; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::test_utils::test_loop::ClientQueries; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::transactions::execute_money_transfers; -use crate::test_loop::utils::ONE_NEAR; /// Runs chain with sequence of chunks with empty state changes, long enough to /// cover 5 epochs which is default GC period. @@ -25,28 +28,28 @@ fn test_load_memtrie_after_empty_chunks() { let num_accounts = 3; let num_clients = 2; let epoch_length = 5; - let initial_balance = 10000 * ONE_NEAR; + // Set 2 shards, first of which doesn't have any validators. + let shard_layout = ShardLayout::simple_v1(&["account1"]); let accounts = (num_accounts - num_clients..num_accounts) .map(|i| format!("account{}", i).parse().unwrap()) .collect::>(); let client_accounts = accounts.iter().take(num_clients).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - // Set 2 shards, first of which doesn't have any validators. - .shard_layout_simple_v1(&["account1"]) - .transaction_validity_period(1000) - .epoch_length(epoch_length) - .validators_desired_roles(&client_accounts.iter().map(|t| t.as_str()).collect_vec(), &[]); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); - let shard_layout = genesis.config.shard_layout.clone(); + let validators_spec = ValidatorsSpec::desired_roles( + &client_accounts.iter().map(|t| t.as_str()).collect_vec(), + &[], + ); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout: shard_layout.clone(), + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| epoch_config_builder, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder .genesis(genesis) diff --git a/integration-tests/src/test_loop/tests/multinode_stateless_validators.rs b/integration-tests/src/test_loop/tests/multinode_stateless_validators.rs index bfa9dcc45fe..ecefa11b146 100644 --- a/integration-tests/src/test_loop/tests/multinode_stateless_validators.rs +++ b/integration-tests/src/test_loop/tests/multinode_stateless_validators.rs @@ -3,16 +3,19 @@ use std::collections::HashMap; use itertools::Itertools; use near_async::messaging::Handler; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::{GetValidatorInfo, ViewClientActorInner}; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::{AccountId, EpochId, EpochReference}; +use near_primitives::version::PROTOCOL_VERSION; use near_primitives::views::{CurrentEpochValidatorInfo, EpochValidatorInfo}; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::transactions::execute_money_transfers; -use crate::test_loop::utils::ONE_NEAR; const NUM_ACCOUNTS: usize = 20; const NUM_SHARDS: u64 = 4; @@ -27,7 +30,6 @@ fn slow_test_stateless_validators_with_multi_test_loop() { init_test_logger(); let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = (0..NUM_ACCOUNTS) .map(|i| format!("account{}", i).parse().unwrap()) .collect::>(); @@ -41,22 +43,23 @@ fn slow_test_stateless_validators_with_multi_test_loop() { .collect_vec(); let clients = accounts.iter().take(NUM_VALIDATORS).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(1000) - .epoch_length(EPOCH_LENGTH) - .validators_desired_roles(&block_and_chunk_producers, &chunk_validators_only) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = + ValidatorsSpec::desired_roles(&block_and_chunk_producers, &chunk_validators_only); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length: EPOCH_LENGTH, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/multinode_test_loop_example.rs b/integration-tests/src/test_loop/tests/multinode_test_loop_example.rs index 89bd24d5f1d..731a1c5352d 100644 --- a/integration-tests/src/test_loop/tests/multinode_test_loop_example.rs +++ b/integration-tests/src/test_loop/tests/multinode_test_loop_example.rs @@ -1,14 +1,17 @@ use itertools::Itertools; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::test_utils::test_loop::ClientQueries; use near_o11y::testonly::init_test_logger; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::transactions::execute_money_transfers; -use crate::test_loop::utils::ONE_NEAR; const NUM_CLIENTS: usize = 4; @@ -17,27 +20,28 @@ fn slow_test_client_with_multi_test_loop() { init_test_logger(); let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let clients = accounts.iter().take(NUM_CLIENTS).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(1000) - .epoch_length(10) - .validators_desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = + ValidatorsSpec::desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build(); diff --git a/integration-tests/src/test_loop/tests/protocol_upgrade.rs b/integration-tests/src/test_loop/tests/protocol_upgrade.rs index d68aa5c2100..c5cb7ee550f 100644 --- a/integration-tests/src/test_loop/tests/protocol_upgrade.rs +++ b/integration-tests/src/test_loop/tests/protocol_upgrade.rs @@ -2,7 +2,9 @@ use aurora_engine_types::BTreeSet; use itertools::Itertools; use near_async::test_loop::data::TestLoopData; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + TestEpochConfigBuilder, TestGenesisBuilder, ValidatorsSpec, +}; use near_o11y::testonly::init_test_logger; use near_primitives::epoch_manager::{EpochConfig, EpochConfigStore}; use near_primitives::shard_layout::ShardLayout; @@ -57,22 +59,24 @@ pub(crate) fn test_protocol_upgrade( let producers = producers.iter().map(|account| account.as_str()).collect_vec(); let validators = validators.iter().map(|account| account.as_str()).collect_vec(); + let validators_spec = ValidatorsSpec::desired_roles(&producers, &validators); let [_rpc_id] = rpcs else { panic!("Expected exactly one rpc node") }; let builder = TestLoopBuilder::new(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .protocol_version(old_protocol) .genesis_time_from_clock(&builder.clock()) .genesis_height(10000) .shard_layout(shard_layout.clone()) .epoch_length(epoch_length) - .validators_desired_roles(&producers, &validators); - for account in accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, genesis_epoch_config_store) = genesis_builder.build(); - let genesis_epoch_info = genesis_epoch_config_store.get_config(old_protocol); + .validators_spec(validators_spec.clone()) + .add_user_accounts_simple(&accounts, initial_balance) + .build(); + let genesis_epoch_info = TestEpochConfigBuilder::new() + .epoch_length(epoch_length) + .shard_layout(shard_layout.clone()) + .validators_spec(validators_spec) + .build(); let mainnet_epoch_config_store = EpochConfigStore::for_chain_id("mainnet", None).unwrap(); let mut old_epoch_config: EpochConfig = diff --git a/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs b/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs index 29be7240707..f1ace7c7ba8 100644 --- a/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs +++ b/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs @@ -6,6 +6,7 @@ use near_async::test_loop::data::TestLoopData; use near_async::time::Duration; use near_chain::{Block, Error, Provenance}; use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::ValidatorsSpec; use near_crypto::InMemorySigner; use near_crypto::KeyType; use near_o11y::testonly::init_test_logger; @@ -49,6 +50,7 @@ fn slow_test_reject_blocks_with_outdated_protocol_version() { let epoch_config_store = EpochConfigStore::for_chain_id("mainnet", None).unwrap(); let epoch_length = 10; + let initial_balance = 1_000_000 * ONE_NEAR; let accounts = (0..5).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let clients = accounts.iter().cloned().collect_vec(); @@ -58,19 +60,16 @@ fn slow_test_reject_blocks_with_outdated_protocol_version() { amount: 62_500 * ONE_NEAR, }]; - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .protocol_version(protocol_version) .genesis_time_from_clock(&test_loop_builder.clock()) .shard_layout(epoch_config_store.get_config(protocol_version).shard_layout.clone()) .epoch_length(epoch_length) - .validators_raw(validators, 3, 3, 3) - .max_inflation_rate(Rational32::new(0, 1)); - let initial_balance = 1_000_000 * ONE_NEAR; - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, _) = genesis_builder.build(); + .validators_spec(ValidatorsSpec::raw(validators, 3, 3, 3)) + .max_inflation_rate(Rational32::new(0, 1)) + .add_user_accounts_simple(&accounts, initial_balance) + .build(); + let TestLoopEnv { mut test_loop, datas: node_data, tempdir } = test_loop_builder .genesis(genesis) .epoch_config_store(epoch_config_store) diff --git a/integration-tests/src/test_loop/tests/resharding_v3.rs b/integration-tests/src/test_loop/tests/resharding_v3.rs index 42be04e0a4c..e0d87a6c243 100644 --- a/integration-tests/src/test_loop/tests/resharding_v3.rs +++ b/integration-tests/src/test_loop/tests/resharding_v3.rs @@ -3,7 +3,7 @@ use itertools::Itertools; use near_async::test_loop::data::{TestLoopData, TestLoopDataHandle}; use near_async::time::Duration; use near_chain::ChainStoreAccess; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{TestGenesisBuilder, ValidatorsSpec}; use near_chain_configs::DEFAULT_GC_NUM_EPOCHS_TO_KEEP; use near_client::Client; use near_o11y::testonly::init_test_logger; @@ -961,24 +961,21 @@ fn test_resharding_v3_base(params: TestReshardingParameters) { (base_protocol_version + 1, Arc::new(epoch_config)), ])); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .genesis_time_from_clock(&builder.clock()) .shard_layout(base_shard_layout) .protocol_version(base_protocol_version) .epoch_length(params.epoch_length) - .validators_desired_roles( + .validators_spec(ValidatorsSpec::desired_roles( ¶ms .block_and_chunk_producers .iter() .map(|account_id| account_id.as_str()) .collect_vec(), &[], - ); - for account in ¶ms.accounts { - genesis_builder.add_user_account_simple(account.clone(), params.initial_balance); - } - let (genesis, _) = genesis_builder.build(); + )) + .add_user_accounts_simple(¶ms.accounts, params.initial_balance) + .build(); if params.track_all_shards { builder = builder.track_all_shards(); diff --git a/integration-tests/src/test_loop/tests/simple_test_loop_example.rs b/integration-tests/src/test_loop/tests/simple_test_loop_example.rs index 2fcbe084a1f..b4a2667dd84 100644 --- a/integration-tests/src/test_loop/tests/simple_test_loop_example.rs +++ b/integration-tests/src/test_loop/tests/simple_test_loop_example.rs @@ -2,7 +2,7 @@ use near_async::messaging::{noop, IntoMultiSender, IntoSender, LateBoundSender}; use near_async::test_loop::TestLoopV2; use near_async::time::Duration; use near_chain::ChainGenesis; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{TestGenesisBuilder, ValidatorsSpec}; use near_chain_configs::{ClientConfig, MutableConfigValue}; use near_chunks::shards_manager_actor::ShardsManagerActor; use near_client::client_actor::ClientActorInner; @@ -14,9 +14,10 @@ use near_epoch_manager::EpochManager; use near_o11y::testonly::init_test_logger; use near_primitives::network::PeerId; +use near_primitives::shard_layout::ShardLayout; use near_primitives::test_utils::create_test_signer; use near_primitives::types::AccountId; -use near_primitives::version::PROTOCOL_UPGRADE_SCHEDULE; +use near_primitives::version::{PROTOCOL_UPGRADE_SCHEDULE, PROTOCOL_VERSION}; use near_store::adapter::StoreAdapter; use crate::test_loop::utils::ONE_NEAR; @@ -44,22 +45,16 @@ fn test_client_with_simple_test_loop() { let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let genesis = TestGenesisBuilder::new() .genesis_time_from_clock(&test_loop.clock()) - .protocol_version_latest() + .protocol_version(PROTOCOL_VERSION) .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) + .shard_layout(ShardLayout::simple_v1(&["account3", "account5", "account7"])) .transaction_validity_period(1000) .epoch_length(10) - .validators_desired_roles(&["account0"], &[]) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, _) = genesis_builder.build(); + .validators_spec(ValidatorsSpec::desired_roles(&["account0"], &[])) + .add_user_accounts_simple(&accounts, initial_balance) + .build(); let store = create_test_store(); initialize_genesis_state(store.clone(), &genesis, None); diff --git a/integration-tests/src/test_loop/tests/state_sync.rs b/integration-tests/src/test_loop/tests/state_sync.rs index 3d2fb557b8b..2c591b5b863 100644 --- a/integration-tests/src/test_loop/tests/state_sync.rs +++ b/integration-tests/src/test_loop/tests/state_sync.rs @@ -1,13 +1,18 @@ use near_async::messaging::{Handler, SendAsync}; use near_async::test_loop::TestLoopV2; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + TestEpochConfigBuilder, TestGenesisBuilder, ValidatorsSpec, +}; use near_network::client::{ProcessTxRequest, StateRequestHeader}; use near_o11y::testonly::init_test_logger; +use near_primitives::epoch_manager::EpochConfigStore; use near_primitives::hash::CryptoHash; +use near_primitives::shard_layout::ShardLayout; use near_primitives::test_utils::create_user_test_signer; use near_primitives::transaction::SignedTransaction; use near_primitives::types::{AccountId, AccountInfo, BlockHeightDelta, Nonce, NumSeats, ShardId}; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::{TestData, TestLoopEnv}; @@ -15,7 +20,8 @@ use crate::test_loop::utils::transactions::get_anchor_hash; use crate::test_loop::utils::ONE_NEAR; use itertools::Itertools; -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; +use std::sync::Arc; const EPOCH_LENGTH: BlockHeightDelta = 40; @@ -90,35 +96,45 @@ fn setup_initial_blockchain( let accounts = if generate_shard_accounts { Some(generate_accounts(&boundary_accounts)) } else { None }; - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + let epoch_length = 10; + let shard_layout = + ShardLayout::simple_v1(&boundary_accounts.iter().map(|s| s.as_str()).collect::>()); + let validators_spec = ValidatorsSpec::raw( + validators, + num_block_producer_seats as NumSeats, + num_chunk_producer_seats as NumSeats, + 0, + ); + + let mut genesis_builder = TestGenesisBuilder::new() .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() + .protocol_version(PROTOCOL_VERSION) .genesis_height(10000) - .epoch_length(EPOCH_LENGTH) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&boundary_accounts.iter().map(|s| s.as_str()).collect::>()) + .epoch_length(epoch_length) + .shard_layout(shard_layout.clone()) .transaction_validity_period(1000) - .epoch_length(10) - .validators_raw( - validators, - num_block_producer_seats as NumSeats, - num_chunk_producer_seats as NumSeats, - 0, - ) - // shuffle the shard assignment so that nodes will have to state sync to catch up future tracked shards. - // This part is the only reference to state sync at all in this test, since all we check is that the blockchain - // progresses for a few epochs, meaning that state sync must have been successful. - .shuffle_shard_assignment_for_chunk_producers(true); + .validators_spec(validators_spec.clone()); if let Some(accounts) = accounts.as_ref() { for accounts in accounts.iter() { for (account, _nonce) in accounts.iter() { - genesis_builder.add_user_account_simple(account.clone(), 10000 * ONE_NEAR); + genesis_builder = + genesis_builder.add_user_account_simple(account.clone(), 10000 * ONE_NEAR); } } } - let (genesis, epoch_config_store) = genesis_builder.build(); + let genesis = genesis_builder.build(); + + let epoch_config = TestEpochConfigBuilder::new() + .epoch_length(epoch_length) + .shard_layout(shard_layout) + .validators_spec(validators_spec) + // shuffle the shard assignment so that nodes will have to state sync to catch up future tracked shards. + // This part is the only reference to state sync at all in this test, since all we check is that the blockchain + // progresses for a few epochs, meaning that state sync must have been successful. + .shuffle_shard_assignment_for_chunk_producers(true) + .build(); + let epoch_config_store = + EpochConfigStore::test(BTreeMap::from([(PROTOCOL_VERSION, Arc::new(epoch_config))])); let env = builder .genesis(genesis) diff --git a/integration-tests/src/test_loop/tests/syncing.rs b/integration-tests/src/test_loop/tests/syncing.rs index ac35a55899e..c9136326aa1 100644 --- a/integration-tests/src/test_loop/tests/syncing.rs +++ b/integration-tests/src/test_loop/tests/syncing.rs @@ -1,18 +1,21 @@ use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::transactions::execute_money_transfers; -use crate::test_loop::utils::ONE_NEAR; use itertools::Itertools; use near_async::messaging::CanSend; use near_async::time::Duration; use near_chain::ChainStoreAccess; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::test_utils::test_loop::ClientQueries; use near_client::SetNetworkInfo; use near_network::types::{HighestHeightPeerInfo, NetworkInfo, PeerInfo}; use near_o11y::testonly::init_test_logger; use near_primitives::block::GenesisId; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use near_store::test_utils::create_test_store; const NUM_CLIENTS: usize = 4; @@ -24,27 +27,28 @@ fn slow_test_sync_from_genesis() { init_test_logger(); let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let clients = accounts.iter().take(NUM_CLIENTS).cloned().collect_vec(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(1000) - .epoch_length(10) - .validators_desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = + ValidatorsSpec::desired_roles(&clients.iter().map(|t| t.as_str()).collect_vec(), &[]); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder .genesis(genesis.clone()) diff --git a/integration-tests/src/test_loop/tests/view_requests_to_archival_node.rs b/integration-tests/src/test_loop/tests/view_requests_to_archival_node.rs index 36726034aa7..969c4a1e2ef 100644 --- a/integration-tests/src/test_loop/tests/view_requests_to_archival_node.rs +++ b/integration-tests/src/test_loop/tests/view_requests_to_archival_node.rs @@ -5,7 +5,9 @@ use near_async::messaging::Handler; use near_async::test_loop::data::TestLoopDataHandle; use near_async::test_loop::TestLoopV2; use near_async::time::Duration; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; use near_client::{ GetBlock, GetChunk, GetExecutionOutcomesForBlock, GetProtocolConfig, GetShardChunk, GetStateChanges, GetStateChangesInBlock, GetValidatorInfo, GetValidatorOrdered, @@ -28,7 +30,6 @@ use near_primitives::views::{ use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::{TestData, TestLoopEnv}; use crate::test_loop::utils::transactions::execute_money_transfers; -use crate::test_loop::utils::ONE_NEAR; const NUM_VALIDATORS: usize = 2; const NUM_ACCOUNTS: usize = 20; @@ -49,7 +50,6 @@ fn slow_test_view_requests_to_archival_node() { init_test_logger(); let builder = TestLoopBuilder::new(); - let initial_balance = 10000 * ONE_NEAR; let accounts = (0..NUM_ACCOUNTS) .map(|i| format!("account{}", i).parse().unwrap()) .collect::>(); @@ -64,19 +64,18 @@ fn slow_test_view_requests_to_archival_node() { let archival_clients: HashSet = vec![all_clients[NUM_VALIDATORS].clone()].into_iter().collect(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .genesis_height(GENESIS_HEIGHT) - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .epoch_length(EPOCH_LENGTH) - .validators_desired_roles(&validators, &[]); - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); - let shard_layout = genesis.config.shard_layout.clone(); + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length: EPOCH_LENGTH, + protocol_version: PROTOCOL_VERSION, + shard_layout: shard_layout.clone(), + validators_spec: ValidatorsSpec::desired_roles(&validators, &[]), + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(GENESIS_HEIGHT), + |epoch_config_builder| epoch_config_builder, + ); let TestLoopEnv { mut test_loop, datas: node_datas, tempdir } = builder .genesis(genesis) diff --git a/integration-tests/src/test_loop/utils/setups.rs b/integration-tests/src/test_loop/utils/setups.rs index 97bb16828f0..7ed65a01a41 100644 --- a/integration-tests/src/test_loop/utils/setups.rs +++ b/integration-tests/src/test_loop/utils/setups.rs @@ -2,12 +2,15 @@ //! Using TestLoopBuilder gives a lot of flexibility, but sometimes you just need some basic blockchain. use itertools::Itertools; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, ValidatorsSpec, +}; +use near_primitives::shard_layout::ShardLayout; use near_primitives::types::AccountId; +use near_primitives::version::PROTOCOL_VERSION; use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; -use crate::test_loop::utils::ONE_NEAR; /// 2 producers, 2 validators, 1 rpc node, 4 shards, 20 accounts (account{i}) with 10k NEAR each. pub fn standard_setup_1() -> TestLoopEnv { @@ -17,8 +20,6 @@ pub fn standard_setup_1() -> TestLoopEnv { let num_rpc = 1; let accounts = (0..20).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); - - let initial_balance = 10000 * ONE_NEAR; let clients = accounts.iter().take(num_clients).cloned().collect_vec(); // split the clients into producers, validators, and rpc nodes @@ -32,23 +33,27 @@ pub fn standard_setup_1() -> TestLoopEnv { let validators = validators.iter().map(|account| account.as_str()).collect_vec(); let [_rpc_id] = rpcs else { panic!("Expected exactly one rpc node") }; - let builder = TestLoopBuilder::new(); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&builder.clock()) - .protocol_version_latest() - .genesis_height(10000) - .gas_prices_free() - .gas_limit_one_petagas() - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - .transaction_validity_period(1000) - .epoch_length(10) - .validators_desired_roles(&producers, &validators) - .shuffle_shard_assignment_for_chunk_producers(true); - for account in accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); - - builder.genesis(genesis).epoch_config_store(epoch_config_store).clients(clients).build() + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = ValidatorsSpec::desired_roles(&producers, &validators); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| genesis_builder.genesis_height(10000).transaction_validity_period(1000), + |epoch_config_builder| { + epoch_config_builder.shuffle_shard_assignment_for_chunk_producers(true) + }, + ); + + TestLoopBuilder::new() + .genesis(genesis) + .epoch_config_store(epoch_config_store) + .clients(clients) + .build() } diff --git a/integration-tests/src/tests/client/features/in_memory_tries.rs b/integration-tests/src/tests/client/features/in_memory_tries.rs index 56776d860c5..e03631df9c1 100644 --- a/integration-tests/src/tests/client/features/in_memory_tries.rs +++ b/integration-tests/src/tests/client/features/in_memory_tries.rs @@ -1,7 +1,10 @@ use near_async::messaging::CanSend; use near_async::time::{FakeClock, Utc}; use near_chain::{Block, Provenance}; -use near_chain_configs::test_genesis::TestGenesisBuilder; +use near_chain_configs::test_genesis::{ + build_genesis_and_epoch_config_store, GenesisAndEpochConfigParams, TestGenesisBuilder, + ValidatorsSpec, +}; use near_chunks::shards_manager_actor::CHUNK_REQUEST_SWITCH_TO_FULL_FETCH; use near_chunks::test_utils::ShardsManagerResendChunkRequests; @@ -10,10 +13,12 @@ use near_client::ProcessTxResponse; use near_o11y::testonly::init_test_logger; use near_primitives::block::Tip; +use near_primitives::shard_layout::ShardLayout; use near_primitives::test_utils::create_user_test_signer; use near_primitives::transaction::SignedTransaction; use near_primitives::types::EpochId; +use near_primitives::version::PROTOCOL_VERSION; use near_primitives_core::types::AccountId; use near_store::test_utils::create_test_store; @@ -29,45 +34,26 @@ const ONE_NEAR: u128 = 1_000_000_000_000_000_000_000_000; fn slow_test_in_memory_trie_node_consistency() { // Recommended to run with RUST_LOG=memtrie=debug,chunks=error,info init_test_logger(); - let initial_balance = 10000 * ONE_NEAR; + let initial_balance = 1000000 * ONE_NEAR; let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); let mut clock = FakeClock::new(Utc::UNIX_EPOCH); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder + + let epoch_length = 10000; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = ValidatorsSpec::desired_roles(&["account0", "account1"], &[]); + + let genesis = TestGenesisBuilder::new() .genesis_time_from_clock(&clock.clock()) - // Use the latest protocol version. Otherwise, the version may be too - // old that e.g. blocks don't even store previous heights. - .protocol_version_latest() - // We'll test with 4 shards. This can be any number, but we want to test - // the case when some shards are loaded into memory and others are not. - // We pick the boundaries so that each shard would get some transactions. - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - // We're going to send NEAR between accounts and then assert at the end - // that these transactions have been processed correctly, so here we set - // the gas price to 0 so that we don't have to calculate gas cost. + .protocol_version(PROTOCOL_VERSION) + .epoch_length(epoch_length) + .shard_layout(shard_layout) + .validators_spec(validators_spec) + .add_user_accounts_simple(&accounts, initial_balance) .gas_prices_free() - // Set the block gas limit high enough so we don't have to worry about - // transactions being throttled. .gas_limit_one_petagas() - // Set the validity period high enough so even if a transaction gets - // included a few blocks later it won't be rejected. .transaction_validity_period(100) - // Make two validators. In this test we don't care about validators but - // the TestEnv framework works best if all clients are validators. So - // since we are using two clients, make two validators. - .validators_desired_roles(&["account0", "account1"], &[]) - // We don't care about epoch transitions in this test, and epoch - // transitions means validator selection, which can kick out validators - // (due to our test purposefully skipping blocks to create forks), and - // that's annoying to deal with. So set this to a high value to stay - // within a single epoch. - .epoch_length(10000); - - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, _) = genesis_builder.build(); + .build(); // Create two stores, one for each node. We'll be reusing the stores later // to emulate node restarts. @@ -429,7 +415,7 @@ fn num_memtrie_roots(env: &TestEnv, client_id: usize, shard: ShardUId) -> Option fn test_in_memory_trie_consistency_with_state_sync_base_case(track_all_shards: bool) { // Recommended to run with RUST_LOG=memtrie=debug,chunks=error,info init_test_logger(); - let initial_balance = 10000 * ONE_NEAR; + let initial_balance = 1000000 * ONE_NEAR; let accounts = (0..100).map(|i| format!("account{}", i).parse().unwrap()).collect::>(); // We'll test with 4 shards. This can be any number, but we want to test @@ -439,42 +425,33 @@ fn test_in_memory_trie_consistency_with_state_sync_base_case(track_all_shards: b const NUM_VALIDATORS: usize = NUM_VALIDATORS_PER_SHARD * 4; let mut clock = FakeClock::new(Utc::UNIX_EPOCH); - let mut genesis_builder = TestGenesisBuilder::new(); - genesis_builder - .genesis_time_from_clock(&clock.clock()) - .genesis_height(10000) - // Use the latest protocol version. Otherwise, the version may be too - // old that e.g. blocks don't even store previous heights. - .protocol_version_latest() - // We'll test with 4 shards. This can be any number, but we want to test - // the case when some shards are loaded into memory and others are not. - // We pick the boundaries so that each shard would get some transactions. - .shard_layout_simple_v1(&["account3", "account5", "account7"]) - // We're going to send NEAR between accounts and then assert at the end - // that these transactions have been processed correctly, so here we set - // the gas price to 0 so that we don't have to calculate gas cost. - .gas_prices_free() - // Set the block gas limit high enough so we don't have to worry about - // transactions being throttled. - .gas_limit_one_petagas() - // Set the validity period high enough so even if a transaction gets - // included a few blocks later it won't be rejected. - .transaction_validity_period(1000) - // Make NUM_VALIDATORS validators. - .validators_desired_roles( - &accounts[0..NUM_VALIDATORS].iter().map(|a| a.as_str()).collect::>(), - &[], - ) - .minimum_validators_per_shard(NUM_VALIDATORS_PER_SHARD as u64) - // Disable kickouts or else the short epoch length will kick out some validators. - .kickouts_disabled() - // Test epoch transitions. - .epoch_length(10); - - for account in &accounts { - genesis_builder.add_user_account_simple(account.clone(), initial_balance); - } - let (genesis, epoch_config_store) = genesis_builder.build(); + + let epoch_length = 10; + let shard_layout = ShardLayout::simple_v1(&["account3", "account5", "account7"]); + let validators_spec = ValidatorsSpec::desired_roles( + &accounts[0..NUM_VALIDATORS].iter().map(|a| a.as_str()).collect::>(), + &[], + ); + + let (genesis, epoch_config_store) = build_genesis_and_epoch_config_store( + GenesisAndEpochConfigParams { + epoch_length, + protocol_version: PROTOCOL_VERSION, + shard_layout, + validators_spec, + accounts: &accounts, + }, + |genesis_builder| { + genesis_builder + .genesis_time_from_clock(&clock.clock()) + .genesis_height(10000) + .transaction_validity_period(1000) + }, + |epoch_config_builder| { + epoch_config_builder.minimum_validators_per_shard(NUM_VALIDATORS_PER_SHARD as u64) + }, + ); + let stores = (0..NUM_VALIDATORS).map(|_| create_test_store()).collect::>(); let mut env = TestEnv::builder(&genesis.config) .clock(clock.clock())