2018-06-04 10:19:50 +02:00
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
2016-02-05 13:40:41 +01:00
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
2016-01-11 02:42:02 +01:00
//! Transaction Execution environment.
2017-07-29 17:12:07 +02:00
use std ::cmp ;
2017-07-29 21:56:42 +02:00
use std ::sync ::Arc ;
2017-08-30 19:18:28 +02:00
use hash ::keccak ;
2018-01-10 13:35:18 +01:00
use ethereum_types ::{ H256 , U256 , U512 , Address } ;
2017-09-06 20:47:45 +02:00
use bytes ::{ Bytes , BytesRef } ;
2017-02-21 12:35:21 +01:00
use state ::{ Backend as StateBackend , State , Substate , CleanupMode } ;
2016-10-24 18:35:25 +02:00
use error ::ExecutionError ;
2018-07-23 15:48:01 +02:00
use machine ::EthereumMachine as Machine ;
2018-02-19 12:27:42 +01:00
use evm ::{ CallType , Finalize , FinalizationResult } ;
use vm ::{
2018-07-23 15:48:01 +02:00
self , EnvInfo , CreateContractAddress , ReturnData , CleanDustMode , ActionParams ,
2018-10-02 16:33:19 +02:00
ActionValue , Schedule , TrapError , ResumeCall , ResumeCreate
2018-02-19 12:27:42 +01:00
} ;
2018-10-02 16:33:19 +02:00
use factory ::VmFactory ;
2016-01-15 14:22:46 +01:00
use externalities ::* ;
2017-10-20 15:40:25 +02:00
use trace ::{ self , Tracer , VMTracer } ;
2016-10-24 18:35:25 +02:00
use transaction ::{ Action , SignedTransaction } ;
2016-01-26 10:15:55 +01:00
use crossbeam ;
2017-07-12 13:09:17 +02:00
pub use executed ::{ Executed , ExecutionResult } ;
2016-05-16 18:33:32 +02:00
2018-04-20 12:32:25 +02:00
#[ cfg(debug_assertions) ]
/// Roughly estimate what stack size each level of evm depth will use. (Debug build)
const STACK_SIZE_PER_DEPTH : usize = 128 * 1024 ;
#[ cfg(not(debug_assertions)) ]
/// Roughly estimate what stack size each level of evm depth will use.
const STACK_SIZE_PER_DEPTH : usize = 24 * 1024 ;
#[ cfg(debug_assertions) ]
/// Entry stack overhead prior to execution. (Debug build)
const STACK_SIZE_ENTRY_OVERHEAD : usize = 100 * 1024 ;
#[ cfg(not(debug_assertions)) ]
/// Entry stack overhead prior to execution.
const STACK_SIZE_ENTRY_OVERHEAD : usize = 20 * 1024 ;
2016-01-07 23:33:54 +01:00
2017-04-19 14:30:00 +02:00
/// Returns new address created from address, nonce, and code hash
2017-06-30 11:30:32 +02:00
pub fn contract_address ( address_scheme : CreateContractAddress , sender : & Address , nonce : & U256 , code : & [ u8 ] ) -> ( Address , Option < H256 > ) {
2017-03-20 19:14:29 +01:00
use rlp ::RlpStream ;
2016-09-01 14:29:59 +02:00
2017-04-19 14:30:00 +02:00
match address_scheme {
CreateContractAddress ::FromSenderAndNonce = > {
let mut stream = RlpStream ::new_list ( 2 ) ;
stream . append ( sender ) ;
stream . append ( nonce ) ;
2017-08-30 19:18:28 +02:00
( From ::from ( keccak ( stream . as_raw ( ) ) ) , None )
2017-04-19 14:30:00 +02:00
} ,
2018-08-01 13:17:04 +02:00
CreateContractAddress ::FromSenderSaltAndCodeHash ( salt ) = > {
2017-08-30 19:18:28 +02:00
let code_hash = keccak ( code ) ;
2018-08-31 17:43:51 +02:00
let mut buffer = [ 0 u8 ; 1 + 20 + 32 + 32 ] ;
buffer [ 0 ] = 0xff ;
& mut buffer [ 1 .. ( 1 + 20 ) ] . copy_from_slice ( & sender [ .. ] ) ;
& mut buffer [ ( 1 + 20 ) .. ( 1 + 20 + 32 ) ] . copy_from_slice ( & salt [ .. ] ) ;
& mut buffer [ ( 1 + 20 + 32 ) .. ] . copy_from_slice ( & code_hash [ .. ] ) ;
2017-08-30 19:18:28 +02:00
( From ::from ( keccak ( & buffer [ .. ] ) ) , Some ( code_hash ) )
2017-04-19 14:30:00 +02:00
} ,
CreateContractAddress ::FromSenderAndCodeHash = > {
2017-08-30 19:18:28 +02:00
let code_hash = keccak ( code ) ;
2017-04-19 14:30:00 +02:00
let mut buffer = [ 0 u8 ; 20 + 32 ] ;
& mut buffer [ .. 20 ] . copy_from_slice ( & sender [ .. ] ) ;
& mut buffer [ 20 .. ] . copy_from_slice ( & code_hash [ .. ] ) ;
2017-08-30 19:18:28 +02:00
( From ::from ( keccak ( & buffer [ .. ] ) ) , Some ( code_hash ) )
2017-04-19 14:30:00 +02:00
} ,
}
2016-01-07 23:33:54 +01:00
}
2016-01-07 19:05:44 +01:00
2018-10-02 16:33:19 +02:00
/// Convert a finalization result into a VM message call result.
pub fn into_message_call_result ( result : vm ::Result < FinalizationResult > ) -> vm ::MessageCallResult {
match result {
Ok ( FinalizationResult { gas_left , return_data , apply_state : true } ) = > vm ::MessageCallResult ::Success ( gas_left , return_data ) ,
Ok ( FinalizationResult { gas_left , return_data , apply_state : false } ) = > vm ::MessageCallResult ::Reverted ( gas_left , return_data ) ,
_ = > vm ::MessageCallResult ::Failed
}
}
/// Convert a finalization result into a VM contract create result.
pub fn into_contract_create_result ( result : vm ::Result < FinalizationResult > , address : & Address , substate : & mut Substate ) -> vm ::ContractCreateResult {
match result {
Ok ( FinalizationResult { gas_left , apply_state : true , .. } ) = > {
substate . contracts_created . push ( address . clone ( ) ) ;
vm ::ContractCreateResult ::Created ( address . clone ( ) , gas_left )
} ,
Ok ( FinalizationResult { gas_left , apply_state : false , return_data } ) = > {
vm ::ContractCreateResult ::Reverted ( gas_left , return_data )
} ,
_ = > vm ::ContractCreateResult ::Failed ,
}
}
2016-04-06 13:05:58 +02:00
/// Transaction execution options.
2017-08-28 14:25:16 +02:00
#[ derive(Copy, Clone, PartialEq) ]
pub struct TransactOptions < T , V > {
2016-04-06 13:05:58 +02:00
/// Enable call tracing.
2017-08-28 14:25:16 +02:00
pub tracer : T ,
2016-06-02 12:40:31 +02:00
/// Enable VM tracing.
2017-08-28 14:25:16 +02:00
pub vm_tracer : V ,
2016-04-06 13:05:58 +02:00
/// Check transaction nonce before execution.
pub check_nonce : bool ,
2017-09-05 13:22:19 +02:00
/// Records the output from init contract calls.
pub output_from_init_contract : bool ,
2016-04-06 13:05:58 +02:00
}
2017-08-28 14:25:16 +02:00
impl < T , V > TransactOptions < T , V > {
/// Create new `TransactOptions` with given tracer and VM tracer.
pub fn new ( tracer : T , vm_tracer : V ) -> Self {
TransactOptions {
tracer ,
vm_tracer ,
check_nonce : true ,
2017-09-05 13:22:19 +02:00
output_from_init_contract : false ,
2017-08-28 14:25:16 +02:00
}
}
/// Disables the nonce check
pub fn dont_check_nonce ( mut self ) -> Self {
self . check_nonce = false ;
self
}
2017-09-05 13:22:19 +02:00
/// Saves the output from contract creation.
pub fn save_output_from_contract ( mut self ) -> Self {
self . output_from_init_contract = true ;
self
}
2017-08-28 14:25:16 +02:00
}
impl TransactOptions < trace ::ExecutiveTracer , trace ::ExecutiveVMTracer > {
/// Creates new `TransactOptions` with default tracing and VM tracing.
pub fn with_tracing_and_vm_tracing ( ) -> Self {
TransactOptions {
tracer : trace ::ExecutiveTracer ::default ( ) ,
vm_tracer : trace ::ExecutiveVMTracer ::toplevel ( ) ,
check_nonce : true ,
2017-09-05 13:22:19 +02:00
output_from_init_contract : false ,
2017-08-28 14:25:16 +02:00
}
}
}
impl TransactOptions < trace ::ExecutiveTracer , trace ::NoopVMTracer > {
/// Creates new `TransactOptions` with default tracing and no VM tracing.
pub fn with_tracing ( ) -> Self {
TransactOptions {
tracer : trace ::ExecutiveTracer ::default ( ) ,
vm_tracer : trace ::NoopVMTracer ,
check_nonce : true ,
2017-09-05 13:22:19 +02:00
output_from_init_contract : false ,
2017-08-28 14:25:16 +02:00
}
}
}
impl TransactOptions < trace ::NoopTracer , trace ::ExecutiveVMTracer > {
/// Creates new `TransactOptions` with no tracing and default VM tracing.
pub fn with_vm_tracing ( ) -> Self {
TransactOptions {
tracer : trace ::NoopTracer ,
vm_tracer : trace ::ExecutiveVMTracer ::toplevel ( ) ,
check_nonce : true ,
2017-09-05 13:22:19 +02:00
output_from_init_contract : false ,
2017-08-28 14:25:16 +02:00
}
}
}
impl TransactOptions < trace ::NoopTracer , trace ::NoopVMTracer > {
/// Creates new `TransactOptions` without any tracing.
pub fn with_no_tracing ( ) -> Self {
TransactOptions {
tracer : trace ::NoopTracer ,
vm_tracer : trace ::NoopVMTracer ,
check_nonce : true ,
2017-09-05 13:22:19 +02:00
output_from_init_contract : false ,
2017-08-28 14:25:16 +02:00
}
}
}
2018-10-02 16:33:19 +02:00
/// Trap result returned by executive.
pub type ExecutiveTrapResult < ' a , T > = vm ::TrapResult < T , CallCreateExecutive < ' a > , CallCreateExecutive < ' a > > ;
/// Trap error for executive.
pub type ExecutiveTrapError < ' a > = vm ::TrapError < CallCreateExecutive < ' a > , CallCreateExecutive < ' a > > ;
enum CallCreateExecutiveKind {
Transfer ( ActionParams ) ,
CallBuiltin ( ActionParams ) ,
ExecCall ( ActionParams , Substate ) ,
ExecCreate ( ActionParams , Substate ) ,
ResumeCall ( OriginInfo , Box < ResumeCall > , Substate ) ,
ResumeCreate ( OriginInfo , Box < ResumeCreate > , Substate ) ,
}
/// Executive for a raw call/create action.
pub struct CallCreateExecutive < ' a > {
info : & ' a EnvInfo ,
machine : & ' a Machine ,
schedule : & ' a Schedule ,
factory : & ' a VmFactory ,
depth : usize ,
stack_depth : usize ,
static_flag : bool ,
is_create : bool ,
gas : U256 ,
kind : CallCreateExecutiveKind ,
}
impl < ' a > CallCreateExecutive < ' a > {
/// Create a new call executive using raw data.
pub fn new_call_raw ( params : ActionParams , info : & ' a EnvInfo , machine : & ' a Machine , schedule : & ' a Schedule , factory : & ' a VmFactory , depth : usize , stack_depth : usize , parent_static_flag : bool ) -> Self {
trace! ( " Executive::call(params={:?}) self.env_info={:?}, parent_static={} " , params , info , parent_static_flag ) ;
let gas = params . gas ;
let static_flag = parent_static_flag | | params . call_type = = CallType ::StaticCall ;
// if destination is builtin, try to execute it
let kind = if let Some ( builtin ) = machine . builtin ( & params . code_address , info . number ) {
// Engines aren't supposed to return builtins until activation, but
// prefer to fail rather than silently break consensus.
if ! builtin . is_active ( info . number ) {
panic! ( " Consensus failure: engine implementation prematurely enabled built-in at {} " , params . code_address ) ;
}
CallCreateExecutiveKind ::CallBuiltin ( params )
} else {
if params . code . is_some ( ) {
CallCreateExecutiveKind ::ExecCall ( params , Substate ::new ( ) )
} else {
CallCreateExecutiveKind ::Transfer ( params )
}
} ;
Self {
info , machine , schedule , factory , depth , stack_depth , static_flag , kind , gas ,
is_create : false ,
}
}
/// Create a new create executive using raw data.
pub fn new_create_raw ( params : ActionParams , info : & ' a EnvInfo , machine : & ' a Machine , schedule : & ' a Schedule , factory : & ' a VmFactory , depth : usize , stack_depth : usize , static_flag : bool ) -> Self {
trace! ( " Executive::create(params={:?}) self.env_info={:?}, static={} " , params , info , static_flag ) ;
let gas = params . gas ;
let kind = CallCreateExecutiveKind ::ExecCreate ( params , Substate ::new ( ) ) ;
Self {
info , machine , schedule , factory , depth , stack_depth , static_flag , kind , gas ,
is_create : true ,
}
}
/// If this executive contains an unconfirmed substate, returns a mutable reference to it.
pub fn unconfirmed_substate ( & mut self ) -> Option < & mut Substate > {
match self . kind {
CallCreateExecutiveKind ::ExecCall ( _ , ref mut unsub ) = > Some ( unsub ) ,
CallCreateExecutiveKind ::ExecCreate ( _ , ref mut unsub ) = > Some ( unsub ) ,
CallCreateExecutiveKind ::ResumeCreate ( _ , _ , ref mut unsub ) = > Some ( unsub ) ,
CallCreateExecutiveKind ::ResumeCall ( _ , _ , ref mut unsub ) = > Some ( unsub ) ,
CallCreateExecutiveKind ::Transfer ( .. ) | CallCreateExecutiveKind ::CallBuiltin ( .. ) = > None ,
}
}
fn check_static_flag ( params : & ActionParams , static_flag : bool , is_create : bool ) -> vm ::Result < ( ) > {
if is_create {
if static_flag {
return Err ( vm ::Error ::MutableCallInStaticContext ) ;
}
} else {
if ( static_flag & &
( params . call_type = = CallType ::StaticCall | | params . call_type = = CallType ::Call ) ) & &
params . value . value ( ) > U256 ::zero ( )
{
return Err ( vm ::Error ::MutableCallInStaticContext ) ;
}
}
Ok ( ( ) )
}
fn check_eip684 < B : ' a + StateBackend > ( params : & ActionParams , state : & State < B > ) -> vm ::Result < ( ) > {
if state . exists_and_has_code_or_nonce ( & params . address ) ? {
return Err ( vm ::Error ::OutOfGas ) ;
}
Ok ( ( ) )
}
fn transfer_exec_balance < B : ' a + StateBackend > ( params : & ActionParams , schedule : & Schedule , state : & mut State < B > , substate : & mut Substate ) -> vm ::Result < ( ) > {
if let ActionValue ::Transfer ( val ) = params . value {
state . transfer_balance ( & params . sender , & params . address , & val , substate . to_cleanup_mode ( & schedule ) ) ? ;
}
Ok ( ( ) )
}
fn transfer_exec_balance_and_init_contract < B : ' a + StateBackend > ( params : & ActionParams , schedule : & Schedule , state : & mut State < B > , substate : & mut Substate ) -> vm ::Result < ( ) > {
let nonce_offset = if schedule . no_empty { 1 } else { 0 } . into ( ) ;
let prev_bal = state . balance ( & params . address ) ? ;
if let ActionValue ::Transfer ( val ) = params . value {
state . sub_balance ( & params . sender , & val , & mut substate . to_cleanup_mode ( & schedule ) ) ? ;
state . new_contract ( & params . address , val + prev_bal , nonce_offset ) ? ;
} else {
state . new_contract ( & params . address , prev_bal , nonce_offset ) ? ;
}
Ok ( ( ) )
}
fn enact_result < B : ' a + StateBackend > ( result : & vm ::Result < FinalizationResult > , state : & mut State < B > , substate : & mut Substate , un_substate : Substate ) {
match * result {
Err ( vm ::Error ::OutOfGas )
| Err ( vm ::Error ::BadJumpDestination { .. } )
| Err ( vm ::Error ::BadInstruction { .. } )
| Err ( vm ::Error ::StackUnderflow { .. } )
| Err ( vm ::Error ::BuiltIn { .. } )
| Err ( vm ::Error ::Wasm { .. } )
| Err ( vm ::Error ::OutOfStack { .. } )
| Err ( vm ::Error ::MutableCallInStaticContext )
| Err ( vm ::Error ::OutOfBounds )
| Err ( vm ::Error ::Reverted )
| Ok ( FinalizationResult { apply_state : false , .. } ) = > {
state . revert_to_checkpoint ( ) ;
} ,
Ok ( _ ) | Err ( vm ::Error ::Internal ( _ ) ) = > {
state . discard_checkpoint ( ) ;
substate . accrue ( un_substate ) ;
}
}
}
/// Creates `Externalities` from `Executive`.
fn as_externalities < ' any , B : ' any + StateBackend , T , V > (
state : & ' any mut State < B > ,
info : & ' any EnvInfo ,
machine : & ' any Machine ,
schedule : & ' any Schedule ,
depth : usize ,
stack_depth : usize ,
static_flag : bool ,
origin_info : & ' any OriginInfo ,
substate : & ' any mut Substate ,
output : OutputPolicy ,
tracer : & ' any mut T ,
vm_tracer : & ' any mut V ,
) -> Externalities < ' any , T , V , B > where T : Tracer , V : VMTracer {
Externalities ::new ( state , info , machine , schedule , depth , stack_depth , origin_info , substate , output , tracer , vm_tracer , static_flag )
}
/// Execute the executive. If a sub-call/create action is required, a resume trap error is returned. The caller is
/// then expected to call `resume_call` or `resume_create` to continue the execution.
///
/// Current-level tracing is expected to be handled by caller.
pub fn exec < B : ' a + StateBackend , T : Tracer , V : VMTracer > ( mut self , state : & mut State < B > , substate : & mut Substate , tracer : & mut T , vm_tracer : & mut V ) -> ExecutiveTrapResult < ' a , FinalizationResult > {
match self . kind {
CallCreateExecutiveKind ::Transfer ( ref params ) = > {
assert! ( ! self . is_create ) ;
let mut inner = | | {
Self ::check_static_flag ( params , self . static_flag , self . is_create ) ? ;
Self ::transfer_exec_balance ( params , self . schedule , state , substate ) ? ;
Ok ( FinalizationResult {
gas_left : params . gas ,
return_data : ReturnData ::empty ( ) ,
apply_state : true ,
} )
} ;
Ok ( inner ( ) )
} ,
CallCreateExecutiveKind ::CallBuiltin ( ref params ) = > {
assert! ( ! self . is_create ) ;
let mut inner = | | {
let builtin = self . machine . builtin ( & params . code_address , self . info . number ) . expect ( " Builtin is_some is checked when creating this kind in new_call_raw; qed " ) ;
Self ::check_static_flag ( & params , self . static_flag , self . is_create ) ? ;
state . checkpoint ( ) ;
Self ::transfer_exec_balance ( & params , self . schedule , state , substate ) ? ;
let default = [ ] ;
let data = if let Some ( ref d ) = params . data { d as & [ u8 ] } else { & default as & [ u8 ] } ;
let cost = builtin . cost ( data ) ;
if cost < = params . gas {
let mut builtin_out_buffer = Vec ::new ( ) ;
let result = {
let mut builtin_output = BytesRef ::Flexible ( & mut builtin_out_buffer ) ;
builtin . execute ( data , & mut builtin_output )
} ;
if let Err ( e ) = result {
state . revert_to_checkpoint ( ) ;
Err ( e . into ( ) )
} else {
state . discard_checkpoint ( ) ;
let out_len = builtin_out_buffer . len ( ) ;
Ok ( FinalizationResult {
gas_left : params . gas - cost ,
return_data : ReturnData ::new ( builtin_out_buffer , 0 , out_len ) ,
apply_state : true ,
} )
}
} else {
// just drain the whole gas
state . revert_to_checkpoint ( ) ;
Err ( vm ::Error ::OutOfGas )
}
} ;
Ok ( inner ( ) )
} ,
CallCreateExecutiveKind ::ExecCall ( params , mut unconfirmed_substate ) = > {
assert! ( ! self . is_create ) ;
{
let static_flag = self . static_flag ;
let is_create = self . is_create ;
let schedule = self . schedule ;
let mut pre_inner = | | {
Self ::check_static_flag ( & params , static_flag , is_create ) ? ;
state . checkpoint ( ) ;
Self ::transfer_exec_balance ( & params , schedule , state , substate ) ? ;
Ok ( ( ) )
} ;
match pre_inner ( ) {
Ok ( ( ) ) = > ( ) ,
Err ( err ) = > return Ok ( Err ( err ) ) ,
}
}
let origin_info = OriginInfo ::from ( & params ) ;
let exec = self . factory . create ( params , self . schedule , self . depth ) ;
let out = {
let mut ext = Self ::as_externalities ( state , self . info , self . machine , self . schedule , self . depth , self . stack_depth , self . static_flag , & origin_info , & mut unconfirmed_substate , OutputPolicy ::Return , tracer , vm_tracer ) ;
match exec . exec ( & mut ext ) {
Ok ( val ) = > Ok ( val . finalize ( ext ) ) ,
Err ( err ) = > Err ( err ) ,
}
} ;
let res = match out {
Ok ( val ) = > val ,
Err ( TrapError ::Call ( subparams , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCall ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Call ( subparams , self ) ) ;
} ,
Err ( TrapError ::Create ( subparams , address , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCreate ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Create ( subparams , address , self ) ) ;
} ,
} ;
Self ::enact_result ( & res , state , substate , unconfirmed_substate ) ;
Ok ( res )
} ,
CallCreateExecutiveKind ::ExecCreate ( params , mut unconfirmed_substate ) = > {
assert! ( self . is_create ) ;
{
let static_flag = self . static_flag ;
let is_create = self . is_create ;
let schedule = self . schedule ;
let mut pre_inner = | | {
Self ::check_eip684 ( & params , state ) ? ;
Self ::check_static_flag ( & params , static_flag , is_create ) ? ;
state . checkpoint ( ) ;
Self ::transfer_exec_balance_and_init_contract ( & params , schedule , state , substate ) ? ;
Ok ( ( ) )
} ;
match pre_inner ( ) {
Ok ( ( ) ) = > ( ) ,
Err ( err ) = > return Ok ( Err ( err ) ) ,
}
}
let origin_info = OriginInfo ::from ( & params ) ;
let exec = self . factory . create ( params , self . schedule , self . depth ) ;
let out = {
let mut ext = Self ::as_externalities ( state , self . info , self . machine , self . schedule , self . depth , self . stack_depth , self . static_flag , & origin_info , & mut unconfirmed_substate , OutputPolicy ::InitContract , tracer , vm_tracer ) ;
match exec . exec ( & mut ext ) {
Ok ( val ) = > Ok ( val . finalize ( ext ) ) ,
Err ( err ) = > Err ( err ) ,
}
} ;
let res = match out {
Ok ( val ) = > val ,
Err ( TrapError ::Call ( subparams , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCall ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Call ( subparams , self ) ) ;
} ,
Err ( TrapError ::Create ( subparams , address , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCreate ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Create ( subparams , address , self ) ) ;
} ,
} ;
Self ::enact_result ( & res , state , substate , unconfirmed_substate ) ;
Ok ( res )
} ,
CallCreateExecutiveKind ::ResumeCall ( .. ) | CallCreateExecutiveKind ::ResumeCreate ( .. ) = > panic! ( " This executive has already been executed once. " ) ,
}
}
/// Resume execution from a call trap previsouly trapped by `exec`.
///
/// Current-level tracing is expected to be handled by caller.
pub fn resume_call < B : ' a + StateBackend , T : Tracer , V : VMTracer > ( mut self , result : vm ::MessageCallResult , state : & mut State < B > , substate : & mut Substate , tracer : & mut T , vm_tracer : & mut V ) -> ExecutiveTrapResult < ' a , FinalizationResult > {
match self . kind {
CallCreateExecutiveKind ::ResumeCall ( origin_info , resume , mut unconfirmed_substate ) = > {
let out = {
let exec = resume . resume_call ( result ) ;
let mut ext = Self ::as_externalities ( state , self . info , self . machine , self . schedule , self . depth , self . stack_depth , self . static_flag , & origin_info , & mut unconfirmed_substate , if self . is_create { OutputPolicy ::InitContract } else { OutputPolicy ::Return } , tracer , vm_tracer ) ;
match exec . exec ( & mut ext ) {
Ok ( val ) = > Ok ( val . finalize ( ext ) ) ,
Err ( err ) = > Err ( err ) ,
}
} ;
let res = match out {
Ok ( val ) = > val ,
Err ( TrapError ::Call ( subparams , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCall ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Call ( subparams , self ) ) ;
} ,
Err ( TrapError ::Create ( subparams , address , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCreate ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Create ( subparams , address , self ) ) ;
} ,
} ;
Self ::enact_result ( & res , state , substate , unconfirmed_substate ) ;
Ok ( res )
} ,
CallCreateExecutiveKind ::ResumeCreate ( .. ) = >
panic! ( " Resumable as create, but called resume_call " ) ,
CallCreateExecutiveKind ::Transfer ( .. ) | CallCreateExecutiveKind ::CallBuiltin ( .. ) |
CallCreateExecutiveKind ::ExecCall ( .. ) | CallCreateExecutiveKind ::ExecCreate ( .. ) = >
panic! ( " Not resumable " ) ,
}
}
/// Resume execution from a create trap previsouly trapped by `exec`.
///
/// Current-level tracing is expected to be handled by caller.
pub fn resume_create < B : ' a + StateBackend , T : Tracer , V : VMTracer > ( mut self , result : vm ::ContractCreateResult , state : & mut State < B > , substate : & mut Substate , tracer : & mut T , vm_tracer : & mut V ) -> ExecutiveTrapResult < ' a , FinalizationResult > {
match self . kind {
CallCreateExecutiveKind ::ResumeCreate ( origin_info , resume , mut unconfirmed_substate ) = > {
let out = {
let exec = resume . resume_create ( result ) ;
let mut ext = Self ::as_externalities ( state , self . info , self . machine , self . schedule , self . depth , self . stack_depth , self . static_flag , & origin_info , & mut unconfirmed_substate , if self . is_create { OutputPolicy ::InitContract } else { OutputPolicy ::Return } , tracer , vm_tracer ) ;
match exec . exec ( & mut ext ) {
Ok ( val ) = > Ok ( val . finalize ( ext ) ) ,
Err ( err ) = > Err ( err ) ,
}
} ;
let res = match out {
Ok ( val ) = > val ,
Err ( TrapError ::Call ( subparams , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCall ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Call ( subparams , self ) ) ;
} ,
Err ( TrapError ::Create ( subparams , address , resume ) ) = > {
self . kind = CallCreateExecutiveKind ::ResumeCreate ( origin_info , resume , unconfirmed_substate ) ;
return Err ( TrapError ::Create ( subparams , address , self ) ) ;
} ,
} ;
Self ::enact_result ( & res , state , substate , unconfirmed_substate ) ;
Ok ( res )
} ,
CallCreateExecutiveKind ::ResumeCall ( .. ) = >
panic! ( " Resumable as call, but called resume_create " ) ,
CallCreateExecutiveKind ::Transfer ( .. ) | CallCreateExecutiveKind ::CallBuiltin ( .. ) |
CallCreateExecutiveKind ::ExecCall ( .. ) | CallCreateExecutiveKind ::ExecCreate ( .. ) = >
panic! ( " Not resumable " ) ,
}
}
/// Execute and consume the current executive. This function handles resume traps and sub-level tracing. The caller is expected to handle current-level tracing.
pub fn consume < B : ' a + StateBackend , T : Tracer , V : VMTracer > ( self , state : & mut State < B > , top_substate : & mut Substate , tracer : & mut T , vm_tracer : & mut V ) -> vm ::Result < FinalizationResult > {
let mut last_res = Some ( ( false , self . gas , self . exec ( state , top_substate , tracer , vm_tracer ) ) ) ;
let mut callstack : Vec < ( Option < Address > , CallCreateExecutive < ' a > ) > = Vec ::new ( ) ;
loop {
match last_res {
None = > {
match callstack . pop ( ) {
Some ( ( _ , exec ) ) = > {
let second_last = callstack . last_mut ( ) ;
let parent_substate = match second_last {
Some ( ( _ , ref mut second_last ) ) = > second_last . unconfirmed_substate ( ) . expect ( " Current stack value is created from second last item; second last item must be call or create; qed " ) ,
None = > top_substate ,
} ;
last_res = Some ( ( exec . is_create , exec . gas , exec . exec ( state , parent_substate , tracer , vm_tracer ) ) ) ;
} ,
None = > panic! ( " When callstack only had one item and it was executed, this function would return; callstack never reaches zero item; qed " ) ,
}
} ,
Some ( ( is_create , gas , Ok ( val ) ) ) = > {
let current = callstack . pop ( ) ;
match current {
Some ( ( address , mut exec ) ) = > {
if is_create {
let address = address . expect ( " If the last executed status was from a create executive, then the destination address was pushed to the callstack; address is_some if it is_create; qed " ) ;
match val {
Ok ( ref val ) if val . apply_state = > {
tracer . done_trace_create (
gas - val . gas_left ,
& val . return_data ,
address
) ;
} ,
Ok ( _ ) = > {
tracer . done_trace_failed ( & vm ::Error ::Reverted ) ;
} ,
Err ( ref err ) = > {
tracer . done_trace_failed ( err ) ;
} ,
}
vm_tracer . done_subtrace ( ) ;
let second_last = callstack . last_mut ( ) ;
let parent_substate = match second_last {
Some ( ( _ , ref mut second_last ) ) = > second_last . unconfirmed_substate ( ) . expect ( " Current stack value is created from second last item; second last item must be call or create; qed " ) ,
None = > top_substate ,
} ;
let contract_create_result = into_contract_create_result ( val , & address , exec . unconfirmed_substate ( ) . expect ( " Executive is resumed from a create; it has an unconfirmed substate; qed " ) ) ;
last_res = Some ( ( exec . is_create , exec . gas , exec . resume_create (
contract_create_result ,
state ,
parent_substate ,
tracer ,
vm_tracer
) ) ) ;
} else {
match val {
Ok ( ref val ) if val . apply_state = > {
tracer . done_trace_call (
gas - val . gas_left ,
& val . return_data ,
) ;
} ,
Ok ( _ ) = > {
tracer . done_trace_failed ( & vm ::Error ::Reverted ) ;
} ,
Err ( ref err ) = > {
tracer . done_trace_failed ( err ) ;
} ,
}
vm_tracer . done_subtrace ( ) ;
let second_last = callstack . last_mut ( ) ;
let parent_substate = match second_last {
Some ( ( _ , ref mut second_last ) ) = > second_last . unconfirmed_substate ( ) . expect ( " Current stack value is created from second last item; second last item must be call or create; qed " ) ,
None = > top_substate ,
} ;
last_res = Some ( ( exec . is_create , exec . gas , exec . resume_call (
into_message_call_result ( val ) ,
state ,
parent_substate ,
tracer ,
vm_tracer
) ) ) ;
}
} ,
None = > return val ,
}
} ,
Some ( ( _ , _ , Err ( TrapError ::Call ( subparams , resume ) ) ) ) = > {
tracer . prepare_trace_call ( & subparams , resume . depth + 1 , resume . machine . builtin ( & subparams . address , resume . info . number ) . is_some ( ) ) ;
vm_tracer . prepare_subtrace ( subparams . code . as_ref ( ) . map_or_else ( | | & [ ] as & [ u8 ] , | d | & * d as & [ u8 ] ) ) ;
let sub_exec = CallCreateExecutive ::new_call_raw (
subparams ,
resume . info ,
resume . machine ,
resume . schedule ,
resume . factory ,
resume . depth + 1 ,
resume . stack_depth ,
resume . static_flag ,
) ;
callstack . push ( ( None , resume ) ) ;
callstack . push ( ( None , sub_exec ) ) ;
last_res = None ;
} ,
Some ( ( _ , _ , Err ( TrapError ::Create ( subparams , address , resume ) ) ) ) = > {
tracer . prepare_trace_create ( & subparams ) ;
vm_tracer . prepare_subtrace ( subparams . code . as_ref ( ) . map_or_else ( | | & [ ] as & [ u8 ] , | d | & * d as & [ u8 ] ) ) ;
let sub_exec = CallCreateExecutive ::new_create_raw (
subparams ,
resume . info ,
resume . machine ,
resume . schedule ,
resume . factory ,
resume . depth + 1 ,
resume . stack_depth ,
resume . static_flag
) ;
callstack . push ( ( Some ( address ) , resume ) ) ;
callstack . push ( ( None , sub_exec ) ) ;
last_res = None ;
} ,
}
}
}
}
2016-01-11 19:25:37 +01:00
/// Transaction executor.
2018-07-09 13:55:27 +02:00
pub struct Executive < ' a , B : ' a > {
2017-02-21 12:35:21 +01:00
state : & ' a mut State < B > ,
2016-01-07 19:05:44 +01:00
info : & ' a EnvInfo ,
2017-09-26 14:19:08 +02:00
machine : & ' a Machine ,
2018-07-23 15:48:01 +02:00
schedule : & ' a Schedule ,
2016-03-18 23:49:12 +01:00
depth : usize ,
2017-06-19 11:41:46 +02:00
static_flag : bool ,
2016-01-07 19:05:44 +01:00
}
2017-09-26 14:19:08 +02:00
impl < ' a , B : ' a + StateBackend > Executive < ' a , B > {
2016-01-11 19:25:37 +01:00
/// Basic constructor.
2018-07-23 15:48:01 +02:00
pub fn new ( state : & ' a mut State < B > , info : & ' a EnvInfo , machine : & ' a Machine , schedule : & ' a Schedule ) -> Self {
2016-03-19 12:54:34 +01:00
Executive {
state : state ,
info : info ,
2017-09-26 14:19:08 +02:00
machine : machine ,
2018-07-23 15:48:01 +02:00
schedule : schedule ,
2016-03-19 12:54:34 +01:00
depth : 0 ,
2017-06-19 11:41:46 +02:00
static_flag : false ,
2016-03-19 12:54:34 +01:00
}
2016-01-09 17:55:47 +01:00
}
2016-01-09 00:51:09 +01:00
2016-01-11 14:08:03 +01:00
/// Populates executive from parent properties. Increments executive depth.
2018-07-23 15:48:01 +02:00
pub fn from_parent ( state : & ' a mut State < B > , info : & ' a EnvInfo , machine : & ' a Machine , schedule : & ' a Schedule , parent_depth : usize , static_flag : bool ) -> Self {
2016-01-07 19:05:44 +01:00
Executive {
state : state ,
info : info ,
2017-09-26 14:19:08 +02:00
machine : machine ,
2018-07-23 15:48:01 +02:00
schedule : schedule ,
2016-03-19 12:54:34 +01:00
depth : parent_depth + 1 ,
2017-06-19 11:41:46 +02:00
static_flag : static_flag ,
2016-01-07 19:05:44 +01:00
}
}
2016-04-28 21:47:44 +02:00
/// This function should be used to execute transaction.
2017-08-28 14:25:16 +02:00
pub fn transact < T , V > ( & ' a mut self , t : & SignedTransaction , options : TransactOptions < T , V > )
2017-10-20 15:40:25 +02:00
-> Result < Executed < T ::Output , V ::Output > , ExecutionError > where T : Tracer , V : VMTracer ,
2017-08-28 14:25:16 +02:00
{
2017-09-05 13:22:19 +02:00
self . transact_with_tracer ( t , options . check_nonce , options . output_from_init_contract , options . tracer , options . vm_tracer )
2016-04-08 01:50:55 +02:00
}
2017-05-17 12:41:33 +02:00
/// Execute a transaction in a "virtual" context.
/// This will ensure the caller has enough balance to execute the desired transaction.
/// Used for extra-block executions for things like consensus contracts and RPCs
2017-08-28 14:25:16 +02:00
pub fn transact_virtual < T , V > ( & ' a mut self , t : & SignedTransaction , options : TransactOptions < T , V > )
2017-10-20 15:40:25 +02:00
-> Result < Executed < T ::Output , V ::Output > , ExecutionError > where T : Tracer , V : VMTracer ,
2017-08-28 14:25:16 +02:00
{
2017-05-17 12:41:33 +02:00
let sender = t . sender ( ) ;
let balance = self . state . balance ( & sender ) ? ;
2017-08-15 10:07:00 +02:00
let needed_balance = t . value . saturating_add ( t . gas . saturating_mul ( t . gas_price ) ) ;
2017-05-17 12:41:33 +02:00
if balance < needed_balance {
// give the sender a sufficient balance
self . state . add_balance ( & sender , & ( needed_balance - balance ) , CleanupMode ::NoEmpty ) ? ;
}
self . transact ( t , options )
}
2016-04-28 21:47:44 +02:00
/// Execute transaction/call with tracing enabled
2017-08-28 14:25:16 +02:00
fn transact_with_tracer < T , V > (
2016-06-02 12:40:31 +02:00
& ' a mut self ,
t : & SignedTransaction ,
check_nonce : bool ,
2017-09-05 13:22:19 +02:00
output_from_create : bool ,
2016-06-02 12:40:31 +02:00
mut tracer : T ,
mut vm_tracer : V
2017-10-20 15:40:25 +02:00
) -> Result < Executed < T ::Output , V ::Output > , ExecutionError > where T : Tracer , V : VMTracer {
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2017-02-26 13:10:50 +01:00
let nonce = self . state . nonce ( & sender ) ? ;
2016-01-10 12:29:35 +01:00
2018-07-23 15:48:01 +02:00
let schedule = self . schedule ;
2016-01-15 13:07:44 +01:00
let base_gas_required = U256 ::from ( t . gas_required ( & schedule ) ) ;
if t . gas < base_gas_required {
2018-04-19 13:16:04 +02:00
return Err ( ExecutionError ::NotEnoughBaseGas { required : base_gas_required , got : t . gas } ) ;
2016-01-15 13:07:44 +01:00
}
2017-06-28 09:10:57 +02:00
if ! t . is_unsigned ( ) & & check_nonce & & schedule . kill_dust ! = CleanDustMode ::Off & & ! self . state . exists ( & sender ) ? {
2018-04-19 13:16:04 +02:00
return Err ( ExecutionError ::SenderMustExist ) ;
2017-06-28 09:10:57 +02:00
}
2016-01-15 13:07:44 +01:00
let init_gas = t . gas - base_gas_required ;
2016-01-14 02:20:46 +01:00
2016-01-10 12:29:35 +01:00
// validate transaction nonce
2016-04-12 13:54:34 +02:00
if check_nonce & & t . nonce ! = nonce {
2018-04-19 13:16:04 +02:00
return Err ( ExecutionError ::InvalidNonce { expected : nonce , got : t . nonce } ) ;
2016-01-10 12:29:35 +01:00
}
2016-02-09 16:31:57 +01:00
2016-01-11 02:17:29 +01:00
// validate if transaction fits into given block
2016-01-11 02:42:02 +01:00
if self . info . gas_used + t . gas > self . info . gas_limit {
2018-04-19 13:16:04 +02:00
return Err ( ExecutionError ::BlockGasLimitReached {
2016-02-09 16:31:57 +01:00
gas_limit : self . info . gas_limit ,
gas_used : self . info . gas_used ,
gas : t . gas
2018-04-19 13:16:04 +02:00
} ) ;
2016-01-11 02:17:29 +01:00
}
2016-01-10 12:29:35 +01:00
// TODO: we might need bigints here, or at least check overflows.
2017-02-26 13:10:50 +01:00
let balance = self . state . balance ( & sender ) ? ;
2016-10-06 18:42:54 +02:00
let gas_cost = t . gas . full_mul ( t . gas_price ) ;
2016-01-12 17:40:34 +01:00
let total_cost = U512 ::from ( t . value ) + gas_cost ;
2016-01-10 12:29:35 +01:00
// avoid unaffordable transactions
2016-10-06 18:42:54 +02:00
let balance512 = U512 ::from ( balance ) ;
if balance512 < total_cost {
2018-04-19 13:16:04 +02:00
return Err ( ExecutionError ::NotEnoughCash { required : total_cost , got : balance512 } ) ;
2016-01-10 12:29:35 +01:00
}
2016-01-07 21:29:36 +01:00
2017-06-28 09:10:57 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-11 02:17:29 +01:00
// NOTE: there can be no invalid transactions from this point.
2018-08-31 17:43:51 +02:00
if ! schedule . keep_unsigned_nonce | | ! t . is_unsigned ( ) {
2017-04-19 14:30:00 +02:00
self . state . inc_nonce ( & sender ) ? ;
}
2017-06-28 09:10:57 +02:00
self . state . sub_balance ( & sender , & U256 ::from ( gas_cost ) , & mut substate . to_cleanup_mode ( & schedule ) ) ? ;
2016-01-11 15:55:54 +01:00
2017-06-06 17:47:12 +02:00
let ( result , output ) = match t . action {
2016-01-17 15:56:09 +01:00
Action ::Create = > {
2017-09-26 14:19:08 +02:00
let ( new_address , code_hash ) = contract_address ( self . machine . create_address_scheme ( self . info . number ) , & sender , & nonce , & t . data ) ;
2016-01-11 16:33:08 +01:00
let params = ActionParams {
2016-01-15 15:00:28 +01:00
code_address : new_address . clone ( ) ,
2017-04-19 14:30:00 +02:00
code_hash : code_hash ,
2016-01-15 15:00:28 +01:00
address : new_address ,
2016-01-09 17:55:47 +01:00
sender : sender . clone ( ) ,
origin : sender . clone ( ) ,
2016-01-14 01:18:44 +01:00
gas : init_gas ,
2016-01-09 17:55:47 +01:00
gas_price : t . gas_price ,
2016-01-20 17:27:33 +01:00
value : ActionValue ::Transfer ( t . value ) ,
2016-10-02 18:45:36 +02:00
code : Some ( Arc ::new ( t . data . clone ( ) ) ) ,
2016-01-15 15:00:28 +01:00
data : None ,
2016-07-27 17:41:21 +02:00
call_type : CallType ::None ,
2017-11-02 12:49:57 +01:00
params_type : vm ::ParamsType ::Embedded ,
2016-01-09 17:55:47 +01:00
} ;
2018-08-13 23:27:13 +02:00
let res = self . create ( params , & mut substate , & mut tracer , & mut vm_tracer ) ;
let out = match & res {
Ok ( res ) if output_from_create = > res . return_data . to_vec ( ) ,
_ = > Vec ::new ( ) ,
} ;
( res , out )
2016-01-09 00:51:09 +01:00
} ,
2016-01-17 15:56:09 +01:00
Action ::Call ( ref address ) = > {
2016-01-11 16:33:08 +01:00
let params = ActionParams {
2016-01-15 15:00:28 +01:00
code_address : address . clone ( ) ,
2016-01-11 15:23:27 +01:00
address : address . clone ( ) ,
2016-01-09 17:55:47 +01:00
sender : sender . clone ( ) ,
origin : sender . clone ( ) ,
2016-01-14 01:18:44 +01:00
gas : init_gas ,
2016-01-09 17:55:47 +01:00
gas_price : t . gas_price ,
2016-01-20 17:27:33 +01:00
value : ActionValue ::Transfer ( t . value ) ,
2017-02-26 13:10:50 +01:00
code : self . state . code ( address ) ? ,
2018-07-31 07:27:57 +02:00
code_hash : self . state . code_hash ( address ) ? ,
2016-01-15 15:00:28 +01:00
data : Some ( t . data . clone ( ) ) ,
2016-07-27 17:41:21 +02:00
call_type : CallType ::Call ,
2017-11-02 12:49:57 +01:00
params_type : vm ::ParamsType ::Separate ,
2016-01-09 17:55:47 +01:00
} ;
2018-08-13 23:27:13 +02:00
let res = self . call ( params , & mut substate , & mut tracer , & mut vm_tracer ) ;
let out = match & res {
Ok ( res ) = > res . return_data . to_vec ( ) ,
_ = > Vec ::new ( ) ,
} ;
( res , out )
2016-01-09 17:55:47 +01:00
}
2016-01-09 21:39:38 +01:00
} ;
// finalize here!
2017-08-28 14:25:16 +02:00
Ok ( self . finalize ( t , substate , result , output , tracer . drain ( ) , vm_tracer . drain ( ) ) ? )
2016-01-07 19:05:44 +01:00
}
2018-10-02 16:33:19 +02:00
/// Calls contract function with given contract params and stack depth.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate and the output.
/// Returns either gas_left or `vm::Error`.
pub fn call_with_stack_depth < T , V > (
2016-06-02 12:40:31 +02:00
& mut self ,
params : ActionParams ,
2018-10-02 16:33:19 +02:00
substate : & mut Substate ,
stack_depth : usize ,
2016-06-02 12:40:31 +02:00
tracer : & mut T ,
vm_tracer : & mut V
2017-08-01 12:37:57 +02:00
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
2018-10-02 16:33:19 +02:00
tracer . prepare_trace_call ( & params , self . depth , self . machine . builtin ( & params . address , self . info . number ) . is_some ( ) ) ;
vm_tracer . prepare_subtrace ( params . code . as_ref ( ) . map_or_else ( | | & [ ] as & [ u8 ] , | d | & * d as & [ u8 ] ) ) ;
let gas = params . gas ;
2016-10-06 18:42:54 +02:00
2018-10-02 16:33:19 +02:00
let vm_factory = self . state . vm_factory ( ) ;
let result = CallCreateExecutive ::new_call_raw (
params ,
self . info ,
self . machine ,
self . schedule ,
& vm_factory ,
self . depth ,
stack_depth ,
self . static_flag
) . consume ( self . state , substate , tracer , vm_tracer ) ;
match result {
Ok ( ref val ) if val . apply_state = > {
tracer . done_trace_call (
gas - val . gas_left ,
& val . return_data ,
) ;
} ,
Ok ( _ ) = > {
tracer . done_trace_failed ( & vm ::Error ::Reverted ) ;
} ,
Err ( ref err ) = > {
tracer . done_trace_failed ( err ) ;
} ,
2016-01-26 10:15:55 +01:00
}
2018-10-02 16:33:19 +02:00
vm_tracer . done_subtrace ( ) ;
2016-01-26 10:15:55 +01:00
2018-10-02 16:33:19 +02:00
result
}
2016-01-26 10:15:55 +01:00
2018-10-02 16:33:19 +02:00
/// Calls contract function with given contract params, if the stack depth is above a threshold, create a new thread
/// to execute it.
pub fn call_with_crossbeam < T , V > (
& mut self ,
params : ActionParams ,
substate : & mut Substate ,
stack_depth : usize ,
tracer : & mut T ,
vm_tracer : & mut V
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
let local_stack_size = ::io ::LOCAL_STACK_SIZE . with ( | sz | sz . get ( ) ) ;
let depth_threshold = local_stack_size . saturating_sub ( STACK_SIZE_ENTRY_OVERHEAD ) / STACK_SIZE_PER_DEPTH ;
if stack_depth ! = depth_threshold {
self . call_with_stack_depth ( params , substate , stack_depth , tracer , vm_tracer )
} else {
crossbeam ::scope ( | scope | {
scope . builder ( ) . stack_size ( ::std ::cmp ::max ( self . schedule . max_depth . saturating_sub ( depth_threshold ) * STACK_SIZE_PER_DEPTH , local_stack_size ) ) . spawn ( move | | {
self . call_with_stack_depth ( params , substate , stack_depth , tracer , vm_tracer )
} ) . expect ( " Sub-thread creation cannot fail; the host might run out of resources; qed " )
} ) . join ( )
}
2016-01-26 10:15:55 +01:00
}
2016-01-09 21:39:38 +01:00
/// Calls contract function with given contract params.
2016-06-02 12:40:31 +02:00
pub fn call < T , V > (
& mut self ,
params : ActionParams ,
substate : & mut Substate ,
tracer : & mut T ,
vm_tracer : & mut V
2017-09-15 21:07:54 +02:00
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
2018-10-02 16:33:19 +02:00
self . call_with_stack_depth ( params , substate , 0 , tracer , vm_tracer )
}
2017-06-19 11:41:46 +02:00
2018-10-02 16:33:19 +02:00
/// Creates contract with given contract params and stack depth.
/// NOTE. It does not finalize the transaction (doesn't do refunds, nor suicides).
/// Modifies the substate.
pub fn create_with_stack_depth < T , V > (
& mut self ,
params : ActionParams ,
substate : & mut Substate ,
stack_depth : usize ,
tracer : & mut T ,
vm_tracer : & mut V ,
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
tracer . prepare_trace_create ( & params ) ;
vm_tracer . prepare_subtrace ( params . code . as_ref ( ) . map_or_else ( | | & [ ] as & [ u8 ] , | d | & * d as & [ u8 ] ) ) ;
2017-06-19 11:41:46 +02:00
2018-10-02 16:33:19 +02:00
let address = params . address ;
let gas = params . gas ;
2016-01-14 17:40:38 +01:00
2018-10-02 16:33:19 +02:00
let vm_factory = self . state . vm_factory ( ) ;
let result = CallCreateExecutive ::new_create_raw (
params ,
self . info ,
self . machine ,
self . schedule ,
& vm_factory ,
self . depth ,
stack_depth ,
self . static_flag
) . consume ( self . state , substate , tracer , vm_tracer ) ;
2016-11-03 22:22:25 +01:00
2018-10-02 16:33:19 +02:00
match result {
Ok ( ref val ) if val . apply_state = > {
tracer . done_trace_create (
gas - val . gas_left ,
& val . return_data ,
address ,
) ;
} ,
Ok ( _ ) = > {
tracer . done_trace_failed ( & vm ::Error ::Reverted ) ;
} ,
Err ( ref err ) = > {
tracer . done_trace_failed ( err ) ;
} ,
2016-01-20 16:52:22 +01:00
}
2018-10-02 16:33:19 +02:00
vm_tracer . done_subtrace ( ) ;
2016-01-09 22:54:16 +01:00
2018-10-02 16:33:19 +02:00
result
}
2016-04-30 17:41:24 +02:00
2018-10-02 16:33:19 +02:00
/// Creates contract with given contract params, if the stack depth is above a threshold, create a new thread to
/// execute it.
pub fn create_with_crossbeam < T , V > (
& mut self ,
params : ActionParams ,
substate : & mut Substate ,
stack_depth : usize ,
tracer : & mut T ,
vm_tracer : & mut V ,
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
let local_stack_size = ::io ::LOCAL_STACK_SIZE . with ( | sz | sz . get ( ) ) ;
let depth_threshold = local_stack_size . saturating_sub ( STACK_SIZE_ENTRY_OVERHEAD ) / STACK_SIZE_PER_DEPTH ;
2016-04-30 17:41:24 +02:00
2018-10-02 16:33:19 +02:00
if stack_depth ! = depth_threshold {
self . create_with_stack_depth ( params , substate , stack_depth , tracer , vm_tracer )
2016-03-21 11:24:03 +01:00
} else {
2018-10-02 16:33:19 +02:00
crossbeam ::scope ( | scope | {
scope . builder ( ) . stack_size ( ::std ::cmp ::max ( self . schedule . max_depth . saturating_sub ( depth_threshold ) * STACK_SIZE_PER_DEPTH , local_stack_size ) ) . spawn ( move | | {
self . create_with_stack_depth ( params , substate , stack_depth , tracer , vm_tracer )
} ) . expect ( " Sub-thread creation cannot fail; the host might run out of resources; qed " )
} ) . join ( )
2016-01-09 22:54:16 +01:00
}
2016-01-07 19:05:44 +01:00
}
2016-02-09 16:31:57 +01:00
2016-01-09 21:39:38 +01:00
/// Creates contract with given contract params.
2016-06-02 12:40:31 +02:00
pub fn create < T , V > (
& mut self ,
params : ActionParams ,
substate : & mut Substate ,
tracer : & mut T ,
2017-04-19 14:30:00 +02:00
vm_tracer : & mut V ,
2017-09-15 21:07:54 +02:00
) -> vm ::Result < FinalizationResult > where T : Tracer , V : VMTracer {
2018-10-02 16:33:19 +02:00
self . create_with_stack_depth ( params , substate , 0 , tracer , vm_tracer )
2016-01-07 19:05:44 +01:00
}
2016-01-09 21:39:38 +01:00
2016-01-09 22:54:16 +01:00
/// Finalizes the transaction (does refunds and suicides).
2017-10-20 15:40:25 +02:00
fn finalize < T , V > (
2016-06-02 12:40:31 +02:00
& mut self ,
t : & SignedTransaction ,
2016-11-03 22:22:25 +01:00
mut substate : Substate ,
2017-09-15 21:07:54 +02:00
result : vm ::Result < FinalizationResult > ,
2016-06-02 12:40:31 +02:00
output : Bytes ,
2017-10-20 15:40:25 +02:00
trace : Vec < T > ,
vm_trace : Option < V >
) -> Result < Executed < T , V > , ExecutionError > {
2018-07-23 15:48:01 +02:00
let schedule = self . schedule ;
2016-01-15 00:36:58 +01:00
// refunds from SSTORE nonzero -> zero
2018-10-15 11:09:55 +02:00
assert! ( substate . sstore_clears_refund > = 0 , " On transaction level, sstore clears refund cannot go below zero. " ) ;
let sstore_refunds = U256 ::from ( substate . sstore_clears_refund as u64 ) ;
2016-01-15 00:36:58 +01:00
// refunds from contract suicides
let suicide_refunds = U256 ::from ( schedule . suicide_refund_gas ) * U256 ::from ( substate . suicides . len ( ) ) ;
2016-01-15 18:56:28 +01:00
let refunds_bound = sstore_refunds + suicide_refunds ;
2016-01-15 00:36:58 +01:00
// real ammount to refund
2017-09-15 21:07:54 +02:00
let gas_left_prerefund = match result { Ok ( FinalizationResult { gas_left , .. } ) = > gas_left , _ = > 0. into ( ) } ;
2016-10-06 18:42:54 +02:00
let refunded = cmp ::min ( refunds_bound , ( t . gas - gas_left_prerefund ) > > 1 ) ;
2016-01-15 18:56:28 +01:00
let gas_left = gas_left_prerefund + refunded ;
let gas_used = t . gas - gas_left ;
let refund_value = gas_left * t . gas_price ;
let fees_value = gas_used * t . gas_price ;
2016-01-16 01:48:38 +01:00
trace! ( " exec::finalize: t.gas={}, sstore_refunds={}, suicide_refunds={}, refunds_bound={}, gas_left_prerefund={}, refunded={}, gas_left={}, gas_used={}, refund_value={}, fees_value={} \n " ,
t . gas , sstore_refunds , suicide_refunds , refunds_bound , gas_left_prerefund , refunded , gas_left , gas_used , refund_value , fees_value ) ;
2016-01-15 18:56:28 +01:00
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2016-10-20 23:41:15 +02:00
trace! ( " exec::finalize: Refunding refund_value={}, sender={} \n " , refund_value , sender ) ;
2016-11-03 22:22:25 +01:00
// Below: NoEmpty is safe since the sender must already be non-null to have sent this transaction
2017-02-26 13:10:50 +01:00
self . state . add_balance ( & sender , & refund_value , CleanupMode ::NoEmpty ) ? ;
2016-01-16 01:48:38 +01:00
trace! ( " exec::finalize: Compensating author: fees_value={}, author={} \n " , fees_value , & self . info . author ) ;
2017-02-26 13:10:50 +01:00
self . state . add_balance ( & self . info . author , & fees_value , substate . to_cleanup_mode ( & schedule ) ) ? ;
2016-01-15 00:36:58 +01:00
// perform suicides
2016-01-17 15:56:09 +01:00
for address in & substate . suicides {
2016-01-15 00:36:58 +01:00
self . state . kill_account ( address ) ;
}
2016-11-03 22:22:25 +01:00
// perform garbage-collection
2017-06-28 09:10:57 +02:00
let min_balance = if schedule . kill_dust ! = CleanDustMode ::Off { Some ( U256 ::from ( schedule . tx_gas ) * t . gas_price ) } else { None } ;
self . state . kill_garbage ( & substate . touched , schedule . kill_empty , & min_balance , schedule . kill_dust = = CleanDustMode ::WithCodeAndStorage ) ? ;
2016-11-03 22:22:25 +01:00
2016-02-09 16:31:57 +01:00
match result {
2017-08-01 12:37:57 +02:00
Err ( vm ::Error ::Internal ( msg ) ) = > Err ( ExecutionError ::Internal ( msg ) ) ,
2017-01-12 11:06:12 +01:00
Err ( exception ) = > {
2016-01-11 17:37:22 +01:00
Ok ( Executed {
2017-01-12 11:06:12 +01:00
exception : Some ( exception ) ,
2016-01-11 17:37:22 +01:00
gas : t . gas ,
gas_used : t . gas ,
refunded : U256 ::zero ( ) ,
cumulative_gas_used : self . info . gas_used + t . gas ,
logs : vec ! [ ] ,
2016-03-18 23:49:12 +01:00
contracts_created : vec ! [ ] ,
2016-03-19 14:29:09 +01:00
output : output ,
2016-03-20 12:04:31 +01:00
trace : trace ,
2016-06-02 12:40:31 +02:00
vm_trace : vm_trace ,
2016-06-02 12:39:25 +02:00
state_diff : None ,
2016-01-11 17:37:22 +01:00
} )
2016-01-11 15:55:54 +01:00
} ,
2017-09-15 21:07:54 +02:00
Ok ( r ) = > {
2016-01-11 16:05:21 +01:00
Ok ( Executed {
2017-09-15 21:07:54 +02:00
exception : if r . apply_state { None } else { Some ( vm ::Error ::Reverted ) } ,
2016-01-11 16:05:21 +01:00
gas : t . gas ,
gas_used : gas_used ,
2016-01-15 18:56:28 +01:00
refunded : refunded ,
2016-01-11 16:05:21 +01:00
cumulative_gas_used : self . info . gas_used + gas_used ,
2016-01-11 17:37:22 +01:00
logs : substate . logs ,
2016-01-15 18:56:28 +01:00
contracts_created : substate . contracts_created ,
2016-03-19 14:29:09 +01:00
output : output ,
2016-03-20 12:04:31 +01:00
trace : trace ,
2016-06-02 12:40:31 +02:00
vm_trace : vm_trace ,
2016-06-02 12:39:25 +02:00
state_diff : None ,
2016-01-11 16:05:21 +01:00
} )
2016-01-14 17:40:38 +01:00
} ,
2016-01-09 23:24:01 +01:00
}
2016-01-09 21:39:38 +01:00
}
2016-01-09 17:55:47 +01:00
}
2016-01-07 23:33:54 +01:00
#[ cfg(test) ]
2016-02-08 22:54:33 +01:00
#[ allow(dead_code) ]
2016-01-07 23:33:54 +01:00
mod tests {
2016-11-28 17:05:37 +01:00
use std ::sync ::Arc ;
2017-07-29 17:12:07 +02:00
use std ::str ::FromStr ;
2017-07-06 11:26:14 +02:00
use rustc_hex ::FromHex ;
2016-08-24 18:35:21 +02:00
use ethkey ::{ Generator , Random } ;
2016-01-11 17:49:49 +01:00
use super ::* ;
2018-01-10 13:35:18 +01:00
use ethereum_types ::{ H256 , U256 , U512 , Address } ;
2017-08-01 12:37:57 +02:00
use vm ::{ ActionParams , ActionValue , CallType , EnvInfo , CreateContractAddress } ;
use evm ::{ Factory , VMType } ;
2016-10-24 18:35:25 +02:00
use error ::ExecutionError ;
2017-09-26 14:19:08 +02:00
use machine ::EthereumMachine ;
2016-11-03 22:22:25 +01:00
use state ::{ Substate , CleanupMode } ;
2018-04-09 16:14:33 +02:00
use test_helpers ::{ get_temp_state_with_factory , get_temp_state } ;
2016-04-30 17:41:24 +02:00
use trace ::trace ;
2016-07-28 20:31:29 +02:00
use trace ::{ FlatTrace , Tracer , NoopTracer , ExecutiveTracer } ;
2016-06-02 12:40:31 +02:00
use trace ::{ VMTrace , VMOperation , VMExecutedOperation , MemoryDiff , StorageDiff , VMTracer , NoopVMTracer , ExecutiveVMTracer } ;
2016-10-24 18:35:25 +02:00
use transaction ::{ Action , Transaction } ;
2017-09-26 14:19:08 +02:00
fn make_frontier_machine ( max_depth : usize ) -> EthereumMachine {
let mut machine = ::ethereum ::new_frontier_test_machine ( ) ;
machine . set_schedule_creation_rules ( Box ::new ( move | s , _ | s . max_depth = max_depth ) ) ;
machine
}
2018-05-09 08:48:55 +02:00
fn make_byzantium_machine ( max_depth : usize ) -> EthereumMachine {
let mut machine = ::ethereum ::new_byzantium_test_machine ( ) ;
machine . set_schedule_creation_rules ( Box ::new ( move | s , _ | s . max_depth = max_depth ) ) ;
machine
}
2016-01-07 23:33:54 +01:00
#[ test ]
fn test_contract_address ( ) {
let address = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
2016-01-09 02:12:17 +01:00
let expected_address = Address ::from_str ( " 3f09c73a5ed19289fb9bdc72f1742566df146f56 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
assert_eq! ( expected_address , contract_address ( CreateContractAddress ::FromSenderAndNonce , & address , & U256 ::from ( 88 ) , & [ ] ) . 0 ) ;
2016-01-07 23:33:54 +01:00
}
2016-01-09 01:33:50 +01:00
2016-01-09 13:51:59 +01:00
// TODO: replace params with transactions!
2018-04-04 11:07:49 +02:00
evm_test! { test_sender_balance : test_sender_balance_int }
2016-01-14 16:17:44 +01:00
fn test_sender_balance ( factory : Factory ) {
2016-01-09 02:12:17 +01:00
let sender = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-09 02:12:17 +01:00
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
2016-01-12 13:39:12 +01:00
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( " 3331600055 " . from_hex ( ) . unwrap ( ) ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 0x7 ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 0x100 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-09 02:12:17 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2016-01-12 13:39:12 +01:00
} ;
2016-01-09 02:12:17 +01:00
2016-01-12 13:39:12 +01:00
assert_eq! ( gas_left , U256 ::from ( 79_975 ) ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . storage_at ( & address , & H256 ::new ( ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 0xf9 u64 ) ) ) ;
assert_eq! ( state . balance ( & sender ) . unwrap ( ) , U256 ::from ( 0xf9 ) ) ;
assert_eq! ( state . balance ( & address ) . unwrap ( ) , U256 ::from ( 0x7 ) ) ;
2016-01-12 16:05:54 +01:00
assert_eq! ( substate . contracts_created . len ( ) , 0 ) ;
2016-01-11 17:37:22 +01:00
// TODO: just test state root.
2016-01-09 01:33:50 +01:00
}
2016-01-09 13:51:59 +01:00
2018-04-04 11:07:49 +02:00
evm_test! { test_create_contract_out_of_depth : test_create_contract_out_of_depth_int }
2016-03-19 21:02:44 +01:00
fn test_create_contract_out_of_depth ( factory : Factory ) {
2016-01-12 16:05:54 +01:00
// code:
//
2016-01-12 13:39:12 +01:00
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 17 - push 17
// f0 - create
// 60 00 - push 0
// 55 sstore
2016-01-12 16:05:54 +01:00
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
2016-01-12 13:39:12 +01:00
let code = " 7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055 " . from_hex ( ) . unwrap ( ) ;
2016-01-09 13:51:59 +01:00
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-12 13:39:12 +01:00
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-09 13:51:59 +01:00
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
2016-01-12 13:39:12 +01:00
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-09 13:51:59 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2016-01-12 13:39:12 +01:00
} ;
2016-02-09 16:31:57 +01:00
2016-01-13 13:16:53 +01:00
assert_eq! ( gas_left , U256 ::from ( 62_976 ) ) ;
// ended with max depth
assert_eq! ( substate . contracts_created . len ( ) , 0 ) ;
}
2018-05-09 08:48:55 +02:00
#[ test ]
fn test_call_to_precompiled_tracing ( ) {
// code:
//
// 60 00 - push 00 out size
// 60 00 - push 00 out offset
// 60 00 - push 00 in size
// 60 00 - push 00 in offset
// 60 01 - push 01 value
// 60 03 - push 03 to
// 61 ffff - push fff gas
// f1 - CALL
let code = " 60006000600060006001600361fffff1 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " 4444444444444444444444444444444444444444 " ) . unwrap ( ) ;
let address = Address ::from_str ( " 5555555555555555555555555555555555555555 " ) . unwrap ( ) ;
let mut params = ActionParams ::default ( ) ;
params . address = address . clone ( ) ;
params . code_address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
params . code = Some ( Arc ::new ( code ) ) ;
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
params . call_type = CallType ::Call ;
let mut state = get_temp_state ( ) ;
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
let info = EnvInfo ::default ( ) ;
let machine = make_byzantium_machine ( 5 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2018-05-09 08:48:55 +02:00
let mut substate = Substate ::new ( ) ;
let mut tracer = ExecutiveTracer ::default ( ) ;
let mut vm_tracer = ExecutiveVMTracer ::toplevel ( ) ;
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut tracer , & mut vm_tracer ) . unwrap ( ) ;
2018-05-09 08:48:55 +02:00
assert_eq! ( tracer . drain ( ) , vec! [ FlatTrace {
action : trace ::Action ::Call ( trace ::Call {
from : " 4444444444444444444444444444444444444444 " . into ( ) ,
to : " 5555555555555555555555555555555555555555 " . into ( ) ,
value : 100. into ( ) ,
gas : 100_000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : 33021. into ( ) ,
output : vec ! [ ]
} ) ,
subtraces : 1 ,
trace_address : Default ::default ( )
} , FlatTrace {
action : trace ::Action ::Call ( trace ::Call {
from : " 5555555555555555555555555555555555555555 " . into ( ) ,
to : " 0000000000000000000000000000000000000003 " . into ( ) ,
value : 1. into ( ) ,
gas : 66560. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call
} ) , result : trace ::Res ::Call ( trace ::CallResult {
gas_used : 600. into ( ) ,
2018-08-13 23:27:13 +02:00
output : vec ! [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 156 , 17 , 133 , 165 , 197 , 233 , 252 , 84 , 97 , 40 , 8 , 151 , 126 , 232 , 245 , 72 , 178 , 37 , 141 , 49 ]
2018-05-09 08:48:55 +02:00
} ) ,
subtraces : 0 ,
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
} ] ) ;
}
2016-09-28 23:33:12 +02:00
#[ test ]
// Tracing is not suported in JIT
fn test_call_to_create ( ) {
2016-03-19 21:02:44 +01:00
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
2016-06-02 12:40:31 +02:00
// 60 17 - push 23
2016-03-19 21:02:44 +01:00
// f0 - create
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = " 7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0600055 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-03-19 21:02:44 +01:00
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams ::default ( ) ;
params . address = address . clone ( ) ;
2016-03-21 11:24:03 +01:00
params . code_address = address . clone ( ) ;
2016-03-19 21:02:44 +01:00
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-03-19 21:02:44 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
2016-07-27 17:41:21 +02:00
params . call_type = CallType ::Call ;
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-03-19 21:02:44 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
let mut tracer = ExecutiveTracer ::default ( ) ;
2016-08-03 23:23:45 +02:00
let mut vm_tracer = ExecutiveVMTracer ::toplevel ( ) ;
2016-03-19 21:02:44 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut tracer , & mut vm_tracer ) . unwrap ( )
2016-03-19 21:02:44 +01:00
} ;
2016-06-02 12:40:31 +02:00
assert_eq! ( gas_left , U256 ::from ( 44_752 ) ) ;
2016-07-28 20:31:29 +02:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
2016-04-30 17:41:24 +02:00
action : trace ::Action ::Call ( trace ::Call {
2016-05-31 16:59:01 +02:00
from : " cd1722f3947def4cf144679da39c4c32bdc35681 " . into ( ) ,
to : " b010143a42d5980c7e5ef0e4a4416dc098a4fed3 " . into ( ) ,
value : 100. into ( ) ,
gas : 100000. into ( ) ,
2016-03-19 21:02:44 +01:00
input : vec ! [ ] ,
2016-07-27 17:41:21 +02:00
call_type : CallType ::Call ,
2016-04-08 01:50:55 +02:00
} ) ,
2016-04-30 17:41:24 +02:00
result : trace ::Res ::Call ( trace ::CallResult {
2016-04-08 01:50:55 +02:00
gas_used : U256 ::from ( 55_248 ) ,
output : vec ! [ ] ,
2016-03-19 21:02:44 +01:00
} ) ,
2016-07-28 20:31:29 +02:00
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Create ( trace ::Create {
from : " b010143a42d5980c7e5ef0e4a4416dc098a4fed3 " . into ( ) ,
value : 23. into ( ) ,
gas : 67979. into ( ) ,
init : vec ! [ 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ]
} ) ,
result : trace ::Res ::Create ( trace ::CreateResult {
gas_used : U256 ::from ( 3224 ) ,
address : Address ::from_str ( " c6d80f262ae5e0f164e5fde365044d7ada2bfa34 " ) . unwrap ( ) ,
code : vec ! [ 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 ]
} ) ,
2016-04-08 01:50:55 +02:00
} ] ;
2016-07-28 20:31:29 +02:00
2017-08-28 14:25:16 +02:00
assert_eq! ( tracer . drain ( ) , expected_trace ) ;
2016-06-02 12:40:31 +02:00
let expected_vm_trace = VMTrace {
parent_step : 0 ,
code : vec ! [ 124 , 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 , 96 , 0 , 82 , 96 , 29 , 96 , 3 , 96 , 23 , 240 , 96 , 0 , 85 ] ,
operations : vec ! [
2016-06-02 19:04:15 +02:00
VMOperation { pc : 0 , instruction : 124 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99997. into ( ) , stack_push : vec_into ! [ U256 ::from_dec_str ( " 2589892687202724018173567190521546555304938078595079151649957320078677 " ) . unwrap ( ) ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 30 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99994. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 32 , instruction : 82 , gas_cost : 6. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99988. into ( ) , stack_push : vec_into ! [ ] , mem_diff : Some ( MemoryDiff { offset : 0 , data : vec ! [ 0 , 0 , 0 , 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ] } ) , store_diff : None } ) } ,
VMOperation { pc : 33 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99985. into ( ) , stack_push : vec_into ! [ 29 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 35 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99982. into ( ) , stack_push : vec_into ! [ 3 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 37 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99979. into ( ) , stack_push : vec_into ! [ 23 ] , mem_diff : None , store_diff : None } ) } ,
2016-10-15 14:39:15 +02:00
VMOperation { pc : 39 , instruction : 240 , gas_cost : 99979. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 64755. into ( ) , stack_push : vec_into ! [ U256 ::from_dec_str ( " 1135198453258042933984631383966629874710669425204 " ) . unwrap ( ) ] , mem_diff : None , store_diff : None } ) } ,
2016-06-02 19:04:15 +02:00
VMOperation { pc : 40 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 64752. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
2016-06-02 12:40:31 +02:00
VMOperation { pc : 42 , instruction : 85 , gas_cost : 20000. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 44752. into ( ) , stack_push : vec_into ! [ ] , mem_diff : None , store_diff : Some ( StorageDiff { location : 0. into ( ) , value : U256 ::from_dec_str ( " 1135198453258042933984631383966629874710669425204 " ) . unwrap ( ) } ) } ) }
] ,
subs : vec ! [
VMTrace {
2016-08-03 23:23:45 +02:00
parent_step : 6 ,
2016-06-02 12:40:31 +02:00
code : vec ! [ 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ] ,
operations : vec ! [
2016-06-02 19:04:15 +02:00
VMOperation { pc : 0 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67976. into ( ) , stack_push : vec_into ! [ 16 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 2 , instruction : 128 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67973. into ( ) , stack_push : vec_into ! [ 16 , 16 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 3 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67970. into ( ) , stack_push : vec_into ! [ 12 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 5 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67967. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 7 , instruction : 57 , gas_cost : 9. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67958. into ( ) , stack_push : vec_into ! [ ] , mem_diff : Some ( MemoryDiff { offset : 0 , data : vec ! [ 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 ] } ) , store_diff : None } ) } ,
VMOperation { pc : 8 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67955. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
2016-06-02 12:40:31 +02:00
VMOperation { pc : 10 , instruction : 243 , gas_cost : 0. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 67955. into ( ) , stack_push : vec_into ! [ ] , mem_diff : None , store_diff : None } ) }
] ,
subs : vec ! [ ]
}
]
} ;
assert_eq! ( vm_tracer . drain ( ) . unwrap ( ) , expected_vm_trace ) ;
2016-03-19 21:02:44 +01:00
}
2017-12-29 15:29:18 +01:00
#[ test ]
fn test_trace_reverted_create ( ) {
// code:
//
// 65 60016000fd - push 5 bytes
// 60 00 - push 0
// 52 mstore
// 60 05 - push 5
// 60 1b - push 27
// 60 17 - push 23
// f0 - create
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 01
// 60 00
// fd - revert
let code = " 6460016000fd6000526005601b6017f0600055 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
let mut params = ActionParams ::default ( ) ;
params . address = address . clone ( ) ;
params . code_address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
params . code = Some ( Arc ::new ( code ) ) ;
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
params . call_type = CallType ::Call ;
let mut state = get_temp_state ( ) ;
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
let info = EnvInfo ::default ( ) ;
let machine = ::ethereum ::new_byzantium_test_machine ( ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2017-12-29 15:29:18 +01:00
let mut substate = Substate ::new ( ) ;
let mut tracer = ExecutiveTracer ::default ( ) ;
let mut vm_tracer = ExecutiveVMTracer ::toplevel ( ) ;
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut tracer , & mut vm_tracer ) . unwrap ( )
2017-12-29 15:29:18 +01:00
} ;
assert_eq! ( gas_left , U256 ::from ( 62967 ) ) ;
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 1 ,
action : trace ::Action ::Call ( trace ::Call {
from : " cd1722f3947def4cf144679da39c4c32bdc35681 " . into ( ) ,
to : " b010143a42d5980c7e5ef0e4a4416dc098a4fed3 " . into ( ) ,
value : 100. into ( ) ,
gas : 100_000. into ( ) ,
input : vec ! [ ] ,
call_type : CallType ::Call ,
} ) ,
result : trace ::Res ::Call ( trace ::CallResult {
gas_used : U256 ::from ( 37_033 ) ,
output : vec ! [ ] ,
} ) ,
} , FlatTrace {
trace_address : vec ! [ 0 ] . into_iter ( ) . collect ( ) ,
subtraces : 0 ,
action : trace ::Action ::Create ( trace ::Create {
from : " b010143a42d5980c7e5ef0e4a4416dc098a4fed3 " . into ( ) ,
value : 23. into ( ) ,
gas : 66_917. into ( ) ,
init : vec ! [ 0x60 , 0x01 , 0x60 , 0x00 , 0xfd ]
} ) ,
result : trace ::Res ::FailedCreate ( vm ::Error ::Reverted . into ( ) ) ,
} ] ;
assert_eq! ( tracer . drain ( ) , expected_trace ) ;
}
2016-09-28 23:33:12 +02:00
#[ test ]
fn test_create_contract ( ) {
// Tracing is not supported in JIT
2016-03-19 22:12:52 +01:00
// code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = " 601080600c6000396000f3006000355415600957005b60203560003555 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-03-19 22:12:52 +01:00
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
let mut params = ActionParams ::default ( ) ;
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-05-31 16:59:01 +02:00
params . value = ActionValue ::Transfer ( 100. into ( ) ) ;
2017-04-06 19:26:17 +02:00
let mut state = get_temp_state ( ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-03-19 22:12:52 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 5 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
let mut tracer = ExecutiveTracer ::default ( ) ;
2016-08-03 23:23:45 +02:00
let mut vm_tracer = ExecutiveVMTracer ::toplevel ( ) ;
2016-03-19 22:12:52 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params . clone ( ) , & mut substate , & mut tracer , & mut vm_tracer ) . unwrap ( )
2016-03-19 22:12:52 +01:00
} ;
2016-06-02 12:40:31 +02:00
assert_eq! ( gas_left , U256 ::from ( 96_776 ) ) ;
2016-07-28 20:31:29 +02:00
let expected_trace = vec! [ FlatTrace {
trace_address : Default ::default ( ) ,
subtraces : 0 ,
2016-04-30 17:41:24 +02:00
action : trace ::Action ::Create ( trace ::Create {
2016-03-19 22:12:52 +01:00
from : params . sender ,
2016-05-31 16:59:01 +02:00
value : 100. into ( ) ,
2016-03-19 22:12:52 +01:00
gas : params . gas ,
init : vec ! [ 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ] ,
2016-04-08 01:50:55 +02:00
} ) ,
2016-04-30 17:41:24 +02:00
result : trace ::Res ::Create ( trace ::CreateResult {
2016-04-08 01:50:55 +02:00
gas_used : U256 ::from ( 3224 ) ,
address : params . address ,
code : vec ! [ 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 ]
2016-03-19 22:12:52 +01:00
} ) ,
2016-04-08 01:50:55 +02:00
} ] ;
2016-07-28 20:31:29 +02:00
2017-08-28 14:25:16 +02:00
assert_eq! ( tracer . drain ( ) , expected_trace ) ;
2016-06-02 19:04:15 +02:00
2016-06-02 12:40:31 +02:00
let expected_vm_trace = VMTrace {
parent_step : 0 ,
code : vec ! [ 96 , 16 , 128 , 96 , 12 , 96 , 0 , 57 , 96 , 0 , 243 , 0 , 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 , 85 ] ,
operations : vec ! [
VMOperation { pc : 0 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99997. into ( ) , stack_push : vec_into ! [ 16 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 2 , instruction : 128 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99994. into ( ) , stack_push : vec_into ! [ 16 , 16 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 3 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99991. into ( ) , stack_push : vec_into ! [ 12 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 5 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99988. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 7 , instruction : 57 , gas_cost : 9. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99979. into ( ) , stack_push : vec_into ! [ ] , mem_diff : Some ( MemoryDiff { offset : 0 , data : vec ! [ 96 , 0 , 53 , 84 , 21 , 96 , 9 , 87 , 0 , 91 , 96 , 32 , 53 , 96 , 0 , 53 ] } ) , store_diff : None } ) } ,
VMOperation { pc : 8 , instruction : 96 , gas_cost : 3. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99976. into ( ) , stack_push : vec_into ! [ 0 ] , mem_diff : None , store_diff : None } ) } ,
VMOperation { pc : 10 , instruction : 243 , gas_cost : 0. into ( ) , executed : Some ( VMExecutedOperation { gas_used : 99976. into ( ) , stack_push : vec_into ! [ ] , mem_diff : None , store_diff : None } ) }
] ,
subs : vec ! [ ]
} ;
assert_eq! ( vm_tracer . drain ( ) . unwrap ( ) , expected_vm_trace ) ;
2016-03-19 22:12:52 +01:00
}
2016-03-21 11:24:03 +01:00
2018-04-04 11:07:49 +02:00
evm_test! { test_create_contract_value_too_high : test_create_contract_value_too_high_int }
2016-01-14 16:17:44 +01:00
fn test_create_contract_value_too_high ( factory : Factory ) {
2016-01-13 13:16:53 +01:00
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 e6 - push 230
// f0 - create a contract trying to send 230.
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
let code = " 7c601080600c6000396000f3006000355415600957005b60203560003555600052601d600360e6f0600055 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-13 13:16:53 +01:00
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-13 13:16:53 +01:00
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-13 13:16:53 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2016-01-13 13:16:53 +01:00
} ;
2016-02-09 16:31:57 +01:00
2016-01-13 13:16:53 +01:00
assert_eq! ( gas_left , U256 ::from ( 62_976 ) ) ;
2016-01-12 16:05:54 +01:00
assert_eq! ( substate . contracts_created . len ( ) , 0 ) ;
}
2018-04-04 11:07:49 +02:00
evm_test! { test_create_contract_without_max_depth : test_create_contract_without_max_depth_int }
2016-01-14 16:17:44 +01:00
fn test_create_contract_without_max_depth ( factory : Factory ) {
2016-01-12 16:05:54 +01:00
// code:
//
// 7c 601080600c6000396000f3006000355415600957005b60203560003555 - push 29 bytes?
// 60 00 - push 0
// 52
// 60 1d - push 29
// 60 03 - push 3
// 60 17 - push 17
// f0 - create
// 60 00 - push 0
// 55 sstore
//
// other code:
//
// 60 10 - push 16
// 80 - duplicate first stack item
// 60 0c - push 12
// 60 00 - push 0
// 39 - copy current code to memory
// 60 00 - push 0
// f3 - return
2016-01-14 12:33:49 +01:00
let code = " 7c601080600c6000396000f3006000355415600957005b60203560003555600052601d60036017f0 " . from_hex ( ) . unwrap ( ) ;
2016-01-12 16:05:54 +01:00
2016-01-09 13:51:59 +01:00
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
let next_address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & address , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-09 13:51:59 +01:00
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
2016-01-12 16:05:54 +01:00
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 100 ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 1024 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-09 13:51:59 +01:00
{
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( ) ;
2016-01-09 13:51:59 +01:00
}
2016-02-09 16:31:57 +01:00
2016-01-12 16:05:54 +01:00
assert_eq! ( substate . contracts_created . len ( ) , 1 ) ;
assert_eq! ( substate . contracts_created [ 0 ] , next_address ) ;
2016-01-12 13:39:12 +01:00
}
2016-01-16 04:59:53 +01:00
// test is incorrect, mk
2016-02-08 22:54:33 +01:00
// TODO: fix (preferred) or remove
2018-04-04 11:07:49 +02:00
evm_test_ignore! { test_aba_calls : test_aba_calls_int }
2016-01-14 16:17:44 +01:00
fn test_aba_calls ( factory : Factory ) {
2016-01-12 13:39:12 +01:00
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 18 - push 18
// 73 945304eb96065b2a98b57a48a06ae28d285a71b5 - push this address
// 61 03e8 - push 1000
// f1 - message call
// 58 - get PC
// 55 - sstore
let code_a = " 6000600060006000601873945304eb96065b2a98b57a48a06ae28d285a71b56103e8f15855 " . from_hex ( ) . unwrap ( ) ;
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 17 - push 17
// 73 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 - push this address
// 61 0x01f4 - push 500
// f1 - message call
// 60 01 - push 1
// 01 - add
// 58 - get PC
// 55 - sstore
let code_b = " 60006000600060006017730f572e5295c57f15886f9b263e2f6d2d6c7b5ec66101f4f16001015855 " . from_hex ( ) . unwrap ( ) ;
let address_a = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
let address_b = Address ::from_str ( " 945304eb96065b2a98b57a48a06ae28d285a71b5 " ) . unwrap ( ) ;
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-12 13:39:12 +01:00
params . address = address_a . clone ( ) ;
params . sender = sender . clone ( ) ;
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code_a . clone ( ) ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from ( 100_000 ) ) ;
2016-01-12 13:39:12 +01:00
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . init_code ( & address_a , code_a . clone ( ) ) . unwrap ( ) ;
state . init_code ( & address_b , code_b . clone ( ) ) . unwrap ( ) ;
state . add_balance ( & sender , & U256 ::from ( 100_000 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-01-12 13:39:12 +01:00
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-12 13:39:12 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2016-01-12 13:39:12 +01:00
} ;
assert_eq! ( gas_left , U256 ::from ( 73_237 ) ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . storage_at ( & address_a , & H256 ::from ( & U256 ::from ( 0x23 ) ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 1 ) ) ) ;
2016-01-10 16:21:01 +01:00
}
2016-01-16 04:59:53 +01:00
// test is incorrect, mk
2016-02-08 22:54:33 +01:00
// TODO: fix (preferred) or remove
2018-04-04 11:07:49 +02:00
evm_test_ignore! { test_recursive_bomb1 : test_recursive_bomb1_int }
2016-01-14 16:17:44 +01:00
fn test_recursive_bomb1 ( factory : Factory ) {
2016-01-10 16:21:01 +01:00
// 60 01 - push 1
// 60 00 - push 0
2016-02-09 16:31:57 +01:00
// 54 - sload
2016-01-10 16:21:01 +01:00
// 01 - add
// 60 00 - push 0
// 55 - sstore
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 60 00 - push 0
// 30 - load address
// 60 e0 - push e0
// 5a - get gas
// 03 - sub
// f1 - message call (self in this case)
// 60 01 - push 1
2016-01-12 13:39:12 +01:00
// 55 - sstore
2016-01-10 16:21:01 +01:00
let sender = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
2016-01-11 14:08:03 +01:00
let code = " 600160005401600055600060006000600060003060e05a03f1600155 " . from_hex ( ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-10 16:21:01 +01:00
params . address = address . clone ( ) ;
2016-01-12 13:39:12 +01:00
params . gas = U256 ::from ( 100_000 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code . clone ( ) ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . init_code ( & address , code ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-10 16:21:01 +01:00
2017-09-15 21:07:54 +02:00
let FinalizationResult { gas_left , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2016-01-12 13:39:12 +01:00
} ;
2016-01-10 16:21:01 +01:00
2016-01-12 13:39:12 +01:00
assert_eq! ( gas_left , U256 ::from ( 59_870 ) ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . storage_at ( & address , & H256 ::from ( & U256 ::zero ( ) ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 1 ) ) ) ;
assert_eq! ( state . storage_at ( & address , & H256 ::from ( & U256 ::one ( ) ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 1 ) ) ) ;
2016-01-09 13:51:59 +01:00
}
2016-01-12 18:31:47 +01:00
2016-01-16 04:59:53 +01:00
// test is incorrect, mk
2016-02-08 22:54:33 +01:00
// TODO: fix (preferred) or remove
2018-04-04 11:07:49 +02:00
evm_test_ignore! { test_transact_simple : test_transact_simple_int }
2016-01-14 16:17:44 +01:00
fn test_transact_simple ( factory : Factory ) {
2016-08-24 18:35:21 +02:00
let keypair = Random . generate ( ) . unwrap ( ) ;
2016-02-04 23:48:29 +01:00
let t = Transaction {
action : Action ::Create ,
value : U256 ::from ( 17 ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 100_000 ) ,
gas_price : U256 ::zero ( ) ,
nonce : U256 ::zero ( )
2016-11-03 22:22:25 +01:00
} . sign ( keypair . secret ( ) , None ) ;
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2017-06-30 11:30:32 +02:00
let contract = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-12 18:31:47 +01:00
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 18 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let mut info = EnvInfo ::default ( ) ;
2016-01-12 18:31:47 +01:00
info . gas_limit = U256 ::from ( 100_000 ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-01-12 18:31:47 +01:00
let executed = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2017-08-28 14:25:16 +02:00
let opts = TransactOptions ::with_no_tracing ( ) ;
2016-04-06 13:05:58 +02:00
ex . transact ( & t , opts ) . unwrap ( )
2016-01-12 18:31:47 +01:00
} ;
assert_eq! ( executed . gas , U256 ::from ( 100_000 ) ) ;
2016-01-14 16:40:50 +01:00
assert_eq! ( executed . gas_used , U256 ::from ( 41_301 ) ) ;
assert_eq! ( executed . refunded , U256 ::from ( 58_699 ) ) ;
assert_eq! ( executed . cumulative_gas_used , U256 ::from ( 41_301 ) ) ;
2016-01-12 18:31:47 +01:00
assert_eq! ( executed . logs . len ( ) , 0 ) ;
assert_eq! ( executed . contracts_created . len ( ) , 0 ) ;
2017-02-26 13:10:50 +01:00
assert_eq! ( state . balance ( & sender ) . unwrap ( ) , U256 ::from ( 1 ) ) ;
assert_eq! ( state . balance ( & contract ) . unwrap ( ) , U256 ::from ( 17 ) ) ;
assert_eq! ( state . nonce ( & sender ) . unwrap ( ) , U256 ::from ( 1 ) ) ;
assert_eq! ( state . storage_at ( & contract , & H256 ::new ( ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 1 ) ) ) ;
2016-01-12 18:31:47 +01:00
}
2018-04-04 11:07:49 +02:00
evm_test! { test_transact_invalid_nonce : test_transact_invalid_nonce_int }
2016-01-14 16:17:44 +01:00
fn test_transact_invalid_nonce ( factory : Factory ) {
2016-08-24 18:35:21 +02:00
let keypair = Random . generate ( ) . unwrap ( ) ;
2016-02-04 23:48:29 +01:00
let t = Transaction {
action : Action ::Create ,
value : U256 ::from ( 17 ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 100_000 ) ,
gas_price : U256 ::zero ( ) ,
nonce : U256 ::one ( )
2016-11-03 22:22:25 +01:00
} . sign ( keypair . secret ( ) , None ) ;
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2016-02-04 23:48:29 +01:00
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 17 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let mut info = EnvInfo ::default ( ) ;
2016-01-12 19:43:26 +01:00
info . gas_limit = U256 ::from ( 100_000 ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-01-12 19:43:26 +01:00
let res = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2017-08-28 14:25:16 +02:00
let opts = TransactOptions ::with_no_tracing ( ) ;
2016-04-06 13:05:58 +02:00
ex . transact ( & t , opts )
2016-01-12 19:43:26 +01:00
} ;
2016-02-09 16:31:57 +01:00
2016-01-12 19:43:26 +01:00
match res {
2016-05-14 14:28:44 +02:00
Err ( ExecutionError ::InvalidNonce { expected , got } )
2016-02-09 16:31:57 +01:00
if expected = = U256 ::zero ( ) & & got = = U256 ::one ( ) = > ( ) ,
2016-01-12 19:43:26 +01:00
_ = > assert! ( false , " Expected invalid nonce error. " )
}
}
2018-04-04 11:07:49 +02:00
evm_test! { test_transact_gas_limit_reached : test_transact_gas_limit_reached_int }
2016-01-14 16:17:44 +01:00
fn test_transact_gas_limit_reached ( factory : Factory ) {
2016-08-24 18:35:21 +02:00
let keypair = Random . generate ( ) . unwrap ( ) ;
2016-02-04 23:48:29 +01:00
let t = Transaction {
action : Action ::Create ,
value : U256 ::from ( 17 ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 80_001 ) ,
gas_price : U256 ::zero ( ) ,
nonce : U256 ::zero ( )
2016-11-03 22:22:25 +01:00
} . sign ( keypair . secret ( ) , None ) ;
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2016-01-12 19:43:26 +01:00
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 17 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let mut info = EnvInfo ::default ( ) ;
2016-01-12 19:43:26 +01:00
info . gas_used = U256 ::from ( 20_000 ) ;
info . gas_limit = U256 ::from ( 100_000 ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-01-12 19:43:26 +01:00
let res = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2017-08-28 14:25:16 +02:00
let opts = TransactOptions ::with_no_tracing ( ) ;
2016-04-06 13:05:58 +02:00
ex . transact ( & t , opts )
2016-01-12 19:43:26 +01:00
} ;
match res {
2016-05-14 14:28:44 +02:00
Err ( ExecutionError ::BlockGasLimitReached { gas_limit , gas_used , gas } )
2016-02-09 16:31:57 +01:00
if gas_limit = = U256 ::from ( 100_000 ) & & gas_used = = U256 ::from ( 20_000 ) & & gas = = U256 ::from ( 80_001 ) = > ( ) ,
2016-01-12 19:43:26 +01:00
_ = > assert! ( false , " Expected block gas limit error. " )
}
}
2018-04-04 11:07:49 +02:00
evm_test! { test_not_enough_cash : test_not_enough_cash_int }
2016-01-14 16:17:44 +01:00
fn test_not_enough_cash ( factory : Factory ) {
2016-02-04 23:48:29 +01:00
2016-08-24 18:35:21 +02:00
let keypair = Random . generate ( ) . unwrap ( ) ;
2016-02-04 23:48:29 +01:00
let t = Transaction {
action : Action ::Create ,
value : U256 ::from ( 18 ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 100_000 ) ,
gas_price : U256 ::one ( ) ,
nonce : U256 ::zero ( )
2016-11-03 22:22:25 +01:00
} . sign ( keypair . secret ( ) , None ) ;
2017-01-13 09:51:36 +01:00
let sender = t . sender ( ) ;
2016-01-12 19:43:26 +01:00
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from ( 100_017 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let mut info = EnvInfo ::default ( ) ;
2016-01-12 19:43:26 +01:00
info . gas_limit = U256 ::from ( 100_000 ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-01-12 18:31:47 +01:00
let res = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2017-08-28 14:25:16 +02:00
let opts = TransactOptions ::with_no_tracing ( ) ;
2016-04-06 13:05:58 +02:00
ex . transact ( & t , opts )
2016-01-12 18:31:47 +01:00
} ;
2016-02-09 16:31:57 +01:00
2016-01-12 18:31:47 +01:00
match res {
2016-05-14 14:28:44 +02:00
Err ( ExecutionError ::NotEnoughCash { required , got } )
2016-02-09 16:31:57 +01:00
if required = = U512 ::from ( 100_018 ) & & got = = U512 ::from ( 100_017 ) = > ( ) ,
2016-01-13 13:16:53 +01:00
_ = > assert! ( false , " Expected not enough cash error. {:?} " , res )
2016-01-10 16:21:01 +01:00
}
2016-01-09 13:51:59 +01:00
}
2016-01-15 23:32:16 +01:00
2018-04-04 11:07:49 +02:00
evm_test! { test_keccak : test_keccak_int }
2017-08-30 19:18:28 +02:00
fn test_keccak ( factory : Factory ) {
2016-01-15 23:32:16 +01:00
let code = " 6064640fffffffff20600055 " . from_hex ( ) . unwrap ( ) ;
let sender = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
2017-06-30 11:30:32 +02:00
let address = contract_address ( CreateContractAddress ::FromSenderAndNonce , & sender , & U256 ::zero ( ) , & [ ] ) . 0 ;
2016-01-15 23:32:16 +01:00
// TODO: add tests for 'callcreate'
//let next_address = contract_address(&address, &U256::zero());
2016-01-20 16:52:22 +01:00
let mut params = ActionParams ::default ( ) ;
2016-01-15 23:32:16 +01:00
params . address = address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 0x0186a0 ) ;
2016-10-02 18:45:36 +02:00
params . code = Some ( Arc ::new ( code ) ) ;
2016-01-20 17:31:37 +01:00
params . value = ActionValue ::Transfer ( U256 ::from_str ( " 0de0b6b3a7640000 " ) . unwrap ( ) ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory ) ;
2017-02-26 13:10:50 +01:00
state . add_balance ( & sender , & U256 ::from_str ( " 152d02c7e14af6800000 " ) . unwrap ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
2016-02-02 23:06:34 +01:00
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = make_frontier_machine ( 0 ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2016-04-08 01:50:55 +02:00
let mut substate = Substate ::new ( ) ;
2016-01-15 23:32:16 +01:00
let result = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . create ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer )
2016-01-15 23:32:16 +01:00
} ;
match result {
2017-05-23 15:49:17 +02:00
Err ( _ ) = > { } ,
_ = > panic! ( " Expected OutOfGas " ) ,
2016-01-15 23:32:16 +01:00
}
}
2017-05-23 15:49:17 +02:00
2018-04-04 11:07:49 +02:00
evm_test! { test_revert : test_revert_int }
2017-05-23 15:49:17 +02:00
fn test_revert ( factory : Factory ) {
let contract_address = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
let sender = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
// EIP-140 test case
let code = " 6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd " . from_hex ( ) . unwrap ( ) ;
let returns = " 726576657274206d657373616765 " . from_hex ( ) . unwrap ( ) ;
2017-05-30 11:52:33 +02:00
let mut state = get_temp_state_with_factory ( factory . clone ( ) ) ;
2017-05-23 15:49:17 +02:00
state . add_balance ( & sender , & U256 ::from_str ( " 152d02c7e14af68000000 " ) . unwrap ( ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
state . commit ( ) . unwrap ( ) ;
let mut params = ActionParams ::default ( ) ;
params . address = contract_address . clone ( ) ;
params . sender = sender . clone ( ) ;
params . origin = sender . clone ( ) ;
params . gas = U256 ::from ( 20025 ) ;
params . code = Some ( Arc ::new ( code ) ) ;
params . value = ActionValue ::Transfer ( U256 ::zero ( ) ) ;
let info = EnvInfo ::default ( ) ;
2017-09-26 14:19:08 +02:00
let machine = ::ethereum ::new_byzantium_test_machine ( ) ;
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
2017-05-23 15:49:17 +02:00
let mut substate = Substate ::new ( ) ;
let mut output = [ 0 u8 ; 14 ] ;
2018-08-13 23:27:13 +02:00
let FinalizationResult { gas_left : result , return_data , .. } = {
2018-07-23 15:48:01 +02:00
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2017-05-23 15:49:17 +02:00
} ;
2018-08-13 23:27:13 +02:00
( & mut output ) . copy_from_slice ( & return_data [ .. ( cmp ::min ( 14 , return_data . len ( ) ) ) ] ) ;
2017-05-23 15:49:17 +02:00
assert_eq! ( result , U256 ::from ( 1 ) ) ;
assert_eq! ( output [ .. ] , returns [ .. ] ) ;
assert_eq! ( state . storage_at ( & contract_address , & H256 ::from ( & U256 ::zero ( ) ) ) . unwrap ( ) , H256 ::from ( & U256 ::from ( 0 ) ) ) ;
}
2018-02-19 12:27:42 +01:00
2018-09-07 12:51:08 +02:00
evm_test! { test_eip1283 : test_eip1283_int }
fn test_eip1283 ( factory : Factory ) {
let x1 = Address ::from ( 0x1000 ) ;
let x2 = Address ::from ( 0x1001 ) ;
let y1 = Address ::from ( 0x2001 ) ;
let y2 = Address ::from ( 0x2002 ) ;
let operating_address = Address ::from ( 0 ) ;
let k = H256 ::new ( ) ;
let mut state = get_temp_state_with_factory ( factory . clone ( ) ) ;
state . new_contract ( & x1 , U256 ::zero ( ) , U256 ::from ( 1 ) ) . unwrap ( ) ;
state . init_code ( & x1 , " 600160005560006000556001600055 " . from_hex ( ) . unwrap ( ) ) . unwrap ( ) ;
state . new_contract ( & x2 , U256 ::zero ( ) , U256 ::from ( 1 ) ) . unwrap ( ) ;
state . init_code ( & x2 , " 600060005560016000556000600055 " . from_hex ( ) . unwrap ( ) ) . unwrap ( ) ;
state . new_contract ( & y1 , U256 ::zero ( ) , U256 ::from ( 1 ) ) . unwrap ( ) ;
state . init_code ( & y1 , " 600060006000600061100062fffffff4 " . from_hex ( ) . unwrap ( ) ) . unwrap ( ) ;
state . new_contract ( & y2 , U256 ::zero ( ) , U256 ::from ( 1 ) ) . unwrap ( ) ;
state . init_code ( & y2 , " 600060006000600061100162fffffff4 " . from_hex ( ) . unwrap ( ) ) . unwrap ( ) ;
let info = EnvInfo ::default ( ) ;
let machine = ::ethereum ::new_constantinople_test_machine ( ) ;
let schedule = machine . schedule ( info . number ) ;
assert_eq! ( state . storage_at ( & operating_address , & k ) . unwrap ( ) , H256 ::from ( U256 ::from ( 0 ) ) ) ;
// Test a call via top-level -> y1 -> x1
let ( FinalizationResult { gas_left , .. } , refund , gas ) = {
let gas = U256 ::from ( 0xffffffffff u64 ) ;
let mut params = ActionParams ::default ( ) ;
params . code = Some ( Arc ::new ( " 6001600055600060006000600061200163fffffffff4 " . from_hex ( ) . unwrap ( ) ) ) ;
params . gas = gas ;
let mut substate = Substate ::new ( ) ;
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
let res = ex . call ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( ) ;
( res , substate . sstore_clears_refund , gas )
} ;
let gas_used = gas - gas_left ;
// sstore: 0 -> (1) -> () -> (1 -> 0 -> 1)
assert_eq! ( gas_used , U256 ::from ( 41860 ) ) ;
2018-10-15 11:09:55 +02:00
assert_eq! ( refund , 19800 ) ;
2018-09-07 12:51:08 +02:00
assert_eq! ( state . storage_at ( & operating_address , & k ) . unwrap ( ) , H256 ::from ( U256 ::from ( 1 ) ) ) ;
// Test a call via top-level -> y2 -> x2
let ( FinalizationResult { gas_left , .. } , refund , gas ) = {
let gas = U256 ::from ( 0xffffffffff u64 ) ;
let mut params = ActionParams ::default ( ) ;
params . code = Some ( Arc ::new ( " 6001600055600060006000600061200263fffffffff4 " . from_hex ( ) . unwrap ( ) ) ) ;
params . gas = gas ;
let mut substate = Substate ::new ( ) ;
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
let res = ex . call ( params , & mut substate , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( ) ;
( res , substate . sstore_clears_refund , gas )
} ;
let gas_used = gas - gas_left ;
// sstore: 1 -> (1) -> () -> (0 -> 1 -> 0)
assert_eq! ( gas_used , U256 ::from ( 11860 ) ) ;
2018-10-15 11:09:55 +02:00
assert_eq! ( refund , 19800 ) ;
2018-09-07 12:51:08 +02:00
}
2018-02-19 12:27:42 +01:00
fn wasm_sample_code ( ) -> Arc < Vec < u8 > > {
Arc ::new (
" 0061736d01000000010d0360027f7f0060017f0060000002270303656e7603726574000003656e760673656e646572000103656e76066d656d6f727902010110030201020404017000000501000708010463616c6c00020901000ac10101be0102057f017e4100410028020441c0006b22043602042004412c6a41106a220041003602002004412c6a41086a22014200370200200441186a41106a22024100360200200441186a41086a220342003703002004420037022c2004410036021c20044100360218200441186a1001200020022802002202360200200120032903002205370200200441106a2002360200200441086a200537030020042004290318220537022c200420053703002004411410004100200441c0006a3602040b0b0a010041040b0410c00000 "
. from_hex ( )
. unwrap ( )
)
}
#[ test ]
fn wasm_activated_test ( ) {
let contract_address = Address ::from_str ( " cd1722f3947def4cf144679da39c4c32bdc35681 " ) . unwrap ( ) ;
let sender = Address ::from_str ( " 0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6 " ) . unwrap ( ) ;
let mut state = get_temp_state ( ) ;
state . add_balance ( & sender , & U256 ::from ( 10000000000 u64 ) , CleanupMode ::NoEmpty ) . unwrap ( ) ;
state . commit ( ) . unwrap ( ) ;
let mut params = ActionParams ::default ( ) ;
params . origin = sender . clone ( ) ;
params . sender = sender . clone ( ) ;
params . address = contract_address . clone ( ) ;
params . gas = U256 ::from ( 20025 ) ;
params . code = Some ( wasm_sample_code ( ) ) ;
let mut info = EnvInfo ::default ( ) ;
// 100 > 10
info . number = 100 ;
// Network with wasm activated at block 10
let machine = ::ethereum ::new_kovan_wasm_test_machine ( ) ;
let mut output = [ 0 u8 ; 20 ] ;
2018-08-13 23:27:13 +02:00
let FinalizationResult { gas_left : result , return_data , .. } = {
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params . clone ( ) , & mut Substate ::new ( ) , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2018-02-19 12:27:42 +01:00
} ;
2018-08-13 23:27:13 +02:00
( & mut output ) . copy_from_slice ( & return_data [ .. ( cmp ::min ( 20 , return_data . len ( ) ) ) ] ) ;
2018-02-19 12:27:42 +01:00
assert_eq! ( result , U256 ::from ( 18433 ) ) ;
// Transaction successfully returned sender
assert_eq! ( output [ .. ] , sender [ .. ] ) ;
// 1 < 10
info . number = 1 ;
let mut output = [ 0 u8 ; 20 ] ;
2018-08-13 23:27:13 +02:00
let FinalizationResult { gas_left : result , return_data , .. } = {
2018-07-23 15:48:01 +02:00
let schedule = machine . schedule ( info . number ) ;
let mut ex = Executive ::new ( & mut state , & info , & machine , & schedule ) ;
2018-08-13 23:27:13 +02:00
ex . call ( params , & mut Substate ::new ( ) , & mut NoopTracer , & mut NoopVMTracer ) . unwrap ( )
2018-02-19 12:27:42 +01:00
} ;
2018-08-13 23:27:13 +02:00
( & mut output [ .. ( ( cmp ::min ( 20 , return_data . len ( ) ) ) ) ] ) . copy_from_slice ( & return_data [ .. ( cmp ::min ( 20 , return_data . len ( ) ) ) ] ) ;
2018-02-19 12:27:42 +01:00
assert_eq! ( result , U256 ::from ( 20025 ) ) ;
// Since transaction errored due to wasm was not activated, result is just empty
assert_eq! ( output [ .. ] , [ 0 u8 ; 20 ] [ .. ] ) ;
}
2016-01-07 23:33:54 +01:00
}