parent
ce00c13c7a
commit
63dbb527cc
@ -263,6 +263,7 @@ impl<'a, T, V> Ext for Externalities<'a, T, V> where T: 'a + Tracer, V: 'a + VMT
|
||||
self.state.transfer_balance(&address, refund_address, &balance);
|
||||
}
|
||||
|
||||
self.tracer.trace_suicide(address, balance, refund_address.clone(), self.depth + 1);
|
||||
self.substate.suicides.insert(address);
|
||||
}
|
||||
|
||||
|
@ -222,7 +222,7 @@ impl State {
|
||||
/// Reset the code of account `a` so that it is `code`.
|
||||
pub fn reset_code(&mut self, a: &Address, code: Bytes) {
|
||||
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).reset_code(code);
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute a given transaction.
|
||||
/// This will change the state accordingly.
|
||||
@ -1154,6 +1154,58 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
||||
assert_eq!(result.trace, expected_trace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_trace_suicide() {
|
||||
init_log();
|
||||
|
||||
let temp = RandomTempPath::new();
|
||||
let mut state = get_temp_state_in(temp.as_path());
|
||||
|
||||
let mut info = EnvInfo::default();
|
||||
info.gas_limit = 1_000_000.into();
|
||||
let engine = TestEngine::new(5);
|
||||
|
||||
let t = Transaction {
|
||||
nonce: 0.into(),
|
||||
gas_price: 0.into(),
|
||||
gas: 100_000.into(),
|
||||
action: Action::Call(0xa.into()),
|
||||
value: 100.into(),
|
||||
data: vec![],
|
||||
}.sign(&"".sha3());
|
||||
|
||||
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
|
||||
state.add_balance(&0xa.into(), &50.into());
|
||||
state.add_balance(t.sender().as_ref().unwrap(), &100.into());
|
||||
let vm_factory = Default::default();
|
||||
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
|
||||
let expected_trace = Some(Trace {
|
||||
depth: 0,
|
||||
action: trace::Action::Call(trace::Call {
|
||||
from: "9cce34f7ab185c7aba1b7c8140d620b4bda941d6".into(),
|
||||
to: 0xa.into(),
|
||||
value: 100.into(),
|
||||
gas: 79000.into(),
|
||||
input: vec![],
|
||||
}),
|
||||
result: trace::Res::Call(trace::CallResult {
|
||||
gas_used: 3.into(),
|
||||
output: vec![]
|
||||
}),
|
||||
subs: vec![Trace {
|
||||
depth: 1,
|
||||
action: trace::Action::Suicide(trace::Suicide {
|
||||
address: 0xa.into(),
|
||||
refund_address: 0xb.into(),
|
||||
balance: 150.into(),
|
||||
}),
|
||||
result: trace::Res::None,
|
||||
subs: vec![]
|
||||
}]
|
||||
});
|
||||
assert_eq!(result.trace, expected_trace);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_from_database() {
|
||||
let a = Address::zero();
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use util::{Bytes, Address, U256};
|
||||
use action_params::ActionParams;
|
||||
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff};
|
||||
use trace::trace::{Trace, Call, Create, Action, Res, CreateResult, CallResult, VMTrace, VMOperation, VMExecutedOperation, MemoryDiff, StorageDiff, Suicide};
|
||||
use trace::{Tracer, VMTracer};
|
||||
|
||||
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
||||
@ -97,6 +97,20 @@ impl Tracer for ExecutiveTracer {
|
||||
self.traces.push(trace);
|
||||
}
|
||||
|
||||
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address, depth: usize) {
|
||||
let trace = Trace {
|
||||
depth: depth,
|
||||
subs: vec![],
|
||||
action: Action::Suicide(Suicide {
|
||||
address: address,
|
||||
refund_address: refund_address,
|
||||
balance: balance,
|
||||
}),
|
||||
result: Res::None,
|
||||
};
|
||||
self.traces.push(trace);
|
||||
}
|
||||
|
||||
fn subtracer(&self) -> Self {
|
||||
ExecutiveTracer::default()
|
||||
}
|
||||
|
@ -81,6 +81,9 @@ pub trait Tracer: Send {
|
||||
/// Stores failed create trace.
|
||||
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>);
|
||||
|
||||
/// Stores suicide info.
|
||||
fn trace_suicide(&mut self, address: Address, balance: U256, refund_address: Address, depth: usize);
|
||||
|
||||
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||
fn subtracer(&self) -> Self where Self: Sized;
|
||||
|
||||
|
@ -55,6 +55,9 @@ impl Tracer for NoopTracer {
|
||||
assert!(create.is_none(), "self.prepare_trace_create().is_none(): so we can't be tracing: qed");
|
||||
}
|
||||
|
||||
fn trace_suicide(&mut self, _address: Address, _balance: U256, _refund_address: Address, _depth: usize) {
|
||||
}
|
||||
|
||||
fn subtracer(&self) -> Self {
|
||||
NoopTracer
|
||||
}
|
||||
|
@ -121,15 +121,20 @@ impl Filter {
|
||||
let to_matches = self.to_address.matches_all();
|
||||
from_matches && to_matches
|
||||
}
|
||||
Action::Suicide(ref suicide) => {
|
||||
let from_matches = self.from_address.matches(&suicide.address);
|
||||
let to_matches = self.to_address.matches(&suicide.refund_address);
|
||||
from_matches && to_matches
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use util::{FixedHash, Address, U256};
|
||||
use util::{FixedHash, Address};
|
||||
use util::sha3::Hashable;
|
||||
use trace::trace::{Action, Call, Res};
|
||||
use trace::trace::{Action, Call, Res, Suicide};
|
||||
use trace::flat::FlatTrace;
|
||||
use trace::{Filter, AddressesFilter};
|
||||
use basic_types::LogBloom;
|
||||
@ -270,10 +275,10 @@ mod tests {
|
||||
|
||||
let trace = FlatTrace {
|
||||
action: Action::Call(Call {
|
||||
from: Address::from(1),
|
||||
to: Address::from(2),
|
||||
value: U256::from(3),
|
||||
gas: U256::from(4),
|
||||
from: 1.into(),
|
||||
to: 2.into(),
|
||||
value: 3.into(),
|
||||
gas: 4.into(),
|
||||
input: vec![0x5],
|
||||
}),
|
||||
result: Res::FailedCall,
|
||||
@ -288,5 +293,24 @@ mod tests {
|
||||
assert!(f4.matches(&trace));
|
||||
assert!(f5.matches(&trace));
|
||||
assert!(!f6.matches(&trace));
|
||||
|
||||
let trace = FlatTrace {
|
||||
action: Action::Suicide(Suicide {
|
||||
address: 1.into(),
|
||||
refund_address: 2.into(),
|
||||
balance: 3.into(),
|
||||
}),
|
||||
result: Res::None,
|
||||
trace_address: vec![],
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
@ -205,6 +205,48 @@ impl Create {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suicide action.
|
||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||
pub struct Suicide {
|
||||
/// Suicided address.
|
||||
pub address: Address,
|
||||
/// Suicided contract heir.
|
||||
pub refund_address: Address,
|
||||
/// Balance of the contract just before suicide.
|
||||
pub balance: U256,
|
||||
}
|
||||
|
||||
impl Suicide {
|
||||
/// Return suicide action bloom.
|
||||
pub fn bloom(&self) -> LogBloom {
|
||||
LogBloom::from_bloomed(&self.address.sha3())
|
||||
.with_bloomed(&self.refund_address.sha3())
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for Suicide {
|
||||
fn rlp_append(&self, s: &mut RlpStream) {
|
||||
s.begin_list(3);
|
||||
s.append(&self.address);
|
||||
s.append(&self.refund_address);
|
||||
s.append(&self.balance);
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for Suicide {
|
||||
fn decode<D>(decoder: &D) -> Result<Self, DecoderError> where D: Decoder {
|
||||
let d = decoder.as_rlp();
|
||||
let res = Suicide {
|
||||
address: try!(d.val_at(0)),
|
||||
refund_address: try!(d.val_at(1)),
|
||||
balance: try!(d.val_at(3)),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Description of an action that we trace; will be either a call or a create.
|
||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||
pub enum Action {
|
||||
@ -212,6 +254,8 @@ pub enum Action {
|
||||
Call(Call),
|
||||
/// It's a create action.
|
||||
Create(Create),
|
||||
/// Suicide.
|
||||
Suicide(Suicide),
|
||||
}
|
||||
|
||||
impl Encodable for Action {
|
||||
@ -225,6 +269,10 @@ impl Encodable for Action {
|
||||
Action::Create(ref create) => {
|
||||
s.append(&1u8);
|
||||
s.append(create);
|
||||
},
|
||||
Action::Suicide(ref suicide) => {
|
||||
s.append(&2u8);
|
||||
s.append(suicide);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -237,6 +285,7 @@ impl Decodable for Action {
|
||||
match action_type {
|
||||
0 => d.val_at(1).map(Action::Call),
|
||||
1 => d.val_at(1).map(Action::Create),
|
||||
2 => d.val_at(2).map(Action::Suicide),
|
||||
_ => Err(DecoderError::Custom("Invalid action type.")),
|
||||
}
|
||||
}
|
||||
@ -248,6 +297,7 @@ impl Action {
|
||||
match *self {
|
||||
Action::Call(ref call) => call.bloom(),
|
||||
Action::Create(ref create) => create.bloom(),
|
||||
Action::Suicide(ref suicide) => suicide.bloom(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -263,6 +313,8 @@ pub enum Res {
|
||||
FailedCall,
|
||||
/// Failed create.
|
||||
FailedCreate,
|
||||
/// None
|
||||
None,
|
||||
}
|
||||
|
||||
impl Encodable for Res {
|
||||
@ -285,6 +337,10 @@ impl Encodable for Res {
|
||||
Res::FailedCreate => {
|
||||
s.begin_list(1);
|
||||
s.append(&3u8);
|
||||
},
|
||||
Res::None => {
|
||||
s.begin_list(1);
|
||||
s.append(&4u8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -299,6 +355,7 @@ impl Decodable for Res {
|
||||
1 => d.val_at(1).map(Res::Create),
|
||||
2 => Ok(Res::FailedCall),
|
||||
3 => Ok(Res::FailedCreate),
|
||||
4 => Ok(Res::None),
|
||||
_ => Err(DecoderError::Custom("Invalid result type.")),
|
||||
}
|
||||
}
|
||||
@ -518,7 +575,7 @@ 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};
|
||||
use trace::trace::{Call, CallResult, Create, Res, Action, Trace, Suicide};
|
||||
|
||||
#[test]
|
||||
fn traces_rlp() {
|
||||
@ -577,6 +634,16 @@ mod tests {
|
||||
}),
|
||||
subs: vec![],
|
||||
result: Res::FailedCreate
|
||||
},
|
||||
Trace {
|
||||
depth: 3,
|
||||
action: Action::Suicide(Suicide {
|
||||
address: 101.into(),
|
||||
refund_address: 102.into(),
|
||||
balance: 0.into(),
|
||||
}),
|
||||
subs: vec![],
|
||||
result: Res::None,
|
||||
}
|
||||
],
|
||||
result: Res::Call(CallResult {
|
||||
@ -592,5 +659,8 @@ mod tests {
|
||||
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
|
||||
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
|
||||
assert!(bloom.contains_bloomed(&Address::from(6).sha3()));
|
||||
assert!(bloom.contains_bloomed(&Address::from(101).sha3()));
|
||||
assert!(bloom.contains_bloomed(&Address::from(102).sha3()));
|
||||
assert!(!bloom.contains_bloomed(&Address::from(103).sha3()));
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +260,28 @@ impl From<trace::Call> for Call {
|
||||
}
|
||||
}
|
||||
|
||||
/// Suicide
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct Suicide {
|
||||
/// Address.
|
||||
pub address: H160,
|
||||
/// Refund address.
|
||||
#[serde(rename="refundAddress")]
|
||||
pub refund_address: H160,
|
||||
/// Balance.
|
||||
pub balance: U256,
|
||||
}
|
||||
|
||||
impl From<trace::Suicide> for Suicide {
|
||||
fn from(s: trace::Suicide) -> Self {
|
||||
Suicide {
|
||||
address: s.address.into(),
|
||||
refund_address: s.refund_address.into(),
|
||||
balance: s.balance.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Action
|
||||
#[derive(Debug, Serialize)]
|
||||
pub enum Action {
|
||||
@ -269,13 +291,17 @@ pub enum Action {
|
||||
/// Create
|
||||
#[serde(rename="create")]
|
||||
Create(Create),
|
||||
/// Suicide
|
||||
#[serde(rename="suicide")]
|
||||
Suicide(Suicide),
|
||||
}
|
||||
|
||||
impl From<trace::Action> for Action {
|
||||
fn from(c: trace::Action) -> Self {
|
||||
match c {
|
||||
trace::Action::Call(call) => Action::Call(Call::from(call)),
|
||||
trace::Action::Create(create) => Action::Create(Create::from(create)),
|
||||
trace::Action::Call(call) => Action::Call(call.into()),
|
||||
trace::Action::Create(create) => Action::Create(create.into()),
|
||||
trace::Action::Suicide(suicide) => Action::Suicide(suicide.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,6 +362,9 @@ pub enum Res {
|
||||
/// Creation failure
|
||||
#[serde(rename="failedCreate")]
|
||||
FailedCreate,
|
||||
/// None
|
||||
#[serde(rename="none")]
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<trace::Res> for Res {
|
||||
@ -345,6 +374,7 @@ impl From<trace::Res> for Res {
|
||||
trace::Res::Create(create) => Res::Create(CreateResult::from(create)),
|
||||
trace::Res::FailedCall => Res::FailedCall,
|
||||
trace::Res::FailedCreate => Res::FailedCreate,
|
||||
trace::Res::None => Res::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user