1use alloy_primitives::{Address, Bytes, U256};
9use alloy_sol_types::{decode_revert_reason, SolCall};
10use anyhow::{anyhow, bail, Result};
11use revm::{
12 db::{DatabaseCommit, DatabaseRef},
13 primitives::{
14 Account, AccountInfo, BlockEnv, Env, EnvWithHandlerCfg, ExecutionResult, HashMap as Map,
15 Log, Output, ResultAndState, TransactTo, TxEnv,
16 },
17};
18
19use crate::{
20 db::{CreateFork, StorageBackend},
21 SnapShot,
22};
23
24type StateChangeSet = Map<Address, Account>;
26
27pub struct BaseEvm {
29 backend: StorageBackend,
30 env: EnvWithHandlerCfg,
31}
32
33impl Default for BaseEvm {
35 fn default() -> Self {
36 BaseEvm::new(None)
37 }
38}
39
40impl BaseEvm {
41 pub fn new(fork: Option<CreateFork>) -> Self {
44 let env = EnvWithHandlerCfg::default();
45 let backend = StorageBackend::new(fork);
46 Self { env, backend }
47 }
48
49 pub fn new_from_snapshot(snap: SnapShot) -> Self {
52 let env = EnvWithHandlerCfg::default();
53 let mut backend = StorageBackend::default();
54 backend.load_snapshot(snap);
55 Self { env, backend }
56 }
57
58 pub fn create_account(&mut self, user: Address, amount: Option<U256>) -> Result<()> {
61 let mut info = AccountInfo::default();
62 if let Some(amnt) = amount {
63 info.balance = amnt;
64 }
65 self.backend.insert_account_info(user, info);
66 Ok(())
67 }
68
69 pub fn get_balance(&mut self, caller: Address) -> Result<U256> {
71 Ok(self
72 .backend
73 .basic_ref(caller)?
74 .map(|acc| acc.balance)
75 .unwrap_or_default())
76 }
77
78 pub fn set_balance(&mut self, address: Address, amount: U256) -> Result<&mut Self> {
80 let mut account = self.backend.basic_ref(address)?.unwrap_or_default();
81 account.balance = amount;
82
83 self.backend.insert_account_info(address, account);
84 Ok(self)
85 }
86
87 pub fn create_snapshot(&self) -> Result<SnapShot> {
89 self.backend.create_snapshot()
90 }
91
92 pub fn deploy(&mut self, caller: Address, data: Vec<u8>, value: U256) -> Result<Address> {
95 let mut env = self.build_env(Some(caller), TransactTo::create(), data.into(), value);
96 let result = self.backend.run_transact(&mut env)?;
97 let mut call_results = process_call_result(result)?;
98 self.commit(&mut call_results);
99
100 match call_results.address {
101 Some(addr) => Ok(addr),
102 _ => Err(anyhow!("deploy did not return an Address!")),
103 }
104 }
105
106 pub fn transfer(&mut self, caller: Address, to: Address, value: U256) -> Result<()> {
108 let _ = self.transact_commit(caller, to, vec![], value)?;
109 Ok(())
110 }
111
112 pub fn transact_commit_sol<T: SolCall>(
114 &mut self,
115 caller: Address,
116 to: Address,
117 args: T,
118 value: U256,
119 ) -> Result<<T as SolCall>::Return> {
120 let data = args.abi_encode();
121 let result = self.transact_commit(caller, to, data, value)?;
122 T::abi_decode_returns(&result.result, true)
123 .map_err(|e| anyhow!("transact commit sol error: {:?}", e))
124 }
125
126 pub fn transact_commit(
128 &mut self,
129 caller: Address,
130 to: Address,
131 data: Vec<u8>,
132 value: U256,
133 ) -> Result<CallResult> {
134 let mut env = self.build_env(Some(caller), TransactTo::call(to), data.into(), value);
135 let result = self.backend.run_transact(&mut env)?;
136 let mut call_results = process_call_result(result)?;
137 self.commit(&mut call_results);
138
139 Ok(call_results)
140 }
141
142 pub fn transact_call_sol<T: SolCall>(
144 &mut self,
145 to: Address,
146 args: T,
147 value: U256,
148 ) -> Result<<T as SolCall>::Return> {
149 let data = args.abi_encode();
150 let result = self.transact_call(to, data, value)?;
151 T::abi_decode_returns(&result.result, true)
152 .map_err(|e| anyhow!("transact call sol error: {:?}", e))
153 }
154
155 pub fn transact_call(&mut self, to: Address, data: Vec<u8>, value: U256) -> Result<CallResult> {
158 let mut env = self.build_env(None, TransactTo::call(to), data.into(), value);
159 let result = self.backend.run_transact(&mut env)?;
160 process_call_result(result)
161 }
162
163 pub fn simulate(
165 &mut self,
166 caller: Address,
167 to: Address,
168 data: Vec<u8>,
169 value: U256,
170 ) -> Result<CallResult> {
171 let mut env = self.build_env(Some(caller), TransactTo::call(to), data.into(), value);
172 let result = self.backend.run_transact(&mut env)?;
173 process_call_result(result)
174 }
175
176 pub fn update_block(&mut self, interval: u64) {
182 self.backend.update_block_info(interval);
183 }
184
185 fn build_env(
186 &self,
187 caller: Option<Address>,
188 transact_to: TransactTo,
189 data: Bytes,
190 value: U256,
191 ) -> EnvWithHandlerCfg {
192 let blkn = self.backend.block_number;
193 let ts = self.backend.timestamp;
194
195 let env = Env {
196 cfg: self.env.cfg.clone(),
197 block: BlockEnv {
198 basefee: U256::ZERO,
199 timestamp: U256::from(ts),
200 number: U256::from(blkn),
201 ..self.env.block.clone()
202 },
203 tx: TxEnv {
204 caller: caller.unwrap_or(Address::ZERO),
205 transact_to,
206 data,
207 value,
208 gas_price: U256::ZERO,
209 gas_priority_fee: None,
210 ..self.env.tx.clone()
211 },
212 };
213
214 EnvWithHandlerCfg::new_with_spec_id(Box::new(env), self.env.handler_cfg.spec_id)
215 }
216
217 fn commit(&mut self, result: &mut CallResult) {
218 if let Some(changes) = &result.state_changeset {
219 self.backend.commit(changes.clone());
220 }
221 }
222}
223
224pub struct CallResult {
226 pub result: Bytes,
228 pub address: Option<Address>,
230 pub gas_used: u64,
232 pub gas_refunded: u64,
234 pub logs: Vec<Log>,
236 pub state_changeset: Option<StateChangeSet>,
238}
239
240fn process_call_result(result: ResultAndState) -> Result<CallResult> {
241 let ResultAndState {
242 result: exec_result,
243 state: state_changeset,
244 } = result;
245
246 let (gas_refunded, gas_used, out, logs) = match exec_result {
247 ExecutionResult::Success {
248 gas_used,
249 gas_refunded,
250 output,
251 logs,
252 ..
253 } => (gas_refunded, gas_used, output, logs),
254 ExecutionResult::Revert { gas_used, output } => match decode_revert_reason(&output) {
255 Some(reason) => bail!("Reverted: {:?}. Gas used: {:?}", reason, gas_used),
256 _ => bail!("Reverted with no reason. Gas used: {:?}", gas_used),
257 },
258 ExecutionResult::Halt { reason, gas_used } => {
259 bail!("Halted: {:?}. Gas used: {:?}", reason, gas_used)
260 }
261 };
262
263 match out {
264 Output::Call(result) => Ok(CallResult {
265 result,
266 gas_used,
267 gas_refunded,
268 logs,
269 address: None,
270 state_changeset: Some(state_changeset),
271 }),
272 Output::Create(data, address) => Ok(CallResult {
273 result: data.clone(),
274 address,
275 gas_used,
276 logs,
277 gas_refunded,
278 state_changeset: Some(state_changeset),
279 }),
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use crate::ContractAbi;
286 use crate::{generate_random_addresses, BaseEvm};
287 use alloy_dyn_abi::DynSolValue;
288 use alloy_primitives::{Address, U256};
289 use alloy_sol_types::{sol, SolConstructor};
290 use rstest::*;
291
292 sol! {
293 struct ChangeIt {
294 address owner;
295 uint256 value;
296 }
297
298 contract TestContract {
299 address public owner;
300 uint256 public value;
301
302 constructor(uint256 _value) payable;
303
304 function increment() public returns (uint256);
306
307 function increment(uint256 _input) public returns (uint256, uint256);
309
310 function changeIt(ChangeIt calldata _input) public returns (bool);
312
313 function deposit() public payable;
314 }
315 }
316
317 sol! {
318 contract BlockMeta {
319 function getMeta() external view returns (uint, uint);
320 }
321 }
322
323 #[fixture]
324 fn contract_bytecode() -> Vec<u8> {
325 let raw: &str = "608060405260405161032c38038061032c8339810160408190526100\
326 229161003c565b600155600080546001600160a01b03191633179055610055565b6000602\
327 0828403121561004e57600080fd5b5051919050565b6102c8806100646000396000f3fe60\
328 80604052600436106100555760003560e01c80633fa4f2451461005a57806361fa423b146\
329 100835780637cf5dab0146100b35780638da5cb5b146100e8578063d09de08a1461012057\
330 8063d0e30db014610135575b600080fd5b34801561006657600080fd5b506100706001548\
331 1565b6040519081526020015b60405180910390f35b34801561008f57600080fd5b506100\
332 a361009e36600461020a565b610137565b604051901515815260200161007a565b3480156\
333 100bf57600080fd5b506100d36100ce366004610222565b6101c8565b6040805192835260\
334 208301919091520161007a565b3480156100f457600080fd5b50600054610108906001600\
335 160a01b031681565b6040516001600160a01b03909116815260200161007a565b34801561\
336 012c57600080fd5b506100706101ec565b005b600080546001600160a01b0316331461018\
337 e5760405162461bcd60e51b81526020600482015260156024820152743737ba103a343290\
338 31bab93932b73a1037bbb732b960591b604482015260640160405180910390fd5b61019b6\
339 02083018361023b565b600080546001600160a01b0319166001600160a01b039290921691\
340 90911790555060200135600190815590565b60008082600160008282546101dd919061026\
341 b565b90915550506001549293915050565b6001805460009180836101ff828561026b565b\
342 909155509092915050565b60006040828403121561021c57600080fd5b50919050565b600\
343 06020828403121561023457600080fd5b5035919050565b60006020828403121561024d57\
344 600080fd5b81356001600160a01b038116811461026457600080fd5b9392505050565b808\
345 2018082111561028c57634e487b7160e01b600052601160045260246000fd5b9291505056\
346 fea264697066735822122073a633ec59ee8e261bbdfefdc6d54f1d47dd6ccd6dcab4aa1eb\
347 37b62d24b4c1b64736f6c63430008140033";
348
349 hex::decode(raw).expect("failed to decode bytecode")
350 }
351
352 #[fixture]
353 fn meta_bytecode() -> Vec<u8> {
354 let raw: &str = "6080604052348015600f57600080fd5b50607c80601d6000396000f\
355 3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063a79af2ce\
356 14602d575b600080fd5b6040805142815243602082015281519081900390910190f3fea2646\
357 9706673582212202c76d8081bf4b8745cf50463d5b4f48aadbd688456ec111406e9010a51d4\
358 56ba64736f6c63430008150033";
359 hex::decode(raw).expect("failed to decode meta bytecode")
360 }
361
362 #[test]
363 fn balances() {
364 let zero = U256::from(0);
365 let one_eth = U256::from(1e18);
366
367 let mut evm = BaseEvm::default();
368 let bob = Address::repeat_byte(23);
369
370 evm.create_account(bob, None).unwrap();
371 assert!(evm.get_balance(bob).unwrap() == zero);
372
373 evm.set_balance(bob, one_eth).unwrap();
374 assert!(evm.get_balance(bob).unwrap() == one_eth);
375 }
376
377 #[test]
378 fn simple_transfers() {
379 let one_eth = U256::from(1e18);
380 let addresses = generate_random_addresses(2);
381 let bob = addresses[0];
382 let alice = addresses[1];
383
384 let mut evm = BaseEvm::new(None);
385 evm.create_account(bob, Some(U256::from(2e18))).unwrap();
386 evm.create_account(alice, None).unwrap();
387
388 assert!(evm.transfer(alice, bob, one_eth).is_err()); assert!(evm.transfer(bob, alice, one_eth).is_ok());
390
391 assert!(evm.get_balance(bob).unwrap() == one_eth);
392 assert!(evm.get_balance(alice).unwrap() == one_eth);
393
394 let s = evm.create_snapshot();
395 println!("{:?}", s);
396 }
397
398 #[rstest]
399 fn no_sol_test_contract(contract_bytecode: Vec<u8>) {
400 let zero = U256::from(0);
401 let owner = Address::repeat_byte(12);
402 let mut evm = BaseEvm::default();
403 evm.create_account(owner, Some(U256::from(1e18))).unwrap();
404
405 let mut test_contract_abi = ContractAbi::from_human_readable(vec![
406 "constructor(uint256)",
407 "function owner() (address)",
408 "function value() (uint256)",
409 "function increment() (uint256)",
410 "function increment(uint256) (uint256, uint256)",
411 ]);
412 test_contract_abi.bytecode = Some(contract_bytecode.into());
413
414 let (args, _) = test_contract_abi.encode_constructor("(1)").unwrap();
415 let contract_address = evm.deploy(owner, args, U256::from(0)).unwrap();
416
417 let (enc_owner_call, _, de1) = test_contract_abi.encode_function("owner", "()").unwrap();
419 let o1 = evm
420 .transact_call(contract_address, enc_owner_call, zero)
421 .unwrap();
422 assert!(DynSolValue::Address(owner) == de1.unwrap().abi_decode(&o1.result).unwrap());
423
424 let (enc_inc_0, _, de2) = test_contract_abi
426 .encode_function("increment", "()")
427 .unwrap();
428 let o2 = evm
429 .transact_commit(owner, contract_address, enc_inc_0, zero)
430 .unwrap();
431 assert!(
432 DynSolValue::Uint(U256::from(1), 256) == de2.unwrap().abi_decode(&o2.result).unwrap()
433 );
434
435 let (enc_value_call, _, de3) = test_contract_abi.encode_function("value", "()").unwrap();
437 let o3 = evm
438 .transact_call(contract_address, enc_value_call, zero)
439 .unwrap();
440 assert!(
441 DynSolValue::Uint(U256::from(2), 256) == de3.unwrap().abi_decode(&o3.result).unwrap()
442 );
443
444 let (enc_inc_1, _, de4) = test_contract_abi
446 .encode_function("increment", "(2)")
447 .unwrap();
448 let o4 = evm
449 .transact_commit(owner, contract_address, enc_inc_1, zero)
450 .unwrap();
451 assert!(
452 DynSolValue::Tuple(vec![
453 DynSolValue::Uint(U256::from(2), 256),
454 DynSolValue::Uint(U256::from(4), 256)
455 ]) == de4.unwrap().abi_decode(&o4.result).unwrap()
456 );
457
458 let (enc_inc_sim, _, des) = test_contract_abi
460 .encode_function("increment", "()")
461 .unwrap();
462 let os = evm
463 .simulate(owner, contract_address, enc_inc_sim, zero)
464 .unwrap();
465 assert!(
466 DynSolValue::Uint(U256::from(4), 256) == des.unwrap().abi_decode(&os.result).unwrap()
467 );
468
469 let (enc_value_call1, _, de5) = test_contract_abi.encode_function("value", "()").unwrap();
471 let o5 = evm
472 .transact_call(contract_address, enc_value_call1, zero)
473 .unwrap();
474 assert!(
475 DynSolValue::Uint(U256::from(4), 256) == de5.unwrap().abi_decode(&o5.result).unwrap()
476 );
477 }
478
479 #[rstest]
480 fn sol_calls_on_test_contract(mut contract_bytecode: Vec<u8>) {
481 let zero = U256::from(0);
482 let owner = Address::repeat_byte(12);
483 let new_owner = Address::repeat_byte(33);
484
485 let mut evm = BaseEvm::default();
486
487 evm.create_account(owner, Some(U256::from(1e18))).unwrap();
488
489 let encode_constructor_args = TestContract::constructorCall {
490 _value: U256::from(1),
491 }
492 .abi_encode();
493 contract_bytecode.extend(encode_constructor_args);
494
495 let contract_address = evm
496 .deploy(owner, contract_bytecode, U256::from(1e18))
497 .unwrap();
498
499 let owner_back = evm
500 .transact_call_sol(contract_address, TestContract::ownerCall {}, zero)
501 .unwrap()
502 ._0;
503
504 assert!(owner == owner_back);
505
506 assert_eq!(
508 U256::from(1),
509 evm.transact_commit_sol(
510 owner,
511 contract_address,
512 TestContract::increment_0Call {},
513 zero,
514 )
515 .unwrap()
516 ._0
517 );
518
519 let rt = evm
521 .transact_commit_sol(
522 owner,
523 contract_address,
524 TestContract::increment_1Call {
525 _input: U256::from(3),
526 },
527 zero,
528 )
529 .unwrap();
530 let inp = rt._0;
531 let nv = rt._1;
532
533 assert_eq!(U256::from(3), inp);
534 assert_eq!(U256::from(5), nv);
535
536 assert_eq!(
537 U256::from(5),
538 evm.transact_call_sol(contract_address, TestContract::valueCall {}, zero)
539 .unwrap()
540 ._0
541 );
542
543 assert_eq!(
544 owner,
545 evm.transact_call_sol(contract_address, TestContract::ownerCall {}, zero)
546 .unwrap()
547 ._0
548 );
549
550 assert!(evm
552 .transact_commit_sol(
553 new_owner,
554 contract_address,
555 TestContract::changeItCall {
556 _input: ChangeIt {
557 owner: new_owner,
558 value: zero,
559 },
560 },
561 zero,
562 )
563 .is_err());
564
565 assert!(evm
566 .transact_commit_sol(
567 owner,
568 contract_address,
569 TestContract::changeItCall {
570 _input: ChangeIt {
571 owner: new_owner,
572 value: zero,
573 },
574 },
575 zero,
576 )
577 .is_ok());
578
579 assert_eq!(
580 U256::from(0),
581 evm.transact_call_sol(contract_address, TestContract::valueCall {}, zero)
582 .unwrap()
583 ._0
584 );
585
586 assert_eq!(
587 new_owner,
588 evm.transact_call_sol(contract_address, TestContract::ownerCall {}, zero)
589 .unwrap()
590 ._0
591 );
592
593 assert_eq!(U256::from(1e18), evm.get_balance(contract_address).unwrap());
594 }
595
596 #[rstest]
597 fn snapshots_with_memdb(mut contract_bytecode: Vec<u8>) {
598 let zero = U256::from(0);
599 let owner = Address::repeat_byte(12);
600
601 let mut evm = BaseEvm::default();
602
603 evm.create_account(owner, Some(U256::from(1e18))).unwrap();
604
605 let encode_constructor_args = TestContract::constructorCall {
606 _value: U256::from(0),
607 }
608 .abi_encode();
609 contract_bytecode.extend(encode_constructor_args);
610
611 let contract_address = evm
612 .deploy(owner, contract_bytecode, U256::from(1e18))
613 .unwrap();
614
615 let snap = evm.create_snapshot().unwrap();
616
617 let mut evm2 = BaseEvm::new_from_snapshot(snap);
618
619 assert_eq!(
620 U256::from(1e18),
621 evm2.get_balance(contract_address).unwrap()
622 );
623 assert_eq!(zero, evm2.get_balance(owner).unwrap());
624
625 assert_eq!(
626 U256::from(0),
627 evm2.transact_call_sol(contract_address, TestContract::valueCall {}, zero)
628 .unwrap()
629 ._0
630 );
631
632 assert_eq!(
633 owner,
634 evm2.transact_call_sol(contract_address, TestContract::ownerCall {}, zero)
635 .unwrap()
636 ._0
637 );
638 }
639
640 #[rstest]
641 fn updates_block_meta(meta_bytecode: Vec<u8>) {
642 const INTERVAL: u64 = 15; let owner = Address::repeat_byte(12);
645 let mut evm = BaseEvm::default();
646 evm.create_account(owner, Some(U256::from(1e18))).unwrap();
647 let addr = evm.deploy(owner, meta_bytecode, U256::from(0)).unwrap();
648
649 let tx1 = evm
650 .transact_call_sol(addr, BlockMeta::getMetaCall {}, U256::from(0))
651 .unwrap();
652 assert_eq!(U256::from(1), tx1._1);
653
654 let start = tx1._0;
655 evm.update_block(INTERVAL);
656 evm.update_block(INTERVAL);
657 evm.update_block(INTERVAL);
658
659 let tx2 = evm
660 .transact_call_sol(addr, BlockMeta::getMetaCall {}, U256::from(0))
661 .unwrap();
662
663 let expected_time = start + U256::from(45);
664 let expected_block = U256::from(4);
665
666 assert_eq!(expected_block, tx2._1);
668 assert_eq!(expected_time, tx2._0);
669
670 let snap = evm.create_snapshot().unwrap();
671 assert_eq!(snap.block_num, 4);
672 assert_eq!(U256::from(snap.timestamp), expected_time);
673
674 let mut evm2 = BaseEvm::new_from_snapshot(snap);
676 let tx3 = evm2
677 .transact_call_sol(addr, BlockMeta::getMetaCall {}, U256::from(0))
678 .unwrap();
679 assert_eq!(expected_block, tx3._1);
680 assert_eq!(expected_time, tx3._0);
681 }
682}