fix: exclude calls to precompiles in parity tracers (#2987)

This commit is contained in:
Matthias Seitz
2023-06-06 20:20:49 +02:00
committed by GitHub
parent 1a4f407c4a
commit 8f4e37e8ff
6 changed files with 57 additions and 9 deletions

14
Cargo.lock generated
View File

@ -5538,8 +5538,7 @@ dependencies = [
[[package]] [[package]]
name = "revm" name = "revm"
version = "3.3.0" version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/bluealloy/revm/?branch=release/v25#88337924f4d16ed1f5e4cde12a03d0cb755cd658"
checksum = "f293f351c4c203d321744e54ed7eed3d2b6eef4c140228910dde3ac9a5ea8031"
dependencies = [ dependencies = [
"auto_impl", "auto_impl",
"revm-interpreter", "revm-interpreter",
@ -5549,8 +5548,7 @@ dependencies = [
[[package]] [[package]]
name = "revm-interpreter" name = "revm-interpreter"
version = "1.1.2" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/bluealloy/revm/?branch=release/v25#88337924f4d16ed1f5e4cde12a03d0cb755cd658"
checksum = "a53980a26f9b5a66d13511c35074d4b53631e157850a1d7cf1af4efc2c2b72c9"
dependencies = [ dependencies = [
"derive_more", "derive_more",
"enumn", "enumn",
@ -5560,9 +5558,8 @@ dependencies = [
[[package]] [[package]]
name = "revm-precompile" name = "revm-precompile"
version = "2.0.2" version = "2.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/bluealloy/revm/?branch=release/v25#88337924f4d16ed1f5e4cde12a03d0cb755cd658"
checksum = "10a3eabf08ea9e4063f5531b8735e29344d9d6eaebaa314c58253f6c17fcdf2d"
dependencies = [ dependencies = [
"k256 0.13.1", "k256 0.13.1",
"num", "num",
@ -5578,8 +5575,7 @@ dependencies = [
[[package]] [[package]]
name = "revm-primitives" name = "revm-primitives"
version = "1.1.2" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "git+https://github.com/bluealloy/revm/?branch=release/v25#88337924f4d16ed1f5e4cde12a03d0cb755cd658"
checksum = "304d998f466ffef72d76c7f20b05bf08a96801736a6fb1fdef47d49a292618df"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"auto_impl", "auto_impl",

View File

@ -73,6 +73,9 @@ incremental = false
# patched for quantity U256 responses <https://github.com/recmo/uint/issues/224> # patched for quantity U256 responses <https://github.com/recmo/uint/issues/224>
ruint = { git = "https://github.com/paradigmxyz/uint" } ruint = { git = "https://github.com/paradigmxyz/uint" }
revm = { git = "https://github.com/bluealloy/revm/", branch = "release/v25" }
revm-primitives = { git = "https://github.com/bluealloy/revm/", branch = "release/v25" }
[workspace.dependencies] [workspace.dependencies]
## eth ## eth
revm = { version = "3" } revm = { version = "3" }

View File

@ -124,6 +124,11 @@ impl ParityTraceBuilder {
let mut diff = StateDiff::default(); let mut diff = StateDiff::default();
for (node, trace_address) in self.nodes.iter().zip(trace_addresses) { for (node, trace_address) in self.nodes.iter().zip(trace_addresses) {
// skip precompiles
if node.is_precompile() {
continue
}
if with_traces { if with_traces {
let trace = node.parity_transaction_trace(trace_address); let trace = node.parity_transaction_trace(trace_address);
traces.push(trace); traces.push(trace);
@ -145,6 +150,7 @@ impl ParityTraceBuilder {
self.nodes self.nodes
.into_iter() .into_iter()
.zip(trace_addresses) .zip(trace_addresses)
.filter(|(node, _)| !node.is_precompile())
.map(|(node, trace_address)| node.parity_transaction_trace(trace_address)) .map(|(node, trace_address)| node.parity_transaction_trace(trace_address))
} }

View File

@ -14,6 +14,8 @@ pub struct TracingInspectorConfig {
pub record_stack_snapshots: bool, pub record_stack_snapshots: bool,
/// Whether to record state diffs. /// Whether to record state diffs.
pub record_state_diff: bool, pub record_state_diff: bool,
/// Whether to ignore precompile calls.
pub exclude_precompile_calls: bool,
} }
impl TracingInspectorConfig { impl TracingInspectorConfig {
@ -24,6 +26,7 @@ impl TracingInspectorConfig {
record_memory_snapshots: true, record_memory_snapshots: true,
record_stack_snapshots: true, record_stack_snapshots: true,
record_state_diff: false, record_state_diff: false,
exclude_precompile_calls: false,
} }
} }
@ -36,6 +39,7 @@ impl TracingInspectorConfig {
record_memory_snapshots: false, record_memory_snapshots: false,
record_stack_snapshots: false, record_stack_snapshots: false,
record_state_diff: false, record_state_diff: false,
exclude_precompile_calls: true,
} }
} }
@ -48,6 +52,7 @@ impl TracingInspectorConfig {
record_memory_snapshots: true, record_memory_snapshots: true,
record_stack_snapshots: true, record_stack_snapshots: true,
record_state_diff: true, record_state_diff: true,
exclude_precompile_calls: false,
} }
} }
@ -61,6 +66,14 @@ impl TracingInspectorConfig {
} }
} }
/// Configure whether calls to precompiles should be ignored.
///
/// If set to `true`, calls to precompiles without value transfers will be ignored.
pub fn set_exclude_precompile_calls(mut self, exclude_precompile_calls: bool) -> Self {
self.exclude_precompile_calls = exclude_precompile_calls;
self
}
/// Configure whether individual opcode level steps should be recorded /// Configure whether individual opcode level steps should be recorded
pub fn set_steps(mut self, record_steps: bool) -> Self { pub fn set_steps(mut self, record_steps: bool) -> Self {
self.record_steps = record_steps; self.record_steps = record_steps;

View File

@ -101,6 +101,7 @@ impl TracingInspector {
/// Starts tracking a new trace. /// Starts tracking a new trace.
/// ///
/// Invoked on [Inspector::call]. /// Invoked on [Inspector::call].
#[allow(clippy::too_many_arguments)]
fn start_trace_on_call( fn start_trace_on_call(
&mut self, &mut self,
depth: usize, depth: usize,
@ -109,6 +110,7 @@ impl TracingInspector {
value: U256, value: U256,
kind: CallKind, kind: CallKind,
caller: Address, caller: Address,
maybe_precompile: Option<bool>,
) { ) {
self.trace_stack.push(self.traces.push_trace( self.trace_stack.push(self.traces.push_trace(
0, 0,
@ -121,6 +123,7 @@ impl TracingInspector {
status: InstructionResult::Continue, status: InstructionResult::Continue,
caller, caller,
last_call_return_value: self.last_call_return_data.clone(), last_call_return_value: self.last_call_return_data.clone(),
maybe_precompile,
..Default::default() ..Default::default()
}, },
)); ));
@ -318,6 +321,12 @@ where
_ => (inputs.context.caller, inputs.context.address), _ => (inputs.context.caller, inputs.context.address),
}; };
// if calls to precompiles should be excluded, check whether this is a call to a precompile
let maybe_precompile = self
.config
.exclude_precompile_calls
.then(|| is_precompile_call(data, &to, inputs.transfer.value));
self.start_trace_on_call( self.start_trace_on_call(
data.journaled_state.depth() as usize, data.journaled_state.depth() as usize,
to, to,
@ -325,6 +334,7 @@ where
inputs.transfer.value, inputs.transfer.value,
inputs.context.scheme.into(), inputs.context.scheme.into(),
from, from,
maybe_precompile,
); );
(InstructionResult::Continue, Gas::new(0), Bytes::new()) (InstructionResult::Continue, Gas::new(0), Bytes::new())
@ -367,6 +377,7 @@ where
inputs.value, inputs.value,
inputs.scheme.into(), inputs.scheme.into(),
inputs.caller, inputs.caller,
Some(false),
); );
(InstructionResult::Continue, None, Gas::new(inputs.gas_limit), Bytes::default()) (InstructionResult::Continue, None, Gas::new(inputs.gas_limit), Bytes::default())
@ -421,3 +432,12 @@ struct StackStep {
trace_idx: usize, trace_idx: usize,
step_idx: usize, step_idx: usize,
} }
/// Returns true if this a call to a precompile contract with `depth > 0 && value == 0`.
#[inline]
fn is_precompile_call<DB: Database>(data: &EVMData<'_, DB>, to: &Address, value: U256) -> bool {
if data.precompiles.contains(to) {
return data.journaled_state.depth() > 0 && value == U256::ZERO
}
false
}

View File

@ -121,6 +121,10 @@ pub(crate) struct CallTrace {
/// In other words, this is the callee if the [CallKind::Call] or the address of the created /// In other words, this is the callee if the [CallKind::Call] or the address of the created
/// contract if [CallKind::Create]. /// contract if [CallKind::Create].
pub(crate) address: Address, pub(crate) address: Address,
/// Whether this is a call to a precompile
///
/// Note: This is an Option because not all tracers make use of this
pub(crate) maybe_precompile: Option<bool>,
/// Holds the target for the selfdestruct refund target if `status` is /// Holds the target for the selfdestruct refund target if `status` is
/// [InstructionResult::SelfDestruct] /// [InstructionResult::SelfDestruct]
pub(crate) selfdestruct_refund_target: Option<Address>, pub(crate) selfdestruct_refund_target: Option<Address>,
@ -168,6 +172,7 @@ impl Default for CallTrace {
kind: Default::default(), kind: Default::default(),
value: Default::default(), value: Default::default(),
data: Default::default(), data: Default::default(),
maybe_precompile: None,
output: Default::default(), output: Default::default(),
last_call_return_value: None, last_call_return_value: None,
gas_used: Default::default(), gas_used: Default::default(),
@ -233,6 +238,11 @@ impl CallTraceNode {
stack stack
} }
/// Returns true if this is a call to a precompile
pub(crate) fn is_precompile(&self) -> bool {
self.trace.maybe_precompile.unwrap_or(false)
}
/// Returns the kind of call the trace belongs to /// Returns the kind of call the trace belongs to
pub(crate) fn kind(&self) -> CallKind { pub(crate) fn kind(&self) -> CallKind {
self.trace.kind self.trace.kind