backwards compatible call_type creation_method (#11450)
* rlp_derive: update syn & co
* rlp_derive: remove dummy_const
* rlp_derive: remove unused attirubutes
* rlp-derive: change authors
* rlp_derive: add rlp(default) attribute
* Revert "Revert "[Trace] Distinguish between `create` and `create2` (#11311)" (#11427)"
This reverts commit 5d4993b0f8
.
* trace: backwards compatible call_type and creation_method
* trace: add rlp backward compatibility tests
* cleanup
* i know, i hate backwards compatibility too
* address review grumbles
This commit is contained in:
parent
7108b3f048
commit
626543326d
@ -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),
|
||||
)
|
||||
},
|
||||
};
|
||||
|
@ -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<Bytes>,
|
||||
/// 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<ActionParams> 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<Cost: CostType> Interpreter<Cost> {
|
||||
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<Cost: CostType> Interpreter<Cost> {
|
||||
|
||||
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<Cost: CostType> Interpreter<Cost> {
|
||||
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))
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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(),
|
||||
|
@ -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),
|
||||
|
@ -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<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
call_type: CallType,
|
||||
call_type: ActionType,
|
||||
trap: bool,
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind> {
|
||||
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::<U256>().unwrap()),
|
||||
&[],
|
||||
&Address::zero(),
|
||||
CallType::Call,
|
||||
ActionType::Call,
|
||||
false,
|
||||
).ok().unwrap();
|
||||
}
|
||||
|
@ -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<ActionValue>,
|
||||
gas: U256,
|
||||
data: Option<Vec<u8>>,
|
||||
call_type: Option<CallType>,
|
||||
action_type: Option<ActionType>,
|
||||
) -> Result<Vec<u8>, 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);
|
||||
|
@ -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<T: Backend>(
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -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<U256>,
|
||||
data: &[u8],
|
||||
_code_address: &Address,
|
||||
_call_type: CallType,
|
||||
_call_type: ActionType,
|
||||
_trap: bool
|
||||
) -> Result<MessageCallResult, vm::TrapKind> {
|
||||
self.callcreates.push(CallCreate {
|
||||
|
@ -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);
|
||||
|
@ -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![],
|
||||
|
@ -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(),
|
||||
|
@ -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(),
|
||||
|
@ -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<ActionType> for CallType {
|
||||
type Error = &'static str;
|
||||
fn try_from(action_type: ActionType) -> Result<Self, Self::Error> {
|
||||
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<Self, DecoderError> {
|
||||
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<ActionType> for CreationMethod {
|
||||
type Error = &'static str;
|
||||
fn try_from(action_type: ActionType) -> Result<Self, Self::Error> {
|
||||
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<Self, DecoderError> {
|
||||
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<CallType>`, 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<CallType>);
|
||||
|
||||
impl From<Option<CallType>> for BackwardsCompatibleCallType {
|
||||
fn from(option: Option<CallType>) -> 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<CallType_v2_7_0>`.
|
||||
impl Decodable for BackwardsCompatibleCallType {
|
||||
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
||||
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<Self, DecoderError> {
|
||||
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<CallType_v2_7_0> 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<CallType_v2_7_0> = Decodable::decode(rlp)?;
|
||||
Ok(optional.map(Into::into).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ActionParams> 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<ActionParams> 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<CreationMethod>,
|
||||
}
|
||||
|
||||
impl From<ActionParams> for Create {
|
||||
@ -122,6 +303,7 @@ impl From<ActionParams> 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<VMTrace>,
|
||||
}
|
||||
|
||||
#[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));
|
||||
}
|
||||
}
|
||||
|
@ -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<Bytes>,
|
||||
/// 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<ethjson::vm::Transaction> 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,
|
||||
}
|
||||
}
|
||||
|
@ -14,47 +14,51 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! 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<Self, DecoderError> {
|
||||
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);
|
||||
}
|
||||
}
|
@ -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<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
call_type: CallType,
|
||||
call_type: ActionType,
|
||||
trap: bool
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind>;
|
||||
|
||||
|
@ -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};
|
||||
|
@ -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<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
_call_type: CallType,
|
||||
_call_type: ActionType,
|
||||
_trap: bool,
|
||||
) -> ::std::result::Result<MessageCallResult, TrapKind> {
|
||||
self.calls.insert(FakeCall {
|
||||
|
@ -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<RuntimeValue>
|
||||
@ -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<RuntimeValue> {
|
||||
self.do_call(true, CallType::Call, args)
|
||||
self.do_call(true, ActionType::Call, args)
|
||||
}
|
||||
|
||||
/// Delegate call
|
||||
fn dcall(&mut self, args: RuntimeArgs) -> Result<RuntimeValue> {
|
||||
self.do_call(false, CallType::DelegateCall, args)
|
||||
self.do_call(false, ActionType::DelegateCall, args)
|
||||
}
|
||||
|
||||
/// Static call
|
||||
fn scall(&mut self, args: RuntimeArgs) -> Result<RuntimeValue> {
|
||||
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<()>
|
||||
|
@ -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<T: Informant>(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;
|
||||
|
@ -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,
|
||||
|
@ -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<state_diff::StateDiff> 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<CreationMethod>,
|
||||
}
|
||||
|
||||
impl From<trace::Create> for Create {
|
||||
@ -232,6 +235,7 @@ impl From<trace::Create> 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<trace::Create> 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<vm::CallType> for CallType {
|
||||
fn from(c: vm::CallType) -> Self {
|
||||
impl From<trace::CallType> 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<trace::CreationMethod> 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<CallType>,
|
||||
}
|
||||
|
||||
impl From<trace::Call> for Call {
|
||||
fn from(c: trace::Call) -> Self {
|
||||
let optional: Option<trace::CallType> = 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]
|
||||
|
@ -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()?, }
|
||||
}
|
||||
|
@ -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 },
|
||||
|
@ -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);
|
||||
|
@ -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<Vec<u8>>,
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user