Skip to main content

revive_strategy/tracing/
call_tracer.rs

1use alloy_primitives::{Address, U256 as RU256};
2use foundry_cheatcodes::ExpectedCallTracker;
3use polkadot_sdk::{
4    pallet_revive,
5    pallet_revive::tracing::Tracing,
6    sp_core::{H160, U256},
7};
8
9#[derive(Debug)]
10pub(crate) struct ExpectedCallTracer {
11    pub data: ExpectedCallTracker,
12    is_create: bool,
13}
14
15impl ExpectedCallTracer {
16    pub fn new(data: ExpectedCallTracker) -> Self {
17        Self { data, is_create: false }
18    }
19}
20
21impl Tracing for ExpectedCallTracer {
22    fn enter_child_span(
23        &mut self,
24        _from: H160,
25        to: H160,
26        is_delegate_call: Option<H160>,
27        _is_read_only: bool,
28        value: U256,
29        input: &[u8],
30        _gas: U256,
31    ) {
32        let addr =
33            is_delegate_call.map(|x| Address::from(x.0)).unwrap_or_else(|| Address::from(to.0));
34        if !self.is_create
35            && let Some(expected_calls_for_target) = self.data.get_mut(&addr)
36        {
37            // Match every partial/full calldata
38            for (calldata, (expected, actual_count)) in expected_calls_for_target {
39                // Increment actual times seen if...
40                // The calldata is at most, as big as this call's input, and
41                if calldata.len() <= input.len() &&
42                    // Both calldata match, taking the length of the assumed smaller one (which will have at least the selector), and
43                    *calldata == input[..calldata.len()] &&
44                    // The value matches, if provided
45                    expected
46                        .value.is_none_or(|v| v == RU256::from_limbs(value.0))
47                // gas tracking is broken now
48                // // The gas matches, if provided
49                // expected.gas.is_none_or(|g| g == gas) &&
50                // // The minimum gas matches, if provided
51                {
52                    *actual_count += 1;
53                }
54            }
55        }
56    }
57    fn exit_child_span(&mut self, _output: &pallet_revive::ExecReturnValue, _gas_left: U256) {
58        self.is_create = false;
59    }
60
61    fn instantiate_code(
62        &mut self,
63        _code: &polkadot_sdk::pallet_revive::Code,
64        _salt: Option<&[u8; 32]>,
65    ) {
66        self.is_create = true;
67    }
68}