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