@@ -525,6 +525,99 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
525
525
}
526
526
}
527
527
528
+ /// Utility function used when parsing a script from an expression tree.
529
+ ///
530
+ /// Checks that the name of each fragment has at most one `:`, splits
531
+ /// the name at the `:`, and implements aliases for the old `pk`/`pk_h`
532
+ /// fragments.
533
+ ///
534
+ /// Returns the fragment name (right of the `:`) and a list of wrappers
535
+ /// (left of the `:`).
536
+ fn split_expression_name ( name : & str ) -> Result < ( & str , Cow < str > ) , Error > {
537
+ let mut aliased_wrap;
538
+ let frag_name;
539
+ let frag_wrap;
540
+ let mut name_split = name. split ( ':' ) ;
541
+ match ( name_split. next ( ) , name_split. next ( ) , name_split. next ( ) ) {
542
+ ( None , _, _) => {
543
+ frag_name = "" ;
544
+ frag_wrap = "" . into ( ) ;
545
+ }
546
+ ( Some ( name) , None , _) => {
547
+ if name == "pk" {
548
+ frag_name = "pk_k" ;
549
+ frag_wrap = "c" . into ( ) ;
550
+ } else if name == "pkh" {
551
+ frag_name = "pk_h" ;
552
+ frag_wrap = "c" . into ( ) ;
553
+ } else {
554
+ frag_name = name;
555
+ frag_wrap = "" . into ( ) ;
556
+ }
557
+ }
558
+ ( Some ( wrap) , Some ( name) , None ) => {
559
+ if wrap. is_empty ( ) {
560
+ return Err ( Error :: Unexpected ( name. to_owned ( ) ) ) ;
561
+ }
562
+ if name == "pk" {
563
+ frag_name = "pk_k" ;
564
+ aliased_wrap = wrap. to_owned ( ) ;
565
+ aliased_wrap. push ( 'c' ) ;
566
+ frag_wrap = aliased_wrap. into ( ) ;
567
+ } else if name == "pkh" {
568
+ frag_name = "pk_h" ;
569
+ aliased_wrap = wrap. to_owned ( ) ;
570
+ aliased_wrap. push ( 'c' ) ;
571
+ frag_wrap = aliased_wrap. into ( ) ;
572
+ } else {
573
+ frag_name = name;
574
+ frag_wrap = wrap. into ( ) ;
575
+ }
576
+ }
577
+ ( Some ( _) , Some ( _) , Some ( _) ) => {
578
+ return Err ( Error :: MultiColon ( name. to_owned ( ) ) ) ;
579
+ }
580
+ }
581
+ Ok ( ( frag_name, frag_wrap) )
582
+ }
583
+
584
+ /// Utility function used when parsing a script from an expression tree.
585
+ ///
586
+ /// Once a Miniscript fragment has been parsed into a terminal, apply any
587
+ /// wrappers that were included in its name.
588
+ fn wrap_into_miniscript < Pk , Ctx > (
589
+ term : Terminal < Pk , Ctx > ,
590
+ frag_wrap : Cow < str > ,
591
+ ) -> Result < Miniscript < Pk , Ctx > , Error >
592
+ where
593
+ Pk : MiniscriptKey ,
594
+ Ctx : ScriptContext ,
595
+ {
596
+ let mut unwrapped = term;
597
+ for ch in frag_wrap. chars ( ) . rev ( ) {
598
+ // Check whether the wrapper is valid under the current context
599
+ let ms = Miniscript :: from_ast ( unwrapped) ?;
600
+ Ctx :: check_global_validity ( & ms) ?;
601
+ match ch {
602
+ 'a' => unwrapped = Terminal :: Alt ( Arc :: new ( ms) ) ,
603
+ 's' => unwrapped = Terminal :: Swap ( Arc :: new ( ms) ) ,
604
+ 'c' => unwrapped = Terminal :: Check ( Arc :: new ( ms) ) ,
605
+ 'd' => unwrapped = Terminal :: DupIf ( Arc :: new ( ms) ) ,
606
+ 'v' => unwrapped = Terminal :: Verify ( Arc :: new ( ms) ) ,
607
+ 'j' => unwrapped = Terminal :: NonZero ( Arc :: new ( ms) ) ,
608
+ 'n' => unwrapped = Terminal :: ZeroNotEqual ( Arc :: new ( ms) ) ,
609
+ 't' => unwrapped = Terminal :: AndV ( Arc :: new ( ms) , Arc :: new ( Miniscript :: TRUE ) ) ,
610
+ 'u' => unwrapped = Terminal :: OrI ( Arc :: new ( ms) , Arc :: new ( Miniscript :: FALSE ) ) ,
611
+ 'l' => unwrapped = Terminal :: OrI ( Arc :: new ( Miniscript :: FALSE ) , Arc :: new ( ms) ) ,
612
+ x => return Err ( Error :: UnknownWrapper ( x) ) ,
613
+ }
614
+ }
615
+ // Check whether the unwrapped miniscript is valid under the current context
616
+ let ms = Miniscript :: from_ast ( unwrapped) ?;
617
+ Ctx :: check_global_validity ( & ms) ?;
618
+ Ok ( ms)
619
+ }
620
+
528
621
impl < Pk : crate :: FromStrKey , Ctx : ScriptContext > Miniscript < Pk , Ctx > {
529
622
/// Attempt to parse an insane(scripts don't clear sanity checks)
530
623
/// from string into a Miniscript representation.
0 commit comments