Skip to main content

foundry_evm_traces/identifier/
mod.rs

1use alloy_json_abi::JsonAbi;
2use alloy_primitives::{Address, Bytes, map::AddressHashMap};
3use foundry_common::ContractsByArtifact;
4use foundry_compilers::ArtifactId;
5use foundry_config::{Chain, Config};
6use revm_inspectors::tracing::types::CallTraceNode;
7use std::borrow::Cow;
8
9mod local;
10pub use local::LocalTraceIdentifier;
11
12mod external;
13pub use external::ExternalIdentifier;
14
15mod signatures;
16pub use signatures::{SignaturesCache, SignaturesIdentifier};
17
18/// An address identified by a [`TraceIdentifier`].
19#[derive(Debug)]
20pub struct IdentifiedAddress<'a> {
21    /// The address.
22    pub address: Address,
23    /// The label for the address.
24    pub label: Option<String>,
25    /// The contract this address represents.
26    ///
27    /// Note: This may be in the format `"<artifact>:<contract>"`.
28    pub contract: Option<String>,
29    /// The ABI of the contract at this address.
30    pub abi: Option<Cow<'a, JsonAbi>>,
31    /// Byte offset where ABI-encoded constructor arguments begin in the creation input.
32    pub constructor_args_offset: Option<usize>,
33    /// The artifact ID of the contract, if any.
34    pub artifact_id: Option<ArtifactId>,
35}
36
37/// Trace identifiers figure out what ABIs and labels belong to all the addresses of the trace.
38pub trait TraceIdentifier {
39    /// Attempts to identify an address in one or more call traces.
40    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>>;
41}
42
43/// A collection of trace identifiers.
44pub struct TraceIdentifiers<'a> {
45    /// The local trace identifier.
46    pub local: Option<LocalTraceIdentifier<'a>>,
47    /// The optional external trace identifier.
48    pub external: Option<ExternalIdentifier>,
49}
50
51impl Default for TraceIdentifiers<'_> {
52    fn default() -> Self {
53        Self::new()
54    }
55}
56
57impl TraceIdentifier for TraceIdentifiers<'_> {
58    fn identify_addresses(&mut self, nodes: &[&CallTraceNode]) -> Vec<IdentifiedAddress<'_>> {
59        if nodes.is_empty() {
60            return Vec::new();
61        }
62
63        let mut identities = Vec::with_capacity(nodes.len());
64        if let Some(local) = &mut self.local {
65            identities.extend(local.identify_addresses(nodes));
66            if identities.len() >= nodes.len() {
67                return identities;
68            }
69        }
70        if let Some(external) = &mut self.external {
71            identities.extend(external.identify_addresses(nodes));
72        }
73        identities
74    }
75}
76
77impl<'a> TraceIdentifiers<'a> {
78    /// Creates a new, empty instance.
79    pub const fn new() -> Self {
80        Self { local: None, external: None }
81    }
82
83    /// Sets the local identifier.
84    pub fn with_local(mut self, known_contracts: &'a ContractsByArtifact) -> Self {
85        self.local = Some(LocalTraceIdentifier::new(known_contracts));
86        self
87    }
88
89    /// Sets the local identifier.
90    pub fn with_local_and_bytecodes(
91        mut self,
92        known_contracts: &'a ContractsByArtifact,
93        contracts_bytecode: &'a AddressHashMap<Bytes>,
94    ) -> Self {
95        self.local =
96            Some(LocalTraceIdentifier::new(known_contracts).with_bytecodes(contracts_bytecode));
97        self
98    }
99
100    /// Sets the external identifier.
101    pub fn with_external(mut self, config: &Config, chain: Option<Chain>) -> eyre::Result<Self> {
102        self.external = ExternalIdentifier::new(config, chain)?;
103        Ok(self)
104    }
105
106    /// Returns `true` if there are no set identifiers.
107    pub const fn is_empty(&self) -> bool {
108        self.local.is_none() && self.external.is_none()
109    }
110}