Skip to content

Commit

Permalink
feat: access key mgmt for relayer
Browse files Browse the repository at this point in the history
add/remove relayer keys for fast submit calls
  • Loading branch information
vzctl committed Feb 4, 2023
1 parent 5675e75 commit 2fe577d
Show file tree
Hide file tree
Showing 12 changed files with 525 additions and 34 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 9 additions & 11 deletions engine-sdk/src/near_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ impl crate::promise::PromiseHandler for Runtime {
receiver_id,
function_names,
} => {
feature_gated!("all-promise-actions", {
{
let pk: RawPublicKey = public_key.into();
let pk_bytes = pk.as_bytes();
let allowance = allowance.as_u128();
Expand All @@ -432,18 +432,16 @@ impl crate::promise::PromiseHandler for Runtime {
function_names.len() as _,
function_names.as_ptr() as _,
)
});
};
}
PromiseAction::DeleteKey { public_key } => {
feature_gated!("all-promise-actions", {
let pk: RawPublicKey = public_key.into();
let pk_bytes = pk.as_bytes();
exports::promise_batch_action_delete_key(
id,
pk_bytes.len() as _,
pk_bytes.as_ptr() as _,
)
});
let pk: RawPublicKey = public_key.into();
let pk_bytes = pk.as_bytes();
exports::promise_batch_action_delete_key(
id,
pk_bytes.len() as _,
pk_bytes.as_ptr() as _,
)
}
PromiseAction::DeleteAccount { beneficiary_id } => {
feature_gated!("all-promise-actions", {
Expand Down
22 changes: 22 additions & 0 deletions engine-tests/src/test_utils/asserts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use near_primitives::transaction::ExecutionStatus;

pub fn assert_execution_status_failure(
execution_status: ExecutionStatus,
err_msg: &str,
panic_msg: &str,
) {
// Usually the converted to string has either of following two messages formats:
// "Action #0: Smart contract panicked: ERR_MSG [src/some_file.rs:LINE_NUMBER:COLUMN_NUMBER]"
// "right: 'MISMATCHED_DATA': ERR_MSG [src/some_file.rs:LINE_NUMBER:COLUMN_NUMBER]"
// So the ": ERR_MSG [" pattern should catch all invariants of error, even if one of the errors
// message is a subset of another one (e.g. `ERR_MSG_FAILED` is a subset of `ERR_MSG_FAILED_FOO`)
let expected_err_msg_pattern = format!(": {}", err_msg);

match execution_status {
ExecutionStatus::Failure(err) => {
println!("Error: {}", err);
assert!(err.to_string().contains(&expected_err_msg_pattern));
}
_ => panic!("{}", panic_msg),
}
}
1 change: 1 addition & 0 deletions engine-tests/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ pub(crate) const PAUSE_PRECOMPILES: &str = "pause_precompiles";
pub(crate) const PAUSED_PRECOMPILES: &str = "paused_precompiles";
pub(crate) const RESUME_PRECOMPILES: &str = "resume_precompiles";

pub(crate) mod asserts;
pub(crate) mod erc20;
pub(crate) mod exit_precompile;
pub(crate) mod mocked_external;
Expand Down
22 changes: 1 addition & 21 deletions engine-tests/src/tests/eth_connector.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::prelude::Address;
use crate::prelude::WithdrawCallArgs;
use crate::test_utils::asserts::assert_execution_status_failure;
use crate::test_utils::str_to_account_id;
use aurora_engine::admin_controlled::{PausedMask, ERR_PAUSED};
use aurora_engine::connector::{
Expand Down Expand Up @@ -1561,27 +1562,6 @@ fn test_deposit_to_aurora_amount_equal_fee_non_zero() {
assert_proof_was_not_used(&contract, CONTRACT_ACC, proof_str);
}

fn assert_execution_status_failure(
execution_status: ExecutionStatus,
err_msg: &str,
panic_msg: &str,
) {
// Usually the converted to string has either of following two messages formats:
// "Action #0: Smart contract panicked: ERR_MSG [src/some_file.rs:LINE_NUMBER:COLUMN_NUMBER]"
// "right: 'MISMATCHED_DATA': ERR_MSG [src/some_file.rs:LINE_NUMBER:COLUMN_NUMBER]"
// So the ": ERR_MSG [" pattern should catch all invariants of error, even if one of the errors
// message is a subset of another one (e.g. `ERR_MSG_FAILED` is a subset of `ERR_MSG_FAILED_FOO`)
let expected_err_msg_pattern = format!(": {}", err_msg);

match execution_status {
ExecutionStatus::Failure(err) => {
println!("Error: {}", err);
assert!(err.to_string().contains(&expected_err_msg_pattern));
}
_ => panic!("{}", panic_msg),
}
}

#[test]
fn test_ft_transfer_max_value() {
let (_, contract) = init(CUSTODIAN_ADDRESS);
Expand Down
1 change: 1 addition & 0 deletions engine-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ mod pausable_precompiles;
mod prepaid_gas_precompile;
mod promise_results_precompile;
mod random;
mod relayer_keys;
mod repro;
pub(crate) mod sanity;
mod self_destruct_state;
Expand Down
122 changes: 122 additions & 0 deletions engine-tests/src/tests/relayer_keys.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::prelude::U256;
use crate::test_utils::asserts::assert_execution_status_failure;
use crate::test_utils::{str_to_account_id, AuroraRunner};
use aurora_engine::parameters::NewCallArgs;
use aurora_engine_types::types::ZERO_YOCTO;
use borsh::BorshSerialize;
use near_crypto::PublicKey;
use near_primitives::account::AccessKeyPermission;
use near_sdk_sim::{ExecutionResult, UserAccount};
use std::str::FromStr;

const PUBLIC_KEY: &str = "ed25519:3gyjNWQWMZNrzqWLhwxzQqfeDFyd3KhXjzmwCqzVCRuF";
const PUBLIC_KEY_BUDGET: u128 = 1_000_000;

// there are multiple deploy_evm implementations but their API is not good enough
// TODO replace with near-workspaces
fn deploy_evm_with_relayer() -> AuroraAccount {
let aurora_runner = AuroraRunner::default();
let main_account = near_sdk_sim::init_simulator(None);

let sim_aurora_account = format!(
"{}.{}",
aurora_runner.aurora_account_id,
main_account.account_id()
);
let contract_account = main_account.deploy(
aurora_runner.code.code(),
sim_aurora_account.parse().unwrap(),
5 * near_sdk_sim::STORAGE_AMOUNT,
);
let prover_account = str_to_account_id("prover.near");
let relayer_account =
main_account.create_user("relay.root".parse().unwrap(), near_sdk_sim::STORAGE_AMOUNT);

let new_args = NewCallArgs {
chain_id: crate::prelude::u256_to_arr(&U256::from(aurora_runner.chain_id)),
owner_id: str_to_account_id(main_account.account_id.as_str()),
bridge_prover_id: prover_account,
upgrade_delay_blocks: 1,
};
main_account
.call(
contract_account.account_id.clone(),
"new",
&new_args.try_to_vec().unwrap(),
near_sdk_sim::DEFAULT_GAS,
0,
)
.assert_success();

AuroraAccount {
user: main_account,
contract: contract_account,
relayer: relayer_account,
}
}

pub struct AuroraAccount {
pub user: UserAccount,
pub contract: UserAccount,
pub relayer: UserAccount,
}

fn add_relayer_key_call(user: &UserAccount, runner: &AuroraAccount) -> ExecutionResult {
user.call(
runner.contract.account_id.clone(),
"add_relayer_key",
format!("{{\"public_key\": \"{PUBLIC_KEY}\"}}").as_bytes(),
near_sdk_sim::DEFAULT_GAS,
PUBLIC_KEY_BUDGET,
)
}

fn remove_relayer_key_call(user: &UserAccount, runner: &AuroraAccount) -> ExecutionResult {
user.call(
runner.contract.account_id.clone(),
"remove_relayer_key",
format!("{{\"public_key\": \"{PUBLIC_KEY}\"}}").as_bytes(),
near_sdk_sim::DEFAULT_GAS,
ZERO_YOCTO.as_u128(),
)
}

#[test]
fn test_relayer_keys_mgmt_access() {
let runner = deploy_evm_with_relayer();

let result = add_relayer_key_call(&runner.contract, &runner);
assert_execution_status_failure(
result.outcome().clone().status,
"ERR_NOT_ALLOWED",
"Expected failure as public key does not exist",
);
}

#[test]
fn test_relayer_keys_mgmt() {
let runner = deploy_evm_with_relayer();

add_relayer_key_call(&runner.relayer, &runner).assert_success();

let pk = PublicKey::from_str(PUBLIC_KEY).unwrap();
let ak = runner
.contract
.borrow_runtime()
.view_access_key(runner.contract.account_id.clone().as_str(), &pk)
.unwrap();
let fk = match ak.permission {
AccessKeyPermission::FullAccess => panic!("Expected function access key"),
AccessKeyPermission::FunctionCall(fk) => fk,
};
assert_eq!(fk.allowance.unwrap(), PUBLIC_KEY_BUDGET);
assert_eq!(fk.method_names.join(","), "submit");

remove_relayer_key_call(&runner.relayer, &runner).assert_success();
let ak = runner
.contract
.borrow_runtime()
.view_access_key(runner.contract.account_id.clone().as_str(), &pk);

assert_eq!(ak, None);
}
9 changes: 8 additions & 1 deletion engine-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,15 @@ autobenches = false
[dependencies]
borsh = { version = "0.9.3", default-features = false }
hex = { version = "0.4", default-features = false, features = ["alloc"] }
primitive-types = { version = "0.12", default-features = false, features = ["rlp"] }
primitive-types = { version = "0.12", default-features = false, features = [
"rlp",
] }
serde = { version = "1", features = ["derive"], optional = true }
bs58 = { version = "0.4.0", default-features = false, features = [
"alloc",
"sha2",
] }


[dev-dependencies]
rand = "0.8.5"
Expand Down
1 change: 1 addition & 0 deletions engine-types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

pub mod account_id;
pub mod parameters;
pub mod public_key;
pub mod storage;
pub mod types;

Expand Down
Loading

0 comments on commit 2fe577d

Please sign in to comment.