Skip to content

Commit

Permalink
Feat(engine): EIP-2930 support (#181)
Browse files Browse the repository at this point in the history
* Start defining AccessList transaction type

* Mostly integrate AccessList transaction into the submit flow. Will not work properly without upstream changes. Also need to add tests

* access list transaction signature includes the type byte

* Use berlin pre-release from our fork

* Migrate all workflows to self-hosted runners

* EIP-2930 refactor and extra changes (#182)

* Add initial work

* Rest of changes

* More verbose

Co-authored-by: Joshua J. Bouw <joshua@aurora.dev>
Co-authored-by: DimasGhost <strokovghost@gmail.com>
Co-authored-by: Joshua J. Bouw <dev@joshuajbouw.com>
  • Loading branch information
4 people authored Jul 20, 2021
1 parent ebf63a3 commit 93898da
Show file tree
Hide file tree
Showing 19 changed files with 701 additions and 669 deletions.
12 changes: 4 additions & 8 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ rpath = false
blake2 = { git = "https://github.com/near/near-blake2.git", version = "0.9.1", default-features = false }
borsh = { version = "0.8.2", default-features = false }
bn = { package = "aurora-bn", git = "https://github.com/aurora-is-near/aurora-bn.git", default-features = false }
evm = { version = "0.28.0", default-features = false }
evm-core = { version = "0.28.0", default-features = false }
evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "09d4fe09dcb5fcabed8c1076699c8a2e70f14c23", default-features = false }
evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "09d4fe09dcb5fcabed8c1076699c8a2e70f14c23", default-features = false }
libsecp256k1 = { version = "0.3.5", default-features = false }
num = { version = "0.4.0", default-features = false, features = ["alloc"] }
primitive-types = { version = "0.9.0", default-features = false, features = ["rlp"] }
Expand Down
12 changes: 4 additions & 8 deletions etc/state-migration-test/Cargo.lock

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

21 changes: 12 additions & 9 deletions src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::parameters::{
ViewCallArgs,
};

