@@ -12,7 +12,7 @@ use crate::{
1212 CommonMemoryAddressGadget , MemoryCopierGasGadget , MemoryExpandedAddressGadget ,
1313 MemoryExpansionGadget ,
1414 } ,
15- or, select, CachedRegion , Cell , Word ,
15+ not , or, select, CachedRegion , Cell , Word ,
1616 } ,
1717 witness:: { Block , Call , ExecStep , Transaction } ,
1818 } ,
@@ -40,10 +40,14 @@ pub(crate) struct ErrorOOGMemoryCopyGadget<F> {
4040 src_memory_addr : MemoryExpandedAddressGadget < F > ,
4141 /// Destination offset and size to copy
4242 dst_memory_addr : MemoryExpandedAddressGadget < F > ,
43- memory_expansion : MemoryExpansionGadget < F , 1 , N_BYTES_MEMORY_WORD_SIZE > ,
43+ // mcopy expansion
44+ memory_expansion_mcopy : MemoryExpansionGadget < F , 2 , N_BYTES_MEMORY_WORD_SIZE > ,
45+ // other kind(CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY) expansion
46+ memory_expansion_normal : MemoryExpansionGadget < F , 1 , N_BYTES_MEMORY_WORD_SIZE > ,
4447 memory_copier_gas : MemoryCopierGasGadget < F , { GasCost :: COPY } > ,
4548 insufficient_gas : LtGadget < F , N_BYTES_GAS > ,
4649 is_extcodecopy : IsZeroGadget < F > ,
50+ is_mcopy : IsZeroGadget < F > ,
4751 common_error_gadget : CommonErrorGadget < F > ,
4852}
4953
@@ -72,6 +76,7 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
7276
7377 let is_extcodecopy =
7478 IsZeroGadget :: construct ( cb, opcode. expr ( ) - OpcodeId :: EXTCODECOPY . expr ( ) ) ;
79+ let is_mcopy = IsZeroGadget :: construct ( cb, opcode. expr ( ) - OpcodeId :: MCOPY . expr ( ) ) ;
7580
7681 cb. condition ( is_extcodecopy. expr ( ) , |cb| {
7782 cb. call_context_lookup ( false . expr ( ) , None , CallContextFieldTag :: TxId , tx_id. expr ( ) ) ;
@@ -95,12 +100,31 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
95100 cb. stack_pop ( src_memory_addr. offset_rlc ( ) ) ;
96101 cb. stack_pop ( dst_memory_addr. length_rlc ( ) ) ;
97102
98- let memory_expansion = MemoryExpansionGadget :: construct ( cb, [ dst_memory_addr. end_offset ( ) ] ) ;
99- let memory_copier_gas = MemoryCopierGasGadget :: construct (
100- cb,
101- dst_memory_addr. length ( ) ,
102- memory_expansion. gas_cost ( ) ,
103+ // for mcopy
104+ let memory_expansion_mcopy = cb. condition ( is_mcopy. expr ( ) , |cb| {
105+ cb. require_equal (
106+ "mcopy src_address length == dst_address length" ,
107+ src_memory_addr. length_rlc ( ) ,
108+ dst_memory_addr. length_rlc ( ) ,
109+ ) ;
110+ MemoryExpansionGadget :: construct (
111+ cb,
112+ [ src_memory_addr. end_offset ( ) , dst_memory_addr. end_offset ( ) ] ,
113+ )
114+ } ) ;
115+
116+ // for others (CALLDATACOPY, CODECOPY, EXTCODECOPY, RETURNDATACOPY)
117+ let memory_expansion_normal = cb. condition ( not:: expr ( is_mcopy. expr ( ) ) , |cb| {
118+ MemoryExpansionGadget :: construct ( cb, [ dst_memory_addr. end_offset ( ) ] )
119+ } ) ;
120+
121+ let memory_expansion_cost = select:: expr (
122+ is_mcopy. expr ( ) ,
123+ memory_expansion_mcopy. gas_cost ( ) ,
124+ memory_expansion_normal. gas_cost ( ) ,
103125 ) ;
126+ let memory_copier_gas =
127+ MemoryCopierGasGadget :: construct ( cb, dst_memory_addr. length ( ) , memory_expansion_cost) ;
104128
105129 let constant_gas_cost = select:: expr (
106130 is_extcodecopy. expr ( ) ,
@@ -111,7 +135,7 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
111135 GasCost :: WARM_ACCESS . expr ( ) ,
112136 GasCost :: COLD_ACCOUNT_ACCESS . expr ( ) ,
113137 ) ,
114- // Constant gas cost is same for CALLDATACOPY, CODECOPY and RETURNDATACOPY .
138+ // Constant gas cost is same for CALLDATACOPY, CODECOPY,RETURNDATACOPY and mcopy .
115139 OpcodeId :: CALLDATACOPY . constant_gas_cost ( ) . expr ( ) ,
116140 ) ;
117141
@@ -147,10 +171,12 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
147171 external_address,
148172 src_memory_addr,
149173 dst_memory_addr,
150- memory_expansion,
174+ memory_expansion_mcopy,
175+ memory_expansion_normal,
151176 memory_copier_gas,
152177 insufficient_gas,
153178 is_extcodecopy,
179+ is_mcopy,
154180 common_error_gadget,
155181 }
156182 }
@@ -166,6 +192,7 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
166192 ) -> Result < ( ) , Error > {
167193 let opcode = step. opcode . unwrap ( ) ;
168194 let is_extcodecopy = opcode == OpcodeId :: EXTCODECOPY ;
195+ let is_mcopy = opcode == OpcodeId :: MCOPY ;
169196
170197 log:: debug!(
171198 "ErrorOutOfGasMemoryCopy: opcode = {}, gas_left = {}, gas_cost = {}" ,
@@ -195,21 +222,37 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
195222 . assign ( region, offset, Value :: known ( F :: from ( transaction. id as u64 ) ) ) ?;
196223 self . external_address
197224 . assign ( region, offset, Some ( external_address. to_le_bytes ( ) ) ) ?;
198- // self.src_offset
199- // .assign(region, offset, Some(src_offset.to_le_bytes()))?;
200- self . src_memory_addr
225+
226+ let src_memory_addr = self
227+ . src_memory_addr
201228 . assign ( region, offset, src_offset, copy_size) ?;
202- let memory_addr = self
229+ let dst_memory_addr = self
203230 . dst_memory_addr
204231 . assign ( region, offset, dst_offset, copy_size) ?;
205- let ( _, memory_expansion_cost) =
206- self . memory_expansion
207- . assign ( region, offset, step. memory_word_size ( ) , [ memory_addr] ) ?;
232+ let ( _, memory_expansion_cost) = self . memory_expansion_normal . assign (
233+ region,
234+ offset,
235+ step. memory_word_size ( ) ,
236+ [ dst_memory_addr] ,
237+ ) ?;
238+
239+ // assign memory_expansion_mcopy
240+ let ( _, memory_expansion_cost_mcopy) = self . memory_expansion_mcopy . assign (
241+ region,
242+ offset,
243+ step. memory_word_size ( ) ,
244+ [ src_memory_addr, dst_memory_addr] ,
245+ ) ?;
246+
208247 let memory_copier_gas = self . memory_copier_gas . assign (
209248 region,
210249 offset,
211250 MemoryExpandedAddressGadget :: < F > :: length_value ( dst_offset, copy_size) ,
212- memory_expansion_cost,
251+ if is_mcopy {
252+ memory_expansion_cost_mcopy
253+ } else {
254+ memory_expansion_cost
255+ } ,
213256 ) ?;
214257 let constant_gas_cost = if is_extcodecopy {
215258 if is_warm {
@@ -231,6 +274,11 @@ impl<F: Field> ExecutionGadget<F> for ErrorOOGMemoryCopyGadget<F> {
231274 offset,
232275 F :: from ( opcode. as_u64 ( ) ) - F :: from ( OpcodeId :: EXTCODECOPY . as_u64 ( ) ) ,
233276 ) ?;
277+ self . is_mcopy . assign (
278+ region,
279+ offset,
280+ F :: from ( opcode. as_u64 ( ) ) - F :: from ( OpcodeId :: MCOPY . as_u64 ( ) ) ,
281+ ) ?;
234282 self . common_error_gadget . assign (
235283 region,
236284 offset,
@@ -313,7 +361,6 @@ mod tests {
313361 for ( src_offset, dest_offset, copy_size) in TESTING_MCOPY_PARIS {
314362 let testing_data =
315363 TestingData :: new_for_mcopy ( * src_offset, * dest_offset, * copy_size, None ) ;
316-
317364 test_root ( & testing_data) ;
318365 test_internal ( & testing_data) ;
319366 }
@@ -431,13 +478,18 @@ mod tests {
431478 } ;
432479
433480 let gas_cost = gas_cost. unwrap_or_else ( || {
434- let cur_memory_word_size = ( src_offset + 31 ) / 32 ;
435- let memory_word_size = ( dst_offset + copy_size + 31 ) / 32 ;
481+ // no memory operation before mcopy
482+ let cur_memory_word_size = 0 ;
483+ let next_memory_word_size = if copy_size == 0 {
484+ cur_memory_word_size
485+ } else {
486+ ( std:: cmp:: max ( src_offset, dst_offset) + copy_size + 31 ) / 32
487+ } ;
436488
437489 OpcodeId :: PUSH32 . constant_gas_cost ( ) . 0 * 3
438490 + memory_copier_gas_cost (
439491 cur_memory_word_size,
440- memory_word_size ,
492+ next_memory_word_size ,
441493 copy_size,
442494 GasCost :: COPY . as_u64 ( ) ,
443495 )
0 commit comments