facelift for traces, added errors (#2042)
* evm errors facelift * facelift for traces, added errors with description * additional tests for traces json serialization
This commit is contained in:
parent
59f18ab958
commit
da2c2e5fc6
@ -16,11 +16,13 @@
|
|||||||
|
|
||||||
//! Evm interface.
|
//! Evm interface.
|
||||||
|
|
||||||
use common::*;
|
use std::{ops, cmp, fmt};
|
||||||
|
use util::{U128, U256, U512, Uint};
|
||||||
|
use action_params::ActionParams;
|
||||||
use evm::Ext;
|
use evm::Ext;
|
||||||
|
|
||||||
/// Evm errors.
|
/// Evm errors.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
/// The state should be reverted to the state from before the
|
/// The state should be reverted to the state from before the
|
||||||
@ -63,6 +65,21 @@ pub enum Error {
|
|||||||
Internal,
|
Internal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
let message = match *self {
|
||||||
|
OutOfGas => "Out of gas",
|
||||||
|
BadJumpDestination { .. } => "Bad jump destination",
|
||||||
|
BadInstruction { .. } => "Bad instruction",
|
||||||
|
StackUnderflow { .. } => "Stack underflow",
|
||||||
|
OutOfStack { .. } => "Out of stack",
|
||||||
|
Internal => "Internal error",
|
||||||
|
};
|
||||||
|
message.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A specialized version of Result over EVM errors.
|
/// A specialized version of Result over EVM errors.
|
||||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
pub type Result<T> = ::std::result::Result<T, Error>;
|
||||||
|
|
||||||
@ -193,10 +210,13 @@ pub trait Evm {
|
|||||||
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
fn exec(&mut self, params: ActionParams, ext: &mut Ext) -> Result<GasLeft>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn should_calculate_overflow_mul_shr_without_overflow() {
|
mod tests {
|
||||||
|
use util::{U256, Uint};
|
||||||
|
use super::CostType;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_calculate_overflow_mul_shr_without_overflow() {
|
||||||
// given
|
// given
|
||||||
let num = 1048576;
|
let num = 1048576;
|
||||||
|
|
||||||
@ -209,15 +229,14 @@ fn should_calculate_overflow_mul_shr_without_overflow() {
|
|||||||
assert!(!o1);
|
assert!(!o1);
|
||||||
assert_eq!(res2, num);
|
assert_eq!(res2, num);
|
||||||
assert!(!o2);
|
assert!(!o2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(test)]
|
fn should_calculate_overflow_mul_shr_with_overflow() {
|
||||||
fn should_calculate_overflow_mul_shr_with_overflow() {
|
|
||||||
// given
|
// given
|
||||||
let max = ::std::u64::MAX;
|
let max = u64::max_value();
|
||||||
let num1 = U256([max, max, max, max]);
|
let num1 = U256([max, max, max, max]);
|
||||||
let num2 = ::std::usize::MAX;
|
let num2 = usize::max_value();
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let (res1, o1) = num1.overflow_mul_shr(num1, 256);
|
let (res1, o1) = num1.overflow_mul_shr(num1, 256);
|
||||||
@ -229,17 +248,17 @@ fn should_calculate_overflow_mul_shr_with_overflow() {
|
|||||||
|
|
||||||
assert_eq!(res1, !U256::zero() - U256::one());
|
assert_eq!(res1, !U256::zero() - U256::one());
|
||||||
assert!(o1);
|
assert!(o1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(test)]
|
fn should_validate_u256_to_usize_conversion() {
|
||||||
fn should_validate_u256_to_usize_conversion() {
|
|
||||||
// given
|
// given
|
||||||
let v = U256::from(::std::usize::MAX) + U256::from(1);
|
let v = U256::from(usize::max_value()) + U256::from(1);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let res = usize::from_u256(v);
|
let res = usize::from_u256(v);
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert!(res.is_err());
|
assert!(res.is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -286,7 +286,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, vec![]);
|
tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into());
|
||||||
|
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
}
|
}
|
||||||
@ -320,7 +320,7 @@ impl<'a> Executive<'a> {
|
|||||||
trace_output,
|
trace_output,
|
||||||
traces
|
traces
|
||||||
),
|
),
|
||||||
_ => tracer.trace_failed_call(trace_info, traces),
|
Err(e) => tracer.trace_failed_call(trace_info, traces, e.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||||
@ -385,7 +385,7 @@ impl<'a> Executive<'a> {
|
|||||||
created,
|
created,
|
||||||
subtracer.traces()
|
subtracer.traces()
|
||||||
),
|
),
|
||||||
_ => tracer.trace_failed_create(trace_info, subtracer.traces())
|
Err(e) => tracer.trace_failed_create(trace_info, subtracer.traces(), e.into())
|
||||||
};
|
};
|
||||||
|
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
|
@ -444,8 +444,7 @@ use env_info::*;
|
|||||||
use spec::*;
|
use spec::*;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use util::log::init_log;
|
use util::log::init_log;
|
||||||
use trace::trace;
|
use trace::{FlatTrace, TraceError, trace};
|
||||||
use trace::FlatTrace;
|
|
||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -538,7 +537,7 @@ fn should_trace_failed_create_transaction() {
|
|||||||
gas: 78792.into(),
|
gas: 78792.into(),
|
||||||
init: vec![91, 96, 0, 86],
|
init: vec![91, 96, 0, 86],
|
||||||
}),
|
}),
|
||||||
result: trace::Res::FailedCreate,
|
result: trace::Res::FailedCreate(TraceError::OutOfGas),
|
||||||
subtraces: 0
|
subtraces: 0
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -869,7 +868,7 @@ fn should_trace_failed_call_transaction() {
|
|||||||
input: vec![],
|
input: vec![],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: trace::Res::FailedCall,
|
result: trace::Res::FailedCall(TraceError::OutOfGas),
|
||||||
subtraces: 0,
|
subtraces: 0,
|
||||||
}];
|
}];
|
||||||
|
|
||||||
@ -1084,7 +1083,7 @@ fn should_trace_failed_subcall_transaction() {
|
|||||||
input: vec![],
|
input: vec![],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: trace::Res::FailedCall,
|
result: trace::Res::FailedCall(TraceError::OutOfGas),
|
||||||
}];
|
}];
|
||||||
|
|
||||||
assert_eq!(result.trace, expected_trace);
|
assert_eq!(result.trace, expected_trace);
|
||||||
@ -1217,7 +1216,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
|||||||
input: vec![],
|
input: vec![],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: trace::Res::FailedCall,
|
result: trace::Res::FailedCall(TraceError::OutOfGas),
|
||||||
}, FlatTrace {
|
}, FlatTrace {
|
||||||
trace_address: vec![0, 0].into_iter().collect(),
|
trace_address: vec![0, 0].into_iter().collect(),
|
||||||
subtraces: 0,
|
subtraces: 0,
|
||||||
|
@ -420,7 +420,7 @@ mod tests {
|
|||||||
use devtools::RandomTempPath;
|
use devtools::RandomTempPath;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
use trace::{Config, Switch, TraceDB, Database as TraceDatabase, DatabaseExtras, ImportRequest};
|
use trace::{Config, Switch, TraceDB, Database as TraceDatabase, DatabaseExtras, ImportRequest};
|
||||||
use trace::{Filter, LocalizedTrace, AddressesFilter};
|
use trace::{Filter, LocalizedTrace, AddressesFilter, TraceError};
|
||||||
use trace::trace::{Call, Action, Res};
|
use trace::trace::{Call, Action, Res};
|
||||||
use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
|
use trace::flat::{FlatTrace, FlatBlockTraces, FlatTransactionTraces};
|
||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
@ -560,7 +560,7 @@ mod tests {
|
|||||||
input: vec![],
|
input: vec![],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCall,
|
result: Res::FailedCall(TraceError::OutOfGas),
|
||||||
}])]),
|
}])]),
|
||||||
block_hash: block_hash.clone(),
|
block_hash: block_hash.clone(),
|
||||||
block_number: block_number,
|
block_number: block_number,
|
||||||
@ -579,7 +579,7 @@ mod tests {
|
|||||||
input: vec![],
|
input: vec![],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCall,
|
result: Res::FailedCall(TraceError::OutOfGas),
|
||||||
trace_address: vec![],
|
trace_address: vec![],
|
||||||
subtraces: 0,
|
subtraces: 0,
|
||||||
transaction_number: 0,
|
transaction_number: 0,
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
|
use trace::trace::{Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
|
||||||
use trace::{Tracer, VMTracer, FlatTrace};
|
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
||||||
|
|
||||||
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -112,23 +112,23 @@ impl Tracer for ExecutiveTracer {
|
|||||||
self.traces.extend(update_trace_address(subs));
|
self.traces.extend(update_trace_address(subs));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>) {
|
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>, error: TraceError) {
|
||||||
let trace = FlatTrace {
|
let trace = FlatTrace {
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
subtraces: top_level_subtraces(&subs),
|
subtraces: top_level_subtraces(&subs),
|
||||||
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
|
action: Action::Call(call.expect("self.prepare_trace_call().is_some(): so we must be tracing: qed")),
|
||||||
result: Res::FailedCall,
|
result: Res::FailedCall(error),
|
||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced failed call {:?}", trace);
|
debug!(target: "trace", "Traced failed call {:?}", trace);
|
||||||
self.traces.push(trace);
|
self.traces.push(trace);
|
||||||
self.traces.extend(update_trace_address(subs));
|
self.traces.extend(update_trace_address(subs));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>) {
|
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>, error: TraceError) {
|
||||||
let trace = FlatTrace {
|
let trace = FlatTrace {
|
||||||
subtraces: top_level_subtraces(&subs),
|
subtraces: top_level_subtraces(&subs),
|
||||||
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
|
action: Action::Create(create.expect("self.prepare_trace_create().is_some(): so we must be tracing: qed")),
|
||||||
result: Res::FailedCreate,
|
result: Res::FailedCreate(error),
|
||||||
trace_address: Default::default(),
|
trace_address: Default::default(),
|
||||||
};
|
};
|
||||||
debug!(target: "trace", "Traced failed create {:?}", trace);
|
debug!(target: "trace", "Traced failed create {:?}", trace);
|
||||||
|
@ -24,7 +24,8 @@ mod executive_tracer;
|
|||||||
mod import;
|
mod import;
|
||||||
mod noop_tracer;
|
mod noop_tracer;
|
||||||
|
|
||||||
pub use types::trace_types::*;
|
pub use types::trace_types::{filter, flat, localized, trace};
|
||||||
|
pub use types::trace_types::error::Error as TraceError;
|
||||||
pub use self::config::{Config, Switch};
|
pub use self::config::{Config, Switch};
|
||||||
pub use self::db::TraceDB;
|
pub use self::db::TraceDB;
|
||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
@ -71,10 +72,10 @@ pub trait Tracer: Send {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/// Stores failed call trace.
|
/// Stores failed call trace.
|
||||||
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>);
|
fn trace_failed_call(&mut self, call: Option<Call>, subs: Vec<FlatTrace>, error: TraceError);
|
||||||
|
|
||||||
/// Stores failed create trace.
|
/// Stores failed create trace.
|
||||||
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>);
|
fn trace_failed_create(&mut self, create: Option<Create>, subs: Vec<FlatTrace>, error: TraceError);
|
||||||
|
|
||||||
/// Stores suicide info.
|
/// Stores suicide info.
|
||||||
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address);
|
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address);
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use trace::{Tracer, VMTracer, FlatTrace};
|
use trace::{Tracer, VMTracer, FlatTrace, TraceError};
|
||||||
use trace::trace::{Call, Create, VMTrace};
|
use trace::trace::{Call, Create, VMTrace};
|
||||||
|
|
||||||
/// Nonoperative tracer. Does not trace anything.
|
/// Nonoperative tracer. Does not trace anything.
|
||||||
@ -47,11 +47,11 @@ 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>, _: Vec<FlatTrace>) {
|
fn trace_failed_call(&mut self, call: Option<Call>, _: Vec<FlatTrace>, _: TraceError) {
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace_failed_create(&mut self, create: Option<Create>, _: Vec<FlatTrace>) {
|
fn trace_failed_create(&mut self, create: Option<Create>, _: Vec<FlatTrace>, _: TraceError) {
|
||||||
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
|
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
99
ethcore/src/types/trace_types/error.rs
Normal file
99
ethcore/src/types/trace_types/error.rs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Trace errors.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
use rlp::{Encodable, RlpStream, Decodable, Decoder, DecoderError, Stream, View};
|
||||||
|
use evm::Error as EvmError;
|
||||||
|
|
||||||
|
/// Trace evm errors.
|
||||||
|
#[derive(Debug, PartialEq, Clone, Binary)]
|
||||||
|
pub enum Error {
|
||||||
|
/// `OutOfGas` is returned when transaction execution runs out of gas.
|
||||||
|
OutOfGas,
|
||||||
|
/// `BadJumpDestination` is returned when execution tried to move
|
||||||
|
/// to position that wasn't marked with JUMPDEST instruction
|
||||||
|
BadJumpDestination,
|
||||||
|
/// `BadInstructions` is returned when given instruction is not supported
|
||||||
|
BadInstruction,
|
||||||
|
/// `StackUnderflow` when there is not enough stack elements to execute instruction
|
||||||
|
StackUnderflow,
|
||||||
|
/// When execution would exceed defined Stack Limit
|
||||||
|
OutOfStack,
|
||||||
|
/// Returned on evm internal error. Should never be ignored during development.
|
||||||
|
/// Likely to cause consensus issues.
|
||||||
|
Internal,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EvmError> for Error {
|
||||||
|
fn from(e: EvmError) -> Self {
|
||||||
|
match e {
|
||||||
|
EvmError::OutOfGas => Error::OutOfGas,
|
||||||
|
EvmError::BadJumpDestination { .. } => Error::BadJumpDestination,
|
||||||
|
EvmError::BadInstruction { .. } => Error::BadInstruction,
|
||||||
|
EvmError::StackUnderflow { .. } => Error::StackUnderflow,
|
||||||
|
EvmError::OutOfStack { .. } => Error::OutOfStack,
|
||||||
|
EvmError::Internal => Error::Internal,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use self::Error::*;
|
||||||
|
let message = match *self {
|
||||||
|
OutOfGas => "Out of gas",
|
||||||
|
BadJumpDestination => "Bad jump destination",
|
||||||
|
BadInstruction => "Bad instruction",
|
||||||
|
StackUnderflow => "Stack underflow",
|
||||||
|
OutOfStack => "Out of stack",
|
||||||
|
Internal => "Internal error",
|
||||||
|
};
|
||||||
|
message.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Encodable for Error {
|
||||||
|
fn rlp_append(&self, s: &mut RlpStream) {
|
||||||
|
use self::Error::*;
|
||||||
|
let value = match *self {
|
||||||
|
OutOfGas => 0u8,
|
||||||
|
BadJumpDestination => 1,
|
||||||
|
BadInstruction => 2,
|
||||||
|
StackUnderflow => 3,
|
||||||
|
OutOfStack => 4,
|
||||||
|
Internal => 5,
|
||||||
|
};
|
||||||
|
s.append(&value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Error {
|
||||||
|
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||||
|
use self::Error::*;
|
||||||
|
let value: u8 = try!(decoder.as_rlp().as_val());
|
||||||
|
match value {
|
||||||
|
0 => Ok(OutOfGas),
|
||||||
|
1 => Ok(BadJumpDestination),
|
||||||
|
2 => Ok(BadInstruction),
|
||||||
|
3 => Ok(StackUnderflow),
|
||||||
|
4 => Ok(OutOfStack),
|
||||||
|
5 => Ok(Internal),
|
||||||
|
_ => Err(DecoderError::Custom("Invalid error type")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -140,7 +140,7 @@ mod tests {
|
|||||||
use util::bloom::Bloomable;
|
use util::bloom::Bloomable;
|
||||||
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide};
|
use trace::trace::{Action, Call, Res, Create, CreateResult, Suicide};
|
||||||
use trace::flat::FlatTrace;
|
use trace::flat::FlatTrace;
|
||||||
use trace::{Filter, AddressesFilter};
|
use trace::{Filter, AddressesFilter, TraceError};
|
||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -286,7 +286,7 @@ mod tests {
|
|||||||
input: vec![0x5],
|
input: vec![0x5],
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCall,
|
result: Res::FailedCall(TraceError::OutOfGas),
|
||||||
trace_address: vec![0].into_iter().collect(),
|
trace_address: vec![0].into_iter().collect(),
|
||||||
subtraces: 0,
|
subtraces: 0,
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
//! Types used in the public api
|
//! Types used in the public api
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub mod filter;
|
pub mod filter;
|
||||||
pub mod flat;
|
pub mod flat;
|
||||||
pub mod trace;
|
pub mod trace;
|
||||||
|
@ -24,6 +24,7 @@ use rlp::*;
|
|||||||
use action_params::ActionParams;
|
use action_params::ActionParams;
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
use types::executed::CallType;
|
use types::executed::CallType;
|
||||||
|
use super::error::Error;
|
||||||
|
|
||||||
/// `Call` result.
|
/// `Call` result.
|
||||||
#[derive(Debug, Clone, PartialEq, Default, Binary)]
|
#[derive(Debug, Clone, PartialEq, Default, Binary)]
|
||||||
@ -322,9 +323,9 @@ pub enum Res {
|
|||||||
/// Successful create action result.
|
/// Successful create action result.
|
||||||
Create(CreateResult),
|
Create(CreateResult),
|
||||||
/// Failed call.
|
/// Failed call.
|
||||||
FailedCall,
|
FailedCall(Error),
|
||||||
/// Failed create.
|
/// Failed create.
|
||||||
FailedCreate,
|
FailedCreate(Error),
|
||||||
/// None
|
/// None
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
@ -342,13 +343,15 @@ impl Encodable for Res {
|
|||||||
s.append(&1u8);
|
s.append(&1u8);
|
||||||
s.append(create);
|
s.append(create);
|
||||||
},
|
},
|
||||||
Res::FailedCall => {
|
Res::FailedCall(ref err) => {
|
||||||
s.begin_list(1);
|
s.begin_list(2);
|
||||||
s.append(&2u8);
|
s.append(&2u8);
|
||||||
|
s.append(err);
|
||||||
},
|
},
|
||||||
Res::FailedCreate => {
|
Res::FailedCreate(ref err) => {
|
||||||
s.begin_list(1);
|
s.begin_list(2);
|
||||||
s.append(&3u8);
|
s.append(&3u8);
|
||||||
|
s.append(err);
|
||||||
},
|
},
|
||||||
Res::None => {
|
Res::None => {
|
||||||
s.begin_list(1);
|
s.begin_list(1);
|
||||||
@ -365,8 +368,8 @@ impl Decodable for Res {
|
|||||||
match action_type {
|
match action_type {
|
||||||
0 => d.val_at(1).map(Res::Call),
|
0 => d.val_at(1).map(Res::Call),
|
||||||
1 => d.val_at(1).map(Res::Create),
|
1 => d.val_at(1).map(Res::Create),
|
||||||
2 => Ok(Res::FailedCall),
|
2 => d.val_at(1).map(Res::FailedCall),
|
||||||
3 => Ok(Res::FailedCreate),
|
3 => d.val_at(1).map(Res::FailedCreate),
|
||||||
4 => Ok(Res::None),
|
4 => Ok(Res::None),
|
||||||
_ => Err(DecoderError::Custom("Invalid result type.")),
|
_ => Err(DecoderError::Custom("Invalid result type.")),
|
||||||
}
|
}
|
||||||
@ -378,7 +381,7 @@ impl Res {
|
|||||||
pub fn bloom(&self) -> LogBloom {
|
pub fn bloom(&self) -> LogBloom {
|
||||||
match *self {
|
match *self {
|
||||||
Res::Create(ref create) => create.bloom(),
|
Res::Create(ref create) => create.bloom(),
|
||||||
Res::Call(_) | Res::FailedCall | Res::FailedCreate | Res::None => Default::default(),
|
Res::Call(_) | Res::FailedCall(_) | Res::FailedCreate(_) | Res::None => Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,8 +16,7 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
use ethcore::trace::trace;
|
use ethcore::trace::{FlatTrace, LocalizedTrace as EthLocalizedTrace, trace, TraceError};
|
||||||
use ethcore::trace::{FlatTrace, 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;
|
||||||
@ -319,16 +318,13 @@ impl From<trace::Suicide> for Suicide {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Action
|
/// Action
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
/// Call
|
/// Call
|
||||||
#[serde(rename="call")]
|
|
||||||
Call(Call),
|
Call(Call),
|
||||||
/// Create
|
/// Create
|
||||||
#[serde(rename="create")]
|
|
||||||
Create(Create),
|
Create(Create),
|
||||||
/// Suicide
|
/// Suicide
|
||||||
#[serde(rename="suicide")]
|
|
||||||
Suicide(Suicide),
|
Suicide(Suicide),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,22 +380,17 @@ impl From<trace::CreateResult> for CreateResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Response
|
/// Response
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub enum Res {
|
pub enum Res {
|
||||||
/// Call
|
/// Call
|
||||||
#[serde(rename="call")]
|
|
||||||
Call(CallResult),
|
Call(CallResult),
|
||||||
/// Create
|
/// Create
|
||||||
#[serde(rename="create")]
|
|
||||||
Create(CreateResult),
|
Create(CreateResult),
|
||||||
/// Call failure
|
/// Call failure
|
||||||
#[serde(rename="failedCall")]
|
FailedCall(TraceError),
|
||||||
FailedCall,
|
|
||||||
/// Creation failure
|
/// Creation failure
|
||||||
#[serde(rename="failedCreate")]
|
FailedCreate(TraceError),
|
||||||
FailedCreate,
|
|
||||||
/// None
|
/// None
|
||||||
#[serde(rename="none")]
|
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,39 +399,73 @@ impl From<trace::Res> for Res {
|
|||||||
match t {
|
match t {
|
||||||
trace::Res::Call(call) => Res::Call(CallResult::from(call)),
|
trace::Res::Call(call) => Res::Call(CallResult::from(call)),
|
||||||
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
||||||
trace::Res::FailedCall => Res::FailedCall,
|
trace::Res::FailedCall(error) => Res::FailedCall(error),
|
||||||
trace::Res::FailedCreate => Res::FailedCreate,
|
trace::Res::FailedCreate(error) => Res::FailedCreate(error),
|
||||||
trace::Res::None => Res::None,
|
trace::Res::None => Res::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trace
|
/// Trace
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct LocalizedTrace {
|
pub struct LocalizedTrace {
|
||||||
/// Action
|
/// Action
|
||||||
action: Action,
|
action: Action,
|
||||||
/// Result
|
/// Result
|
||||||
result: Res,
|
result: Res,
|
||||||
/// Trace address
|
/// Trace address
|
||||||
#[serde(rename="traceAddress")]
|
|
||||||
trace_address: Vec<U256>,
|
trace_address: Vec<U256>,
|
||||||
/// Subtraces
|
/// Subtraces
|
||||||
subtraces: U256,
|
subtraces: U256,
|
||||||
/// Transaction position
|
/// Transaction position
|
||||||
#[serde(rename="transactionPosition")]
|
|
||||||
transaction_position: U256,
|
transaction_position: U256,
|
||||||
/// Transaction hash
|
/// Transaction hash
|
||||||
#[serde(rename="transactionHash")]
|
|
||||||
transaction_hash: H256,
|
transaction_hash: H256,
|
||||||
/// Block Number
|
/// Block Number
|
||||||
#[serde(rename="blockNumber")]
|
|
||||||
block_number: U256,
|
block_number: U256,
|
||||||
/// Block Hash
|
/// Block Hash
|
||||||
#[serde(rename="blockHash")]
|
|
||||||
block_hash: H256,
|
block_hash: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for LocalizedTrace {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
let mut state = try!(serializer.serialize_struct("LocalizedTrace", 9));
|
||||||
|
match self.action {
|
||||||
|
Action::Call(ref call) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "call"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", call));
|
||||||
|
},
|
||||||
|
Action::Create(ref create) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "create"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", create));
|
||||||
|
},
|
||||||
|
Action::Suicide(ref suicide) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "suicide"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", suicide));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.result {
|
||||||
|
Res::Call(ref call) => try!(serializer.serialize_struct_elt(&mut state, "result", call)),
|
||||||
|
Res::Create(ref create) => try!(serializer.serialize_struct_elt(&mut state, "result", create)),
|
||||||
|
Res::FailedCall(ref error) => try!(serializer.serialize_struct_elt(&mut state, "error", error.to_string())),
|
||||||
|
Res::FailedCreate(ref error) => try!(serializer.serialize_struct_elt(&mut state, "error", error.to_string())),
|
||||||
|
Res::None => try!(serializer.serialize_struct_elt(&mut state, "result", None as Option<u8>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "traceAddress", &self.trace_address));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "subtraces", &self.subtraces));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "transactionPosition", &self.transaction_position));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "transactionHash", &self.transaction_hash));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "blockNumber", &self.block_number));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "blockHash", &self.block_hash));
|
||||||
|
|
||||||
|
serializer.serialize_struct_end(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<EthLocalizedTrace> for LocalizedTrace {
|
impl From<EthLocalizedTrace> for LocalizedTrace {
|
||||||
fn from(t: EthLocalizedTrace) -> Self {
|
fn from(t: EthLocalizedTrace) -> Self {
|
||||||
LocalizedTrace {
|
LocalizedTrace {
|
||||||
@ -457,10 +482,9 @@ impl From<EthLocalizedTrace> for LocalizedTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Trace
|
/// Trace
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug)]
|
||||||
pub struct Trace {
|
pub struct Trace {
|
||||||
/// Trace address
|
/// Trace address
|
||||||
#[serde(rename="traceAddress")]
|
|
||||||
trace_address: Vec<U256>,
|
trace_address: Vec<U256>,
|
||||||
/// Subtraces
|
/// Subtraces
|
||||||
subtraces: U256,
|
subtraces: U256,
|
||||||
@ -470,6 +494,41 @@ pub struct Trace {
|
|||||||
result: Res,
|
result: Res,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for Trace {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
let mut state = try!(serializer.serialize_struct("Trace", 4));
|
||||||
|
match self.action {
|
||||||
|
Action::Call(ref call) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "call"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", call));
|
||||||
|
},
|
||||||
|
Action::Create(ref create) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "create"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", create));
|
||||||
|
},
|
||||||
|
Action::Suicide(ref suicide) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "type", "suicide"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "action", suicide));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.result {
|
||||||
|
Res::Call(ref call) => try!(serializer.serialize_struct_elt(&mut state, "result", call)),
|
||||||
|
Res::Create(ref create) => try!(serializer.serialize_struct_elt(&mut state, "result", create)),
|
||||||
|
Res::FailedCall(ref error) => try!(serializer.serialize_struct_elt(&mut state, "error", error.to_string())),
|
||||||
|
Res::FailedCreate(ref error) => try!(serializer.serialize_struct_elt(&mut state, "error", error.to_string())),
|
||||||
|
Res::None => try!(serializer.serialize_struct_elt(&mut state, "result", None as Option<u8>)),
|
||||||
|
}
|
||||||
|
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "traceAddress", &self.trace_address));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "subtraces", &self.subtraces));
|
||||||
|
|
||||||
|
serializer.serialize_struct_end(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<FlatTrace> for Trace {
|
impl From<FlatTrace> for Trace {
|
||||||
fn from(t: FlatTrace) -> Self {
|
fn from(t: FlatTrace) -> Self {
|
||||||
Trace {
|
Trace {
|
||||||
@ -511,7 +570,8 @@ impl From<Executed> for TraceResults {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use v1::types::{Bytes, U256, H256, H160};
|
use v1::types::Bytes;
|
||||||
|
use ethcore::trace::TraceError;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -527,29 +587,118 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_trace_serialize() {
|
fn test_trace_call_serialize() {
|
||||||
let t = LocalizedTrace {
|
let t = LocalizedTrace {
|
||||||
action: Action::Call(Call {
|
action: Action::Call(Call {
|
||||||
from: H160::from(4),
|
from: 4.into(),
|
||||||
to: H160::from(5),
|
to: 5.into(),
|
||||||
value: U256::from(6),
|
value: 6.into(),
|
||||||
gas: U256::from(7),
|
gas: 7.into(),
|
||||||
input: Bytes::new(vec![0x12, 0x34]),
|
input: Bytes::new(vec![0x12, 0x34]),
|
||||||
call_type: CallType::Call,
|
call_type: CallType::Call,
|
||||||
}),
|
}),
|
||||||
result: Res::Call(CallResult {
|
result: Res::Call(CallResult {
|
||||||
gas_used: U256::from(8),
|
gas_used: 8.into(),
|
||||||
output: vec![0x56, 0x78].into(),
|
output: vec![0x56, 0x78].into(),
|
||||||
}),
|
}),
|
||||||
trace_address: vec![U256::from(10)],
|
trace_address: vec![10.into()],
|
||||||
subtraces: U256::from(1),
|
subtraces: 1.into(),
|
||||||
transaction_position: U256::from(11),
|
transaction_position: 11.into(),
|
||||||
transaction_hash: H256::from(12),
|
transaction_hash: 12.into(),
|
||||||
block_number: U256::from(13),
|
block_number: 13.into(),
|
||||||
block_hash: H256::from(14),
|
block_hash: 14.into(),
|
||||||
};
|
};
|
||||||
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":"0x6","gas":"0x7","input":"0x1234","callType":"call"}},"result":{"call":{"gasUsed":"0x8","output":"0x5678"}},"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"result":{"gasUsed":"0x8","output":"0x5678"},"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trace_failed_call_serialize() {
|
||||||
|
let t = LocalizedTrace {
|
||||||
|
action: Action::Call(Call {
|
||||||
|
from: 4.into(),
|
||||||
|
to: 5.into(),
|
||||||
|
value: 6.into(),
|
||||||
|
gas: 7.into(),
|
||||||
|
input: Bytes::new(vec![0x12, 0x34]),
|
||||||
|
call_type: CallType::Call,
|
||||||
|
}),
|
||||||
|
result: Res::FailedCall(TraceError::OutOfGas),
|
||||||
|
trace_address: vec![10.into()],
|
||||||
|
subtraces: 1.into(),
|
||||||
|
transaction_position: 11.into(),
|
||||||
|
transaction_hash: 12.into(),
|
||||||
|
block_number: 13.into(),
|
||||||
|
block_hash: 14.into(),
|
||||||
|
};
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"type":"call","action":{"from":"0x0000000000000000000000000000000000000004","to":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","input":"0x1234","callType":"call"},"error":"Out of gas","traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trace_create_serialize() {
|
||||||
|
let t = LocalizedTrace {
|
||||||
|
action: Action::Create(Create {
|
||||||
|
from: 4.into(),
|
||||||
|
value: 6.into(),
|
||||||
|
gas: 7.into(),
|
||||||
|
init: Bytes::new(vec![0x12, 0x34]),
|
||||||
|
}),
|
||||||
|
result: Res::Create(CreateResult {
|
||||||
|
gas_used: 8.into(),
|
||||||
|
code: vec![0x56, 0x78].into(),
|
||||||
|
address: 0xff.into(),
|
||||||
|
}),
|
||||||
|
trace_address: vec![10.into()],
|
||||||
|
subtraces: 1.into(),
|
||||||
|
transaction_position: 11.into(),
|
||||||
|
transaction_hash: 12.into(),
|
||||||
|
block_number: 13.into(),
|
||||||
|
block_hash: 14.into(),
|
||||||
|
};
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"result":{"gasUsed":"0x8","code":"0x5678","address":"0x00000000000000000000000000000000000000ff"},"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trace_failed_create_serialize() {
|
||||||
|
let t = LocalizedTrace {
|
||||||
|
action: Action::Create(Create {
|
||||||
|
from: 4.into(),
|
||||||
|
value: 6.into(),
|
||||||
|
gas: 7.into(),
|
||||||
|
init: Bytes::new(vec![0x12, 0x34]),
|
||||||
|
}),
|
||||||
|
result: Res::FailedCreate(TraceError::OutOfGas),
|
||||||
|
trace_address: vec![10.into()],
|
||||||
|
subtraces: 1.into(),
|
||||||
|
transaction_position: 11.into(),
|
||||||
|
transaction_hash: 12.into(),
|
||||||
|
block_number: 13.into(),
|
||||||
|
block_hash: 14.into(),
|
||||||
|
};
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"type":"create","action":{"from":"0x0000000000000000000000000000000000000004","value":"0x6","gas":"0x7","init":"0x1234"},"error":"Out of gas","traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_trace_suicide_serialize() {
|
||||||
|
let t = LocalizedTrace {
|
||||||
|
action: Action::Suicide(Suicide {
|
||||||
|
address: 4.into(),
|
||||||
|
refund_address: 6.into(),
|
||||||
|
balance: 7.into(),
|
||||||
|
}),
|
||||||
|
result: Res::None,
|
||||||
|
trace_address: vec![10.into()],
|
||||||
|
subtraces: 1.into(),
|
||||||
|
transaction_position: 11.into(),
|
||||||
|
transaction_hash: 12.into(),
|
||||||
|
block_number: 13.into(),
|
||||||
|
block_hash: 14.into(),
|
||||||
|
};
|
||||||
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
|
assert_eq!(serialized, r#"{"type":"suicide","action":{"address":"0x0000000000000000000000000000000000000004","refundAddress":"0x0000000000000000000000000000000000000006","balance":"0x7"},"result":null,"traceAddress":["0xa"],"subtraces":"0x1","transactionPosition":"0xb","transactionHash":"0x000000000000000000000000000000000000000000000000000000000000000c","blockNumber":"0xd","blockHash":"0x000000000000000000000000000000000000000000000000000000000000000e"}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -616,44 +765,4 @@ mod tests {
|
|||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"0x000000000000000000000000000000000000002a":{"balance":"=","nonce":{"+":"0x1"},"code":"=","storage":{"0x000000000000000000000000000000000000000000000000000000000000002a":"="}},"0x0000000000000000000000000000000000000045":{"balance":"=","nonce":{"*":{"from":"0x1","to":"0x0"}},"code":{"-":"0x60"},"storage":{}}}"#);
|
assert_eq!(serialized, r#"{"0x000000000000000000000000000000000000002a":{"balance":"=","nonce":{"+":"0x1"},"code":"=","storage":{"0x000000000000000000000000000000000000000000000000000000000000002a":"="}},"0x0000000000000000000000000000000000000045":{"balance":"=","nonce":{"*":{"from":"0x1","to":"0x0"}},"code":{"-":"0x60"},"storage":{}}}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_action_serialize() {
|
|
||||||
let actions = vec![Action::Call(Call {
|
|
||||||
from: H160::from(1),
|
|
||||||
to: H160::from(2),
|
|
||||||
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),
|
|
||||||
gas: U256::from(7),
|
|
||||||
init: vec![0x56, 0x78].into(),
|
|
||||||
})];
|
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&actions).unwrap();
|
|
||||||
assert_eq!(serialized, r#"[{"call":{"from":"0x0000000000000000000000000000000000000001","to":"0x0000000000000000000000000000000000000002","value":"0x3","gas":"0x4","input":"0x1234","callType":"call"}},{"create":{"from":"0x0000000000000000000000000000000000000005","value":"0x6","gas":"0x7","init":"0x5678"}}]"#);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_result_serialize() {
|
|
||||||
let results = vec![
|
|
||||||
Res::Call(CallResult {
|
|
||||||
gas_used: U256::from(1),
|
|
||||||
output: vec![0x12, 0x34].into(),
|
|
||||||
}),
|
|
||||||
Res::Create(CreateResult {
|
|
||||||
gas_used: U256::from(2),
|
|
||||||
code: vec![0x45, 0x56].into(),
|
|
||||||
address: H160::from(3),
|
|
||||||
}),
|
|
||||||
Res::FailedCall,
|
|
||||||
Res::FailedCreate,
|
|
||||||
];
|
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&results).unwrap();
|
|
||||||
assert_eq!(serialized, r#"[{"call":{"gasUsed":"0x1","output":"0x1234"}},{"create":{"gasUsed":"0x2","code":"0x4556","address":"0x0000000000000000000000000000000000000003"}},"failedCall","failedCreate"]"#);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user