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:
Gav Wood
2016-07-27 17:41:21 +02:00
committed by GitHub
parent edda0b2380
commit ccb62d3b55
17 changed files with 228 additions and 62 deletions

View File

@@ -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?
}
}
}

View File

@@ -18,6 +18,7 @@
use util::common::*;
use evm::{self, Schedule};
use types::executed::CallType;
use env_info::*;
/// Result of externalities create function.
@@ -69,13 +70,15 @@ pub trait Ext {
/// and true if subcall was successfull.
#[cfg_attr(feature="dev", allow(too_many_arguments))]
fn call(&mut self,
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
output: &mut [u8]) -> MessageCallResult;
gas: &U256,
sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
code_address: &Address,
output: &mut [u8],
call_type: CallType
) -> MessageCallResult;
/// Returns code at given address
fn extcode(&self, address: &Address) -> Bytes;

View File

@@ -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(&params.address) >= value.unwrap();
(&params.address, &code_address, has_balance)
(&params.address, &code_address, has_balance, CallType::Call)
},
instructions::CALLCODE => {
let has_balance = ext.balance(&params.address) >= value.unwrap();
(&params.address, &params.address, has_balance)
(&params.address, &params.address, has_balance, CallType::CallCode)
},
instructions::DELEGATECALL => (&params.sender, &params.address, true),
instructions::DELEGATECALL => (&params.sender, &params.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 {

View File

@@ -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,

View File

@@ -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(&params.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),

View File

@@ -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]

View File

@@ -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};
@@ -109,13 +110,15 @@ impl<'a, T, V> Ext for TestExt<'a, T, V> where T: Tracer, V: VMTracer {
}
fn call(&mut self,
gas: &U256,
_sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
_code_address: &Address,
_output: &mut [u8]) -> MessageCallResult {
gas: &U256,
_sender_address: &Address,
receive_address: &Address,
value: Option<U256>,
data: &[u8],
_code_address: &Address,
_output: &mut [u8],
_call_type: CallType
) -> MessageCallResult {
self.callcreates.push(CallCreate {
data: data.to_vec(),
destination: Some(receive_address.clone()),

View File

@@ -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(),

View File

@@ -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![],

View File

@@ -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,

View File

@@ -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(),

View File

@@ -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>);

View File

@@ -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");
}

View File

@@ -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);
}

View File

@@ -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],

View File

@@ -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 {