anvil/eth/backend/
cheats.rs

1//! Support for "cheat codes" / bypass functions
2
3use alloy_primitives::{map::AddressHashSet, Address};
4use parking_lot::RwLock;
5use std::sync::Arc;
6
7/// Manages user modifications that may affect the node's behavior
8///
9/// Contains the state of executed, non-eth standard cheat code RPC
10#[derive(Clone, Debug, Default)]
11pub struct CheatsManager {
12    /// shareable state
13    state: Arc<RwLock<CheatsState>>,
14}
15
16impl CheatsManager {
17    /// Sets the account to impersonate
18    ///
19    /// This also accepts the actual code hash if the address is a contract to bypass EIP-3607
20    ///
21    /// Returns `true` if the account is already impersonated
22    pub fn impersonate(&self, addr: Address) -> bool {
23        trace!(target: "cheats", "Start impersonating {:?}", addr);
24        let mut state = self.state.write();
25        // When somebody **explicitly** impersonates an account we need to store it so we are able
26        // to return it from `eth_accounts`. That's why we do not simply call `is_impersonated()`
27        // which does not check that list when auto impersonation is enabled.
28        if state.impersonated_accounts.contains(&addr) {
29            // need to check if already impersonated, so we don't overwrite the code
30            return true
31        }
32        state.impersonated_accounts.insert(addr)
33    }
34
35    /// Removes the account that from the impersonated set
36    pub fn stop_impersonating(&self, addr: &Address) {
37        trace!(target: "cheats", "Stop impersonating {:?}", addr);
38        self.state.write().impersonated_accounts.remove(addr);
39    }
40
41    /// Returns true if the `addr` is currently impersonated
42    pub fn is_impersonated(&self, addr: Address) -> bool {
43        if self.auto_impersonate_accounts() {
44            true
45        } else {
46            self.state.read().impersonated_accounts.contains(&addr)
47        }
48    }
49
50    /// Returns true is auto impersonation is enabled
51    pub fn auto_impersonate_accounts(&self) -> bool {
52        self.state.read().auto_impersonate_accounts
53    }
54
55    /// Sets the auto impersonation flag which if set to true will make the `is_impersonated`
56    /// function always return true
57    pub fn set_auto_impersonate_account(&self, enabled: bool) {
58        trace!(target: "cheats", "Auto impersonation set to {:?}", enabled);
59        self.state.write().auto_impersonate_accounts = enabled
60    }
61
62    /// Returns all accounts that are currently being impersonated.
63    pub fn impersonated_accounts(&self) -> AddressHashSet {
64        self.state.read().impersonated_accounts.clone()
65    }
66}
67
68/// Container type for all the state variables
69#[derive(Clone, Debug, Default)]
70pub struct CheatsState {
71    /// All accounts that are currently impersonated
72    pub impersonated_accounts: AddressHashSet,
73    /// If set to true will make the `is_impersonated` function always return true
74    pub auto_impersonate_accounts: bool,
75}