Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.

Commit 1cb76ea

Browse files
DreamWuGitlispc
andauthored
feat: implement mcopy opcode (#1209)
* draft buss mapping for mcopy * rename to mcopy.rs * add mcopy.rs * add helper gen_copy_steps_for_memory_to_memory * add MCOPY in opcode_ids * handle opcode_id others as_u8, constant_gas etc. * draft mcopy gadgets * add gadget to execution config * remove unused fields * update buss mapping test * update gadget tests * remove unnecessary testing stuff * update ExecutionState * add cancun config * update buss mapping test * remove commented codes * enable multi copy case * fix buss mapping tests * update gas cost * remove tx id lookup * fix memory_word_size * update word size if no copy happens * add copy circuit test * remove debug log * fmt align * minor update * add OOGMemoryCopy test for mcopy * make oog memorycopy include mcopy opcode * revert temp debug changes * add more test data * minor updates * fmt adjust * fix clippy * add testool * fix memory word * increase fix table rows detected by ci * update testool * remove unused import * clippy update * fix large dest memory addr * refactor to use memory_expansion for dest_addr * handle dest_addr < src_addr * update per cargo check * intermediate clean up * fix testool * fix u64 overflow * update oog memorycopy to cover src_offset overflow case * fix clippy; fix codehash.txt * remove debug codes * fix clippy * reverted commented for testing * remove outdated comment and todo for overlap case --------- Co-authored-by: Zhuo Zhang <mycinbrin@gmail.com>
1 parent 69b9a3e commit 1cb76ea

File tree

20 files changed

+756
-36
lines changed

20 files changed

+756
-36
lines changed

bus-mapping/src/circuit_input_builder/input_state_ref.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1950,6 +1950,7 @@ impl<'a> CircuitInputStateRef<'a> {
19501950
copy_length,
19511951
&bytecode.code,
19521952
&mut self.call_ctx_mut()?.memory,
1953+
false,
19531954
);
19541955

19551956
let copy_steps = CopyEventStepsBuilder::new()
@@ -2039,6 +2040,7 @@ impl<'a> CircuitInputStateRef<'a> {
20392040
copy_length,
20402041
result,
20412042
&mut self.caller_ctx_mut()?.memory,
2043+
false,
20422044
);
20432045

20442046
let read_slot_bytes = MemoryRef(result).read_chunk(src_range);
@@ -2096,6 +2098,7 @@ impl<'a> CircuitInputStateRef<'a> {
20962098
copy_length,
20972099
&call_ctx.call_data,
20982100
&mut call_ctx.memory,
2101+
false,
20992102
);
21002103

21012104
let copy_steps = CopyEventStepsBuilder::memory_range(range)
@@ -2144,6 +2147,7 @@ impl<'a> CircuitInputStateRef<'a> {
21442147
copy_length,
21452148
call_data,
21462149
&mut call_ctx.memory,
2150+
false,
21472151
);
21482152

21492153
let read_slot_bytes = self.caller_ctx()?.memory.read_chunk(src_range);
@@ -2205,6 +2209,7 @@ impl<'a> CircuitInputStateRef<'a> {
22052209
copy_length,
22062210
return_data,
22072211
&mut call_ctx.memory,
2212+
false,
22082213
);
22092214
let read_slot_bytes = self.call()?.last_callee_memory.read_chunk(src_range);
22102215

@@ -2247,6 +2252,71 @@ impl<'a> CircuitInputStateRef<'a> {
22472252
Ok((read_steps, write_steps, prev_bytes))
22482253
}
22492254

2255+
// generates copy steps for memory to memory case.
2256+
pub(crate) fn gen_copy_steps_for_memory_to_memory(
2257+
&mut self,
2258+
exec_step: &mut ExecStep,
2259+
src_addr: impl Into<MemoryAddress>,
2260+
dst_addr: impl Into<MemoryAddress>,
2261+
copy_length: impl Into<MemoryAddress>,
2262+
) -> Result<(CopyEventSteps, CopyEventSteps, Vec<u8>), Error> {
2263+
let copy_length = copy_length.into().0;
2264+
if copy_length == 0 {
2265+
return Ok((vec![], vec![], vec![]));
2266+
}
2267+
2268+
// current call's memory
2269+
let memory = self.call_ctx()?.memory.clone();
2270+
let call_ctx = self.call_ctx_mut()?;
2271+
let (src_range, dst_range, write_slot_bytes) = combine_copy_slot_bytes(
2272+
src_addr.into().0,
2273+
dst_addr.into().0,
2274+
copy_length,
2275+
&memory.0,
2276+
&mut call_ctx.memory,
2277+
true,
2278+
);
2279+
let read_slot_bytes = memory.read_chunk(src_range);
2280+
2281+
let read_steps = CopyEventStepsBuilder::memory_range(src_range)
2282+
.source(read_slot_bytes.as_slice())
2283+
.build();
2284+
let write_steps = CopyEventStepsBuilder::memory_range(dst_range)
2285+
.source(write_slot_bytes.as_slice())
2286+
.build();
2287+
2288+
let mut src_chunk_index = src_range.start_slot().0;
2289+
let mut dst_chunk_index = dst_range.start_slot().0;
2290+
let mut prev_bytes: Vec<u8> = vec![];
2291+
// memory word reads from source and writes to destination word
2292+
let call_id = self.call()?.call_id;
2293+
for (read_chunk, write_chunk) in read_slot_bytes.chunks(32).zip(write_slot_bytes.chunks(32))
2294+
{
2295+
self.push_op(
2296+
exec_step,
2297+
RW::READ,
2298+
MemoryOp::new(
2299+
call_id,
2300+
src_chunk_index.into(),
2301+
Word::from_big_endian(read_chunk),
2302+
),
2303+
)?;
2304+
trace!("read chunk: {call_id} {src_chunk_index} {read_chunk:?}");
2305+
src_chunk_index += 32;
2306+
2307+
self.write_chunk_for_copy_step(
2308+
exec_step,
2309+
write_chunk,
2310+
dst_chunk_index,
2311+
&mut prev_bytes,
2312+
)?;
2313+
2314+
dst_chunk_index += 32;
2315+
}
2316+
2317+
Ok((read_steps, write_steps, prev_bytes))
2318+
}
2319+
22502320
pub(crate) fn gen_copy_steps_for_log(
22512321
&mut self,
22522322
exec_step: &mut ExecStep,
@@ -2349,13 +2419,20 @@ fn combine_copy_slot_bytes(
23492419
copy_length: usize,
23502420
src_data: &[impl Into<u8> + Clone],
23512421
dst_memory: &mut Memory,
2422+
is_memory_copy: bool, // indicates memroy --> memory copy type.
23522423
) -> (MemoryWordRange, MemoryWordRange, Vec<u8>) {
23532424
let mut src_range = MemoryWordRange::align_range(src_addr, copy_length);
23542425
let mut dst_range = MemoryWordRange::align_range(dst_addr, copy_length);
23552426
src_range.ensure_equal_length(&mut dst_range);
23562427

23572428
// Extend call memory.
2358-
dst_memory.extend_for_range(dst_addr.into(), copy_length.into());
2429+
// if is_memory_copy=true, both dst_addr and src_addr are memory address
2430+
if is_memory_copy && dst_addr < src_addr {
2431+
dst_memory.extend_for_range(src_addr.into(), copy_length.into());
2432+
} else {
2433+
dst_memory.extend_for_range(dst_addr.into(), copy_length.into());
2434+
}
2435+
23592436
let dst_begin_slot = dst_range.start_slot().0;
23602437
let dst_end_slot = dst_range.end_slot().0;
23612438

bus-mapping/src/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ pub(crate) fn get_step_reported_error(op: &OpcodeId, error: GethExecError) -> Ex
192192
OpcodeId::CALLDATACOPY
193193
| OpcodeId::CODECOPY
194194
| OpcodeId::EXTCODECOPY
195+
| OpcodeId::MCOPY
195196
| OpcodeId::RETURNDATACOPY => OogError::MemoryCopy,
196197
OpcodeId::BALANCE | OpcodeId::EXTCODESIZE | OpcodeId::EXTCODEHASH => {
197198
OogError::AccountAccess

bus-mapping/src/evm/opcodes.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ mod extcodesize;
4242
mod gasprice;
4343
mod jumpi;
4444
mod logs;
45+
mod mcopy;
4546
mod mload;
4647
mod mstore;
4748
mod number;
@@ -116,6 +117,7 @@ use extcodehash::Extcodehash;
116117
use extcodesize::Extcodesize;
117118
use gasprice::GasPrice;
118119
use logs::Log;
120+
use mcopy::MCopy;
119121
use mload::Mload;
120122
use mstore::Mstore;
121123
use origin::Origin;
@@ -235,6 +237,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
235237
OpcodeId::SELFBALANCE => Selfbalance::gen_associated_ops,
236238
OpcodeId::BASEFEE => GetBlockHeaderField::<{ OpcodeId::BASEFEE }>::gen_associated_ops,
237239
OpcodeId::POP => StackPopOnlyOpcode::<1>::gen_associated_ops,
240+
OpcodeId::MCOPY => MCopy::gen_associated_ops,
238241
OpcodeId::MLOAD => Mload::gen_associated_ops,
239242
OpcodeId::MSTORE => Mstore::<false>::gen_associated_ops,
240243
OpcodeId::MSTORE8 => Mstore::<true>::gen_associated_ops,
@@ -477,6 +480,7 @@ pub fn gen_associated_ops(
477480
} else {
478481
None
479482
};
483+
480484
if let Some(exec_error) = state.get_step_err(geth_step, next_step).unwrap() {
481485
log::debug!(
482486
"geth error {:?} occurred in {:?} at pc {:?}",

bus-mapping/src/evm/opcodes/error_oog_memory_copy.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ impl Opcode for OOGMemoryCopy {
2323
OpcodeId::CALLDATACOPY,
2424
OpcodeId::CODECOPY,
2525
OpcodeId::EXTCODECOPY,
26-
OpcodeId::RETURNDATACOPY
26+
OpcodeId::RETURNDATACOPY,
27+
OpcodeId::MCOPY,
2728
]
2829
.contains(&geth_step.op));
2930

0 commit comments

Comments
 (0)