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