Trace other types of calls (#1727)
* Trace through DELEGATECALL and CALLCODE Add them to the JSON output and RLP database store. * Fix tests. * Fix all tests. * Fix one more test.
This commit is contained in:
parent
edda0b2380
commit
ccb62d3b55
@ -17,6 +17,7 @@
|
||||
//! Evm input params.
|
||||
use common::*;
|
||||
use ethjson;
|
||||
use types::executed::CallType;
|
||||
|
||||
/// Transaction value
|
||||
#[derive(Clone, Debug)]
|
||||
@ -58,7 +59,10 @@ pub struct ActionParams {
|
||||
/// Code being executed.
|
||||
pub code: Option<Bytes>,
|
||||
/// Input data.
|
||||
pub data: Option<Bytes>
|
||||
pub data: Option<Bytes>,
|
||||
/// Type of call
|
||||
pub call_type: CallType,
|
||||
|
||||
}
|
||||
|
||||
impl Default for ActionParams {
|
||||
@ -73,16 +77,18 @@ impl Default for ActionParams {
|
||||
gas_price: U256::zero(),
|
||||
value: ActionValue::Transfer(U256::zero()),
|
||||
code: None,
|
||||
data: None
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ethjson::vm::Transaction> for ActionParams {
|
||||
fn from(t: ethjson::vm::Transaction) -> Self {
|
||||
let address: Address = t.address.into();
|
||||
ActionParams {
|
||||
code_address: Address::new(),
|
||||
address: t.address.into(),
|
||||
address: address,
|
||||
sender: t.sender.into(),
|
||||
origin: t.origin.into(),
|
||||
code: Some(t.code.into()),
|
||||
@ -90,6 +96,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?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
use util::common::*;
|
||||
use evm::{self, Schedule};
|
||||
use types::executed::CallType;
|
||||
use env_info::*;
|
||||
|
||||
/// Result of externalities create function.
|
||||
@ -75,7 +76,9 @@ pub trait Ext {
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
output: &mut [u8]) -> MessageCallResult;
|
||||
output: &mut [u8],
|
||||
call_type: CallType
|
||||
) -> MessageCallResult;
|
||||
|
||||
/// Returns code at given address
|
||||
fn extcode(&self, address: &Address) -> Bytes;
|
||||
|
@ -38,6 +38,7 @@ use self::memory::Memory;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use common::*;
|
||||
use types::executed::CallType;
|
||||
use super::instructions::{self, Instruction, InstructionInfo};
|
||||
use evm::{self, MessageCallResult, ContractCreateResult, GasLeft, CostType};
|
||||
|
||||
@ -311,16 +312,16 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
});
|
||||
|
||||
// Get sender & receive addresses, check if we have balance
|
||||
let (sender_address, receive_address, has_balance) = match instruction {
|
||||
let (sender_address, receive_address, has_balance, call_type) = match instruction {
|
||||
instructions::CALL => {
|
||||
let has_balance = ext.balance(¶ms.address) >= value.unwrap();
|
||||
(¶ms.address, &code_address, has_balance)
|
||||
(¶ms.address, &code_address, has_balance, CallType::Call)
|
||||
},
|
||||
instructions::CALLCODE => {
|
||||
let has_balance = ext.balance(¶ms.address) >= value.unwrap();
|
||||
(¶ms.address, ¶ms.address, has_balance)
|
||||
(¶ms.address, ¶ms.address, has_balance, CallType::CallCode)
|
||||
},
|
||||
instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true),
|
||||
instructions::DELEGATECALL => (¶ms.sender, ¶ms.address, true, CallType::DelegateCall),
|
||||
_ => panic!(format!("Unexpected instruction {} in CALL branch.", instruction))
|
||||
};
|
||||
|
||||
@ -335,7 +336,7 @@ impl<Cost: CostType> Interpreter<Cost> {
|
||||
// and we don't want to copy
|
||||
let input = unsafe { ::std::mem::transmute(self.mem.read_slice(in_off, in_size)) };
|
||||
let output = self.mem.writeable_slice(out_off, out_size);
|
||||
ext.call(&call_gas.as_u256(), sender_address, receive_address, value, input, &code_address, output)
|
||||
ext.call(&call_gas.as_u256(), sender_address, receive_address, value, input, &code_address, output, call_type)
|
||||
};
|
||||
|
||||
return match call_result {
|
||||
|
@ -15,6 +15,7 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use common::*;
|
||||
use types::executed::CallType;
|
||||
use evm::{self, Ext, Schedule, Factory, GasLeft, VMType, ContractCreateResult, MessageCallResult};
|
||||
use std::fmt::Debug;
|
||||
|
||||
@ -36,7 +37,7 @@ pub struct FakeCall {
|
||||
receive_address: Option<Address>,
|
||||
value: Option<U256>,
|
||||
data: Bytes,
|
||||
code_address: Option<Address>
|
||||
code_address: Option<Address>,
|
||||
}
|
||||
|
||||
/// Fake externalities test structure.
|
||||
@ -119,7 +120,9 @@ impl Ext for FakeExt {
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
_output: &mut [u8]) -> MessageCallResult {
|
||||
_output: &mut [u8],
|
||||
_call_type: CallType
|
||||
) -> MessageCallResult {
|
||||
|
||||
self.calls.insert(FakeCall {
|
||||
call_type: FakeCallType::Call,
|
||||
|
@ -18,6 +18,7 @@
|
||||
use common::*;
|
||||
use state::*;
|
||||
use engine::*;
|
||||
use types::executed::CallType;
|
||||
use evm::{self, Ext, Factory, Finalize};
|
||||
use externalities::*;
|
||||
use substate::*;
|
||||
@ -173,6 +174,7 @@ impl<'a> Executive<'a> {
|
||||
value: ActionValue::Transfer(t.value),
|
||||
code: Some(t.data.clone()),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
};
|
||||
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![])
|
||||
},
|
||||
@ -187,6 +189,7 @@ impl<'a> Executive<'a> {
|
||||
value: ActionValue::Transfer(t.value),
|
||||
code: self.state.code(address),
|
||||
data: Some(t.data.clone()),
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
// TODO: move output upstream
|
||||
let mut out = vec![];
|
||||
@ -248,8 +251,6 @@ impl<'a> Executive<'a> {
|
||||
}
|
||||
trace!("Executive::call(params={:?}) self.env_info={:?}", params, self.info);
|
||||
|
||||
let delegate_call = params.code_address != params.address;
|
||||
|
||||
if self.engine.is_builtin(¶ms.code_address) {
|
||||
// if destination is builtin, try to execute it
|
||||
|
||||
@ -275,8 +276,7 @@ impl<'a> Executive<'a> {
|
||||
cost,
|
||||
trace_output,
|
||||
self.depth,
|
||||
vec![],
|
||||
delegate_call
|
||||
vec![]
|
||||
);
|
||||
}
|
||||
|
||||
@ -285,7 +285,7 @@ impl<'a> Executive<'a> {
|
||||
// just drain the whole gas
|
||||
self.state.revert_snapshot();
|
||||
|
||||
tracer.trace_failed_call(trace_info, self.depth, vec![], delegate_call);
|
||||
tracer.trace_failed_call(trace_info, self.depth, vec![]);
|
||||
|
||||
Err(evm::Error::OutOfGas)
|
||||
}
|
||||
@ -318,10 +318,9 @@ impl<'a> Executive<'a> {
|
||||
gas - gas_left,
|
||||
trace_output,
|
||||
self.depth,
|
||||
traces,
|
||||
delegate_call
|
||||
traces
|
||||
),
|
||||
_ => tracer.trace_failed_call(trace_info, self.depth, traces, delegate_call),
|
||||
_ => tracer.trace_failed_call(trace_info, self.depth, traces),
|
||||
};
|
||||
|
||||
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||
@ -333,7 +332,7 @@ impl<'a> Executive<'a> {
|
||||
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
||||
self.state.clear_snapshot();
|
||||
|
||||
tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![], delegate_call);
|
||||
tracer.trace_call(trace_info, U256::zero(), trace_output, self.depth, vec![]);
|
||||
Ok(params.gas)
|
||||
}
|
||||
}
|
||||
@ -495,6 +494,7 @@ mod tests {
|
||||
use trace::trace;
|
||||
use trace::{Trace, Tracer, NoopTracer, ExecutiveTracer};
|
||||
use trace::{VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, VMTracer, NoopVMTracer, ExecutiveVMTracer};
|
||||
use types::executed::CallType;
|
||||
|
||||
#[test]
|
||||
fn test_contract_address() {
|
||||
@ -628,6 +628,7 @@ mod tests {
|
||||
params.gas = U256::from(100_000);
|
||||
params.code = Some(code.clone());
|
||||
params.value = ActionValue::Transfer(U256::from(100));
|
||||
params.call_type = CallType::Call;
|
||||
let mut state_result = get_temp_state();
|
||||
let mut state = state_result.reference_mut();
|
||||
state.add_balance(&sender, &U256::from(100));
|
||||
@ -653,6 +654,7 @@ mod tests {
|
||||
value: 100.into(),
|
||||
gas: 100000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(55_248),
|
||||
|
@ -21,6 +21,7 @@ use engine::*;
|
||||
use executive::*;
|
||||
use evm::{self, Schedule, Ext, ContractCreateResult, MessageCallResult, Factory};
|
||||
use substate::*;
|
||||
use types::executed::CallType;
|
||||
use trace::{Tracer, VMTracer};
|
||||
|
||||
/// Policy for handling output data on `RETURN` opcode.
|
||||
@ -148,6 +149,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
value: ActionValue::Transfer(*value),
|
||||
code: Some(code.to_vec()),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
};
|
||||
|
||||
self.state.inc_nonce(&self.origin_info.address);
|
||||
@ -170,7 +172,8 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
code_address: &Address,
|
||||
output: &mut [u8]
|
||||
output: &mut [u8],
|
||||
call_type: CallType
|
||||
) -> MessageCallResult {
|
||||
trace!(target: "externalities", "call");
|
||||
|
||||
@ -184,6 +187,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
gas_price: self.origin_info.gas_price,
|
||||
code: self.state.code(code_address),
|
||||
data: Some(data.to_vec()),
|
||||
call_type: call_type,
|
||||
};
|
||||
|
||||
if let Some(value) = value {
|
||||
@ -303,6 +307,7 @@ mod tests {
|
||||
use devtools::GuardedTempResult;
|
||||
use super::*;
|
||||
use trace::{NoopTracer, NoopVMTracer};
|
||||
use types::executed::CallType;
|
||||
|
||||
fn get_test_origin() -> OriginInfo {
|
||||
OriginInfo {
|
||||
@ -421,7 +426,9 @@ mod tests {
|
||||
Some(U256::from_str("0000000000000000000000000000000000000000000000000000000000150000").unwrap()),
|
||||
&[],
|
||||
&Address::new(),
|
||||
&mut output);
|
||||
&mut output,
|
||||
CallType::Call
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -22,6 +22,7 @@ use evm;
|
||||
use evm::{Schedule, Ext, Factory, Finalize, VMType, ContractCreateResult, MessageCallResult};
|
||||
use externalities::*;
|
||||
use substate::*;
|
||||
use types::executed::CallType;
|
||||
use tests::helpers::*;
|
||||
use ethjson;
|
||||
use trace::{Tracer, NoopTracer};
|
||||
@ -115,7 +116,9 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
|
||||
value: Option<U256>,
|
||||
data: &[u8],
|
||||
_code_address: &Address,
|
||||
_output: &mut [u8]) -> MessageCallResult {
|
||||
_output: &mut [u8],
|
||||
_call_type: CallType
|
||||
) -> MessageCallResult {
|
||||
self.callcreates.push(CallCreate {
|
||||
data: data.to_vec(),
|
||||
destination: Some(receive_address.clone()),
|
||||
|
@ -403,6 +403,7 @@ use transaction::*;
|
||||
use util::log::init_log;
|
||||
use trace::trace;
|
||||
use trace::trace::{Trace};
|
||||
use types::executed::CallType;
|
||||
|
||||
#[test]
|
||||
fn should_apply_create_transaction() {
|
||||
@ -535,6 +536,7 @@ fn should_trace_call_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(3),
|
||||
@ -577,6 +579,7 @@ fn should_trace_basic_call_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(0),
|
||||
@ -619,6 +622,7 @@ fn should_trace_call_transaction_to_builtin() {
|
||||
value: 0.into(),
|
||||
gas: 79_000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(3000),
|
||||
@ -660,6 +664,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
|
||||
value: 0.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(28_061),
|
||||
@ -703,12 +708,28 @@ fn should_not_trace_callcode() {
|
||||
value: 0.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(64),
|
||||
gas_used: 64.into(),
|
||||
output: vec![]
|
||||
}),
|
||||
subs: vec![]
|
||||
subs: vec![Trace {
|
||||
depth: 1,
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: 0xa.into(),
|
||||
to: 0xa.into(),
|
||||
value: 0.into(),
|
||||
gas: 4096.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::CallCode,
|
||||
}),
|
||||
subs: vec![],
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 3.into(),
|
||||
output: vec![],
|
||||
}),
|
||||
}],
|
||||
});
|
||||
assert_eq!(result.trace, expected_trace);
|
||||
}
|
||||
@ -749,12 +770,28 @@ fn should_not_trace_delegatecall() {
|
||||
value: 0.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(61),
|
||||
output: vec![]
|
||||
}),
|
||||
subs: vec![]
|
||||
subs: vec![Trace {
|
||||
depth: 1,
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
|
||||
to: 0xa.into(),
|
||||
value: 0.into(),
|
||||
gas: 32768.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::DelegateCall,
|
||||
}),
|
||||
subs: vec![],
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 3.into(),
|
||||
output: vec![],
|
||||
}),
|
||||
}],
|
||||
});
|
||||
assert_eq!(result.trace, expected_trace);
|
||||
}
|
||||
@ -791,6 +828,7 @@ fn should_trace_failed_call_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::FailedCall,
|
||||
subs: vec![]
|
||||
@ -834,6 +872,7 @@ fn should_trace_call_with_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(69),
|
||||
@ -847,6 +886,7 @@ fn should_trace_call_with_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78934.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(3),
|
||||
@ -891,6 +931,7 @@ fn should_trace_call_with_basic_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(31761),
|
||||
@ -904,6 +945,7 @@ fn should_trace_call_with_basic_subcall_transaction() {
|
||||
value: 69.into(),
|
||||
gas: 2300.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult::default()),
|
||||
subs: vec![]
|
||||
@ -945,6 +987,7 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(31761),
|
||||
@ -989,6 +1032,7 @@ fn should_trace_failed_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(79_000),
|
||||
@ -1002,6 +1046,7 @@ fn should_trace_failed_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78934.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::FailedCall,
|
||||
subs: vec![]
|
||||
@ -1045,6 +1090,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(135),
|
||||
@ -1058,6 +1104,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78934.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(69),
|
||||
@ -1071,6 +1118,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78868.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(3),
|
||||
@ -1118,6 +1166,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(79_000),
|
||||
@ -1131,6 +1180,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78934.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::FailedCall,
|
||||
subs: vec![Trace {
|
||||
@ -1141,6 +1191,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
||||
value: 0.into(),
|
||||
gas: 78868.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: U256::from(3),
|
||||
@ -1187,6 +1238,7 @@ fn should_trace_suicide() {
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 3.into(),
|
||||
|
@ -367,6 +367,7 @@ mod tests {
|
||||
use trace::{Config, Switch, TraceDB, Database, DatabaseExtras, ImportRequest};
|
||||
use trace::{BlockTraces, Trace, Filter, LocalizedTrace, AddressesFilter};
|
||||
use trace::trace::{Call, Action, Res};
|
||||
use types::executed::CallType;
|
||||
|
||||
struct NoopExtras;
|
||||
|
||||
@ -492,6 +493,7 @@ mod tests {
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::FailedCall,
|
||||
subs: vec![],
|
||||
@ -511,6 +513,7 @@ mod tests {
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::FailedCall,
|
||||
trace_address: vec![],
|
||||
|
@ -40,12 +40,7 @@ impl Tracer for ExecutiveTracer {
|
||||
Some(vec![])
|
||||
}
|
||||
|
||||
fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, depth: usize, subs: Vec<Trace>, delegate_call: bool) {
|
||||
// don't trace if it's DELEGATECALL or CALLCODE.
|
||||
if delegate_call {
|
||||
return;
|
||||
}
|
||||
|
||||
fn trace_call(&mut self, call: Option<Call>, gas_used: U256, output: Option<Bytes>, depth: usize, subs: Vec<Trace>) {
|
||||
let trace = Trace {
|
||||
depth: depth,
|
||||
subs: subs,
|
||||
@ -72,12 +67,7 @@ impl Tracer for ExecutiveTracer {
|
||||
self.traces.push(trace);
|
||||
}
|
||||
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>, delegate_call: bool) {
|
||||
// don't trace if it's DELEGATECALL or CALLCODE.
|
||||
if delegate_call {
|
||||
return;
|
||||
}
|
||||
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>) {
|
||||
let trace = Trace {
|
||||
depth: depth,
|
||||
subs: subs,
|
||||
|
@ -171,6 +171,7 @@ mod tests {
|
||||
use util::{U256, Address};
|
||||
use trace::trace::{Action, Res, CallResult, Call, Create, Trace};
|
||||
use trace::BlockTraces;
|
||||
use types::executed::CallType;
|
||||
|
||||
#[test]
|
||||
fn test_block_from() {
|
||||
@ -181,7 +182,8 @@ mod tests {
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5]
|
||||
input: vec![0x5],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
subs: vec![
|
||||
Trace {
|
||||
@ -265,7 +267,8 @@ mod tests {
|
||||
to: 2.into(),
|
||||
value: 3.into(),
|
||||
gas: 4.into(),
|
||||
input: vec![0x5]
|
||||
input: vec![0x5],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: 10.into(),
|
||||
|
@ -60,8 +60,7 @@ pub trait Tracer: Send {
|
||||
gas_used: U256,
|
||||
output: Option<Bytes>,
|
||||
depth: usize,
|
||||
subs: Vec<Trace>,
|
||||
delegate_call: bool
|
||||
subs: Vec<Trace>
|
||||
);
|
||||
|
||||
/// Stores trace create info.
|
||||
@ -76,7 +75,7 @@ pub trait Tracer: Send {
|
||||
);
|
||||
|
||||
/// Stores failed call trace.
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>, delegate_call: bool);
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, depth: usize, subs: Vec<Trace>);
|
||||
|
||||
/// Stores failed create trace.
|
||||
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>);
|
||||
|
@ -37,7 +37,7 @@ impl Tracer for NoopTracer {
|
||||
None
|
||||
}
|
||||
|
||||
fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: usize, _: Vec<Trace>, _: bool) {
|
||||
fn trace_call(&mut self, call: Option<Call>, _: U256, output: Option<Bytes>, _: usize, _: Vec<Trace>) {
|
||||
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
|
||||
assert!(output.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
|
||||
}
|
||||
@ -47,7 +47,7 @@ impl Tracer for NoopTracer {
|
||||
assert!(code.is_none(), "self.prepare_trace_output().is_none(): so we can't be tracing: qed");
|
||||
}
|
||||
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, _: usize, _: Vec<Trace>, _: bool) {
|
||||
fn trace_failed_call(&mut self, call: Option<Call>, _: usize, _: Vec<Trace>) {
|
||||
assert!(call.is_none(), "self.prepare_trace_call().is_none(): so we can't be tracing: qed");
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
use util::numbers::*;
|
||||
use util::Bytes;
|
||||
use util::rlp::*;
|
||||
use trace::{Trace, VMTrace};
|
||||
use types::log_entry::LogEntry;
|
||||
use types::state_diff::StateDiff;
|
||||
@ -26,6 +27,43 @@ use std::fmt;
|
||||
use std::mem;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
/// The type of the call-like instruction.
|
||||
#[derive(Debug, PartialEq, Clone, Binary)]
|
||||
pub enum CallType {
|
||||
/// Not a CALL.
|
||||
None,
|
||||
/// CALL.
|
||||
Call,
|
||||
/// CALLCODE.
|
||||
CallCode,
|
||||
/// DELEGATECALL.
|
||||
DelegateCall,
|
||||
}
|
||||
|
||||
impl Encodable for CallType {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
let v = match *self {
|
||||
CallType::None => 0u32,
|
||||
CallType::Call => 1,
|
||||
CallType::CallCode => 2,
|
||||
CallType::DelegateCall => 3,
|
||||
};
|
||||
s.append(&v);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for CallType {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
decoder.as_rlp().as_val().and_then(|v| Ok(match v {
|
||||
0u32 => CallType::None,
|
||||
1 => CallType::Call,
|
||||
2 => CallType::CallCode,
|
||||
3 => CallType::DelegateCall,
|
||||
_ => return Err(DecoderError::Custom("Invalid value of CallType item")),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Transaction execution receipt.
|
||||
#[derive(Debug, PartialEq, Clone, Binary)]
|
||||
pub struct Executed {
|
||||
@ -135,3 +173,12 @@ impl fmt::Display for ExecutionError {
|
||||
|
||||
/// Transaction execution result.
|
||||
pub type ExecutionResult = Result<Executed, ExecutionError>;
|
||||
|
||||
#[test]
|
||||
fn should_encode_and_decode_call_type() {
|
||||
use util::rlp;
|
||||
let original = CallType::Call;
|
||||
let encoded = rlp::encode(&original);
|
||||
let decoded = rlp::decode(&encoded);
|
||||
assert_eq!(original, decoded);
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ mod tests {
|
||||
use trace::flat::FlatTrace;
|
||||
use trace::{Filter, AddressesFilter};
|
||||
use basic_types::LogBloom;
|
||||
use types::executed::CallType;
|
||||
|
||||
#[test]
|
||||
fn empty_trace_filter_bloom_possibilities() {
|
||||
@ -285,6 +286,7 @@ mod tests {
|
||||
value: 3.into(),
|
||||
gas: 4.into(),
|
||||
input: vec![0x5],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::FailedCall,
|
||||
trace_address: vec![0],
|
||||
|
@ -21,6 +21,7 @@ use util::rlp::*;
|
||||
use util::sha3::Hashable;
|
||||
use action_params::ActionParams;
|
||||
use basic_types::LogBloom;
|
||||
use types::executed::CallType;
|
||||
use ipc::binary::BinaryConvertError;
|
||||
use std::mem;
|
||||
use std::collections::VecDeque;
|
||||
@ -107,6 +108,8 @@ pub struct Call {
|
||||
pub gas: U256,
|
||||
/// The input data provided to the call.
|
||||
pub input: Bytes,
|
||||
/// The type of the call.
|
||||
pub call_type: CallType,
|
||||
}
|
||||
|
||||
impl From<ActionParams> for Call {
|
||||
@ -117,18 +120,20 @@ 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Call {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(5);
|
||||
s.begin_list(6);
|
||||
s.append(&self.from);
|
||||
s.append(&self.to);
|
||||
s.append(&self.value);
|
||||
s.append(&self.gas);
|
||||
s.append(&self.input);
|
||||
s.append(&self.call_type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,6 +146,7 @@ impl Decodable for Call {
|
||||
value: try!(d.val_at(2)),
|
||||
gas: try!(d.val_at(3)),
|
||||
input: try!(d.val_at(4)),
|
||||
call_type: try!(d.val_at(5)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
@ -593,6 +599,7 @@ mod tests {
|
||||
use util::rlp::{encode, decode};
|
||||
use util::sha3::Hashable;
|
||||
use trace::trace::{Call, CallResult, Create, Res, Action, Trace, Suicide, CreateResult};
|
||||
use types::executed::CallType;
|
||||
|
||||
#[test]
|
||||
fn traces_rlp() {
|
||||
@ -603,7 +610,8 @@ mod tests {
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5]
|
||||
input: vec![0x5],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
subs: vec![
|
||||
Trace {
|
||||
@ -638,7 +646,8 @@ mod tests {
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5]
|
||||
input: vec![0x5],
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
subs: vec![
|
||||
Trace {
|
||||
|
@ -21,6 +21,7 @@ use ethcore::trace::{Trace as EthTrace, LocalizedTrace as EthLocalizedTrace};
|
||||
use ethcore::trace as et;
|
||||
use ethcore::state_diff;
|
||||
use ethcore::account_diff;
|
||||
use ethcore::executed;
|
||||
use ethcore::client::Executed;
|
||||
use util::Uint;
|
||||
use v1::types::{Bytes, H160, H256, U256};
|
||||
@ -235,6 +236,34 @@ impl From<trace::Create> for Create {
|
||||
}
|
||||
}
|
||||
|
||||
/// Call type.
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum CallType {
|
||||
/// None
|
||||
#[serde(rename="none")]
|
||||
None,
|
||||
/// Call
|
||||
#[serde(rename="call")]
|
||||
Call,
|
||||
/// Call code
|
||||
#[serde(rename="callcode")]
|
||||
CallCode,
|
||||
/// Delegate call
|
||||
#[serde(rename="delegatecall")]
|
||||
DelegateCall,
|
||||
}
|
||||
|
||||
impl From<executed::CallType> for CallType {
|
||||
fn from(c: executed::CallType) -> Self {
|
||||
match c {
|
||||
executed::CallType::None => CallType::None,
|
||||
executed::CallType::Call => CallType::Call,
|
||||
executed::CallType::CallCode => CallType::CallCode,
|
||||
executed::CallType::DelegateCall => CallType::DelegateCall,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Call response
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Call {
|
||||
@ -248,6 +277,9 @@ pub struct Call {
|
||||
gas: U256,
|
||||
/// Input data
|
||||
input: Bytes,
|
||||
/// The type of the call.
|
||||
#[serde(rename="callType")]
|
||||
call_type: CallType,
|
||||
}
|
||||
|
||||
impl From<trace::Call> for Call {
|
||||
@ -258,6 +290,7 @@ impl From<trace::Call> for Call {
|
||||
value: c.value.into(),
|
||||
gas: c.gas.into(),
|
||||
input: c.input.into(),
|
||||
call_type: c.call_type.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -500,6 +533,7 @@ mod tests {
|
||||
value: U256::from(6),
|
||||
gas: U256::from(7),
|
||||
input: Bytes::new(vec![0x12, 0x34]),
|
||||
call_type: CallType::Call,
|
||||
}),
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: U256::from(8),
|
||||
@ -513,7 +547,7 @@ mod tests {
|
||||
block_hash: H256::from(14),
|
||||
};
|
||||
let serialized = serde_json::to_string(&t).unwrap();
|
||||
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234"}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||
assert_eq!(serialized, r#"{"action":{"call":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","input":"0x1234","callType":{"call":[]}}},"result":{"call":{"gasUsed":"0x08","output":"0x5678"}},"traceAddress":["0x0a"],"subtraces":"0x01","transactionPosition":"0x0b","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0x0d","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -589,6 +623,7 @@ mod tests {
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x12, 0x34].into(),
|
||||
call_type: CallType::Call,
|
||||
}), Action::Create(Create {
|
||||
from: H160::from(5),
|
||||
value: U256::from(6),
|
||||
@ -597,7 +632,7 @@ mod tests {
|
||||
})];
|
||||
|
||||
let serialized = serde_json::to_string(&actions).unwrap();
|
||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234"}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x03","gas":"0x04","input":"0x1234","callType":{"call":[]}}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x06","gas":"0x07","init":"0x5678"}}]"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user