Moving all Client public API types to separate mod & binary serialization codegen for that mod (#1051)
* transaction moved * trash remove * ids move * receipt * tree-route * blockchain info * log_entry move * trace filter moved * executed & trace moved * localized trace moved * block status moved * build scripts and codegen refs * Cargo.lock update * binary for blockstatus, blockchaininfo * binary for trace * trace filters binary ser * binary for log entries & executed * binary for receipt * special case for u8 & transaction binary attribute * resolved remaining issues & error binary serialization * json-tests util import * fix warnings * ids attr * add missing attributes * Update build.rs
This commit is contained in:
@@ -1,283 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use std::ops::Range;
|
||||
use bloomchain::{Filter as BloomFilter, Bloom, Number};
|
||||
use util::{Address, FixedHash};
|
||||
use util::sha3::Hashable;
|
||||
use basic_types::LogBloom;
|
||||
use super::flat::FlatTrace;
|
||||
use super::trace::Action;
|
||||
|
||||
/// Addresses filter.
|
||||
///
|
||||
/// Used to create bloom possibilities and match filters.
|
||||
pub struct AddressesFilter(Vec<Address>);
|
||||
|
||||
impl From<Vec<Address>> for AddressesFilter {
|
||||
fn from(addresses: Vec<Address>) -> Self {
|
||||
AddressesFilter(addresses)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressesFilter {
|
||||
/// Returns true if address matches one of the searched addresses.
|
||||
pub fn matches(&self, address: &Address) -> bool {
|
||||
self.matches_all() || self.0.contains(address)
|
||||
}
|
||||
|
||||
/// Returns true if this address filter matches everything.
|
||||
pub fn matches_all(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// Returns blooms of this addresses filter.
|
||||
pub fn blooms(&self) -> Vec<LogBloom> {
|
||||
match self.0.is_empty() {
|
||||
true => vec![LogBloom::new()],
|
||||
false => self.0.iter()
|
||||
.map(|address| LogBloom::from_bloomed(&address.sha3()))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns vector of blooms zipped with blooms of this addresses filter.
|
||||
pub fn with_blooms(&self, blooms: Vec<LogBloom>) -> Vec<LogBloom> {
|
||||
match self.0.is_empty() {
|
||||
true => blooms,
|
||||
false => blooms
|
||||
.into_iter()
|
||||
.flat_map(|bloom| self.0.iter()
|
||||
.map(|address| bloom.with_bloomed(&address.sha3()))
|
||||
.collect::<Vec<_>>())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Traces filter.
|
||||
pub struct Filter {
|
||||
/// Block range.
|
||||
pub range: Range<usize>,
|
||||
|
||||
/// From address filter.
|
||||
pub from_address: AddressesFilter,
|
||||
|
||||
/// To address filter.
|
||||
pub to_address: AddressesFilter,
|
||||
}
|
||||
|
||||
impl BloomFilter for Filter {
|
||||
fn bloom_possibilities(&self) -> Vec<Bloom> {
|
||||
self.bloom_possibilities()
|
||||
.into_iter()
|
||||
.map(|b| Bloom::from(b.0))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn range(&self) -> Range<Number> {
|
||||
self.range.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
/// Returns combinations of each address.
|
||||
fn bloom_possibilities(&self) -> Vec<LogBloom> {
|
||||
self.to_address.with_blooms(self.from_address.blooms())
|
||||
}
|
||||
|
||||
/// Returns true if given trace matches the filter.
|
||||
pub fn matches(&self, trace: &FlatTrace) -> bool {
|
||||
match trace.action {
|
||||
Action::Call(ref call) => {
|
||||
let from_matches = self.from_address.matches(&call.from);
|
||||
let to_matches = self.to_address.matches(&call.to);
|
||||
from_matches && to_matches
|
||||
},
|
||||
Action::Create(ref create) => {
|
||||
let from_matches = self.from_address.matches(&create.from);
|
||||
let to_matches = self.to_address.matches_all();
|
||||
from_matches && to_matches
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::{FixedHash, Address, U256};
|
||||
use util::sha3::Hashable;
|
||||
use trace::trace::{Action, Call, Res};
|
||||
use trace::flat::FlatTrace;
|
||||
use trace::{Filter, AddressesFilter};
|
||||
use basic_types::LogBloom;
|
||||
|
||||
#[test]
|
||||
fn empty_trace_filter_bloom_possibilities() {
|
||||
let filter = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![]),
|
||||
to_address: AddressesFilter::from(vec![]),
|
||||
};
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
assert_eq!(blooms, vec![LogBloom::new()]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_trace_filter_bloom_possibility() {
|
||||
let filter = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(2)]),
|
||||
};
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
assert_eq!(blooms.len(), 1);
|
||||
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(!blooms[0].contains_bloomed(&Address::from(3).sha3()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_from_trace_filter_bloom_possibility() {
|
||||
let filter = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![]),
|
||||
};
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
assert_eq!(blooms.len(), 1);
|
||||
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(!blooms[0].contains_bloomed(&Address::from(2).sha3()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn only_to_trace_filter_bloom_possibility() {
|
||||
let filter = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
};
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
assert_eq!(blooms.len(), 1);
|
||||
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(!blooms[0].contains_bloomed(&Address::from(2).sha3()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_trace_filter_bloom_possibility() {
|
||||
let filter = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1), Address::from(3)]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(2), Address::from(4)]),
|
||||
};
|
||||
|
||||
let blooms = filter.bloom_possibilities();
|
||||
assert_eq!(blooms.len(), 4);
|
||||
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(blooms[0].contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(!blooms[0].contains_bloomed(&Address::from(3).sha3()));
|
||||
assert!(!blooms[0].contains_bloomed(&Address::from(4).sha3()));
|
||||
|
||||
assert!(blooms[1].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(blooms[1].contains_bloomed(&Address::from(4).sha3()));
|
||||
assert!(!blooms[1].contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(!blooms[1].contains_bloomed(&Address::from(3).sha3()));
|
||||
|
||||
assert!(blooms[2].contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(blooms[2].contains_bloomed(&Address::from(3).sha3()));
|
||||
assert!(!blooms[2].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(!blooms[2].contains_bloomed(&Address::from(4).sha3()));
|
||||
|
||||
assert!(blooms[3].contains_bloomed(&Address::from(3).sha3()));
|
||||
assert!(blooms[3].contains_bloomed(&Address::from(4).sha3()));
|
||||
assert!(!blooms[3].contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(!blooms[3].contains_bloomed(&Address::from(2).sha3()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filter_matches() {
|
||||
let f0 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![]),
|
||||
};
|
||||
|
||||
let f1 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(3), Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![]),
|
||||
};
|
||||
|
||||
let f2 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![]),
|
||||
to_address: AddressesFilter::from(vec![]),
|
||||
};
|
||||
|
||||
let f3 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(2)]),
|
||||
};
|
||||
|
||||
let f4 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(2), Address::from(3)]),
|
||||
};
|
||||
|
||||
let f5 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(2), Address::from(3)]),
|
||||
};
|
||||
|
||||
let f6 = Filter {
|
||||
range: (0..0),
|
||||
from_address: AddressesFilter::from(vec![Address::from(1)]),
|
||||
to_address: AddressesFilter::from(vec![Address::from(4)]),
|
||||
};
|
||||
|
||||
let trace = FlatTrace {
|
||||
action: Action::Call(Call {
|
||||
from: Address::from(1),
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5],
|
||||
}),
|
||||
result: Res::FailedCall,
|
||||
trace_address: vec![0],
|
||||
subtraces: 0,
|
||||
};
|
||||
|
||||
assert!(f0.matches(&trace));
|
||||
assert!(f1.matches(&trace));
|
||||
assert!(f2.matches(&trace));
|
||||
assert!(f3.matches(&trace));
|
||||
assert!(f4.matches(&trace));
|
||||
assert!(f5.matches(&trace));
|
||||
assert!(!f6.matches(&trace));
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Flat trace module
|
||||
|
||||
use trace::BlockTraces;
|
||||
use super::trace::{Trace, Action, Res};
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use util::H256;
|
||||
use super::trace::{Action, Res};
|
||||
use header::BlockNumber;
|
||||
|
||||
/// Localized trace.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct LocalizedTrace {
|
||||
/// Type of action performed by a transaction.
|
||||
pub action: Action,
|
||||
/// Result of this action.
|
||||
pub result: Res,
|
||||
/// Number of subtraces.
|
||||
pub subtraces: usize,
|
||||
/// Exact location of trace.
|
||||
///
|
||||
/// [index in root, index in first CALL, index in second CALL, ...]
|
||||
pub trace_address: Vec<usize>,
|
||||
/// Transaction number within the block.
|
||||
pub transaction_number: usize,
|
||||
/// Signed transaction hash.
|
||||
pub transaction_hash: H256,
|
||||
/// Block number.
|
||||
pub block_number: BlockNumber,
|
||||
/// Block hash.
|
||||
pub block_hash: H256,
|
||||
}
|
||||
@@ -21,20 +21,18 @@ mod bloom;
|
||||
mod config;
|
||||
mod db;
|
||||
mod executive_tracer;
|
||||
mod filter;
|
||||
mod flat;
|
||||
pub mod flat;
|
||||
mod import;
|
||||
mod localized;
|
||||
mod noop_tracer;
|
||||
pub mod trace;
|
||||
|
||||
pub use types::trace_types::*;
|
||||
pub use self::block::BlockTraces;
|
||||
pub use self::config::{Config, Switch};
|
||||
pub use self::db::TraceDB;
|
||||
pub use self::trace::Trace;
|
||||
pub use types::trace_types::trace::Trace;
|
||||
pub use self::noop_tracer::NoopTracer;
|
||||
pub use self::executive_tracer::ExecutiveTracer;
|
||||
pub use self::filter::{Filter, AddressesFilter};
|
||||
pub use types::trace_types::filter::{Filter, AddressesFilter};
|
||||
pub use self::import::ImportRequest;
|
||||
pub use self::localized::LocalizedTrace;
|
||||
use util::{Bytes, Address, U256, H256};
|
||||
|
||||
@@ -1,428 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Tracing datatypes.
|
||||
use util::{U256, Bytes, Address, FixedHash};
|
||||
use util::rlp::*;
|
||||
use util::sha3::Hashable;
|
||||
use action_params::ActionParams;
|
||||
use basic_types::LogBloom;
|
||||
|
||||
/// `Call` result.
|
||||
#[derive(Debug, Clone, PartialEq, Default)]
|
||||
pub struct CallResult {
|
||||
/// Gas used by call.
|
||||
pub gas_used: U256,
|
||||
/// Call Output.
|
||||
pub output: Bytes,
|
||||
}
|
||||
|
||||
impl Encodable for CallResult {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2);
|
||||
s.append(&self.gas_used);
|
||||
s.append(&self.output);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for CallResult {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = CallResult {
|
||||
gas_used: try!(d.val_at(0)),
|
||||
output: try!(d.val_at(1)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// `Create` result.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct CreateResult {
|
||||
/// Gas used by create.
|
||||
pub gas_used: U256,
|
||||
/// Code of the newly created contract.
|
||||
pub code: Bytes,
|
||||
/// Address of the newly created contract.
|
||||
pub address: Address,
|
||||
}
|
||||
|
||||
impl Encodable for CreateResult {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(3);
|
||||
s.append(&self.gas_used);
|
||||
s.append(&self.code);
|
||||
s.append(&self.address);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for CreateResult {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = CreateResult {
|
||||
gas_used: try!(d.val_at(0)),
|
||||
code: try!(d.val_at(1)),
|
||||
address: try!(d.val_at(2)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
/// Description of a _call_ action, either a `CALL` operation or a message transction.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Call {
|
||||
/// The sending account.
|
||||
pub from: Address,
|
||||
/// The destination account.
|
||||
pub to: Address,
|
||||
/// The value transferred to the destination account.
|
||||
pub value: U256,
|
||||
/// The gas available for executing the call.
|
||||
pub gas: U256,
|
||||
/// The input data provided to the call.
|
||||
pub input: Bytes,
|
||||
}
|
||||
|
||||
impl From<ActionParams> for Call {
|
||||
fn from(p: ActionParams) -> Self {
|
||||
Call {
|
||||
from: p.sender,
|
||||
to: p.address,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
input: p.data.unwrap_or_else(Vec::new),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Call {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(5);
|
||||
s.append(&self.from);
|
||||
s.append(&self.to);
|
||||
s.append(&self.value);
|
||||
s.append(&self.gas);
|
||||
s.append(&self.input);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Call {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = Call {
|
||||
from: try!(d.val_at(0)),
|
||||
to: try!(d.val_at(1)),
|
||||
value: try!(d.val_at(2)),
|
||||
gas: try!(d.val_at(3)),
|
||||
input: try!(d.val_at(4)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Call {
|
||||
/// Returns call action bloom.
|
||||
/// The bloom contains from and to addresses.
|
||||
pub fn bloom(&self) -> LogBloom {
|
||||
LogBloom::from_bloomed(&self.from.sha3())
|
||||
.with_bloomed(&self.to.sha3())
|
||||
}
|
||||
}
|
||||
|
||||
/// Description of a _create_ action, either a `CREATE` operation or a create transction.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Create {
|
||||
/// The address of the creator.
|
||||
pub from: Address,
|
||||
/// The value with which the new account is endowed.
|
||||
pub value: U256,
|
||||
/// The gas available for the creation init code.
|
||||
pub gas: U256,
|
||||
/// The init code.
|
||||
pub init: Bytes,
|
||||
}
|
||||
|
||||
impl From<ActionParams> for Create {
|
||||
fn from(p: ActionParams) -> Self {
|
||||
Create {
|
||||
from: p.sender,
|
||||
value: p.value.value(),
|
||||
gas: p.gas,
|
||||
init: p.code.unwrap_or_else(Vec::new),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Create {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4);
|
||||
s.append(&self.from);
|
||||
s.append(&self.value);
|
||||
s.append(&self.gas);
|
||||
s.append(&self.init);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Create {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = Create {
|
||||
from: try!(d.val_at(0)),
|
||||
value: try!(d.val_at(1)),
|
||||
gas: try!(d.val_at(2)),
|
||||
init: try!(d.val_at(3)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Create {
|
||||
/// Returns bloom create action bloom.
|
||||
/// The bloom contains only from address.
|
||||
pub fn bloom(&self) -> LogBloom {
|
||||
LogBloom::from_bloomed(&self.from.sha3())
|
||||
}
|
||||
}
|
||||
|
||||
/// Description of an action that we trace; will be either a call or a create.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Action {
|
||||
/// It's a call action.
|
||||
Call(Call),
|
||||
/// It's a create action.
|
||||
Create(Create),
|
||||
}
|
||||
|
||||
impl Encodable for Action {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(2);
|
||||
match *self {
|
||||
Action::Call(ref call) => {
|
||||
s.append(&0u8);
|
||||
s.append(call);
|
||||
},
|
||||
Action::Create(ref create) => {
|
||||
s.append(&1u8);
|
||||
s.append(create);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Action {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let action_type: u8 = try!(d.val_at(0));
|
||||
match action_type {
|
||||
0 => d.val_at(1).map(Action::Call),
|
||||
1 => d.val_at(1).map(Action::Create),
|
||||
_ => Err(DecoderError::Custom("Invalid action type.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Action {
|
||||
/// Returns action bloom.
|
||||
pub fn bloom(&self) -> LogBloom {
|
||||
match *self {
|
||||
Action::Call(ref call) => call.bloom(),
|
||||
Action::Create(ref create) => create.bloom(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The result of the performed action.
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum Res {
|
||||
/// Successful call action result.
|
||||
Call(CallResult),
|
||||
/// Successful create action result.
|
||||
Create(CreateResult),
|
||||
/// Failed call.
|
||||
FailedCall,
|
||||
/// Failed create.
|
||||
FailedCreate,
|
||||
}
|
||||
|
||||
impl Encodable for Res {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
match *self {
|
||||
Res::Call(ref call) => {
|
||||
s.begin_list(2);
|
||||
s.append(&0u8);
|
||||
s.append(call);
|
||||
},
|
||||
Res::Create(ref create) => {
|
||||
s.begin_list(2);
|
||||
s.append(&1u8);
|
||||
s.append(create);
|
||||
},
|
||||
Res::FailedCall => {
|
||||
s.begin_list(1);
|
||||
s.append(&2u8);
|
||||
},
|
||||
Res::FailedCreate => {
|
||||
s.begin_list(1);
|
||||
s.append(&3u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Res {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let action_type: u8 = try!(d.val_at(0));
|
||||
match action_type {
|
||||
0 => d.val_at(1).map(Res::Call),
|
||||
1 => d.val_at(1).map(Res::Create),
|
||||
2 => Ok(Res::FailedCall),
|
||||
3 => Ok(Res::FailedCreate),
|
||||
_ => Err(DecoderError::Custom("Invalid result type.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
/// A trace; includes a description of the action being traced and sub traces of each interior action.
|
||||
pub struct Trace {
|
||||
/// The number of EVM execution environments active when this action happened; 0 if it's
|
||||
/// the outer action of the transaction.
|
||||
pub depth: usize,
|
||||
/// The action being performed.
|
||||
pub action: Action,
|
||||
/// The sub traces for each interior action performed as part of this call.
|
||||
pub subs: Vec<Trace>,
|
||||
/// The result of the performed action.
|
||||
pub result: Res,
|
||||
}
|
||||
|
||||
impl Encodable for Trace {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(4);
|
||||
s.append(&self.depth);
|
||||
s.append(&self.action);
|
||||
s.append(&self.subs);
|
||||
s.append(&self.result);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Trace {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = Trace {
|
||||
depth: try!(d.val_at(0)),
|
||||
action: try!(d.val_at(1)),
|
||||
subs: try!(d.val_at(2)),
|
||||
result: try!(d.val_at(3)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
impl Trace {
|
||||
/// Returns trace bloom.
|
||||
pub fn bloom(&self) -> LogBloom {
|
||||
self.subs.iter().fold(self.action.bloom(), |b, s| b | s.bloom())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::{Address, U256, FixedHash};
|
||||
use util::rlp::{encode, decode};
|
||||
use util::sha3::Hashable;
|
||||
use trace::trace::{Call, CallResult, Create, Res, Action, Trace};
|
||||
|
||||
#[test]
|
||||
fn traces_rlp() {
|
||||
let trace = Trace {
|
||||
depth: 2,
|
||||
action: Action::Call(Call {
|
||||
from: Address::from(1),
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5]
|
||||
}),
|
||||
subs: vec![
|
||||
Trace {
|
||||
depth: 3,
|
||||
action: Action::Create(Create {
|
||||
from: Address::from(6),
|
||||
value: U256::from(7),
|
||||
gas: U256::from(8),
|
||||
init: vec![0x9]
|
||||
}),
|
||||
subs: vec![],
|
||||
result: Res::FailedCreate
|
||||
}
|
||||
],
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: U256::from(10),
|
||||
output: vec![0x11, 0x12]
|
||||
})
|
||||
};
|
||||
|
||||
let encoded = encode(&trace);
|
||||
let decoded: Trace = decode(&encoded);
|
||||
assert_eq!(trace, decoded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn traces_bloom() {
|
||||
let trace = Trace {
|
||||
depth: 2,
|
||||
action: Action::Call(Call {
|
||||
from: Address::from(1),
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
input: vec![0x5]
|
||||
}),
|
||||
subs: vec![
|
||||
Trace {
|
||||
depth: 3,
|
||||
action: Action::Create(Create {
|
||||
from: Address::from(6),
|
||||
value: U256::from(7),
|
||||
gas: U256::from(8),
|
||||
init: vec![0x9]
|
||||
}),
|
||||
subs: vec![],
|
||||
result: Res::FailedCreate
|
||||
}
|
||||
],
|
||||
result: Res::Call(CallResult {
|
||||
gas_used: U256::from(10),
|
||||
output: vec![0x11, 0x12]
|
||||
})
|
||||
};
|
||||
|
||||
let bloom = trace.bloom();
|
||||
|
||||
// right now only addresses are bloomed
|
||||
assert!(bloom.contains_bloomed(&Address::from(1).sha3()));
|
||||
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
|
||||
assert!(bloom.contains_bloomed(&Address::from(6).sha3()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user