anvil/eth/backend/
cheats.rs

1//! Support for "cheat codes" / bypass functions
2
3use alloy_primitives::{Address, map::AddressHashSet};
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    /// Returns `true` if the account is already impersonated
20    pub fn impersonate(&self, addr: Address) -> bool {
21        trace!(target: "cheats", "Start impersonating {:?}", addr);
22        let mut state = self.state.write();
23        // When somebody **explicitly** impersonates an account we need to store it so we are able
24        // to return it from `eth_accounts`. That's why we do not simply call `is_impersonated()`
25        // which does not check that list when auto impersonation is enabled.
26        if state.impersonated_accounts.contains(&addr) {
27            // need to check if already impersonated, so we don't overwrite the code
28            return true;
29        }
30        state.impersonated_accounts.insert(addr)
31    }
32
33    /// Removes the account that from the impersonated set
34    pub fn stop_impersonating(&self, addr: &Address) {
35        trace!(target: "cheats", "Stop impersonating {:?}", addr);
36        self.state.write().impersonated_accounts.remove(addr);
37    }
38
39    /// Returns true if the `addr` is currently impersonated
40    pub fn is_impersonated(&self, addr: Address) -> bool {
41        if self.auto_impersonate_accounts() {
42            true
43        } else {
44            self.state.read().impersonated_accounts.contains(&addr)
45        }
46    }
47
48    /// Returns true is auto impersonation is enabled
49    pub fn auto_impersonate_accounts(&self) -> bool {
50        self.state.read().auto_impersonate_accounts
51    }
52
53    /// Sets the auto impersonation flag which if set to true will make the `is_impersonated`
54    /// function always return true
55    pub fn set_auto_impersonate_account(&self, enabled: bool) {
56        trace!(target: "cheats", "Auto impersonation set to {:?}", enabled);
57        self.state.write().auto_impersonate_accounts = enabled
58    }
59
60    /// Returns all accounts that are currently being impersonated.
61    pub fn impersonated_accounts(&self) -> AddressHashSet {
62        self.state.read().impersonated_accounts.clone()
63    }
64}
65
66/// Container type for all the state variables
67#[derive(Clone, Debug, Default)]
68pub struct CheatsState {
69    /// All accounts that are currently impersonated
70    pub impersonated_accounts: AddressHashSet,
71    /// If set to true will make the `is_impersonated` function always return true
72    pub auto_impersonate_accounts: bool,
73}