Skip to content

Commit

Permalink
Add simple test executing an EIP-1559 transaction; take gas price fro…
Browse files Browse the repository at this point in the history
…m tx in engine; use london config
  • Loading branch information
birchmd committed Oct 22, 2021
1 parent 845f42e commit aca38dc
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 37 deletions.
45 changes: 44 additions & 1 deletion engine-tests/src/test_utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::prelude::transaction::{
eip_2930::{self, SignedTransaction2930, Transaction2930},
legacy::{LegacyEthSignedTransaction, TransactionLegacy},
};
use crate::prelude::{sdk, AccountId, Address, Wei, U256};
use crate::prelude::{sdk, AccountId, Address, Wei, H256, U256};
use crate::test_utils::solidity::{ContractConstructor, DeployedContract};

// TODO(Copied from #84): Make sure that there is only one Signer after both PR are merged.
Expand Down Expand Up @@ -196,6 +196,26 @@ impl AuroraRunner {
address: Address,
init_balance: crate::prelude::Wei,
init_nonce: U256,
) {
self.internal_create_address(address, init_balance, init_nonce, None)
}

pub fn create_address_with_code(
&mut self,
address: Address,
init_balance: crate::prelude::Wei,
init_nonce: U256,
code: Vec<u8>,
) {
self.internal_create_address(address, init_balance, init_nonce, Some(code))
}

