anvil/eth/backend/
cheats.rs1use 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
15static PRECOMPILE_ID_CHEAT_ECRECOVER: PrecompileId =
17 PrecompileId::Custom(Cow::Borrowed("cheat_ecrecover"));
18
19#[derive(Clone, Debug, Default)]
23pub struct CheatsManager {
24 state: Arc<RwLock<CheatsState>>,
26}
27
28impl CheatsManager {
29 pub fn impersonate(&self, addr: Address) -> bool {
33 trace!(target: "cheats", %addr, "start impersonating");
34 !self.state.write().impersonated_accounts.insert(addr)
38 }
39
40 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 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 pub fn auto_impersonate_accounts(&self) -> bool {
57 self.state.read().auto_impersonate_accounts
58 }
59
60 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 pub fn impersonated_accounts(&self) -> AddressHashSet {
69 self.state.read().impersonated_accounts.clone()
70 }
71
72 pub fn add_recover_override(&self, sig: Bytes, addr: Address) {
74 self.state.write().signature_overrides.insert(sig, addr);
75 }
76
77 pub fn get_recover_override(&self, sig: &Bytes) -> Option<Address> {
79 self.state.read().signature_overrides.get(sig).copied()
80 }
81
82 pub fn has_recover_overrides(&self) -> bool {
84 !self.state.read().signature_overrides.is_empty()
85 }
86
87 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 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 pub(crate) fn next_block_overrides(&self) -> NextBlockOverrides {
107 self.state.read().next_block
108 }
109
110 pub fn take_next_block_prevrandao(&self) -> Option<B256> {
112 self.state.write().next_block.prevrandao.replace(None)
113 }
114
115 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 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 pub fn clear_next_block_overrides(&self) {
134 self.restore_next_block_overrides(&NextBlockOverrides::default());
135 }
136}
137
138#[derive(Clone, Debug, Default)]
140pub struct CheatsState {
141 pub impersonated_accounts: AddressHashSet,
143 pub auto_impersonate_accounts: bool,
145 pub signature_overrides: HashMap<Bytes, Address>,
147 pub(crate) next_block: NextBlockOverrides,
149}
150
151#[derive(Clone, Copy, Debug, Default)]
153pub(crate) struct NextBlockOverrides {
154 pub(crate) prevrandao: NextBlockOverride<B256>,
156 pub(crate) parent_beacon_block_root: NextBlockOverride<B256>,
158}
159
160#[derive(Clone, Copy, Debug, Default)]
162pub(crate) struct NextBlockOverride<T> {
163 pub(crate) value: Option<T>,
164 generation: u64,
166}
167
168impl<T> NextBlockOverride<T> {
169 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 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#[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}