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.state.transfer_balance(&address, refund_address, &balance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.tracer.trace_suicide(address, balance, refund_address.clone(), self.depth + 1);
|
||||||
self.substate.suicides.insert(address);
|
self.substate.suicides.insert(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ impl State {
|
|||||||
/// Reset the code of account `a` so that it is `code`.
|
/// Reset the code of account `a` so that it is `code`.
|
||||||
pub fn reset_code(&mut self, a: &Address, code: Bytes) {
|
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);
|
self.require_or_from(a, true, || Account::new_contract(0.into(), self.account_start_nonce), |_|{}).reset_code(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a given transaction.
|
/// Execute a given transaction.
|
||||||
/// This will change the state accordingly.
|
/// This will change the state accordingly.
|
||||||
@ -1154,6 +1154,58 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
|
|||||||
assert_eq!(result.trace, expected_trace);
|
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]
|
#[test]
|
||||||
fn code_from_database() {
|
fn code_from_database() {
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
use action_params::ActionParams;
|
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};
|
use trace::{Tracer, VMTracer};
|
||||||
|
|
||||||
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
/// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls.
|
||||||
@ -97,6 +97,20 @@ impl Tracer for ExecutiveTracer {
|
|||||||
self.traces.push(trace);
|
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 {
|
fn subtracer(&self) -> Self {
|
||||||
ExecutiveTracer::default()
|
ExecutiveTracer::default()
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,9 @@ pub trait Tracer: Send {
|
|||||||
/// Stores failed create trace.
|
/// Stores failed create trace.
|
||||||
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>);
|
fn trace_failed_create(&mut self, create: Option<Create>, depth: usize, subs: Vec<Trace>);
|
||||||
|
|
||||||
|
/// 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.
|
/// Spawn subtracer which will be used to trace deeper levels of execution.
|
||||||
fn subtracer(&self) -> Self where Self: Sized;
|
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");
|
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 {
|
fn subtracer(&self) -> Self {
|
||||||
NoopTracer
|
NoopTracer
|
||||||
}
|
}
|
||||||
|
@ -121,15 +121,20 @@ impl Filter {
|
|||||||
let to_matches = self.to_address.matches_all();
|
let to_matches = self.to_address.matches_all();
|
||||||
from_matches && to_matches
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use util::{FixedHash, Address, U256};
|
use util::{FixedHash, Address};
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use trace::trace::{Action, Call, Res};
|
use trace::trace::{Action, Call, Res, Suicide};
|
||||||
use trace::flat::FlatTrace;
|
use trace::flat::FlatTrace;
|
||||||
use trace::{Filter, AddressesFilter};
|
use trace::{Filter, AddressesFilter};
|
||||||
use basic_types::LogBloom;
|
use basic_types::LogBloom;
|
||||||
@ -270,10 +275,10 @@ mod tests {
|
|||||||
|
|
||||||
let trace = FlatTrace {
|
let trace = FlatTrace {
|
||||||
action: Action::Call(Call {
|
action: Action::Call(Call {
|
||||||
from: Address::from(1),
|
from: 1.into(),
|
||||||
to: Address::from(2),
|
to: 2.into(),
|
||||||
value: U256::from(3),
|
value: 3.into(),
|
||||||
gas: U256::from(4),
|
gas: 4.into(),
|
||||||
input: vec![0x5],
|
input: vec![0x5],
|
||||||
}),
|
}),
|
||||||
result: Res::FailedCall,
|
result: Res::FailedCall,
|
||||||
@ -288,5 +293,24 @@ mod tests {
|
|||||||
assert!(f4.matches(&trace));
|
assert!(f4.matches(&trace));
|
||||||
assert!(f5.matches(&trace));
|
assert!(f5.matches(&trace));
|
||||||
assert!(!f6.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.
|
/// Description of an action that we trace; will be either a call or a create.
|
||||||
#[derive(Debug, Clone, PartialEq, Binary)]
|
#[derive(Debug, Clone, PartialEq, Binary)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
@ -212,6 +254,8 @@ pub enum Action {
|
|||||||
Call(Call),
|
Call(Call),
|
||||||
/// It's a create action.
|
/// It's a create action.
|
||||||
Create(Create),
|
Create(Create),
|
||||||
|
/// Suicide.
|
||||||
|
Suicide(Suicide),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for Action {
|
impl Encodable for Action {
|
||||||
@ -225,6 +269,10 @@ impl Encodable for Action {
|
|||||||
Action::Create(ref create) => {
|
Action::Create(ref create) => {
|
||||||
s.append(&1u8);
|
s.append(&1u8);
|
||||||
s.append(create);
|
s.append(create);
|
||||||
|
},
|
||||||
|
Action::Suicide(ref suicide) => {
|
||||||
|
s.append(&2u8);
|
||||||
|
s.append(suicide);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,6 +285,7 @@ impl Decodable for Action {
|
|||||||
match action_type {
|
match action_type {
|
||||||
0 => d.val_at(1).map(Action::Call),
|
0 => d.val_at(1).map(Action::Call),
|
||||||
1 => d.val_at(1).map(Action::Create),
|
1 => d.val_at(1).map(Action::Create),
|
||||||
|
2 => d.val_at(2).map(Action::Suicide),
|
||||||
_ => Err(DecoderError::Custom("Invalid action type.")),
|
_ => Err(DecoderError::Custom("Invalid action type.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -248,6 +297,7 @@ impl Action {
|
|||||||
match *self {
|
match *self {
|
||||||
Action::Call(ref call) => call.bloom(),
|
Action::Call(ref call) => call.bloom(),
|
||||||
Action::Create(ref create) => create.bloom(),
|
Action::Create(ref create) => create.bloom(),
|
||||||
|
Action::Suicide(ref suicide) => suicide.bloom(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,6 +313,8 @@ pub enum Res {
|
|||||||
FailedCall,
|
FailedCall,
|
||||||
/// Failed create.
|
/// Failed create.
|
||||||
FailedCreate,
|
FailedCreate,
|
||||||
|
/// None
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for Res {
|
impl Encodable for Res {
|
||||||
@ -285,6 +337,10 @@ impl Encodable for Res {
|
|||||||
Res::FailedCreate => {
|
Res::FailedCreate => {
|
||||||
s.begin_list(1);
|
s.begin_list(1);
|
||||||
s.append(&3u8);
|
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),
|
1 => d.val_at(1).map(Res::Create),
|
||||||
2 => Ok(Res::FailedCall),
|
2 => Ok(Res::FailedCall),
|
||||||
3 => Ok(Res::FailedCreate),
|
3 => Ok(Res::FailedCreate),
|
||||||
|
4 => Ok(Res::None),
|
||||||
_ => Err(DecoderError::Custom("Invalid result type.")),
|
_ => Err(DecoderError::Custom("Invalid result type.")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,7 +575,7 @@ mod tests {
|
|||||||
use util::{Address, U256, FixedHash};
|
use util::{Address, U256, FixedHash};
|
||||||
use util::rlp::{encode, decode};
|
use util::rlp::{encode, decode};
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use trace::trace::{Call, CallResult, Create, Res, Action, Trace};
|
use trace::trace::{Call, CallResult, Create, Res, Action, Trace, Suicide};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn traces_rlp() {
|
fn traces_rlp() {
|
||||||
@ -577,6 +634,16 @@ mod tests {
|
|||||||
}),
|
}),
|
||||||
subs: vec![],
|
subs: vec![],
|
||||||
result: Res::FailedCreate
|
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 {
|
result: Res::Call(CallResult {
|
||||||
@ -592,5 +659,8 @@ mod tests {
|
|||||||
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
|
assert!(bloom.contains_bloomed(&Address::from(2).sha3()));
|
||||||
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
|
assert!(!bloom.contains_bloomed(&Address::from(20).sha3()));
|
||||||
assert!(bloom.contains_bloomed(&Address::from(6).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
|
/// Action
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
pub enum Action {
|
pub enum Action {
|
||||||
@ -269,13 +291,17 @@ pub enum Action {
|
|||||||
/// Create
|
/// Create
|
||||||
#[serde(rename="create")]
|
#[serde(rename="create")]
|
||||||
Create(Create),
|
Create(Create),
|
||||||
|
/// Suicide
|
||||||
|
#[serde(rename="suicide")]
|
||||||
|
Suicide(Suicide),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<trace::Action> for Action {
|
impl From<trace::Action> for Action {
|
||||||
fn from(c: trace::Action) -> Self {
|
fn from(c: trace::Action) -> Self {
|
||||||
match c {
|
match c {
|
||||||
trace::Action::Call(call) => Action::Call(Call::from(call)),
|
trace::Action::Call(call) => Action::Call(call.into()),
|
||||||
trace::Action::Create(create) => Action::Create(Create::from(create)),
|
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
|
/// Creation failure
|
||||||
#[serde(rename="failedCreate")]
|
#[serde(rename="failedCreate")]
|
||||||
FailedCreate,
|
FailedCreate,
|
||||||
|
/// None
|
||||||
|
#[serde(rename="none")]
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<trace::Res> for Res {
|
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::Create(create) => Res::Create(CreateResult::from(create)),
|
||||||
trace::Res::FailedCall => Res::FailedCall,
|
trace::Res::FailedCall => Res::FailedCall,
|
||||||
trace::Res::FailedCreate => Res::FailedCreate,
|
trace::Res::FailedCreate => Res::FailedCreate,
|
||||||
|
trace::Res::None => Res::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user