@@ -481,6 +481,153 @@ impl DbUpdateType {
481481 migrator. commit ( state. db ( ) ) ?;
482482 Ok ( status)
483483 }
484+
485+ /// Validate a change and persist it to pre-commit merkle tree if valid.
486+ pub fn pre_commit_update < D , H > (
487+ & self ,
488+ state : & mut FullAccessState < D , H > ,
489+ ) -> eyre:: Result < UpdateStatus >
490+ where
491+ D : ' static + DB + for < ' iter > DBIter < ' iter > ,
492+ H : ' static + StorageHasher ,
493+ {
494+ let migrator = D :: migrator ( ) ;
495+ let status = match self {
496+ Self :: Add { key, cf, value, .. } => {
497+ let ( deserialized, deserializer) = self . validate ( ) ?;
498+ if let ( Some ( prev) , Some ( des) ) =
499+ ( migrator. read ( state. db ( ) , key, cf) , deserializer)
500+ {
501+ des ( prev) . ok_or_else ( || {
502+ eyre:: eyre!(
503+ "The previous value under the key {} did not have \
504+ the same type as that provided: Input was {}",
505+ key,
506+ deserialized
507+ )
508+ } ) ?;
509+ }
510+ let value = value. bytes ( ) ;
511+ let persist_diffs = ( state. diff_key_filter ) ( key) ;
512+ if let DbColFam :: SUBSPACE = cf {
513+ // Update the merkle tree
514+ let merk_key = if !persist_diffs {
515+ let prefix = storage:: Key :: from (
516+ NO_DIFF_KEY_PREFIX . to_string ( ) . to_db_key ( ) ,
517+ ) ;
518+ & prefix. join ( key)
519+ } else {
520+ key
521+ } ;
522+ state
523+ . in_mem_mut ( )
524+ . block
525+ . pre_commit_tree
526+ . update ( merk_key, value) ?;
527+ }
528+ Ok ( UpdateStatus :: Add ( vec ! [ ( key. to_string( ) , deserialized) ] ) )
529+ }
530+ Self :: Delete ( key, cf) => {
531+ let persist_diffs = ( state. diff_key_filter ) ( key) ;
532+ if let DbColFam :: SUBSPACE = cf {
533+ // Update the merkle tree
534+ let merk_key = if !persist_diffs {
535+ let prefix = storage:: Key :: from (
536+ NO_DIFF_KEY_PREFIX . to_string ( ) . to_db_key ( ) ,
537+ ) ;
538+ & prefix. join ( key)
539+ } else {
540+ key
541+ } ;
542+ state
543+ . in_mem_mut ( )
544+ . block
545+ . pre_commit_tree
546+ . delete ( merk_key) ?;
547+ }
548+ Ok ( UpdateStatus :: Deleted ( vec ! [ key. to_string( ) ] ) )
549+ }
550+ DbUpdateType :: RepeatAdd {
551+ pattern, cf, value, ..
552+ } => {
553+ let pattern = Regex :: new ( pattern) . unwrap ( ) ;
554+ let mut pairs = vec ! [ ] ;
555+ let ( deserialized, deserializer) = self . validate ( ) ?;
556+ for ( key, prev) in
557+ migrator. get_pattern ( state. db ( ) , pattern. clone ( ) )
558+ {
559+ if let Some ( des) = deserializer {
560+ des ( prev) . ok_or_else ( || {
561+ eyre:: eyre!(
562+ "The previous value under the key {} did not \
563+ have the same type as that provided: Input \
564+ was {}",
565+ key,
566+ deserialized,
567+ )
568+ } ) ?;
569+ pairs. push ( ( key. clone ( ) , deserialized. clone ( ) ) ) ;
570+ } else {
571+ pairs. push ( ( key. clone ( ) , deserialized. clone ( ) ) ) ;
572+ }
573+ let key = storage:: Key :: from_str ( & key) . unwrap ( ) ;
574+ let value = value. bytes ( ) ;
575+ let persist_diffs = ( state. diff_key_filter ) ( & key) ;
576+ if let DbColFam :: SUBSPACE = cf {
577+ // Update the merkle tree
578+ let merk_key = if !persist_diffs {
579+ let prefix = storage:: Key :: from (
580+ NO_DIFF_KEY_PREFIX . to_string ( ) . to_db_key ( ) ,
581+ ) ;
582+ & prefix. join ( & key)
583+ } else {
584+ & key
585+ } ;
586+ state
587+ . in_mem_mut ( )
588+ . block
589+ . pre_commit_tree
590+ . update ( merk_key, value) ?;
591+ }
592+ }
593+ Ok :: < _ , eyre:: Error > ( UpdateStatus :: Add ( pairs) )
594+ }
595+ DbUpdateType :: RepeatDelete ( pattern, cf) => {
596+ let pattern = Regex :: new ( pattern) . unwrap ( ) ;
597+ Ok ( UpdateStatus :: Deleted (
598+ migrator
599+ . get_pattern ( state. db ( ) , pattern. clone ( ) )
600+ . into_iter ( )
601+ . map ( |( raw_key, _) | {
602+ let key = storage:: Key :: from_str ( & raw_key) . unwrap ( ) ;
603+ let persist_diffs = ( state. diff_key_filter ) ( & key) ;
604+ if let DbColFam :: SUBSPACE = cf {
605+ // Update the merkle tree
606+ let merk_key = if !persist_diffs {
607+ let prefix = storage:: Key :: from (
608+ NO_DIFF_KEY_PREFIX
609+ . to_string ( )
610+ . to_db_key ( ) ,
611+ ) ;
612+ & prefix. join ( & key)
613+ } else {
614+ & key
615+ } ;
616+ state
617+ . in_mem_mut ( )
618+ . block
619+ . pre_commit_tree
620+ . delete ( merk_key) ?;
621+ }
622+
623+ Ok ( raw_key)
624+ } )
625+ . collect :: < eyre:: Result < Vec < _ > > > ( ) ?,
626+ ) )
627+ }
628+ } ?;
629+ Ok ( status)
630+ }
484631}
485632
486633/// A set of key-value changes to be applied to
@@ -655,6 +802,39 @@ pub fn commit<D, H>(
655802 }
656803}
657804
805+ /// Check if a scheduled migration should take place at this block height.
806+ /// If so, apply it to the pre-commit merkle tree.
807+ pub fn pre_commit < D , H > (
808+ state : & mut FullAccessState < D , H > ,
809+ migration : impl IntoIterator < Item = DbUpdateType > ,
810+ ) where
811+ D : ' static + DB + for < ' iter > DBIter < ' iter > ,
812+ H : ' static + StorageHasher ,
813+ {
814+ tracing:: info!( "Starting pre-commit migration..." ) ;
815+
816+ for change in migration. into_iter ( ) {
817+ match change. pre_commit_update ( state) {
818+ Ok ( status) => {
819+ tracing:: info!( "{status}" ) ;
820+ }
821+ Err ( e) => {
822+ let error = format ! (
823+ "Attempt to write to key/pattern <{}> failed:\n {}." ,
824+ change. pattern( ) ,
825+ e
826+ ) ;
827+ tracing:: error!( error) ;
828+ panic ! (
829+ "Failed to execute migration, no changes persisted. \
830+ Encountered error: {}",
831+ e
832+ ) ;
833+ }
834+ }
835+ }
836+ }
837+
658838derive_borshdeserializer ! ( Vec :: <u8 >) ;
659839derive_borshdeserializer ! ( Vec :: <String >) ;
660840derive_borshdeserializer ! ( u64 ) ;
0 commit comments