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::{gas_table_spec, instruction_table},
12 interpreter::ExtBytecode,
13};
14use revm_primitives::{B256, HashMap, Log, hardfork::SpecId};
15use similar_asserts::assert_eq;
16use std::{fmt, path::Path, sync::OnceLock};
17
18pub fn init_tracing() {
20 let _ = tracing_subscriber::fmt::try_init();
21}
22
23#[derive(Clone, Debug)]
25pub struct DefEnv {
26 pub tx: DefTx,
27 pub block: DefBlock,
28 pub cfg: DefCfg,
29}
30
31#[derive(Clone, Debug)]
32pub struct DefTx {
33 pub caller: Address,
34 pub blob_hashes: Vec<B256>,
35}
36
37#[derive(Clone, Debug)]
38pub struct DefBlock {
39 pub coinbase: Address,
40 pub timestamp: U256,
41 pub number: U256,
42 pub difficulty: U256,
43 pub prevrandao: Option<B256>,
44 pub gas_limit: U256,
45 pub basefee: U256,
46}
47
48impl DefBlock {
49 pub fn get_blob_gasprice(&self) -> Option<u64> {
50 Some(0) }
52}
53
54#[derive(Clone, Debug)]
55pub struct DefCfg {
56 pub chain_id: u64,
57}
58
59impl DefEnv {
60 pub fn effective_gas_price(&self) -> U256 {
61 U256::from(0x4567)
62 }
63}
64
65pub fn def_env() -> DefEnv {
67 DefEnv {
68 tx: DefTx {
69 caller: Address::repeat_byte(0xcc),
70 blob_hashes: vec![B256::repeat_byte(0x01), B256::repeat_byte(0x02)],
71 },
72 block: DefBlock {
73 coinbase: Address::repeat_byte(0xcb),
74 timestamp: U256::from(0x1234),
75 number: DEF_BN,
76 difficulty: U256::from(0xcdef),
77 prevrandao: Some(B256::from(U256::from(0x0123))),
78 gas_limit: U256::from(0x5678),
79 basefee: U256::from(0x1231),
80 },
81 cfg: DefCfg { chain_id: 69 },
82 }
83}
84
85pub fn memory_gas_cost(num_words: usize) -> u64 {
87 (num_words as u64) * 3 + (num_words as u64) * (num_words as u64) / 512
88}
89
90pub struct TestCase<'a> {
91 pub bytecode: &'a [u8],
92 pub spec_id: SpecId,
93 pub is_static: bool,
94 pub gas_limit: u64,
95
96 pub inspect_stack: Option<bool>,
98 pub modify_ecx: Option<fn(&mut EvmContext<'_>)>,
99
100 pub expected_return: InstructionResult,
101 pub expected_stack: &'a [U256],
102 pub expected_memory: &'a [u8],
103 pub expected_gas: u64,
104 pub expected_next_action: InterpreterAction,
105 pub assert_host: Option<fn(&TestHost)>,
106 pub assert_ecx: Option<fn(&EvmContext<'_>)>,
107}
108
109#[cfg(feature = "__fuzzing")]
110impl<'a> arbitrary::Arbitrary<'a> for TestCase<'a> {
111 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
112 let spec_id_range = 0..=(SpecId::OSAKA as u8 - 1);
113 let spec_id = SpecId::try_from_u8(u.int_in_range(spec_id_range)?).unwrap_or(DEF_SPEC);
114
115 let bytecode: &'a [u8] = u.arbitrary()?;
116
117 Ok(Self::what_interpreter_says(bytecode, spec_id))
118 }
119}
120
121impl Default for TestCase<'_> {
122 fn default() -> Self {
123 Self {
124 bytecode: &[],
125 spec_id: DEF_SPEC,
126 is_static: false,
127 gas_limit: DEF_GAS_LIMIT,
128 inspect_stack: None,
129 modify_ecx: None,
130 expected_return: InstructionResult::Stop,
131 expected_stack: &[],
132 expected_memory: &[],
133 expected_gas: 0,
134 expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
135 assert_host: None,
136 assert_ecx: None,
137 }
138 }
139}
140
141impl fmt::Debug for TestCase<'_> {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.debug_struct("TestCase")
144 .field("bytecode", &format_bytecode(self.bytecode, self.spec_id))
145 .field("spec_id", &self.spec_id)
146 .field("inspect_stack", &self.inspect_stack)
147 .field("modify_ecx", &self.modify_ecx.is_some())
148 .field("expected_return", &self.expected_return)
149 .field("expected_stack", &self.expected_stack)
150 .field("expected_memory", &MemDisplay(self.expected_memory))
151 .field("expected_gas", &self.expected_gas)
152 .field("expected_next_action", &self.expected_next_action)
153 .field("assert_host", &self.assert_host.is_some())
154 .field("assert_ecx", &self.assert_ecx.is_some())
155 .finish()
156 }
157}
158
159impl<'a> TestCase<'a> {
160 pub fn what_interpreter_says(bytecode: &'a [u8], spec_id: SpecId) -> Self {
161 Self {
162 bytecode,
163 spec_id,
164 is_static: false,
165 gas_limit: DEF_GAS_LIMIT,
166 inspect_stack: None,
167 modify_ecx: None,
168 expected_return: RETURN_WHAT_INTERPRETER_SAYS,
169 expected_stack: STACK_WHAT_INTERPRETER_SAYS,
170 expected_memory: MEMORY_WHAT_INTERPRETER_SAYS,
171 expected_gas: GAS_WHAT_INTERPRETER_SAYS,
172 expected_next_action: ACTION_WHAT_INTERPRETER_SAYS,
173 assert_host: None,
174 assert_ecx: None,
175 }
176 }
177}
178
179pub const DEF_SPEC: SpecId = SpecId::CANCUN;
181pub static DEF_OPINFOS: std::sync::LazyLock<&'static [OpcodeInfo; 256]> =
182 std::sync::LazyLock::new(|| op_info_map(DEF_SPEC));
183
184pub const DEF_GAS_LIMIT: u64 = 100_000;
185pub const DEF_GAS_LIMIT_U256: U256 = U256::from_le_slice(&DEF_GAS_LIMIT.to_le_bytes());
186
187pub const DEF_ADDR: Address = Address::repeat_byte(0xba);
189pub const DEF_CALLER: Address = Address::repeat_byte(0xca);
190pub static DEF_CD: &[u8] = &[0xaa; 64];
191pub static DEF_RD: &[u8] = &[0xbb; 64];
192pub static DEF_DATA: &[u8] = &[0xcc; 64];
193pub const DEF_VALUE: U256 = uint!(123_456_789_U256);
194pub static DEF_STORAGE: OnceLock<HashMap<U256, U256>> = OnceLock::new();
195pub static DEF_CODEMAP: OnceLock<HashMap<Address, revm_bytecode::Bytecode>> = OnceLock::new();
196pub const OTHER_ADDR: Address = Address::repeat_byte(0x69);
197pub const DEF_BN: U256 = uint!(500_U256);
198
199pub const RETURN_WHAT_INTERPRETER_SAYS: InstructionResult = InstructionResult::PrecompileError;
200pub const STACK_WHAT_INTERPRETER_SAYS: &[U256] =
201 &[U256::from_be_slice(&GAS_WHAT_INTERPRETER_SAYS.to_be_bytes())];
202pub const MEMORY_WHAT_INTERPRETER_SAYS: &[u8] = &GAS_WHAT_INTERPRETER_SAYS.to_be_bytes();
203pub const GAS_WHAT_INTERPRETER_SAYS: u64 = 0x4682e332d6612de1;
204pub const ACTION_WHAT_INTERPRETER_SAYS: InterpreterAction =
205 InterpreterAction::Return(InterpreterResult {
206 gas: Gas::new(GAS_WHAT_INTERPRETER_SAYS),
207 output: Bytes::from_static(MEMORY_WHAT_INTERPRETER_SAYS),
208 result: RETURN_WHAT_INTERPRETER_SAYS,
209 });
210
211pub fn def_storage() -> &'static HashMap<U256, U256> {
212 DEF_STORAGE.get_or_init(|| {
213 let mut map = HashMap::default();
214 map.insert(U256::from(0), U256::from(1));
215 map.insert(U256::from(1), U256::from(2));
216 map.insert(U256::from(69), U256::from(42));
217 map
218 })
219}
220
221pub fn def_codemap() -> &'static HashMap<Address, revm_bytecode::Bytecode> {
222 DEF_CODEMAP.get_or_init(|| {
223 let mut map = HashMap::default();
224 map.insert(
225 OTHER_ADDR,
226 revm_bytecode::Bytecode::new_raw(Bytes::from_static(&[
227 op::PUSH1,
228 0x69,
229 op::PUSH1,
230 0x42,
231 op::ADD,
232 op::STOP,
233 ])),
234 );
235 map
236 })
237}
238
239pub struct TestHost {
241 pub storage: HashMap<U256, U256>,
242 pub transient_storage: HashMap<U256, U256>,
243 pub code_map: &'static HashMap<Address, revm_bytecode::Bytecode>,
244 pub selfdestructs: Vec<(Address, Address)>,
245 pub logs: Vec<Log>,
246 pub gas_params: GasParams,
247}
248
249impl Default for TestHost {
250 fn default() -> Self {
251 Self::new()
252 }
253}
254
255impl TestHost {
256 pub fn new() -> Self {
257 Self::with_spec(DEF_SPEC)
258 }
259
260 pub fn with_spec(spec_id: SpecId) -> Self {
261 Self {
262 storage: def_storage().clone(),
263 transient_storage: HashMap::default(),
264 code_map: def_codemap(),
265 selfdestructs: Vec::new(),
266 logs: Vec::new(),
267 gas_params: GasParams::new_spec(spec_id),
268 }
269 }
270}
271
272impl Host for TestHost {
273 fn basefee(&self) -> U256 {
274 U256::from(0x1231)
275 }
276
277 fn blob_gasprice(&self) -> U256 {
278 U256::ZERO
279 }
280
281 fn gas_limit(&self) -> U256 {
282 U256::from(0x5678)
283 }
284
285 fn gas_params(&self) -> &GasParams {
286 &self.gas_params
287 }
288
289 fn is_amsterdam_eip8037_enabled(&self) -> bool {
290 false
291 }
292
293 fn difficulty(&self) -> U256 {
294 U256::from(0xcdef)
295 }
296
297 fn prevrandao(&self) -> Option<U256> {
298 Some(U256::from(0x0123))
299 }
300
301 fn block_number(&self) -> U256 {
302 DEF_BN
303 }
304
305 fn timestamp(&self) -> U256 {
306 U256::from(0x1234)
307 }
308
309 fn beneficiary(&self) -> Address {
310 Address::repeat_byte(0xcb)
311 }
312
313 fn slot_num(&self) -> U256 {
314 U256::ZERO
315 }
316
317 fn chain_id(&self) -> U256 {
318 U256::from(69)
319 }
320
321 fn effective_gas_price(&self) -> U256 {
322 U256::from(0x4567)
323 }
324
325 fn caller(&self) -> Address {
326 Address::repeat_byte(0xcc)
327 }
328
329 fn blob_hash(&self, number: usize) -> Option<U256> {
330 let env = def_env();
331 env.tx.blob_hashes.get(number).map(|h| (*h).into())
332 }
333
334 fn max_initcode_size(&self) -> usize {
335 49152
337 }
338
339 fn block_hash(&mut self, number: u64) -> Option<B256> {
340 Some(U256::from(number).into())
341 }
342
343 fn selfdestruct(
344 &mut self,
345 address: Address,
346 target: Address,
347 _skip_cold_load: bool,
348 ) -> Result<StateLoad<SelfDestructResult>, LoadError> {
349 self.selfdestructs.push((address, target));
350
351 Ok(StateLoad::new(
352 SelfDestructResult {
353 had_value: false,
354 target_exists: true,
355 previously_destroyed: false,
356 },
357 false,
358 ))
359 }
360
361 fn log(&mut self, log: Log) {
362 self.logs.push(log);
363 }
364
365 fn tstore(&mut self, _address: Address, key: U256, value: U256) {
366 self.transient_storage.insert(key, value);
367 }
368
369 fn tload(&mut self, _address: Address, key: U256) -> U256 {
370 self.transient_storage.get(&key).copied().unwrap_or(U256::ZERO)
371 }
372
373 fn load_account_info_skip_cold_load(
374 &mut self,
375 address: Address,
376 load_code: bool,
377 _skip_cold_load: bool,
378 ) -> Result<AccountInfoLoad<'_>, LoadError> {
379 use revm_state::AccountInfo;
380 use std::borrow::Cow;
381
382 let code = if load_code {
383 Some(self.code_map.get(&address).cloned().unwrap_or_default())
385 } else {
386 None
387 };
388
389 let balance = U256::from(address.0[19]);
392
393 let code_hash = if let Some(bytecode) = self.code_map.get(&address) {
395 keccak256(bytecode.original_byte_slice())
396 } else {
397 KECCAK_EMPTY
398 };
399
400 let info = AccountInfo { balance, nonce: 0, code_hash, account_id: None, code };
402
403 let is_empty = info.code.is_none() && info.balance.is_zero() && info.nonce == 0;
404
405 Ok(AccountInfoLoad { account: Cow::Owned(info), is_cold: false, is_empty })
406 }
407
408 fn sstore_skip_cold_load(
409 &mut self,
410 _address: Address,
411 key: U256,
412 value: U256,
413 _skip_cold_load: bool,
414 ) -> Result<StateLoad<SStoreResult>, LoadError> {
415 let original = self.storage.get(&key).copied().unwrap_or(U256::ZERO);
416 self.storage.insert(key, value);
417 Ok(StateLoad::new(
418 SStoreResult { original_value: original, present_value: original, new_value: value },
419 false,
420 ))
421 }
422
423 fn sload_skip_cold_load(
424 &mut self,
425 _address: Address,
426 key: U256,
427 _skip_cold_load: bool,
428 ) -> Result<StateLoad<U256>, LoadError> {
429 let value = self.storage.get(&key).copied().unwrap_or(U256::ZERO);
430 Ok(StateLoad::new(value, false))
431 }
432}
433
434pub fn with_evm_context<F: FnOnce(&mut EvmContext<'_>, &mut EvmStack, &mut usize) -> R, R>(
435 bytecode: &[u8],
436 spec_id: SpecId,
437 f: F,
438) -> R {
439 let input = InputsImpl {
440 target_address: DEF_ADDR,
441 bytecode_address: None,
442 caller_address: DEF_CALLER,
443 input: CallInput::Bytes(Bytes::from_static(DEF_CD)),
444 call_value: DEF_VALUE,
445 };
446
447 let bytecode_obj = revm_bytecode::Bytecode::new_raw(Bytes::copy_from_slice(bytecode));
448 let ext_bytecode = ExtBytecode::new(bytecode_obj);
449
450 let mut interpreter =
451 Interpreter::new(SharedMemory::new(), ext_bytecode, input, false, spec_id, DEF_GAS_LIMIT);
452
453 let mut host = TestHost::with_spec(spec_id);
454
455 let (mut ecx, stack, stack_len) =
456 EvmContext::from_interpreter_with_stack(&mut interpreter, &mut host);
457 f(&mut ecx, stack, stack_len)
458}
459
460pub fn set_test_dump<B: Backend>(compiler: &mut EvmCompiler<B>, module_path: &str) {
461 let root = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
462 let mut dump_path = root.to_path_buf();
463 dump_path.push("target");
464 dump_path.push("tests_dump");
465 dump_path.extend(module_path.split("::").skip(2));
467 dump_path.push(format!("{:?}", compiler.opt_level()));
468 compiler.set_dump_to(Some(dump_path));
469}
470
471pub fn run_test_case<B: Backend>(test_case: &TestCase<'_>, compiler: &mut EvmCompiler<B>) {
472 let TestCase { bytecode, spec_id, .. } = *test_case;
473 compiler.inspect_stack(test_case.inspect_stack.unwrap_or(true));
474 let f = unsafe { compiler.jit("test", bytecode, spec_id) }.unwrap();
476 run_compiled_test_case(test_case, f);
477}
478
479fn run_compiled_test_case(test_case: &TestCase<'_>, f: EvmCompilerFn) {
480 let TestCase {
481 bytecode,
482 spec_id,
483 is_static,
484 gas_limit,
485 inspect_stack: _,
486 modify_ecx,
487 expected_return,
488 expected_stack,
489 expected_memory,
490 expected_gas,
491 ref expected_next_action,
492 assert_host,
493 assert_ecx,
494 } = *test_case;
495
496 with_evm_context(bytecode, spec_id, |ecx, stack, stack_len| {
497 if is_static {
498 ecx.is_static = true;
499 }
500 if gas_limit != DEF_GAS_LIMIT {
501 ecx.gas = Gas::new(gas_limit);
502 }
503 if let Some(modify_ecx) = modify_ecx {
504 modify_ecx(ecx);
505 ecx.refresh_memory_cache();
506 }
507
508 let input = InputsImpl {
510 target_address: DEF_ADDR,
511 bytecode_address: None,
512 caller_address: DEF_CALLER,
513 input: CallInput::Bytes(Bytes::from_static(DEF_CD)),
514 call_value: DEF_VALUE,
515 };
516 let bytecode_obj = revm_bytecode::Bytecode::new_raw(Bytes::copy_from_slice(bytecode));
517 let ext_bytecode = ExtBytecode::new(bytecode_obj);
518 let mut interpreter = Interpreter::new(
519 SharedMemory::new(),
520 ext_bytecode,
521 input,
522 is_static,
523 spec_id,
524 gas_limit,
525 );
526
527 let table = instruction_table::<revm_interpreter::interpreter::EthInterpreter, TestHost>();
528 let gas_table = gas_table_spec(spec_id);
529 let mut int_host = TestHost::with_spec(spec_id);
530 let interpreter_action = interpreter.run_plain(&table, &gas_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_halt();
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_halt(),
628 expected_return.is_halt(),
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_halt() {
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}