diff --git a/core/primitives-core/src/version.rs b/core/primitives-core/src/version.rs index ce12dcbe518..437f90e57a1 100644 --- a/core/primitives-core/src/version.rs +++ b/core/primitives-core/src/version.rs @@ -135,6 +135,12 @@ pub enum ProtocolFeature { /// Enables stateless validation which is introduced in https://github.com/near/NEPs/pull/509 StatelessValidationV0, EthImplicitAccounts, + /// Enables yield execution which is introduced in https://github.com/near/NEPs/pull/519 + YieldExecution, + + /// Protocol version reserved for use in resharding tests. This is necessary because stateless + /// validation is enabled in nightly and it is incompatible with resharding. + SimpleNightshadeTestonly, // Stateless validation: lower block and chunk validator kickout percent from 90 to 50. LowerValidatorKickoutPercentForDebugging, @@ -196,6 +202,13 @@ impl ProtocolFeature { #[cfg(not(feature = "statelessnet_protocol"))] ProtocolFeature::SimpleNightshadeV3 => 65, + // Yield execution is a nightly feature. However, resharding tests need to be able to + // pick a protocol version which has yield execution and *not* stateless validation. + ProtocolFeature::YieldExecution => 78, + // This protocol version is reserved for use in resharding tests. It can be ignored + // otherwise; protocol versions greater than it will still have the production layout. + ProtocolFeature::SimpleNightshadeTestonly => 79, + // StatelessNet features ProtocolFeature::StatelessValidationV0 => 80, ProtocolFeature::LowerValidatorKickoutPercentForDebugging => 81, diff --git a/core/primitives/src/epoch_manager.rs b/core/primitives/src/epoch_manager.rs index 22d54ddfaa1..fecc578cfcc 100644 --- a/core/primitives/src/epoch_manager.rs +++ b/core/primitives/src/epoch_manager.rs @@ -14,6 +14,9 @@ use near_primitives_core::types::BlockHeight; use smart_default::SmartDefault; use std::collections::{BTreeMap, HashMap}; +#[cfg(feature = "nightly")] +use crate::version::ProtocolFeature; + pub type RngSeed = [u8; 32]; pub const AGGREGATOR_KEY: &[u8] = b"AGGREGATOR"; @@ -177,6 +180,17 @@ impl AllEpochConfig { } fn config_nightshade(config: &mut EpochConfig, protocol_version: ProtocolVersion) { + // Unlike the other checks, this one is for strict equality. The testonly nightshade layout + // is specifically used in resharding tests, not for any other protocol versions. + #[cfg(feature = "nightly")] + if protocol_version == ProtocolFeature::SimpleNightshadeTestonly.protocol_version() { + Self::config_nightshade_impl( + config, + ShardLayout::get_simple_nightshade_layout_testonly(), + ); + return; + } + if checked_feature!("stable", SimpleNightshadeV3, protocol_version) { Self::config_nightshade_impl(config, ShardLayout::get_simple_nightshade_layout_v3()); return; diff --git a/core/primitives/src/shard_layout.rs b/core/primitives/src/shard_layout.rs index b8ecb68a9c0..a08ffa78b1f 100644 --- a/core/primitives/src/shard_layout.rs +++ b/core/primitives/src/shard_layout.rs @@ -185,6 +185,27 @@ impl ShardLayout { ) } + /// This layout is used only in resharding tests. It allows testing of any features which were + /// introduced after the last layout upgrade in production. Currently it is built on top of V3. + #[cfg(feature = "nightly")] + pub fn get_simple_nightshade_layout_testonly() -> ShardLayout { + ShardLayout::v1( + vec![ + "aurora", + "aurora-0", + "game.hot.tg", + "kkuuue2akv_1630967379.near", + "nightly", + "tge-lockup.sweat", + ] + .into_iter() + .map(|s| s.parse().unwrap()) + .collect(), + Some(vec![vec![0], vec![1], vec![2], vec![3], vec![4, 5], vec![6]]), + 4, + ) + } + /// Given a parent shard id, return the shard uids for the shards in the current shard layout that /// are split from this parent shard. If this shard layout has no parent shard layout, return None pub fn get_children_shards_uids(&self, parent_shard_id: ShardId) -> Option> { diff --git a/integration-tests/src/tests/client/resharding.rs b/integration-tests/src/tests/client/resharding.rs index e315e2cca4a..95d00f1e2b8 100644 --- a/integration-tests/src/tests/client/resharding.rs +++ b/integration-tests/src/tests/client/resharding.rs @@ -8,7 +8,6 @@ use near_client::test_utils::{run_catchup, TestEnv}; use near_client::{Client, ProcessTxResponse}; use near_crypto::{InMemorySigner, KeyType, Signer}; use near_o11y::testonly::init_test_logger; -use near_parameters::RuntimeConfig; use near_primitives::account::id::AccountId; use near_primitives::block::{Block, Tip}; use near_primitives::epoch_manager::{AllEpochConfig, AllEpochConfigTestOverrides, EpochConfig}; @@ -39,6 +38,9 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::sync::Arc; use tracing::debug; +#[cfg(feature = "nightly")] +use near_parameters::RuntimeConfig; + const SIMPLE_NIGHTSHADE_PROTOCOL_VERSION: ProtocolVersion = ProtocolFeature::SimpleNightshade.protocol_version(); @@ -49,6 +51,10 @@ const SIMPLE_NIGHTSHADE_V2_PROTOCOL_VERSION: ProtocolVersion = const SIMPLE_NIGHTSHADE_V3_PROTOCOL_VERSION: ProtocolVersion = ProtocolFeature::SimpleNightshadeV3.protocol_version(); +#[cfg(feature = "nightly")] +const SIMPLE_NIGHTSHADE_TESTONLY_PROTOCOL_VERSION: ProtocolVersion = + ProtocolFeature::SimpleNightshadeTestonly.protocol_version(); + const P_CATCHUP: f64 = 0.2; #[derive(Clone, Copy)] @@ -60,6 +66,9 @@ enum ReshardingType { // In the V2->V3 resharding outgoing receipts are reassigned to lowest index child. #[cfg(not(feature = "statelessnet_protocol"))] V3, + // In V3->TESTONLY resharding outgoing receipts are reassigned to lowest index child. + #[cfg(feature = "nightly")] + TESTONLY, } fn get_target_protocol_version(resharding_type: &ReshardingType) -> ProtocolVersion { @@ -68,16 +77,13 @@ fn get_target_protocol_version(resharding_type: &ReshardingType) -> ProtocolVers ReshardingType::V2 => SIMPLE_NIGHTSHADE_V2_PROTOCOL_VERSION, #[cfg(not(feature = "statelessnet_protocol"))] ReshardingType::V3 => SIMPLE_NIGHTSHADE_V3_PROTOCOL_VERSION, + #[cfg(feature = "nightly")] + ReshardingType::TESTONLY => SIMPLE_NIGHTSHADE_TESTONLY_PROTOCOL_VERSION, } } fn get_genesis_protocol_version(resharding_type: &ReshardingType) -> ProtocolVersion { - match resharding_type { - ReshardingType::V1 => SIMPLE_NIGHTSHADE_PROTOCOL_VERSION - 1, - ReshardingType::V2 => SIMPLE_NIGHTSHADE_V2_PROTOCOL_VERSION - 1, - #[cfg(not(feature = "statelessnet_protocol"))] - ReshardingType::V3 => SIMPLE_NIGHTSHADE_V3_PROTOCOL_VERSION - 1, - } + get_target_protocol_version(resharding_type) - 1 } fn get_parent_shard_uids(resharding_type: &ReshardingType) -> Vec { @@ -86,6 +92,8 @@ fn get_parent_shard_uids(resharding_type: &ReshardingType) -> Vec { ReshardingType::V2 => ShardLayout::get_simple_nightshade_layout(), #[cfg(not(feature = "statelessnet_protocol"))] ReshardingType::V3 => ShardLayout::get_simple_nightshade_layout_v2(), + #[cfg(feature = "nightly")] + ReshardingType::TESTONLY => ShardLayout::get_simple_nightshade_layout_v3(), }; shard_layout.shard_uids().collect() } @@ -102,6 +110,8 @@ fn get_expected_shards_num( ReshardingType::V2 => 4, #[cfg(not(feature = "statelessnet_protocol"))] ReshardingType::V3 => 5, + #[cfg(feature = "nightly")] + ReshardingType::TESTONLY => 6, } } else { match resharding_type { @@ -109,6 +119,8 @@ fn get_expected_shards_num( ReshardingType::V2 => 5, #[cfg(not(feature = "statelessnet_protocol"))] ReshardingType::V3 => 6, + #[cfg(feature = "nightly")] + ReshardingType::TESTONLY => 7, } } } @@ -829,6 +841,17 @@ fn check_outgoing_receipts_reassigned_impl( assert!(outgoing_receipts.is_empty()); } } + #[cfg(feature = "nightly")] + ReshardingType::TESTONLY => { + // In V3->TESTONLY resharding the outgoing receipts should be reassigned + // to the lowest index child of the parent shard. + // We can't directly check that here but we can check that the + // non-lowest-index shards are not assigned any receipts. + // We check elsewhere that no receipts are lost so this should be sufficient. + if shard_id == 5 { + assert!(outgoing_receipts.is_empty()); + } + } } } @@ -1488,6 +1511,7 @@ fn test_shard_layout_upgrade_cross_contract_calls_v3_seed_44() { test_shard_layout_upgrade_cross_contract_calls_impl(ReshardingType::V3, 44); } +#[cfg(feature = "nightly")] fn generate_yield_create_tx( account_id: &AccountId, callback_method_name: String, @@ -1512,6 +1536,7 @@ fn generate_yield_create_tx( ) } +#[cfg(feature = "nightly")] fn setup_test_env_with_promise_yield_txs( test_env: &mut TestReshardingEnv, epoch_length: u64, @@ -1583,6 +1608,7 @@ fn setup_test_env_with_promise_yield_txs( } // Test delivery of promise yield timeouts +#[cfg(feature = "nightly")] fn test_shard_layout_upgrade_promise_yield_impl(resharding_type: ReshardingType, rng_seed: u64) { init_test_logger(); @@ -1620,20 +1646,10 @@ fn test_shard_layout_upgrade_promise_yield_impl(resharding_type: ReshardingType, test_env.check_resharding_artifacts(0); } +#[cfg(feature = "nightly")] #[test] -fn test_shard_layout_upgrade_promise_yield_v1() { - test_shard_layout_upgrade_promise_yield_impl(ReshardingType::V1, 42); -} - -#[test] -fn test_shard_layout_upgrade_promise_yield_v2() { - test_shard_layout_upgrade_promise_yield_impl(ReshardingType::V2, 42); -} - -#[cfg(not(feature = "statelessnet_protocol"))] -#[test] -fn test_shard_layout_upgrade_promise_yield_v3() { - test_shard_layout_upgrade_promise_yield_impl(ReshardingType::V3, 42); +fn test_shard_layout_upgrade_promise_yield() { + test_shard_layout_upgrade_promise_yield_impl(ReshardingType::TESTONLY, 42); } fn test_shard_layout_upgrade_incoming_receipts_impl( @@ -1965,13 +1981,13 @@ fn test_shard_layout_upgrade_error_handling_impl( } // corrupt the state snapshot if available to make resharding fail - currupt_state_snapshot(&test_env); + corrupt_state_snapshot(&test_env); } assert!(false, "no error was recorded, something is wrong in error handling"); } -fn currupt_state_snapshot(test_env: &TestReshardingEnv) { +fn corrupt_state_snapshot(test_env: &TestReshardingEnv) { let tries = test_env.env.clients[0].runtime_adapter.get_tries(); let Ok(snapshot_hash) = tries.get_state_snapshot_hash() else { return }; let (store, flat_storage_manager) = tries.get_state_snapshot(&snapshot_hash).unwrap();