@@ -428,6 +428,65 @@ pub(crate) static UPDATE_EVAL_FN: EvalFn =
428428 } )
429429 } ;
430430
431+ pub ( crate ) static INSERT_OR_UPDATE_EVAL_FN : EvalFn = |_mc, _env, _ctx, obj, args| {
432+ let mut avl_tree_data = obj. try_extract_into :: < AvlTreeData > ( ) ?;
433+
434+ if !avl_tree_data. tree_flags . insert_allowed ( ) || !avl_tree_data. tree_flags . update_allowed ( ) {
435+ return Ok ( Value :: Opt ( None ) ) ;
436+ }
437+
438+ let entries = {
439+ let v = args
440+ . first ( )
441+ . cloned ( )
442+ . ok_or_else ( || EvalError :: AvlTree ( "eval is missing first arg (entries)" . to_string ( ) ) ) ?;
443+ v. try_extract_into :: < Vec < ( Vec < u8 > , Vec < u8 > ) > > ( ) ?
444+ } ;
445+
446+ let proof = {
447+ let v = args
448+ . get ( 1 )
449+ . cloned ( )
450+ . ok_or_else ( || EvalError :: AvlTree ( "eval is missing second arg (proof)" . to_string ( ) ) ) ?;
451+ Bytes :: from ( v. try_extract_into :: < Vec < u8 > > ( ) ?)
452+ } ;
453+
454+ let starting_digest = Bytes :: from ( avl_tree_data. digest . 0 . to_vec ( ) ) ;
455+ let mut bv = BatchAVLVerifier :: new (
456+ & starting_digest,
457+ & proof,
458+ AVLTree :: new (
459+ |digest| Node :: LabelOnly ( NodeHeader :: new ( Some ( * digest) , None ) ) ,
460+ avl_tree_data. key_length as usize ,
461+ avl_tree_data
462+ . value_length_opt
463+ . as_ref ( )
464+ . map ( |v| * * v as usize ) ,
465+ ) ,
466+ None ,
467+ None ,
468+ )
469+ . map_err ( map_eval_err) ?;
470+ for ( key, value) in entries {
471+ if bv
472+ . perform_one_operation ( & Operation :: InsertOrUpdate ( KeyValue {
473+ key : key. into ( ) ,
474+ value : value. into ( ) ,
475+ } ) )
476+ . is_err ( )
477+ {
478+ break ;
479+ }
480+ }
481+ Ok ( if let Some ( new_digest) = bv. digest ( ) {
482+ let digest = ADDigest :: scorex_parse_bytes ( & new_digest) ?;
483+ avl_tree_data. digest = digest;
484+ Value :: Opt ( Some ( Box :: new ( Value :: AvlTree ( avl_tree_data. into ( ) ) ) ) )
485+ } else {
486+ Value :: Opt ( None )
487+ } )
488+ } ;
489+
431490fn map_eval_err < T : core:: fmt:: Debug > ( e : T ) -> EvalError {
432491 EvalError :: AvlTree ( format ! ( "{:?}" , e) )
433492}
@@ -708,6 +767,75 @@ mod tests {
708767 Value :: Opt ( None )
709768 ) ;
710769 }
770+
771+ #[ test]
772+ fn eval_avl_insert_or_update ( ) {
773+ let mut prover = BatchAVLProver :: new (
774+ AVLTree :: new (
775+ |digest| Node :: LabelOnly ( NodeHeader :: new ( Some ( * digest) , None ) ) ,
776+ 1 ,
777+ None ,
778+ ) ,
779+ true ,
780+ ) ;
781+ let initial_digest = ADDigest :: scorex_parse_bytes ( & prover. digest ( ) . unwrap ( ) ) . unwrap ( ) ;
782+ let key1 = Bytes :: from ( vec ! [ 1u8 ] ) ;
783+ let op = Operation :: InsertOrUpdate ( KeyValue {
784+ key : key1,
785+ value : Bytes :: from ( 10u64 . to_be_bytes ( ) . to_vec ( ) ) ,
786+ } ) ;
787+ prover. perform_one_operation ( & op) . unwrap ( ) ;
788+ prover. perform_one_operation ( & op) . unwrap ( ) ;
789+ let final_digest = ADDigest :: scorex_parse_bytes ( & prover. digest ( ) . unwrap ( ) ) . unwrap ( ) ;
790+ let proof: Constant = prover
791+ . generate_proof ( )
792+ . into_iter ( )
793+ . collect :: < Vec < _ > > ( )
794+ . into ( ) ;
795+
796+ let tree_flags = AvlTreeFlags :: new ( true , true , false ) ;
797+ let obj = Expr :: Const (
798+ AvlTreeData {
799+ digest : initial_digest,
800+ tree_flags,
801+ key_length : 1 ,
802+ value_length_opt : None ,
803+ }
804+ . into ( ) ,
805+ ) ;
806+ let pair1 = Literal :: Tup ( mk_pair ( 1u8 , 10u64 ) . into ( ) ) ;
807+ let entries = Constant {
808+ tpe : SType :: SColl ( Arc :: new ( SType :: STuple ( STuple :: pair (
809+ SType :: SColl ( Arc :: new ( SType :: SByte ) ) ,
810+ SType :: SColl ( Arc :: new ( SType :: SByte ) ) ,
811+ ) ) ) ) ,
812+ v : Literal :: Coll ( CollKind :: WrappedColl {
813+ items : Arc :: new ( [ pair1. clone ( ) , pair1. clone ( ) ] ) ,
814+ elem_tpe : SType :: STuple ( STuple :: pair (
815+ SType :: SColl ( Arc :: new ( SType :: SByte ) ) ,
816+ SType :: SColl ( Arc :: new ( SType :: SByte ) ) ,
817+ ) ) ,
818+ } ) ,
819+ } ;
820+ let expr: Expr = MethodCall :: new (
821+ obj. clone ( ) ,
822+ savltree:: INSERT_OR_UPDATE_METHOD . clone ( ) ,
823+ vec ! [ entries. clone( ) . into( ) , proof. clone( ) . into( ) ] ,
824+ )
825+ . unwrap ( )
826+ . into ( ) ;
827+
828+ let res = eval_out_wo_ctx :: < Value > ( & expr) ;
829+ if let Value :: Opt ( opt) = res {
830+ if let Some ( Value :: AvlTree ( avl) ) = opt. as_deref ( ) {
831+ assert_eq ! ( avl. digest, final_digest) ;
832+ } else {
833+ unreachable ! ( ) ;
834+ }
835+ } else {
836+ unreachable ! ( ) ;
837+ }
838+ }
711839 proptest ! {
712840 #[ test]
713841 fn eval_avl_digest( v in any:: <AvlTreeData >( ) ) {
0 commit comments