diff --git a/Cargo.lock b/Cargo.lock index 9132efb9441..227515dbbf5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4713,6 +4713,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.6", + "sha3", "tempfile", "testlib", "thiserror", diff --git a/chain/rosetta-rpc/src/lib.rs b/chain/rosetta-rpc/src/lib.rs index 2106e5dd634..7d6829ed245 100644 --- a/chain/rosetta-rpc/src/lib.rs +++ b/chain/rosetta-rpc/src/lib.rs @@ -502,7 +502,7 @@ async fn construction_derive( let public_key: near_crypto::PublicKey = (&public_key) .try_into() .map_err(|_| errors::ErrorKind::InvalidInput("Invalid PublicKey".to_string()))?; - // TODO handle eth-implicit accounts + // TODO should ETH-implicit account be handled there? let address = if let near_crypto::KeyType::ED25519 = public_key.key_type() { hex::encode(public_key.key_data()) } else { diff --git a/core/account-id/src/lib.rs b/core/account-id/src/lib.rs index 99074c9a496..22a4d31ce9a 100644 --- a/core/account-id/src/lib.rs +++ b/core/account-id/src/lib.rs @@ -64,12 +64,22 @@ pub use errors::{ParseAccountError, ParseErrorKind}; #[derive(Eq, Ord, Hash, Clone, Debug, PartialEq, PartialOrd)] pub struct AccountId(Box); +#[derive(PartialEq)] pub enum AccountType { NamedAccount, NearImplicitAccount, EthImplicitAccount, } +impl AccountType { + pub fn is_implicit(&self) -> bool { + match &self { + Self::NearImplicitAccount | Self::EthImplicitAccount => true, + Self::NamedAccount => false, + } + } +} + impl AccountId { /// Shortest valid length for a NEAR Account ID. pub const MIN_LEN: usize = 2; @@ -133,13 +143,12 @@ impl AccountId { /// assert!(!alice_app.is_sub_account_of(&near_tla)); /// ``` pub fn is_sub_account_of(&self, parent: &AccountId) -> bool { - // TODO what if this account type is EthImplicitAccount ? + // TODO what if this is EthImplicitAccount ? self.strip_suffix(parent.as_str()) .and_then(|s| s.strip_suffix('.')) .map_or(false, |s| !s.contains('.')) } - // TODO change docs /// Returns `true` if the `AccountId` is a 40 characters long hexadecimal, possibly with capital letters. /// /// See [Implicit-Accounts](https://docs.near.org/docs/concepts/account#implicit-accounts). @@ -152,14 +161,15 @@ impl AccountId { /// let alice: AccountId = "alice.near".parse().unwrap(); /// assert!(!alice.is_eth_implicit()); /// - /// let rando = "b794f5eA0ba39494ce839613FFfba74279579268" + /// let rando = "0xb794f5eA0ba39494ce839613FFfba74279579268" /// .parse::() /// .unwrap(); /// assert!(rando.is_eth_implicit()); /// ``` - pub fn is_eth_implicit(&self) -> bool { - self.len() == 40 - && self.as_bytes().iter().all(|b| matches!(b, b'a'..=b'f' | b'A'..=b'F' | b'0'..=b'9')) + fn is_eth_implicit(&self) -> bool { + self.len() == 42 + && self.starts_with("0x") + && self[2..].as_bytes().iter().all(|b| matches!(b, b'a'..=b'f' | b'A'..=b'F' | b'0'..=b'9')) } /// Returns `true` if the `AccountId` is a 64 characters long hexadecimal. @@ -179,7 +189,7 @@ impl AccountId { /// .unwrap(); /// assert!(rando.is_near_implicit()); /// ``` - pub fn is_near_implicit(&self) -> bool { + fn is_near_implicit(&self) -> bool { self.len() == 64 && self.as_bytes().iter().all(|b| matches!(b, b'a'..=b'f' | b'0'..=b'9')) } @@ -465,7 +475,7 @@ mod tests { "b-o_w_e-n", "no_lols", "0123456789012345678901234567890123456789012345678901234567890123", - "b794f5eA0ba39494ce839613FFfba74279579268", + "0xb794f5eA0ba39494ce839613FFfba74279579268", // Valid, but can't be created "near.a", ]; @@ -721,7 +731,7 @@ mod tests { } } - // TODO add corresponding test for 40 len hex ETH accounts + // TODO add corresponding test for 42 len hex ETH accounts #[test] fn test_is_account_id_64_len_hex() { let valid_64_len_hex_account_ids = &[ @@ -735,7 +745,7 @@ mod tests { assert!( matches!( valid_account_id.parse::(), - Ok(account_id) if account_id.is_near_implicit() + Ok(account_id) if account_id.get_account_type() == AccountType::NearImplicitAccount ), "Account ID {} should be valid 64-len hex", valid_account_id @@ -754,7 +764,7 @@ mod tests { assert!( !matches!( invalid_account_id.parse::(), - Ok(account_id) if account_id.is_near_implicit() + Ok(account_id) if account_id.get_account_type() == AccountType::NearImplicitAccount ), "Account ID {} is not an implicit account", invalid_account_id diff --git a/core/crypto/src/util.rs b/core/crypto/src/util.rs index d6346d870af..8d3eb2303c6 100644 --- a/core/crypto/src/util.rs +++ b/core/crypto/src/util.rs @@ -7,6 +7,8 @@ use curve25519_dalek::traits::VartimeMultiscalarMul; pub use curve25519_dalek::ristretto::RistrettoPoint as Point; pub use curve25519_dalek::scalar::Scalar; +use near_account_id::AccountType; + pub fn vmul2(s1: Scalar, p1: &Point, s2: Scalar, p2: &Point) -> Point { Point::vartime_multiscalar_mul(&[s1, s2], [p1, p2].iter().copied()) } @@ -104,7 +106,7 @@ impl PublicKey { pub fn from_near_implicit_account( account_id: &near_account_id::AccountId, ) -> Result { - if !account_id.is_near_implicit() { + if account_id.get_account_type() != AccountType::NearImplicitAccount { return Err(ImplicitPublicKeyError::AccountIsNotNearImplicit { account_id: account_id.clone(), }); diff --git a/core/primitives-core/src/runtime/fees.rs b/core/primitives-core/src/runtime/fees.rs index 15326f8786f..e6637754d63 100644 --- a/core/primitives-core/src/runtime/fees.rs +++ b/core/primitives-core/src/runtime/fees.rs @@ -7,6 +7,7 @@ use crate::config::ActionCosts; use crate::num_rational::Rational32; use crate::types::{Balance, Gas}; use enum_map::EnumMap; +use near_account_id::AccountType; /// Costs associated with an object that can only be sent over the network (and executed /// by the receiver). @@ -203,17 +204,17 @@ impl StorageUsageConfig { /// Helper functions for computing Transfer fees. /// In case of implicit account creation they always include extra fees for the CreateAccount and -/// AddFullAccessKey (except ETH-implicit account) actions that are implicit. +/// AddFullAccessKey (for NEAR-implicit account only) actions that are implicit. /// We can assume that no overflow will happen here. pub fn transfer_exec_fee( cfg: &RuntimeFeesConfig, is_receiver_implicit: bool, - is_receiver_eth_implictit: bool, + receiver_account_type: AccountType, ) -> Gas { let mut result = cfg.fee(ActionCosts::transfer).exec_fee(); if is_receiver_implicit { result += cfg.fee(ActionCosts::create_account).exec_fee(); - if !is_receiver_eth_implictit { + if receiver_account_type != AccountType::EthImplicitAccount { result += cfg.fee(ActionCosts::add_full_access_key).exec_fee(); } } @@ -224,12 +225,12 @@ pub fn transfer_send_fee( cfg: &RuntimeFeesConfig, sender_is_receiver: bool, is_receiver_implicit: bool, - is_receiver_eth_implictit: bool, + receiver_account_type: AccountType, ) -> Gas { let mut result = cfg.fee(ActionCosts::transfer).send_fee(sender_is_receiver); if is_receiver_implicit { result += cfg.fee(ActionCosts::create_account).send_fee(sender_is_receiver); - if !is_receiver_eth_implictit { + if receiver_account_type != AccountType::EthImplicitAccount { result += cfg.fee(ActionCosts::add_full_access_key).send_fee(sender_is_receiver); } } diff --git a/core/primitives/src/errors.rs b/core/primitives/src/errors.rs index f46894a70e0..8e581346e1d 100644 --- a/core/primitives/src/errors.rs +++ b/core/primitives/src/errors.rs @@ -209,6 +209,8 @@ pub enum InvalidAccessKeyError { }, /// Having a deposit with a function call action is not allowed with a function call access key. DepositWithFunctionCall, + /// Transaction is from ETH-implicit `account_id` and uses invalid `public_key` for that address. + InvalidPkForEthAddress { account_id: AccountId, public_key: PublicKey }, } /// Describes the error for validating a list of actions. @@ -485,7 +487,7 @@ pub enum ActionErrorKind { /// receipt validation. NewReceiptValidationError(ReceiptValidationError), /// Error occurs when a `CreateAccount` action is called on hex-characters - /// account of length 64 or 40. See implicit account creation NEP: + /// account of length 64 or 42. See implicit account creation NEP: /// . /// /// TODO(#8598): This error is named very poorly. A better name would be @@ -609,7 +611,12 @@ impl Display for InvalidAccessKeyError { ), InvalidAccessKeyError::DepositWithFunctionCall => { write!(f, "Having a deposit with a function call action is not allowed with a function call access key.") - } + }, + InvalidAccessKeyError::InvalidPkForEthAddress { account_id, public_key } => write!( + f, + "Address {:?} is ETH-implicit and does not correspond to the public_key {}", + account_id, public_key + ), } } } diff --git a/integration-tests/src/tests/client/features/restrict_tla.rs b/integration-tests/src/tests/client/features/restrict_tla.rs index 54a20ed597a..8ca0cadf08d 100644 --- a/integration-tests/src/tests/client/features/restrict_tla.rs +++ b/integration-tests/src/tests/client/features/restrict_tla.rs @@ -23,7 +23,7 @@ fn test_create_top_level_accounts() { .build(); // These accounts cannot be created because they are top level accounts that are not implicit. - // Note that implicit accounts have to be 64 or 40 characters long. + // Note that implicit accounts have to be 64 or 42 characters long. let top_level_accounts = [ "0x06012c8cf97bead5deae237070f9587f8e7a266da", "0a5e97870f263700f46aa00d967821199b9bc5a120", diff --git a/runtime/near-vm-runner/src/logic/logic.rs b/runtime/near-vm-runner/src/logic/logic.rs index f633da7c04a..038d0325c5a 100644 --- a/runtime/near-vm-runner/src/logic/logic.rs +++ b/runtime/near-vm-runner/src/logic/logic.rs @@ -9,7 +9,6 @@ use super::{StorageGetMode, ValuePtr}; use crate::config::Config; use crate::ProfileDataV3; use near_crypto::Secp256K1Signature; -use near_primitives_core::account::id::AccountType; use near_primitives_core::config::ExtCosts::*; use near_primitives_core::config::ViewConfig; use near_primitives_core::config::{ActionCosts, ExtCosts}; @@ -1774,14 +1773,11 @@ impl<'a> VMLogic<'a> { let (receipt_idx, sir) = self.promise_idx_to_receipt_idx_with_sir(promise_idx)?; let receiver_id = self.ext.get_receipt_receiver(receipt_idx); - let is_receiver_implicit = match receiver_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => self.config.implicit_account_creation, - AccountType::NamedAccount => false, - }; + let is_receiver_implicit = self.config.implicit_account_creation && receiver_id.get_account_type().is_implicit(); let send_fee = - transfer_send_fee(self.fees_config, sir, is_receiver_implicit, receiver_id.is_eth_implicit()); + transfer_send_fee(self.fees_config, sir, is_receiver_implicit, receiver_id.get_account_type()); let exec_fee = - transfer_exec_fee(self.fees_config, is_receiver_implicit, receiver_id.is_eth_implicit()); + transfer_exec_fee(self.fees_config, is_receiver_implicit, receiver_id.get_account_type()); let burn_gas = send_fee; let use_gas = burn_gas.checked_add(exec_fee).ok_or(HostError::IntegerOverflow)?; self.gas_counter.pay_action_accumulated(burn_gas, use_gas, ActionCosts::transfer)?; diff --git a/runtime/runtime/Cargo.toml b/runtime/runtime/Cargo.toml index 58e79b8abc3..47d3c22ff12 100644 --- a/runtime/runtime/Cargo.toml +++ b/runtime/runtime/Cargo.toml @@ -20,6 +20,7 @@ rayon.workspace = true serde.workspace = true serde_json.workspace = true sha2.workspace = true +sha3.workspace = true thiserror.workspace = true tracing.workspace = true diff --git a/runtime/runtime/src/actions.rs b/runtime/runtime/src/actions.rs index 74810945750..104ad0ac1c1 100644 --- a/runtime/runtime/src/actions.rs +++ b/runtime/runtime/src/actions.rs @@ -441,32 +441,46 @@ pub(crate) fn action_implicit_account_creation_transfer( ) { *actor_id = account_id.clone(); - let mut access_key = AccessKey::full_access(); - // Set default nonce for newly created access key to avoid transaction hash collision. - // See . - if checked_feature!("stable", AccessKeyNonceForImplicitAccounts, current_protocol_version) { - access_key.nonce = (block_height - 1) - * near_primitives::account::AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER; - } - - // TODO add support for creating ETH-implicit accounts - - // Invariant: The account_id is hex like (implicit account id). - // It holds because in the only calling site, we've checked the permissions before. - // unwrap: Can only fail if `account_id` is not NEAR-implicit. - let public_key = PublicKey::from_near_implicit_account(account_id).unwrap(); + match account_id.get_account_type() { + AccountType::NearImplicitAccount => { + let mut access_key = AccessKey::full_access(); + // Set default nonce for newly created access key to avoid transaction hash collision. + // See . + if checked_feature!("stable", AccessKeyNonceForImplicitAccounts, current_protocol_version) { + access_key.nonce = (block_height - 1) + * near_primitives::account::AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER; + } - *account = Some(Account::new( - transfer.deposit, - 0, - CryptoHash::default(), - fee_config.storage_usage_config.num_bytes_account - + public_key.len() as u64 - + borsh::object_length(&access_key).unwrap() as u64 - + fee_config.storage_usage_config.num_extra_bytes_record, - )); + // Invariant: The account_id is hex like (implicit account id). + // It holds because in the only calling site, we've checked the permissions before. + // unwrap: Can only fail if `account_id` is not NEAR-implicit. + let public_key = PublicKey::from_near_implicit_account(account_id).unwrap(); + + *account = Some(Account::new( + transfer.deposit, + 0, + CryptoHash::default(), + fee_config.storage_usage_config.num_bytes_account + + public_key.len() as u64 + + borsh::object_length(&access_key).unwrap() as u64 + + fee_config.storage_usage_config.num_extra_bytes_record, + )); + + set_access_key(state_update, account_id.clone(), public_key, &access_key); + }, + 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, + )); + }, + AccountType::NamedAccount => panic!("Should only be called for an implicit account"), + } - set_access_key(state_update, account_id.clone(), public_key, &access_key); + } pub(crate) fn action_deploy_contract( @@ -885,12 +899,8 @@ pub(crate) fn check_account_existence( } .into()); } else { - let is_implicit = match account_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => true, - AccountType::NamedAccount => false, - }; // TODO: this should be `config.implicit_account_creation`. - if config.wasm_config.implicit_account_creation && is_implicit { + if config.wasm_config.implicit_account_creation && account_id.get_account_type().is_implicit() { // 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 @@ -909,13 +919,9 @@ pub(crate) fn check_account_existence( } Action::Transfer(_) => { if account.is_none() { - let is_implicit = match account_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => true, - AccountType::NamedAccount => false, - }; return if config.wasm_config.implicit_account_creation && is_the_only_action - && is_implicit + && account_id.get_account_type().is_implicit() && !is_refund { // OK. It's implicit account creation. diff --git a/runtime/runtime/src/config.rs b/runtime/runtime/src/config.rs index b7437c04ade..8d6bf588fb7 100644 --- a/runtime/runtime/src/config.rs +++ b/runtime/runtime/src/config.rs @@ -97,15 +97,12 @@ pub fn total_send_fees( } Transfer(_) => { // Account for implicit account creation - let is_receiver_implicit = match receiver_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => config.wasm_config.implicit_account_creation, - AccountType::NamedAccount => false, - }; + let is_receiver_implicit = config.wasm_config.implicit_account_creation && receiver_id.get_account_type().is_implicit(); transfer_send_fee( fees, sender_is_receiver, is_receiver_implicit, - receiver_id.is_eth_implicit(), + receiver_id.get_account_type(), ) } Stake(_) => fees.fee(ActionCosts::stake).send_fee(sender_is_receiver), @@ -196,11 +193,8 @@ pub fn exec_fee(config: &RuntimeConfig, action: &Action, receiver_id: &AccountId } Transfer(_) => { // Account for implicit account creation - let is_receiver_implicit = match receiver_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => config.wasm_config.implicit_account_creation, - AccountType::NamedAccount => false, - }; - transfer_exec_fee(fees, is_receiver_implicit, receiver_id.is_eth_implicit()) + let is_receiver_implicit = config.wasm_config.implicit_account_creation && receiver_id.get_account_type().is_implicit(); + transfer_exec_fee(fees, is_receiver_implicit, receiver_id.get_account_type()) } Stake(_) => fees.fee(ActionCosts::stake).exec_fee(), AddKey(add_key_action) => match &add_key_action.access_key.permission { diff --git a/runtime/runtime/src/verifier.rs b/runtime/runtime/src/verifier.rs index 08323a15948..0778a2e150b 100644 --- a/runtime/runtime/src/verifier.rs +++ b/runtime/runtime/src/verifier.rs @@ -1,8 +1,9 @@ use crate::config::{total_prepaid_gas, tx_cost, TransactionCost}; use crate::near_primitives::account::Account; use crate::VerificationResult; +use near_crypto::{PublicKey, KeyType}; use near_crypto::key_conversion::is_valid_staking_key; -use near_primitives::account::AccessKeyPermission; +use near_primitives::account::{AccessKey, AccessKeyPermission}; use near_primitives::action::delegate::SignedDelegateAction; use near_primitives::checked_feature; use near_primitives::errors::{ @@ -19,6 +20,7 @@ use near_primitives::types::{AccountId, Balance}; use near_primitives::types::{BlockHeight, StorageUsage}; use near_primitives::version::ProtocolFeature; use near_primitives::version::ProtocolVersion; +use near_primitives_core::account::id::AccountType; use near_store::{ get_access_key, get_account, set_access_key, set_account, StorageError, TrieUpdate, }; @@ -123,6 +125,18 @@ pub fn validate_transaction( .map_err(|_| InvalidTxError::CostOverflow.into()) } +fn is_pk_valid_for_eth_address(public_key: &PublicKey, account_id: &AccountId) -> bool { + match public_key.key_type() { + KeyType::SECP256K1 => { + use sha3::Digest; + let pk_hash = sha3::Keccak256::digest(&public_key.key_data()); + format!("0x{}", hex::encode(&pk_hash[12..32])) == account_id.as_str() + }, + // Should panic instead? + KeyType::ED25519 => false, + } +} + /// Verifies the signed transaction on top of given state, charges transaction fees /// and balances, and updates the state for the used account and access keys. pub fn verify_and_charge_transaction( @@ -144,6 +158,7 @@ pub fn verify_and_charge_transaction( )?; let transaction = &signed_transaction.transaction; let signer_id = &transaction.signer_id; + let public_key = &transaction.public_key; let mut signer = match get_account(state_update, signer_id)? { Some(signer) => signer, @@ -151,16 +166,30 @@ pub fn verify_and_charge_transaction( return Err(InvalidTxError::SignerDoesNotExist { signer_id: signer_id.clone() }.into()); } }; - let mut access_key = match get_access_key(state_update, signer_id, &transaction.public_key)? { + let mut access_key = match get_access_key(state_update, signer_id, public_key)? { Some(access_key) => access_key, - None => { - return Err(InvalidTxError::InvalidAccessKeyError( - InvalidAccessKeyError::AccessKeyNotFound { - account_id: signer_id.clone(), - public_key: transaction.public_key.clone(), - }, - ) - .into()); + None => match signer_id.get_account_type() { + AccountType::EthImplicitAccount => { + if is_pk_valid_for_eth_address(public_key, signer_id) { + // TODO what about increasing storage usage for that account + AccessKey::full_access() + } else { + return Err(InvalidTxError::InvalidAccessKeyError( + InvalidAccessKeyError::InvalidPkForEthAddress { + account_id: signer_id.clone(), + public_key: public_key.clone(), + }) + .into()); + } + }, + _ => { + return Err(InvalidTxError::InvalidAccessKeyError( + InvalidAccessKeyError::AccessKeyNotFound { + account_id: signer_id.clone(), + public_key: public_key.clone(), + }) + .into()); + }, } }; @@ -202,7 +231,7 @@ pub fn verify_and_charge_transaction( *allowance = allowance.checked_sub(total_cost).ok_or_else(|| { InvalidTxError::InvalidAccessKeyError(InvalidAccessKeyError::NotEnoughAllowance { account_id: signer_id.clone(), - public_key: transaction.public_key.clone(), + public_key: public_key.clone(), allowance: *allowance, cost: total_cost, }) @@ -268,7 +297,7 @@ pub fn verify_and_charge_transaction( } }; - set_access_key(state_update, signer_id.clone(), transaction.public_key.clone(), &access_key); + set_access_key(state_update, signer_id.clone(), public_key.clone(), &access_key); set_account(state_update, signer_id.clone(), &signer); Ok(VerificationResult { gas_burnt, gas_remaining, receipt_gas_price, burnt_amount }) diff --git a/tools/mirror/src/genesis.rs b/tools/mirror/src/genesis.rs index 6b96edf9b53..bdc17ab138c 100644 --- a/tools/mirror/src/genesis.rs +++ b/tools/mirror/src/genesis.rs @@ -38,11 +38,7 @@ pub fn map_records>( public_key: replacement.public_key(), access_key: access_key.clone(), }; - let is_implicit = match account_id.get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => true, - AccountType::NamedAccount => false, - }; - if !is_implicit && access_key.permission == AccessKeyPermission::FullAccess { + if !account_id.get_account_type().is_implicit() && access_key.permission == AccessKeyPermission::FullAccess { has_full_key.insert(account_id.clone()); } // TODO: would be nice for stream_records_from_file() to let you return early on error so @@ -50,7 +46,7 @@ pub fn map_records>( records_seq.serialize_element(&new_record).unwrap(); } StateRecord::Account { account_id, .. } => { - if account_id.is_near_implicit() { + if account_id.get_account_type() == AccountType::NearImplicitAccount { *account_id = crate::key_mapping::map_account(&account_id, secret.as_ref()); } else { accounts.insert(account_id.clone()); @@ -58,20 +54,20 @@ pub fn map_records>( records_seq.serialize_element(&r).unwrap(); } StateRecord::Data { account_id, .. } => { - if account_id.is_near_implicit() { + if account_id.get_account_type() == AccountType::NearImplicitAccount { *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.is_near_implicit() { + if account_id.get_account_type() == AccountType::NearImplicitAccount { *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.is_near_implicit() - || receipt.receiver_id.is_near_implicit() + if receipt.predecessor_id.get_account_type() == AccountType::NearImplicitAccount + || receipt.receiver_id.get_account_type() == AccountType::NearImplicitAccount { receipt.predecessor_id = crate::key_mapping::map_account(&receipt.predecessor_id, secret.as_ref()); @@ -81,14 +77,14 @@ pub fn map_records>( records_seq.serialize_element(&r).unwrap(); } StateRecord::ReceivedData { account_id, .. } => { - if account_id.is_near_implicit() { + if account_id.get_account_type() == AccountType::NearImplicitAccount { *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.is_near_implicit() - || receipt.receiver_id.is_near_implicit() + if receipt.predecessor_id.get_account_type() == AccountType::NearImplicitAccount + || receipt.receiver_id.get_account_type() == AccountType::NearImplicitAccount { receipt.predecessor_id = crate::key_mapping::map_account(&receipt.predecessor_id, secret.as_ref()); diff --git a/tools/mirror/src/key_mapping.rs b/tools/mirror/src/key_mapping.rs index a965754bebb..d9c352c74b2 100644 --- a/tools/mirror/src/key_mapping.rs +++ b/tools/mirror/src/key_mapping.rs @@ -1,5 +1,6 @@ use hkdf::Hkdf; use near_crypto::{ED25519PublicKey, ED25519SecretKey, PublicKey, Secp256K1PublicKey, SecretKey}; +use near_primitives_core::account::id::AccountType; use near_primitives::types::AccountId; use sha2::Sha256; @@ -97,7 +98,7 @@ pub fn map_account( account_id: &AccountId, secret: Option<&[u8; crate::secret::SECRET_LEN]>, ) -> AccountId { - if account_id.is_near_implicit() { + if account_id.get_account_type() == AccountType::NearImplicitAccount { let public_key = PublicKey::from_near_implicit_account(account_id).expect("must be implicit"); let mapped_key = map_key(&public_key, secret); diff --git a/tools/mirror/src/lib.rs b/tools/mirror/src/lib.rs index 096c9358f45..7fae7845e5d 100644 --- a/tools/mirror/src/lib.rs +++ b/tools/mirror/src/lib.rs @@ -989,11 +989,7 @@ impl TxMirror { actions.push(Action::DeleteKey(Box::new(DeleteKeyAction { public_key }))); } Action::Transfer(_) => { - let is_receiver_implicit = match tx.receiver_id().get_account_type() { - AccountType::NearImplicitAccount | AccountType::EthImplicitAccount => true, - AccountType::NamedAccount => false, - }; - if is_receiver_implicit && source_actions.len() == 1 { + if tx.receiver_id().get_account_type().is_implicit() && 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)