Skip to main content

anvil/eth/backend/
cheats.rs

1//! Support for "cheat codes" / bypass functions
2
3use alloy_evm::precompiles::{Precompile, PrecompileInput};
4use alloy_primitives::{
5    Address, B256, Bytes,
6    map::{AddressHashSet, foldhash::HashMap},
7};
8use parking_lot::RwLock;
9use revm::precompile::{
10    PrecompileHalt, PrecompileId, PrecompileOutput, PrecompileResult, call_eth_precompile,
11    secp256k1::ec_recover_run, utilities::right_pad,
12};
13use std::{borrow::Cow, sync::Arc};
14
15/// ID for the [`CheatEcrecover::precompile_id`] precompile.
16static PRECOMPILE_ID_CHEAT_ECRECOVER: PrecompileId =
17    PrecompileId::Custom(Cow::Borrowed("cheat_ecrecover"));
18
19/// Manages user modifications that may affect the node's behavior
20///
21/// Contains the state of executed, non-eth standard cheat code RPC
22#[derive(Clone, Debug, Default)]
23pub struct CheatsManager {
24    /// shareable state
25    state: Arc<RwLock<CheatsState>>,
26}
27
28impl CheatsManager {
29    /// Sets the account to impersonate
30    ///
31    /// Returns `true` if the account is already impersonated
32    pub fn impersonate(&self, addr: Address) -> bool {
33        trace!(target: "cheats", %addr, "start impersonating");
34        // When somebody **explicitly** impersonates an account we need to store it so we are able
35        // to return it from `eth_accounts`. That's why we do not simply call `is_impersonated()`
36        // which does not check that list when auto impersonation is enabled.
37        !self.state.write().impersonated_accounts.insert(addr)
38    }
39
40    /// Removes the account that from the impersonated set
41    pub fn stop_impersonating(&self, addr: &Address) {
42        trace!(target: "cheats", %addr, "stop impersonating");
43        self.state.write().impersonated_accounts.remove(addr);
44    }
45
46    /// Returns true if the `addr` is currently impersonated
47    pub fn is_impersonated(&self, addr: Address) -> bool {
48        if self.auto_impersonate_accounts() {
49            true
50        } else {
51            self.state.read().impersonated_accounts.contains(&addr)
52        }
53    }
54
55    /// Returns true is auto impersonation is enabled
56    pub fn auto_impersonate_accounts(&self) -> bool {
57        self.state.read().auto_impersonate_accounts
58    }
59
60    /// Sets the auto impersonation flag which if set to true will make the `is_impersonated`
61    /// function always return true
62    pub fn set_auto_impersonate_account(&self, enabled: bool) {
63        trace!(target: "cheats", "Auto impersonation set to {:?}", enabled);
64        self.state.write().auto_impersonate_accounts = enabled
65    }
66
67    /// Returns all accounts that are currently being impersonated.
68    pub fn impersonated_accounts(&self) -> AddressHashSet {
69        self.state.read().impersonated_accounts.clone()
70    }
71
72    /// Registers an override so that `ecrecover(signature)` returns `addr`.
73    pub fn add_recover_override(&self, sig: Bytes, addr: Address) {
74        self.state.write().signature_overrides.insert(sig, addr);
75    }
76
77    /// If an override exists for `sig`, returns the address; otherwise `None`.
78    pub fn get_recover_override(&self, sig: &Bytes) -> Option<Address> {
79        self.state.read().signature_overrides.get(sig).copied()
80    }
81
82    /// Returns true if any ecrecover overrides have been registered.
83    pub fn has_recover_overrides(&self) -> bool {
84        !self.state.read().signature_overrides.is_empty()
85    }
86
87    /// Sets the `prevrandao` value to use for the next mined block.
88    ///
89    /// This is a one-shot override that is consumed by the next block and applies to that block
90    /// only.
91    pub fn set_next_block_prevrandao(&self, prevrandao: B256) {
92        trace!(target: "cheats", %prevrandao, "set next block prevrandao");
93        self.state.write().next_block.prevrandao.replace(Some(prevrandao));
94    }
95
96    /// Sets the parent beacon block root to use for the next mined block.
97    ///
98    /// This is a one-shot override that is consumed by the next block and applies to that block
99    /// only.
100    pub fn set_next_block_parent_beacon_block_root(&self, root: B256) {
101        trace!(target: "cheats", %root, "set next block parent beacon block root");
102        self.state.write().next_block.parent_beacon_block_root.replace(Some(root));
103    }
104
105    /// Returns the manually set values for the next block without consuming them.
106    pub(crate) fn next_block_overrides(&self) -> NextBlockOverrides {
107        self.state.read().next_block
108    }
109
110    /// Takes the manually set `prevrandao` value for forced replay mining.
111    pub fn take_next_block_prevrandao(&self) -> Option<B256> {
112        self.state.write().next_block.prevrandao.replace(None)
113    }
114
115    /// Consumes the overrides a committed block was built with, keeping any set since.
116    pub(crate) fn consume_next_block_overrides(&self, used: &NextBlockOverrides) {
117        let mut state = self.state.write();
118        state.next_block.prevrandao.consume(&used.prevrandao);
119        state.next_block.parent_beacon_block_root.consume(&used.parent_beacon_block_root);
120    }
121
122    /// Restores the overrides saved with a state snapshot.
123    pub(crate) fn restore_next_block_overrides(&self, saved: &NextBlockOverrides) {
124        let mut state = self.state.write();
125        state.next_block.prevrandao.replace(saved.prevrandao.value);
126        state.next_block.parent_beacon_block_root.replace(saved.parent_beacon_block_root.value);
127    }
128
129    /// Clears any manually set values for the next block.
130    ///
131    /// Used on reset/revert so a set-but-unmined override does not leak into a later block,
132    /// mirroring how the next-block timestamp override is cleared by `TimeManager::reset`.
133    pub fn clear_next_block_overrides(&self) {
134        self.restore_next_block_overrides(&NextBlockOverrides::default());
135    }
136}
137
138/// Container type for all the state variables
139#[derive(Clone, Debug, Default)]
140pub struct CheatsState {
141    /// All accounts that are currently impersonated
142    pub impersonated_accounts: AddressHashSet,
143    /// If set to true will make the `is_impersonated` function always return true
144    pub auto_impersonate_accounts: bool,
145    /// Overrides for ecrecover: Signature => Address
146    pub signature_overrides: HashMap<Bytes, Address>,
147    /// Manually set values for the next mined block.
148    pub(crate) next_block: NextBlockOverrides,
149}
150
151/// Values manually set for the next mined block.
152#[derive(Clone, Copy, Debug, Default)]
153pub(crate) struct NextBlockOverrides {
154    /// Set via `anvil_setNextBlockPrevRandao`.
155    pub(crate) prevrandao: NextBlockOverride<B256>,
156    /// Set via `anvil_setNextBlockParentBeaconBlockRoot`.
157    pub(crate) parent_beacon_block_root: NextBlockOverride<B256>,
158}
159
160/// A one-shot override of a value of the next mined block.
161#[derive(Clone, Copy, Debug, Default)]
162pub(crate) struct NextBlockOverride<T> {
163    pub(crate) value: Option<T>,
164    /// Bumped on every replacement, so a block consumes only the value it was built with.
165    generation: u64,
166}
167
168impl<T> NextBlockOverride<T> {
169    /// Replaces the value, returning the previous one.
170    const fn replace(&mut self, value: Option<T>) -> Option<T> {
171        self.generation = self.generation.wrapping_add(1);
172        std::mem::replace(&mut self.value, value)
173    }
174
175    /// Clears the value if it is still the one `used` was taken from.
176    fn consume(&mut self, used: &Self) {
177        if self.generation == used.generation {
178            self.value = None;
179        }
180    }
181}
182
183impl CheatEcrecover {
184    pub const fn new(cheats: Arc<CheatsManager>) -> Self {
185        Self { cheats }
186    }
187}
188
189impl Precompile for CheatEcrecover {
190    fn call(&self, input: PrecompileInput<'_>) -> PrecompileResult {
191        if !self.cheats.has_recover_overrides() {
192            return Ok(call_eth_precompile(
193                ec_recover_run,
194                input.data,
195                input.gas(),
196                input.reservoir,
197            ));
198        }
199
200        const ECRECOVER_BASE: u64 = 3_000;
201        if input.gas() < ECRECOVER_BASE {
202            return Ok(PrecompileOutput::halt(PrecompileHalt::OutOfGas, input.reservoir));
203        }
204        let padded = right_pad::<128>(input.data);
205        let v = padded[63];
206        let mut sig_bytes = [0u8; 65];
207        sig_bytes[..64].copy_from_slice(&padded[64..128]);
208        sig_bytes[64] = v;
209        let sig_bytes_wrapped = Bytes::from(sig_bytes);
210        if let Some(addr) = self.cheats.get_recover_override(&sig_bytes_wrapped) {
211            let mut out = [0u8; 32];
212            out[12..].copy_from_slice(addr.as_slice());
213            return Ok(PrecompileOutput::new(ECRECOVER_BASE, out.into(), input.reservoir));
214        }
215        Ok(call_eth_precompile(ec_recover_run, input.data, input.gas(), input.reservoir))
216    }
217
218    fn precompile_id(&self) -> &PrecompileId {
219        &PRECOMPILE_ID_CHEAT_ECRECOVER
220    }
221
222    fn supports_caching(&self) -> bool {
223        false
224    }
225}
226
227/// A custom ecrecover precompile that supports cheat-based signature overrides.
228#[derive(Clone, Debug)]
229pub struct CheatEcrecover {
230    cheats: Arc<CheatsManager>,
231}
232
233#[cfg(test)]
234mod tests {
235    use super::*;
236
237    #[test]
238    fn candidate_consumes_only_its_next_block_overrides() {
239        let cheats = CheatsManager::default();
240        let value = B256::with_last_byte(1);
241        cheats.set_next_block_prevrandao(value);
242        cheats.set_next_block_parent_beacon_block_root(value);
243        let used = cheats.next_block_overrides();
244
245        cheats.set_next_block_prevrandao(value);
246        cheats.consume_next_block_overrides(&used);
247
248        let overrides = cheats.next_block_overrides();
249        assert_eq!(overrides.prevrandao.value, Some(value));
250        assert_eq!(overrides.parent_beacon_block_root.value, None);
251    }
252
253    #[test]
254    fn impersonate_returns_false_then_true() {
255        let mgr = CheatsManager::default();
256        let addr = Address::repeat_byte(1u8);
257        assert!(!mgr.impersonate(addr));
258        assert!(mgr.impersonate(addr));
259    }
260}