@@ -269,15 +269,15 @@ pub type E1VmSegmentExecutor<F, VC> = VmSegmentExecutor<F, VC, E1ExecutionContro
269
269
pub struct MeteredCtx {
270
270
continuations_enabled : bool ,
271
271
memory_dimensions : MemoryDimensions ,
272
- addr_space_alignment_bytes : Vec < usize > ,
272
+ // addr_space_alignment_bytes: Vec<usize>,
273
273
274
274
// Trace heights for each chip
275
275
pub trace_heights : Vec < usize > ,
276
276
// Accesses of size [1, 2, 4, 8, 16, 32]
277
277
// TODO(ayush): no magic number
278
278
pub memory_ops : [ usize ; 6 ] ,
279
- // (addr_space, addr, size)
280
- pub memory_addresses : BTreeSet < ( u8 , u32 , u8 ) > ,
279
+ // Indices of leaf nodes in the memory merkle tree
280
+ pub leaf_indices : BTreeSet < u64 > ,
281
281
}
282
282
283
283
impl MeteredCtx {
@@ -291,7 +291,7 @@ impl MeteredCtx {
291
291
memory_dimensions,
292
292
trace_heights : vec ! [ 0 ; num_traces] ,
293
293
memory_ops : [ 0 ; 6 ] ,
294
- memory_addresses : BTreeSet :: new ( ) ,
294
+ leaf_indices : BTreeSet :: new ( ) ,
295
295
}
296
296
}
297
297
}
@@ -338,48 +338,77 @@ impl E1E2ExecutionCtx for MeteredCtx {
338
338
self . memory_ops [ log2_strict_usize ( size) ] += 1 ;
339
339
// TODO(ayush): access adapter heights based on this
340
340
341
- // TODO(ayush): see if this can be approximated by total number of reads/writes for AS != register
342
- self . memory_addresses
343
- . insert ( ( address_space as u8 , ptr, size as u8 ) ) ;
341
+ // Calculate unique chunks and inner nodes in Merkle tree
342
+ let mt_height = self . memory_dimensions . overall_height ( ) ;
344
343
345
- let log2_chunk = log2_strict_usize ( CHUNK ) ;
346
- self . trace_heights [ offset + log2_chunk] = leaf_indices. len ( ) * 2 ;
344
+ // TODO(ayush): see if this can be approximated by total number of reads/writes for AS != register
345
+ let num_chunks = size. div_ceil ( CHUNK ) ;
346
+ for i in 0 ..num_chunks {
347
+ let addr = ptr. wrapping_add ( ( i * CHUNK ) as u32 ) ;
348
+ let block_id = addr / CHUNK as u32 ;
349
+ let leaf_index = self
350
+ . memory_dimensions
351
+ . label_to_index ( ( address_space, block_id) ) ;
352
+
353
+ // TODO(ayush): see if insertion and finding pred/succ can be done in single binary search pass
354
+ if self . leaf_indices . insert ( leaf_index) {
355
+ // | Boundary | Merkle | Access Adapters |
356
+ // TODO(ayush): no magic numbers
357
+ let mut offset = 2 ;
358
+
359
+ // Boundary chip
360
+ self . trace_heights [ offset] += 1 ;
361
+
362
+ if self . continuations_enabled {
363
+ // Merkle chip
364
+ offset += 1 ;
365
+
366
+ let height_change =
367
+ calculate_merkle_height_changes ( leaf_index, & self . leaf_indices , mt_height) ;
368
+ self . trace_heights [ offset] += height_change * 2 ;
369
+ }
347
370
348
- // Calculate unique chunks and inner nodes in Merkle tree
349
- let height = self . memory_dimensions . overall_height ( ) ;
350
-
351
- // Map memory addresses to leaf indices in the Merkle tree
352
- let leaf_indices: BTreeSet < u64 > = self
353
- . memory_addresses
354
- . iter ( )
355
- . map ( |& ( space, addr, _size) | {
356
- let block_id = addr / CHUNK as u32 ;
357
- ( 1 << height)
358
- + ( ( ( space as u32 - self . memory_dimensions . as_offset ) as u64 )
359
- << self . memory_dimensions . address_height )
360
- + block_id as u64
361
- } )
362
- . collect ( ) ;
363
-
364
- // Sum up the heights of the XORs between consecutive leaf indices
365
- let path_divergences = leaf_indices
366
- . iter ( )
367
- . zip ( leaf_indices. iter ( ) . skip ( 1 ) )
368
- . map ( |( & lhs, & rhs) | ( lhs ^ rhs) . checked_ilog2 ( ) . map_or ( 0 , |bits| bits as usize ) )
369
- . sum :: < usize > ( ) ;
370
-
371
- let modified_nodes_count = height + path_divergences;
372
-
373
- // | Boundary | Merkle | Access Adapters |
374
- let mut offset = 2 ;
375
- self . trace_heights [ offset] = leaf_indices. len ( ) ;
376
-
377
- if self . continuations_enabled {
378
- offset += 1 ;
379
- self . trace_heights [ offset] = modified_nodes_count * 2 ;
371
+ // 8-byte access adapter
372
+ let log2_chunk = log2_strict_usize ( CHUNK ) ;
373
+ self . trace_heights [ offset + log2_chunk] += 2 ;
374
+ }
380
375
}
376
+ }
377
+ }
381
378
382
- let log2_chunk = log2_strict_usize ( CHUNK ) ;
383
- self . trace_heights [ offset + log2_chunk] = leaf_indices. len ( ) * 2 ;
379
+ /// Updates Merkle tree heights based on a new leaf index
380
+ fn calculate_merkle_height_changes (
381
+ leaf_index : u64 ,
382
+ leaf_indices : & BTreeSet < u64 > ,
383
+ height : usize ,
384
+ ) -> usize {
385
+ if leaf_indices. len ( ) == 1 {
386
+ return height;
384
387
}
388
+
389
+ // Find predecessor and successor nodes
390
+ let pred = leaf_indices. range ( ..leaf_index) . next_back ( ) . copied ( ) ;
391
+ let succ = leaf_indices. range ( leaf_index + 1 ..) . next ( ) . copied ( ) ;
392
+
393
+ let mut diff = 0 ;
394
+
395
+ // Add new divergences between pred and leaf_index
396
+ if let Some ( p) = pred {
397
+ let new_divergence = ( p ^ leaf_index) . ilog2 ( ) as usize ;
398
+ diff += new_divergence;
399
+ }
400
+
401
+ // Add new divergences between leaf_index and succ
402
+ if let Some ( s) = succ {
403
+ let new_divergence = ( leaf_index ^ s) . ilog2 ( ) as usize ;
404
+ diff += new_divergence;
405
+ }
406
+
407
+ // Remove old divergence between pred and succ if both existed
408
+ if let ( Some ( p) , Some ( s) ) = ( pred, succ) {
409
+ let old_divergence = ( p ^ s) . ilog2 ( ) as usize ;
410
+ diff -= old_divergence;
411
+ }
412
+
413
+ diff
385
414
}
0 commit comments