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}