1mod utils;
11mod validator;
12
13use crate::contract::{Event, Transaction};
14use crate::utils::Eth;
15use crate::{ForkDb, LocalDB, RequestCache, DB};
16use alloy_primitives::{Address, FixedBytes, B256, U256};
17use alloy_sol_types::SolCall;
18use log::debug;
19use rand::Rng;
20use revm::primitives::{AccountInfo, Bytecode, ExecutionResult, Log, ResultAndState, TxEnv};
21use revm::{ContextWithHandlerCfg, Evm, Handler};
22pub use utils::{decode_event, process_events, RevertError};
23pub use validator::{GasPriorityValidator, RandomValidator, Validator};
24
25pub struct Env<D: DB, V: Validator> {
31 pub evm_state: Option<ContextWithHandlerCfg<(), D>>,
33 pub last_events: Vec<Event>,
35 pub event_history: Vec<Event>,
38 pub validator: V,
40}
41
42trait CallEVM {
44 fn execute(&mut self, tx: TxEnv) -> ExecutionResult;
46 fn call(&mut self, tx: TxEnv) -> ResultAndState;
48}
49
50impl<'a, D: DB> CallEVM for Evm<'a, (), D> {
51 fn execute(&mut self, tx: TxEnv) -> ExecutionResult {
52 self.context.evm.env.tx = tx;
53
54 match self.transact_commit() {
55 Ok(val) => val,
56 Err(e) => match e {
57 revm::primitives::EVMError::Transaction(t) => {
58 panic!("Call failed: Invalid transaction {:?}", t)
59 }
60 revm::primitives::EVMError::Header(h) => {
61 panic!("Call failed: Invalid header {:?}", h)
62 }
63 revm::primitives::EVMError::Database(d) => {
64 panic!("Call failed: Database error {:?}", d)
65 }
66 revm::primitives::EVMError::Custom(c) => {
67 panic!("Call failed: Custom error {:?}", c)
68 }
69 },
70 }
71 }
72
73 fn call(&mut self, tx: TxEnv) -> ResultAndState {
74 self.context.evm.env.tx = tx;
75
76 match self.transact() {
77 Ok(val) => val,
78 Err(e) => match e {
79 revm::primitives::EVMError::Transaction(t) => {
80 panic!("Call failed: Invalid transaction {:?}", t)
81 }
82 revm::primitives::EVMError::Header(h) => {
83 panic!("Call failed: Invalid header {:?}", h)
84 }
85 revm::primitives::EVMError::Database(d) => {
86 panic!("Call failed: Database error {:?}", d)
87 }
88 revm::primitives::EVMError::Custom(c) => {
89 panic!("Call failed: Custom error {:?}", c)
90 }
91 },
92 }
93 }
94}
95
96impl<V: Validator> Env<ForkDb, V> {
97 pub fn init(node_url: &str, block_number: Option<u64>, validator: V) -> Self {
113 let db = ForkDb::new(node_url, block_number);
114 let timestamp = db.block.timestamp.as_u128();
115 let block_number = match db.block.number {
116 Some(n) => U256::try_from(n.as_u64()).unwrap(),
117 None => U256::ZERO,
118 };
119
120 let evm = Evm::builder()
121 .with_db(db)
122 .modify_cfg_env(|cfg| {
123 cfg.limit_contract_code_size = Some(0x1000000);
124 cfg.disable_eip3607 = true;
125 })
126 .modify_block_env(|block| {
127 block.gas_limit = U256::MAX;
128 block.timestamp = U256::try_from(timestamp).unwrap();
129 block.number = block_number;
130 })
131 .build();
132
133 let context = evm.into_context_with_handler_cfg();
134
135 Self {
136 evm_state: Some(context),
137 last_events: Vec::new(),
138 event_history: Vec::new(),
139 validator,
140 }
141 }
142
143 pub fn get_request_history(&self) -> &RequestCache {
150 match &self.evm_state {
151 Some(e) => &e.context.evm.db.requests,
152 None => panic!("No EVM state set"),
153 }
154 }
155}
156
157impl<V: Validator> Env<LocalDB, V> {
158 pub fn init(timestamp: U256, block_number: U256, validator: V) -> Self {
171 let evm = Evm::builder()
172 .with_db(LocalDB::new())
173 .modify_cfg_env(|cfg| {
174 cfg.limit_contract_code_size = Some(0x1000000);
175 cfg.disable_eip3607 = true;
176 })
177 .modify_block_env(|block| {
178 block.gas_limit = U256::MAX;
179 block.timestamp = timestamp;
180 block.number = block_number;
181 })
182 .build();
183
184 let start_balance = U256::to_weth(10_000);
185
186 let mut env = Self {
187 evm_state: Some(evm.into_context_with_handler_cfg()),
188 last_events: Vec::new(),
189 event_history: Vec::new(),
190 validator,
191 };
192
193 env.insert_account(Address::ZERO, start_balance);
194
195 env
196 }
197}
198
199impl<D: DB, V: Validator> Env<D, V> {
200 fn evm(&mut self) -> Evm<(), D> {
201 let state = self.evm_state.take();
202
203 match state {
204 Some(s) => {
205 let ContextWithHandlerCfg { context, cfg } = s;
206 Evm {
207 context,
208 handler: Handler::new(cfg),
209 }
210 }
211 None => panic!("No EVM state set (this should not happen!)"),
212 }
213 }
214
215 pub fn evm_state(&mut self) -> &mut ContextWithHandlerCfg<(), D> {
217 match &mut self.evm_state {
218 Some(e) => e,
219 None => panic!("No EVM state set (this should not happen!)"),
220 }
221 }
222
223 pub fn increment_time<R: Rng>(&mut self, rng: &mut R, interval: u64) {
225 let state = self.evm_state();
226 state.context.evm.env.block.timestamp += U256::from(interval);
227 state.context.evm.env.block.number += U256::from(1);
228 state.context.evm.env.block.prevrandao = Some(FixedBytes(rng.gen::<[u8; 32]>()));
229 }
230
231 pub fn insert_account(&mut self, address: Address, start_balance: U256) {
239 self.evm_state().context.evm.db.insert_account_info(
240 address,
241 AccountInfo::new(start_balance, 0, B256::default(), Bytecode::default()),
242 );
243 }
244
245 pub fn insert_accounts(&mut self, start_balance: u128, addresses: Vec<Address>) {
253 let start_balance = U256::from(start_balance);
254 for address in addresses {
255 self.insert_account(address, start_balance);
256 }
257 }
258
259 pub fn deploy_contract(
270 &mut self,
271 deployer: Address,
272 contract_name: &str,
273 data: Vec<u8>,
274 ) -> Address {
275 let tx = utils::init_create_transaction(deployer, data);
276 let mut evm = self.evm();
277 let result = evm.execute(tx);
278 let output = utils::deployment_output(contract_name, result);
279 let deploy_address = match output {
280 revm::primitives::Output::Create(_, address) => address.unwrap(),
281 _ => panic!("Deployment of {} failed", contract_name),
282 };
283 debug!("Deployed {} to {}", contract_name, deploy_address);
284 self.evm_state = Some(evm.into_context_with_handler_cfg());
285 deploy_address
286 }
287
288 pub fn direct_execute_raw(
299 &mut self,
300 callee: Address,
301 contract: Address,
302 encoded_args: Vec<u8>,
303 value: U256,
304 ) -> Result<ExecutionResult, RevertError> {
305 let tx = utils::init_call_transaction(callee, contract, encoded_args, value);
306 let mut evm = self.evm();
307 let execution_result = evm.execute(tx);
308 self.evm_state = Some(evm.into_context_with_handler_cfg());
309 utils::result_to_raw_output(callee, execution_result)
310 }
311
312 pub fn direct_execute<T: SolCall>(
322 &mut self,
323 callee: Address,
324 contract: Address,
325 call_args: T,
326 value: U256,
327 ) -> Result<(<T as SolCall>::Return, Vec<Log>), utils::RevertError> {
328 let function_name = T::SIGNATURE;
329 let call_args = call_args.abi_encode();
330 let tx = utils::init_call_transaction(callee, contract, call_args, value);
331 let mut evm = self.evm();
332 let execution_result = evm.execute(tx);
333 let (output, events) = utils::result_to_output(function_name, callee, execution_result)?;
334 let output_data = output.into_data();
335 let decoded = T::abi_decode_returns(&output_data, true);
336 let decoded = match decoded {
337 Ok(x) => x,
338 Err(e) => panic!("Decoding error from {} {:?}", function_name, e),
339 };
340 self.evm_state = Some(evm.into_context_with_handler_cfg());
341 Ok((decoded, events))
342 }
343
344 pub fn direct_call_raw(
353 &mut self,
354 callee: Address,
355 contract: Address,
356 encoded_args: Vec<u8>,
357 value: U256,
358 ) -> Result<ExecutionResult, RevertError> {
359 let tx = utils::init_call_transaction(callee, contract, encoded_args, value);
360 let mut evm = self.evm();
361 let result = evm.call(tx);
362 self.evm_state = Some(evm.into_context_with_handler_cfg());
363 utils::result_to_raw_output(callee, result.result)
364 }
365
366 pub fn direct_call<T: SolCall>(
376 &mut self,
377 callee: Address,
378 contract: Address,
379 call_args: T,
380 value: U256,
381 ) -> Result<(<T as SolCall>::Return, Vec<Log>), utils::RevertError> {
382 let function_name = T::SIGNATURE;
383 let call_args = call_args.abi_encode();
384 let tx = utils::init_call_transaction(callee, contract, call_args, value);
385 let mut evm = self.evm();
386 let execution_result = evm.call(tx);
387 let (output, events) =
388 utils::result_to_output(function_name, callee, execution_result.result)?;
389 let output_data = output.into_data();
390 let decoded = T::abi_decode_returns(&output_data, true);
391 let decoded = match decoded {
392 Ok(x) => x,
393 Err(_) => panic!("Decoding error from {}", function_name),
394 };
395 self.evm_state = Some(evm.into_context_with_handler_cfg());
396 Ok((decoded, events))
397 }
398
399 fn call_from_transaction(
412 evm: &mut Evm<'_, (), D>,
413 last_events: &mut Vec<Event>,
414 transaction: Transaction,
415 step: usize,
416 sequence: usize,
417 ) {
418 debug!(
419 "Calling {:?} of {}",
420 transaction.function_selector, transaction.transact_to
421 );
422 let function_selector = transaction.function_selector;
423 let check_call = transaction.checked;
424 let tx = utils::init_call_transaction(
425 transaction.callee,
426 transaction.transact_to,
427 transaction.args,
428 transaction.value,
429 );
430 let execution_result = evm.execute(tx);
431 let result = utils::result_to_output_with_events(
432 step,
433 sequence,
434 function_selector,
435 transaction.callee,
436 execution_result,
437 check_call,
438 );
439 last_events.push(result);
440 }
441
442 pub fn process_transactions<R: Rng>(
449 &mut self,
450 transactions: Vec<Transaction>,
451 rng: &mut R,
452 step: usize,
453 ) {
454 let transactions = self.validator.order_transactions(rng, transactions);
455
456 let mut evm = self.evm();
457 let mut events = Vec::<Event>::new();
458
459 for (i, call) in transactions.into_iter().enumerate() {
460 Self::call_from_transaction(&mut evm, &mut events, call, step, i);
461 }
462 self.evm_state = Some(evm.into_context_with_handler_cfg());
463 self.last_events.extend(events);
464 }
465
466 pub fn clear_events(&mut self) {
472 self.event_history.append(&mut self.last_events);
473 }
474}
475
476#[cfg(test)]
477mod tests {
478
479 use super::*;
480 use crate::utils;
481 use alloy_primitives::{Address, Signed, Uint};
482 use alloy_sol_types::{sol, SolValue};
483 use rand::SeedableRng;
484 use rand_xoshiro::Xoroshiro128StarStar;
485 use rstest::*;
486
487 sol!(
488 TestContract,
489 r#"[
490 {
491 "inputs": [
492 {
493 "internalType": "int256",
494 "name": "x",
495 "type": "int256"
496 }
497 ],
498 "stateMutability": "nonpayable",
499 "type": "constructor"
500 },
501 {
502 "inputs": [],
503 "name": "getValue",
504 "outputs": [
505 {
506 "internalType": "int256",
507 "name": "",
508 "type": "int256"
509 }
510 ],
511 "stateMutability": "view",
512 "type": "function"
513 },
514 {
515 "inputs": [
516 {
517 "internalType": "int256",
518 "name": "x",
519 "type": "int256"
520 }
521 ],
522 "name": "setValue",
523 "outputs": [],
524 "stateMutability": "nonpayable",
525 "type": "function"
526 }
527 ]"#
528 );
529
530 #[fixture]
531 fn deployment() -> (Env<LocalDB, RandomValidator>, Address, Address) {
532 let mut network =
533 Env::<LocalDB, RandomValidator>::init(U256::ZERO, U256::ZERO, RandomValidator {});
534
535 let constructor_args = <i128>::abi_encode(&101);
536 let bytecode_hex = "608060405234801561001057600080fd5b50\
537 6040516102063803806102068339818101604052810190610032919061007a\
538 565b80600081905550506100a7565b600080fd5b6000819050919050565b61\
539 005781610044565b811461006257600080fd5b50565b600081519050610074\
540 8161004e565b92915050565b6000602082840312156100905761008f61003f\
541 565b5b600061009e84828501610065565b91505092915050565b6101508061\
542 00b66000396000f3fe608060405234801561001057600080fd5b5060043610\
543 6100365760003560e01c8063209652551461003b5780635093dc7d14610059\
544 575b600080fd5b610043610075565b60405161005091906100a1565b604051\
545 80910390f35b610073600480360381019061006e91906100ed565b61007e56\
546 5b005b60008054905090565b8060008190555050565b600081905091905056\
547 5b61009b81610088565b82525050565b60006020820190506100b660008301\
548 84610092565b92915050565b600080fd5b6100ca81610088565b81146100d5\
549 57600080fd5b50565b6000813590506100e7816100c1565b92915050565b60\
550 0060208284031215610103576101026100bc565b5b60006101118482850161\
551 00d8565b9150509291505056fea2646970667358221220d99fa7a11a5739cf\
552 9f1c4e30ebbb603943f8e1e44a3b4c0c10c3ea53799a236d64736f6c634300\
553 080a0033";
554
555 let user_address = Address::from(Uint::from(999));
556 network.insert_account(user_address, Eth::to_weth(100));
557
558 let mut bytecode: Vec<u8> = utils::data_bytes_from_hex(bytecode_hex);
559 bytecode.extend(constructor_args);
560 let contract_address = network.deploy_contract(user_address, "test", bytecode);
561
562 (network, contract_address, user_address)
563 }
564
565 #[rstest]
566 fn direct_execute_and_call(deployment: (Env<LocalDB, RandomValidator>, Address, Address)) {
567 let (mut network, contract_address, user_address) = deployment;
568
569 let (v, _) = network
570 .direct_call(
571 user_address,
572 contract_address,
573 TestContract::getValueCall {},
574 U256::ZERO,
575 )
576 .unwrap();
577
578 assert_eq!(v._0.as_i64(), 101i64);
579
580 let _ = network
581 .direct_execute(
582 user_address,
583 contract_address,
584 TestContract::setValueCall { x: Signed::ONE },
585 U256::ZERO,
586 )
587 .unwrap();
588
589 let (v, _) = network
590 .direct_call(
591 user_address,
592 contract_address,
593 TestContract::getValueCall {},
594 U256::ZERO,
595 )
596 .unwrap();
597
598 assert_eq!(v._0.as_i64(), 1i64);
599 }
600
601 #[rstest]
602 fn processing_calls(deployment: (Env<LocalDB, RandomValidator>, Address, Address)) {
603 let (mut network, contract_address, user_address) = deployment;
604
605 let calls = vec![
606 Transaction::basic(
607 user_address,
608 contract_address,
609 TestContract::setValueCall {
610 x: Signed::try_from_be_slice(&303u128.to_be_bytes()).unwrap(),
611 },
612 true,
613 ),
614 Transaction::basic(
615 user_address,
616 contract_address,
617 TestContract::setValueCall {
618 x: Signed::try_from_be_slice(&303u128.to_be_bytes()).unwrap(),
619 },
620 true,
621 ),
622 ];
623
624 let mut rng = Xoroshiro128StarStar::seed_from_u64(101);
625
626 network.process_transactions(calls, &mut rng, 1);
627
628 let (v, _) = network
629 .direct_call(
630 user_address,
631 contract_address,
632 TestContract::getValueCall {},
633 U256::ZERO,
634 )
635 .unwrap();
636
637 assert_eq!(v._0.as_i64(), 303i64);
638 }
639}