fn internal_create_address(
&mut self,
address: Address,
init_balance: crate::prelude::Wei,
init_nonce: U256,
code: Option<Vec<u8>>,
) {
let trie = &mut self.ext.fake_trie;

Expand All @@ -211,6 +231,14 @@ impl AuroraRunner {
);
let nonce_value = crate::prelude::u256_to_arr(&init_nonce);

if let Some(code) = code {
let code_key = crate::prelude::storage::address_to_key(
crate::prelude::storage::KeyPrefix::Code,
&address,
);
trie.insert(code_key.to_vec(), code);
}

let ft_key = crate::prelude::storage::bytes_to_key(
crate::prelude::storage::KeyPrefix::EthConnector,
&[crate::prelude::storage::EthConnectorStorageId::FungibleToken as u8],
Expand Down Expand Up @@ -335,6 +363,21 @@ impl AuroraRunner {
self.getter_method_call("get_code", address)
}

pub fn get_storage(&self, address: Address, key: H256) -> H256 {
let input = aurora_engine::parameters::GetStorageAtArgs {
address: address.0,
key: key.0,
};
let (outcome, maybe_error) =
self.one_shot()
.call("get_storage_at", "getter", input.try_to_vec().unwrap());
assert!(maybe_error.is_none());
let output = outcome.unwrap().return_data.as_value().unwrap();
let mut result = [0u8; 32];
result.copy_from_slice(&output);
H256(result)
}

fn u256_getter_method_call(&self, method_name: &str, address: Address) -> U256 {
let bytes = self.getter_method_call(method_name, address);
U256::from_big_endian(&bytes)
Expand Down
141 changes: 116 additions & 25 deletions engine-tests/src/tests/eip1559.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,35 @@
use crate::prelude::Wei;
use crate::prelude::{H256, U256};
use crate::test_utils;
use aurora_engine::transaction::eip_1559::{self, Transaction1559};
use aurora_engine::parameters::SubmitResult;
use aurora_engine::transaction::eip_1559::{self, SignedTransaction1559, Transaction1559};
use aurora_engine::transaction::eip_2930::AccessTuple;
use aurora_engine::transaction::EthTransactionKind;
use borsh::BorshDeserialize;
use std::convert::TryFrom;
use std::iter;

const SECRET_KEY: &str = "45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8";
const INITIAL_NONCE: u64 = 1;
const INITIAL_BALANCE: Wei = Wei::new_u64(0x0de0b6b3a7640000);

const CONTRACT_ADDRESS: &str = "0xcccccccccccccccccccccccccccccccccccccccc";
const CONTRACT_NONCE: u64 = 1;
const CONTRACT_CODE: &str = "3a6000554860015500";
const CONTRACT_BALANCE: Wei = Wei::new_u64(0x0de0b6b3a7640000);

const EXAMPLE_TX_HEX: &str = "02f8c101010a8207d0833d090094cccccccccccccccccccccccccccccccccccccccc8000f85bf85994ccccccccccccccccccccccccccccccccccccccccf842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000180a0d671815898b8dd34321adbba4cb6a57baa7017323c26946f3719b00e70c755c2a03528b9efe3be57ea65a933d1e6bbf3b7d0c78830138883c1201e0c641fee6464";

// Test taken from https://github.com/ethereum/tests/blob/develop/GeneralStateTests/stExample/eip1559.json
// TODO(#170): generally support Ethereum tests
#[test]
fn test_eip_1559_tx_encoding_decoding() {
let secret_key = secp256k1::SecretKey::parse_slice(
&hex::decode("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8").unwrap(),
)
.unwrap();
let transaction = Transaction1559 {
chain_id: 1,
nonce: U256::one(),
gas_limit: U256::from(0x3d0900),
max_fee_per_gas: U256::from(0x07d0),
max_priority_fee_per_gas: U256::from(0x0a),
to: Some(test_utils::address_from_hex(
"0xcccccccccccccccccccccccccccccccccccccccc",
)),
value: Wei::zero(),
data: vec![0],
access_list: vec![AccessTuple {
address: test_utils::address_from_hex("0xcccccccccccccccccccccccccccccccccccccccc"),
storage_keys: vec![H256::zero(), one()],
}],
};
let secret_key = exmaple_signer().secret_key;
let transaction = example_transaction();

let signed_tx = test_utils::sign_eip_1559_transaction(transaction, &secret_key);
let bytes: Vec<u8> = iter::once(eip_1559::TYPE_BYTE)
.chain(rlp::encode(&signed_tx).into_iter())
.collect();
let expected_bytes = hex::decode("02f8c101010a8207d0833d090094cccccccccccccccccccccccccccccccccccccccc8000f85bf85994ccccccccccccccccccccccccccccccccccccccccf842a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000180a0d671815898b8dd34321adbba4cb6a57baa7017323c26946f3719b00e70c755c2a03528b9efe3be57ea65a933d1e6bbf3b7d0c78830138883c1201e0c641fee6464").unwrap();
let bytes = encode_tx(&signed_tx);
let expected_bytes = hex::decode(EXAMPLE_TX_HEX).unwrap();

assert_eq!(bytes, expected_bytes);

Expand All @@ -54,6 +47,104 @@ fn test_eip_1559_tx_encoding_decoding() {
)
}

// Test inspired by https://github.com/ethereum/tests/blob/develop/GeneralStateTests/stExample/eip1559.json
// but modified slightly because out BASEFEE is always 0.
#[test]
fn test_eip_1559_example() {
let mut runner = test_utils::deploy_evm();
let mut signer = exmaple_signer();
let signer_address = test_utils::address_from_secret_key(&signer.secret_key);
let contract_address = test_utils::address_from_hex(CONTRACT_ADDRESS);
let contract_code = hex::decode(CONTRACT_CODE).unwrap();

runner.create_address(signer_address, INITIAL_BALANCE, signer.nonce.into());
runner.create_address_with_code(
contract_address,
CONTRACT_BALANCE,
CONTRACT_NONCE.into(),
contract_code.clone(),
);

// Check initial state
assert_eq!(runner.get_balance(signer_address), INITIAL_BALANCE);
assert_eq!(runner.get_nonce(signer_address), signer.nonce.into());
assert_eq!(runner.get_balance(contract_address), CONTRACT_BALANCE);
assert_eq!(runner.get_nonce(contract_address), CONTRACT_NONCE.into());
assert_eq!(runner.get_code(contract_address), contract_code);

let mut transaction = example_transaction();
transaction.chain_id = runner.chain_id;
signer.use_nonce();
let signed_tx = test_utils::sign_eip_1559_transaction(transaction, &signer.secret_key);

let sender = "relay.aurora";
let (maybe_outcome, maybe_err) = runner.call(test_utils::SUBMIT, sender, encode_tx(&signed_tx));
assert!(maybe_err.is_none());
let result =
SubmitResult::try_from_slice(&maybe_outcome.unwrap().return_data.as_value().unwrap())
.unwrap();
assert_eq!(result.gas_used, 0xb8d2);

// Check post state:
// signer spent some ETH on gas fees and incremented nonce for submitting transaction
assert_eq!(
runner.get_balance(signer_address),
Wei::new_u64(0x0de0b6b3a75cc7cc)
);
assert_eq!(runner.get_nonce(signer_address), signer.nonce.into());
// Contract balance, code, nonce all unchanged, but storage was written
assert_eq!(runner.get_balance(contract_address), CONTRACT_BALANCE);
assert_eq!(runner.get_nonce(contract_address), CONTRACT_NONCE.into());
assert_eq!(runner.get_code(contract_address), contract_code);
assert_eq!(
runner.get_storage(contract_address, H256::zero()),
h256_from_hex("000000000000000000000000000000000000000000000000000000000000000a")
);
assert_eq!(runner.get_storage(contract_address, one()), H256::zero());
// Gas fees were awarded to the address derived from sending account
let coinbase = aurora_engine_sdk::types::near_account_to_evm_address(sender.as_bytes());
assert_eq!(runner.get_balance(coinbase), Wei::new_u64(0x73834));
}

fn encode_tx(signed_tx: &SignedTransaction1559) -> Vec<u8> {
iter::once(eip_1559::TYPE_BYTE)
.chain(rlp::encode(signed_tx).into_iter())
.collect()
}

fn exmaple_signer() -> test_utils::Signer {
let secret_key = secp256k1::SecretKey::parse_slice(&hex::decode(SECRET_KEY).unwrap()).unwrap();

test_utils::Signer {
nonce: INITIAL_NONCE,
secret_key,
}
}

fn example_transaction() -> Transaction1559 {
Transaction1559 {
chain_id: 1,
nonce: U256::from(INITIAL_NONCE),
gas_limit: U256::from(0x3d0900),
max_fee_per_gas: U256::from(0x07d0),
max_priority_fee_per_gas: U256::from(0x0a),
to: Some(test_utils::address_from_hex(CONTRACT_ADDRESS)),
value: Wei::zero(),
data: vec![0],
access_list: vec![AccessTuple {
address: test_utils::address_from_hex(CONTRACT_ADDRESS),
storage_keys: vec![H256::zero(), one()],
}],
}
}

fn h256_from_hex(hex: &str) -> H256 {
let bytes = hex::decode(hex).unwrap();
let mut result = [0u8; 32];
result.copy_from_slice(&bytes);
H256(result)
}

fn one() -> H256 {
let mut x = [0u8; 32];
x[31] = 1;
Expand Down
2 changes: 1 addition & 1 deletion engine-tests/src/tests/uniswap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn test_uniswap_exact_output() {

let (_result, profile) =
context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b);
test_utils::assert_gas_bound(profile.all_gas(), 107);
test_utils::assert_gas_bound(profile.all_gas(), 108);
let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas();
assert!(wasm_fraction >= 70, "{}% not more than 70%", wasm_fraction);

Expand Down
20 changes: 12 additions & 8 deletions engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,11 @@ impl From<NewCallArgs> for EngineState {
pub struct Engine {
state: EngineState,
origin: Address,
gas_price: U256,
}

// TODO: upgrade to Berlin HF
pub(crate) const CONFIG: &Config = &Config::istanbul();
pub(crate) const CONFIG: &Config = &Config::london();

/// Key for storing the state of the engine.
const STATE_KEY: &[u8; 5] = b"STATE";
Expand All @@ -311,7 +312,11 @@ impl Engine {
}

pub fn new_with_state(state: EngineState, origin: Address) -> Self {
Self { state, origin }
Self {
state,
origin,
gas_price: U256::zero(),
}
}

/// Saves state into the storage.
Expand Down Expand Up @@ -358,7 +363,7 @@ impl Engine {
}

pub fn charge_gas(
&self,
&mut self,
sender: &Address,
transaction: &NormalizedEthTransaction,
) -> Result<GasPaymentResult, GasPaymentError> {
Expand All @@ -382,6 +387,8 @@ impl Engine {

Self::set_balance(sender, &new_balance);

self.gas_price = effective_gas_price;

Ok(GasPaymentResult {
prepaid_amount,
effective_gas_price,
Expand Down Expand Up @@ -905,12 +912,9 @@ impl Engine {
}

impl evm::backend::Backend for Engine {
/// Returns the gas price.
///
/// This is currently zero, but may be changed in the future. This is mainly
/// because there already is another cost for transactions.
/// Returns the "effective" gas price (as defined by EIP-1559)
fn gas_price(&self) -> U256 {
U256::zero()
self.gas_price
}

/// Returns the origin address that created the contract.
Expand Down
4 changes: 2 additions & 2 deletions engine/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ mod contract {
}
}

if transaction.max_fee_per_gas > transaction.max_priority_fee_per_gas {
sdk::panic_utf8(b"ERR_MAX_FEE_GREATER")
if transaction.max_priority_fee_per_gas > transaction.max_fee_per_gas {
sdk::panic_utf8(b"ERR_MAX_PRIORITY_FEE_GREATER")
}

// Figure out what kind of a transaction this is, and execute it:
Expand Down

0 comments on commit aca38dc

Please sign in to comment.