From e9230605370892a1ad6a5b57284b148b210d376a Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 19:55:19 +0300 Subject: [PATCH 01/10] Refactor vm.mockCall to be based on mutable VecDeque --- crates/cheatcodes/src/evm/mock.rs | 4 ++-- crates/cheatcodes/src/inspector.rs | 38 +++++++++++++++++++----------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index ab858c612da6..f356dee95ffb 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -1,7 +1,7 @@ use crate::{inspector::InnerEcx, Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*}; use alloy_primitives::{Address, Bytes, U256}; use revm::{interpreter::InstructionResult, primitives::Bytecode}; -use std::cmp::Ordering; +use std::{cmp::Ordering, collections::VecDeque}; /// Mocked call data. #[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] @@ -105,7 +105,7 @@ fn mock_call( ) { state.mocked_calls.entry(*callee).or_default().insert( MockCallDataContext { calldata: Bytes::copy_from_slice(cdata), value: value.copied() }, - MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) }, + VecDeque::from(vec![MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) }]), ); } diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index fe8834d5f5a8..d74ece7049f4 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -402,7 +402,7 @@ pub struct Cheatcodes { /// Mocked calls // **Note**: inner must a BTreeMap because of special `Ord` impl for `MockCallDataContext` - pub mocked_calls: HashMap>, + pub mocked_calls: HashMap>>, /// Mocked functions. Maps target address to be mocked to pair of (calldata, mock address). pub mocked_functions: HashMap>, @@ -889,26 +889,36 @@ where { } // Handle mocked calls - if let Some(mocks) = self.mocked_calls.get(&call.bytecode_address) { + if let Some(mocks) = self.mocked_calls.get_mut(&call.bytecode_address) { let ctx = MockCallDataContext { calldata: call.input.clone(), value: call.transfer_value() }; - if let Some(return_data) = mocks.get(&ctx).or_else(|| { - mocks - .iter() + + if let Some(return_data_queue) = match mocks.get_mut(&ctx) { + Some(queue) => Some(queue), + None => mocks + .iter_mut() .find(|(mock, _)| { call.input.get(..mock.calldata.len()) == Some(&mock.calldata[..]) && mock.value.map_or(true, |value| Some(value) == call.transfer_value()) }) .map(|(_, v)| v) - }) { - return Some(CallOutcome { - result: InterpreterResult { - result: return_data.ret_type, - output: return_data.data.clone(), - gas, - }, - memory_offset: call.return_memory_offset.clone(), - }); + } { + if let Some(return_data) = if return_data_queue.len() == 1 { + // If the mocked calls stack has a single element in it, don't empty it + return_data_queue.front().map(|x| x.to_owned()) + } else { + // Else, we pop the front element + return_data_queue.pop_front() + } { + return Some(CallOutcome { + result: InterpreterResult { + result: return_data.ret_type, + output: return_data.data.clone(), + gas, + }, + memory_offset: call.return_memory_offset.clone(), + }); + } } } From 1a9d2214e73810d4596c2ca6fde537a486d8f153 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 20:15:16 +0300 Subject: [PATCH 02/10] Add vm.mockCalls cheatcode --- crates/cheatcodes/assets/cheatcodes.json | 40 ++++++++++++++++++++++++ crates/cheatcodes/spec/src/vm.rs | 8 +++++ crates/cheatcodes/src/evm/mock.rs | 36 +++++++++++++++++++++ testdata/cheats/Vm.sol | 2 ++ 4 files changed, 86 insertions(+) diff --git a/crates/cheatcodes/assets/cheatcodes.json b/crates/cheatcodes/assets/cheatcodes.json index 9f08702266e9..3988fd475c51 100644 --- a/crates/cheatcodes/assets/cheatcodes.json +++ b/crates/cheatcodes/assets/cheatcodes.json @@ -5777,6 +5777,46 @@ "status": "stable", "safety": "unsafe" }, + { + "func": { + "id": "mockCalls_0", + "description": "Mocks multiple calls to an address, returning specified data for each call.", + "declaration": "function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external;", + "visibility": "external", + "mutability": "", + "signature": "mockCalls(address,bytes,bytes[])", + "selector": "0x5c5c3de9", + "selectorBytes": [ + 92, + 92, + 61, + 233 + ] + }, + "group": "evm", + "status": "stable", + "safety": "unsafe" + }, + { + "func": { + "id": "mockCalls_1", + "description": "Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call.", + "declaration": "function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external;", + "visibility": "external", + "mutability": "", + "signature": "mockCalls(address,uint256,bytes,bytes[])", + "selector": "0x08bcbae1", + "selectorBytes": [ + 8, + 188, + 186, + 225 + ] + }, + "group": "evm", + "status": "stable", + "safety": "unsafe" + }, { "func": { "id": "mockFunction", diff --git a/crates/cheatcodes/spec/src/vm.rs b/crates/cheatcodes/spec/src/vm.rs index 4ec51130a22a..87b2a04d2987 100644 --- a/crates/cheatcodes/spec/src/vm.rs +++ b/crates/cheatcodes/spec/src/vm.rs @@ -465,6 +465,14 @@ interface Vm { #[cheatcode(group = Evm, safety = Unsafe)] function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + /// Mocks multiple calls to an address, returning specified data for each call. + #[cheatcode(group = Evm, safety = Unsafe)] + function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; + + /// Mocks multiple calls to an address with a specific `msg.value`, returning specified data for each call. + #[cheatcode(group = Evm, safety = Unsafe)] + function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; + /// Reverts a call to an address with specified revert data. #[cheatcode(group = Evm, safety = Unsafe)] function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external; diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index f356dee95ffb..633a0b631bbb 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -65,6 +65,25 @@ impl Cheatcode for mockCall_1Call { } } +impl Cheatcode for mockCalls_0Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { callee, data, returnData } = self; + let _ = make_acc_non_empty(callee, ccx.ecx)?; + + mock_calls(ccx.state, callee, data, None, returnData, InstructionResult::Return); + Ok(Default::default()) + } +} + +impl Cheatcode for mockCalls_1Call { + fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { + let Self { callee, msgValue, data, returnData } = self; + ccx.ecx.load_account(*callee)?; + mock_calls(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return); + Ok(Default::default()) + } +} + impl Cheatcode for mockCallRevert_0Call { fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result { let Self { callee, data, revertData } = self; @@ -109,6 +128,23 @@ fn mock_call( ); } +#[allow(clippy::ptr_arg)] // Not public API, doesn't matter +fn mock_calls( + state: &mut Cheatcodes, + callee: &Address, + cdata: &Bytes, + value: Option<&U256>, + rdata_vec: &[Bytes], + ret_type: InstructionResult, +) { + state.mocked_calls.entry(*callee).or_default().insert( + MockCallDataContext { calldata: Bytes::copy_from_slice(cdata), value: value.copied() }, + rdata_vec.iter().map(|rdata| + MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) } + ).collect::>(), + ); +} + // Etches a single byte onto the account if it is empty to circumvent the `extcodesize` // check Solidity might perform. fn make_acc_non_empty(callee: &Address, ecx: InnerEcx) -> Result { diff --git a/testdata/cheats/Vm.sol b/testdata/cheats/Vm.sol index 7dc38480a0d3..b95153106528 100644 --- a/testdata/cheats/Vm.sol +++ b/testdata/cheats/Vm.sol @@ -284,6 +284,8 @@ interface Vm { function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData) external; function mockCall(address callee, bytes calldata data, bytes calldata returnData) external; function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external; + function mockCalls(address callee, bytes calldata data, bytes[] calldata returnData) external; + function mockCalls(address callee, uint256 msgValue, bytes calldata data, bytes[] calldata returnData) external; function mockFunction(address callee, address target, bytes calldata data) external; function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue); function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue); From c7f0f63189254eb9354b3320b6d5ee59b13a1d3f Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 20:27:35 +0300 Subject: [PATCH 03/10] Refactor mock_call to be wrapper for mock_calls --- crates/cheatcodes/src/evm/mock.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index 633a0b631bbb..4bc2ccde23ba 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -122,10 +122,7 @@ fn mock_call( rdata: &Bytes, ret_type: InstructionResult, ) { - state.mocked_calls.entry(*callee).or_default().insert( - MockCallDataContext { calldata: Bytes::copy_from_slice(cdata), value: value.copied() }, - VecDeque::from(vec![MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) }]), - ); + mock_calls(state, callee, cdata, value, &[rdata.clone()], ret_type) } #[allow(clippy::ptr_arg)] // Not public API, doesn't matter From 7452271871b9ae4a31d4789270299976771f3c86 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 20:33:46 +0300 Subject: [PATCH 04/10] Add a test to vm.mockCalls --- testdata/default/cheats/MockCalls.t.sol | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 testdata/default/cheats/MockCalls.t.sol diff --git a/testdata/default/cheats/MockCalls.t.sol b/testdata/default/cheats/MockCalls.t.sol new file mode 100644 index 000000000000..e977f2443b97 --- /dev/null +++ b/testdata/default/cheats/MockCalls.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT OR Apache-2.0 +pragma solidity 0.8.18; + +import "ds-test/test.sol"; +import "cheats/Vm.sol"; + +contract MockCallsTest is DSTest { + Vm constant vm = Vm(HEVM_ADDRESS); + + function testMockCalls() public { + address mockUser = vm.addr(vm.randomUint()); + address mockErc20 = vm.addr(vm.randomUint()); + bytes memory data = abi.encodeWithSignature('balanceOf(address)', mockUser); + bytes[] memory mocks = new bytes[](3); + mocks[0] = abi.encode(2 ether); + mocks[1] = abi.encode(1 ether); + mocks[2] = abi.encode(6.423 ether); + vm.mockCalls(mockErc20, data, mocks); + (, bytes memory ret1) = mockErc20.call(data); + assertEq(abi.decode(ret1, (uint)), 2 ether); + (, bytes memory ret2) = mockErc20.call(data); + assertEq(abi.decode(ret2, (uint)), 1 ether); + (, bytes memory ret3) = mockErc20.call(data); + assertEq(abi.decode(ret3, (uint)), 6.423 ether); + } +} From e93afd138f7abd0bac5be29ef068288df53bae5a Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 20:42:18 +0300 Subject: [PATCH 05/10] Add test for vm.mockCalls with msg.value --- testdata/default/cheats/MockCalls.t.sol | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/testdata/default/cheats/MockCalls.t.sol b/testdata/default/cheats/MockCalls.t.sol index e977f2443b97..0086210ddc82 100644 --- a/testdata/default/cheats/MockCalls.t.sol +++ b/testdata/default/cheats/MockCalls.t.sol @@ -7,6 +7,23 @@ import "cheats/Vm.sol"; contract MockCallsTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); + function testMockCallsWithValue() public { + address mockUser = vm.addr(vm.randomUint()); + address mockErc20 = vm.addr(vm.randomUint()); + bytes memory data = abi.encodeWithSignature('balanceOf(address)', mockUser); + bytes[] memory mocks = new bytes[](3); + mocks[0] = abi.encode(2 ether); + mocks[1] = abi.encode(1 ether); + mocks[2] = abi.encode(6.423 ether); + vm.mockCalls(mockErc20, 1 ether, data, mocks); + (, bytes memory ret1) = mockErc20.call{ value: 1 ether }(data); + assertEq(abi.decode(ret1, (uint)), 2 ether); + (, bytes memory ret2) = mockErc20.call{ value: 1 ether }(data); + assertEq(abi.decode(ret2, (uint)), 1 ether); + (, bytes memory ret3) = mockErc20.call{ value: 1 ether }(data); + assertEq(abi.decode(ret3, (uint)), 6.423 ether); + } + function testMockCalls() public { address mockUser = vm.addr(vm.randomUint()); address mockErc20 = vm.addr(vm.randomUint()); From 2450f358246135c1ff27e84cc18fff1449981de3 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 20:58:11 +0300 Subject: [PATCH 06/10] Fix fmt & clippy following vm.mockCalls implementation --- crates/cheatcodes/src/evm/mock.rs | 7 ++++--- crates/cheatcodes/src/inspector.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index 4bc2ccde23ba..73d9b17448e5 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -136,9 +136,10 @@ fn mock_calls( ) { state.mocked_calls.entry(*callee).or_default().insert( MockCallDataContext { calldata: Bytes::copy_from_slice(cdata), value: value.copied() }, - rdata_vec.iter().map(|rdata| - MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) } - ).collect::>(), + rdata_vec + .iter() + .map(|rdata| MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) }) + .collect::>(), ); } diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index d74ece7049f4..bdcb1ad8d0e6 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -901,7 +901,7 @@ where { call.input.get(..mock.calldata.len()) == Some(&mock.calldata[..]) && mock.value.map_or(true, |value| Some(value) == call.transfer_value()) }) - .map(|(_, v)| v) + .map(|(_, v)| v), } { if let Some(return_data) = if return_data_queue.len() == 1 { // If the mocked calls stack has a single element in it, don't empty it @@ -913,7 +913,7 @@ where { return Some(CallOutcome { result: InterpreterResult { result: return_data.ret_type, - output: return_data.data.clone(), + output: return_data.data, gas, }, memory_offset: call.return_memory_offset.clone(), From 94f70a17584b9fa984d2fb3d5889e9e43e7dba91 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Thu, 3 Oct 2024 21:17:01 +0300 Subject: [PATCH 07/10] Fix Solidity fmt in testdata/default/cheats/MockCalls.t.sol --- testdata/default/cheats/MockCalls.t.sol | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/testdata/default/cheats/MockCalls.t.sol b/testdata/default/cheats/MockCalls.t.sol index 0086210ddc82..3bd835f3d915 100644 --- a/testdata/default/cheats/MockCalls.t.sol +++ b/testdata/default/cheats/MockCalls.t.sol @@ -10,34 +10,34 @@ contract MockCallsTest is DSTest { function testMockCallsWithValue() public { address mockUser = vm.addr(vm.randomUint()); address mockErc20 = vm.addr(vm.randomUint()); - bytes memory data = abi.encodeWithSignature('balanceOf(address)', mockUser); + bytes memory data = abi.encodeWithSignature("balanceOf(address)", mockUser); bytes[] memory mocks = new bytes[](3); mocks[0] = abi.encode(2 ether); mocks[1] = abi.encode(1 ether); mocks[2] = abi.encode(6.423 ether); vm.mockCalls(mockErc20, 1 ether, data, mocks); - (, bytes memory ret1) = mockErc20.call{ value: 1 ether }(data); - assertEq(abi.decode(ret1, (uint)), 2 ether); - (, bytes memory ret2) = mockErc20.call{ value: 1 ether }(data); - assertEq(abi.decode(ret2, (uint)), 1 ether); - (, bytes memory ret3) = mockErc20.call{ value: 1 ether }(data); - assertEq(abi.decode(ret3, (uint)), 6.423 ether); + (, bytes memory ret1) = mockErc20.call{value: 1 ether}(data); + assertEq(abi.decode(ret1, (uint256)), 2 ether); + (, bytes memory ret2) = mockErc20.call{value: 1 ether}(data); + assertEq(abi.decode(ret2, (uint256)), 1 ether); + (, bytes memory ret3) = mockErc20.call{value: 1 ether}(data); + assertEq(abi.decode(ret3, (uint256)), 6.423 ether); } function testMockCalls() public { address mockUser = vm.addr(vm.randomUint()); address mockErc20 = vm.addr(vm.randomUint()); - bytes memory data = abi.encodeWithSignature('balanceOf(address)', mockUser); + bytes memory data = abi.encodeWithSignature("balanceOf(address)", mockUser); bytes[] memory mocks = new bytes[](3); mocks[0] = abi.encode(2 ether); mocks[1] = abi.encode(1 ether); mocks[2] = abi.encode(6.423 ether); vm.mockCalls(mockErc20, data, mocks); (, bytes memory ret1) = mockErc20.call(data); - assertEq(abi.decode(ret1, (uint)), 2 ether); + assertEq(abi.decode(ret1, (uint256)), 2 ether); (, bytes memory ret2) = mockErc20.call(data); - assertEq(abi.decode(ret2, (uint)), 1 ether); + assertEq(abi.decode(ret2, (uint256)), 1 ether); (, bytes memory ret3) = mockErc20.call(data); - assertEq(abi.decode(ret3, (uint)), 6.423 ether); + assertEq(abi.decode(ret3, (uint256)), 6.423 ether); } } From 97328625683d35e0cb98b5b2c0ac5263ad624d27 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Fri, 4 Oct 2024 00:55:45 +0300 Subject: [PATCH 08/10] Add test in MockCalls.t.sol to check last mocked data persists --- testdata/default/cheats/MockCalls.t.sol | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/testdata/default/cheats/MockCalls.t.sol b/testdata/default/cheats/MockCalls.t.sol index 3bd835f3d915..13e3cb78c992 100644 --- a/testdata/default/cheats/MockCalls.t.sol +++ b/testdata/default/cheats/MockCalls.t.sol @@ -7,6 +7,22 @@ import "cheats/Vm.sol"; contract MockCallsTest is DSTest { Vm constant vm = Vm(HEVM_ADDRESS); + function testMockCallsLastShouldPersist() public { + address mockUser = vm.addr(vm.randomUint()); + address mockErc20 = vm.addr(vm.randomUint()); + bytes memory data = abi.encodeWithSignature("balanceOf(address)", mockUser); + bytes[] memory mocks = new bytes[](2); + mocks[0] = abi.encode(2 ether); + mocks[1] = abi.encode(7.219 ether); + vm.mockCalls(mockErc20, data, mocks); + (, bytes memory ret1) = mockErc20.call(data); + assertEq(abi.decode(ret1, (uint256)), 2 ether); + (, bytes memory ret2) = mockErc20.call(data); + assertEq(abi.decode(ret2, (uint256)), 7.219 ether); + (, bytes memory ret3) = mockErc20.call(data); + assertEq(abi.decode(ret3, (uint256)), 7.219 ether); + } + function testMockCallsWithValue() public { address mockUser = vm.addr(vm.randomUint()); address mockErc20 = vm.addr(vm.randomUint()); From 999b385a15a319484b6024d1f1e69f618d3dc6e4 Mon Sep 17 00:00:00 2001 From: Yotam Bar-On Date: Fri, 4 Oct 2024 13:08:32 +0300 Subject: [PATCH 09/10] Remove allow(clippy::ptr_arg) from mock_call & mock_calls --- crates/cheatcodes/src/evm/mock.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index 73d9b17448e5..13c1bf0bfa48 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -113,7 +113,6 @@ impl Cheatcode for mockFunctionCall { } } -#[allow(clippy::ptr_arg)] // Not public API, doesn't matter fn mock_call( state: &mut Cheatcodes, callee: &Address, @@ -125,7 +124,6 @@ fn mock_call( mock_calls(state, callee, cdata, value, &[rdata.clone()], ret_type) } -#[allow(clippy::ptr_arg)] // Not public API, doesn't matter fn mock_calls( state: &mut Cheatcodes, callee: &Address, From 0b947d90c29503485010b3d797584457d743b7c6 Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:58:58 +0200 Subject: [PATCH 10/10] Apply suggestions from code review --- crates/cheatcodes/src/evm/mock.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/cheatcodes/src/evm/mock.rs b/crates/cheatcodes/src/evm/mock.rs index 13c1bf0bfa48..50551d179c84 100644 --- a/crates/cheatcodes/src/evm/mock.rs +++ b/crates/cheatcodes/src/evm/mock.rs @@ -121,7 +121,7 @@ fn mock_call( rdata: &Bytes, ret_type: InstructionResult, ) { - mock_calls(state, callee, cdata, value, &[rdata.clone()], ret_type) + mock_calls(state, callee, cdata, value, std::slice::from_ref(rdata), ret_type) } fn mock_calls( @@ -136,7 +136,7 @@ fn mock_calls( MockCallDataContext { calldata: Bytes::copy_from_slice(cdata), value: value.copied() }, rdata_vec .iter() - .map(|rdata| MockCallReturnData { ret_type, data: Bytes::copy_from_slice(rdata) }) + .map(|rdata| MockCallReturnData { ret_type, data: rdata.clone() }) .collect::>(), ); }