From 46cb45fe150b39ad703cd87929a4d078918d9963 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Fri, 10 Nov 2023 10:10:07 +0100 Subject: [PATCH] Implement transact_create and transact_create2 --- interpreter/src/eval/mod.rs | 68 ++++---- interpreter/src/eval/system.rs | 47 +++--- interpreter/src/lib.rs | 2 +- interpreter/src/runtime.rs | 11 +- interpreter/tests/usability.rs | 5 +- src/backend/in_memory.rs | 27 ++- src/standard/invoker.rs | 297 ++++++++++++++++++++++++++++++--- 7 files changed, 354 insertions(+), 103 deletions(-) diff --git a/interpreter/src/eval/mod.rs b/interpreter/src/eval/mod.rs index 7b3651ed5..57ebbcd22 100644 --- a/interpreter/src/eval/mod.rs +++ b/interpreter/src/eval/mod.rs @@ -6,8 +6,8 @@ mod misc; mod system; use crate::{ - CallCreateTrap, ExitException, ExitResult, ExitSucceed, Machine, Opcode, RuntimeHandle, - RuntimeState, + CallCreateTrap, ExitException, ExitResult, ExitSucceed, Machine, Opcode, RuntimeBackend, + RuntimeEnvironment, RuntimeState, }; use core::marker::PhantomData; use core::ops::{BitAnd, BitOr, BitXor, Deref, DerefMut}; @@ -182,7 +182,9 @@ impl Etable { } } -impl, H: RuntimeHandle, Tr: CallCreateTrap> Etable { +impl, H: RuntimeEnvironment + RuntimeBackend, Tr: CallCreateTrap> + Etable +{ /// Runtime Etable. pub const fn runtime() -> Etable { let mut table = Self::core(); @@ -1220,7 +1222,7 @@ fn eval_unknown( Control::Exit(ExitException::InvalidOpcode(opcode).into()) } -fn eval_sha3, H: RuntimeHandle, Tr>( +fn eval_sha3, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1229,7 +1231,7 @@ fn eval_sha3, H: RuntimeHandle, Tr>( self::system::sha3(machine) } -fn eval_address, H: RuntimeHandle, Tr>( +fn eval_address, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1238,7 +1240,7 @@ fn eval_address, H: RuntimeHandle, Tr>( self::system::address(machine) } -fn eval_balance, H: RuntimeHandle, Tr>( +fn eval_balance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1247,7 +1249,7 @@ fn eval_balance, H: RuntimeHandle, Tr>( self::system::balance(machine, handle) } -fn eval_selfbalance, H: RuntimeHandle, Tr>( +fn eval_selfbalance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1256,7 +1258,7 @@ fn eval_selfbalance, H: RuntimeHandle, Tr>( self::system::selfbalance(machine, handle) } -fn eval_origin, H: RuntimeHandle, Tr>( +fn eval_origin, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1265,7 +1267,7 @@ fn eval_origin, H: RuntimeHandle, Tr>( self::system::origin(machine, handle) } -fn eval_caller, H: RuntimeHandle, Tr>( +fn eval_caller, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1274,7 +1276,7 @@ fn eval_caller, H: RuntimeHandle, Tr>( self::system::caller(machine) } -fn eval_callvalue, H: RuntimeHandle, Tr>( +fn eval_callvalue, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1283,7 +1285,7 @@ fn eval_callvalue, H: RuntimeHandle, Tr>( self::system::callvalue(machine) } -fn eval_gasprice, H: RuntimeHandle, Tr>( +fn eval_gasprice, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1292,7 +1294,7 @@ fn eval_gasprice, H: RuntimeHandle, Tr>( self::system::gasprice(machine, handle) } -fn eval_extcodesize, H: RuntimeHandle, Tr>( +fn eval_extcodesize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1301,7 +1303,7 @@ fn eval_extcodesize, H: RuntimeHandle, Tr>( self::system::extcodesize(machine, handle) } -fn eval_extcodehash, H: RuntimeHandle, Tr>( +fn eval_extcodehash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1310,7 +1312,7 @@ fn eval_extcodehash, H: RuntimeHandle, Tr>( self::system::extcodehash(machine, handle) } -fn eval_extcodecopy, H: RuntimeHandle, Tr>( +fn eval_extcodecopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1319,7 +1321,7 @@ fn eval_extcodecopy, H: RuntimeHandle, Tr>( self::system::extcodecopy(machine, handle) } -fn eval_returndatasize, H: RuntimeHandle, Tr>( +fn eval_returndatasize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1328,7 +1330,7 @@ fn eval_returndatasize, H: RuntimeHandle, Tr>( self::system::returndatasize(machine) } -fn eval_returndatacopy, H: RuntimeHandle, Tr>( +fn eval_returndatacopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handle: &mut H, _opcode: Opcode, @@ -1337,7 +1339,7 @@ fn eval_returndatacopy, H: RuntimeHandle, Tr>( self::system::returndatacopy(machine) } -fn eval_blockhash, H: RuntimeHandle, Tr>( +fn eval_blockhash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1346,7 +1348,7 @@ fn eval_blockhash, H: RuntimeHandle, Tr>( self::system::blockhash(machine, handle) } -fn eval_coinbase, H: RuntimeHandle, Tr>( +fn eval_coinbase, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1355,7 +1357,7 @@ fn eval_coinbase, H: RuntimeHandle, Tr>( self::system::coinbase(machine, handle) } -fn eval_timestamp, H: RuntimeHandle, Tr>( +fn eval_timestamp, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1364,7 +1366,7 @@ fn eval_timestamp, H: RuntimeHandle, Tr>( self::system::timestamp(machine, handle) } -fn eval_number, H: RuntimeHandle, Tr>( +fn eval_number, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1373,7 +1375,7 @@ fn eval_number, H: RuntimeHandle, Tr>( self::system::number(machine, handle) } -fn eval_difficulty, H: RuntimeHandle, Tr>( +fn eval_difficulty, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1382,7 +1384,7 @@ fn eval_difficulty, H: RuntimeHandle, Tr>( self::system::prevrandao(machine, handle) } -fn eval_gaslimit, H: RuntimeHandle, Tr>( +fn eval_gaslimit, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1391,7 +1393,7 @@ fn eval_gaslimit, H: RuntimeHandle, Tr>( self::system::gaslimit(machine, handle) } -fn eval_sload, H: RuntimeHandle, Tr>( +fn eval_sload, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1400,7 +1402,7 @@ fn eval_sload, H: RuntimeHandle, Tr>( self::system::sload(machine, handle) } -fn eval_sstore, H: RuntimeHandle, Tr>( +fn eval_sstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1409,7 +1411,7 @@ fn eval_sstore, H: RuntimeHandle, Tr>( self::system::sstore(machine, handle) } -fn eval_gas, H: RuntimeHandle, Tr>( +fn eval_gas, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1418,7 +1420,7 @@ fn eval_gas, H: RuntimeHandle, Tr>( self::system::gas(machine, handle) } -fn eval_log0, H: RuntimeHandle, Tr>( +fn eval_log0, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1427,7 +1429,7 @@ fn eval_log0, H: RuntimeHandle, Tr>( self::system::log(machine, 0, handle) } -fn eval_log1, H: RuntimeHandle, Tr>( +fn eval_log1, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1436,7 +1438,7 @@ fn eval_log1, H: RuntimeHandle, Tr>( self::system::log(machine, 1, handle) } -fn eval_log2, H: RuntimeHandle, Tr>( +fn eval_log2, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1445,7 +1447,7 @@ fn eval_log2, H: RuntimeHandle, Tr>( self::system::log(machine, 2, handle) } -fn eval_log3, H: RuntimeHandle, Tr>( +fn eval_log3, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1454,7 +1456,7 @@ fn eval_log3, H: RuntimeHandle, Tr>( self::system::log(machine, 3, handle) } -fn eval_log4, H: RuntimeHandle, Tr>( +fn eval_log4, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1463,7 +1465,7 @@ fn eval_log4, H: RuntimeHandle, Tr>( self::system::log(machine, 4, handle) } -fn eval_suicide, H: RuntimeHandle, Tr>( +fn eval_suicide, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1472,7 +1474,7 @@ fn eval_suicide, H: RuntimeHandle, Tr>( self::system::suicide(machine, handle) } -fn eval_chainid, H: RuntimeHandle, Tr>( +fn eval_chainid, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, @@ -1481,7 +1483,7 @@ fn eval_chainid, H: RuntimeHandle, Tr>( self::system::chainid(machine, handle) } -fn eval_basefee, H: RuntimeHandle, Tr>( +fn eval_basefee, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handle: &mut H, _opcode: Opcode, diff --git a/interpreter/src/eval/system.rs b/interpreter/src/eval/system.rs index 8bbde22fc..90fad99c7 100644 --- a/interpreter/src/eval/system.rs +++ b/interpreter/src/eval/system.rs @@ -1,5 +1,8 @@ use super::Control; -use crate::{ExitException, ExitFatal, ExitSucceed, Log, Machine, RuntimeHandle, RuntimeState}; +use crate::{ + ExitException, ExitFatal, ExitSucceed, Log, Machine, RuntimeBackend, RuntimeEnvironment, + RuntimeState, +}; use alloc::vec::Vec; use primitive_types::{H256, U256}; use sha3::{Digest, Keccak256}; @@ -23,7 +26,7 @@ pub fn sha3, Tr>(machine: &mut Machine) -> Control Control::Continue } -pub fn chainid, H: RuntimeHandle, Tr>( +pub fn chainid, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -39,7 +42,7 @@ pub fn address, Tr>(machine: &mut Machine) -> Control< Control::Continue } -pub fn balance, H: RuntimeHandle, Tr>( +pub fn balance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -50,7 +53,7 @@ pub fn balance, H: RuntimeHandle, Tr>( Control::Continue } -pub fn selfbalance, H: RuntimeHandle, Tr>( +pub fn selfbalance, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -62,7 +65,7 @@ pub fn selfbalance, H: RuntimeHandle, Tr>( Control::Continue } -pub fn origin, H: RuntimeHandle, Tr>( +pub fn origin, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handler: &H, ) -> Control { @@ -92,7 +95,7 @@ pub fn callvalue, Tr>(machine: &mut Machine) -> Contro Control::Continue } -pub fn gasprice, H: RuntimeHandle, Tr>( +pub fn gasprice, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handler: &H, ) -> Control { @@ -108,7 +111,7 @@ pub fn gasprice, H: RuntimeHandle, Tr>( Control::Continue } -pub fn basefee, H: RuntimeHandle, Tr>( +pub fn basefee, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -119,7 +122,7 @@ pub fn basefee, H: RuntimeHandle, Tr>( Control::Continue } -pub fn extcodesize, H: RuntimeHandle, Tr>( +pub fn extcodesize, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -131,7 +134,7 @@ pub fn extcodesize, H: RuntimeHandle, Tr>( Control::Continue } -pub fn extcodehash, H: RuntimeHandle, Tr>( +pub fn extcodehash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -143,7 +146,7 @@ pub fn extcodehash, H: RuntimeHandle, Tr>( Control::Continue } -pub fn extcodecopy, H: RuntimeHandle, Tr>( +pub fn extcodecopy, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -195,7 +198,7 @@ pub fn returndatacopy, Tr>(machine: &mut Machine) -> C } } -pub fn blockhash, H: RuntimeHandle, Tr>( +pub fn blockhash, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -205,7 +208,7 @@ pub fn blockhash, H: RuntimeHandle, Tr>( Control::Continue } -pub fn coinbase, H: RuntimeHandle, Tr>( +pub fn coinbase, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -213,7 +216,7 @@ pub fn coinbase, H: RuntimeHandle, Tr>( Control::Continue } -pub fn timestamp, H: RuntimeHandle, Tr>( +pub fn timestamp, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -221,7 +224,7 @@ pub fn timestamp, H: RuntimeHandle, Tr>( Control::Continue } -pub fn number, H: RuntimeHandle, Tr>( +pub fn number, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -229,7 +232,7 @@ pub fn number, H: RuntimeHandle, Tr>( Control::Continue } -pub fn difficulty, H: RuntimeHandle, Tr>( +pub fn difficulty, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -237,7 +240,7 @@ pub fn difficulty, H: RuntimeHandle, Tr>( Control::Continue } -pub fn prevrandao, H: RuntimeHandle, Tr>( +pub fn prevrandao, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -249,7 +252,7 @@ pub fn prevrandao, H: RuntimeHandle, Tr>( } } -pub fn gaslimit, H: RuntimeHandle, Tr>( +pub fn gaslimit, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &H, ) -> Control { @@ -257,7 +260,7 @@ pub fn gaslimit, H: RuntimeHandle, Tr>( Control::Continue } -pub fn sload, H: RuntimeHandle, Tr>( +pub fn sload, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -269,7 +272,7 @@ pub fn sload, H: RuntimeHandle, Tr>( Control::Continue } -pub fn sstore, H: RuntimeHandle, Tr>( +pub fn sstore, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { @@ -282,7 +285,7 @@ pub fn sstore, H: RuntimeHandle, Tr>( } } -pub fn gas, H: RuntimeHandle, Tr>( +pub fn gas, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, _handler: &H, ) -> Control { @@ -291,7 +294,7 @@ pub fn gas, H: RuntimeHandle, Tr>( Control::Continue } -pub fn log, H: RuntimeHandle, Tr>( +pub fn log, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, n: u8, handler: &mut H, @@ -328,7 +331,7 @@ pub fn log, H: RuntimeHandle, Tr>( } } -pub fn suicide, H: RuntimeHandle, Tr>( +pub fn suicide, H: RuntimeEnvironment + RuntimeBackend, Tr>( machine: &mut Machine, handler: &mut H, ) -> Control { diff --git a/interpreter/src/lib.rs b/interpreter/src/lib.rs index 16ad618b2..dab5971d1 100644 --- a/interpreter/src/lib.rs +++ b/interpreter/src/lib.rs @@ -22,7 +22,7 @@ pub use crate::memory::Memory; pub use crate::opcode::Opcode; pub use crate::runtime::{ CallCreateTrap, Context, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, - RuntimeHandle, RuntimeState, TransactionContext, Transfer, + RuntimeState, TransactionContext, Transfer, }; pub use crate::stack::Stack; pub use crate::valids::Valids; diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index f45b3e91c..9de2b69ff 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -142,11 +142,14 @@ pub trait RuntimeBackend: RuntimeBaseBackend { fn set_code(&mut self, address: H160, code: Vec); /// Reset balance of an account. fn reset_balance(&mut self, address: H160); + fn deposit(&mut self, target: H160, value: U256); + fn withdrawal(&mut self, source: H160, value: U256) -> Result<(), ExitError>; /// Initiate a transfer. - fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError>; + fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> { + self.withdrawal(transfer.source, transfer.value)?; + self.deposit(transfer.target, transfer.value); + Ok(()) + } /// Increase the nonce value. fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>; } - -pub trait RuntimeHandle: RuntimeBackend + RuntimeEnvironment {} -impl RuntimeHandle for T {} diff --git a/interpreter/tests/usability.rs b/interpreter/tests/usability.rs index e1dfbef67..1494b9dac 100644 --- a/interpreter/tests/usability.rs +++ b/interpreter/tests/usability.rs @@ -152,7 +152,10 @@ impl<'a> RuntimeBackend for UnimplementedHandler { unimplemented!() } - fn transfer(&mut self, _transfer: Transfer) -> Result<(), ExitError> { + fn deposit(&mut self, _address: H160, _value: U256) { + unimplemented!() + } + fn withdrawal(&mut self, _address: H160, _value: U256) -> Result<(), ExitError> { unimplemented!() } diff --git a/src/backend/in_memory.rs b/src/backend/in_memory.rs index c23d4edef..981b6848e 100644 --- a/src/backend/in_memory.rs +++ b/src/backend/in_memory.rs @@ -1,6 +1,6 @@ use crate::{ ExitError, ExitException, Log, RuntimeBackend, RuntimeBaseBackend, RuntimeEnvironment, - TransactionalBackend, TransactionalMergeStrategy, Transfer, + TransactionalBackend, TransactionalMergeStrategy, }; use alloc::collections::{BTreeMap, BTreeSet}; use primitive_types::{H160, H256, U256}; @@ -219,24 +219,21 @@ impl RuntimeBackend for InMemoryBackend { .balance = U256::zero(); } - fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> { - { - let source = self - .current_layer_mut() - .state - .entry(transfer.source) - .or_default(); - if source.balance < transfer.value { - return Err(ExitException::OutOfFund.into()); - } - source.balance -= transfer.value; + fn withdrawal(&mut self, source: H160, value: U256) -> Result<(), ExitError> { + let source = self.current_layer_mut().state.entry(source).or_default(); + if source.balance < value { + return Err(ExitException::OutOfFund.into()); } + source.balance -= value; + Ok(()) + } + + fn deposit(&mut self, target: H160, value: U256) { self.current_layer_mut() .state - .entry(transfer.target) + .entry(target) .or_default() - .balance += transfer.value; - Ok(()) + .balance += value; } fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> { diff --git a/src/standard/invoker.rs b/src/standard/invoker.rs index 1b6998bd1..582011b03 100644 --- a/src/standard/invoker.rs +++ b/src/standard/invoker.rs @@ -1,14 +1,15 @@ use super::{gasometer::TransactionCost, Config, Etable, GasedMachine, Gasometer, Machine}; -use crate::call_create::{CallCreateTrapData, CallTrapData, CreateTrapData}; +use crate::call_create::{CallCreateTrapData, CallTrapData, CreateScheme, CreateTrapData}; use crate::{ Capture, Context, ExitError, ExitException, ExitResult, Gasometer as GasometerT, - GasometerMergeStrategy, Invoker as InvokerT, Opcode, RuntimeHandle, RuntimeState, - TransactionContext, TransactionalBackend, TransactionalMergeStrategy, Transfer, + GasometerMergeStrategy, Invoker as InvokerT, Opcode, RuntimeBackend, RuntimeEnvironment, + RuntimeState, TransactionContext, TransactionalBackend, TransactionalMergeStrategy, Transfer, }; use alloc::rc::Rc; use core::cmp::min; use core::convert::Infallible; use primitive_types::{H160, H256, U256}; +use sha3::{Digest, Keccak256}; pub enum CallCreateTrapPrepareData { Call { @@ -54,18 +55,14 @@ impl<'config> Invoker<'config> { etable: &Etable, ) -> ExitResult where - H: RuntimeHandle + TransactionalBackend, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { + let gas_fee = gas_limit.saturating_mul(gas_price); + handler.withdrawal(caller, gas_fee)?; + handler.push_substate(); let work = || -> ExitResult { - let gas_fee = gas_limit.saturating_mul(gas_price); - handler.transfer(Transfer { - source: caller, - target: handler.block_coinbase(), - value: gas_fee, - })?; - let gas_limit = if gas_limit > U256::from(u64::MAX) { return Err(ExitException::OutOfGas.into()); } else { @@ -130,11 +127,10 @@ impl<'config> Invoker<'config> { let refunded_gas = U256::from(machine.gasometer.gas()); let refunded_fee = refunded_gas * gas_price; - handler.transfer(Transfer { - source: handler.block_coinbase(), - target: caller, - value: refunded_fee, - })?; + let coinbase_reward = gas_fee - refunded_fee; + + handler.deposit(caller, refunded_fee); + handler.deposit(handler.block_coinbase(), coinbase_reward); result }; @@ -150,11 +146,258 @@ impl<'config> Invoker<'config> { } } } + + pub fn transact_create( + &self, + caller: H160, + value: U256, + init_code: Vec, + gas_limit: U256, + gas_price: U256, + access_list: Vec<(H160, Vec)>, + handler: &mut H, + etable: &Etable, + ) -> Result + where + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + { + let gas_fee = gas_limit.saturating_mul(gas_price); + handler.withdrawal(caller, gas_fee)?; + + handler.push_substate(); + + let work = || -> Result { + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + return Err(ExitException::CreateContractLimit.into()); + } + } + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + return Err(ExitException::OutOfGas.into()); + } else { + gas_limit.as_u64() + }; + + let scheme = CreateScheme::Legacy { caller }; + let address = scheme.address(handler); + + if self.config.create_increase_nonce { + handler.inc_nonce(address)?; + } + + let context = Context { + caller, + address, + apparent_value: value, + }; + + let transaction_cost = + TransactionCost::create(&init_code, &access_list).cost(self.config); + + let machine = Machine::new( + Rc::new(init_code), + Rc::new(Vec::new()), + self.config.stack_limit, + self.config.memory_limit, + RuntimeState { + context, + transaction_context: TransactionContext { + origin: caller, + gas_price, + } + .into(), + retbuf: Vec::new(), + gas: U256::zero(), + }, + ); + let mut gasometer = Gasometer::new(gas_limit, &machine, self.config); + + gasometer.record_cost(transaction_cost)?; + + let transfer = Transfer { + source: caller, + target: address, + value, + }; + handler.transfer(transfer)?; + + let machine = GasedMachine { + machine, + gasometer, + is_static: false, + }; + + let (mut machine, result) = + crate::execute(machine, handler, 0, DEFAULT_HEAP_DEPTH, self, etable); + result?; + + let retbuf = machine.machine.into_retbuf(); + check_first_byte(self.config, &retbuf[..])?; + + if let Some(limit) = self.config.create_contract_limit { + if retbuf.len() > limit { + return Err(ExitException::CreateContractLimit.into()); + } + } + + GasometerT::::record_codedeposit( + &mut machine.gasometer, + retbuf.len(), + )?; + + let refunded_gas = U256::from(machine.gasometer.gas()); + let refunded_fee = refunded_gas * gas_price; + let coinbase_reward = gas_fee - refunded_fee; + + handler.deposit(caller, refunded_fee); + handler.deposit(handler.block_coinbase(), coinbase_reward); + + Ok(address) + }; + + match work() { + Ok(exit) => { + handler.pop_substate(TransactionalMergeStrategy::Commit); + Ok(exit) + } + Err(err) => { + handler.pop_substate(TransactionalMergeStrategy::Discard); + Err(err) + } + } + } + + pub fn transact_create2( + &self, + caller: H160, + value: U256, + init_code: Vec, + salt: H256, + gas_limit: U256, + gas_price: U256, + access_list: Vec<(H160, Vec)>, + handler: &mut H, + etable: &Etable, + ) -> Result + where + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, + { + let gas_fee = gas_limit.saturating_mul(gas_price); + handler.withdrawal(caller, gas_fee)?; + + handler.push_substate(); + + let work = || -> Result { + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + return Err(ExitException::CreateContractLimit.into()); + } + } + + let gas_limit = if gas_limit > U256::from(u64::MAX) { + return Err(ExitException::OutOfGas.into()); + } else { + gas_limit.as_u64() + }; + + let scheme = CreateScheme::Create2 { + caller, + code_hash: H256::from_slice(Keccak256::digest(&init_code).as_slice()), + salt, + }; + let address = scheme.address(handler); + + if self.config.create_increase_nonce { + handler.inc_nonce(address)?; + } + + let context = Context { + caller, + address, + apparent_value: value, + }; + + let transaction_cost = + TransactionCost::create(&init_code, &access_list).cost(self.config); + + let machine = Machine::new( + Rc::new(init_code), + Rc::new(Vec::new()), + self.config.stack_limit, + self.config.memory_limit, + RuntimeState { + context, + transaction_context: TransactionContext { + origin: caller, + gas_price, + } + .into(), + retbuf: Vec::new(), + gas: U256::zero(), + }, + ); + let mut gasometer = Gasometer::new(gas_limit, &machine, self.config); + + gasometer.record_cost(transaction_cost)?; + + let transfer = Transfer { + source: caller, + target: address, + value, + }; + handler.transfer(transfer)?; + + let machine = GasedMachine { + machine, + gasometer, + is_static: false, + }; + + let (mut machine, result) = + crate::execute(machine, handler, 0, DEFAULT_HEAP_DEPTH, self, etable); + result?; + + let retbuf = machine.machine.into_retbuf(); + check_first_byte(self.config, &retbuf[..])?; + + if let Some(limit) = self.config.create_contract_limit { + if retbuf.len() > limit { + return Err(ExitException::CreateContractLimit.into()); + } + } + + GasometerT::::record_codedeposit( + &mut machine.gasometer, + retbuf.len(), + )?; + + let refunded_gas = U256::from(machine.gasometer.gas()); + let refunded_fee = refunded_gas * gas_price; + let coinbase_reward = gas_fee - refunded_fee; + + handler.deposit(caller, refunded_fee); + handler.deposit(handler.block_coinbase(), coinbase_reward); + + Ok(address) + }; + + match work() { + Ok(exit) => { + handler.pop_substate(TransactionalMergeStrategy::Commit); + Ok(exit) + } + Err(err) => { + handler.pop_substate(TransactionalMergeStrategy::Discard); + Err(err) + } + } + } } impl<'config, H> InvokerT, H, Opcode> for Invoker<'config> where - H: RuntimeHandle + TransactionalBackend, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { type Interrupt = Infallible; type CallCreateTrapPrepareData = CallCreateTrapPrepareData; @@ -348,7 +591,7 @@ fn enter_create_trap_stack<'config, H>( config: &'config Config, ) -> Result<(CallCreateTrapEnterData, GasedMachine<'config>), ExitError> where - H: RuntimeHandle + TransactionalBackend, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { handler.push_substate(); @@ -432,6 +675,13 @@ where } } +fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { + if config.disallow_executable_format && Some(&Opcode::EOFMAGIC.as_u8()) == code.first() { + return Err(ExitException::InvalidOpcode(Opcode::EOFMAGIC).into()); + } + Ok(()) +} + fn exit_create_trap_stack_no_exit_substate<'config, H>( result: Result, retbuf: &Vec, @@ -440,15 +690,8 @@ fn exit_create_trap_stack_no_exit_substate<'config, H>( config: &'config Config, ) -> Result where - H: RuntimeHandle + TransactionalBackend, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { - fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { - if config.disallow_executable_format && Some(&Opcode::EOFMAGIC.as_u8()) == code.first() { - return Err(ExitException::InvalidOpcode(Opcode::EOFMAGIC).into()); - } - Ok(()) - } - let address = result?; check_first_byte(config, &retbuf[..])?; @@ -474,7 +717,7 @@ fn enter_call_trap_stack<'config, H>( config: &'config Config, ) -> Result<(CallCreateTrapEnterData, GasedMachine<'config>), ExitError> where - H: RuntimeHandle + TransactionalBackend, + H: RuntimeEnvironment + RuntimeBackend + TransactionalBackend, { handler.push_substate();