From e4cca01d862fd3634214fff20f148c07018e4e7a Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Tue, 14 Feb 2023 10:46:19 +0100 Subject: [PATCH 1/4] test: meta transaction account creation scenarios Integration tests for different ways of creating accounts. This adds some test utilities for implicit accounts, and it fixes the meta tx checker functions to also work with implicit accounts, as they don't use the account name as seed for the access key. --- Cargo.lock | 1 + core/crypto/Cargo.toml | 1 + core/crypto/src/test_utils.rs | 14 ++ core/primitives/src/test_utils.rs | 21 ++- .../tests/client/features/delegate_action.rs | 178 ++++++++++++++++-- test-utils/testlib/src/fees_utils.rs | 12 +- 6 files changed, 209 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3aa877cddbe..8ab8e8016d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3209,6 +3209,7 @@ dependencies = [ "curve25519-dalek", "derive_more", "ed25519-dalek", + "hex", "hex-literal", "near-account-id", "near-config-utils", diff --git a/core/crypto/Cargo.toml b/core/crypto/Cargo.toml index 2a0a0ac9c1c..c6d4947f631 100644 --- a/core/crypto/Cargo.toml +++ b/core/crypto/Cargo.toml @@ -18,6 +18,7 @@ c2-chacha.workspace = true curve25519-dalek.workspace = true derive_more.workspace = true ed25519-dalek.workspace = true +hex.workspace = true near-account-id = { path = "../account-id" } once_cell.workspace = true primitive-types.workspace = true diff --git a/core/crypto/src/test_utils.rs b/core/crypto/src/test_utils.rs index 08e8435f5fa..7e15e80ca80 100644 --- a/core/crypto/src/test_utils.rs +++ b/core/crypto/src/test_utils.rs @@ -1,3 +1,4 @@ +use borsh::BorshDeserialize; use secp256k1::rand::SeedableRng; use crate::signature::{ED25519PublicKey, ED25519SecretKey, KeyType, PublicKey, SecretKey}; @@ -33,6 +34,19 @@ impl PublicKey { _ => unimplemented!(), } } + + pub fn from_implicit_account(account_id: &AccountId) -> Self { + assert!(account_id.is_implicit()); + let mut public_key_data = Vec::with_capacity(33); + public_key_data.push(KeyType::ED25519 as u8); + public_key_data.extend( + hex::decode(account_id.as_ref().as_bytes()) + .expect("account id was a valid hex of length 64 resulting in 32 bytes"), + ); + assert_eq!(public_key_data.len(), 33); + PublicKey::try_from_slice(&public_key_data) + .expect("we should be able to deserialize ED25519 public key") + } } impl SecretKey { diff --git a/core/primitives/src/test_utils.rs b/core/primitives/src/test_utils.rs index b9296f7dc44..9d0577e3092 100644 --- a/core/primitives/src/test_utils.rs +++ b/core/primitives/src/test_utils.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::sync::Arc; -use near_crypto::{EmptySigner, InMemorySigner, KeyType, PublicKey, Signature, Signer}; +use near_crypto::{EmptySigner, InMemorySigner, KeyType, PublicKey, SecretKey, Signature, Signer}; use near_primitives_core::types::ProtocolVersion; use crate::account::{AccessKey, AccessKeyPermission, Account}; @@ -491,9 +491,26 @@ pub fn create_test_signer(account_name: &str) -> InMemoryValidatorSigner { /// Helper function that creates a new signer for a given account, that uses the account name as seed. /// +/// This also works for predefined implicit accounts, where the signer will use the implicit key. +/// /// Should be used only in tests. pub fn create_user_test_signer(account_name: &str) -> InMemorySigner { - InMemorySigner::from_seed(account_name.parse().unwrap(), KeyType::ED25519, account_name) + let account_id = account_name.parse().unwrap(); + if account_id == implicit_test_account() { + InMemorySigner::from_secret_key(account_id, implicit_test_account_secret()) + } else { + InMemorySigner::from_seed(account_id, KeyType::ED25519, account_name) + } +} + +/// A fixed implicit account for which tests can know the private key. +pub fn implicit_test_account() -> AccountId { + "061b1dd17603213b00e1a1e53ba060ad427cef4887bd34a5e0ef09010af23b0a".parse().unwrap() +} + +/// Private key for the fixed implicit test account. +pub fn implicit_test_account_secret() -> SecretKey { + "ed25519:5roj6k68kvZu3UEJFyXSfjdKGrodgZUfFLZFpzYXWtESNsLWhYrq3JGi4YpqeVKuw1m9R2TEHjfgWT1fjUqB1DNy".parse().unwrap() } impl FinalExecutionOutcomeView { diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index 20d8861519c..f19cc61c2b0 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -12,18 +12,20 @@ use near_client::test_utils::TestEnv; use near_crypto::{KeyType, PublicKey}; use near_primitives::account::AccessKey; use near_primitives::config::ActionCosts; -use near_primitives::errors::{ActionsValidationError, InvalidTxError, TxExecutionError}; -use near_primitives::test_utils::create_user_test_signer; +use near_primitives::errors::{ + ActionError, ActionErrorKind, ActionsValidationError, InvalidTxError, TxExecutionError, +}; +use near_primitives::test_utils::{create_user_test_signer, implicit_test_account}; use near_primitives::transaction::{ - Action, AddKeyAction, DeleteAccountAction, DeleteKeyAction, DeployContractAction, - FunctionCallAction, StakeAction, TransferAction, + Action, AddKeyAction, CreateAccountAction, DeleteAccountAction, DeleteKeyAction, + DeployContractAction, FunctionCallAction, StakeAction, TransferAction, }; use near_primitives::types::{AccountId, Balance}; use near_primitives::version::{ProtocolFeature, ProtocolVersion}; use near_primitives::views::{ AccessKeyPermissionView, FinalExecutionOutcomeView, FinalExecutionStatus, }; -use near_test_contracts::smallest_rs_contract; +use near_test_contracts::{ft_contract, smallest_rs_contract}; use nearcore::config::GenesisExt; use nearcore::NEAR_BASE; use testlib::runtime_utils::{ @@ -117,15 +119,17 @@ fn check_meta_tx_execution( let sender_before = node_user.view_balance(&sender).unwrap(); let relayer_before = node_user.view_balance(&relayer).unwrap(); - let receiver_before = node_user.view_balance(&receiver).unwrap(); + let receiver_before = node_user.view_balance(&receiver).unwrap_or(0); let relayer_nonce_before = node_user .get_access_key(&relayer, &PublicKey::from_seed(KeyType::ED25519, &relayer)) .unwrap() .nonce; - let user_nonce_before = node_user - .get_access_key(&sender, &PublicKey::from_seed(KeyType::ED25519, &sender)) - .unwrap() - .nonce; + let user_pubk = if sender.is_implicit() { + PublicKey::from_implicit_account(&sender) + } else { + PublicKey::from_seed(KeyType::ED25519, &sender) + }; + let user_nonce_before = node_user.get_access_key(&sender, &user_pubk).unwrap().nonce; let tx_result = node_user .meta_tx(sender.clone(), receiver.clone(), relayer.clone(), actions.clone()) @@ -171,7 +175,8 @@ fn check_meta_tx_no_fn_call( receiver: AccountId, ) -> FinalExecutionOutcomeView { let fee_helper = fee_helper(node); - let gas_cost = normal_tx_cost + fee_helper.meta_tx_overhead_cost(&actions); + let gas_cost = + normal_tx_cost + fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); let (tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(node, actions, sender, relayer, receiver); @@ -203,7 +208,7 @@ fn check_meta_tx_fn_call( ) -> FinalExecutionOutcomeView { let fee_helper = fee_helper(node); let num_fn_calls = actions.len(); - let meta_tx_overhead_cost = fee_helper.meta_tx_overhead_cost(&actions); + let meta_tx_overhead_cost = fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); let (tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(node, actions, sender, relayer, receiver); @@ -401,8 +406,8 @@ fn meta_tx_delete_account() { vec![Action::DeleteAccount(DeleteAccountAction { beneficiary_id: relayer.clone() })]; // special case balance check for deleting account - let gas_cost = - fee_helper.prepaid_delete_account_cost() + fee_helper.meta_tx_overhead_cost(&actions); + let gas_cost = fee_helper.prepaid_delete_account_cost() + + fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); let (_tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(&node, actions, sender, relayer, receiver.clone()); @@ -572,3 +577,148 @@ fn assert_ft_balance( let balance = std::str::from_utf8(&response.result).expect("invalid UTF8"); assert_eq!(format!("\"{expected_balance}\""), balance); } + +/// Test account creation scenarios with meta transactions. +/// +/// Named accounts aren't the primary use case for meta transactions but still +/// worth a test case. +#[test] +fn meta_tx_create_named_account() { + let relayer = bob_account(); + let sender = alice_account(); + let new_account = eve_dot_alice_account(); + let node = RuntimeNode::new(&relayer); + + let fee_helper = fee_helper(&node); + let amount = NEAR_BASE; + + let public_key = PublicKey::from_seed(KeyType::ED25519, &new_account); + + // That's the minium to create a (useful) account. + let actions = vec![ + Action::CreateAccount(CreateAccountAction {}), + Action::Transfer(TransferAction { deposit: amount }), + Action::AddKey(AddKeyAction { public_key, access_key: AccessKey::full_access() }), + ]; + + // Check account doesn't exist, yet + node.view_account(&new_account).expect_err("account already exists"); + + let tx_cost = fee_helper.create_account_transfer_full_key_cost(); + check_meta_tx_no_fn_call(&node, actions, tx_cost, amount, sender, relayer, new_account.clone()); + + // Check account exists + node.view_account(&new_account).expect("failed looking up account"); +} + +/// Try creating an implicit account with `CreateAction` which is not allowed in +/// or outside meta transactions and must fail with `OnlyImplicitAccountCreationAllowed`. +#[test] +fn meta_tx_create_implicit_account_fails() { + let relayer = bob_account(); + let sender = alice_account(); + let new_account: AccountId = implicit_test_account(); + let node = RuntimeNode::new(&relayer); + + let actions = vec![Action::CreateAccount(CreateAccountAction {})]; + let tx_result = node + .user() + .meta_tx(sender.clone(), new_account.clone(), relayer.clone(), actions.clone()) + .unwrap(); + + let account_creation_result = &tx_result.receipts_outcome[1].outcome.status; + assert!(matches!( + account_creation_result, + near_primitives::views::ExecutionStatusView::Failure(TxExecutionError::ActionError( + ActionError { kind: ActionErrorKind::OnlyImplicitAccountCreationAllowed { .. }, .. } + )), + )); +} + +/// Try creating an implicit account with a meta tx transfer and use the account +/// in the same meta transaction. +/// +/// This is expected to fail with `AccountDoesNotExist` as noted in NEP-366. +#[test] +fn meta_tx_create_and_use_implicit_account() { + let relayer = bob_account(); + let sender = alice_account(); + let new_account: AccountId = implicit_test_account(); + let node = RuntimeNode::new(&relayer); + + // Check account doesn't exist, yet + node.view_account(&new_account).expect_err("account already exists"); + + let initial_amount = nearcore::NEAR_BASE; + let actions = vec![ + Action::Transfer(TransferAction { deposit: initial_amount }), + Action::DeployContract(DeployContractAction { code: ft_contract().to_vec() }), + ]; + + // execute and expect `AccountDoesNotExist` + let tx_result = + node.user().meta_tx(sender.clone(), new_account.clone(), relayer.clone(), actions).unwrap(); + let status = &tx_result.receipts_outcome[1].outcome.status; + assert!(matches!( + status, + near_primitives::views::ExecutionStatusView::Failure(TxExecutionError::ActionError( + ActionError { kind: ActionErrorKind::AccountDoesNotExist { account_id }, .. } + )) if *account_id == new_account, + )); +} + +/// Creating an implicit account with a meta tx transfer and use the account in +/// a second meta transaction. +/// +/// Creation through a meta tx should work as normal, it's just that the relayer +/// pays for the storage and the user could delete the account and cash in, +/// hence this workflow is not ideal from all circumstances. +#[test] +fn meta_tx_create_implicit_account() { + let relayer = bob_account(); + let sender = alice_account(); + let new_account: AccountId = implicit_test_account(); + let node = RuntimeNode::new(&relayer); + + // Check account doesn't exist, yet + node.view_account(&new_account).expect_err("account already exists"); + + let fee_helper = fee_helper(&node); + let initial_amount = nearcore::NEAR_BASE; + let actions = vec![Action::Transfer(TransferAction { deposit: initial_amount })]; + let tx_cost = fee_helper.create_account_transfer_full_key_cost(); + check_meta_tx_no_fn_call( + &node, + actions, + tx_cost, + initial_amount, + sender.clone(), + relayer.clone(), + new_account.clone(), + ); + + // Check account exists with expected balance + node.view_account(&new_account).expect("failed looking up account"); + let balance = node.view_balance(&new_account).expect("failed looking up balance"); + assert_eq!(balance, initial_amount); + + // Now test we can use this account in a meta transaction that sends back half the tokens to alice. + let transfer_amount = initial_amount / 2; + let actions = vec![Action::Transfer(TransferAction { deposit: transfer_amount })]; + let tx_cost = fee_helper.transfer_cost(); + check_meta_tx_no_fn_call( + &node, + actions, + tx_cost, + transfer_amount, + new_account.clone(), + relayer, + sender, + ) + .assert_success(); + + // balance of the new account should NOT change, the relayer pays for it! + // (note: relayer balance checks etc are done in the shared checker function) + let balance = node.view_balance(&new_account).expect("failed looking up balance"); + assert_eq!(balance, initial_amount); +} diff --git a/test-utils/testlib/src/fees_utils.rs b/test-utils/testlib/src/fees_utils.rs index 935273a0049..8d00de19b9f 100644 --- a/test-utils/testlib/src/fees_utils.rs +++ b/test-utils/testlib/src/fees_utils.rs @@ -176,7 +176,7 @@ impl FeeHelper { /// - The base cost of the delegate action (send and exec). /// - The additional send cost for all inner actions. #[cfg(feature = "protocol_feature_nep366_delegate_action")] - pub fn meta_tx_overhead_cost(&self, actions: &[Action]) -> Balance { + pub fn meta_tx_overhead_cost(&self, actions: &[Action], is_receiver_implicit: bool) -> Balance { // for tests, we assume sender != receiver let sir = false; let base = self.cfg.fee(ActionCosts::delegate); @@ -196,7 +196,15 @@ impl FeeHelper { + self.cfg.fee(ActionCosts::function_call_byte).send_fee(sir) * num_bytes as u64 } - Action::Transfer(_) => self.cfg.fee(ActionCosts::transfer).send_fee(sir), + Action::Transfer(_) => { + if is_receiver_implicit { + self.cfg.fee(ActionCosts::transfer).send_fee(sir) + + self.cfg.fee(ActionCosts::create_account).send_fee(sir) + + self.cfg.fee(ActionCosts::add_full_access_key).send_fee(sir) + } else { + self.cfg.fee(ActionCosts::transfer).send_fee(sir) + } + } Action::Stake(_) => self.cfg.fee(ActionCosts::stake).send_fee(sir), Action::AddKey(AddKeyAction { access_key: AccessKey { permission, .. }, .. From de56b4fae66bc8deda9b8a147c73dd70fe7a188c Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 17 Feb 2023 13:00:13 +0100 Subject: [PATCH 2/4] reuse `total_send_fees` --- Cargo.lock | 1 + .../tests/client/features/delegate_action.rs | 7 +- test-utils/testlib/Cargo.toml | 1 + test-utils/testlib/src/fees_utils.rs | 71 +++++-------------- 4 files changed, 22 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ab8e8016d3..2e69f7201d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5981,6 +5981,7 @@ dependencies = [ "near-crypto", "near-primitives", "near-test-contracts", + "node-runtime", "once_cell", ] diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index f19cc61c2b0..d3b984f4ccb 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -175,8 +175,7 @@ fn check_meta_tx_no_fn_call( receiver: AccountId, ) -> FinalExecutionOutcomeView { let fee_helper = fee_helper(node); - let gas_cost = - normal_tx_cost + fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); + let gas_cost = normal_tx_cost + fee_helper.meta_tx_overhead_cost(&actions, &receiver); let (tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(node, actions, sender, relayer, receiver); @@ -208,7 +207,7 @@ fn check_meta_tx_fn_call( ) -> FinalExecutionOutcomeView { let fee_helper = fee_helper(node); let num_fn_calls = actions.len(); - let meta_tx_overhead_cost = fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); + let meta_tx_overhead_cost = fee_helper.meta_tx_overhead_cost(&actions, &receiver); let (tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(node, actions, sender, relayer, receiver); @@ -407,7 +406,7 @@ fn meta_tx_delete_account() { // special case balance check for deleting account let gas_cost = fee_helper.prepaid_delete_account_cost() - + fee_helper.meta_tx_overhead_cost(&actions, receiver.is_implicit()); + + fee_helper.meta_tx_overhead_cost(&actions, &receiver); let (_tx_result, sender_diff, relayer_diff, receiver_diff) = check_meta_tx_execution(&node, actions, sender, relayer, receiver.clone()); diff --git a/test-utils/testlib/Cargo.toml b/test-utils/testlib/Cargo.toml index 1f6f54a089e..a991f382401 100644 --- a/test-utils/testlib/Cargo.toml +++ b/test-utils/testlib/Cargo.toml @@ -13,6 +13,7 @@ near-chain = { path = "../../chain/chain" } near-crypto = { path = "../../core/crypto" } near-primitives = { path = "../../core/primitives" } near-test-contracts = { path = "../../runtime/near-test-contracts" } +node-runtime = { path = "../../runtime/runtime" } [features] default = [] diff --git a/test-utils/testlib/src/fees_utils.rs b/test-utils/testlib/src/fees_utils.rs index 8d00de19b9f..0e0b3ed76a0 100644 --- a/test-utils/testlib/src/fees_utils.rs +++ b/test-utils/testlib/src/fees_utils.rs @@ -1,15 +1,11 @@ //! Helper functions to compute the costs of certain actions assuming they succeed and the only //! actions in the transaction batch. -#[cfg(feature = "protocol_feature_nep366_delegate_action")] -use near_primitives::account::AccessKeyPermission; -#[cfg(feature = "protocol_feature_nep366_delegate_action")] -use near_primitives::account::{AccessKey, FunctionCallPermission}; use near_primitives::config::ActionCosts; use near_primitives::runtime::fees::RuntimeFeesConfig; #[cfg(feature = "protocol_feature_nep366_delegate_action")] -use near_primitives::transaction::{ - Action, AddKeyAction, DeployContractAction, FunctionCallAction, -}; +use near_primitives::transaction::Action; +#[cfg(feature = "protocol_feature_nep366_delegate_action")] +use near_primitives::types::AccountId; use near_primitives::types::{Balance, Gas}; pub struct FeeHelper { @@ -176,57 +172,24 @@ impl FeeHelper { /// - The base cost of the delegate action (send and exec). /// - The additional send cost for all inner actions. #[cfg(feature = "protocol_feature_nep366_delegate_action")] - pub fn meta_tx_overhead_cost(&self, actions: &[Action], is_receiver_implicit: bool) -> Balance { + pub fn meta_tx_overhead_cost(&self, actions: &[Action], receiver: &AccountId) -> Balance { // for tests, we assume sender != receiver + + use near_primitives::version::PROTOCOL_VERSION; let sir = false; let base = self.cfg.fee(ActionCosts::delegate); let receipt = self.cfg.fee(ActionCosts::new_action_receipt); - let mut total_gas = base.exec_fee() + base.send_fee(false) + receipt.send_fee(sir); - for action in actions { - let send_gas = match action { - Action::CreateAccount(_) => self.cfg.fee(ActionCosts::create_account).send_fee(sir), - Action::DeployContract(DeployContractAction { code }) => { - self.cfg.fee(ActionCosts::deploy_contract_base).send_fee(sir) - + self.cfg.fee(ActionCosts::deploy_contract_byte).send_fee(sir) - * code.len() as u64 - } - Action::FunctionCall(FunctionCallAction { method_name, args, .. }) => { - let num_bytes = method_name.len() + args.len(); - self.cfg.fee(ActionCosts::function_call_base).send_fee(sir) - + self.cfg.fee(ActionCosts::function_call_byte).send_fee(sir) - * num_bytes as u64 - } - Action::Transfer(_) => { - if is_receiver_implicit { - self.cfg.fee(ActionCosts::transfer).send_fee(sir) - + self.cfg.fee(ActionCosts::create_account).send_fee(sir) - + self.cfg.fee(ActionCosts::add_full_access_key).send_fee(sir) - } else { - self.cfg.fee(ActionCosts::transfer).send_fee(sir) - } - } - Action::Stake(_) => self.cfg.fee(ActionCosts::stake).send_fee(sir), - Action::AddKey(AddKeyAction { - access_key: AccessKey { permission, .. }, .. - }) => match permission { - AccessKeyPermission::FunctionCall(FunctionCallPermission { - method_names, - .. - }) => { - self.cfg.fee(ActionCosts::add_function_call_key_base).send_fee(sir) - + self.cfg.fee(ActionCosts::add_function_call_key_byte).send_fee(sir) - * method_names.len() as u64 - } - AccessKeyPermission::FullAccess => { - self.cfg.fee(ActionCosts::add_full_access_key).send_fee(sir) - } - }, - Action::DeleteKey(_) => self.cfg.fee(ActionCosts::delete_key).send_fee(sir), - Action::DeleteAccount(_) => self.cfg.fee(ActionCosts::delete_account).send_fee(sir), - Action::Delegate(_) => self.cfg.fee(ActionCosts::delegate).send_fee(sir), - }; - total_gas += send_gas; - } + let total_gas = base.exec_fee() + + base.send_fee(sir) + + receipt.send_fee(sir) + + node_runtime::config::total_send_fees( + &self.cfg, + sir, + actions, + receiver, + PROTOCOL_VERSION, + ) + .unwrap(); self.gas_to_balance(total_gas) } } From 0f977e22d937f889a7f8482fad6be0b83cfd6000 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 17 Feb 2023 23:02:22 +0100 Subject: [PATCH 3/4] update various comments --- core/primitives/src/errors.rs | 3 +++ .../src/tests/client/features/delegate_action.rs | 15 +++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/core/primitives/src/errors.rs b/core/primitives/src/errors.rs index 469f6d9efe3..08235ddc2b6 100644 --- a/core/primitives/src/errors.rs +++ b/core/primitives/src/errors.rs @@ -468,6 +468,9 @@ pub enum ActionErrorKind { /// Error occurs when a `CreateAccount` action is called on hex-characters /// account of length 64. See implicit account creation NEP: /// . + /// + /// TODO(#8598): This error is named very poorly. A better name would be + /// `OnlyNamedAccountCreationAllowed`. OnlyImplicitAccountCreationAllowed { account_id: AccountId }, /// Delete account whose state is large is temporarily banned. DeleteAccountWithLargeState { account_id: AccountId }, diff --git a/integration-tests/src/tests/client/features/delegate_action.rs b/integration-tests/src/tests/client/features/delegate_action.rs index d3b984f4ccb..e8245d7e0c0 100644 --- a/integration-tests/src/tests/client/features/delegate_action.rs +++ b/integration-tests/src/tests/client/features/delegate_action.rs @@ -593,20 +593,20 @@ fn meta_tx_create_named_account() { let public_key = PublicKey::from_seed(KeyType::ED25519, &new_account); - // That's the minium to create a (useful) account. + // That's the minimum to create a (useful) account. let actions = vec![ Action::CreateAccount(CreateAccountAction {}), Action::Transfer(TransferAction { deposit: amount }), Action::AddKey(AddKeyAction { public_key, access_key: AccessKey::full_access() }), ]; - // Check account doesn't exist, yet + // Check the account doesn't exist, yet. We want to create it. node.view_account(&new_account).expect_err("account already exists"); let tx_cost = fee_helper.create_account_transfer_full_key_cost(); check_meta_tx_no_fn_call(&node, actions, tx_cost, amount, sender, relayer, new_account.clone()); - // Check account exists + // Check the account exists after we created it. node.view_account(&new_account).expect("failed looking up account"); } @@ -637,7 +637,9 @@ fn meta_tx_create_implicit_account_fails() { /// Try creating an implicit account with a meta tx transfer and use the account /// in the same meta transaction. /// -/// This is expected to fail with `AccountDoesNotExist` as noted in NEP-366. +/// This is expected to fail with `AccountDoesNotExist`, known limitation of NEP-366. +/// It only works with accounts that already exists because it needs to do a +/// nonce check against the access key, which can only exist if the account exists. #[test] fn meta_tx_create_and_use_implicit_account() { let relayer = bob_account(); @@ -645,7 +647,7 @@ fn meta_tx_create_and_use_implicit_account() { let new_account: AccountId = implicit_test_account(); let node = RuntimeNode::new(&relayer); - // Check account doesn't exist, yet + // Check the account doesn't exist, yet. We will attempt creating it. node.view_account(&new_account).expect_err("account already exists"); let initial_amount = nearcore::NEAR_BASE; @@ -654,7 +656,8 @@ fn meta_tx_create_and_use_implicit_account() { Action::DeployContract(DeployContractAction { code: ft_contract().to_vec() }), ]; - // execute and expect `AccountDoesNotExist` + // Execute and expect `AccountDoesNotExist`, as we try to call a meta + // transaction on a user that doesn't exist yet. let tx_result = node.user().meta_tx(sender.clone(), new_account.clone(), relayer.clone(), actions).unwrap(); let status = &tx_result.receipts_outcome[1].outcome.status; From 9c72eb780af3ca2de2c6539bed5da1758d4a3429 Mon Sep 17 00:00:00 2001 From: Jakob Meier Date: Fri, 17 Feb 2023 23:14:47 +0100 Subject: [PATCH 4/4] rm whitespace --- core/primitives/src/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/primitives/src/errors.rs b/core/primitives/src/errors.rs index 08235ddc2b6..211e67bf4e5 100644 --- a/core/primitives/src/errors.rs +++ b/core/primitives/src/errors.rs @@ -468,7 +468,7 @@ pub enum ActionErrorKind { /// Error occurs when a `CreateAccount` action is called on hex-characters /// account of length 64. See implicit account creation NEP: /// . - /// + /// /// TODO(#8598): This error is named very poorly. A better name would be /// `OnlyNamedAccountCreationAllowed`. OnlyImplicitAccountCreationAllowed { account_id: AccountId },