11// SPDX-License-Identifier: CC0-1.0
22
3- use core:: str:: FromStr ;
43use core:: { cmp, fmt, hash} ;
54
65#[ cfg( not( test) ) ] // https://github.com/rust-lang/rust/issues/121684
@@ -12,9 +11,10 @@ use bitcoin::taproot::{
1211use bitcoin:: { opcodes, Address , Network , ScriptBuf , Weight } ;
1312use sync:: Arc ;
1413
15- use super :: checksum:: { self , verify_checksum } ;
14+ use super :: checksum;
1615use crate :: descriptor:: DefiniteDescriptorKey ;
1716use crate :: expression:: { self , FromTree } ;
17+ use crate :: iter:: TreeLike as _;
1818use crate :: miniscript:: satisfy:: { Placeholder , Satisfaction , SchnorrSigType , Witness } ;
1919use crate :: miniscript:: Miniscript ;
2020use crate :: plan:: AssetProvider ;
@@ -23,8 +23,8 @@ use crate::policy::Liftable;
2323use crate :: prelude:: * ;
2424use crate :: util:: { varint_len, witness_size} ;
2525use crate :: {
26- Error , ForEachKey , FromStrKey , MiniscriptKey , Satisfier , ScriptContext , Tap , Threshold ,
27- ToPublicKey , TranslateErr , Translator ,
26+ Error , ForEachKey , FromStrKey , MiniscriptKey , ParseError , Satisfier , ScriptContext , Tap ,
27+ Threshold , ToPublicKey , TranslateErr , Translator ,
2828} ;
2929
3030/// A Taproot Tree representation.
@@ -490,79 +490,114 @@ where
490490 }
491491}
492492
493- #[ rustfmt:: skip]
494- impl < Pk : FromStrKey > Tr < Pk > {
495- // Helper function to parse taproot script path
496- fn parse_tr_script_spend ( tree : & expression:: Tree , ) -> Result < TapTree < Pk > , Error > {
497- match tree {
498- expression:: Tree { name, args, .. } if !name. is_empty ( ) && args. is_empty ( ) => {
499- let script = Miniscript :: < Pk , Tap > :: from_str ( name) ?;
500- Ok ( TapTree :: Leaf ( Arc :: new ( script) ) )
501- }
502- expression:: Tree { name, args, .. } if name. is_empty ( ) && args. len ( ) == 2 => {
503- let left = Self :: parse_tr_script_spend ( & args[ 0 ] ) ?;
504- let right = Self :: parse_tr_script_spend ( & args[ 1 ] ) ?;
505- Ok ( TapTree :: combine ( left, right) )
506- }
507- _ => {
508- Err ( Error :: Unexpected (
509- "unknown format for script spending paths while parsing taproot descriptor"
510- . to_string ( ) ,
511- ) ) } ,
512- }
493+ impl < Pk : FromStrKey > core:: str:: FromStr for Tr < Pk > {
494+ type Err = Error ;
495+
496+ fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
497+ let expr_tree = expression:: Tree :: from_str ( s) ?;
498+ Self :: from_tree ( & expr_tree)
513499 }
514500}
515501
516502impl < Pk : FromStrKey > crate :: expression:: FromTree for Tr < Pk > {
517- fn from_tree ( top : & expression:: Tree ) -> Result < Self , Error > {
518- if top. name == "tr" {
519- match top. args . len ( ) {
520- 1 => {
521- let key = & top. args [ 0 ] ;
522- if !key. args . is_empty ( ) {
523- return Err ( Error :: Unexpected ( format ! (
524- "#{} script associated with `key-path` while parsing taproot descriptor" ,
525- key. args. len( )
526- ) ) ) ;
503+ fn from_tree ( expr_tree : & expression:: Tree ) -> Result < Self , Error > {
504+ use crate :: expression:: { Parens , ParseTreeError } ;
505+
506+ expr_tree
507+ . verify_toplevel ( "tr" , 1 ..=2 )
508+ . map_err ( From :: from)
509+ . map_err ( Error :: Parse ) ?;
510+
511+ let mut round_paren_depth = 0 ;
512+
513+ let mut internal_key = None ;
514+ let mut tree_stack = vec ! [ ] ;
515+
516+ for item in expr_tree. verbose_pre_order_iter ( ) {
517+ // Top-level "tr" node.
518+ if item. index == 0 {
519+ if item. is_complete {
520+ debug_assert ! (
521+ internal_key. is_some( ) ,
522+ "checked above that top-level 'tr' has children"
523+ ) ;
524+ }
525+ } else if item. index == 1 {
526+ // First child of tr, which must be the internal key
527+ if !item. node . args . is_empty ( ) {
528+ return Err ( Error :: Parse ( ParseError :: Tree (
529+ ParseTreeError :: IncorrectNumberOfChildren {
530+ description : "internal key" ,
531+ n_children : item. node . args . len ( ) ,
532+ minimum : Some ( 0 ) ,
533+ maximum : Some ( 0 ) ,
534+ } ,
535+ ) ) ) ;
536+ }
537+ internal_key = Some (
538+ Pk :: from_str ( item. node . name )
539+ . map_err ( ParseError :: box_from_str)
540+ . map_err ( Error :: Parse ) ?,
541+ ) ;
542+ } else {
543+ // From here on we are into the taptree.
544+ if item. n_children_yielded == 0 {
545+ match item. node . parens {
546+ Parens :: Curly => {
547+ if !item. node . name . is_empty ( ) {
548+ return Err ( Error :: Parse ( ParseError :: Tree (
549+ ParseTreeError :: IncorrectName {
550+ actual : item. node . name . to_owned ( ) ,
551+ expected : "" ,
552+ } ,
553+ ) ) ) ;
554+ }
555+ if round_paren_depth > 0 {
556+ return Err ( Error :: Parse ( ParseError :: Tree (
557+ ParseTreeError :: IllegalCurlyBrace {
558+ pos : item. node . children_pos ,
559+ } ,
560+ ) ) ) ;
561+ }
562+ }
563+ Parens :: Round => round_paren_depth += 1 ,
564+ _ => { }
527565 }
528- Tr :: new ( expression:: terminal ( key, Pk :: from_str) ?, None )
529566 }
530- 2 => {
531- let key = & top. args [ 0 ] ;
532- if !key. args . is_empty ( ) {
533- return Err ( Error :: Unexpected ( format ! (
534- "#{} script associated with `key-path` while parsing taproot descriptor" ,
535- key. args. len( )
536- ) ) ) ;
567+ if item. is_complete {
568+ if item. node . parens == Parens :: Curly {
569+ if item. n_children_yielded == 2 {
570+ let rchild = tree_stack. pop ( ) . unwrap ( ) ;
571+ let lchild = tree_stack. pop ( ) . unwrap ( ) ;
572+ tree_stack. push ( TapTree :: combine ( lchild, rchild) ) ;
573+ } else {
574+ return Err ( Error :: Parse ( ParseError :: Tree (
575+ ParseTreeError :: IncorrectNumberOfChildren {
576+ description : "Taptree node" ,
577+ n_children : item. n_children_yielded ,
578+ minimum : Some ( 2 ) ,
579+ maximum : Some ( 2 ) ,
580+ } ,
581+ ) ) ) ;
582+ }
583+ } else {
584+ if item. node . parens == Parens :: Round {
585+ round_paren_depth -= 1 ;
586+ }
587+ if round_paren_depth == 0 {
588+ let script = Miniscript :: from_tree ( item. node ) ?;
589+ // FIXME hack for https://github.com/rust-bitcoin/rust-miniscript/issues/734
590+ if script. ty . corr . base != crate :: miniscript:: types:: Base :: B {
591+ return Err ( Error :: NonTopLevel ( format ! ( "{:?}" , script) ) ) ;
592+ } ;
593+ tree_stack. push ( TapTree :: Leaf ( Arc :: new ( script) ) ) ;
594+ }
537595 }
538- let tree = & top. args [ 1 ] ;
539- let ret = Self :: parse_tr_script_spend ( tree) ?;
540- Tr :: new ( expression:: terminal ( key, Pk :: from_str) ?, Some ( ret) )
541596 }
542- _ => Err ( Error :: Unexpected ( format ! (
543- "{}[#{} args] while parsing taproot descriptor" ,
544- top. name,
545- top. args. len( )
546- ) ) ) ,
547597 }
548- } else {
549- Err ( Error :: Unexpected ( format ! (
550- "{}[#{} args] while parsing taproot descriptor" ,
551- top. name,
552- top. args. len( )
553- ) ) )
554598 }
555- }
556- }
557-
558- impl < Pk : FromStrKey > core:: str:: FromStr for Tr < Pk > {
559- type Err = Error ;
560- fn from_str ( s : & str ) -> Result < Self , Self :: Err > {
561- let desc_str = verify_checksum ( s)
562- . map_err ( From :: from)
563- . map_err ( Error :: ParseTree ) ?;
564- let top = parse_tr_tree ( desc_str) ?;
565- Self :: from_tree ( & top)
599+ assert ! ( tree_stack. len( ) <= 1 ) ;
600+ Tr :: new ( internal_key. unwrap ( ) , tree_stack. pop ( ) )
566601 }
567602}
568603
@@ -588,69 +623,6 @@ impl<Pk: MiniscriptKey> fmt::Display for Tr<Pk> {
588623 }
589624}
590625
591- // Helper function to parse string into miniscript tree form
592- fn parse_tr_tree ( s : & str ) -> Result < expression:: Tree , Error > {
593- if s. len ( ) > 3 && & s[ ..3 ] == "tr(" && s. as_bytes ( ) [ s. len ( ) - 1 ] == b')' {
594- let rest = & s[ 3 ..s. len ( ) - 1 ] ;
595- if !rest. contains ( ',' ) {
596- let key = expression:: Tree :: from_str ( rest) ?;
597- if !key. args . is_empty ( ) {
598- return Err ( Error :: Unexpected ( "invalid taproot internal key" . to_string ( ) ) ) ;
599- }
600- let internal_key = expression:: Tree {
601- name : key. name ,
602- parens : expression:: Parens :: None ,
603- children_pos : 0 ,
604- args : vec ! [ ] ,
605- } ;
606- return Ok ( expression:: Tree {
607- name : "tr" ,
608- parens : expression:: Parens :: Round ,
609- children_pos : 0 ,
610- args : vec ! [ internal_key] ,
611- } ) ;
612- }
613- // use str::split_once() method to refactor this when compiler version bumps up
614- let ( key, script) = split_once ( rest, ',' )
615- . ok_or_else ( || Error :: BadDescriptor ( "invalid taproot descriptor" . to_string ( ) ) ) ?;
616-
617- let key = expression:: Tree :: from_str ( key) ?;
618- if !key. args . is_empty ( ) {
619- return Err ( Error :: Unexpected ( "invalid taproot internal key" . to_string ( ) ) ) ;
620- }
621- let internal_key = expression:: Tree {
622- name : key. name ,
623- parens : expression:: Parens :: None ,
624- children_pos : 0 ,
625- args : vec ! [ ] ,
626- } ;
627- let tree = expression:: Tree :: from_slice_delim ( script, expression:: Delimiter :: Taproot )
628- . map_err ( Error :: ParseTree ) ?;
629- Ok ( expression:: Tree {
630- name : "tr" ,
631- parens : expression:: Parens :: Round ,
632- children_pos : 0 ,
633- args : vec ! [ internal_key, tree] ,
634- } )
635- } else {
636- Err ( Error :: Unexpected ( "invalid taproot descriptor" . to_string ( ) ) )
637- }
638- }
639-
640- fn split_once ( inp : & str , delim : char ) -> Option < ( & str , & str ) > {
641- if inp. is_empty ( ) {
642- None
643- } else {
644- // find the first character that matches delim
645- let res = inp
646- . chars ( )
647- . position ( |ch| ch == delim)
648- . map ( |idx| ( & inp[ ..idx] , & inp[ idx + 1 ..] ) )
649- . unwrap_or ( ( inp, "" ) ) ;
650- Some ( res)
651- }
652- }
653-
654626impl < Pk : MiniscriptKey > Liftable < Pk > for TapTree < Pk > {
655627 fn lift ( & self ) -> Result < Policy < Pk > , Error > {
656628 fn lift_helper < Pk : MiniscriptKey > ( s : & TapTree < Pk > ) -> Result < Policy < Pk > , Error > {
@@ -767,6 +739,8 @@ where
767739
768740#[ cfg( test) ]
769741mod tests {
742+ use core:: str:: FromStr ;
743+
770744 use super :: * ;
771745
772746 fn descriptor ( ) -> String {
0 commit comments