1use super::*;
2use context_interface::{
3 cfg::GasParams,
4 context::{SStoreResult, SelfDestructResult, StateLoad},
5 host::LoadError,
6 journaled_state::AccountInfoLoad,
7};
8use revm_bytecode::opcode as op;
9use revm_interpreter::{
10 CallInput, Host, InputsImpl, Interpreter, SharedMemory,
11 instructions::instruction_table_gas_changes_spec, interpreter::ExtBytecode,
12};
13use revm_primitives::{B256, HashMap, Log, hardfork::SpecId};
14use similar_asserts::assert_eq;
15use std::{fmt, path::Path, sync::OnceLock};
16
17pub fn init_tracing() {
19 let _ = tracing_subscriber::fmt::try_init();
20}
21
22#[derive(Clone, Debug)]
24pub struct DefEnv {
25 pub tx: DefTx,
26 pub block: DefBlock,
27 pub cfg: DefCfg,
28}
29
30#[derive(Clone, Debug)]
31pub struct DefTx {
32 pub caller: Address,
33 pub blob_hashes: Vec<B256>,
34}
35
36#[derive(Clone, Debug)]
37pub struct DefBlock {
38 pub coinbase: Address,
39 pub timestamp: U256,
40 pub number: U256,
41 pub difficulty: U256,
42 pub prevrandao: Option<B256>,
43 pub gas_limit: U256,
44 pub basefee: U256,
45}
46
47impl DefBlock {
48 pub fn get_blob_gasprice(&self) -> Option<u64> {
49 Some(0) }
51}
52
53#[derive(Clone, Debug)]
54pub struct DefCfg {
55 pub chain_id: u64,
56}
57
58impl DefEnv {
59 pub fn effective_gas_price(&self) -> U256 {
60 U256::from(0x4567)
61 }
62}
63
64pub fn def_env() -> DefEnv {
66 DefEnv {
67 tx: DefTx {
68 caller: Address::repeat_byte(0xcc),
69 blob_hashes: vec![B256::repeat_byte(0x01), B256::repeat_byte(0x02)],
70 },
71 block: DefBlock {
72 coinbase: Address::repeat_byte(0xcb),
73 timestamp: U256::from(0x1234),
74 number: DEF_BN,
75 difficulty: U256::from(0xcdef),
76 prevrandao: Some(B256::from(U256::from(0x0123))),
77 gas_limit: U256::from(0x5678),
78 basefee: U256::from(0x1231),
79 },
80 cfg: DefCfg { chain_id: 69 },
81 }
82}
83
84pub fn memory_gas_cost(num_words: usize) -> u64 {
86 (num_words as u64) * 3 + (num_words as u64) * (num_words as u64) / 512
87}
88
89pub struct TestCase<'a> {
90 pub bytecode: &'a [u8],
91 pub spec_id: SpecId,
92 pub is_static: bool,
93 pub gas_limit: u64,
94
95 pub inspect_stack: Option<bool>,
97 pub modify_ecx: Option<fn(&mut EvmContext<'_>)>,
98
99 pub expected_return: InstructionResult,
100 pub expected_stack: &'a [U256],
101 pub expected_memory: &'a [u8],
102 pub expected_gas: u64,
103 pub expected_next_action: InterpreterAction,
104 pub assert_host: Option<fn(&TestHost)>,
105 pub assert_ecx: Option<fn(&EvmContext<'_>)>,
106}
107
108#[cfg(feature = "__fuzzing")]
109impl<'a> arbitrary::Arbitrary<'a> for TestCase<'a> {
110 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
111 let spec_id_range = 0..=(SpecId::OSAKA as u8 - 1);
112 let spec_id = SpecId::try_from_u8(u.int_in_range(spec_id_range)?).unwrap_or(DEF_SPEC);
113
114 let bytecode: &'a [u8] = u.arbitrary()?;
115
116 Ok(Self::what_interpreter_says(bytecode, spec_id))
117 }
118}
119
120impl Default for TestCase<'_> {
121 fn default() -> Self {
122 Self {
123 bytecode: &[],
124 spec_id: DEF_SPEC,
125 is_static: false,
126 gas_limit: DEF_GAS_LIMIT,
127 inspect_stack: None,
128 modify_ecx: None,
129 expected_return: InstructionResult::Stop,
130 expected_stack: &[],
131 expected_memory: &[],
132 expected_gas: 0,
133 expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
134 assert_host: None,
135 assert_ecx: None,
136 }
137 }
138}
139
140impl fmt::Debug for TestCase<'_> {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 f.debug_struct("TestCase")
143 .field("bytecode", &format_bytecode(self.bytecode, self.spec_id))
144 .field("spec_id", &self.spec_id)
145 .field("inspect_stack", &self.inspect_stack)
146 .field("modify_ecx", &self.modify_ecx.is_some())
147 .field("expected_return", &self.expected_return)
148 .field("expected_stack", &self.expected_stack)
149 .field("expected_memory", &MemDisplay(self.expected_memory))
150 .field("expected_gas", &self.expected_gas)
151 .field("expected_next_action", &self.expected_next_action)
152 .field("assert_host", &self.assert_host.is_some())
153 .field("assert_ecx", &self.assert_ecx.is_some())
154 .finish()
155 }
156}
157
158impl<'a> TestCase<'a> {
159 pub fn what_interpreter_says(bytecode: &'a [u8], spec_id: SpecId) -> Self {
160 Self {
161 bytecode,
162 spec_id,
163 is_static: false,
164 gas_limit: DEF_GAS_LIMIT,
165 inspect_stack: None,
166 modify_ecx: None,
167 expected_return: RETURN_WHAT_INTERPRETER_SAYS,
168 expected_stack: STACK_WHAT_INTERPRETER_SAYS,
169 expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
170 expected_gas: GAS_WHAT_INTERPRETER_SAYS,
171 expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
172 assert_host: None,
173 assert_ecx: None,
174 }
175 }
176}
177
178pub const DEF_SPEC: SpecId = SpecId::CANCUN;
180pub static DEF_OPINFOS: std::sync::LazyLock<&'static [OpcodeInfo; 256]> =
181 std::sync::LazyLock::new(|| op_info_map(DEF_SPEC));
182
183pub const DEF_GAS_LIMIT: u64 = 100_000;
184pub const DEF_GAS_LIMIT_U256: U256 = U256::from_le_slice(&DEF_GAS_LIMIT.to_le_bytes());
185
186pub const DEF_ADDR: Address = Address::repeat_byte(0xba);
188pub const DEF_CALLER: Address = Address::repeat_byte(0xca);
189pub static DEF_CD: &[u8] = &[0xaa; 64];
190pub static DEF_RD: &[u8] = &[0xbb; 64];
191pub static DEF_DATA: &[u8] = &[0xcc; 64];
192pub const DEF_VALUE: U256 = uint!(123_456_789_U256);
193pub static DEF_STORAGE: OnceLock<HashMap<U256, U256>> = OnceLock::new();
194pub static DEF_CODEMAP: OnceLock<HashMap<Address, revm_bytecode::Bytecode>> = OnceLock::new();
195pub const OTHER_ADDR: Address = Address::repeat_byte(0x69);
196pub const DEF_BN: U256 = uint!(500_U256);
197
198pub const RETURN_WHAT_INTERPRETER_SAYS: InstructionResult = InstructionResult::PrecompileError;
199pub const STACK_WHAT_INTERPRETER_SAYS: &[U256] =
200 &[U256::from_be_slice(&GAS_WHAT_INTERPRETER_SAYS.to_be_bytes())];
201pub const MEMORY_WHAT_INTERPRETER_SAYS: &[u8] = &GAS_WHAT_INTERPRETER_SAYS.to_be_bytes();
202pub const GAS_WHAT_INTERPRETER_SAYS: u64 = 0x4682e332d6612de1;
203pub const ACTION_WHAT_INTERPRETER_SAYS: InterpreterAction =
204 InterpreterAction::Return(InterpreterResult {
205 gas: Gas::new(GAS_WHAT_INTERPRETER_SAYS),
206 output: Bytes::from_static(MEMORY_WHAT_INTERPRETER_SAYS),
207 result: RETURN_WHAT_INTERPRETER_SAYS,
208 });
209
210pub fn def_storage() -> &'static HashMap<U256, U256> {
211 DEF_STORAGE.get_or_init(|| {
212 let mut map = HashMap::default();
213 map.insert(U256::from(0), U256::from(1));
214 map.insert(U256::from(1), U256::from(2));
215 map.insert(U256::from(69), U256::from(42));
216 map
217 })
218}
219
220pub fn def_codemap() -> &'static HashMap<Address, revm_bytecode::Bytecode> {
221 DEF_CODEMAP.get_or_init(|| {
222 let mut map = HashMap::default();
223 map.insert(
224 OTHER_ADDR,
225 revm_bytecode::Bytecode::new_raw(Bytes::from_static(&[
226 op::PUSH1,
227 0x69,
228 op::PUSH1,
229 0x42,
230 op::ADD,
231 op::STOP,
232 ])),
233 );
234 map
235 })
236}
237
238pub struct TestHost {
240 pub storage: HashMap<U256, U256>,
241 pub transient_storage: HashMap<U256, U256>,
242 pub code_map: &'static HashMap<Address, revm_bytecode::Bytecode>,
243 pub selfdestructs: Vec<(Address, Address)>,
244 pub logs: Vec<Log>,
245 pub gas_params: GasParams,
246}
247
248impl Default for TestHost {
249 fn default() -> Self {
250 Self::new()
251 }
252}
253
254impl TestHost {
255 pub fn new() -> Self {
256 Self::with_spec(DEF_SPEC)
257 }
258
259 pub fn with_spec(spec_id: SpecId) -> Self {
260 Self {
261 storage: def_storage().clone(),
262 transient_storage: HashMap::default(),
263 code_map: def_codemap(),
264 selfdestructs: Vec::new(),
265 logs: Vec::new(),
266 gas_params: GasParams::new_spec(spec_id),
267 }
268 }
269}
270
271impl Host for TestHost {
272 fn basefee(&self) -> U256 {
273 U256::from(0x1231)
274 }
275
276 fn blob_gasprice(&self) -> U256 {
277 U256::ZERO
278 }
279
280 fn gas_limit(&self) -> U256 {
281 U256::from(0x5678)
282 }
283
284 fn gas_params(&self) -> &GasParams {
285 &self.gas_params
286 }
287
288 fn is_amsterdam_eip8037_enabled(&self) -> bool {
289 false
290 }
291
292 fn difficulty(&self) -> U256 {
293 U256::from(0xcdef)
294 }
295
296 fn prevrandao(&self) -> Option<U256> {
297 Some(U256::from(0x0123))
298 }
299
300 fn block_number(&self) -> U256 {
301 DEF_BN
302 }
303
304 fn timestamp(&self) -> U256 {
305 U256::from(0x1234)
306 }
307
308 fn beneficiary(&self) -> Address {
309 Address::repeat_byte(0xcb)
310 }
311
312 fn slot_num(&self) -> U256 {
313 U256::ZERO
314 }
315
316 fn chain_id(&self) -> U256 {
317 U256::from(69)
318 }
319
320 fn effective_gas_price(&self) -> U256 {
321 U256::from(0x4567)
322 }
323
324 fn caller(&self) -> Address {
325 Address::repeat_byte(0xcc)
326 }
327
328 fn blob_hash(&self, number: usize) -> Option<U256> {
329 let env = def_env();
330 env.tx.blob_hashes.get(number).map(|h| (*h).into())
331 }
332
333 fn max_initcode_size(&self) -> usize {
334 49152
336 }
337
338 fn block_hash(&mut self, number: u64) -> Option<B256> {
339 Some(U256::from(number).into())
340 }
341
342 fn selfdestruct(
343 &mut self,
344 address: Address,
345 target: Address,
346 _skip_cold_load: bool,
347 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
348 self.selfdestructs.push((address, target));
349
350 Ok(StateLoad::new(
351 SelfDestructResult {
352 had_value: false,
353 target_exists: true,
354 previously_destroyed: false,
355 },
356 false,
357 ))
358 }
359
360 fn log(&mut self, log: Log) {
361 self.logs.push(log);
362 }
363
364 fn tstore(&mut self, _address: Address, key: U256, value: U256) {
365 self.transient_storage.insert(key, value);
366 }
367
368 fn tload(&mut self, _address: Address, key: U256) -> U256 {
369 self.transient_storage.get(&key).copied().unwrap_or(U256::ZERO)
370 }
371
372 fn load_account_info_skip_cold_load(
373 &mut self,
374 address: Address,
375 load_code: bool,
376 _skip_cold_load: bool,
377 ) -> Result<AccountInfoLoad<'_>, LoadError> {
378 use revm_state::AccountInfo;
379 use std::borrow::Cow;
380
381 let code = if load_code {
382 Some(self.code_map.get(&address).cloned().unwrap_or_default())
384 } else {
385 None
386 };
387
388 let balance = U256::from(address.0[19]);
391
392 let code_hash = if let Some(bytecode) = self.code_map.get(&address) {
394 keccak256(bytecode.original_byte_slice())
395 } else {
396 KECCAK_EMPTY
397 };
398
399 let info = AccountInfo { balance, nonce: 0, code_hash, account_id: None, code };
401
402 let is_empty = info.code.is_none() && info.balance.is_zero() && info.nonce == 0;
403
404 Ok(AccountInfoLoad { account: Cow::Owned(info), is_cold: false, is_empty })
405 }
406
407 fn sstore_skip_cold_load(
408 &mut self,
409 _address: Address,
410 key: U256,
411 value: U256,
412 _skip_cold_load: bool,
413 ) -> Result<StateLoad<SStoreResult>, LoadError> {
414 let original = self.storage.get(&key).copied().unwrap_or(U256::ZERO);
415 self.storage.insert(key, value);
416 Ok(StateLoad::new(
417 SStoreResult { original_value: original, present_value: original, new_value: value },
418 false,
419 ))
420 }
421
422 fn sload_skip_cold_load(
423 &mut self,
424 _address: Address,
425 key: U256,
426 _skip_cold_load: bool,
427 ) -> Result<StateLoad<U256>, LoadError> {
428 let value = self.storage.get(&key).copied().unwrap_or(U256::ZERO);
429 Ok(StateLoad::new(value, false))
430 }
431}
432
433pub fn with_evm_context<F: FnOnce(&mut EvmContext<'_>, &mut EvmStack, &mut usize) -> R, R>(
434 bytecode: &[u8],
435 spec_id: SpecId,
436 f: F,
437) -> R {
438 let input = InputsImpl {
439 target_address: DEF_ADDR,
440 bytecode_address: None,
441 caller_address: DEF_CALLER,
442 input: CallInput::Bytes(Bytes::from_static(DEF_CD)),
443 call_value: DEF_VALUE,
444 };
445
446 let bytecode_obj = revm_bytecode::Bytecode::new_raw(Bytes::copy_from_slice(bytecode));
447 let ext_bytecode = ExtBytecode::new(bytecode_obj);
448
449 let mut interpreter =
450 Interpreter::new(SharedMemory::new(), ext_bytecode, input, false, spec_id, DEF_GAS_LIMIT);
451
452 let mut host = TestHost::with_spec(spec_id);
453
454 let (mut ecx, stack, stack_len) =
455 EvmContext::from_interpreter_with_stack(&mut interpreter, &mut host);
456 f(&mut ecx, stack, stack_len)
457}
458
459pub fn set_test_dump<B: Backend>(compiler: &mut EvmCompiler<B>, module_path: &str) {
460 let root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
461 let mut dump_path = root.to_path_buf();
462 dump_path.push("target");
463 dump_path.push("tests_dump");
464 dump_path.extend(module_path.split("::").skip(2));
466 dump_path.push(format!("{:?}", compiler.opt_level()));
467 compiler.set_dump_to(Some(dump_path));
468}
469
470pub fn run_test_case<B: Backend>(test_case: &TestCase<'_>, compiler: &mut EvmCompiler<B>) {
471 let TestCase { bytecode, spec_id, .. } = *test_case;
472 compiler.inspect_stack(test_case.inspect_stack.unwrap_or(true));
473 let f = unsafe { compiler.jit("test", bytecode, spec_id) }.unwrap();
475 run_compiled_test_case(test_case, f);
476}
477
478fn run_compiled_test_case(test_case: &TestCase<'_>, f: EvmCompilerFn) {
479 let TestCase {
480 bytecode,
481 spec_id,
482 is_static,
483 gas_limit,
484 inspect_stack: _,
485 modify_ecx,
486 expected_return,
487 expected_stack,
488 expected_memory,
489 expected_gas,
490 ref expected_next_action,
491 assert_host,
492 assert_ecx,
493 } = *test_case;
494
495 with_evm_context(bytecode, spec_id, |ecx, stack, stack_len| {
496 if is_static {
497 ecx.is_static = true;
498 }
499 if gas_limit != DEF_GAS_LIMIT {
500 ecx.gas = Gas::new(gas_limit);
501 }
502 if let Some(modify_ecx) = modify_ecx {
503 modify_ecx(ecx);
504 }
505
506 let input = InputsImpl {
508 target_address: DEF_ADDR,
509 bytecode_address: None,
510 caller_address: DEF_CALLER,
511 input: CallInput::Bytes(Bytes::from_static(DEF_CD)),
512 call_value: DEF_VALUE,
513 };
514 let bytecode_obj = revm_bytecode::Bytecode::new_raw(Bytes::copy_from_slice(bytecode));
515 let ext_bytecode = ExtBytecode::new(bytecode_obj);
516 let mut interpreter = Interpreter::new(
517 SharedMemory::new(),
518 ext_bytecode,
519 input,
520 is_static,
521 spec_id,
522 gas_limit,
523 );
524
525 let table = instruction_table_gas_changes_spec::<
526 revm_interpreter::interpreter::EthInterpreter,
527 TestHost,
528 >(spec_id);
529 let mut int_host = TestHost::with_spec(spec_id);
530 let interpreter_action = interpreter.run_plain(&table, &mut int_host);
531
532 let int_result = match &interpreter_action {
533 InterpreterAction::Return(result) => result.result,
534 _ => InstructionResult::Stop,
535 };
536
537 let mut expected_return = expected_return;
538 if expected_return == RETURN_WHAT_INTERPRETER_SAYS {
539 expected_return = int_result;
540 } else if modify_ecx.is_none() {
541 assert_eq!(int_result, expected_return, "interpreter return value mismatch");
545 }
546
547 let skip_interpreter_checks = modify_ecx.is_some() || expected_return.is_error();
550
551 let mut expected_stack = expected_stack;
552 if expected_stack == STACK_WHAT_INTERPRETER_SAYS {
553 if skip_interpreter_checks {
554 expected_stack = &[]; } else {
556 expected_stack = interpreter.stack.data();
557 }
558 } else if !skip_interpreter_checks {
559 assert_eq!(interpreter.stack.data(), expected_stack, "interpreter stack mismatch");
560 }
561
562 let interpreter_memory = interpreter.memory.context_memory();
563 let mut expected_memory = expected_memory;
564 if expected_memory == MEMORY_WHAT_INTERPRETER_SAYS {
565 if skip_interpreter_checks {
566 expected_memory = &[]; } else {
568 expected_memory = &*interpreter_memory;
569 }
570 } else if !skip_interpreter_checks {
571 assert_eq!(
572 MemDisplay(&interpreter_memory),
573 MemDisplay(expected_memory),
574 "interpreter memory mismatch"
575 );
576 }
577
578 let mut expected_gas = expected_gas;
579 if expected_gas == GAS_WHAT_INTERPRETER_SAYS {
580 if skip_interpreter_checks {
581 expected_gas = 0; } else {
583 expected_gas = interpreter.gas.total_gas_spent();
584 }
585 } else if !skip_interpreter_checks {
586 assert_eq!(interpreter.gas.total_gas_spent(), expected_gas, "interpreter gas mismatch");
587 }
588
589 let skip_jit_stack =
591 skip_interpreter_checks && test_case.expected_stack == STACK_WHAT_INTERPRETER_SAYS;
592 let skip_jit_memory =
593 skip_interpreter_checks && test_case.expected_memory == MEMORY_WHAT_INTERPRETER_SAYS;
594 let skip_jit_gas =
595 skip_interpreter_checks && test_case.expected_gas == GAS_WHAT_INTERPRETER_SAYS;
596
597 let default_action = InterpreterAction::Return(InterpreterResult {
599 result: int_result,
600 output: Bytes::new(),
601 gas: interpreter.gas,
602 });
603 let mut expected_next_action = expected_next_action;
604 if *expected_next_action == ACTION_WHAT_INTERPRETER_SAYS {
605 expected_next_action = &interpreter_action;
606 } else if modify_ecx.is_none() {
607 assert_actions(&interpreter_action, expected_next_action);
611 }
612
613 if let Some(assert_host) = assert_host {
614 assert_host(&int_host);
615 }
616
617 let actual_return = unsafe { f.call(stack, stack_len, ecx) };
618
619 if matches!(
620 actual_return,
621 |InstructionResult::StackOverflow| InstructionResult::StackUnderflow
623 | InstructionResult::OutOfGas | InstructionResult::MemoryOOG | InstructionResult::InvalidOperandOOG
625 ) {
626 assert_eq!(
627 actual_return.is_error(),
628 expected_return.is_error(),
629 "return value mismatch: {actual_return:?} != {expected_return:?}"
630 );
631 } else {
632 assert_eq!(actual_return, expected_return, "return value mismatch");
633 }
634
635 let actual_stack =
636 unsafe { stack.as_slice(*stack_len).iter().map(|x| x.to_u256()).collect::<Vec<_>>() };
637
638 if !actual_return.is_error() {
641 if !skip_jit_stack {
642 assert_eq!(actual_stack, *expected_stack, "stack mismatch");
643 }
644
645 if !skip_jit_memory {
646 assert_eq!(
647 MemDisplay(&ecx.memory.context_memory()),
648 MemDisplay(expected_memory),
649 "memory mismatch"
650 );
651 }
652
653 if !skip_jit_gas {
654 assert_eq!(ecx.gas.total_gas_spent(), expected_gas, "gas mismatch");
655 }
656 }
657
658 let actual_next_action = match ecx.next_action.as_ref() {
659 Some(action) => action,
660 None => &default_action,
661 };
662 assert_actions(actual_next_action, expected_next_action);
663
664 if let Some(_assert_host) = assert_host {
665 let host = unsafe { &*(ecx.host as *mut dyn Host as *mut TestHost) };
666 _assert_host(host);
667 }
668
669 if let Some(assert_ecx) = assert_ecx {
670 assert_ecx(ecx);
671 }
672 });
673}
674
675#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
676struct MemDisplay<'a>(&'a [u8]);
677impl fmt::Debug for MemDisplay<'_> {
678 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679 let chunks = self.0.chunks(32).map(revm_primitives::hex::encode_prefixed);
680 f.debug_list().entries(chunks).finish()
681 }
682}
683
684#[track_caller]
685fn assert_actions(actual: &InterpreterAction, expected: &InterpreterAction) {
686 match (actual, expected) {
687 (InterpreterAction::Return(result), InterpreterAction::Return(expected_result)) => {
688 assert_eq!(result.result, expected_result.result, "result mismatch");
689 assert_eq!(result.output, expected_result.output, "result output mismatch");
690 if expected_result.gas.limit() != GAS_WHAT_INTERPRETER_SAYS {
691 assert_eq!(
692 result.gas.total_gas_spent(),
693 expected_result.gas.total_gas_spent(),
694 "result gas mismatch"
695 );
696 }
697 }
698 (
699 InterpreterAction::NewFrame(FrameInput::Call(actual_call)),
700 InterpreterAction::NewFrame(FrameInput::Call(expected_call)),
701 ) => {
702 assert_eq!(
705 actual_call.return_memory_offset, expected_call.return_memory_offset,
706 "return_memory_offset mismatch"
707 );
708 assert_eq!(actual_call.gas_limit, expected_call.gas_limit, "gas_limit mismatch");
709 assert_eq!(
710 actual_call.bytecode_address, expected_call.bytecode_address,
711 "bytecode_address mismatch"
712 );
713 assert_eq!(
714 actual_call.target_address, expected_call.target_address,
715 "target_address mismatch"
716 );
717 assert_eq!(actual_call.caller, expected_call.caller, "caller mismatch");
718 assert_eq!(actual_call.value, expected_call.value, "value mismatch");
719 assert_eq!(actual_call.scheme, expected_call.scheme, "scheme mismatch");
720 assert_eq!(actual_call.is_static, expected_call.is_static, "is_static mismatch");
721 }
725 (
726 InterpreterAction::NewFrame(FrameInput::Create(actual_create)),
727 InterpreterAction::NewFrame(FrameInput::Create(expected_create)),
728 ) => {
729 assert_eq!(actual_create.caller(), expected_create.caller(), "caller mismatch");
731 assert_eq!(actual_create.scheme(), expected_create.scheme(), "scheme mismatch");
732 assert_eq!(actual_create.value(), expected_create.value(), "value mismatch");
733 assert_eq!(
734 actual_create.init_code(),
735 expected_create.init_code(),
736 "init_code mismatch"
737 );
738 assert_eq!(
739 actual_create.gas_limit(),
740 expected_create.gas_limit(),
741 "gas_limit mismatch"
742 );
743 }
744 (a, b) => assert_eq!(a, b, "next action mismatch"),
745 }
746}
747
748pub fn insert_call_outcome_test(
753 interpreter: &mut revm_interpreter::Interpreter,
754 outcome: InterpreterResult,
755 return_memory_offset: Option<std::ops::Range<usize>>,
756) {
757 use revm_interpreter::interpreter_types::ReturnData;
758
759 let ins_result = outcome.result;
760 let out_gas = outcome.gas;
761 let returned_len = outcome.output.len();
762
763 interpreter.return_data.set_buffer(outcome.output);
764
765 let success_indicator = if ins_result.is_ok() { U256::from(1) } else { U256::ZERO };
766 let _ = interpreter.stack.push(success_indicator);
767
768 if ins_result.is_ok_or_revert() {
769 interpreter.gas.erase_cost(out_gas.remaining());
770
771 if let Some(mem_range) = return_memory_offset {
772 let target_len = std::cmp::min(mem_range.len(), returned_len);
773 if target_len > 0 {
774 interpreter
775 .memory
776 .set(mem_range.start, &interpreter.return_data.buffer()[..target_len]);
777 }
778 }
779 }
780
781 if ins_result.is_ok() {
782 interpreter.gas.record_refund(out_gas.refunded());
783 }
784}