Trace basic calls! And tests.
This commit is contained in:
parent
72b604b8e8
commit
c4d45e0cf0
@ -246,41 +246,49 @@ impl<'a> Executive<'a> {
|
|||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if params.code.is_some() {
|
} else {
|
||||||
// if destination is a contract, do normal message call
|
// if destination is a contract, do normal message call
|
||||||
|
|
||||||
// don't trace is it's DELEGATECALL or CALLCODE.
|
// don't trace if it's DELEGATECALL or CALLCODE.
|
||||||
let should_trace = if let ActionValue::Transfer(_) = params.value {
|
let should_trace = if let ActionValue::Transfer(_) = params.value {
|
||||||
params.code_address == params.address
|
params.code_address == params.address && substate.subtraces.is_some()
|
||||||
} else { false };
|
} else { false };
|
||||||
|
|
||||||
// part of substate that may be reverted
|
|
||||||
let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some());
|
|
||||||
|
|
||||||
// transaction tracing stuff. None if there's no tracing.
|
// transaction tracing stuff. None if there's no tracing.
|
||||||
let mut trace_info = if should_trace { substate.subtraces.as_ref().map(|_| (TraceAction::from_call(¶ms), self.depth)) } else { None };
|
let (mut trace_info, mut trace_output) = if should_trace {
|
||||||
let mut trace_output = trace_info.as_ref().map(|_| vec![]);
|
(Some((TraceAction::from_call(¶ms), self.depth)), Some(vec![]))
|
||||||
|
} else { (None, None) };
|
||||||
|
|
||||||
let res = {
|
if params.code.is_some() {
|
||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()))
|
// part of substate that may be reverted
|
||||||
};
|
let mut unconfirmed_substate = Substate::new(substate.subtraces.is_some());
|
||||||
|
|
||||||
trace!(target: "executive", "res={:?}", res);
|
let res = {
|
||||||
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::Return(output, trace_output.as_mut()))
|
||||||
|
};
|
||||||
|
|
||||||
// if there's tracing, make up trace_info's result with trace_output and some arithmetic.
|
trace!(target: "executive", "res={:?}", res);
|
||||||
if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
|
|
||||||
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: qed")));
|
// if there's tracing, make up trace_info's result with trace_output and some arithmetic.
|
||||||
|
if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
|
||||||
|
c.result = res.as_ref().ok().map(|gas_left| (c.gas - *gas_left, trace_output.expect("trace_info is Some: so should_trace: qed")));
|
||||||
|
}
|
||||||
|
|
||||||
|
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||||
|
|
||||||
|
self.enact_result(&res, substate, unconfirmed_substate, trace_info);
|
||||||
|
trace!(target: "executive", "enacted: substate={:?}\n", substate);
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
||||||
|
trace!(target: "executive", "Basic message (send funds) should_trace={}", should_trace);
|
||||||
|
self.state.clear_snapshot();
|
||||||
|
if let Some((TraceAction::Call(ref mut c), _)) = trace_info {
|
||||||
|
c.result = Some((x!(0), vec![]));
|
||||||
|
}
|
||||||
|
substate.accrue_trace(if should_trace {Some(vec![])} else {None}, trace_info);
|
||||||
|
Ok(x!(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
trace!(target: "executive", "substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
|
||||||
|
|
||||||
self.enact_result(&res, substate, unconfirmed_substate, trace_info);
|
|
||||||
trace!(target: "executive", "enacted: substate={:?}\n", substate);
|
|
||||||
res
|
|
||||||
} else {
|
|
||||||
// otherwise, nothing
|
|
||||||
self.state.clear_snapshot();
|
|
||||||
Ok(params.gas)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +545,7 @@ mod tests {
|
|||||||
//let next_address = contract_address(&address, &U256::zero());
|
//let next_address = contract_address(&address, &U256::zero());
|
||||||
let mut params = ActionParams::default();
|
let mut params = ActionParams::default();
|
||||||
params.address = address.clone();
|
params.address = address.clone();
|
||||||
|
params.code_address = address.clone();
|
||||||
params.sender = sender.clone();
|
params.sender = sender.clone();
|
||||||
params.origin = sender.clone();
|
params.origin = sender.clone();
|
||||||
params.gas = U256::from(100_000);
|
params.gas = U256::from(100_000);
|
||||||
@ -634,6 +643,7 @@ mod tests {
|
|||||||
assert_eq!(substate.subtraces, expected_trace);
|
assert_eq!(substate.subtraces, expected_trace);
|
||||||
assert_eq!(gas_left, U256::from(96_776));
|
assert_eq!(gas_left, U256::from(96_776));
|
||||||
}
|
}
|
||||||
|
|
||||||
evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int}
|
evm_test!{test_create_contract_value_too_high: test_create_contract_value_too_high_jit, test_create_contract_value_too_high_int}
|
||||||
fn test_create_contract_value_too_high(factory: Factory) {
|
fn test_create_contract_value_too_high(factory: Factory) {
|
||||||
// code:
|
// code:
|
||||||
|
@ -469,6 +469,44 @@ fn should_trace_call_transaction() {
|
|||||||
assert_eq!(result.trace, expected_trace);
|
assert_eq!(result.trace, expected_trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_trace_basic_call_transaction() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
|
|
||||||
|
let mut info = EnvInfo::default();
|
||||||
|
info.gas_limit = x!(1_000_000);
|
||||||
|
let engine = TestEngine::new(5, Factory::default());
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: x!(0),
|
||||||
|
gas_price: x!(0),
|
||||||
|
gas: x!(100_000),
|
||||||
|
action: Action::Call(x!(0xa)),
|
||||||
|
value: x!(100),
|
||||||
|
data: vec![],
|
||||||
|
}.sign(&"".sha3());
|
||||||
|
|
||||||
|
state.add_balance(t.sender().as_ref().unwrap(), &x!(100));
|
||||||
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
|
let expected_trace = Some(Trace {
|
||||||
|
depth: 0,
|
||||||
|
action: TraceAction::Call(TraceCall {
|
||||||
|
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"),
|
||||||
|
to: x!(0xa),
|
||||||
|
value: x!(100),
|
||||||
|
gas: x!(79000),
|
||||||
|
input: vec![],
|
||||||
|
result: Some((x!(0), vec![]))
|
||||||
|
}),
|
||||||
|
subs: vec![]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(result.trace, expected_trace);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_trace_call_transaction_to_builtin() {
|
fn should_not_trace_call_transaction_to_builtin() {
|
||||||
init_log();
|
init_log();
|
||||||
@ -705,6 +743,95 @@ fn should_trace_call_with_subcall_transaction() {
|
|||||||
assert_eq!(result.trace, expected_trace);
|
assert_eq!(result.trace, expected_trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_trace_call_with_basic_subcall_transaction() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
|
|
||||||
|
let mut info = EnvInfo::default();
|
||||||
|
info.gas_limit = x!(1_000_000);
|
||||||
|
let engine = TestEngine::new(5, Factory::default());
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: x!(0),
|
||||||
|
gas_price: x!(0),
|
||||||
|
gas: x!(100_000),
|
||||||
|
action: Action::Call(x!(0xa)),
|
||||||
|
value: x!(100),
|
||||||
|
data: vec![],
|
||||||
|
}.sign(&"".sha3());
|
||||||
|
|
||||||
|
state.init_code(&x!(0xa), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
|
||||||
|
state.add_balance(t.sender().as_ref().unwrap(), &x!(100));
|
||||||
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
|
let expected_trace = Some(Trace {
|
||||||
|
depth: 0,
|
||||||
|
action: TraceAction::Call(TraceCall {
|
||||||
|
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"),
|
||||||
|
to: x!(0xa),
|
||||||
|
value: x!(100),
|
||||||
|
gas: x!(79000),
|
||||||
|
input: vec![],
|
||||||
|
result: Some((x!(34061), vec![]))
|
||||||
|
}),
|
||||||
|
subs: vec![Trace {
|
||||||
|
depth: 1,
|
||||||
|
action: TraceAction::Call(TraceCall {
|
||||||
|
from: x!(0xa),
|
||||||
|
to: x!(0xb),
|
||||||
|
value: x!(69),
|
||||||
|
gas: x!(2300),
|
||||||
|
input: vec![],
|
||||||
|
result: Some((x!(0), vec![]))
|
||||||
|
}),
|
||||||
|
subs: vec![]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(result.trace, expected_trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
|
||||||
|
init_log();
|
||||||
|
|
||||||
|
let temp = RandomTempPath::new();
|
||||||
|
let mut state = get_temp_state_in(temp.as_path());
|
||||||
|
|
||||||
|
let mut info = EnvInfo::default();
|
||||||
|
info.gas_limit = x!(1_000_000);
|
||||||
|
let engine = TestEngine::new(5, Factory::default());
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: x!(0),
|
||||||
|
gas_price: x!(0),
|
||||||
|
gas: x!(100_000),
|
||||||
|
action: Action::Call(x!(0xa)),
|
||||||
|
value: x!(100),
|
||||||
|
data: vec![],
|
||||||
|
}.sign(&"".sha3());
|
||||||
|
|
||||||
|
state.init_code(&x!(0xa), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
|
||||||
|
state.add_balance(t.sender().as_ref().unwrap(), &x!(100));
|
||||||
|
let result = state.apply(&info, &engine, &t, true).unwrap();
|
||||||
|
let expected_trace = Some(Trace {
|
||||||
|
depth: 0,
|
||||||
|
action: TraceAction::Call(TraceCall {
|
||||||
|
from: x!("9cce34f7ab185c7aba1b7c8140d620b4bda941d6"),
|
||||||
|
to: x!(0xa),
|
||||||
|
value: x!(100),
|
||||||
|
gas: x!(79000),
|
||||||
|
input: vec![],
|
||||||
|
result: Some((x!(31761), vec![]))
|
||||||
|
}),
|
||||||
|
subs: vec![]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(result.trace, expected_trace);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_trace_failed_subcall_transaction() {
|
fn should_trace_failed_subcall_transaction() {
|
||||||
init_log();
|
init_log();
|
||||||
|
Loading…
Reference in New Issue
Block a user