From 3073ac1ddd624820e2c2618a4efe666724ab6844 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 4 Aug 2021 15:57:49 -0400 Subject: [PATCH 1/9] Test showing state changes to do stick when transaction execution causes an error --- src/lib.rs | 15 ++++++++++++ src/tests/state_migration.rs | 44 +++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 3f2843730..896e5b619 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -607,6 +607,21 @@ mod contract { sdk::return_output(&data[..]); } + #[cfg(feature = "integration-test")] + #[no_mangle] + pub extern "C" fn mint_account() { + use crate::parameters::WithdrawCallArgs; + // This function has nothing to do with withdraw, it just so happens that + // `WithdrawCallArgs` contains all the information I need, and I am being lazy since + // this is meant to be a minimal reproduction of a bug. + let args: WithdrawCallArgs = sdk::read_input_borsh().sdk_expect("yo"); + let amount = crate::types::Wei::new(args.amount.into()); + let address = Address(args.recipient_address); + Engine::set_balance(&address, &amount); + Engine::set_nonce(&address, &U256::zero()); + Engine::set_code(&address, &[]); + } + /// /// Utility methods. /// diff --git a/src/tests/state_migration.rs b/src/tests/state_migration.rs index 297501024..de0874a51 100644 --- a/src/tests/state_migration.rs +++ b/src/tests/state_migration.rs @@ -1,12 +1,13 @@ use crate::parameters::NewCallArgs; use crate::prelude::U256; -use crate::test_utils::AuroraRunner; +use crate::test_utils::{self, AuroraRunner}; use crate::types; use borsh::BorshSerialize; use near_sdk_sim::{ExecutionResult, UserAccount}; use std::fs; use std::path::Path; use std::process::Command; +use crate::types::Wei; #[test] fn test_state_migration() { @@ -26,6 +27,47 @@ fn test_state_migration() { assert_eq!(some_numbers, [3, 1, 4, 1, 5, 9, 2]); } +// This test has nothing to do with migration. I'm just putting it here for convenience +// because it does require near-sdk-sim and the state migration test already had the +// `deploy_evm()` function to set everything up. +#[test] +fn test_state_revert() { + let aurora = deploy_evm(); + let mut signer = test_utils::Signer::random(); + let address = test_utils::address_from_secret_key(&signer.secret_key); + + // create account + let args = crate::parameters::WithdrawCallArgs { + recipient_address: address.0, + amount: 1_000_000 + }; + aurora.call("mint_account", &args.try_to_vec().unwrap()).assert_success(); + + // confirm nonce is zero + let x = aurora.call("get_nonce", &address.0); + let observed_nonce = match &x.outcome().status { + near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), + _ => panic!("?"), + }; + assert_eq!(observed_nonce, U256::zero()); + + // try operation that fails (transfer more eth than we have) + let nonce = signer.use_nonce(); + let tx = test_utils::transfer(crate::prelude::Address([0; 20]), Wei::new_u64(2_000_000), nonce.into()); + let signed_tx = test_utils::sign_transaction(tx, Some(AuroraRunner::default().chain_id), &signer.secret_key); + let x = aurora.call("submit", rlp::encode(&signed_tx).as_ref()); + println!("{:?}", x); + + // check nonce again; it should have incremented because the transaction was valid + // (even though its execution failed) + let x = aurora.call("get_nonce", &address.0); + let observed_nonce = match &x.outcome().status { + near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), + _ => panic!("?"), + }; + assert_eq!(observed_nonce, U256::one()); +} + fn deploy_evm() -> AuroraAccount { let aurora_runner = AuroraRunner::default(); let main_account = near_sdk_sim::init_simulator(None); From 276f7653d2cf3bd17ad552c7a41ce62a0e4a65a7 Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Thu, 5 Aug 2021 17:21:23 +0700 Subject: [PATCH 2/9] `OutOfOffset`, `OutOfFund`, `OutOfGas` are all ok and valid --- src/engine.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/engine.rs b/src/engine.rs index 6ac4471bf..90dc0a140 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -130,6 +130,9 @@ impl ExitIntoResult for ExitReason { use ExitReason::*; match self { Succeed(_) | Revert(_) => Ok(()), + Error(ExitError::OutOfOffset) + | Error(ExitError::OutOfFund) + | Error(ExitError::OutOfGas) => Ok(()), Error(e) => Err(e.into()), Fatal(e) => Err(e.into()), } From bf69932ff12378ee768bb95b377f9a0abe400c44 Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Thu, 5 Aug 2021 18:50:57 +0700 Subject: [PATCH 3/9] Fix tests --- src/engine.rs | 52 ++++++++++++++++++------------- src/parameters.rs | 27 +++++++++++++++- src/test_utils/exit_precompile.rs | 2 +- src/tests/erc20.rs | 15 +++++---- src/tests/sanity.rs | 10 +++--- src/tests/standard_precompiles.rs | 2 +- src/tests/state_migration.rs | 20 +++++++++--- 7 files changed, 85 insertions(+), 43 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 90dc0a140..2df451668 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -10,8 +10,8 @@ use crate::connector::EthConnectorContract; use crate::contract::current_address; use crate::map::{BijectionMap, LookupMap}; use crate::parameters::{ - FunctionCallArgs, NEP141FtOnTransferArgs, NewCallArgs, PromiseCreateArgs, SubmitResult, - ViewCallArgs, + EvmStatus, FunctionCallArgs, NEP141FtOnTransferArgs, NewCallArgs, PromiseCreateArgs, + SubmitResult, ViewCallArgs, }; use crate::precompiles::Precompiles; @@ -122,17 +122,18 @@ pub type EngineResult = Result; trait ExitIntoResult { /// Checks if the EVM exit is ok or an error. - fn into_result(self) -> EngineResult<()>; + fn into_result(self) -> EngineResult; } impl ExitIntoResult for ExitReason { - fn into_result(self) -> EngineResult<()> { + fn into_result(self) -> EngineResult { use ExitReason::*; match self { - Succeed(_) | Revert(_) => Ok(()), - Error(ExitError::OutOfOffset) - | Error(ExitError::OutOfFund) - | Error(ExitError::OutOfGas) => Ok(()), + Succeed(_) => Ok(EvmStatus::Succeed), + Revert(_) => Ok(EvmStatus::Revert), + Error(ExitError::OutOfOffset) => Ok(EvmStatus::OutOfOffset), + Error(ExitError::OutOfFund) => Ok(EvmStatus::OutOfFund), + Error(ExitError::OutOfGas) => Ok(EvmStatus::OutOfGas), Error(e) => Err(e.into()), Fatal(e) => Err(e.into()), } @@ -443,22 +444,26 @@ impl Engine { ) -> EngineResult { let mut executor = self.make_executor(gas_limit); let address = executor.create_address(CreateScheme::Legacy { caller: origin }); - let (status, result) = ( + let (exit_reason, result) = ( executor.transact_create(origin, value.raw(), input, gas_limit, access_list), address, ); - let is_succeed = status.is_succeed(); - if let Err(e) = status.into_result() { - Engine::increment_nonce(&origin); - return Err(e); - } + + let status = match exit_reason.into_result() { + Ok(status) => status, + Err(e) => { + Engine::increment_nonce(&origin); + return Err(e); + } + }; + let used_gas = executor.used_gas(); let (values, logs, promises) = executor.into_state().deconstruct(); self.apply(values, Vec::::new(), true); Self::schedule_promises(promises); Ok(SubmitResult { - status: is_succeed, + status, gas_used: used_gas, result: result.0.to_vec(), logs: logs.into_iter().map(Into::into).collect(), @@ -482,14 +487,17 @@ impl Engine { access_list: Vec<(Address, Vec)>, // See EIP-2930 ) -> EngineResult { let mut executor = self.make_executor(gas_limit); - let (status, result) = + let (exit_reason, result) = executor.transact_call(origin, contract, value.raw(), input, gas_limit, access_list); - let is_succeed = status.is_succeed(); - if let Err(e) = status.into_result() { - Engine::increment_nonce(&origin); - return Err(e); - } + let status = match exit_reason.into_result() { + Ok(status) => status, + Err(e) => { + Engine::increment_nonce(&origin); + return Err(e); + } + }; + let used_gas = executor.used_gas(); let (values, logs, promises) = executor.into_state().deconstruct(); @@ -500,7 +508,7 @@ impl Engine { Self::schedule_promises(promises); Ok(SubmitResult { - status: is_succeed, + status, gas_used: used_gas, result, logs: logs.into_iter().map(Into::into).collect(), diff --git a/src/parameters.rs b/src/parameters.rs index 58cd1c730..2810c7243 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -61,11 +61,36 @@ impl From for ResultLog { } } +#[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq)] +pub enum EvmStatus { + Succeed, + Revert, + OutOfGas, + OutOfFund, + OutOfOffset, +} + +impl EvmStatus { + pub fn is_ok(&self) -> bool { + *self == EvmStatus::Succeed + } + + pub fn is_revert(&self) -> bool { + *self == EvmStatus::Revert + } + + pub fn is_fail(&self) -> bool { + *self == EvmStatus::OutOfGas + || *self == EvmStatus::OutOfFund + || *self == EvmStatus::OutOfOffset + } +} + /// Borsh-encoded parameters for the `call`, `call_with_args`, `deploy_code`, /// and `deploy_with_input` methods. #[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct SubmitResult { - pub status: bool, + pub status: EvmStatus, pub gas_used: u64, pub result: Vec, pub logs: Vec, diff --git a/src/test_utils/exit_precompile.rs b/src/test_utils/exit_precompile.rs index 2912fbca4..8ed02e149 100644 --- a/src/test_utils/exit_precompile.rs +++ b/src/test_utils/exit_precompile.rs @@ -78,7 +78,7 @@ impl Tester { let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); - if result.status { + if result.status.is_ok() { Ok(ethabi::decode(output_type, result.result.as_slice()).unwrap()) } else { Err(result) diff --git a/src/tests/erc20.rs b/src/tests/erc20.rs index 95dd88bc2..c4045fad2 100644 --- a/src/tests/erc20.rs +++ b/src/tests/erc20.rs @@ -1,3 +1,4 @@ +use crate::parameters::EvmStatus; use crate::prelude::{Address, U256}; use crate::test_utils::{ self, @@ -61,9 +62,8 @@ fn erc20_mint_out_of_gas() { // not enough gas to complete transaction mint_tx.gas = U256::from(67_000); let outcome = runner.submit_transaction(&source_account.secret_key, mint_tx); - let error = outcome.unwrap_err(); - let error_message = format!("{:?}", error); - assert!(error_message.contains("ERR_OUT_OF_GAS")); + let error = outcome.unwrap(); + assert_eq!(error.status, EvmStatus::OutOfGas); // Validate post-state test_utils::validate_address_balance_and_nonce( @@ -100,7 +100,7 @@ fn erc20_transfer_success() { contract.transfer(dest_address, TRANSFER_AMOUNT.into(), nonce) }) .unwrap(); - assert!(outcome.status); + assert!(outcome.status.is_ok()); // Validate post-state assert_eq!( @@ -139,7 +139,7 @@ fn erc20_transfer_insufficient_balance() { contract.transfer(dest_address, (2 * INITIAL_BALANCE).into(), nonce) }) .unwrap(); - assert!(!outcome.status); // status == false means execution error + assert!(outcome.status.is_revert()); // status == false means execution error let message = parse_erc20_error_message(&outcome.result); assert_eq!(&message, "&ERC20: transfer amount exceeds balance"); @@ -183,9 +183,8 @@ fn deploy_erc_20_out_of_gas() { // not enough gas to complete transaction deploy_transaction.gas = U256::from(3_200_000); let outcome = runner.submit_transaction(&source_account, deploy_transaction); - let error = outcome.unwrap_err(); - let error_message = format!("{:?}", error); - assert!(error_message.contains("ERR_OUT_OF_GAS")); + let error = outcome.unwrap(); + assert_eq!(error.status, EvmStatus::OutOfGas); // Validate post-state test_utils::validate_address_balance_and_nonce( diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index 66ff69ec6..a07a48c62 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -1,3 +1,4 @@ +use crate::parameters::EvmStatus; use crate::prelude::Address; use crate::test_utils; use crate::types::{Wei, ERC20_MINT_SELECTOR}; @@ -63,14 +64,13 @@ fn test_eth_transfer_insufficient_balance() { test_utils::validate_address_balance_and_nonce(&runner, dest_address, Wei::zero(), 0.into()); // attempt transfer - let err = runner + let result = runner .submit_with_signer(&mut source_account, |nonce| { // try to transfer more than we have test_utils::transfer(dest_address, INITIAL_BALANCE + INITIAL_BALANCE, nonce) }) - .unwrap_err(); - let error_message = format!("{:?}", err); - assert!(error_message.contains("ERR_OUT_OF_FUND")); + .unwrap(); + assert_eq!(result.status, EvmStatus::OutOfFund); // validate post-state test_utils::validate_address_balance_and_nonce( @@ -218,7 +218,7 @@ fn test_block_hash_contract() { }) .unwrap(); - if !result.status { + if result.status.is_fail() { panic!("{}", String::from_utf8_lossy(&result.result)); } } diff --git a/src/tests/standard_precompiles.rs b/src/tests/standard_precompiles.rs index bf2ca483a..07496a278 100644 --- a/src/tests/standard_precompiles.rs +++ b/src/tests/standard_precompiles.rs @@ -32,7 +32,7 @@ fn standard_precompiles() { .unwrap(); // status == false indicates failure - if !outcome.status { + if outcome.status.is_fail() { panic!("{}", String::from_utf8_lossy(&outcome.result)) } } diff --git a/src/tests/state_migration.rs b/src/tests/state_migration.rs index de0874a51..3a86a9c5b 100644 --- a/src/tests/state_migration.rs +++ b/src/tests/state_migration.rs @@ -2,12 +2,12 @@ use crate::parameters::NewCallArgs; use crate::prelude::U256; use crate::test_utils::{self, AuroraRunner}; use crate::types; +use crate::types::Wei; use borsh::BorshSerialize; use near_sdk_sim::{ExecutionResult, UserAccount}; use std::fs; use std::path::Path; use std::process::Command; -use crate::types::Wei; #[test] fn test_state_migration() { @@ -39,9 +39,11 @@ fn test_state_revert() { // create account let args = crate::parameters::WithdrawCallArgs { recipient_address: address.0, - amount: 1_000_000 + amount: 1_000_000, }; - aurora.call("mint_account", &args.try_to_vec().unwrap()).assert_success(); + aurora + .call("mint_account", &args.try_to_vec().unwrap()) + .assert_success(); // confirm nonce is zero let x = aurora.call("get_nonce", &address.0); @@ -53,8 +55,16 @@ fn test_state_revert() { // try operation that fails (transfer more eth than we have) let nonce = signer.use_nonce(); - let tx = test_utils::transfer(crate::prelude::Address([0; 20]), Wei::new_u64(2_000_000), nonce.into()); - let signed_tx = test_utils::sign_transaction(tx, Some(AuroraRunner::default().chain_id), &signer.secret_key); + let tx = test_utils::transfer( + crate::prelude::Address([0; 20]), + Wei::new_u64(2_000_000), + nonce.into(), + ); + let signed_tx = test_utils::sign_transaction( + tx, + Some(AuroraRunner::default().chain_id), + &signer.secret_key, + ); let x = aurora.call("submit", rlp::encode(&signed_tx).as_ref()); println!("{:?}", x); From b97f14da33e4ae6f2c4d19ce9f2eb6ad734c82a6 Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Thu, 5 Aug 2021 18:55:42 +0700 Subject: [PATCH 4/9] Revert "Test showing state changes to do stick when transaction execution causes an error" This reverts commit 3073ac1ddd624820e2c2618a4efe666724ab6844. --- src/lib.rs | 15 ---------- src/tests/state_migration.rs | 53 +----------------------------------- 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 896e5b619..3f2843730 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -607,21 +607,6 @@ mod contract { sdk::return_output(&data[..]); } - #[cfg(feature = "integration-test")] - #[no_mangle] - pub extern "C" fn mint_account() { - use crate::parameters::WithdrawCallArgs; - // This function has nothing to do with withdraw, it just so happens that - // `WithdrawCallArgs` contains all the information I need, and I am being lazy since - // this is meant to be a minimal reproduction of a bug. - let args: WithdrawCallArgs = sdk::read_input_borsh().sdk_expect("yo"); - let amount = crate::types::Wei::new(args.amount.into()); - let address = Address(args.recipient_address); - Engine::set_balance(&address, &amount); - Engine::set_nonce(&address, &U256::zero()); - Engine::set_code(&address, &[]); - } - /// /// Utility methods. /// diff --git a/src/tests/state_migration.rs b/src/tests/state_migration.rs index 3a86a9c5b..6138ad524 100644 --- a/src/tests/state_migration.rs +++ b/src/tests/state_migration.rs @@ -1,6 +1,6 @@ use crate::parameters::NewCallArgs; use crate::prelude::U256; -use crate::test_utils::{self, AuroraRunner}; +use crate::test_utils::AuroraRunner; use crate::types; use crate::types::Wei; use borsh::BorshSerialize; @@ -27,57 +27,6 @@ fn test_state_migration() { assert_eq!(some_numbers, [3, 1, 4, 1, 5, 9, 2]); } -// This test has nothing to do with migration. I'm just putting it here for convenience -// because it does require near-sdk-sim and the state migration test already had the -// `deploy_evm()` function to set everything up. -#[test] -fn test_state_revert() { - let aurora = deploy_evm(); - let mut signer = test_utils::Signer::random(); - let address = test_utils::address_from_secret_key(&signer.secret_key); - - // create account - let args = crate::parameters::WithdrawCallArgs { - recipient_address: address.0, - amount: 1_000_000, - }; - aurora - .call("mint_account", &args.try_to_vec().unwrap()) - .assert_success(); - - // confirm nonce is zero - let x = aurora.call("get_nonce", &address.0); - let observed_nonce = match &x.outcome().status { - near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), - _ => panic!("?"), - }; - assert_eq!(observed_nonce, U256::zero()); - - // try operation that fails (transfer more eth than we have) - let nonce = signer.use_nonce(); - let tx = test_utils::transfer( - crate::prelude::Address([0; 20]), - Wei::new_u64(2_000_000), - nonce.into(), - ); - let signed_tx = test_utils::sign_transaction( - tx, - Some(AuroraRunner::default().chain_id), - &signer.secret_key, - ); - let x = aurora.call("submit", rlp::encode(&signed_tx).as_ref()); - println!("{:?}", x); - - // check nonce again; it should have incremented because the transaction was valid - // (even though its execution failed) - let x = aurora.call("get_nonce", &address.0); - let observed_nonce = match &x.outcome().status { - near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => U256::from_big_endian(&b), - _ => panic!("?"), - }; - assert_eq!(observed_nonce, U256::one()); -} - fn deploy_evm() -> AuroraAccount { let aurora_runner = AuroraRunner::default(); let main_account = near_sdk_sim::init_simulator(None); From d03118855ba8f768a16511d2a415912e855835c5 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Thu, 5 Aug 2021 15:40:10 +0000 Subject: [PATCH 5/9] Make near-sdk-sim based AuroraRunner initialize eth-connector, and make it public to be used in other tests --- src/tests/state_migration.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/tests/state_migration.rs b/src/tests/state_migration.rs index 6138ad524..6eb65ae71 100644 --- a/src/tests/state_migration.rs +++ b/src/tests/state_migration.rs @@ -1,8 +1,7 @@ -use crate::parameters::NewCallArgs; +use crate::parameters::{InitCallArgs, NewCallArgs}; use crate::prelude::U256; use crate::test_utils::AuroraRunner; use crate::types; -use crate::types::Wei; use borsh::BorshSerialize; use near_sdk_sim::{ExecutionResult, UserAccount}; use std::fs; @@ -27,7 +26,7 @@ fn test_state_migration() { assert_eq!(some_numbers, [3, 1, 4, 1, 5, 9, 2]); } -fn deploy_evm() -> AuroraAccount { +pub fn deploy_evm() -> AuroraAccount { let aurora_runner = AuroraRunner::default(); let main_account = near_sdk_sim::init_simulator(None); let contract_account = main_account.deploy( @@ -35,10 +34,11 @@ fn deploy_evm() -> AuroraAccount { aurora_runner.aurora_account_id.parse().unwrap(), 5 * near_sdk_sim::STORAGE_AMOUNT, ); + let prover_account = "prover.near".to_string(); let new_args = NewCallArgs { chain_id: types::u256_to_arr(&U256::from(aurora_runner.chain_id)), owner_id: main_account.account_id.clone().into(), - bridge_prover_id: "prover.near".to_string(), + bridge_prover_id: prover_account.clone(), upgrade_delay_blocks: 1, }; main_account @@ -50,19 +50,32 @@ fn deploy_evm() -> AuroraAccount { 0, ) .assert_success(); + let init_args = InitCallArgs { + prover_account, + eth_custodian_address: "d045f7e19B2488924B97F9c145b5E51D0D895A65".to_string(), + }; + contract_account + .call( + contract_account.account_id.clone(), + "new_eth_connector", + &init_args.try_to_vec().unwrap(), + near_sdk_sim::DEFAULT_GAS, + 0, + ) + .assert_success(); AuroraAccount { user: main_account, contract: contract_account, } } -struct AuroraAccount { +pub struct AuroraAccount { user: UserAccount, contract: UserAccount, } impl AuroraAccount { - fn call(&self, method: &str, args: &[u8]) -> ExecutionResult { + pub fn call(&self, method: &str, args: &[u8]) -> ExecutionResult { self.user.call( self.contract.account_id.clone(), method, From 81e580c769e6a8f03c8f6488c25f14faba04cfa8 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Thu, 5 Aug 2021 15:41:25 +0000 Subject: [PATCH 6/9] Add (simulation) test showing nonce is still incremented even with OutOfFund error --- src/lib.rs | 21 +++++++++++++ src/tests/sanity.rs | 76 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 3f2843730..7338a5a52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -607,6 +607,27 @@ mod contract { sdk::return_output(&data[..]); } + /// Function used to create accounts for tests + #[cfg(feature = "integration-test")] + #[no_mangle] + pub extern "C" fn mint_account() { + use evm::backend::ApplyBackend; + + let args: ([u8; 20], u64, u64) = sdk::read_input_borsh().sdk_expect("ERR_ARGS"); + let address = Address(args.0); + let nonce = U256::from(args.1); + let balance = U256::from(args.2); + let mut engine = Engine::new(address).sdk_unwrap(); + let state_change = evm::backend::Apply::Modify { + address, + basic: evm::backend::Basic { balance, nonce }, + code: None, + storage: core::iter::empty(), + reset_storage: false, + }; + engine.apply(core::iter::once(state_change), core::iter::empty(), false); + } + /// /// Utility methods. /// diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index a07a48c62..afef6b7ff 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -1,7 +1,8 @@ -use crate::parameters::EvmStatus; -use crate::prelude::Address; +use crate::parameters::{EvmStatus, SubmitResult}; +use crate::prelude::{Address, U256}; use crate::test_utils; use crate::types::{Wei, ERC20_MINT_SELECTOR}; +use borsh::BorshSerialize; use secp256k1::SecretKey; use std::path::{Path, PathBuf}; @@ -222,3 +223,74 @@ fn test_block_hash_contract() { panic!("{}", String::from_utf8_lossy(&result.result)); } } + +// Same as `test_eth_transfer_insufficient_balance` above, except runs through +// `near-sdk-sim` instead of `near-vm-runner`. This is important because `near-sdk-sim` +// has more production logic, in particular, state revert on contract panic. +// TODO: should be able to generalize the `call` backend of `AuroraRunner` so that this +// test does not need to be written twice. +#[test] +fn test_eth_transfer_insufficient_balance_sim() { + use crate::tests::state_migration; + + // initalize engine contract + let aurora = state_migration::deploy_evm(); + let mut signer = test_utils::Signer::random(); + let address = test_utils::address_from_secret_key(&signer.secret_key); + + let args = (address.0, INITIAL_NONCE, INITIAL_BALANCE.raw().low_u64()); + aurora + .call("mint_account", &args.try_to_vec().unwrap()) + .assert_success(); + + // validate pre-state + assert_eq!( + query_address(&address, "get_nonce", &aurora), + U256::from(INITIAL_NONCE), + ); + assert_eq!( + query_address(&address, "get_balance", &aurora), + INITIAL_BALANCE.raw(), + ); + + // Run transaction which will fail (transfer more than current balance) + let nonce = signer.use_nonce(); + let tx = test_utils::transfer( + Address([1; 20]), + INITIAL_BALANCE + INITIAL_BALANCE, + nonce.into(), + ); + let signed_tx = test_utils::sign_transaction( + tx, + Some(test_utils::AuroraRunner::default().chain_id), + &signer.secret_key, + ); + let call_result = aurora.call("submit", rlp::encode(&signed_tx).as_ref()); + let result: SubmitResult = call_result.unwrap_borsh(); + assert_eq!(result.status, EvmStatus::OutOfFund); + + // validate post-state + assert_eq!( + query_address(&address, "get_nonce", &aurora), + U256::from(INITIAL_NONCE + 1), + ); + assert_eq!( + query_address(&address, "get_balance", &aurora), + INITIAL_BALANCE.raw(), + ); + + // helper function + fn query_address( + address: &Address, + method: &str, + aurora: &state_migration::AuroraAccount, + ) -> U256 { + let x = aurora.call(method, &address.0); + match &x.outcome().status { + near_sdk_sim::transaction::ExecutionStatus::SuccessValue(b) => { + U256::from_big_endian(&b) + } + other => panic!("Unexpected outcome: {:?}", other), + } + } +} From 06872438ce2a5201c0ad63f435f800fadc8d0e03 Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Fri, 6 Aug 2021 00:16:52 +0700 Subject: [PATCH 7/9] Remove result from `SubmitResult` --- src/engine.rs | 31 ++++++++++++++----------------- src/lib.rs | 25 +++++++++++++++---------- src/parameters.rs | 24 +++++++++++++----------- src/test_utils/mod.rs | 2 +- src/tests/erc20.rs | 6 +++--- src/tests/sanity.rs | 6 +++--- src/types.rs | 4 +--- 7 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/engine.rs b/src/engine.rs index 2df451668..91061da4d 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -10,8 +10,8 @@ use crate::connector::EthConnectorContract; use crate::contract::current_address; use crate::map::{BijectionMap, LookupMap}; use crate::parameters::{ - EvmStatus, FunctionCallArgs, NEP141FtOnTransferArgs, NewCallArgs, PromiseCreateArgs, - SubmitResult, ViewCallArgs, + FunctionCallArgs, NEP141FtOnTransferArgs, NewCallArgs, PromiseCreateArgs, SubmitResult, + TransactionStatus, ViewCallArgs, }; use crate::precompiles::Precompiles; @@ -122,18 +122,18 @@ pub type EngineResult = Result; trait ExitIntoResult { /// Checks if the EVM exit is ok or an error. - fn into_result(self) -> EngineResult; + fn into_result(self, data: Vec) -> EngineResult; } impl ExitIntoResult for ExitReason { - fn into_result(self) -> EngineResult { + fn into_result(self, data: Vec) -> EngineResult { use ExitReason::*; match self { - Succeed(_) => Ok(EvmStatus::Succeed), - Revert(_) => Ok(EvmStatus::Revert), - Error(ExitError::OutOfOffset) => Ok(EvmStatus::OutOfOffset), - Error(ExitError::OutOfFund) => Ok(EvmStatus::OutOfFund), - Error(ExitError::OutOfGas) => Ok(EvmStatus::OutOfGas), + Succeed(_) => Ok(TransactionStatus::Succeed(data)), + Revert(_) => Ok(TransactionStatus::Revert(data)), + Error(ExitError::OutOfOffset) => Ok(TransactionStatus::OutOfOffset), + Error(ExitError::OutOfFund) => Ok(TransactionStatus::OutOfFund), + Error(ExitError::OutOfGas) => Ok(TransactionStatus::OutOfGas), Error(e) => Err(e.into()), Fatal(e) => Err(e.into()), } @@ -449,7 +449,7 @@ impl Engine { address, ); - let status = match exit_reason.into_result() { + let status = match exit_reason.into_result(result.0.to_vec()) { Ok(status) => status, Err(e) => { Engine::increment_nonce(&origin); @@ -465,7 +465,6 @@ impl Engine { Ok(SubmitResult { status, gas_used: used_gas, - result: result.0.to_vec(), logs: logs.into_iter().map(Into::into).collect(), }) } @@ -490,7 +489,7 @@ impl Engine { let (exit_reason, result) = executor.transact_call(origin, contract, value.raw(), input, gas_limit, access_list); - let status = match exit_reason.into_result() { + let status = match exit_reason.into_result(result) { Ok(status) => status, Err(e) => { Engine::increment_nonce(&origin); @@ -510,7 +509,6 @@ impl Engine { Ok(SubmitResult { status, gas_used: used_gas, - result, logs: logs.into_iter().map(Into::into).collect(), }) } @@ -521,7 +519,7 @@ impl Engine { Self::set_nonce(address, &new_nonce); } - pub fn view_with_args(&self, args: ViewCallArgs) -> EngineResult> { + pub fn view_with_args(&self, args: ViewCallArgs) -> EngineResult { let origin = Address::from_slice(&args.sender); let contract = Address::from_slice(&args.address); let value = U256::from_big_endian(&args.amount); @@ -535,12 +533,11 @@ impl Engine { value: Wei, input: Vec, gas_limit: u64, - ) -> EngineResult> { + ) -> EngineResult { let mut executor = self.make_executor(gas_limit); let (status, result) = executor.transact_call(origin, contract, value.raw(), input, gas_limit, Vec::new()); - status.into_result()?; - Ok(result) + status.into_result(result) } fn make_executor(&self, gas_limit: u64) -> StackExecutor { diff --git a/src/lib.rs b/src/lib.rs index 7338a5a52..ef954d421 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,13 +77,14 @@ mod contract { use borsh::{BorshDeserialize, BorshSerialize}; use crate::connector::EthConnectorContract; - use crate::engine::{Engine, EngineState}; + use crate::engine::{Engine, EngineError, EngineState}; #[cfg(feature = "evm_bully")] use crate::parameters::{BeginBlockArgs, BeginChainArgs}; use crate::parameters::{ DeployErc20TokenArgs, ExpectUtf8, FunctionCallArgs, GetErc20FromNep141CallArgs, GetStorageAtArgs, InitCallArgs, IsUsedProofCallArgs, NEP141FtOnTransferArgs, NewCallArgs, - PauseEthConnectorCallArgs, SetContractDataCallArgs, TransferCallCallArgs, ViewCallArgs, + PauseEthConnectorCallArgs, SetContractDataCallArgs, TransactionStatus, + TransferCallCallArgs, ViewCallArgs, }; use crate::json::parse_json; @@ -356,21 +357,23 @@ mod contract { ethabi::Token::Address(current_address()), ]); - Engine::deploy_code_with_input( + let result = Engine::deploy_code_with_input( &mut engine, (&[erc20_contract, deploy_args.as_slice()].concat()).to_vec(), ) - .map(|res| { - let address = H160(res.result.as_slice().try_into().unwrap()); + .sdk_unwrap(); + + if let TransactionStatus::Succeed(v) = result.status { + let address = H160(v.as_slice().try_into().unwrap()); crate::log!( crate::prelude::format!("Deployed ERC-20 in Aurora at: {:#?}", address).as_str() ); engine .register_token(address.as_bytes(), &args.nep141.as_bytes()) .sdk_unwrap(); - res.result.try_to_vec().sdk_expect("ERR_SERIALIZE") - }) - .sdk_process(); + } else { + crate::log!("Failed to deploy ERC-20 in Aurora"); + } // TODO: charge for storage } @@ -383,8 +386,10 @@ mod contract { pub extern "C" fn view() { let args: ViewCallArgs = sdk::read_input_borsh().sdk_unwrap(); let engine = Engine::new(Address::from_slice(&args.sender)).sdk_unwrap(); - let result = Engine::view_with_args(&engine, args); - result.sdk_process() + let result = Engine::view_with_args(&engine, args).sdk_unwrap(); + if let TransactionStatus::Succeed(v) = result { + sdk::return_output(v.as_ref()) + } } #[no_mangle] diff --git a/src/parameters.rs b/src/parameters.rs index 2810c7243..4fc4fbf81 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -61,28 +61,31 @@ impl From for ResultLog { } } +/// The status of a transaction. #[derive(Debug, BorshSerialize, BorshDeserialize, PartialEq, Eq)] -pub enum EvmStatus { - Succeed, - Revert, +pub enum TransactionStatus { + Succeed(Vec), + Revert(Vec), OutOfGas, OutOfFund, OutOfOffset, + CallTooDeep, } -impl EvmStatus { +impl TransactionStatus { pub fn is_ok(&self) -> bool { - *self == EvmStatus::Succeed + matches!(*self, TransactionStatus::Succeed(_)) } pub fn is_revert(&self) -> bool { - *self == EvmStatus::Revert + matches!(*self, TransactionStatus::Revert(_)) } pub fn is_fail(&self) -> bool { - *self == EvmStatus::OutOfGas - || *self == EvmStatus::OutOfFund - || *self == EvmStatus::OutOfOffset + *self == TransactionStatus::OutOfGas + || *self == TransactionStatus::OutOfFund + || *self == TransactionStatus::OutOfOffset + || *self == TransactionStatus::CallTooDeep } } @@ -90,9 +93,8 @@ impl EvmStatus { /// and `deploy_with_input` methods. #[derive(Debug, BorshSerialize, BorshDeserialize)] pub struct SubmitResult { - pub status: EvmStatus, + pub status: TransactionStatus, pub gas_used: u64, - pub result: Vec, pub logs: Vec, } diff --git a/src/test_utils/mod.rs b/src/test_utils/mod.rs index 3ab166990..891b3e4bc 100644 --- a/src/test_utils/mod.rs +++ b/src/test_utils/mod.rs @@ -281,7 +281,7 @@ impl AuroraRunner { assert!(maybe_err.is_none()); let submit_result = SubmitResult::try_from_slice(&output.unwrap().return_data.as_value().unwrap()).unwrap(); - let address = Address::from_slice(&submit_result.result); + let address = Address::from_slice(&submit_result); let contract_constructor: ContractConstructor = contract_constructor.into(); DeployedContract { abi: contract_constructor.abi, diff --git a/src/tests/erc20.rs b/src/tests/erc20.rs index c4045fad2..7686d4555 100644 --- a/src/tests/erc20.rs +++ b/src/tests/erc20.rs @@ -1,4 +1,4 @@ -use crate::parameters::EvmStatus; +use crate::parameters::TransactionStatus; use crate::prelude::{Address, U256}; use crate::test_utils::{ self, @@ -63,7 +63,7 @@ fn erc20_mint_out_of_gas() { mint_tx.gas = U256::from(67_000); let outcome = runner.submit_transaction(&source_account.secret_key, mint_tx); let error = outcome.unwrap(); - assert_eq!(error.status, EvmStatus::OutOfGas); + assert_eq!(error.status, TransactionStatus::OutOfGas); // Validate post-state test_utils::validate_address_balance_and_nonce( @@ -184,7 +184,7 @@ fn deploy_erc_20_out_of_gas() { deploy_transaction.gas = U256::from(3_200_000); let outcome = runner.submit_transaction(&source_account, deploy_transaction); let error = outcome.unwrap(); - assert_eq!(error.status, EvmStatus::OutOfGas); + assert_eq!(error.status, TransactionStatus::OutOfGas); // Validate post-state test_utils::validate_address_balance_and_nonce( diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index afef6b7ff..e42a464ac 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -1,5 +1,5 @@ -use crate::parameters::{EvmStatus, SubmitResult}; -use crate::prelude::{Address, U256}; +use crate::parameters::TransactionStatus; +use crate::prelude::Address; use crate::test_utils; use crate::types::{Wei, ERC20_MINT_SELECTOR}; use borsh::BorshSerialize; @@ -71,7 +71,7 @@ fn test_eth_transfer_insufficient_balance() { test_utils::transfer(dest_address, INITIAL_BALANCE + INITIAL_BALANCE, nonce) }) .unwrap(); - assert_eq!(result.status, EvmStatus::OutOfFund); + assert_eq!(result.status, TransactionStatus::OutOfFund); // validate post-state test_utils::validate_address_balance_and_nonce( diff --git a/src/types.rs b/src/types.rs index 03168b82a..2efe8c218 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,8 +1,6 @@ -use crate::prelude::{self, Address, String, ToString, Vec, H256, U256}; +use crate::prelude::{self, str, Address, String, ToString, Vec, H256, U256}; #[cfg(not(feature = "contract"))] use crate::prelude::{format, vec}; - -use crate::prelude::str; use borsh::{BorshDeserialize, BorshSerialize}; use ethabi::{Event, EventParam, Hash, Log, RawLog}; From b7aa7975d8ed4011587131335ad663c706609267 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Thu, 5 Aug 2021 18:27:00 +0000 Subject: [PATCH 8/9] Fix tests --- src/lib.rs | 39 +++++++++++++++---------------- src/parameters.rs | 13 +++++++++++ src/test_utils/exit_precompile.rs | 5 ++-- src/test_utils/mod.rs | 26 +++++++++++++++++++-- src/test_utils/self_destruct.rs | 12 +++++----- src/tests/erc20.rs | 11 +++++---- src/tests/erc20_connector.rs | 3 ++- src/tests/sanity.rs | 10 ++++---- src/tests/standard_precompiles.rs | 5 +--- 9 files changed, 78 insertions(+), 46 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ef954d421..92924c023 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ mod contract { use borsh::{BorshDeserialize, BorshSerialize}; use crate::connector::EthConnectorContract; - use crate::engine::{Engine, EngineError, EngineState}; + use crate::engine::{Engine, EngineState}; #[cfg(feature = "evm_bully")] use crate::parameters::{BeginBlockArgs, BeginChainArgs}; use crate::parameters::{ @@ -357,23 +357,24 @@ mod contract { ethabi::Token::Address(current_address()), ]); - let result = Engine::deploy_code_with_input( + let address = match Engine::deploy_code_with_input( &mut engine, (&[erc20_contract, deploy_args.as_slice()].concat()).to_vec(), - ) - .sdk_unwrap(); - - if let TransactionStatus::Succeed(v) = result.status { - let address = H160(v.as_slice().try_into().unwrap()); - crate::log!( - crate::prelude::format!("Deployed ERC-20 in Aurora at: {:#?}", address).as_str() - ); - engine - .register_token(address.as_bytes(), &args.nep141.as_bytes()) - .sdk_unwrap(); - } else { - crate::log!("Failed to deploy ERC-20 in Aurora"); - } + ) { + Ok(result) => match result.status { + TransactionStatus::Succeed(ret) => H160(ret.as_slice().try_into().unwrap()), + other => sdk::panic_utf8(other.as_ref()), + }, + Err(e) => sdk::panic_utf8(e.as_ref()), + }; + + crate::log!( + crate::prelude::format!("Deployed ERC-20 in Aurora at: {:#?}", address).as_str() + ); + engine + .register_token(address.as_bytes(), &args.nep141.as_bytes()) + .sdk_unwrap(); + sdk::return_output(&address.as_bytes().try_to_vec().sdk_expect("ERR_SERIALIZE")); // TODO: charge for storage } @@ -386,10 +387,8 @@ mod contract { pub extern "C" fn view() { let args: ViewCallArgs = sdk::read_input_borsh().sdk_unwrap(); let engine = Engine::new(Address::from_slice(&args.sender)).sdk_unwrap(); - let result = Engine::view_with_args(&engine, args).sdk_unwrap(); - if let TransactionStatus::Succeed(v) = result { - sdk::return_output(v.as_ref()) - } + let result = Engine::view_with_args(&engine, args); + result.sdk_process() } #[no_mangle] diff --git a/src/parameters.rs b/src/parameters.rs index 4fc4fbf81..fdc3b35c8 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -89,6 +89,19 @@ impl TransactionStatus { } } +impl AsRef<[u8]> for TransactionStatus { + fn as_ref(&self) -> &[u8] { + match self { + Self::Succeed(_) => b"SUCCESS", + Self::Revert(_) => b"ERR_REVERT", + Self::OutOfFund => b"ERR_OUT_OF_FUND", + Self::OutOfGas => b"ERR_OUT_OF_GAS", + Self::OutOfOffset => b"ERR_OUT_OF_OFFSET", + Self::CallTooDeep => b"ERR_CALL_TOO_DEEP", + } + } +} + /// Borsh-encoded parameters for the `call`, `call_with_args`, `deploy_code`, /// and `deploy_with_input` methods. #[derive(Debug, BorshSerialize, BorshDeserialize)] diff --git a/src/test_utils/exit_precompile.rs b/src/test_utils/exit_precompile.rs index 8ed02e149..11ea55bc5 100644 --- a/src/test_utils/exit_precompile.rs +++ b/src/test_utils/exit_precompile.rs @@ -1,6 +1,6 @@ use crate::parameters::SubmitResult; use crate::prelude::{Address, U256}; -use crate::test_utils::{solidity, AuroraRunner, Signer}; +use crate::test_utils::{self, solidity, AuroraRunner, Signer}; use crate::transaction::LegacyEthTransaction; pub(crate) struct TesterConstructor(pub solidity::ContractConstructor); @@ -79,7 +79,8 @@ impl Tester { let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); if result.status.is_ok() { - Ok(ethabi::decode(output_type, result.result.as_slice()).unwrap()) + let result = test_utils::unwrap_success(result); + Ok(ethabi::decode(output_type, result.as_slice()).unwrap()) } else { Err(result) } diff --git a/src/test_utils/mod.rs b/src/test_utils/mod.rs index 891b3e4bc..ea0cf0fce 100644 --- a/src/test_utils/mod.rs +++ b/src/test_utils/mod.rs @@ -13,7 +13,7 @@ use rlp::RlpStream; use secp256k1::{self, Message, PublicKey, SecretKey}; use crate::fungible_token::FungibleToken; -use crate::parameters::{InitCallArgs, NewCallArgs, SubmitResult}; +use crate::parameters::{InitCallArgs, NewCallArgs, SubmitResult, TransactionStatus}; use crate::prelude::Address; use crate::storage; use crate::test_utils::solidity::{ContractConstructor, DeployedContract}; @@ -281,7 +281,7 @@ impl AuroraRunner { assert!(maybe_err.is_none()); let submit_result = SubmitResult::try_from_slice(&output.unwrap().return_data.as_value().unwrap()).unwrap(); - let address = Address::from_slice(&submit_result); + let address = Address::from_slice(&unwrap_success(submit_result)); let contract_constructor: ContractConstructor = contract_constructor.into(); DeployedContract { abi: contract_constructor.abi, @@ -512,3 +512,25 @@ pub(crate) fn address_from_hex(address: &str) -> Address { Address::from_slice(&bytes) } + +pub fn unwrap_success(result: SubmitResult) -> Vec { + match result.status { + TransactionStatus::Succeed(ret) => ret, + other => panic!("Unexpected status: {:?}", other), + } +} + +pub fn unwrap_revert(result: SubmitResult) -> Vec { + match result.status { + TransactionStatus::Revert(ret) => ret, + other => panic!("Unexpected status: {:?}", other), + } +} + +pub fn panic_on_fail(status: TransactionStatus) { + match status { + TransactionStatus::Succeed(_) => (), + TransactionStatus::Revert(message) => panic!("{}", String::from_utf8_lossy(&message)), + other => panic!("{}", String::from_utf8_lossy(other.as_ref())), + } +} diff --git a/src/test_utils/self_destruct.rs b/src/test_utils/self_destruct.rs index d8c268778..0f3745214 100644 --- a/src/test_utils/self_destruct.rs +++ b/src/test_utils/self_destruct.rs @@ -1,6 +1,6 @@ use crate::parameters::FunctionCallArgs; use crate::prelude::Address; -use crate::test_utils::{solidity, AuroraRunner, Signer}; +use crate::test_utils::{self, solidity, AuroraRunner, Signer}; use crate::transaction::LegacyEthTransaction; use borsh::BorshSerialize; use primitive_types::U256; @@ -73,8 +73,9 @@ impl SelfDestructFactory { }; let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); + let result = test_utils::unwrap_success(result); - Address::from_slice(&result.result[12..]) + Address::from_slice(&result[12..]) } } @@ -111,11 +112,10 @@ impl SelfDestruct { }; let result = runner.submit_transaction(&signer.secret_key, tx).unwrap(); + let result = test_utils::unwrap_success(result); - if result.result.len() == 32 { - Some(u128::from_be_bytes( - result.result[16..32].try_into().unwrap(), - )) + if result.len() == 32 { + Some(u128::from_be_bytes(result[16..32].try_into().unwrap())) } else { None } diff --git a/src/tests/erc20.rs b/src/tests/erc20.rs index 7686d4555..45763bbee 100644 --- a/src/tests/erc20.rs +++ b/src/tests/erc20.rs @@ -139,8 +139,7 @@ fn erc20_transfer_insufficient_balance() { contract.transfer(dest_address, (2 * INITIAL_BALANCE).into(), nonce) }) .unwrap(); - assert!(outcome.status.is_revert()); // status == false means execution error - let message = parse_erc20_error_message(&outcome.result); + let message = parse_erc20_error_message(&test_utils::unwrap_revert(outcome)); assert_eq!(&message, "&ERC20: transfer amount exceeds balance"); // Validate post-state @@ -201,9 +200,11 @@ fn get_address_erc20_balance( address: Address, contract: &ERC20, ) -> U256 { - let outcome = runner.submit_with_signer(signer, |nonce| contract.balance_of(address, nonce)); - assert!(outcome.is_ok()); - U256::from_big_endian(&outcome.unwrap().result) + let outcome = runner + .submit_with_signer(signer, |nonce| contract.balance_of(address, nonce)) + .unwrap(); + let output = test_utils::unwrap_success(outcome); + U256::from_big_endian(&output) } fn parse_erc20_error_message(result: &[u8]) -> String { diff --git a/src/tests/erc20_connector.rs b/src/tests/erc20_connector.rs index cc727dd08..79d839388 100644 --- a/src/tests/erc20_connector.rs +++ b/src/tests/erc20_connector.rs @@ -139,7 +139,8 @@ impl test_utils::AuroraRunner { let input = build_input("balanceOf(address)", &[Token::Address(target.into())]); let result = self.evm_call(token, input, origin); result.check_ok(); - U256::from_big_endian(result.submit_result().result.as_slice()) + let output = test_utils::unwrap_success(result.submit_result()); + U256::from_big_endian(output.as_slice()) } pub fn mint( diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index e42a464ac..da39fcfc6 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -1,5 +1,5 @@ -use crate::parameters::TransactionStatus; -use crate::prelude::Address; +use crate::parameters::{SubmitResult, TransactionStatus}; +use crate::prelude::{Address, U256}; use crate::test_utils; use crate::types::{Wei, ERC20_MINT_SELECTOR}; use borsh::BorshSerialize; @@ -219,9 +219,7 @@ fn test_block_hash_contract() { }) .unwrap(); - if result.status.is_fail() { - panic!("{}", String::from_utf8_lossy(&result.result)); - } + test_utils::panic_on_fail(result.status); } // Same as `test_eth_transfer_insufficient_balance` above, except runs through @@ -267,7 +265,7 @@ fn test_eth_transfer_insufficient_balance_sim() { ); let call_result = aurora.call("submit", rlp::encode(&signed_tx).as_ref()); let result: SubmitResult = call_result.unwrap_borsh(); - assert_eq!(result.status, EvmStatus::OutOfFund); + assert_eq!(result.status, TransactionStatus::OutOfFund); // validate post-state assert_eq!( diff --git a/src/tests/standard_precompiles.rs b/src/tests/standard_precompiles.rs index 07496a278..c6dd25f9f 100644 --- a/src/tests/standard_precompiles.rs +++ b/src/tests/standard_precompiles.rs @@ -31,8 +31,5 @@ fn standard_precompiles() { .submit_transaction(&source_account, test_all_tx) .unwrap(); - // status == false indicates failure - if outcome.status.is_fail() { - panic!("{}", String::from_utf8_lossy(&outcome.result)) - } + test_utils::panic_on_fail(outcome.status); } From fc77af87080aebefd709972a0e12e565c8a010be Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Fri, 6 Aug 2021 17:41:44 +0700 Subject: [PATCH 9/9] Change out of funds error string Co-authored-by: Kirill --- src/parameters.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parameters.rs b/src/parameters.rs index fdc3b35c8..b91a8f23b 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -94,7 +94,7 @@ impl AsRef<[u8]> for TransactionStatus { match self { Self::Succeed(_) => b"SUCCESS", Self::Revert(_) => b"ERR_REVERT", - Self::OutOfFund => b"ERR_OUT_OF_FUND", + Self::OutOfFund => b"ERR_OUT_OF_FUNDS", Self::OutOfGas => b"ERR_OUT_OF_GAS", Self::OutOfOffset => b"ERR_OUT_OF_OFFSET", Self::CallTooDeep => b"ERR_CALL_TOO_DEEP",