@@ -10,11 +10,17 @@ use crate::{
10
10
DescriptorExt , DescriptorId , Indexed , Indexer , KeychainIndexed , SpkIterator ,
11
11
} ;
12
12
use alloc:: { borrow:: ToOwned , vec:: Vec } ;
13
- use bitcoin:: { Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxOut , Txid } ;
13
+ use bitcoin:: {
14
+ bip32:: ChildNumber , Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxOut , Txid ,
15
+ } ;
14
16
use core:: {
15
17
fmt:: Debug ,
16
18
ops:: { Bound , RangeBounds } ,
17
19
} ;
20
+ use miniscript:: {
21
+ descriptor:: { DescriptorXKey , Wildcard } ,
22
+ ForEachKey ,
23
+ } ;
18
24
19
25
use crate :: Merge ;
20
26
@@ -170,7 +176,7 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
170
176
}
171
177
}
172
178
173
- fn apply_changeset ( & mut self , changeset : Self :: ChangeSet ) {
179
+ fn apply_changeset ( & mut self , changeset : Self :: ChangeSet ) -> Result < ( ) , InsertDescriptorError > {
174
180
self . apply_changeset ( changeset)
175
181
}
176
182
@@ -767,18 +773,38 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
767
773
}
768
774
769
775
/// Applies the `ChangeSet<K>` to the [`KeychainTxOutIndex<K>`]
770
- pub fn apply_changeset ( & mut self , changeset : ChangeSet ) {
776
+ pub fn apply_changeset ( & mut self , changeset : ChangeSet ) -> Result < ( ) , InsertDescriptorError > {
771
777
for ( & desc_id, & index) in & changeset. last_revealed {
778
+ let descriptor = self . descriptors . get ( & desc_id) . expect ( "invariant" ) ;
779
+ // Ensure the keys don't contain any hardened derivation steps or hardened wildcards
780
+ let descriptor_contains_hardened_steps = descriptor. for_any_key ( |k| {
781
+ if let DescriptorPublicKey :: XPub ( DescriptorXKey {
782
+ derivation_path,
783
+ wildcard,
784
+ ..
785
+ } ) = k
786
+ {
787
+ return * wildcard == Wildcard :: Hardened
788
+ || derivation_path. into_iter ( ) . any ( ChildNumber :: is_hardened) ;
789
+ }
790
+
791
+ false
792
+ } ) ;
793
+ if descriptor_contains_hardened_steps {
794
+ return Err ( InsertDescriptorError :: HardenedDerivationXpub ) ;
795
+ }
796
+ descriptor. sanity_check ( ) ?;
772
797
let v = self . last_revealed . entry ( desc_id) . or_default ( ) ;
773
798
* v = index. max ( * v) ;
774
799
self . replenish_inner_index_did ( desc_id, self . lookahead ) ;
775
800
}
801
+ Ok ( ( ) )
776
802
}
777
803
}
778
804
779
- #[ derive( Clone , Debug , PartialEq ) ]
805
+ #[ derive( Debug , PartialEq ) ]
780
806
/// Error returned from [`KeychainTxOutIndex::insert_descriptor`]
781
- pub enum InsertDescriptorError < K > {
807
+ pub enum InsertDescriptorError < K = ( ) > {
782
808
/// The descriptor has already been assigned to a keychain so you can't assign it to another
783
809
DescriptorAlreadyAssigned {
784
810
/// The descriptor you have attempted to reassign
@@ -793,6 +819,16 @@ pub enum InsertDescriptorError<K> {
793
819
/// The descriptor that the keychain is already assigned to
794
820
existing_assignment : Descriptor < DescriptorPublicKey > ,
795
821
} ,
822
+ /// Miniscript error
823
+ Miniscript ( miniscript:: Error ) ,
824
+ /// The descriptor contains hardened derivation steps on public extended keys
825
+ HardenedDerivationXpub ,
826
+ }
827
+
828
+ impl From < miniscript:: Error > for InsertDescriptorError {
829
+ fn from ( err : miniscript:: Error ) -> Self {
830
+ InsertDescriptorError :: Miniscript ( err)
831
+ }
796
832
}
797
833
798
834
impl < K : core:: fmt:: Debug > core:: fmt:: Display for InsertDescriptorError < K > {
@@ -816,6 +852,11 @@ impl<K: core::fmt::Debug> core::fmt::Display for InsertDescriptorError<K> {
816
852
"attempt to re-assign keychain {keychain:?} already assigned to {existing:?}"
817
853
)
818
854
}
855
+ InsertDescriptorError :: Miniscript ( err) => write ! ( f, "Miniscript error: {}" , err) ,
856
+ InsertDescriptorError :: HardenedDerivationXpub => write ! (
857
+ f,
858
+ "The descriptor contains hardened derivation steps on public extended keys"
859
+ ) ,
819
860
}
820
861
}
821
862
}
0 commit comments