From 2c3f3a3a44c5c251ca2edfd7ce29143a1921c936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Chuda=C5=9B?= Date: Tue, 7 Nov 2023 17:21:47 +0100 Subject: [PATCH] Wrap changes in protocol_feature --- chain/chain/Cargo.toml | 4 + core/primitives-core/Cargo.toml | 2 + core/primitives-core/src/runtime/fees.rs | 11 +- core/primitives-core/src/version.rs | 6 +- core/primitives/Cargo.toml | 2 + core/primitives/src/utils.rs | 12 ++ integration-tests/Cargo.toml | 4 + .../access_key_nonce_for_implicit_accounts.rs | 3 + .../tests/client/features/delegate_action.rs | 3 + nearcore/Cargo.toml | 4 + neard/Cargo.toml | 2 + runtime/runtime/Cargo.toml | 5 + runtime/runtime/src/actions.rs | 123 +++++++++--------- runtime/runtime/src/verifier.rs | 78 +++++------ tools/fork-network/src/cli.rs | 19 +-- tools/mirror/src/genesis.rs | 19 +-- tools/mirror/src/lib.rs | 5 +- 17 files changed, 182 insertions(+), 120 deletions(-) diff --git a/chain/chain/Cargo.toml b/chain/chain/Cargo.toml index 44afc195618..ed9dff237c5 100644 --- a/chain/chain/Cargo.toml +++ b/chain/chain/Cargo.toml @@ -62,6 +62,9 @@ protocol_feature_simple_nightshade_v2 = [ protocol_feature_chunk_validation = [ "near-primitives/protocol_feature_chunk_validation", ] +protocol_feature_eth_implicit = [ + "near-primitives/protocol_feature_eth_implicit", +] nightly = [ "nightly_protocol", @@ -69,6 +72,7 @@ nightly = [ "protocol_feature_reject_blocks_with_outdated_protocol_version", "protocol_feature_simple_nightshade_v2", "near-async/nightly", + "protocol_feature_eth_implicit", "near-chain-configs/nightly", "near-client-primitives/nightly", "near-epoch-manager/nightly", diff --git a/core/primitives-core/Cargo.toml b/core/primitives-core/Cargo.toml index 2d7ff4c30ae..c1d14418301 100644 --- a/core/primitives-core/Cargo.toml +++ b/core/primitives-core/Cargo.toml @@ -37,6 +37,7 @@ protocol_feature_fix_contract_loading_cost = [] protocol_feature_reject_blocks_with_outdated_protocol_version = [] protocol_feature_simple_nightshade_v2 = [] protocol_feature_chunk_validation = [] +protocol_feature_eth_implicit = [] nightly = [ "nightly_protocol", @@ -45,6 +46,7 @@ nightly = [ "protocol_feature_fix_staking_threshold", "protocol_feature_reject_blocks_with_outdated_protocol_version", "protocol_feature_simple_nightshade_v2", + "protocol_feature_eth_implicit", ] nightly_protocol = [ diff --git a/core/primitives-core/src/runtime/fees.rs b/core/primitives-core/src/runtime/fees.rs index 818319eac27..f913a7f66e9 100644 --- a/core/primitives-core/src/runtime/fees.rs +++ b/core/primitives-core/src/runtime/fees.rs @@ -219,7 +219,10 @@ pub fn transfer_exec_fee( (false, _) => transfer_fee, // Extra fee for the CreateAccount. (true, AccountType::EthImplicitAccount) => { - transfer_fee + cfg.fee(ActionCosts::create_account).exec_fee() + #[cfg(feature = "protocol_feature_eth_implicit")] + return transfer_fee + cfg.fee(ActionCosts::create_account).exec_fee(); + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + transfer_fee } // Extra fees for the CreateAccount and AddFullAccessKey. (true, AccountType::NearImplicitAccount) => { @@ -244,7 +247,11 @@ pub fn transfer_send_fee( (false, _) => transfer_fee, // Extra fee for the CreateAccount. (true, AccountType::EthImplicitAccount) => { - transfer_fee + cfg.fee(ActionCosts::create_account).send_fee(sender_is_receiver) + #[cfg(feature = "protocol_feature_eth_implicit")] + return transfer_fee + + cfg.fee(ActionCosts::create_account).send_fee(sender_is_receiver); + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + transfer_fee } // Extra fees for the CreateAccount and AddFullAccessKey. (true, AccountType::NearImplicitAccount) => { diff --git a/core/primitives-core/src/version.rs b/core/primitives-core/src/version.rs index f342479f53b..1327d64a2bc 100644 --- a/core/primitives-core/src/version.rs +++ b/core/primitives-core/src/version.rs @@ -132,6 +132,8 @@ pub enum ProtocolFeature { /// NEP: https://github.com/near/NEPs/pull/509 #[cfg(feature = "protocol_feature_chunk_validation")] ChunkValidation, + #[cfg(feature = "protocol_feature_eth_implicit")] + EthImplicit, } impl ProtocolFeature { @@ -189,6 +191,8 @@ impl ProtocolFeature { ProtocolFeature::PostStateRoot => 136, #[cfg(feature = "protocol_feature_chunk_validation")] ProtocolFeature::ChunkValidation => 137, + #[cfg(feature = "protocol_feature_eth_implicit")] + ProtocolFeature::EthImplicit => 138, } } } @@ -201,7 +205,7 @@ const STABLE_PROTOCOL_VERSION: ProtocolVersion = 64; /// Largest protocol version supported by the current binary. pub const PROTOCOL_VERSION: ProtocolVersion = if cfg!(feature = "nightly_protocol") { // On nightly, pick big enough version to support all features. - 139 + 140 } else { // Enable all stable features. STABLE_PROTOCOL_VERSION diff --git a/core/primitives/Cargo.toml b/core/primitives/Cargo.toml index 74082351104..e0adb999636 100644 --- a/core/primitives/Cargo.toml +++ b/core/primitives/Cargo.toml @@ -51,6 +51,7 @@ protocol_feature_fix_staking_threshold = ["near-primitives-core/protocol_feature protocol_feature_fix_contract_loading_cost = ["near-primitives-core/protocol_feature_fix_contract_loading_cost"] protocol_feature_reject_blocks_with_outdated_protocol_version = ["near-primitives-core/protocol_feature_reject_blocks_with_outdated_protocol_version"] protocol_feature_simple_nightshade_v2 = ["near-primitives-core/protocol_feature_simple_nightshade_v2"] +protocol_feature_eth_implicit = ["near-primitives-core/protocol_feature_eth_implicit"] protocol_feature_chunk_validation = [] nightly = [ "nightly_protocol", @@ -59,6 +60,7 @@ nightly = [ "protocol_feature_fix_staking_threshold", "protocol_feature_reject_blocks_with_outdated_protocol_version", "protocol_feature_simple_nightshade_v2", + "protocol_feature_eth_implicit", "near-fmt/nightly", "near-primitives-core/nightly", "near-vm-runner/nightly", diff --git a/core/primitives/src/utils.rs b/core/primitives/src/utils.rs index 91d4f25d869..1bfd6c99bc3 100644 --- a/core/primitives/src/utils.rs +++ b/core/primitives/src/utils.rs @@ -19,6 +19,8 @@ use crate::version::{ use near_crypto::{KeyType, PublicKey}; use near_primitives_core::account::id::AccountId; +#[cfg(not(feature = "protocol_feature_eth_implicit"))] +use near_primitives_core::account::id::AccountType; use std::mem::size_of; use std::ops::Deref; @@ -469,6 +471,16 @@ where Serializable(object) } +/// From `near-account-id` version `1.0.0-alpha.2`, `is_implicit` returns true for ETH-implicit accounts. +/// This function is a wrapper for `is_implicit` method so that we can easily differentiate its behavior +/// based on the protocol version. +pub fn account_is_implicit(account_id: &AccountId) -> bool { + #[cfg(feature = "protocol_feature_eth_implicit")] + return account_id.get_account_type().is_implicit(); + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + return account_id.get_account_type() == AccountType::NearImplicitAccount; +} + /// Derives `AccountId` from `PublicKey`. /// If the key type is ED25519, returns hex-encoded copy of the key. /// If the key type is SECP256K1, returns '0x' + keccak256(public_key)[12:32].hex(). diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 29a9e6ef6c3..d85e15812e0 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -80,12 +80,16 @@ protocol_feature_reject_blocks_with_outdated_protocol_version = [ protocol_feature_simple_nightshade_v2 = [ "near-primitives/protocol_feature_simple_nightshade_v2", ] +protocol_feature_eth_implicit = [ + "near-primitives/protocol_feature_eth_implicit", +] nightly = [ "nightly_protocol", "protocol_feature_fix_contract_loading_cost", "protocol_feature_reject_blocks_with_outdated_protocol_version", "protocol_feature_simple_nightshade_v2", + "protocol_feature_eth_implicit", "near-actix-test-utils/nightly", "near-async/nightly", "near-chain-configs/nightly", diff --git a/integration-tests/src/tests/client/features/access_key_nonce_for_implicit_accounts.rs b/integration-tests/src/tests/client/features/access_key_nonce_for_implicit_accounts.rs index 5c784fa7953..044a81a6b78 100644 --- a/integration-tests/src/tests/client/features/access_key_nonce_for_implicit_accounts.rs +++ b/integration-tests/src/tests/client/features/access_key_nonce_for_implicit_accounts.rs @@ -201,6 +201,7 @@ fn get_status_of_tx_hash_collision_for_implicit_account( /// Test that duplicate transactions from ETH-implicit account can be properly rejected /// if we set nonce to `(block_height - 1) * 1e6` for transactions that results in /// access key being added to the ETH-implicit account. +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn test_transaction_eth_implicit_account() { let epoch_length = 10; @@ -337,6 +338,7 @@ fn test_transaction_eth_implicit_account() { } /// Test that the signer is correctly verified for transactions done from an ETH-implicit account. +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn test_transaction_eth_implicit_account_invalid_pk() { let epoch_length = 10; @@ -465,6 +467,7 @@ fn test_transaction_hash_collision_for_near_implicit_account_ok() { /// Test that duplicate transactions from ETH-implicit accounts are not rejected before and after protocol upgrade. /// It is responsibility of the transaction signer to choose nonce equal to `(block_height - 1) * 1e6` in case the transaction /// results in adding a new key to an ETH-implicit account (see https://github.com/near/NEPs/issues/498#issuecomment-1782881395). +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn test_transaction_hash_collision_for_eth_implicit_account_ok() { let protocol_version = diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index 405a43a070b..7a327c08d17 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -829,6 +829,7 @@ fn meta_tx_create_near_implicit_account_fails() { meta_tx_create_implicit_account_fails(near_implicit_test_account()); } +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn meta_tx_create_eth_implicit_account_fails() { meta_tx_create_implicit_account_fails(eth_implicit_test_account()); @@ -871,6 +872,7 @@ fn meta_tx_create_and_use_near_implicit_account() { meta_tx_create_and_use_implicit_account(near_implicit_test_account()); } +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn meta_tx_create_and_use_eth_implicit_account() { meta_tx_create_and_use_implicit_account(eth_implicit_test_account()); @@ -952,6 +954,7 @@ fn meta_tx_create_near_implicit_account() { meta_tx_create_implicit_account(near_implicit_test_account(), None); } +#[cfg(feature = "protocol_feature_eth_implicit")] #[test] fn meta_tx_create_eth_implicit_account() { let secret_key = eth_implicit_test_account_secret(); diff --git a/nearcore/Cargo.toml b/nearcore/Cargo.toml index 81d2db6b189..05ffd717318 100644 --- a/nearcore/Cargo.toml +++ b/nearcore/Cargo.toml @@ -115,6 +115,9 @@ protocol_feature_fix_contract_loading_cost = [ protocol_feature_simple_nightshade_v2 = [ "near-primitives/protocol_feature_simple_nightshade_v2", ] +protocol_feature_eth_implicit = [ + "near-primitives/protocol_feature_eth_implicit", +] new_epoch_sync = [ "near-client/new_epoch_sync" ] @@ -125,6 +128,7 @@ nightly = [ "protocol_feature_fix_contract_loading_cost", "protocol_feature_fix_staking_threshold", "protocol_feature_simple_nightshade_v2", + "protocol_feature_eth_implicit", "serialize_all_state_changes", "near-async/nightly", "near-chain-configs/nightly", diff --git a/neard/Cargo.toml b/neard/Cargo.toml index 44ee07b1a72..59fbd7002f0 100644 --- a/neard/Cargo.toml +++ b/neard/Cargo.toml @@ -71,6 +71,7 @@ rosetta_rpc = ["nearcore/rosetta_rpc"] json_rpc = ["nearcore/json_rpc"] protocol_feature_fix_staking_threshold = ["nearcore/protocol_feature_fix_staking_threshold"] protocol_feature_simple_nightshade_v2 = ["nearcore/protocol_feature_simple_nightshade_v2"] +protocol_feature_eth_implicit = ["nearcore/protocol_feature_eth_implicit"] serialize_all_state_changes = ["nearcore/serialize_all_state_changes"] new_epoch_sync = ["nearcore/new_epoch_sync"] @@ -78,6 +79,7 @@ nightly = [ "nightly_protocol", "protocol_feature_fix_staking_threshold", "protocol_feature_simple_nightshade_v2", + "protocol_feature_eth_implicit", "serialize_all_state_changes", "near-chain-configs/nightly", "near-client/nightly", diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 58e79b8abc3..b034e920e3a 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -32,8 +32,13 @@ near-store.workspace = true near-vm-runner.workspace = true [features] +protocol_feature_eth_implicit = [ + "near-primitives/protocol_feature_eth_implicit", +] + nightly = [ "nightly_protocol", + "protocol_feature_eth_implicit", "near-chain-configs/nightly", "near-o11y/nightly", "near-primitives-core/nightly", diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index a3516cc86f9..381e5a8615c 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -22,7 +22,9 @@ use near_primitives::transaction::{ }; use near_primitives::types::validator_stake::ValidatorStake; use near_primitives::types::{AccountId, BlockHeight, EpochInfoProvider, Gas, TrieCacheMode}; -use near_primitives::utils::{create_random_seed, derive_account_id_from_public_key}; +#[cfg(feature = "protocol_feature_eth_implicit")] +use near_primitives::utils::derive_account_id_from_public_key; +use near_primitives::utils::{account_is_implicit, create_random_seed}; use near_primitives::version::{ ProtocolFeature, ProtocolVersion, DELETE_KEY_STORAGE_USAGE_PROTOCOL_VERSION, }; @@ -474,13 +476,19 @@ pub(crate) fn action_implicit_account_creation_transfer( // Invariant: The `account_id` is implicit. // It holds because in the only calling site, we've checked the permissions before. AccountType::EthImplicitAccount => { - *account = Some(Account::new( - transfer.deposit, - 0, - CryptoHash::default(), - fee_config.storage_usage_config.num_bytes_account - + fee_config.storage_usage_config.num_extra_bytes_record, - )); + #[cfg(feature = "protocol_feature_eth_implicit")] + if checked_feature!("stable", EthImplicit, current_protocol_version) { + *account = Some(Account::new( + transfer.deposit, + 0, + CryptoHash::default(), + fee_config.storage_usage_config.num_bytes_account + + fee_config.storage_usage_config.num_extra_bytes_record, + )); + } + + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + panic!("must be near-implicit") } AccountType::NamedAccount => panic!("must be implicit"), } @@ -746,57 +754,56 @@ fn validate_delegate_action_key( ) -> Result<(), RuntimeError> { // 'delegate_action.sender_id' account existence must be checked by a caller let signer_id = &delegate_action.sender_id; - let public_key = &delegate_action.public_key; - // By default, we always check nonce. - let mut should_check_nonce = true; - let mut access_key = - match get_access_key(state_update, &signer_id, &delegate_action.public_key)? { - Some(access_key) => access_key, - None => match signer_id.get_account_type() { - // Access key is missing, but in the case of a transaction from ETH-implicit account - // there is a possibility that full access key will be created now. - AccountType::EthImplicitAccount => { - if derive_account_id_from_public_key(public_key) == *signer_id { - // This is the only case we do not compare access key nonce with transaction nonce, - // because the access key is created now. - should_check_nonce = false; - // TODO What about increasing storage usage for that account, because we added access key? - AccessKey::full_access() - } else { - // Provided public key is not the one from which the signer address was derived. - result.result = Err(ActionErrorKind::DelegateActionAccessKeyError( - InvalidAccessKeyError::InvalidPkForEthAddress { - account_id: signer_id.clone(), - public_key: public_key.clone(), - }, - ) - .into()); - return Ok(()); - } - } - // Transactions done from non-ETH-implicit account must have access key already added. - _ => { - result.result = Err(ActionErrorKind::DelegateActionAccessKeyError( - InvalidAccessKeyError::AccessKeyNotFound { - account_id: signer_id.clone(), - public_key: public_key.clone(), - }, - ) - .into()); - return Ok(()); - } - }, - }; - - if should_check_nonce { - if delegate_action.nonce <= access_key.nonce { - result.result = Err(ActionErrorKind::DelegateActionInvalidNonce { - delegate_nonce: delegate_action.nonce, - ak_nonce: access_key.nonce, + let public_key: &PublicKey = &delegate_action.public_key; + + #[cfg(feature = "protocol_feature_eth_implicit")] + let mut access_key = get_access_key(state_update, &signer_id, &delegate_action.public_key)?; + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + let access_key = get_access_key(state_update, &signer_id, &delegate_action.public_key)?; + + #[cfg(feature = "protocol_feature_eth_implicit")] + if checked_feature!("stable", EthImplicit, apply_state.current_protocol_version) { + // Access key is missing, but in the case of a transaction from ETH-implicit account + // there is a possibility that full access key will be created now. + if access_key.is_none() && signer_id.get_account_type() == AccountType::EthImplicitAccount { + if derive_account_id_from_public_key(public_key) == *signer_id { + // TODO What about increasing storage usage for that account, because we added access key? + access_key = Some(AccessKey::full_access()); + } else { + // Provided public key is not the one from which the signer address was derived. + result.result = Err(ActionErrorKind::DelegateActionAccessKeyError( + InvalidAccessKeyError::InvalidPkForEthAddress { + account_id: signer_id.clone(), + public_key: public_key.clone(), + }, + ) + .into()); + return Ok(()); } + } + } + + let mut access_key = match access_key { + Some(access_key) => access_key, + None => { + result.result = Err(ActionErrorKind::DelegateActionAccessKeyError( + InvalidAccessKeyError::AccessKeyNotFound { + account_id: signer_id.clone(), + public_key: public_key.clone(), + }, + ) .into()); return Ok(()); } + }; + + if delegate_action.nonce <= access_key.nonce { + result.result = Err(ActionErrorKind::DelegateActionInvalidNonce { + delegate_nonce: delegate_action.nonce, + ak_nonce: access_key.nonce, + } + .into()); + return Ok(()); } let upper_bound = apply_state.block_height @@ -925,9 +932,7 @@ pub(crate) fn check_account_existence( .into()); } else { // TODO: this should be `config.implicit_account_creation`. - if config.wasm_config.implicit_account_creation - && account_id.get_account_type().is_implicit() - { + if config.wasm_config.implicit_account_creation && account_is_implicit(account_id) { // If the account doesn't exist and it's implicit, then you // should only be able to create it using single transfer action. // Because you should not be able to add another access key to the account in @@ -948,7 +953,7 @@ pub(crate) fn check_account_existence( if account.is_none() { return if config.wasm_config.implicit_account_creation && is_the_only_action - && account_id.get_account_type().is_implicit() + && account_is_implicit(account_id) && !is_refund { // OK. It's implicit account creation. diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 17cbf60e2ce..8b0c642ef8c 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -2,7 +2,9 @@ use crate::config::{total_prepaid_gas, tx_cost, TransactionCost}; use crate::near_primitives::account::Account; use crate::VerificationResult; use near_crypto::key_conversion::is_valid_staking_key; -use near_primitives::account::{AccessKey, AccessKeyPermission}; +#[cfg(feature = "protocol_feature_eth_implicit")] +use near_primitives::account::AccessKey; +use near_primitives::account::AccessKeyPermission; use near_primitives::action::delegate::SignedDelegateAction; use near_primitives::checked_feature; use near_primitives::errors::{ @@ -17,9 +19,11 @@ use near_primitives::transaction::{ }; use near_primitives::types::{AccountId, Balance}; use near_primitives::types::{BlockHeight, StorageUsage}; +#[cfg(feature = "protocol_feature_eth_implicit")] use near_primitives::utils::derive_account_id_from_public_key; use near_primitives::version::ProtocolFeature; use near_primitives::version::ProtocolVersion; +#[cfg(feature = "protocol_feature_eth_implicit")] use near_primitives_core::account::id::AccountType; use near_store::{ get_access_key, get_account, set_access_key, set_account, StorageError, TrieUpdate, @@ -154,52 +158,52 @@ pub fn verify_and_charge_transaction( return Err(InvalidTxError::SignerDoesNotExist { signer_id: signer_id.clone() }.into()); } }; - // By default, we always check nonce. - let mut should_check_nonce = true; - let mut access_key = match get_access_key(state_update, signer_id, public_key)? { - Some(access_key) => access_key, - None => match signer_id.get_account_type() { - // Access key is missing, but in the case of a transaction from ETH-implicit account - // there is a possibility that full access key will be created now. - AccountType::EthImplicitAccount => { - if derive_account_id_from_public_key(public_key) == *signer_id { - // This is the only case we do not compare access key nonce with transaction nonce, - // because the access key is created now. - should_check_nonce = false; - // TODO What about increasing storage usage for that account, because we added access key? - AccessKey::full_access() - } else { - // Provided public key is not the one from which the signer address was derived. - return Err(InvalidTxError::InvalidAccessKeyError( - InvalidAccessKeyError::InvalidPkForEthAddress { - account_id: signer_id.clone(), - public_key: public_key.clone(), - }, - ) - .into()); - } - } - // Transactions done from non-ETH-implicit account must have access key already added. - _ => { + + #[cfg(feature = "protocol_feature_eth_implicit")] + let mut access_key = get_access_key(state_update, signer_id, public_key)?; + #[cfg(not(feature = "protocol_feature_eth_implicit"))] + let access_key = get_access_key(state_update, signer_id, public_key)?; + + #[cfg(feature = "protocol_feature_eth_implicit")] + if checked_feature!("stable", EthImplicit, current_protocol_version) { + // Access key is missing, but in the case of a transaction from ETH-implicit account + // there is a possibility that full access key will be created now. + if access_key.is_none() && signer_id.get_account_type() == AccountType::EthImplicitAccount { + if derive_account_id_from_public_key(public_key) == *signer_id { + // TODO What about increasing storage usage for that account, because we added access key? + access_key = Some(AccessKey::full_access()); + } else { + // Provided public key is not the one from which the signer address was derived. return Err(InvalidTxError::InvalidAccessKeyError( - InvalidAccessKeyError::AccessKeyNotFound { + InvalidAccessKeyError::InvalidPkForEthAddress { account_id: signer_id.clone(), public_key: public_key.clone(), }, ) .into()); } - }, - }; + } + } - if should_check_nonce { - if transaction.nonce <= access_key.nonce { - return Err(InvalidTxError::InvalidNonce { - tx_nonce: transaction.nonce, - ak_nonce: access_key.nonce, - } + let mut access_key = match access_key { + Some(access_key) => access_key, + None => { + return Err(InvalidTxError::InvalidAccessKeyError( + InvalidAccessKeyError::AccessKeyNotFound { + account_id: signer_id.clone(), + public_key: public_key.clone(), + }, + ) .into()); } + }; + + if transaction.nonce <= access_key.nonce { + return Err(InvalidTxError::InvalidNonce { + tx_nonce: transaction.nonce, + ak_nonce: access_key.nonce, + } + .into()); } if checked_feature!("stable", AccessKeyNonceRange, current_protocol_version) { diff --git a/tools/fork-network/src/cli.rs b/tools/fork-network/src/cli.rs index 63b2d7ff57e..56dfda7d64d 100644 --- a/tools/fork-network/src/cli.rs +++ b/tools/fork-network/src/cli.rs @@ -22,6 +22,7 @@ use near_primitives::trie_key::trie_key_parsers::parse_account_id_from_account_k use near_primitives::types::{ AccountId, AccountInfo, Balance, BlockHeight, EpochId, NumBlocks, ShardId, StateRoot, }; +use near_primitives::utils::account_is_implicit; use near_primitives::version::PROTOCOL_VERSION; use near_store::db::RocksDB; use near_store::flat::FlatStorageStatus; @@ -486,7 +487,7 @@ impl ForkNetworkCommand { if let Some(sr) = StateRecord::from_raw_key_value(key.clone(), value.clone()) { match sr { StateRecord::AccessKey { account_id, public_key, access_key } => { - if !account_id.get_account_type().is_implicit() + if !account_is_implicit(&account_id) && access_key.permission == AccessKeyPermission::FullAccess { has_full_key.insert(account_id.clone()); @@ -503,7 +504,7 @@ impl ForkNetworkCommand { } StateRecord::Account { account_id, account } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(&account_id) { let new_account_id = map_account(&account_id, None); storage_mutator.delete_account(account_id)?; storage_mutator.set_account(new_account_id, account)?; @@ -511,7 +512,7 @@ impl ForkNetworkCommand { } } StateRecord::Data { account_id, data_key, value } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(&account_id) { let new_account_id = map_account(&account_id, None); storage_mutator.delete_data(account_id, &data_key)?; storage_mutator.set_data(new_account_id, &data_key, value)?; @@ -519,7 +520,7 @@ impl ForkNetworkCommand { } } StateRecord::Contract { account_id, code } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(&account_id) { let new_account_id = map_account(&account_id, None); storage_mutator.delete_code(account_id)?; storage_mutator.set_code(new_account_id, code)?; @@ -527,8 +528,8 @@ impl ForkNetworkCommand { } } StateRecord::PostponedReceipt(receipt) => { - if receipt.predecessor_id.get_account_type().is_implicit() - || receipt.receiver_id.get_account_type().is_implicit() + if account_is_implicit(&receipt.predecessor_id) + || account_is_implicit(&receipt.receiver_id) { let new_receipt = Receipt { predecessor_id: map_account(&receipt.predecessor_id, None), @@ -542,7 +543,7 @@ impl ForkNetworkCommand { } } StateRecord::ReceivedData { account_id, data_id, data } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(&account_id) { let new_account_id = map_account(&account_id, None); storage_mutator.delete_received_data(account_id, data_id)?; storage_mutator.set_received_data(new_account_id, data_id, &data)?; @@ -550,8 +551,8 @@ impl ForkNetworkCommand { } } StateRecord::DelayedReceipt(receipt) => { - if receipt.predecessor_id.get_account_type().is_implicit() - || receipt.receiver_id.get_account_type().is_implicit() + if account_is_implicit(&receipt.predecessor_id) + || account_is_implicit(&receipt.receiver_id) { let new_receipt = Receipt { predecessor_id: map_account(&receipt.predecessor_id, None), diff --git a/tools/mirror/src/genesis.rs b/tools/mirror/src/genesis.rs index 6f354d8df76..e48c794dd92 100644 --- a/tools/mirror/src/genesis.rs +++ b/tools/mirror/src/genesis.rs @@ -1,4 +1,5 @@ use near_primitives::state_record::StateRecord; +use near_primitives::utils::account_is_implicit; use near_primitives_core::account::{AccessKey, AccessKeyPermission}; use serde::ser::{SerializeSeq, Serializer}; use std::collections::HashSet; @@ -38,7 +39,7 @@ pub fn map_records>( public_key: replacement.public_key(), access_key: access_key.clone(), }; - if !account_id.get_account_type().is_implicit() + if !account_is_implicit(account_id) && access_key.permission == AccessKeyPermission::FullAccess { has_full_key.insert(account_id.clone()); @@ -48,7 +49,7 @@ pub fn map_records>( records_seq.serialize_element(&new_record).unwrap(); } StateRecord::Account { account_id, .. } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(account_id) { *account_id = crate::key_mapping::map_account(&account_id, secret.as_ref()); } else { accounts.insert(account_id.clone()); @@ -56,20 +57,20 @@ pub fn map_records>( records_seq.serialize_element(&r).unwrap(); } StateRecord::Data { account_id, .. } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(account_id) { *account_id = crate::key_mapping::map_account(&account_id, secret.as_ref()); } records_seq.serialize_element(&r).unwrap(); } StateRecord::Contract { account_id, .. } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(account_id) { *account_id = crate::key_mapping::map_account(&account_id, secret.as_ref()); } records_seq.serialize_element(&r).unwrap(); } StateRecord::PostponedReceipt(receipt) => { - if receipt.predecessor_id.get_account_type().is_implicit() - || receipt.receiver_id.get_account_type().is_implicit() + if account_is_implicit(&receipt.predecessor_id) + || account_is_implicit(&receipt.receiver_id) { receipt.predecessor_id = crate::key_mapping::map_account(&receipt.predecessor_id, secret.as_ref()); @@ -79,14 +80,14 @@ pub fn map_records>( records_seq.serialize_element(&r).unwrap(); } StateRecord::ReceivedData { account_id, .. } => { - if account_id.get_account_type().is_implicit() { + if account_is_implicit(account_id) { *account_id = crate::key_mapping::map_account(&account_id, secret.as_ref()); } records_seq.serialize_element(&r).unwrap(); } StateRecord::DelayedReceipt(receipt) => { - if receipt.predecessor_id.get_account_type().is_implicit() - || receipt.receiver_id.get_account_type().is_implicit() + if account_is_implicit(&receipt.predecessor_id) + || account_is_implicit(&receipt.receiver_id) { receipt.predecessor_id = crate::key_mapping::map_account(&receipt.predecessor_id, secret.as_ref()); diff --git a/tools/mirror/src/lib.rs b/tools/mirror/src/lib.rs index 6f829c2161f..8be2adc51ed 100644 --- a/tools/mirror/src/lib.rs +++ b/tools/mirror/src/lib.rs @@ -22,6 +22,7 @@ use near_primitives::transaction::{ use near_primitives::types::{ AccountId, BlockHeight, BlockReference, Finality, TransactionOrReceiptId, }; +use near_primitives::utils::account_is_implicit; use near_primitives::views::{ ExecutionOutcomeWithIdView, ExecutionStatusView, QueryRequest, QueryResponseKind, SignedTransactionView, @@ -990,9 +991,7 @@ impl TxMirror { actions.push(Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))); } Action::Transfer(_) => { - if tx.receiver_id().get_account_type().is_implicit() - && source_actions.len() == 1 - { + if account_is_implicit(tx.receiver_id()) && source_actions.len() == 1 { let target_account = crate::key_mapping::map_account(tx.receiver_id(), self.secret.as_ref()); if !account_exists(&self.target_view_client, &target_account)