Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ETH-implicit account support #10224

Merged
merged 7 commits into from
Nov 24, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Use near / eth prefix for variable names
staffik committed Nov 24, 2023
commit f20115a60690508703ed6f48eb497e2e4f675a95
2 changes: 1 addition & 1 deletion core/primitives-core/src/version.rs
Original file line number Diff line number Diff line change
@@ -197,7 +197,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.
140
139
} else {
// Enable all stable features.
STABLE_PROTOCOL_VERSION
Original file line number Diff line number Diff line change
@@ -114,13 +114,13 @@ fn test_transaction_hash_collision() {
);
}

/// Helper for checking that duplicate transactions from implicit accounts are properly rejected.
/// It creates implicit account, deletes it and creates again, so that nonce of the access
/// key is updated. Then it tries to send tx from implicit account with invalid nonce, which
/// Helper for checking that duplicate transactions from NEAR-implicit accounts are properly rejected.
/// It creates NEAR-implicit account, deletes it and creates again, so that nonce of the access
/// key is updated. Then it tries to send tx from NEAR-implicit account with invalid nonce, which
/// should fail since the protocol upgrade.
fn get_status_of_tx_hash_collision_for_implicit_account(
fn get_status_of_tx_hash_collision_for_near_implicit_account(
protocol_version: ProtocolVersion,
implicit_account_signer: InMemorySigner,
near_implicit_account_signer: InMemorySigner,
) -> ProcessTxResponse {
let epoch_length = 100;
let mut genesis = Genesis::test(vec!["test0".parse().unwrap(), "test1".parse().unwrap()], 1);
@@ -135,66 +135,67 @@ fn get_status_of_tx_hash_collision_for_implicit_account(
let mut height = 1;
let blocks_number = 5;
let signer1 = InMemorySigner::from_seed("test1".parse().unwrap(), KeyType::ED25519, "test1");
let implicit_account_id = implicit_account_signer.account_id.clone();
let near_implicit_account_id = near_implicit_account_signer.account_id.clone();

// Send money to implicit account, invoking its creation.
// Send money to NEAR-implicit account, invoking its creation.
let send_money_tx = SignedTransaction::send_money(
1,
"test1".parse().unwrap(),
implicit_account_id.clone(),
near_implicit_account_id.clone(),
&signer1,
deposit_for_account_creation,
*genesis_block.hash(),
);
height = check_tx_processing(&mut env, send_money_tx, height, blocks_number);
let block = env.clients[0].chain.get_block_by_height(height - 1).unwrap();

// Delete implicit account.
// Delete NEAR-implicit account.
let delete_account_tx = SignedTransaction::delete_account(
// Because AccessKeyNonceRange is enabled, correctness of this nonce is guaranteed.
(height - 1) * near_primitives::account::AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER,
implicit_account_id.clone(),
implicit_account_id.clone(),
near_implicit_account_id.clone(),
near_implicit_account_id.clone(),
"test0".parse().unwrap(),
&implicit_account_signer,
&near_implicit_account_signer,
*block.hash(),
);
height = check_tx_processing(&mut env, delete_account_tx, height, blocks_number);
let block = env.clients[0].chain.get_block_by_height(height - 1).unwrap();

// Send money to implicit account again, invoking its second creation.
// Send money to NEAR-implicit account again, invoking its second creation.
let send_money_again_tx = SignedTransaction::send_money(
2,
"test1".parse().unwrap(),
implicit_account_id.clone(),
near_implicit_account_id.clone(),
&signer1,
deposit_for_account_creation,
*block.hash(),
);
height = check_tx_processing(&mut env, send_money_again_tx, height, blocks_number);
let block = env.clients[0].chain.get_block_by_height(height - 1).unwrap();

// Send money from implicit account with incorrect nonce.
let send_money_from_implicit_account_tx = SignedTransaction::send_money(
// Send money from NEAR-implicit account with incorrect nonce.
let send_money_from_near_implicit_account_tx = SignedTransaction::send_money(
1,
implicit_account_id.clone(),
near_implicit_account_id.clone(),
"test0".parse().unwrap(),
&implicit_account_signer,
&near_implicit_account_signer,
100,
*block.hash(),
);
let response = env.clients[0].process_tx(send_money_from_implicit_account_tx, false, false);
let response =
env.clients[0].process_tx(send_money_from_near_implicit_account_tx, false, false);

// Check that sending money from implicit account with correct nonce is still valid.
let send_money_from_implicit_account_tx = SignedTransaction::send_money(
// Check that sending money from NEAR-implicit account with correct nonce is still valid.
let send_money_from_near_implicit_account_tx = SignedTransaction::send_money(
(height - 1) * AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER,
implicit_account_id,
near_implicit_account_id,
"test0".parse().unwrap(),
&implicit_account_signer,
&near_implicit_account_signer,
100,
*block.hash(),
);
check_tx_processing(&mut env, send_money_from_implicit_account_tx, height, blocks_number);
check_tx_processing(&mut env, send_money_from_near_implicit_account_tx, height, blocks_number);

response
}
@@ -204,12 +205,13 @@ fn get_status_of_tx_hash_collision_for_implicit_account(
fn test_transaction_hash_collision_for_near_implicit_account_fail() {
let protocol_version = ProtocolFeature::AccessKeyNonceForImplicitAccounts.protocol_version();
let secret_key = SecretKey::from_seed(KeyType::ED25519, "test");
let implicit_account_id = derive_account_id_from_public_key(&secret_key.public_key());
let implicit_account_signer = InMemorySigner::from_secret_key(implicit_account_id, secret_key);
let near_implicit_account_id = derive_account_id_from_public_key(&secret_key.public_key());
let near_implicit_account_signer =
InMemorySigner::from_secret_key(near_implicit_account_id, secret_key);
assert_matches!(
get_status_of_tx_hash_collision_for_implicit_account(
get_status_of_tx_hash_collision_for_near_implicit_account(
protocol_version,
implicit_account_signer
near_implicit_account_signer
),
ProcessTxResponse::InvalidTx(InvalidTxError::InvalidNonce { .. })
);
@@ -221,12 +223,13 @@ fn test_transaction_hash_collision_for_near_implicit_account_ok() {
let protocol_version =
ProtocolFeature::AccessKeyNonceForImplicitAccounts.protocol_version() - 1;
let secret_key = SecretKey::from_seed(KeyType::ED25519, "test");
let implicit_account_id = derive_account_id_from_public_key(&secret_key.public_key());
let implicit_account_signer = InMemorySigner::from_secret_key(implicit_account_id, secret_key);
let near_implicit_account_id = derive_account_id_from_public_key(&secret_key.public_key());
let near_implicit_account_signer =
InMemorySigner::from_secret_key(near_implicit_account_id, secret_key);
assert_matches!(
get_status_of_tx_hash_collision_for_implicit_account(
get_status_of_tx_hash_collision_for_near_implicit_account(
protocol_version,
implicit_account_signer
near_implicit_account_signer
),
ProcessTxResponse::ValidTx
);
@@ -251,15 +254,15 @@ fn test_transaction_from_eth_implicit_account_fail() {

let secret_key = SecretKey::from_seed(KeyType::SECP256K1, "test");
let public_key = secret_key.public_key();
let implicit_account_id = derive_account_id_from_public_key(&public_key);
let implicit_account_signer =
InMemorySigner::from_secret_key(implicit_account_id.clone(), secret_key);
let eth_implicit_account_id = derive_account_id_from_public_key(&public_key);
let eth_implicit_account_signer =
InMemorySigner::from_secret_key(eth_implicit_account_id.clone(), secret_key);

// Send money to ETH-implicit account, invoking its creation.
let send_money_tx = SignedTransaction::send_money(
1,
"test1".parse().unwrap(),
implicit_account_id.clone(),
eth_implicit_account_id.clone(),
&signer1,
deposit_for_account_creation,
*genesis_block.hash(),
@@ -271,61 +274,63 @@ fn test_transaction_from_eth_implicit_account_fail() {
// Try to send money from ETH-implicit account using `(block_height - 1) * 1e6` as a nonce.
// That would be a good nonce for any access key, but the transaction should fail nonetheless because there is no access key.
let nonce = (height - 1) * AccessKey::ACCESS_KEY_NONCE_RANGE_MULTIPLIER;
let send_money_from_implicit_account_tx = SignedTransaction::send_money(
let send_money_from_eth_implicit_account_tx = SignedTransaction::send_money(
nonce,
implicit_account_id.clone(),
eth_implicit_account_id.clone(),
"test0".parse().unwrap(),
&implicit_account_signer,
&eth_implicit_account_signer,
100,
*block.hash(),
);
let response = env.clients[0].process_tx(send_money_from_implicit_account_tx, false, false);
let response = env.clients[0].process_tx(send_money_from_eth_implicit_account_tx, false, false);
let expected_tx_error = ProcessTxResponse::InvalidTx(InvalidTxError::InvalidAccessKeyError(
InvalidAccessKeyError::AccessKeyNotFound {
account_id: implicit_account_id.clone(),
account_id: eth_implicit_account_id.clone(),
public_key: public_key.clone(),
},
));
assert_eq!(response, expected_tx_error);

// Try to delete ETH-implicit account.
let delete_implicit_account_tx = SignedTransaction::delete_account(
// Try to delete ETH-implicit account. Should fail because there is no access key.
let delete_eth_implicit_account_tx = SignedTransaction::delete_account(
nonce,
implicit_account_id.clone(),
implicit_account_id.clone(),
eth_implicit_account_id.clone(),
eth_implicit_account_id.clone(),
"test0".parse().unwrap(),
&implicit_account_signer,
&eth_implicit_account_signer,
*block.hash(),
);
let response = env.clients[0].process_tx(delete_implicit_account_tx, false, false);
let response = env.clients[0].process_tx(delete_eth_implicit_account_tx, false, false);
assert_eq!(response, expected_tx_error);

// Try to add an access key to the ETH-implicit account.
let add_access_key_to_implicit_account_tx = SignedTransaction::from_actions(
// Try to add an access key to the ETH-implicit account. Should fail because there is no access key.
let add_access_key_to_eth_implicit_account_tx = SignedTransaction::from_actions(
nonce,
implicit_account_id.clone(),
implicit_account_id.clone(),
&implicit_account_signer,
eth_implicit_account_id.clone(),
eth_implicit_account_id.clone(),
&eth_implicit_account_signer,
vec![Action::AddKey(Box::new(AddKeyAction {
public_key,
access_key: AccessKey::full_access(),
}))],
*block.hash(),
);
let response = env.clients[0].process_tx(add_access_key_to_implicit_account_tx, false, false);
let response =
env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false);
assert_eq!(response, expected_tx_error);

// Try to deploy the Wallet Contract again to the ETH-implicit account.
// Try to deploy the Wallet Contract again to the ETH-implicit account. Should fail because there is no access key.
let wallet_contract_code = wallet_contract_placeholder().code().to_vec();
let add_access_key_to_implicit_account_tx = SignedTransaction::from_actions(
let add_access_key_to_eth_implicit_account_tx = SignedTransaction::from_actions(
nonce,
implicit_account_id.clone(),
implicit_account_id,
&implicit_account_signer,
eth_implicit_account_id.clone(),
eth_implicit_account_id,
&eth_implicit_account_signer,
vec![Action::DeployContract(DeployContractAction { code: wallet_contract_code })],
*block.hash(),
);
let response = env.clients[0].process_tx(add_access_key_to_implicit_account_tx, false, false);
let response =
env.clients[0].process_tx(add_access_key_to_eth_implicit_account_tx, false, false);
assert_eq!(response, expected_tx_error);
}

10 changes: 5 additions & 5 deletions integration-tests/src/tests/client/features/delegate_action.rs
Original file line number Diff line number Diff line change
@@ -143,7 +143,7 @@ fn check_meta_tx_execution(
AccountType::NearImplicitAccount => PublicKey::from_near_implicit_account(&sender).unwrap(),
AccountType::EthImplicitAccount => {
if checked_feature!("stable", EthImplicit, protocol_version) {
// Eth-implicit accounts must not have access key.
// ETH-implicit accounts must not have access key.
panic!("No access keys");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can you change the panic message to the comment above and remove the comment?

} else {
PublicKey::from_seed(KeyType::ED25519, sender.as_ref())
@@ -826,10 +826,10 @@ fn meta_tx_create_eth_implicit_account_fails() {
/// in the same meta transaction.
///
/// This is expected to fail with `AccountDoesNotExist`, known limitation of NEP-366.
/// In case of Near-implicit accounts it only works with accounts that already exist
/// In case of NEAR-implicit accounts it only works with accounts that already exist
/// because it needs to do a nonce check against the access key,
/// which can only exist if the account exists.
/// In case of Eth-implicit accounts the access key does not exist anyway.
/// In case of ETH-implicit accounts the access key does not exist anyway.
fn meta_tx_create_and_use_implicit_account(new_account: AccountId) {
let relayer = bob_account();
let sender = alice_account();
@@ -876,8 +876,8 @@ fn meta_tx_create_and_use_eth_implicit_account() {
/// pays for the storage and the user could delete the account and cash in,
/// hence this workflow is not ideal from all circumstances.
///
/// Using the account should only work for Near-implicit accounts,
/// as Eth-implicit accounts do not have access keys
/// Using the account should only work for NEAR-implicit accounts,
/// as ETH-implicit accounts do not have access keys
/// and they can only be used by calling associated smart contract.
fn meta_tx_create_implicit_account(new_account: AccountId) {
let relayer = bob_account();