Tracing implemented.
TODO: - make it optional; - track output; - usher through to level higher than ExecutionResult.
This commit is contained in:
parent
2309e19fd9
commit
bd338a5741
@ -65,7 +65,7 @@ pub enum Error {
|
|||||||
|
|
||||||
/// Evm result.
|
/// Evm result.
|
||||||
///
|
///
|
||||||
/// Returns gas_left if execution is successfull, otherwise error.
|
/// Returns gas_left if execution is successful, otherwise error.
|
||||||
pub type Result = result::Result<U256, Error>;
|
pub type Result = result::Result<U256, Error>;
|
||||||
|
|
||||||
/// Evm interface.
|
/// Evm interface.
|
||||||
|
@ -41,26 +41,34 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address {
|
|||||||
pub struct Executed {
|
pub struct Executed {
|
||||||
/// Gas paid up front for execution of transaction.
|
/// Gas paid up front for execution of transaction.
|
||||||
pub gas: U256,
|
pub gas: U256,
|
||||||
|
|
||||||
/// Gas used during execution of transaction.
|
/// Gas used during execution of transaction.
|
||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
|
|
||||||
/// Gas refunded after the execution of transaction.
|
/// Gas refunded after the execution of transaction.
|
||||||
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
/// To get gas that was required up front, add `refunded` and `gas_used`.
|
||||||
pub refunded: U256,
|
pub refunded: U256,
|
||||||
|
|
||||||
/// Cumulative gas used in current block so far.
|
/// Cumulative gas used in current block so far.
|
||||||
///
|
///
|
||||||
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
|
/// `cumulative_gas_used = gas_used(t0) + gas_used(t1) + ... gas_used(tn)`
|
||||||
///
|
///
|
||||||
/// where `tn` is current transaction.
|
/// where `tn` is current transaction.
|
||||||
pub cumulative_gas_used: U256,
|
pub cumulative_gas_used: U256,
|
||||||
|
|
||||||
/// Vector of logs generated by transaction.
|
/// Vector of logs generated by transaction.
|
||||||
pub logs: Vec<LogEntry>,
|
pub logs: Vec<LogEntry>,
|
||||||
|
|
||||||
/// Addresses of contracts created during execution of transaction.
|
/// Addresses of contracts created during execution of transaction.
|
||||||
/// Ordered from earliest creation.
|
/// Ordered from earliest creation.
|
||||||
///
|
///
|
||||||
/// eg. sender creates contract A and A in constructor creates contract B
|
/// eg. sender creates contract A and A in constructor creates contract B
|
||||||
///
|
///
|
||||||
/// B creation ends first, and it will be the first element of the vector.
|
/// B creation ends first, and it will be the first element of the vector.
|
||||||
pub contracts_created: Vec<Address>
|
pub contracts_created: Vec<Address>,
|
||||||
|
|
||||||
|
/// The trace of this transaction.
|
||||||
|
pub trace: Vec<TraceItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transaction execution result.
|
/// Transaction execution result.
|
||||||
@ -71,7 +79,7 @@ pub struct Executive<'a> {
|
|||||||
state: &'a mut State,
|
state: &'a mut State,
|
||||||
info: &'a EnvInfo,
|
info: &'a EnvInfo,
|
||||||
engine: &'a Engine,
|
engine: &'a Engine,
|
||||||
depth: usize
|
depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Executive<'a> {
|
impl<'a> Executive<'a> {
|
||||||
@ -243,13 +251,20 @@ impl<'a> Executive<'a> {
|
|||||||
// part of substate that may be reverted
|
// part of substate that may be reverted
|
||||||
let mut unconfirmed_substate = Substate::new();
|
let mut unconfirmed_substate = Substate::new();
|
||||||
|
|
||||||
|
let mut action = TraceAction::from_call(¶ms);
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output))
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let TraceAction::Call(ref mut c) = action {
|
||||||
|
c.result = res.as_ref().ok().map(|gas_left| c.gas - *gas_left);
|
||||||
|
}
|
||||||
|
|
||||||
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
|
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
|
||||||
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
|
||||||
|
self.enact_result(&res, substate, unconfirmed_substate, action);
|
||||||
trace!("exec: new substate={:?}\n", substate);
|
trace!("exec: new substate={:?}\n", substate);
|
||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
@ -278,10 +293,18 @@ impl<'a> Executive<'a> {
|
|||||||
self.state.new_contract(¶ms.address, prev_bal);
|
self.state.new_contract(¶ms.address, prev_bal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut action = TraceAction::from_create(¶ms);
|
||||||
|
let created = params.address.clone();
|
||||||
|
|
||||||
let res = {
|
let res = {
|
||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
|
||||||
};
|
};
|
||||||
self.enact_result(&res, substate, unconfirmed_substate);
|
|
||||||
|
if let TraceAction::Create(ref mut c) = action {
|
||||||
|
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, created));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.enact_result(&res, substate, unconfirmed_substate, action);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +349,8 @@ impl<'a> Executive<'a> {
|
|||||||
refunded: U256::zero(),
|
refunded: U256::zero(),
|
||||||
cumulative_gas_used: self.info.gas_used + t.gas,
|
cumulative_gas_used: self.info.gas_used + t.gas,
|
||||||
logs: vec![],
|
logs: vec![],
|
||||||
contracts_created: vec![]
|
contracts_created: vec![],
|
||||||
|
trace: substate.trace,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
@ -337,12 +361,13 @@ impl<'a> Executive<'a> {
|
|||||||
cumulative_gas_used: self.info.gas_used + gas_used,
|
cumulative_gas_used: self.info.gas_used + gas_used,
|
||||||
logs: substate.logs,
|
logs: substate.logs,
|
||||||
contracts_created: substate.contracts_created,
|
contracts_created: substate.contracts_created,
|
||||||
|
trace: substate.trace,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
|
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, action: TraceAction) {
|
||||||
match *result {
|
match *result {
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
| Err(evm::Error::BadJumpDestination {..})
|
| Err(evm::Error::BadJumpDestination {..})
|
||||||
@ -353,7 +378,7 @@ impl<'a> Executive<'a> {
|
|||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal) => {
|
Ok(_) | Err(evm::Error::Internal) => {
|
||||||
self.state.clear_snapshot();
|
self.state.clear_snapshot();
|
||||||
substate.accrue(un_substate)
|
substate.accrue(un_substate, action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,43 +17,110 @@
|
|||||||
//! Execution environment substate.
|
//! Execution environment substate.
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TraceCall {
|
||||||
|
pub from: Address,
|
||||||
|
pub to: Address,
|
||||||
|
pub value: U256,
|
||||||
|
pub gas: U256,
|
||||||
|
pub input: Bytes,
|
||||||
|
pub result: Option<U256>,
|
||||||
|
// pub output: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TraceCreate {
|
||||||
|
pub from: Address,
|
||||||
|
pub value: U256,
|
||||||
|
pub gas: U256,
|
||||||
|
pub init: Bytes,
|
||||||
|
pub result: Option<(U256, Address)>,
|
||||||
|
// pub output: Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum TraceAction {
|
||||||
|
Unknown,
|
||||||
|
Call(TraceCall),
|
||||||
|
Create(TraceCreate),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TraceItem {
|
||||||
|
pub action: TraceAction,
|
||||||
|
pub subs: Vec<TraceItem>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TraceItem {
|
||||||
|
fn default() -> TraceItem {
|
||||||
|
TraceItem {
|
||||||
|
action: TraceAction::Unknown,
|
||||||
|
subs: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// State changes which should be applied in finalize,
|
/// State changes which should be applied in finalize,
|
||||||
/// after transaction is fully executed.
|
/// after transaction is fully executed.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Substate {
|
pub struct Substate {
|
||||||
/// Any accounts that have suicided.
|
/// Any accounts that have suicided.
|
||||||
pub suicides: HashSet<Address>,
|
pub suicides: HashSet<Address>,
|
||||||
|
|
||||||
/// Any logs.
|
/// Any logs.
|
||||||
pub logs: Vec<LogEntry>,
|
pub logs: Vec<LogEntry>,
|
||||||
|
|
||||||
/// Refund counter of SSTORE nonzero -> zero.
|
/// Refund counter of SSTORE nonzero -> zero.
|
||||||
pub sstore_clears_count: U256,
|
pub sstore_clears_count: U256,
|
||||||
/// Created contracts.
|
|
||||||
pub contracts_created: Vec<Address>
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Substate {
|
/// Created contracts.
|
||||||
fn default() -> Self {
|
pub contracts_created: Vec<Address>,
|
||||||
Substate::new()
|
|
||||||
}
|
/// The trace during this execution.
|
||||||
|
pub trace: Vec<TraceItem>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Substate {
|
impl Substate {
|
||||||
/// Creates new substate.
|
/// Creates new substate.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Substate {
|
Substate::default()
|
||||||
suicides: HashSet::new(),
|
|
||||||
logs: vec![],
|
|
||||||
sstore_clears_count: U256::zero(),
|
|
||||||
contracts_created: vec![]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge secondary substate `s` into self, accruing each element correspondingly.
|
/// Merge secondary substate `s` into self, accruing each element correspondingly.
|
||||||
pub fn accrue(&mut self, s: Substate) {
|
pub fn accrue(&mut self, s: Substate, action: TraceAction) {
|
||||||
self.suicides.extend(s.suicides.into_iter());
|
self.suicides.extend(s.suicides.into_iter());
|
||||||
self.logs.extend(s.logs.into_iter());
|
self.logs.extend(s.logs.into_iter());
|
||||||
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
|
self.sstore_clears_count = self.sstore_clears_count + s.sstore_clears_count;
|
||||||
self.contracts_created.extend(s.contracts_created.into_iter());
|
self.contracts_created.extend(s.contracts_created.into_iter());
|
||||||
|
self.trace.push(TraceItem {
|
||||||
|
action: action,
|
||||||
|
subs: s.trace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
impl TraceAction {
|
||||||
|
pub fn from_call(p: &ActionParams) -> TraceAction {
|
||||||
|
TraceAction::Call(TraceCall {
|
||||||
|
from: p.sender.clone(),
|
||||||
|
to: p.address.clone(),
|
||||||
|
value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() },
|
||||||
|
gas: p.gas.clone(),
|
||||||
|
input: p.data.clone().unwrap_or(vec![]),
|
||||||
|
result: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_create(p: &ActionParams) -> TraceAction {
|
||||||
|
TraceAction::Create(TraceCreate {
|
||||||
|
from: p.sender.clone(),
|
||||||
|
value: match p.value { ActionValue::Transfer(ref x) | ActionValue::Apparent(ref x) => x.clone() },
|
||||||
|
gas: p.gas.clone(),
|
||||||
|
init: p.data.clone().unwrap_or(vec![]),
|
||||||
|
result: None,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user