From 09022cade5658989e34bfc73e315a197db9057ff Mon Sep 17 00:00:00 2001 From: Waclaw Banasik Date: Fri, 24 Jan 2025 15:39:52 +0000 Subject: [PATCH] feat(resharding) - Stabilize Resharding V3 (#12792) # Feature to stabilize This PR stabilizes Resharding V3. It introduces a new implementation for resharding and two new shard layouts for the production networks. # Context - NEP: https://github.com/near/NEPs/pull/568 - Implementation: https://github.com/near/nearcore/issues/11881 # Testing and QA This feature was extensively tested in unit tests, testloop tests and in forknet. # Checklist - [ ] Link to nightly nayduck run https://nayduck.nearone.org/#/run/1142 - [x] Update CHANGELOG.md to include this protocol feature in the `Unreleased` section. --- CHANGELOG.md | 9 +- chain/chain/src/tests/simple_chain.rs | 4 +- chain/epoch-manager/src/lib.rs | 9 +- .../jsonrpc-tests/res/genesis_config.json | 4 +- core/primitives-core/src/version.rs | 30 ++--- .../res/epoch_configs/mainnet/143.json | 80 ++++++++++--- .../mainnet/{100.json => 75.json} | 77 ++++++++----- .../mainnet/{101.json => 76.json} | 82 ++++++++++---- .../res/epoch_configs/testnet/143.json | 80 ++++++++++--- .../testnet/{100.json => 75.json} | 77 ++++++++----- .../testnet/{101.json => 76.json} | 82 ++++++++++---- core/primitives/src/epoch_manager.rs | 37 +++--- core/primitives/src/shard_layout.rs | 106 ++++++++++++++++-- cspell.json | 2 + .../test_loop/tests/fix_stake_threshold.rs | 33 ++++-- .../test_loop/tests/reject_outdated_blocks.rs | 12 +- pytest/tests/sanity/upgradable.py | 35 +++++- 17 files changed, 568 insertions(+), 191 deletions(-) rename core/primitives/res/epoch_configs/mainnet/{100.json => 75.json} (66%) rename core/primitives/res/epoch_configs/mainnet/{101.json => 76.json} (60%) rename core/primitives/res/epoch_configs/testnet/{100.json => 75.json} (66%) rename core/primitives/res/epoch_configs/testnet/{101.json => 76.json} (60%) diff --git a/CHANGELOG.md b/CHANGELOG.md index c919437a8ed..0196b4b9c2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,10 +6,15 @@ * Add cross-shard bandwidth scheduler which manages transferring receipts between shards, enabling higher throughput of cross-shard receipts and better horizontal scalability. NEP-584 (https://github.com/near/NEPs/pull/584) +* Resharding V3 - a new implementation for resharding and two new shard layouts + for the production networks. + NEP-568 (https://github.com/near/NEPs/pull/568) ### Non-protocol Changes * Parallelize transaction validation (including signature checks) before `verify_and_charge_transaction`, significantly improving throughput for transaction processing on the nodes. [#12654](https://github.com/near/nearcore/pull/12654) +* Current Epoch State Sync - Moves the sync point from the previous epoch to the + current epoch. [#12102](https://github.com/near/nearcore/pull/12102) ## 2.4.0 @@ -225,7 +230,7 @@ to pay for the storage of their accounts. * `/debug` page now has client_config linked. You can also check your client_config directly at /debug/client_config [#8400](https://github.com/near/nearcore/pull/8400) -* Added cold store loop - a background thread that copies data from hot to cold storage and a new json rpc endpoing - split_storage_info - that +* Added cold store loop - a background thread that copies data from hot to cold storage and a new json rpc endpoint - split_storage_info - that exposes debug info about the split storage. [#8432](https://github.com/near/nearcore/pull/8432) * `ClientConfig` can be updated while the node is running. @@ -443,7 +448,7 @@ to pay for the storage of their accounts. ### Protocol Changes * Enable access key nonce range for implicit accounts to prevent tx hash collisions. -* Upgraded our version of pwasm-utils to 0.18 -- the old one severely undercounted stack usage in some cases. +* Upgraded our version of pwasm-utils to 0.18 -- the old one severely under-counted stack usage in some cases. ### Non-protocol Changes diff --git a/chain/chain/src/tests/simple_chain.rs b/chain/chain/src/tests/simple_chain.rs index c903a8de728..b5932d6787d 100644 --- a/chain/chain/src/tests/simple_chain.rs +++ b/chain/chain/src/tests/simple_chain.rs @@ -35,7 +35,7 @@ fn build_chain() { if cfg!(feature = "nightly") { insta::assert_snapshot!(hash, @"GARF4HBtQJ41quFA9fvjHpbVYT4o15syhL3FkH1o7poT"); } else { - insta::assert_snapshot!(hash, @"3JFsPBWs2CmNmvDD49ytuk26H6d4gryBueLBgeD2YojF"); + insta::assert_snapshot!(hash, @"3e2u5p2hUijQd7o5Dg1pK9QAHGZ9uCK19KDV86TJW78f"); } for i in 1..5 { @@ -53,7 +53,7 @@ fn build_chain() { if cfg!(feature = "nightly") { insta::assert_snapshot!(hash, @"HiXuBfW5Xd6e8ZTbMhwtPEXeZxe7macc8DvaWryNdvcf"); } else { - insta::assert_snapshot!(hash, @"5pEwiJcPbEExts9j2fmVSLUYCVRYHbhMDiyaa1LqpxcU"); + insta::assert_snapshot!(hash, @"Gh5KqeboPbLh2ZwTqQLY2n5FQdPasFAEkPVfnM66LGjn"); } } diff --git a/chain/epoch-manager/src/lib.rs b/chain/epoch-manager/src/lib.rs index e861e25c3c5..cdd52594bde 100644 --- a/chain/epoch-manager/src/lib.rs +++ b/chain/epoch-manager/src/lib.rs @@ -1293,9 +1293,16 @@ impl EpochManager { let next_epoch_id = self.get_next_epoch_id_from_prev_block(parent_hash)?; if self.will_shard_layout_change(parent_hash)? { let shard_layout = self.get_shard_layout(&next_epoch_id)?; + // The expect below may be triggered when the protocol version + // changes by multiple versions at once and multiple shard layout + // changes are captured. In this case the shards from the original + // shard layout are not valid parents in the final shard layout. + // + // This typically occurs in tests that are pegged to start at a + // certain protocol version and then upgrade to stable. let split_shards = shard_layout .get_children_shards_ids(shard_id) - .expect("all shard layouts expect the first one must have a split map"); + .unwrap_or_else(|| panic!("all shard layouts expect the first one must have a split map, shard_id={shard_id}, shard_layout={shard_layout:?}")); for next_shard_id in split_shards { if self.cares_about_shard_in_epoch(&next_epoch_id, account_id, next_shard_id)? { return Ok(true); diff --git a/chain/jsonrpc/jsonrpc-tests/res/genesis_config.json b/chain/jsonrpc/jsonrpc-tests/res/genesis_config.json index 3b50d4b11d5..8bfadbb803f 100644 --- a/chain/jsonrpc/jsonrpc-tests/res/genesis_config.json +++ b/chain/jsonrpc/jsonrpc-tests/res/genesis_config.json @@ -1,5 +1,5 @@ { - "protocol_version": 74, + "protocol_version": 76, "genesis_time": "1970-01-01T00:00:00.000000000Z", "chain_id": "sample", "genesis_height": 0, @@ -86,4 +86,4 @@ "num_chunk_validator_seats": 300, "chunk_producer_assignment_changes_limit": 5, "records": [] -} +} \ No newline at end of file diff --git a/core/primitives-core/src/version.rs b/core/primitives-core/src/version.rs index 4c780a2e28b..2424339da5f 100644 --- a/core/primitives-core/src/version.rs +++ b/core/primitives-core/src/version.rs @@ -156,9 +156,6 @@ pub enum ProtocolFeature { /// Increases main_storage_proof_size_soft_limit parameter from 3mb to 4mb IncreaseStorageProofSizeSoftLimit, - /// Protocol version reserved for use in resharding tests. - SimpleNightshadeTestonly, - // Shuffle shard assignments for chunk producers at every epoch. ShuffleShardAssignments, /// Cross-shard congestion control according to . @@ -174,8 +171,10 @@ pub enum ProtocolFeature { ChunkEndorsementsInBlockHeader, /// Store receipts in State in the StateStoredReceipt format. StateStoredReceipt, - /// Resharding V3 + /// Resharding V3 - Adding "game.hot.tg-0" boundary. SimpleNightshadeV4, + /// Resharding V3 - Adding "earn.kaiching" boundary. + SimpleNightshadeV5, /// Exclude contract code from the chunk state witness and distribute it to chunk validators separately. ExcludeContractCodeFromStateWitness, /// A scheduler which limits bandwidth for sending receipts between shards. @@ -261,15 +260,13 @@ impl ProtocolFeature { | ProtocolFeature::RejectBlocksWithOutdatedProtocolVersions | ProtocolFeature::FixChunkProducerStakingThreshold | ProtocolFeature::RelaxedChunkValidation - // BandwidthScheduler must be enabled before ReshardingV3! When - // releasing this feature please make sure to schedule separate - // protocol upgrades for those features! - | ProtocolFeature::BandwidthScheduler => 74, - - // This protocol version is reserved for use in resharding tests. An extra resharding - // is simulated on top of the latest shard layout in production. Note that later - // protocol versions will still have the production layout. - ProtocolFeature::SimpleNightshadeTestonly => 100, + // BandwidthScheduler and CurrentEpochStateSync must be enabled + // before ReshardingV3! When releasing this feature please make sure + // to schedule separate protocol upgrades for these features. + | ProtocolFeature::BandwidthScheduler + | ProtocolFeature::CurrentEpochStateSync => 74, + ProtocolFeature::SimpleNightshadeV4 => 75, + ProtocolFeature::SimpleNightshadeV5 => 76, // Nightly features: #[cfg(feature = "protocol_feature_fix_contract_loading_cost")] @@ -279,11 +276,6 @@ impl ProtocolFeature { // TODO(#11201): When stabilizing this feature in mainnet, also remove the temporary code // that always enables this for mocknet (see config_mocknet function). ProtocolFeature::ShuffleShardAssignments => 143, - // CurrentEpochStateSync must be enabled before ReshardingV3! When - // releasing this feature please make sure to schedule separate - // protocol upgrades for those features! - ProtocolFeature::CurrentEpochStateSync => 144, - ProtocolFeature::SimpleNightshadeV4 => 146, ProtocolFeature::ExcludeExistingCodeFromWitnessForCodeLen => 148, ProtocolFeature::BlockHeightForReceiptId | ProtocolFeature::ProduceOptimisticBlock => { 149 @@ -299,7 +291,7 @@ impl ProtocolFeature { } /// Current protocol version used on the mainnet with all stable features. -const STABLE_PROTOCOL_VERSION: ProtocolVersion = 74; +const STABLE_PROTOCOL_VERSION: ProtocolVersion = 76; // On nightly, pick big enough version to support all features. const NIGHTLY_PROTOCOL_VERSION: ProtocolVersion = 149; diff --git a/core/primitives/res/epoch_configs/mainnet/143.json b/core/primitives/res/epoch_configs/mainnet/143.json index 092c919aee3..c25dd6e32f3 100644 --- a/core/primitives/res/epoch_configs/mainnet/143.json +++ b/core/primitives/res/epoch_configs/mainnet/143.json @@ -7,6 +7,8 @@ 100, 100, 100, + 100, + 100, 100 ], "avg_hidden_validator_seats_per_shard": [ @@ -15,6 +17,8 @@ 0, 0, 0, + 0, + 0, 0 ], "block_producer_kickout_threshold": 80, @@ -37,40 +41,80 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", + "earn.kaiching", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 8, + 9, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "4": 6, + "5": 7, + "6": 4, + "7": 5, + "8": 2, + "9": 3 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 8, + "3": 9, + "4": 6, + "5": 7, + "6": 4, + "7": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ - 2, - 3 + "2": [ + 8, + 9 ], - [ + "4": [ 4 ], - [ + "5": [ 5 + ], + "6": [ + 6 + ], + "7": [ + 7 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 2, - 3, - 4 - ], + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 2, + "9": 2 + }, "version": 3 } }, diff --git a/core/primitives/res/epoch_configs/mainnet/100.json b/core/primitives/res/epoch_configs/mainnet/75.json similarity index 66% rename from core/primitives/res/epoch_configs/mainnet/100.json rename to core/primitives/res/epoch_configs/mainnet/75.json index f006c15274f..66218b141d8 100644 --- a/core/primitives/res/epoch_configs/mainnet/100.json +++ b/core/primitives/res/epoch_configs/mainnet/75.json @@ -39,46 +39,73 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", - "nightly", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 2, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "2": 2, + "4": 5, + "5": 6, + "6": 3, + "7": 4 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 2, + "3": 6, + "4": 7, + "5": 4, + "6": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ + "2": [ 2 ], - [ - 3 + "3": [ + 6, + 7 ], - [ - 4, - 5 + "4": [ + 4 ], - [ - 6 + "5": [ + 5 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 3, - 4, - 4, - 5 - ], - "version": 4 + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "2": 2, + "4": 4, + "5": 5, + "6": 3, + "7": 3 + }, + "version": 3 } }, "num_chunk_producer_seats": 100, @@ -91,4 +118,4 @@ ], "chunk_producer_assignment_changes_limit": 5, "shuffle_shard_assignment_for_chunk_producers": false -} +} \ No newline at end of file diff --git a/core/primitives/res/epoch_configs/mainnet/101.json b/core/primitives/res/epoch_configs/mainnet/76.json similarity index 60% rename from core/primitives/res/epoch_configs/mainnet/101.json rename to core/primitives/res/epoch_configs/mainnet/76.json index 4d750599381..8fbb651ad7d 100644 --- a/core/primitives/res/epoch_configs/mainnet/101.json +++ b/core/primitives/res/epoch_configs/mainnet/76.json @@ -7,6 +7,8 @@ 100, 100, 100, + 100, + 100, 100 ], "avg_hidden_validator_seats_per_shard": [ @@ -15,6 +17,8 @@ 0, 0, 0, + 0, + 0, 0 ], "block_producer_kickout_threshold": 80, @@ -37,40 +41,80 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", + "earn.kaiching", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 8, + 9, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "4": 6, + "5": 7, + "6": 4, + "7": 5, + "8": 2, + "9": 3 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 8, + "3": 9, + "4": 6, + "5": 7, + "6": 4, + "7": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ - 2, - 3 + "2": [ + 8, + 9 ], - [ + "4": [ 4 ], - [ + "5": [ 5 + ], + "6": [ + 6 + ], + "7": [ + 7 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 2, - 3, - 4 - ], + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 2, + "9": 2 + }, "version": 3 } }, @@ -84,4 +128,4 @@ ], "chunk_producer_assignment_changes_limit": 5, "shuffle_shard_assignment_for_chunk_producers": false -} +} \ No newline at end of file diff --git a/core/primitives/res/epoch_configs/testnet/143.json b/core/primitives/res/epoch_configs/testnet/143.json index dda14b41663..e54cceafcdb 100644 --- a/core/primitives/res/epoch_configs/testnet/143.json +++ b/core/primitives/res/epoch_configs/testnet/143.json @@ -7,6 +7,8 @@ 20, 20, 20, + 20, + 20, 20 ], "avg_hidden_validator_seats_per_shard": [ @@ -15,6 +17,8 @@ 0, 0, 0, + 0, + 0, 0 ], "block_producer_kickout_threshold": 80, @@ -37,40 +41,80 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", + "earn.kaiching", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 8, + 9, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "4": 6, + "5": 7, + "6": 4, + "7": 5, + "8": 2, + "9": 3 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 8, + "3": 9, + "4": 6, + "5": 7, + "6": 4, + "7": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ - 2, - 3 + "2": [ + 8, + 9 ], - [ + "4": [ 4 ], - [ + "5": [ 5 + ], + "6": [ + 6 + ], + "7": [ + 7 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 2, - 3, - 4 - ], + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 2, + "9": 2 + }, "version": 3 } }, diff --git a/core/primitives/res/epoch_configs/testnet/100.json b/core/primitives/res/epoch_configs/testnet/75.json similarity index 66% rename from core/primitives/res/epoch_configs/testnet/100.json rename to core/primitives/res/epoch_configs/testnet/75.json index 2b7002fec99..5e43d372884 100644 --- a/core/primitives/res/epoch_configs/testnet/100.json +++ b/core/primitives/res/epoch_configs/testnet/75.json @@ -39,46 +39,73 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", - "nightly", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 2, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "2": 2, + "4": 5, + "5": 6, + "6": 3, + "7": 4 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 2, + "3": 6, + "4": 7, + "5": 4, + "6": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ + "2": [ 2 ], - [ - 3 + "3": [ + 6, + 7 ], - [ - 4, - 5 + "4": [ + 4 ], - [ - 6 + "5": [ + 5 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 3, - 4, - 4, - 5 - ], - "version": 4 + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "2": 2, + "4": 4, + "5": 5, + "6": 3, + "7": 3 + }, + "version": 3 } }, "num_chunk_producer_seats": 20, @@ -91,4 +118,4 @@ ], "chunk_producer_assignment_changes_limit": 5, "shuffle_shard_assignment_for_chunk_producers": false -} +} \ No newline at end of file diff --git a/core/primitives/res/epoch_configs/testnet/101.json b/core/primitives/res/epoch_configs/testnet/76.json similarity index 60% rename from core/primitives/res/epoch_configs/testnet/101.json rename to core/primitives/res/epoch_configs/testnet/76.json index ac3f1d52bb7..5893fb56644 100644 --- a/core/primitives/res/epoch_configs/testnet/101.json +++ b/core/primitives/res/epoch_configs/testnet/76.json @@ -7,6 +7,8 @@ 20, 20, 20, + 20, + 20, 20 ], "avg_hidden_validator_seats_per_shard": [ @@ -15,6 +17,8 @@ 0, 0, 0, + 0, + 0, 0 ], "block_producer_kickout_threshold": 80, @@ -37,40 +41,80 @@ 5 ], "shard_layout": { - "V1": { + "V2": { "boundary_accounts": [ "aurora", "aurora-0", + "earn.kaiching", "game.hot.tg", + "game.hot.tg-0", "kkuuue2akv_1630967379.near", "tge-lockup.sweat" ], - "shards_split_map": [ - [ + "shard_ids": [ + 0, + 1, + 8, + 9, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "4": 6, + "5": 7, + "6": 4, + "7": 5, + "8": 2, + "9": 3 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 8, + "3": 9, + "4": 6, + "5": 7, + "6": 4, + "7": 5 + }, + "shards_split_map": { + "0": [ 0 ], - [ + "1": [ 1 ], - [ - 2, - 3 + "2": [ + 8, + 9 ], - [ + "4": [ 4 ], - [ + "5": [ 5 + ], + "6": [ + 6 + ], + "7": [ + 7 ] - ], - "to_parent_shard_map": [ - 0, - 1, - 2, - 2, - 3, - 4 - ], + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 2, + "9": 2 + }, "version": 3 } }, @@ -84,4 +128,4 @@ ], "chunk_producer_assignment_changes_limit": 5, "shuffle_shard_assignment_for_chunk_producers": false -} +} \ No newline at end of file diff --git a/core/primitives/src/epoch_manager.rs b/core/primitives/src/epoch_manager.rs index a20a4806d9e..478141dba53 100644 --- a/core/primitives/src/epoch_manager.rs +++ b/core/primitives/src/epoch_manager.rs @@ -378,14 +378,13 @@ 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(), - ); + if checked_feature!("stable", SimpleNightshadeV5, protocol_version) { + Self::config_nightshade_impl(config, ShardLayout::get_simple_nightshade_layout_v5()); + return; + } + + if checked_feature!("stable", SimpleNightshadeV4, protocol_version) { + Self::config_nightshade_impl(config, ShardLayout::get_simple_nightshade_layout_v4()); return; } @@ -533,8 +532,8 @@ static CONFIGS: &[(&str, ProtocolVersion, &str)] = &[ include_config!("mainnet", 70, "70.json"), include_config!("mainnet", 71, "71.json"), include_config!("mainnet", 72, "72.json"), - include_config!("mainnet", 100, "100.json"), - include_config!("mainnet", 101, "101.json"), + include_config!("mainnet", 75, "75.json"), + include_config!("mainnet", 76, "76.json"), include_config!("mainnet", 143, "143.json"), // Epoch configs for testnet (genesis protocol version is 29). include_config!("testnet", 29, "29.json"), @@ -546,8 +545,8 @@ static CONFIGS: &[(&str, ProtocolVersion, &str)] = &[ include_config!("testnet", 70, "70.json"), include_config!("testnet", 71, "71.json"), include_config!("testnet", 72, "72.json"), - include_config!("testnet", 100, "100.json"), - include_config!("testnet", 101, "101.json"), + include_config!("testnet", 75, "75.json"), + include_config!("testnet", 76, "76.json"), include_config!("testnet", 143, "143.json"), ]; @@ -707,11 +706,15 @@ mod tests { for protocol_version in genesis_protocol_version..=PROTOCOL_VERSION { let stored_config = config_store.get_config(protocol_version); let expected_config = all_epoch_config.generate_epoch_config(protocol_version); - assert_eq!( - *stored_config.as_ref(), - expected_config, - "Mismatch for protocol version {protocol_version}" - ); + if stored_config.as_ref() != &expected_config { + println!( + "Mismatching epoch configs for protocol version {protocol_version}. + Please update the appropriate .json file." + ); + println!("stored\n{:#?}", stored_config); + println!("expected\n{:#?}", expected_config); + panic!("Mismatch for protocol version {protocol_version}"); + } } } diff --git a/core/primitives/src/shard_layout.rs b/core/primitives/src/shard_layout.rs index eeadd74d0fc..276584122a5 100644 --- a/core/primitives/src/shard_layout.rs +++ b/core/primitives/src/shard_layout.rs @@ -543,18 +543,22 @@ impl ShardLayout { } /// Returns the simple nightshade layout, version 4, that will be used in - /// production. It adds a new boundary account splitting the "game.hot.tg" - /// shard into two smaller shards. This is the first layout used in the - /// Instant Resharding and it is the first one where the shard id contiguity - /// is broken. + /// production. It adds a new boundary account "game.hot.tg". /// - /// TODO(resharding) Determine the shard layout for v4. - /// This layout is provisional, the actual shard layout should be determined - /// based on the fresh data before the resharding. - #[cfg(test)] + /// This is the first layout used in the Resharding V3 and it is the first + /// one where the arbitrary shard ids are used. pub fn get_simple_nightshade_layout_v4() -> ShardLayout { - let v3 = Self::get_simple_nightshade_layout_v3(); - ShardLayout::derive_shard_layout(&v3, "game.hot.tg-0".parse().unwrap()) + let base_shard_layout = Self::get_simple_nightshade_layout_v3(); + let new_boundary_account = "game.hot.tg-0".parse().unwrap(); + ShardLayout::derive_shard_layout(&base_shard_layout, new_boundary_account) + } + + /// Returns the simple nightshade layout, version 5, that will be used in + /// production. It adds a new boundary account "earn.kaiching". + pub fn get_simple_nightshade_layout_v5() -> ShardLayout { + let base_shard_layout = Self::get_simple_nightshade_layout_v4(); + let new_boundary_account = "earn.kaiching".parse().unwrap(); + ShardLayout::derive_shard_layout(&base_shard_layout, new_boundary_account) } /// This layout is used only in resharding tests. It allows testing of any features which were @@ -1318,6 +1322,7 @@ mod tests { let v2 = ShardLayout::get_simple_nightshade_layout_v2(); let v3 = ShardLayout::get_simple_nightshade_layout_v3(); let v4 = ShardLayout::get_simple_nightshade_layout_v4(); + let v5 = ShardLayout::get_simple_nightshade_layout_v5(); insta::assert_snapshot!(serde_json::to_string_pretty(&v0).unwrap(), @r###" { @@ -1501,6 +1506,87 @@ mod tests { } } "###); + + insta::assert_snapshot!(serde_json::to_string_pretty(&v5).unwrap(), @r###" + { + "V2": { + "boundary_accounts": [ + "aurora", + "aurora-0", + "earn.kaiching", + "game.hot.tg", + "game.hot.tg-0", + "kkuuue2akv_1630967379.near", + "tge-lockup.sweat" + ], + "shard_ids": [ + 0, + 1, + 8, + 9, + 6, + 7, + 4, + 5 + ], + "id_to_index_map": { + "0": 0, + "1": 1, + "4": 6, + "5": 7, + "6": 4, + "7": 5, + "8": 2, + "9": 3 + }, + "index_to_id_map": { + "0": 0, + "1": 1, + "2": 8, + "3": 9, + "4": 6, + "5": 7, + "6": 4, + "7": 5 + }, + "shards_split_map": { + "0": [ + 0 + ], + "1": [ + 1 + ], + "2": [ + 8, + 9 + ], + "4": [ + 4 + ], + "5": [ + 5 + ], + "6": [ + 6 + ], + "7": [ + 7 + ] + }, + "shards_parent_map": { + "0": 0, + "1": 1, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 2, + "9": 2 + }, + "version": 3 + } + } + "###); } #[test] diff --git a/cspell.json b/cspell.json index bc988593391..e525b3de9a2 100644 --- a/cspell.json +++ b/cspell.json @@ -30,6 +30,7 @@ "backpressure", "Banasik", "BASEPOINT", + "behaviour", "benchmarknet", "betanet", "bijective", @@ -191,6 +192,7 @@ "profraw", "profraws", "pugachag", + "pwasm", "pytest", "pytests", "PYTHONPATH", 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 c7ccbb22d92..b44e33d7f8e 100644 --- a/integration-tests/src/test_loop/tests/fix_stake_threshold.rs +++ b/integration-tests/src/test_loop/tests/fix_stake_threshold.rs @@ -1,3 +1,5 @@ +use std::cell::Cell; + use crate::test_loop::builder::TestLoopBuilder; use crate::test_loop::env::TestLoopEnv; use crate::test_loop::utils::validators::get_epoch_all_validators; @@ -13,13 +15,21 @@ use near_primitives::num_rational::Rational32; use near_primitives::test_utils::create_test_signer; use near_primitives::types::AccountId; use near_primitives::types::AccountInfo; +use near_primitives::upgrade_schedule::ProtocolUpgradeVotingSchedule; use near_primitives_core::version::ProtocolFeature; +// TODO(resharding) - Implement this test for the stable protocol version. The +// original implementation was not compatible with the two shard layout changes +// in between the FixStakingThreshold and stable. #[test] -fn slow_test_fix_validator_stake_threshold() { +fn slow_test_fix_validator_stake_threshold_protocol_upgrade() { init_test_logger(); let protocol_version = ProtocolFeature::FixStakingThreshold.protocol_version() - 1; + let target_protocol_version = ProtocolFeature::FixStakingThreshold.protocol_version(); + let protocol_upgrade_schedule = + ProtocolUpgradeVotingSchedule::new_immediate(target_protocol_version); + let test_loop_builder = TestLoopBuilder::new(); let epoch_config_store = EpochConfigStore::for_chain_id("mainnet", None).unwrap(); let epoch_length = 10; @@ -59,6 +69,7 @@ fn slow_test_fix_validator_stake_threshold() { let TestLoopEnv { mut test_loop, datas: node_data, tempdir } = test_loop_builder .genesis(genesis) .epoch_config_store(epoch_config_store.clone()) + .protocol_upgrade_schedule(protocol_upgrade_schedule) .clients(clients) .build(); @@ -91,21 +102,25 @@ fn slow_test_fix_validator_stake_threshold() { // Chunk producer stake threshold used to be dependent on the number of shards. assert_eq!(epoch_info.seat_price() / ONE_NEAR, 600_000 / num_shards as u128); + let head_height = Cell::new(client.chain.head().unwrap().height); + test_loop.run_until( |test_loop_data: &mut TestLoopData| { let client = &test_loop_data.get(&handle).client; let head = client.chain.head().unwrap(); - let epoch_height = client - .epoch_manager - .get_epoch_height_from_prev_block(&head.prev_block_hash) - .unwrap(); + let parent_hash = head.prev_block_hash; + let epoch_id = client.epoch_manager.get_epoch_id_from_prev_block(&parent_hash).unwrap(); + let epoch_height = + client.epoch_manager.get_epoch_height_from_prev_block(&parent_hash).unwrap(); + let shard_layout = client.epoch_manager.get_shard_layout(&epoch_id).unwrap(); // ensure loop is exited because condition is met instead of timeout assert!(epoch_height < 3); - let epoch_id = client - .epoch_manager - .get_epoch_id_from_prev_block(&client.chain.head().unwrap().last_block_hash) - .unwrap(); + if head_height.get() != head.height { + head_height.set(head.height); + tracing::info!(target: "test", height = head.height, num_shards=shard_layout.num_shards(), "new head"); + } + // chain will advance to the latest protocol version let protocol_version = client.epoch_manager.get_epoch_protocol_version(&epoch_id).unwrap(); 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 f1ace7c7ba8..6573c84c88d 100644 --- a/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs +++ b/integration-tests/src/test_loop/tests/reject_outdated_blocks.rs @@ -15,6 +15,7 @@ use near_primitives::test_utils::create_test_signer; use near_primitives::transaction::SignedTransaction; use near_primitives::types::AccountId; use near_primitives::types::AccountInfo; +use near_primitives::upgrade_schedule::ProtocolUpgradeVotingSchedule; use near_primitives_core::num_rational::Rational32; use near_primitives_core::version::ProtocolFeature; use std::sync::atomic::{AtomicU64, Ordering}; @@ -40,12 +41,20 @@ fn create_tx(latest_block: &Block, origin: &AccountId, receiver: &AccountId) -> ) } +// TODO(resharding) - Implement this test for the stable protocol version. The +// original implementation was not compatible with the two shard layout changes +// in between the RejectBlocksWithOutdatedProtocolVersions and stable. #[test] -fn slow_test_reject_blocks_with_outdated_protocol_version() { +fn slow_test_reject_blocks_with_outdated_protocol_version_protocol_upgrade() { init_test_logger(); let mut protocol_version = ProtocolFeature::RejectBlocksWithOutdatedProtocolVersions.protocol_version() - 1; + let target_protocol_version = + ProtocolFeature::RejectBlocksWithOutdatedProtocolVersions.protocol_version(); + let protocol_upgrade_schedule = + ProtocolUpgradeVotingSchedule::new_immediate(target_protocol_version); + let test_loop_builder = TestLoopBuilder::new(); let epoch_config_store = EpochConfigStore::for_chain_id("mainnet", None).unwrap(); let epoch_length = 10; @@ -72,6 +81,7 @@ fn slow_test_reject_blocks_with_outdated_protocol_version() { let TestLoopEnv { mut test_loop, datas: node_data, tempdir } = test_loop_builder .genesis(genesis) + .protocol_upgrade_schedule(protocol_upgrade_schedule) .epoch_config_store(epoch_config_store) .clients(clients) .build(); diff --git a/pytest/tests/sanity/upgradable.py b/pytest/tests/sanity/upgradable.py index aa1392244e7..6861650a9d4 100755 --- a/pytest/tests/sanity/upgradable.py +++ b/pytest/tests/sanity/upgradable.py @@ -67,10 +67,37 @@ def get_proto_version(exe: pathlib.Path) -> int: test_proto in (main_proto, main_proto + 1, main_proto + 2)) elif head_proto == 70: # Before stateless validation launch (protocol version 69) on mainnet, - # we have protocol version 70 stabilized in master, while mainnet protocol version is still 67. - ok = (head_proto in (test_proto, test_proto + 1, test_proto + 2, - test_proto + 3) and test_proto - in (main_proto, main_proto + 1, main_proto + 2, main_proto + 3)) + # we have protocol version 70 stabilized in master, while mainnet + # protocol version is still 67. + allowed_head_proto = ( + test_proto, + test_proto + 1, + test_proto + 2, + test_proto + 3, + ) + allowed_main_proto = ( + main_proto, + main_proto + 1, + main_proto + 2, + main_proto + 3, + ) + ok = (head_proto in allowed_head_proto and + test_proto in allowed_main_proto) + elif head_proto == 76: + allowed_head_proto = ( + test_proto, + test_proto + 1, + test_proto + 2, + test_proto + 3, + ) + allowed_main_proto = ( + main_proto, + main_proto + 1, + main_proto + 2, + main_proto + 3, + ) + ok = (head_proto in allowed_head_proto and + test_proto in allowed_main_proto) else: # Otherwise only allow increasing the protocol version by 1. ok = (head_proto in (test_proto, test_proto + 1) and