@@ -180,17 +180,39 @@ impl StorageEngine {
180180 stats,
181181 updated_storage_branch_nodes,
182182 ) ?;
183- let hash = node_hash. unwrap ( ) ;
184- println ! ( "Adding unaffected branch: {:?}" , path_prefix) ;
185- hash_builder. add_branch ( path_prefix. clone ( ) , hash, true ) ;
186- stats. account . branch_nodes += 1 ;
187- self . process_nonoverlapping_overlay_state (
188- context,
189- & post_overlay,
190- hash_builder,
191- stats,
192- updated_storage_branch_nodes,
193- ) ?;
183+ if !node. prefix ( ) . is_empty ( ) {
184+ // The node is actually an extension + branch node. We cannot add it by hash
185+ // as the extension prefix may have changed, which
186+ // would in turn change the hash. We need to
187+ // traverse the node via its full path.
188+ println ! (
189+ "Processing extension + branch: {:?} / {:?}" ,
190+ path_prefix, full_path
191+ ) ;
192+ self . handle_affected_node_with_overlay (
193+ context,
194+ & with_prefix,
195+ hash_builder,
196+ slotted_page,
197+ & node,
198+ & full_path,
199+ stats,
200+ updated_storage_branch_nodes,
201+ ) ?;
202+ } else {
203+ // This is a true branch node, so we can add it by hash.
204+ let hash = node_hash. unwrap ( ) ;
205+ println ! ( "Adding unaffected branch: {:?}" , path_prefix) ;
206+ hash_builder. add_branch ( path_prefix. clone ( ) , hash, true ) ;
207+ stats. account . branch_nodes += 1 ;
208+ self . process_nonoverlapping_overlay_state (
209+ context,
210+ & post_overlay,
211+ hash_builder,
212+ stats,
213+ updated_storage_branch_nodes,
214+ ) ?;
215+ }
194216 return Ok ( ( ) ) ;
195217 } else {
196218 let ( pre_overlay, with_prefix, post_overlay) =
@@ -309,6 +331,7 @@ impl StorageEngine {
309331 }
310332 None => {
311333 // Tombstone - skip
334+ println ! ( "Skipping tombstone: {:?}" , path) ;
312335 last_processed_path = Some ( path) ;
313336 }
314337 }
@@ -355,11 +378,18 @@ impl StorageEngine {
355378 ) ?;
356379 }
357380 NodeKind :: StorageLeaf { .. } => {
358- if let Some ( ( _, Some ( OverlayValue :: Storage ( value) ) ) ) = overlay. get ( 0 ) {
359- hash_builder. add_leaf ( full_path. clone ( ) , & self . encode_storage ( value) ?) ;
360- stats. storage . overlay_leaves += 1 ;
361- } else {
362- panic ! ( "Storage leaf does not have a valid overlay: {full_path:?}" ) ;
381+ match overlay. get ( 0 ) {
382+ Some ( ( _, Some ( OverlayValue :: Storage ( value) ) ) ) => {
383+ hash_builder. add_leaf ( full_path. clone ( ) , & self . encode_storage ( value) ?) ;
384+ stats. storage . overlay_leaves += 1 ;
385+ }
386+ Some ( ( _, None ) ) => {
387+ println ! ( "Skipping deleted storage leaf: {:?}" , full_path) ;
388+ stats. storage . overlay_leaves += 1 ;
389+ }
390+ _ => {
391+ panic ! ( "Storage leaf does not have a valid overlay: {full_path:?}" ) ;
392+ }
363393 }
364394 }
365395 }
@@ -396,22 +426,28 @@ impl StorageEngine {
396426 children[ i as usize ] = ( child_path, child_overlay, node. child ( i as u8 ) . unwrap ( ) ) ;
397427 }
398428
399- let num_children = children
429+ // This conservatively counts the minimum number of children that will exist. It may
430+ // undercount.
431+ let min_num_children = children
400432 . iter ( )
401433 . filter ( |( _, child_overlay, child_pointer) | {
402434 if let Some ( ( _, value) ) = child_overlay. get ( 0 ) {
435+ // If the overlayed value is none, this branch path might be removed.
403436 return value. is_some ( ) ;
404437 } else if child_pointer. is_some ( ) {
438+ // If there is no overlayed value and an existing child, then this path will
439+ // definitely exist.
405440 return true ;
406441 }
407442
408443 false
409444 } )
410445 . count ( ) ;
411446
412- if num_children > 1 {
413- // We have at least 2 children, so we can add non-overlayed children by hash instead of
414- // traversing them. This can save many lookups, hashes, and page reads.
447+ if min_num_children > 1 {
448+ // We are guaranteed to have at least 2 children, keeping this branch node alive.
449+ // We can add non-overlayed children by hash instead of traversing them. This can save
450+ // many lookups, hashes, and page reads.
415451 for ( child_path, child_overlay, child_pointer) in children. iter ( ) {
416452 if let Some ( ( path, _) ) = child_overlay. get ( 0 ) {
417453 if & path == child_path {
@@ -476,8 +512,8 @@ impl StorageEngine {
476512 return Ok ( ( ) ) ;
477513 }
478514
479- // Otherwise, this branch may no longer exist, so we need to traverse and add the children
480- // directly
515+ // Otherwise, it is possible that this branch might be removed.
516+ // We need to traverse and add the children directly in order to be safe.
481517 for ( child_path, child_overlay, child_pointer) in children. iter ( ) {
482518 if let Some ( ( path, _) ) = child_overlay. get ( 0 ) {
483519 if & path == child_path {
@@ -573,7 +609,7 @@ impl StorageEngine {
573609 }
574610 } else {
575611 // If overlay_value is None, it's a deletion - skip
576- // println!("Skipping deletion : {full_path:?}");
612+ println ! ( "Skipping deleted account : {full_path:?}" ) ;
577613 None
578614 }
579615 } else {
@@ -2002,8 +2038,6 @@ mod tests {
20022038 db. storage_engine . compute_root_with_overlay ( & context, & overlay) . unwrap ( ) ;
20032039 assert_ne ! ( overlay_root, initial_root) ;
20042040
2005- // println!("Overlay branches: {:?}", overlay_branches);
2006-
20072041 for ( path, branch) in overlay_branches. iter ( ) {
20082042 if let Some ( root_hash) = branch. root_hash {
20092043 overlay_mut_with_branches. insert ( path. clone ( ) , Some ( OverlayValue :: Hash ( root_hash) ) ) ;
0 commit comments