use crate::precompiles;
use crate::precompiles::Precompiles;
use crate::prelude::{Address, TryInto, Vec, H256, U256};
use crate::sdk;
use crate::state::AuroraStackState;
Expand Down Expand Up @@ -340,7 +340,7 @@ impl Engine {
pub fn deploy_code_with_input(&mut self, input: Vec<u8>) -> EngineResult<SubmitResult> {
let origin = self.origin();
let value = Wei::zero();
self.deploy_code(origin, value, input, u64::MAX)
self.deploy_code(origin, value, input, u64::MAX, Vec::new())
}

pub fn deploy_code(
Expand All @@ -349,11 +349,12 @@ impl Engine {
value: Wei,
input: Vec<u8>,
gas_limit: u64,
access_list: Vec<(Address, Vec<H256>)>, // See EIP-2930
) -> EngineResult<SubmitResult> {
let mut executor = self.make_executor(gas_limit);
let address = executor.create_address(CreateScheme::Legacy { caller: origin });
let (status, result) = (
executor.transact_create(origin, value.raw(), input, gas_limit),
executor.transact_create(origin, value.raw(), input, gas_limit, access_list),
address,
);
let is_succeed = status.is_succeed();
Expand All @@ -378,7 +379,7 @@ impl Engine {
let origin = self.origin();
let contract = Address(args.contract);
let value = Wei::zero();
self.call(origin, contract, value, args.input, u64::MAX)
self.call(origin, contract, value, args.input, u64::MAX, Vec::new())
}

pub fn call(
Expand All @@ -388,10 +389,11 @@ impl Engine {
value: Wei,
input: Vec<u8>,
gas_limit: u64,
access_list: Vec<(Address, Vec<H256>)>, // See EIP-2930
) -> EngineResult<SubmitResult> {
let mut executor = self.make_executor(gas_limit);
let (status, result) =
executor.transact_call(origin, contract, value.raw(), input, gas_limit);
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() {
Expand Down Expand Up @@ -438,15 +440,15 @@ impl Engine {
) -> EngineResult<Vec<u8>> {
let mut executor = self.make_executor(gas_limit);
let (status, result) =
executor.transact_call(origin, contract, value.raw(), input, gas_limit);
executor.transact_call(origin, contract, value.raw(), input, gas_limit, Vec::new());
status.into_result()?;
Ok(result)
}

fn make_executor(&self, gas_limit: u64) -> StackExecutor<AuroraStackState> {
fn make_executor(&self, gas_limit: u64) -> StackExecutor<AuroraStackState, Precompiles> {
let metadata = StackSubstateMetadata::new(gas_limit, CONFIG);
let state = AuroraStackState::new(metadata, self);
StackExecutor::new_with_precompile(state, CONFIG, precompiles::istanbul_precompiles)
StackExecutor::new_with_precompile(state, CONFIG, Precompiles::new_istanbul())
}

pub fn register_relayer(&mut self, account_id: &[u8], evm_address: Address) {
Expand Down Expand Up @@ -486,7 +488,7 @@ impl Engine {
value: Wei,
gas_limit: u64,
) -> EngineResult<SubmitResult> {
self.call(sender, receiver, value, Vec::new(), gas_limit)
self.call(sender, receiver, value, Vec::new(), gas_limit, Vec::new())
}

/// Mint tokens for recipient on a particular ERC20 token
Expand Down Expand Up @@ -572,6 +574,7 @@ impl Engine {
Wei::zero(),
[selector, tail.as_slice()].concat(),
u64::MAX,
Vec::new(), // TODO: are there values we should put here?
),
output_on_fail
);
Expand Down
40 changes: 23 additions & 17 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,7 @@ mod contract {

let input = sdk::read_input();

let EthTransaction::Legacy(signed_transaction) =
EthTransaction::try_from(input.as_slice()).sdk_unwrap();
let signed_transaction = EthTransaction::try_from(input.as_slice()).sdk_unwrap();

let state = Engine::get_state().sdk_unwrap();

Expand All @@ -236,35 +235,41 @@ mod contract {
.sender()
.sdk_expect("ERR_INVALID_ECDSA_SIGNATURE");

Engine::check_nonce(&sender, &signed_transaction.transaction.nonce).sdk_unwrap();
Engine::check_nonce(&sender, signed_transaction.nonce()).sdk_unwrap();

// Check intrinsic gas is covered by transaction gas limit
match signed_transaction
.transaction
.intrinsic_gas(crate::engine::CONFIG)
{
match signed_transaction.intrinsic_gas(crate::engine::CONFIG) {
None => sdk::panic_utf8(GAS_OVERFLOW.as_bytes()),
Some(intrinsic_gas) => {
if signed_transaction.transaction.gas < intrinsic_gas.into() {
if signed_transaction.gas_limit() < &intrinsic_gas.into() {
sdk::panic_utf8(b"ERR_INTRINSIC_GAS")
}
}
}

// Figure out what kind of a transaction this is, and execute it:
let mut engine = Engine::new_with_state(state, sender);
let value = signed_transaction.transaction.value;
let gas_limit = signed_transaction
.transaction
.get_gas_limit()
.sdk_expect(GAS_OVERFLOW);
let data = signed_transaction.transaction.data;
let result = if let Some(receiver) = signed_transaction.transaction.to {
Engine::call(&mut engine, sender, receiver, value, data, gas_limit)
let (value, gas_limit, data, maybe_receiver, access_list) =
signed_transaction.destructure();
let gas_limit = gas_limit.sdk_expect(GAS_OVERFLOW);
let access_list = access_list
.into_iter()
.map(|a| (a.address, a.storage_keys))
.collect();
let result = if let Some(receiver) = maybe_receiver {
Engine::call(
&mut engine,
sender,
receiver,
value,
data,
gas_limit,
access_list,
)
// TODO: charge for storage
} else {
// Execute a contract deployment:
Engine::deploy_code(&mut engine, sender, value, data, gas_limit)
Engine::deploy_code(&mut engine, sender, value, data, gas_limit, access_list)
// TODO: charge for storage
};
result
Expand Down Expand Up @@ -294,6 +299,7 @@ mod contract {
meta_call_args.value,
meta_call_args.input,
u64::MAX, // TODO: is there a gas limit with meta calls?
crate::prelude::Vec::new(),
);
result
.map(|res| res.try_to_vec().sdk_expect("ERR_SERIALIZE"))
Expand Down
2 changes: 1 addition & 1 deletion src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl TryFrom<NEP141FtOnTransferArgs> for String {
}
}

#[derive(BorshSerialize, BorshDeserialize)]
#[derive(Debug, BorshSerialize, BorshDeserialize)]
pub struct PromiseCreateArgs {
pub target_account_id: AccountId,
pub method: String,
Expand Down
30 changes: 14 additions & 16 deletions src/precompiles/blake2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use evm::{Context, ExitError};

use crate::precompiles::{Precompile, PrecompileOutput, PrecompileResult};
use crate::prelude::{mem, Borrowed, PhantomData, TryInto};
use crate::AuroraState;
use crate::prelude::{mem, Address, Borrowed, TryInto};

/// Blake2 costs.
mod costs {
Expand All @@ -15,13 +14,13 @@ mod consts {
pub(super) const INPUT_LENGTH: usize = 213;
}

pub(super) struct Blake2F<S>(PhantomData<S>);
pub(super) struct Blake2F;

impl<S> Blake2F<S> {
pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 9);
impl Blake2F {
pub(super) const ADDRESS: Address = super::make_address(0, 9);
}

impl<S: AuroraState> Precompile<S> for Blake2F<S> {
impl Precompile for Blake2F {
fn required_gas(input: &[u8]) -> Result<u64, ExitError> {
let (int_bytes, _) = input.split_at(mem::size_of::<u32>());
Ok(u64::from(u32::from_be_bytes(
Expand All @@ -43,7 +42,6 @@ impl<S: AuroraState> Precompile<S> for Blake2F<S> {
input: &[u8],
target_gas: u64,
_context: &Context,
_state: &mut S,
_is_static: bool,
) -> PrecompileResult {
if input.len() != consts::INPUT_LENGTH {
Expand Down Expand Up @@ -96,7 +94,7 @@ impl<S: AuroraState> Precompile<S> for Blake2F<S> {
#[cfg(test)]
mod tests {
use crate::prelude::Vec;
use crate::test_utils::{new_context, new_state};
use crate::test_utils::new_context;

use super::*;

Expand All @@ -120,12 +118,12 @@ mod tests {

fn test_blake2f_out_of_gas() -> PrecompileResult {
let input = hex::decode(INPUT).unwrap();
Blake2F::run(&input, 11, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 11, &new_context(), false)
}

fn test_blake2f_empty() -> PrecompileResult {
let input = [0u8; 0];
Blake2F::run(&input, 0, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 0, &new_context(), false)
}

fn test_blake2f_invalid_len_1() -> PrecompileResult {
Expand All @@ -143,7 +141,7 @@ mod tests {
01",
)
.unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
}

fn test_blake2f_invalid_len_2() -> PrecompileResult {
Expand All @@ -161,7 +159,7 @@ mod tests {
01",
)
.unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
}

fn test_blake2f_invalid_flag() -> PrecompileResult {
Expand All @@ -179,7 +177,7 @@ mod tests {
02",
)
.unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
}

fn test_blake2f_r_0() -> Vec<u8> {
Expand All @@ -197,14 +195,14 @@ mod tests {
01",
)
.unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
.unwrap()
.output
}

fn test_blake2f_r_12() -> Vec<u8> {
let input = hex::decode(INPUT).unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
.unwrap()
.output
}
Expand All @@ -224,7 +222,7 @@ mod tests {
00",
)
.unwrap();
Blake2F::run(&input, 12, &new_context(), &mut new_state(), false)
Blake2F::run(&input, 12, &new_context(), false)
.unwrap()
.output
}
Expand Down
Loading

0 comments on commit 93898da

Please sign in to comment.