@@ -194,7 +194,11 @@ fn is_valid_desc_key(key: &descriptor::DescriptorPublicKey) -> bool {
194194/// An [InheritanceDescriptor] that contains multipath keys for (and only for) the receive keychain
195195/// and the change keychain.
196196#[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize ) ]
197- pub struct MultipathDescriptor ( descriptor:: Descriptor < descriptor:: DescriptorPublicKey > ) ;
197+ pub struct MultipathDescriptor {
198+ multi_desc : descriptor:: Descriptor < descriptor:: DescriptorPublicKey > ,
199+ receive_desc : InheritanceDescriptor ,
200+ change_desc : InheritanceDescriptor ,
201+ }
198202
199203/// A Miniscript descriptor with a main, unencombered, branch (the main owner of the coins)
200204/// and a timelocked branch (the heir). All keys in this descriptor are singlepath.
@@ -207,7 +211,7 @@ pub struct DerivedInheritanceDescriptor(descriptor::Descriptor<DerivedPublicKey>
207211
208212impl fmt:: Display for MultipathDescriptor {
209213 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
210- write ! ( f, "{}" , self . 0 )
214+ write ! ( f, "{}" , self . multi_desc )
211215 }
212216}
213217
@@ -277,8 +281,26 @@ impl str::FromStr for MultipathDescriptor {
277281 . iter ( )
278282 . find ( |s| matches ! ( s, SemanticPolicy :: Key ( _) ) )
279283 . ok_or ( DescCreationError :: IncompatibleDesc ) ?;
284+ let multi_desc = descriptor:: Descriptor :: Wsh ( wsh_desc) ;
280285
281- Ok ( MultipathDescriptor ( descriptor:: Descriptor :: Wsh ( wsh_desc) ) )
286+ // Compute the receive and change "sub" descriptors right away. According to our pubkey
287+ // check above, there must be only two of those, 0 and 1.
288+ // We use /0/* for receiving and /1/* for change.
289+ // FIXME: don't rely on into_single_descs()'s ordering.
290+ let mut singlepath_descs = multi_desc
291+ . clone ( )
292+ . into_single_descriptors ( )
293+ . expect ( "Can't error, all paths have the same length" )
294+ . into_iter ( ) ;
295+ assert_eq ! ( singlepath_descs. len( ) , 2 ) ;
296+ let receive_desc = InheritanceDescriptor ( singlepath_descs. next ( ) . expect ( "First of 2" ) ) ;
297+ let change_desc = InheritanceDescriptor ( singlepath_descs. next ( ) . expect ( "Second of 2" ) ) ;
298+
299+ Ok ( MultipathDescriptor {
300+ multi_desc,
301+ receive_desc,
302+ change_desc,
303+ } )
282304 }
283305}
284306
@@ -341,15 +363,33 @@ impl MultipathDescriptor {
341363 . expect ( "Well typed" ) ;
342364 miniscript:: Segwitv0 :: check_local_validity ( & tl_miniscript)
343365 . expect ( "Miniscript must be sane" ) ;
344-
345- Ok ( MultipathDescriptor ( descriptor:: Descriptor :: Wsh (
366+ let multi_desc = descriptor:: Descriptor :: Wsh (
346367 descriptor:: Wsh :: new ( tl_miniscript) . expect ( "Must pass sanity checks" ) ,
347- ) ) )
368+ ) ;
369+
370+ // Compute the receive and change "sub" descriptors right away. According to our pubkey
371+ // check above, there must be only two of those, 0 and 1.
372+ // We use /0/* for receiving and /1/* for change.
373+ // FIXME: don't rely on into_single_descs()'s ordering.
374+ let mut singlepath_descs = multi_desc
375+ . clone ( )
376+ . into_single_descriptors ( )
377+ . expect ( "Can't error, all paths have the same length" )
378+ . into_iter ( ) ;
379+ assert_eq ! ( singlepath_descs. len( ) , 2 ) ;
380+ let receive_desc = InheritanceDescriptor ( singlepath_descs. next ( ) . expect ( "First of 2" ) ) ;
381+ let change_desc = InheritanceDescriptor ( singlepath_descs. next ( ) . expect ( "Second of 2" ) ) ;
382+
383+ Ok ( MultipathDescriptor {
384+ multi_desc,
385+ receive_desc,
386+ change_desc,
387+ } )
348388 }
349389
350390 /// Whether all xpubs contained in this descriptor are for the passed expected network.
351391 pub fn all_xpubs_net_is ( & self , expected_net : bitcoin:: Network ) -> bool {
352- self . 0 . for_each_key ( |xpub| {
392+ self . multi_desc . for_each_key ( |xpub| {
353393 if let descriptor:: DescriptorPublicKey :: MultiXPub ( xpub) = xpub {
354394 xpub. xkey . network == expected_net
355395 } else {
@@ -358,52 +398,19 @@ impl MultipathDescriptor {
358398 } )
359399 }
360400
361- // TODO: Cache it inside the struct, it's very inefficient to use into_single_descriptors() for
362- // every single derivation.
363401 /// Get the descriptor for receiving addresses.
364- pub fn receive_descriptor ( & self ) -> InheritanceDescriptor {
365- let singlepath_descs = self
366- . 0
367- . clone ( )
368- . into_single_descriptors ( )
369- . expect ( "Can't error, all paths have the same length" ) ;
370- assert_eq ! ( singlepath_descs. len( ) , 2 ) ;
371-
372- // We use /0/* for receiving, so it's the first descriptor between <0;1>.
373- // FIXME: don't rely on ordering.
374- InheritanceDescriptor (
375- singlepath_descs
376- . into_iter ( )
377- . next ( )
378- . expect ( "Just checked the length" ) ,
379- )
402+ pub fn receive_descriptor ( & self ) -> & InheritanceDescriptor {
403+ & self . receive_desc
380404 }
381405
382- // TODO: Cache it inside the struct, it's very inefficient to use into_single_descriptors() for
383- // every single derivation.
384406 /// Get the descriptor for change addresses.
385- pub fn change_descriptor ( & self ) -> InheritanceDescriptor {
386- let singlepath_descs = self
387- . 0
388- . clone ( )
389- . into_single_descriptors ( )
390- . expect ( "Can't error, all paths have the same length" ) ;
391- assert_eq ! ( singlepath_descs. len( ) , 2 ) ;
392-
393- // We use /1/* for change, so it's the second descriptor between <0;1>.
394- // FIXME: don't rely on ordering.
395- InheritanceDescriptor (
396- singlepath_descs
397- . into_iter ( )
398- . rev ( )
399- . next ( )
400- . expect ( "Just checked the length" ) ,
401- )
407+ pub fn change_descriptor ( & self ) -> & InheritanceDescriptor {
408+ & self . change_desc
402409 }
403410
404411 /// Get the value (in blocks) of the relative timelock for the heir's spending path.
405412 pub fn timelock_value ( & self ) -> u32 {
406- let wsh_desc = match & self . 0 {
413+ let wsh_desc = match & self . multi_desc {
407414 descriptor:: Descriptor :: Wsh ( desc) => desc,
408415 _ => unreachable ! ( ) ,
409416 } ;
0 commit comments