diff --git a/ethcore/engine/src/engine.rs b/ethcore/engine/src/engine.rs index 5159c1222..3fa13a074 100644 --- a/ethcore/engine/src/engine.rs +++ b/ethcore/engine/src/engine.rs @@ -42,7 +42,7 @@ use machine::{ Machine, executed_block::ExecutedBlock, }; -use vm::{EnvInfo, Schedule, CallType, ActionValue}; +use vm::{EnvInfo, Schedule, ActionType, ActionValue}; use crate::signer::EngineSigner; @@ -82,7 +82,7 @@ pub fn default_system_or_code_call<'a>(machine: &'a Machine, block: &'a mut Exec Some(ActionValue::Apparent(U256::zero())), U256::max_value(), Some(data), - Some(CallType::StaticCall), + Some(ActionType::StaticCall), ) }, }; diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index fded2ac7f..799566eeb 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -33,7 +33,7 @@ use ethereum_types::{U256, U512, H256, Address, BigEndianHash}; use vm::{ - self, ActionParams, ParamsType, ActionValue, CallType, MessageCallResult, + self, ActionParams, ParamsType, ActionValue, ActionType, MessageCallResult, ContractCreateResult, CreateContractAddress, ReturnData, GasLeft, Schedule, TrapKind, TrapError }; @@ -133,8 +133,8 @@ struct InterpreterParams { pub value: ActionValue, /// Input data. pub data: Option, - /// Type of call - pub call_type: CallType, + /// Type of action + pub action_type: ActionType, /// Param types encoding pub params_type: ParamsType, } @@ -152,7 +152,7 @@ impl From for InterpreterParams { gas_price: params.gas_price, value: params.value, data: params.data, - call_type: params.call_type, + action_type: params.action_type, params_type: params.params_type, } } @@ -532,7 +532,9 @@ impl Interpreter { let init_size = self.stack.pop_back(); let address_scheme = match instruction { instructions::CREATE => CreateContractAddress::FromSenderAndNonce, - instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash(BigEndianHash::from_uint(&self.stack.pop_back())), + instructions::CREATE2 => CreateContractAddress::FromSenderSaltAndCodeHash( + BigEndianHash::from_uint(&self.stack.pop_back()) + ), _ => unreachable!("instruction can only be CREATE/CREATE2 checked above; qed"), }; @@ -553,7 +555,14 @@ impl Interpreter { let contract_code = self.mem.read_slice(init_off, init_size); - let create_result = ext.create(&create_gas.as_u256(), &endowment, contract_code, &self.params.code_version, address_scheme, true); + let create_result = ext.create( + &create_gas.as_u256(), + &endowment, + contract_code, + &self.params.code_version, + address_scheme, + true, + ); return match create_result { Ok(ContractCreateResult::Created(address, gas_left)) => { self.stack.push(address_to_u256(address)); @@ -607,14 +616,14 @@ impl Interpreter { return Err(vm::Error::MutableCallInStaticContext); } let has_balance = ext.balance(&self.params.address)? >= value.expect("value set for all but delegate call; qed"); - (&self.params.address, &code_address, has_balance, CallType::Call) + (&self.params.address, &code_address, has_balance, ActionType::Call) }, instructions::CALLCODE => { let has_balance = ext.balance(&self.params.address)? >= value.expect("value set for all but delegate call; qed"); - (&self.params.address, &self.params.address, has_balance, CallType::CallCode) + (&self.params.address, &self.params.address, has_balance, ActionType::CallCode) }, - instructions::DELEGATECALL => (&self.params.sender, &self.params.address, true, CallType::DelegateCall), - instructions::STATICCALL => (&self.params.address, &code_address, true, CallType::StaticCall), + instructions::DELEGATECALL => (&self.params.sender, &self.params.address, true, ActionType::DelegateCall), + instructions::STATICCALL => (&self.params.address, &code_address, true, ActionType::StaticCall), _ => panic!(format!("Unexpected instruction {:?} in CALL branch.", instruction)) }; diff --git a/ethcore/evm/src/lib.rs b/ethcore/evm/src/lib.rs index 1dff2165c..2a1fd3949 100644 --- a/ethcore/evm/src/lib.rs +++ b/ethcore/evm/src/lib.rs @@ -47,7 +47,7 @@ mod instructions; mod tests; pub use vm::{ - Schedule, CleanDustMode, EnvInfo, CallType, ActionParams, Ext, + Schedule, CleanDustMode, EnvInfo, ActionType, ActionParams, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, GasLeft, ReturnData }; diff --git a/ethcore/executive-state/src/lib.rs b/ethcore/executive-state/src/lib.rs index 52a9fae2c..a2f979b10 100644 --- a/ethcore/executive-state/src/lib.rs +++ b/ethcore/executive-state/src/lib.rs @@ -276,7 +276,6 @@ mod tests { test_helpers::{get_temp_state, get_temp_state_db} }; use ethtrie; - use evm::CallType; use machine::Machine; use pod::{self, PodAccount, PodState}; use rustc_hex::FromHex; @@ -324,6 +323,7 @@ mod tests { value: 100.into(), gas: 77412.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], + creation_method: Some(trace::CreationMethod::Create), }), result: trace::Res::Create(trace::CreateResult { gas_used: U256::from(3224), @@ -381,6 +381,7 @@ mod tests { value: 100.into(), gas: 78792.into(), init: vec![91, 96, 0, 86], + creation_method: Some(trace::CreationMethod::Create), }), result: trace::Res::FailedCreate(TraceError::OutOfGas), subtraces: 0 @@ -419,7 +420,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3), @@ -460,7 +461,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(0), @@ -501,7 +502,7 @@ mod tests { value: 0.into(), gas: 79_000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3000), @@ -543,7 +544,7 @@ mod tests { value: 0.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3_721), // in post-eip150 @@ -587,7 +588,7 @@ mod tests { value: 0.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 724.into(), // in post-eip150 @@ -602,7 +603,7 @@ mod tests { value: 0.into(), gas: 4096.into(), input: vec![], - call_type: CallType::CallCode, + call_type: Some(trace::CallType::CallCode).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 3.into(), @@ -646,7 +647,7 @@ mod tests { value: 0.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(736), // in post-eip150 @@ -661,7 +662,7 @@ mod tests { value: 0.into(), gas: 32768.into(), input: vec![], - call_type: CallType::DelegateCall, + call_type: Some(trace::CallType::DelegateCall).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 18.into(), @@ -702,7 +703,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::FailedCall(TraceError::OutOfGas), subtraces: 0, @@ -744,7 +745,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(69), @@ -759,7 +760,7 @@ mod tests { value: 0.into(), gas: 78934.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3), @@ -801,7 +802,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(31761), @@ -816,7 +817,7 @@ mod tests { value: 69.into(), gas: 2300.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult::default()), }]; @@ -855,7 +856,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(31761), @@ -898,7 +899,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(79_000), @@ -913,7 +914,7 @@ mod tests { value: 0.into(), gas: 78934.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::FailedCall(TraceError::OutOfGas), }]; @@ -954,7 +955,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(135), @@ -969,7 +970,7 @@ mod tests { value: 0.into(), gas: 78934.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(69), @@ -984,7 +985,7 @@ mod tests { value: 0.into(), gas: 78868.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(3), @@ -1029,7 +1030,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(79_000), @@ -1044,7 +1045,7 @@ mod tests { value: 0.into(), gas: 78934.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::FailedCall(TraceError::OutOfGas), }, FlatTrace { @@ -1055,7 +1056,7 @@ mod tests { to: Address::from_low_u64_be(0xc), value: 0.into(), gas: 78868.into(), - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), input: vec![], }), result: trace::Res::Call(trace::CallResult { @@ -1099,7 +1100,7 @@ mod tests { value: 100.into(), gas: 79000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 3.into(), diff --git a/ethcore/machine/src/executive.rs b/ethcore/machine/src/executive.rs index f93231c0c..9307b0de1 100644 --- a/ethcore/machine/src/executive.rs +++ b/ethcore/machine/src/executive.rs @@ -26,7 +26,7 @@ use rlp::RlpStream; use log::trace; use account_state::{Backend as StateBackend, State, CleanupMode}; -use evm::{CallType, Finalize, FinalizationResult}; +use evm::{ActionType, Finalize, FinalizationResult}; use vm::{ self, EnvInfo, CreateContractAddress, ReturnData, CleanDustMode, ActionParams, ActionValue, Schedule, TrapError, ResumeCall, ResumeCreate @@ -241,7 +241,7 @@ impl<'a> CallCreateExecutive<'a> { 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; + let static_flag = parent_static_flag || params.action_type == ActionType::StaticCall; // if destination is builtin, try to execute it let kind = if let Some(builtin) = machine.builtin(¶ms.code_address, info.number) { @@ -298,7 +298,7 @@ impl<'a> CallCreateExecutive<'a> { } } else { if (static_flag && - (params.call_type == CallType::StaticCall || params.call_type == CallType::Call)) && + (params.action_type == ActionType::StaticCall || params.action_type == ActionType::Call)) && params.value.value() > U256::zero() { return Err(vm::Error::MutableCallInStaticContext); @@ -909,7 +909,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { code: Some(Arc::new(t.data.clone())), code_version: schedule.latest_version, data: None, - call_type: CallType::None, + action_type: ActionType::Create, params_type: vm::ParamsType::Embedded, }; let res = self.create(params, &mut substate, &mut tracer, &mut vm_tracer); @@ -932,7 +932,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { code_hash: self.state.code_hash(address)?, code_version: self.state.code_version(address)?, data: Some(t.data.clone()), - call_type: CallType::Call, + action_type: ActionType::Call, params_type: vm::ParamsType::Separate, }; let res = self.call(params, &mut substate, &mut tracer, &mut vm_tracer); @@ -1236,7 +1236,7 @@ mod tests { use parity_crypto::publickey::{Generator, Random}; use evm::{Factory, evm_test, evm_test_ignore}; use macros::vec_into; - use vm::{ActionParams, ActionValue, CallType, EnvInfo, CreateContractAddress}; + use vm::{ActionParams, ActionValue, EnvInfo, CreateContractAddress}; use ::trace::{ trace, FlatTrace, Tracer, NoopTracer, ExecutiveTracer, @@ -1414,7 +1414,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - params.call_type = CallType::Call; + params.action_type = ActionType::Call; let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); @@ -1434,7 +1434,7 @@ mod tests { value: 100.into(), gas: 100_000.into(), input: vec![], - call_type: CallType::Call + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 33021.into(), @@ -1449,7 +1449,7 @@ mod tests { value: 1.into(), gas: 66560.into(), input: vec![], - call_type: CallType::Call + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: 600.into(), 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] @@ -1498,7 +1498,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - params.call_type = CallType::Call; + params.action_type = ActionType::Call; let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); @@ -1524,7 +1524,7 @@ mod tests { value: 100.into(), gas: 100000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(55_248), @@ -1537,7 +1537,8 @@ mod tests { from: Address::from_str("b010143a42d5980c7e5ef0e4a4416dc098a4fed3").unwrap(), 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] + 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], + creation_method: Some(trace::CreationMethod::Create), }), result: trace::Res::Create(trace::CreateResult { gas_used: U256::from(3224), @@ -1614,7 +1615,7 @@ mod tests { params.gas = U256::from(100_000); params.code = Some(Arc::new(code)); params.value = ActionValue::Transfer(U256::from(100)); - params.call_type = CallType::Call; + params.action_type = ActionType::Call; let mut state = get_temp_state(); state.add_balance(&sender, &U256::from(100), CleanupMode::NoEmpty).unwrap(); let info = EnvInfo::default(); @@ -1640,7 +1641,7 @@ mod tests { value: 100.into(), gas: 100_000.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(trace::CallType::Call).into(), }), result: trace::Res::Call(trace::CallResult { gas_used: U256::from(37_033), @@ -1653,7 +1654,8 @@ mod tests { from: Address::from_str("b010143a42d5980c7e5ef0e4a4416dc098a4fed3").unwrap(), value: 23.into(), gas: 66_917.into(), - init: vec![0x60, 0x01, 0x60, 0x00, 0xfd] + init: vec![0x60, 0x01, 0x60, 0x00, 0xfd], + creation_method: Some(trace::CreationMethod::Create), }), result: trace::Res::FailedCreate(vm::Error::Reverted.into()), }]; @@ -1711,6 +1713,7 @@ mod tests { value: 100.into(), 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], + creation_method: Some(trace::CreationMethod::Create), }), result: trace::Res::Create(trace::CreateResult { gas_used: U256::from(3224), diff --git a/ethcore/machine/src/externalities.rs b/ethcore/machine/src/externalities.rs index 1b8d3ca0d..0808ebed2 100644 --- a/ethcore/machine/src/externalities.rs +++ b/ethcore/machine/src/externalities.rs @@ -29,7 +29,7 @@ use common_types::{ }; use trace::{Tracer, VMTracer}; use vm::{ - self, ActionParams, ActionValue, EnvInfo, CallType, Schedule, + self, ActionParams, ActionValue, EnvInfo, ActionType, Schedule, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, ReturnData, TrapKind }; @@ -193,7 +193,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> code_hash, code_version, data: Some(data.as_bytes().to_vec()), - call_type: CallType::Call, + action_type: ActionType::Call, params_type: vm::ParamsType::Separate, }; @@ -241,6 +241,12 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> } }; + let create_type = match address_scheme { + CreateContractAddress::FromSenderAndNonce => ActionType::Create, + CreateContractAddress::FromSenderSaltAndCodeHash(_) => ActionType::Create2, + CreateContractAddress::FromSenderAndCodeHash => ActionType::Create2, + }; + // prepare the params let params = ActionParams { code_address: address.clone(), @@ -254,7 +260,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> code_hash, code_version: *parent_version, data: None, - call_type: CallType::None, + action_type: create_type, params_type: vm::ParamsType::Embedded, }; @@ -285,7 +291,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> value: Option, data: &[u8], code_address: &Address, - call_type: CallType, + call_type: ActionType, trap: bool, ) -> ::std::result::Result { trace!(target: "externalities", "call"); @@ -311,7 +317,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> code_hash, code_version, data: Some(data.to_vec()), - call_type, + action_type: call_type, params_type: vm::ParamsType::Separate, }; @@ -457,7 +463,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for Externalities<'a, T, V, B> mod tests { use std::str::FromStr; use ethereum_types::{U256, Address}; - use evm::{EnvInfo, Ext, CallType}; + use evm::{EnvInfo, Ext, ActionType}; use account_state::State; use ethcore::test_helpers::get_temp_state; use trace::{NoopTracer, NoopVMTracer}; @@ -591,7 +597,7 @@ mod tests { Some("0000000000000000000000000000000000000000000000000000000000150000".parse::().unwrap()), &[], &Address::zero(), - CallType::Call, + ActionType::Call, false, ).ok().unwrap(); } diff --git a/ethcore/machine/src/machine.rs b/ethcore/machine/src/machine.rs index 0c9a8a45a..43151d0a0 100644 --- a/ethcore/machine/src/machine.rs +++ b/ethcore/machine/src/machine.rs @@ -34,7 +34,7 @@ use common_types::{ errors::{EngineError, EthcoreError as Error}, transaction::{self, SYSTEM_ADDRESS, UNSIGNED_SENDER, UnverifiedTransaction, SignedTransaction}, }; -use vm::{CallType, ActionParams, ActionValue, ParamsType}; +use vm::{ActionType, ActionParams, ActionValue, ParamsType}; use vm::{EnvInfo, Schedule}; use account_state::CleanupMode; @@ -141,7 +141,7 @@ impl Machine { value: Option, gas: U256, data: Option>, - call_type: Option, + action_type: Option, ) -> Result, Error> { let env_info = { let mut env_info = block.env_info(); @@ -163,7 +163,7 @@ impl Machine { code_hash, code_version: 0.into(), data, - call_type: call_type.unwrap_or(CallType::Call), + action_type: action_type.unwrap_or(ActionType::Call), params_type: ParamsType::Separate, }; let schedule = self.schedule(env_info.number); diff --git a/ethcore/spec/src/spec.rs b/ethcore/spec/src/spec.rs index e6337e0cf..1116fc626 100644 --- a/ethcore/spec/src/spec.rs +++ b/ethcore/spec/src/spec.rs @@ -52,7 +52,7 @@ use pod::PodState; use rlp::{Rlp, RlpStream}; use trace::{NoopTracer, NoopVMTracer}; use trie_vm_factories::Factories; -use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType}; +use vm::{EnvInfo, ActionType, ActionValue, ActionParams, ParamsType}; use crate::{ Genesis, @@ -163,7 +163,7 @@ fn run_constructors( value: ActionValue::Transfer(Default::default()), code: Some(Arc::new(constructor.clone())), data: None, - call_type: CallType::None, + action_type: ActionType::Create, params_type: ParamsType::Embedded, }; diff --git a/ethcore/src/json_tests/executive.rs b/ethcore/src/json_tests/executive.rs index 0a79be7cf..212197e90 100644 --- a/ethcore/src/json_tests/executive.rs +++ b/ethcore/src/json_tests/executive.rs @@ -20,7 +20,7 @@ use super::test_common::*; use account_state::{Backend as StateBackend, State}; use evm::Finalize; use vm::{ - self, ActionParams, CallType, Schedule, Ext, + self, ActionParams, ActionType, Schedule, Ext, ContractCreateResult, EnvInfo, MessageCallResult, CreateContractAddress, ReturnData, }; @@ -172,7 +172,7 @@ impl<'a, T: 'a, V: 'a, B: 'a> Ext for TestExt<'a, T, V, B> value: Option, data: &[u8], _code_address: &Address, - _call_type: CallType, + _call_type: ActionType, _trap: bool ) -> Result { self.callcreates.push(CallCreate { diff --git a/ethcore/src/tests/evm.rs b/ethcore/src/tests/evm.rs index 4b463cb48..f435502f8 100644 --- a/ethcore/src/tests/evm.rs +++ b/ethcore/src/tests/evm.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use hash::keccak; -use vm::{EnvInfo, ActionParams, ActionValue, CallType, ParamsType}; +use vm::{EnvInfo, ActionParams, ActionValue, ActionType, ParamsType}; use evm::Factory; use machine::{ executive::Executive, @@ -62,7 +62,7 @@ fn test_blockhash_eip210(factory: Factory) { code_hash: Some(blockhash_contract_code_hash), code_version: 0.into(), data: Some(H256::from_low_u64_be(i - 1).as_bytes().to_vec()), - call_type: CallType::Call, + action_type: ActionType::Call, params_type: ParamsType::Separate, }; let schedule = machine.schedule(env_info.number); @@ -86,7 +86,7 @@ fn test_blockhash_eip210(factory: Factory) { code_hash: Some(get_prev_hash_code_hash), code_version: 0.into(), data: None, - call_type: CallType::Call, + action_type: ActionType::Call, params_type: ParamsType::Separate, }; let schedule = machine.schedule(env_info.number); diff --git a/ethcore/trace/src/db.rs b/ethcore/trace/src/db.rs index 6fe27a5b2..4de60272c 100644 --- a/ethcore/trace/src/db.rs +++ b/ethcore/trace/src/db.rs @@ -374,13 +374,12 @@ mod tests { use ethcore::test_helpers::new_db; use ethereum_types::{H256, U256, Address}; - use evm::CallType; use kvdb::DBTransaction; use crate::{ BlockNumber, Config, TraceDB, Database as TraceDatabase, ImportRequest, DatabaseExtras, Filter, LocalizedTrace, AddressesFilter, TraceError, - trace::{Call, Action, Res}, + trace::{Call, CallType, Action, Res}, flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces} }; @@ -465,7 +464,7 @@ mod tests { value: 3.into(), gas: 4.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::FailedCall(TraceError::OutOfGas), }])]), @@ -487,7 +486,7 @@ mod tests { value: 3.into(), gas: 4.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::FailedCall(TraceError::OutOfGas), }])]), @@ -506,7 +505,7 @@ mod tests { value: U256::from(3), gas: U256::from(4), input: vec![], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::FailedCall(TraceError::OutOfGas), trace_address: vec![], diff --git a/ethcore/trace/src/types/filter.rs b/ethcore/trace/src/types/filter.rs index cb4b31269..b25e1de02 100644 --- a/ethcore/trace/src/types/filter.rs +++ b/ethcore/trace/src/types/filter.rs @@ -125,10 +125,9 @@ impl Filter { #[cfg(test)] mod tests { use ethereum_types::{Address, Bloom, BloomInput}; - use evm::CallType; use crate::{ Filter, AddressesFilter, TraceError, RewardType, - trace::{Action, Call, Res, Create, CreateResult, Suicide, Reward}, + trace::{Action, Call, CallType, Res, Create, CreationMethod, CreateResult, Suicide, Reward}, flat::FlatTrace, }; @@ -273,7 +272,7 @@ mod tests { value: 3.into(), gas: 4.into(), input: vec![0x5], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::FailedCall(TraceError::OutOfGas), trace_address: vec![0].into_iter().collect(), @@ -294,6 +293,7 @@ mod tests { value: 3.into(), gas: 4.into(), init: vec![0x5], + creation_method: Some(CreationMethod::Create), }), result: Res::Create(CreateResult { gas_used: 10.into(), @@ -413,6 +413,7 @@ mod tests { gas: 4.into(), init: vec![0x5], value: 3.into(), + creation_method: Some(CreationMethod::Create), }), result: Res::FailedCall(TraceError::BadInstruction), trace_address: vec![].into_iter().collect(), diff --git a/ethcore/trace/src/types/flat.rs b/ethcore/trace/src/types/flat.rs index 1f0d87ddf..2fad0c27f 100644 --- a/ethcore/trace/src/types/flat.rs +++ b/ethcore/trace/src/types/flat.rs @@ -123,9 +123,8 @@ mod tests { use rlp::*; use crate::{ FlatBlockTraces, FlatTransactionTraces, FlatTrace, - trace::{Action, Res, CallResult, Call, Suicide, Reward, RewardType} + trace::{Action, Res, CallResult, Call, CallType, Suicide, Reward, RewardType} }; - use evm::CallType; #[test] fn encode_flat_transaction_traces() { @@ -162,7 +161,7 @@ mod tests { value: "3627e8f712373c0000".parse().unwrap(), gas: 0x03e8.into(), input: vec![], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::Call(CallResult { gas_used: 0.into(), @@ -179,7 +178,7 @@ mod tests { value: 0.into(), gas: 0x010c78.into(), input: vec![0x41, 0xc0, 0xe1, 0xb5], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::Call(CallResult { gas_used: 0x0127.into(), diff --git a/ethcore/trace/src/types/trace.rs b/ethcore/trace/src/types/trace.rs index a3fb92dec..6fb1ed6e6 100644 --- a/ethcore/trace/src/types/trace.rs +++ b/ethcore/trace/src/types/trace.rs @@ -16,12 +16,19 @@ //! Tracing data types. +// ================== NOTE ======================== +// IF YOU'RE ADDING A FIELD TO A STRUCT WITH +// RLP ENCODING, MAKE SURE IT'S DONE IN A BACKWARDS +// COMPATIBLE WAY! +// ================== NOTE ======================== + +use std::convert::TryFrom; use ethereum_types::{U256, Address, Bloom, BloomInput}; use parity_bytes::Bytes; use rlp::{Rlp, RlpStream, Encodable, DecoderError, Decodable}; use rlp_derive::{RlpEncodable, RlpDecodable}; use vm::ActionParams; -use evm::CallType; +use evm::ActionType; use super::error::Error; /// `Call` result. @@ -33,6 +40,57 @@ pub struct CallResult { pub output: Bytes, } +/// `Call` type. Distinguish between different types of contract interactions. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum CallType { + /// Call + Call, + /// Call code + CallCode, + /// Delegate call + DelegateCall, + /// Static call + StaticCall, +} + +impl TryFrom for CallType { + type Error = &'static str; + fn try_from(action_type: ActionType) -> Result { + match action_type { + ActionType::Call => Ok(CallType::Call), + ActionType::CallCode => Ok(CallType::CallCode), + ActionType::DelegateCall => Ok(CallType::DelegateCall), + ActionType::StaticCall => Ok(CallType::StaticCall), + ActionType::Create => Err("Create cannot be converted to CallType"), + ActionType::Create2 => Err("Create2 cannot be converted to CallType"), + } + } +} + +impl Encodable for CallType { + fn rlp_append(&self, s: &mut RlpStream) { + let v = match *self { + CallType::Call => 0u32, + CallType::CallCode => 1, + CallType::DelegateCall => 2, + CallType::StaticCall => 3, + }; + Encodable::rlp_append(&v, s); + } +} + +impl Decodable for CallType { + fn decode(rlp: &Rlp) -> Result { + rlp.as_val().and_then(|v| Ok(match v { + 1u32 => CallType::Call, + 2 => CallType::CallCode, + 3 => CallType::DelegateCall, + 4 => CallType::StaticCall, + _ => return Err(DecoderError::Custom("Invalid value of CallType item")), + })) + } +} + /// `Create` result. #[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] pub struct CreateResult { @@ -51,6 +109,49 @@ impl CreateResult { } } +/// `Create` method. Distinguish between use of `CREATE` and `CREATE2` opcodes in an action. +#[derive(Debug, Clone, PartialEq)] +pub enum CreationMethod { + /// Create + Create, + /// Create2 + Create2, +} + +impl TryFrom for CreationMethod { + type Error = &'static str; + fn try_from(action_type: ActionType) -> Result { + match action_type { + ActionType::Call => Err("Call cannot be converted to CreationMethod"), + ActionType::CallCode => Err("CallCode cannot be converted to CreationMethod"), + ActionType::DelegateCall => Err("DelegateCall cannot be converted to CreationMethod"), + ActionType::StaticCall => Err("StaticCall cannot be converted to CreationMethod"), + ActionType::Create => Ok(CreationMethod::Create), + ActionType::Create2 => Ok(CreationMethod::Create2), + } + } +} + +impl Encodable for CreationMethod { + fn rlp_append(&self, s: &mut RlpStream) { + let v = match *self { + CreationMethod::Create => 0u32, + CreationMethod::Create2 => 1, + }; + Encodable::rlp_append(&v, s); + } +} + +impl Decodable for CreationMethod { + fn decode(rlp: &Rlp) -> Result { + rlp.as_val().and_then(|v| Ok(match v { + 0u32 => CreationMethod::Create, + 1 => CreationMethod::Create2, + _ => return Err(DecoderError::Custom("Invalid value of CreationMethod item")), + })) + } +} + /// Description of a _call_ action, either a `CALL` operation or a message transaction. #[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] pub struct Call { @@ -65,19 +166,96 @@ pub struct Call { /// The input data provided to the call. pub input: Bytes, /// The type of the call. - pub call_type: CallType, + pub call_type: BackwardsCompatibleCallType, +} + +/// This is essentially an `Option`, but with a custom +/// `rlp` en/de-coding which preserves backwards compatibility with +/// the older encodings used in parity-ethereum versions < 2.7 and 2.7.0. +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct BackwardsCompatibleCallType(pub Option); + +impl From> for BackwardsCompatibleCallType { + fn from(option: Option) -> Self { + BackwardsCompatibleCallType(option) + } +} + +// Encoding is the same as `CallType_v2_6_x`. +impl Encodable for BackwardsCompatibleCallType { + fn rlp_append(&self, s: &mut RlpStream) { + let v = match self.0 { + None => 0u32, + Some(CallType::Call) => 1, + Some(CallType::CallCode) => 2, + Some(CallType::DelegateCall) => 3, + Some(CallType::StaticCall) => 4, + }; + Encodable::rlp_append(&v, s); + } +} + +// Try to decode it as `CallType_v2_6_x` first, and then as `Option`. +impl Decodable for BackwardsCompatibleCallType { + fn decode(rlp: &Rlp) -> Result { + if rlp.is_data() { + rlp.as_val().and_then(|v| Ok(match v { + 0u32 => None, + 1 => Some(CallType::Call), + 2 => Some(CallType::CallCode), + 3 => Some(CallType::DelegateCall), + 4 => Some(CallType::StaticCall), + _ => return Err(DecoderError::Custom("Invalid value of CallType item")), + }.into())) + } else { + #[allow(non_camel_case_types)] + #[derive(Debug, Clone, Copy, PartialEq)] + enum CallType_v2_7_0 { + Call, + CallCode, + DelegateCall, + StaticCall, + } + + impl Decodable for CallType_v2_7_0 { + fn decode(rlp: &Rlp) -> Result { + rlp.as_val().and_then(|v| Ok(match v { + 0u32 => CallType_v2_7_0::Call, + 1 => CallType_v2_7_0::CallCode, + 2 => CallType_v2_7_0::DelegateCall, + 3 => CallType_v2_7_0::StaticCall, + _ => return Err(DecoderError::Custom("Invalid value of CallType item")), + })) + } + } + + impl From for CallType { + fn from(old_call_type: CallType_v2_7_0) -> Self { + match old_call_type { + CallType_v2_7_0::Call => Self::Call, + CallType_v2_7_0::CallCode => Self::CallCode, + CallType_v2_7_0::DelegateCall => Self::DelegateCall, + CallType_v2_7_0::StaticCall => Self::StaticCall, + } + } + } + + let optional: Option = Decodable::decode(rlp)?; + Ok(optional.map(Into::into).into()) + } + } } impl From for Call { fn from(p: ActionParams) -> Self { - match p.call_type { - CallType::DelegateCall | CallType::CallCode => Call { + match p.action_type { + ActionType::DelegateCall | ActionType::CallCode => Call { from: p.address, to: p.code_address, value: p.value.value(), gas: p.gas, input: p.data.unwrap_or_else(Vec::new), - call_type: p.call_type, + call_type: CallType::try_from(p.action_type).ok().into(), }, _ => Call { from: p.sender, @@ -85,7 +263,7 @@ impl From for Call { value: p.value.value(), gas: p.gas, input: p.data.unwrap_or_else(Vec::new), - call_type: p.call_type, + call_type: CallType::try_from(p.action_type).ok().into(), }, } } @@ -113,6 +291,9 @@ pub struct Create { pub gas: U256, /// The init code. pub init: Bytes, + /// Creation method (CREATE vs CREATE2). + #[rlp(default)] + pub creation_method: Option, } impl From for Create { @@ -122,6 +303,7 @@ impl From for Create { value: p.value.value(), gas: p.gas, init: p.code.map_or_else(Vec::new, |c| (*c).clone()), + creation_method: CreationMethod::try_from(p.action_type).ok().into(), } } } @@ -429,3 +611,132 @@ pub struct VMTrace { /// Thre is a 1:1 correspondance between these and a CALL/CREATE/CALLCODE/DELEGATECALL instruction. pub subs: Vec, } + +#[cfg(test)] +mod tests { + use rlp::{RlpStream, Encodable}; + use rlp_derive::{RlpEncodable, RlpDecodable}; + use super::{Address, Bytes, Call, CallType, Create, CreationMethod, U256}; + + #[test] + fn test_call_type_backwards_compatibility() { + // Call type in version < 2.7. + #[derive(Debug, Clone, PartialEq, RlpEncodable)] + struct OldCall { + from: Address, + to: Address, + value: U256, + gas: U256, + input: Bytes, + call_type: OldCallType, + } + + // CallType type in version < 2.7. + #[allow(dead_code)] + #[derive(Debug, PartialEq, Clone)] + enum OldCallType { + None, + Call, + CallCode, + DelegateCall, + StaticCall, + } + + // CallType rlp encoding in version < 2.7. + impl Encodable for OldCallType { + fn rlp_append(&self, s: &mut RlpStream) { + let v = match *self { + OldCallType::None => 0u32, + OldCallType::Call => 1, + OldCallType::CallCode => 2, + OldCallType::DelegateCall => 3, + OldCallType::StaticCall => 4, + }; + Encodable::rlp_append(&v, s); + } + } + + let old_call = OldCall { + from: Address::from_low_u64_be(1), + to: Address::from_low_u64_be(2), + value: U256::from(3), + gas: U256::from(4), + input: vec![5], + call_type: OldCallType::DelegateCall, + }; + + let old_encoded = rlp::encode(&old_call); + + let new_call = Call { + from: Address::from_low_u64_be(1), + to: Address::from_low_u64_be(2), + value: U256::from(3), + gas: U256::from(4), + input: vec![5], + call_type: Some(CallType::DelegateCall).into(), + }; + + // `old_call` should be deserialized successfully into `new_call` + assert_eq!(rlp::decode(&old_encoded), Ok(new_call.clone())); + // test a roundtrip with `Some` `call_type` + let new_encoded = rlp::encode(&new_call); + assert_eq!(rlp::decode(&new_encoded), Ok(new_call)); + + // test a roundtrip with `None` `call_type` + let none_call = Call { + from: Address::from_low_u64_be(1), + to: Address::from_low_u64_be(2), + value: U256::from(3), + gas: U256::from(4), + input: vec![5], + call_type: None.into(), + }; + let none_encoded = rlp::encode(&none_call); + assert_eq!(rlp::decode(&none_encoded), Ok(none_call)); + } + + #[test] + fn test_creation_method_backwards_compatibility() { + // Create type in version < 2.7. + #[derive(Debug, Clone, PartialEq, RlpEncodable, RlpDecodable)] + struct OldCreate { + from: Address, + value: U256, + gas: U256, + init: Bytes, + } + + let old_create = OldCreate { + from: Address::from_low_u64_be(1), + value: U256::from(3), + gas: U256::from(4), + init: vec![5], + }; + + let old_encoded = rlp::encode(&old_create); + let new_create = Create { + from: Address::from_low_u64_be(1), + value: U256::from(3), + gas: U256::from(4), + init: vec![5], + creation_method: None, + }; + + // `old_create` should be deserialized successfully into `new_create` + assert_eq!(rlp::decode(&old_encoded), Ok(new_create.clone())); + // test a roundtrip with `None` `creation_method` + let new_encoded = rlp::encode(&new_create); + assert_eq!(rlp::decode(&new_encoded), Ok(new_create)); + + // test a roundtrip with `Some` `creation_method` + let some_create = Create { + from: Address::from_low_u64_be(1), + value: U256::from(3), + gas: U256::from(4), + init: vec![5], + creation_method: Some(CreationMethod::Create2), + }; + let some_encoded = rlp::encode(&some_create); + assert_eq!(rlp::decode(&some_encoded), Ok(some_create)); + } +} diff --git a/ethcore/vm/src/action_params.rs b/ethcore/vm/src/action_params.rs index e98e214cd..da06fb3f3 100644 --- a/ethcore/vm/src/action_params.rs +++ b/ethcore/vm/src/action_params.rs @@ -20,7 +20,7 @@ use bytes::Bytes; use hash::{keccak, KECCAK_EMPTY}; use ethjson; -use call_type::CallType; +use action_type::ActionType; use std::sync::Arc; @@ -88,8 +88,8 @@ pub struct ActionParams { pub code_version: U256, /// Input data. pub data: Option, - /// Type of call - pub call_type: CallType, + /// Type of action (e.g. CALL, DELEGATECALL, CREATE, etc.) + pub action_type: ActionType, /// Param types encoding pub params_type: ParamsType, } @@ -109,7 +109,7 @@ impl Default for ActionParams { code: None, code_version: U256::zero(), data: None, - call_type: CallType::None, + action_type: ActionType::Create, params_type: ParamsType::Separate, } } @@ -130,7 +130,7 @@ impl From for ActionParams { gas: t.gas.into(), gas_price: t.gas_price.into(), value: ActionValue::Transfer(t.value.into()), - call_type: match address.is_zero() { true => CallType::None, false => CallType::Call }, // TODO @debris is this correct? + action_type: ActionType::Call, params_type: ParamsType::Separate, } } diff --git a/ethcore/vm/src/call_type.rs b/ethcore/vm/src/action_type.rs similarity index 66% rename from ethcore/vm/src/call_type.rs rename to ethcore/vm/src/action_type.rs index 1bb06d86c..2696ba598 100644 --- a/ethcore/vm/src/call_type.rs +++ b/ethcore/vm/src/action_type.rs @@ -14,47 +14,51 @@ // You should have received a copy of the GNU General Public License // along with Parity Ethereum. If not, see . -//! EVM call types. +//! EVM action types. use rlp::{Encodable, Decodable, DecoderError, RlpStream, Rlp}; -/// The type of the call-like instruction. +/// The type of the instruction. #[derive(Debug, PartialEq, Clone)] -pub enum CallType { - /// Not a CALL. - None, +pub enum ActionType { + /// CREATE. + Create, /// CALL. Call, /// CALLCODE. CallCode, /// DELEGATECALL. DelegateCall, - /// STATICCALL + /// STATICCALL. StaticCall, + /// CREATE2. + Create2 } -impl Encodable for CallType { +impl Encodable for ActionType { fn rlp_append(&self, s: &mut RlpStream) { let v = match *self { - CallType::None => 0u32, - CallType::Call => 1, - CallType::CallCode => 2, - CallType::DelegateCall => 3, - CallType::StaticCall => 4, + ActionType::Create => 0u32, + ActionType::Call => 1, + ActionType::CallCode => 2, + ActionType::DelegateCall => 3, + ActionType::StaticCall => 4, + ActionType::Create2 => 5, }; Encodable::rlp_append(&v, s); } } -impl Decodable for CallType { +impl Decodable for ActionType { fn decode(rlp: &Rlp) -> Result { rlp.as_val().and_then(|v| Ok(match v { - 0u32 => CallType::None, - 1 => CallType::Call, - 2 => CallType::CallCode, - 3 => CallType::DelegateCall, - 4 => CallType::StaticCall, - _ => return Err(DecoderError::Custom("Invalid value of CallType item")), + 0u32 => ActionType::Create, + 1 => ActionType::Call, + 2 => ActionType::CallCode, + 3 => ActionType::DelegateCall, + 4 => ActionType::StaticCall, + 5 => ActionType::Create2, + _ => return Err(DecoderError::Custom("Invalid value of ActionType item")), })) } } @@ -62,11 +66,11 @@ impl Decodable for CallType { #[cfg(test)] mod tests { use rlp::*; - use super::CallType; + use super::ActionType; #[test] fn encode_call_type() { - let ct = CallType::Call; + let ct = ActionType::Call; let mut s = RlpStream::new_list(2); s.append(&ct); @@ -78,9 +82,9 @@ mod tests { #[test] fn should_encode_and_decode_call_type() { - let original = CallType::Call; + let original = ActionType::Call; let encoded = encode(&original); - let decoded = decode(&encoded).expect("failure decoding CallType"); + let decoded = decode(&encoded).expect("failure decoding ActionType"); assert_eq!(original, decoded); } } diff --git a/ethcore/vm/src/ext.rs b/ethcore/vm/src/ext.rs index 0349e3dfa..656831cdc 100644 --- a/ethcore/vm/src/ext.rs +++ b/ethcore/vm/src/ext.rs @@ -19,7 +19,7 @@ use std::sync::Arc; use ethereum_types::{U256, H256, Address}; use bytes::Bytes; -use call_type::CallType; +use action_type::ActionType; use env_info::EnvInfo; use schedule::Schedule; use return_data::ReturnData; @@ -115,7 +115,7 @@ pub trait Ext { value: Option, data: &[u8], code_address: &Address, - call_type: CallType, + call_type: ActionType, trap: bool ) -> ::std::result::Result; diff --git a/ethcore/vm/src/lib.rs b/ethcore/vm/src/lib.rs index 1576dda04..6c5ed98fd 100644 --- a/ethcore/vm/src/lib.rs +++ b/ethcore/vm/src/lib.rs @@ -24,7 +24,7 @@ extern crate keccak_hash as hash; extern crate patricia_trie_ethereum as ethtrie; mod action_params; -mod call_type; +mod action_type; mod env_info; mod schedule; mod ext; @@ -34,7 +34,7 @@ mod error; pub mod tests; pub use action_params::{ActionParams, ActionValue, ParamsType}; -pub use call_type::CallType; +pub use action_type::ActionType; pub use env_info::{EnvInfo, LastHashes}; pub use schedule::{Schedule, VersionedSchedule, CleanDustMode, WasmCosts}; pub use ext::{Ext, MessageCallResult, ContractCreateResult, CreateContractAddress}; diff --git a/ethcore/vm/src/tests.rs b/ethcore/vm/src/tests.rs index d03350409..bdca9bbf3 100644 --- a/ethcore/vm/src/tests.rs +++ b/ethcore/vm/src/tests.rs @@ -20,7 +20,7 @@ use std::collections::{HashMap, HashSet}; use ethereum_types::{U256, H256, Address}; use bytes::Bytes; use { - CallType, Schedule, EnvInfo, + ActionType, Schedule, EnvInfo, ReturnData, Ext, ContractCreateResult, MessageCallResult, CreateContractAddress, Result, GasLeft, }; @@ -185,7 +185,7 @@ impl Ext for FakeExt { value: Option, data: &[u8], code_address: &Address, - _call_type: CallType, + _call_type: ActionType, _trap: bool, ) -> ::std::result::Result { self.calls.insert(FakeCall { diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index 972870bfd..3350e15bd 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -16,7 +16,7 @@ use std::cmp; use ethereum_types::{BigEndianHash, U256, H256, Address}; -use vm::{self, CallType}; +use vm::{self, ActionType}; use wasmi::{self, MemoryRef, RuntimeArgs, RuntimeValue, Error as InterpreterError, Trap, TrapKind}; use super::panic_payload; @@ -384,7 +384,7 @@ impl<'a> Runtime<'a> { fn do_call( &mut self, use_val: bool, - call_type: CallType, + call_type: ActionType, args: RuntimeArgs, ) -> Result @@ -445,8 +445,8 @@ impl<'a> Runtime<'a> { let call_result = self.ext.call( &gas.into(), - match call_type { CallType::DelegateCall => &self.context.sender, _ => &self.context.address }, - match call_type { CallType::Call | CallType::StaticCall => &address, _ => &self.context.address }, + match call_type { ActionType::DelegateCall => &self.context.sender, _ => &self.context.address }, + match call_type { ActionType::Call | ActionType::StaticCall => &address, _ => &self.context.address }, val, &payload, &address, @@ -487,17 +487,17 @@ impl<'a> Runtime<'a> { /// Message call fn ccall(&mut self, args: RuntimeArgs) -> Result { - self.do_call(true, CallType::Call, args) + self.do_call(true, ActionType::Call, args) } /// Delegate call fn dcall(&mut self, args: RuntimeArgs) -> Result { - self.do_call(false, CallType::DelegateCall, args) + self.do_call(false, ActionType::DelegateCall, args) } /// Static call fn scall(&mut self, args: RuntimeArgs) -> Result { - self.do_call(false, CallType::StaticCall, args) + self.do_call(false, ActionType::StaticCall, args) } fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<()> diff --git a/evmbin/src/main.rs b/evmbin/src/main.rs index 4edee5f0f..4e6f637d4 100644 --- a/evmbin/src/main.rs +++ b/evmbin/src/main.rs @@ -45,7 +45,7 @@ use ethereum_types::{U256, Address}; use ethcore::{json_tests, test_helpers::TrieSpec}; use spec; use serde::Deserialize; -use vm::{ActionParams, CallType}; +use vm::{ActionParams, ActionType}; mod info; mod display; @@ -314,7 +314,7 @@ fn run_call(args: Args, informant: T) { } let mut params = ActionParams::default(); - params.call_type = if code.is_none() { CallType::Call } else { CallType::None }; + params.action_type = if code.is_none() { ActionType::Call } else { ActionType::Create }; params.code = code.map(Arc::new); params.code_address = to; params.address = to; diff --git a/rpc/src/v1/tests/mocked/traces.rs b/rpc/src/v1/tests/mocked/traces.rs index aee34a49f..0ae9e6195 100644 --- a/rpc/src/v1/tests/mocked/traces.rs +++ b/rpc/src/v1/tests/mocked/traces.rs @@ -23,7 +23,7 @@ use ethcore::test_helpers::TestBlockChainClient; use ethereum_types::{Address, H256}; use types::transaction::CallError; -use vm::CallType; +use trace::trace::CallType; use jsonrpc_core::IoHandler; use v1::tests::helpers::{TestMinerService}; @@ -44,7 +44,7 @@ fn io() -> Tester { value: 0x1.into(), gas: 0x100.into(), input: vec![1, 2, 3], - call_type: CallType::Call, + call_type: Some(CallType::Call).into(), }), result: Res::None, subtraces: 0, diff --git a/rpc/src/v1/types/trace.rs b/rpc/src/v1/types/trace.rs index e858d7b17..b59a07b6e 100644 --- a/rpc/src/v1/types/trace.rs +++ b/rpc/src/v1/types/trace.rs @@ -24,7 +24,6 @@ use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; use types::account_diff; use types::state_diff; -use vm; use v1::types::Bytes; @@ -214,6 +213,7 @@ impl From for StateDiff { /// Create response #[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] pub struct Create { /// Sender from: H160, @@ -223,6 +223,9 @@ pub struct Create { gas: U256, /// Initialization code init: Bytes, + // Create Type + #[serde(skip_serializing_if="Option::is_none")] + creation_method: Option, } impl From for Create { @@ -232,6 +235,7 @@ impl From for Create { value: c.value, gas: c.gas, init: Bytes::new(c.init), + creation_method: c.creation_method.map(|c| c.into()), } } } @@ -240,8 +244,6 @@ impl From for Create { #[derive(Debug, Serialize)] #[serde(rename_all = "lowercase")] pub enum CallType { - /// None - None, /// Call Call, /// Call code @@ -252,14 +254,32 @@ pub enum CallType { StaticCall, } -impl From for CallType { - fn from(c: vm::CallType) -> Self { +impl From for CallType { + fn from(c: trace::CallType) -> Self { match c { - vm::CallType::None => CallType::None, - vm::CallType::Call => CallType::Call, - vm::CallType::CallCode => CallType::CallCode, - vm::CallType::DelegateCall => CallType::DelegateCall, - vm::CallType::StaticCall => CallType::StaticCall, + trace::CallType::Call => CallType::Call, + trace::CallType::CallCode => CallType::CallCode, + trace::CallType::DelegateCall => CallType::DelegateCall, + trace::CallType::StaticCall => CallType::StaticCall, + } + } +} + +/// Create type. +#[derive(Debug, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum CreationMethod { + /// Create + Create, + /// Create2 + Create2, +} + +impl From for CreationMethod { + fn from(c: trace::CreationMethod) -> Self { + match c { + trace::CreationMethod::Create => CreationMethod::Create, + trace::CreationMethod::Create2 => CreationMethod::Create2, } } } @@ -279,18 +299,19 @@ pub struct Call { /// Input data input: Bytes, /// The type of the call. - call_type: CallType, + call_type: Option, } impl From for Call { fn from(c: trace::Call) -> Self { + let optional: Option = c.call_type.0; Call { from: c.from, to: c.to, value: c.value, gas: c.gas, input: c.input.into(), - call_type: c.call_type.into(), + call_type: optional.map(|c| c.into()), } } } @@ -681,7 +702,7 @@ mod tests { value: 6.into(), gas: 7.into(), input: Bytes::new(vec![0x12, 0x34]), - call_type: CallType::Call, + call_type: Some(CallType::Call), }), result: Res::Call(CallResult { gas_used: 8.into(), @@ -707,7 +728,7 @@ mod tests { value: 6.into(), gas: 7.into(), input: Bytes::new(vec![0x12, 0x34]), - call_type: CallType::Call, + call_type: Some(CallType::Call), }), result: Res::FailedCall(TraceError::OutOfGas), trace_address: vec![10], @@ -729,6 +750,7 @@ mod tests { value: 6.into(), gas: 7.into(), init: Bytes::new(vec![0x12, 0x34]), + creation_method: Some(CreationMethod::Create).into(), }), result: Res::Create(CreateResult { gas_used: 8.into(), @@ -743,7 +765,7 @@ mod tests { block_hash: H256::from_low_u64_be(14), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"result":{"gasUsed":"0x8","code":"0x5678","address":"0x00000000000000000000000000000000000000ff"},"traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234","creationMethod":"create"},"result":{"gasUsed":"0x8","code":"0x5678","address":"0x00000000000000000000000000000000000000ff"},"traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] @@ -754,6 +776,7 @@ mod tests { value: 6.into(), gas: 7.into(), init: Bytes::new(vec![0x12, 0x34]), + creation_method: Some(CreationMethod::Create).into(), }), result: Res::FailedCreate(TraceError::OutOfGas), trace_address: vec![10], @@ -764,7 +787,7 @@ mod tests { block_hash: H256::from_low_u64_be(14), }; let serialized = serde_json::to_string(&t).unwrap(); - assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"error":"Out of gas","traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); + assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234","creationMethod":"create"},"error":"Out of gas","traceAddress":[10],"subtraces":1,"transactionPosition":11,"transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":13,"blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#); } #[test] diff --git a/util/rlp-derive/src/de.rs b/util/rlp-derive/src/de.rs index b35ece3f9..3ae4b3aff 100644 --- a/util/rlp-derive/src/de.rs +++ b/util/rlp-derive/src/de.rs @@ -45,12 +45,17 @@ pub fn impl_decodable(ast: &syn::DeriveInput) -> TokenStream { _ => panic!("#[derive(RlpDecodable)] is only defined for structs."), }; + let mut default_attribute_encountered = false; let stmts: Vec<_> = body .fields .iter() .enumerate() - .map(decodable_field_map) - .collect(); + .map(|(i, field)| decodable_field( + i, + field, + decodable_parse_quotes(), + &mut default_attribute_encountered, + )).collect(); let name = &ast.ident; let impl_block = quote! { @@ -83,7 +88,13 @@ pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> TokenStream { let fields: Vec<_> = body.fields.iter().collect(); if fields.len() == 1 { let field = fields.first().expect("fields.len() == 1; qed"); - decodable_field(0, field, decodable_wrapper_parse_quotes()) + let mut default_attribute_encountered = false; + decodable_field( + 0, + field, + decodable_wrapper_parse_quotes(), + &mut default_attribute_encountered, + ) } else { panic!("#[derive(RlpEncodableWrapper)] is only defined for structs with one field.") } @@ -111,11 +122,12 @@ pub fn impl_decodable_wrapper(ast: &syn::DeriveInput) -> TokenStream { } } -fn decodable_field_map(tuple: (usize, &syn::Field)) -> TokenStream { - decodable_field(tuple.0, tuple.1, decodable_parse_quotes()) -} - -fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> TokenStream { +fn decodable_field( + index: usize, + field: &syn::Field, + quotes: ParseQuotes, + default_attribute_encountered: &mut bool, +) -> TokenStream { let id = match field.ident { Some(ref ident) => quote! { #ident }, None => { @@ -124,11 +136,27 @@ fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> Tok } }; + let index = index - *default_attribute_encountered as usize; let index = quote! { #index }; let single = quotes.single; let list = quotes.list; + let attributes = &field.attrs; + let default = if let Some(attr) = attributes.iter().find(|attr| attr.path.is_ident("rlp")) { + if *default_attribute_encountered { + panic!("only 1 #[rlp(default)] attribute is allowed in a struct") + } + match attr.parse_args() { + Ok(proc_macro2::TokenTree::Ident(ident)) if ident.to_string() == "default" => {}, + _ => panic!("only #[rlp(default)] attribute is supported"), + } + *default_attribute_encountered = true; + true + } else { + false + }; + match field.ty { syn::Type::Path(ref path) => { let ident = &path @@ -137,15 +165,24 @@ fn decodable_field(index: usize, field: &syn::Field, quotes: ParseQuotes) -> Tok .first() .expect("there must be at least 1 segment") .ident; - if &ident.to_string() == "Vec" { + let ident_type = ident.to_string(); + if &ident_type == "Vec" { if quotes.takes_index { - quote! { #id: #list(#index)?, } + if default { + quote! { #id: #list(#index).unwrap_or_default(), } + } else { + quote! { #id: #list(#index)?, } + } } else { quote! { #id: #list()?, } } } else { if quotes.takes_index { - quote! { #id: #single(#index)?, } + if default { + quote! { #id: #single(#index).unwrap_or_default(), } + } else { + quote! { #id: #single(#index)?, } + } } else { quote! { #id: #single()?, } } diff --git a/util/rlp-derive/src/en.rs b/util/rlp-derive/src/en.rs index 6bb22f8dc..32905456a 100644 --- a/util/rlp-derive/src/en.rs +++ b/util/rlp-derive/src/en.rs @@ -27,7 +27,7 @@ pub fn impl_encodable(ast: &syn::DeriveInput) -> TokenStream { .fields .iter() .enumerate() - .map(encodable_field_map) + .map(|(i, field)| encodable_field(i, field)) .collect(); let name = &ast.ident; @@ -84,10 +84,6 @@ pub fn impl_encodable_wrapper(ast: &syn::DeriveInput) -> TokenStream { } } -fn encodable_field_map(tuple: (usize, &syn::Field)) -> TokenStream { - encodable_field(tuple.0, tuple.1) -} - fn encodable_field(index: usize, field: &syn::Field) -> TokenStream { let ident = match field.ident { Some(ref ident) => quote! { #ident }, diff --git a/util/rlp-derive/src/lib.rs b/util/rlp-derive/src/lib.rs index 09d29d250..3c9799e2a 100644 --- a/util/rlp-derive/src/lib.rs +++ b/util/rlp-derive/src/lib.rs @@ -23,7 +23,7 @@ use de::{impl_decodable, impl_decodable_wrapper}; use en::{impl_encodable, impl_encodable_wrapper}; use proc_macro::TokenStream; -#[proc_macro_derive(RlpEncodable)] +#[proc_macro_derive(RlpEncodable, attributes(rlp))] pub fn encodable(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); let gen = impl_encodable(&ast); @@ -37,7 +37,7 @@ pub fn encodable_wrapper(input: TokenStream) -> TokenStream { gen.into() } -#[proc_macro_derive(RlpDecodable)] +#[proc_macro_derive(RlpDecodable, attributes(rlp))] pub fn decodable(input: TokenStream) -> TokenStream { let ast = syn::parse(input).unwrap(); let gen = impl_decodable(&ast); diff --git a/util/rlp-derive/tests/rlp.rs b/util/rlp-derive/tests/rlp.rs index f3889ed18..adf737667 100644 --- a/util/rlp-derive/tests/rlp.rs +++ b/util/rlp-derive/tests/rlp.rs @@ -50,3 +50,30 @@ fn test_encode_foo_wrapper() { let decoded = decode(&expected).expect("decode failure"); assert_eq!(foo, decoded); } + +#[test] +fn test_encode_foo_default() { + #[derive(Debug, PartialEq, RlpEncodable, RlpDecodable)] + struct FooDefault { + a: String, + /// It works with other attributes. + #[rlp(default)] + b: Option>, + } + + let attack_of = String::from("clones"); + let foo = Foo { a: attack_of.clone() }; + + let expected = vec![0xc7, 0x86, b'c', b'l', b'o', b'n', b'e', b's']; + let out = encode(&foo); + assert_eq!(out, expected); + + let foo_default = FooDefault { a: attack_of.clone(), b: None }; + + let decoded = decode(&expected).expect("default failure"); + assert_eq!(foo_default, decoded); + + let foo_some = FooDefault { a: attack_of.clone(), b: Some(vec![1, 2, 3]) }; + let out = encode(&foo_some); + assert_eq!(decode(&out), Ok(foo_some)); +}