diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index d66d7a8079..80caa0c336 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -828,15 +828,21 @@ impl Wallet { let txout_index = &mut self.indexed_graph.index; let (index, spk, changeset) = match address_index { AddressIndex::New => { - let ((index, spk), index_changeset) = txout_index.reveal_next_spk(&keychain); + let ((index, spk), index_changeset) = txout_index + .reveal_next_spk(&keychain) + .expect("Keychain exists (we called map_keychain)"); (index, spk.into(), Some(index_changeset)) } AddressIndex::LastUnused => { - let ((index, spk), index_changeset) = txout_index.next_unused_spk(&keychain); + let ((index, spk), index_changeset) = txout_index + .next_unused_spk(&keychain) + .expect("Keychain exists (we called map_keychain)"); (index, spk.into(), Some(index_changeset)) } AddressIndex::Peek(mut peek_index) => { - let mut spk_iter = txout_index.unbounded_spk_iter(&keychain); + let mut spk_iter = txout_index + .unbounded_spk_iter(&keychain) + .expect("Keychain exists (we called map_keychain)"); if !spk_iter.descriptor().has_wildcard() { peek_index = 0; } @@ -935,7 +941,10 @@ impl Wallet { keychain: KeychainKind, ) -> impl Iterator + Clone { let keychain = self.map_keychain(keychain); - self.indexed_graph.index.unbounded_spk_iter(&keychain) + self.indexed_graph + .index + .unbounded_spk_iter(&keychain) + .expect("Must exist (we called map_keychain)") } /// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the @@ -1569,8 +1578,11 @@ impl Wallet { Some(ref drain_recipient) => drain_recipient.clone(), None => { let change_keychain = self.map_keychain(KeychainKind::Internal); - let ((index, spk), index_changeset) = - self.indexed_graph.index.next_unused_spk(&change_keychain); + let ((index, spk), index_changeset) = self + .indexed_graph + .index + .next_unused_spk(&change_keychain) + .expect("Keychain exists (we called map_keychain)"); let spk = spk.into(); self.indexed_graph.index.mark_used(change_keychain, index); self.persist @@ -2042,7 +2054,12 @@ impl Wallet { /// The index of the next address that you would get if you were to ask the wallet for a new address pub fn next_derivation_index(&self, keychain: KeychainKind) -> u32 { - self.indexed_graph.index.next_index(&keychain).0 + let keychain = self.map_keychain(keychain); + self.indexed_graph + .index + .next_index(&keychain) + .expect("Keychain must exist (we called map_keychain)") + .0 } /// Informs the wallet that you no longer intend to broadcast a tx that was built from it. diff --git a/crates/chain/src/keychain/txout_index.rs b/crates/chain/src/keychain/txout_index.rs index 97fc437dcf..5c365f9194 100644 --- a/crates/chain/src/keychain/txout_index.rs +++ b/crates/chain/src/keychain/txout_index.rs @@ -204,7 +204,9 @@ impl Indexer for KeychainTxOutIndex { match self.inner.scan_txout(outpoint, txout).cloned() { Some((descriptor_id, index)) => { if let Some(keychain) = self.keychain_of_descriptor_id(&descriptor_id) { - self.reveal_to_target(&keychain.clone(), index).1 + self.reveal_to_target(&keychain.clone(), index) + .expect("We know keychain exists") + .1 } else { super::ChangeSet::default() } @@ -473,56 +475,52 @@ impl KeychainTxOutIndex { /// /// This does not change the `lookahead` setting. pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) { - let next_index = self.next_store_index(keychain); - if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) { - self.replenish_lookahead(keychain, temp_lookahead); + if let Some(next_index) = self.next_store_index(keychain) { + if let Some(temp_lookahead) = target_index.checked_sub(next_index).filter(|&v| v > 0) { + self.replenish_lookahead(keychain, temp_lookahead); + } } } fn replenish_lookahead(&mut self, keychain: &K, lookahead: u32) { - let (descriptor_id, descriptor) = self - .keychains_to_descriptors - .get(keychain) - .expect("keychain must exist") - .clone(); - let next_store_index = self.next_store_index(keychain); - let next_reveal_index = self.last_revealed.get(&descriptor_id).map_or(0, |v| *v + 1); - - for (new_index, new_spk) in SpkIterator::new_with_range( - descriptor.clone(), - next_store_index..next_reveal_index + lookahead, - ) { - let _inserted = self.inner.insert_spk((descriptor_id, new_index), new_spk); - debug_assert!(_inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_store_index={}, next_reveal_index={}", keychain, lookahead, next_store_index, next_reveal_index); + let descriptor_opt = self.keychains_to_descriptors.get(keychain).cloned(); + if let Some((descriptor_id, descriptor)) = descriptor_opt { + let next_store_index = self + .next_store_index(keychain) + .expect("We know keychain exists"); + let next_reveal_index = self.last_revealed.get(&descriptor_id).map_or(0, |v| *v + 1); + + for (new_index, new_spk) in SpkIterator::new_with_range( + descriptor.clone(), + next_store_index..next_reveal_index + lookahead, + ) { + let _inserted = self.inner.insert_spk((descriptor_id, new_index), new_spk); + debug_assert!(_inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_store_index={}, next_reveal_index={}", keychain, lookahead, next_store_index, next_reveal_index); + } } } - fn next_store_index(&self, keychain: &K) -> u32 { - let descriptor_id = self - .descriptor_of_keychain(keychain) - .expect("keychain must exist") - .0; - self.inner() - .all_spks() - // This range is filtering out the spks with a keychain different than - // `keychain`. We don't use filter here as range is more optimized. - .range((descriptor_id, u32::MIN)..(descriptor_id, u32::MAX)) - .last() - .map_or(0, |((_, index), _)| *index + 1) + fn next_store_index(&self, keychain: &K) -> Option { + let descriptor_id = self.descriptor_of_keychain(keychain)?.0; + Some( + self.inner() + .all_spks() + // This range is keeping only the spks with descriptor_id equal to + // `descriptor_id`. We don't use filter here as range is more optimized. + .range((descriptor_id, u32::MIN)..(descriptor_id, u32::MAX)) + .last() + .map_or(0, |((_, index), _)| *index + 1), + ) } - /// Get an unbounded spk iterator over a given `keychain`. - /// - /// # Panics - /// - /// This will panic if the given `keychain`'s descriptor does not exist. - pub fn unbounded_spk_iter(&self, keychain: &K) -> SpkIterator> { - let descriptor = self - .descriptor_of_keychain(keychain) - .expect("Keychain must exist") - .1 - .clone(); - SpkIterator::new(descriptor) + /// Get an unbounded spk iterator over a given `keychain`. Returns `None` if the provided + /// keychain doesn't exist + pub fn unbounded_spk_iter( + &self, + keychain: &K, + ) -> Option>> { + let descriptor = self.descriptor_of_keychain(keychain)?.1.clone(); + Some(SpkIterator::new(descriptor)) } /// Get unbounded spk iterators for all keychains. @@ -537,64 +535,55 @@ impl KeychainTxOutIndex { /// Iterate over revealed spks of all keychains. pub fn revealed_spks(&self) -> impl DoubleEndedIterator + Clone { - self.keychains_to_descriptors.keys().flat_map(|keychain| { - self.revealed_keychain_spks(keychain) - .map(|(i, spk)| (keychain.clone(), i, spk)) - }) + self.keychains_to_descriptors + .keys() + .filter_map(|keychain| { + self.revealed_keychain_spks(keychain) + .map(|spk_iter| spk_iter.map(|(i, spk)| (keychain.clone(), i, spk))) + }) + .flatten() } - /// Iterate over revealed spks of the given `keychain`. - /// - /// # Panics - /// - /// This will panic if the given `keychain`'s descriptor does not exist. + /// Iterate over revealed spks of the given `keychain`. Returns None if the provided `keychain` + /// doesn't exist. pub fn revealed_keychain_spks( &self, keychain: &K, - ) -> impl DoubleEndedIterator + Clone { - let desc_id = self - .keychains_to_descriptors - .get(keychain) - .expect("Must exist") - .0; + ) -> Option + Clone> { + let desc_id = self.keychains_to_descriptors.get(keychain)?.0; let next_i = self.last_revealed.get(&desc_id).map_or(0, |&i| i + 1); - self.inner - .all_spks() - .range((desc_id, u32::MIN)..(desc_id, next_i)) - .map(|((_, i), spk)| (*i, spk.as_script())) + Some( + self.inner + .all_spks() + .range((desc_id, u32::MIN)..(desc_id, next_i)) + .map(|((_, i), spk)| (*i, spk.as_script())), + ) } /// Iterate over revealed, but unused, spks of all keychains. pub fn unused_spks(&self) -> impl DoubleEndedIterator + Clone { - self.keychains_to_descriptors.keys().flat_map(|keychain| { - self.unused_keychain_spks(keychain) - .map(|(i, spk)| (keychain.clone(), i, spk)) - }) + self.keychains_to_descriptors + .keys() + .filter_map(|keychain| { + self.unused_keychain_spks(keychain) + .map(|spk_iter| spk_iter.map(|(i, spk)| (keychain.clone(), i, spk))) + }) + .flatten() } /// Iterate over revealed, but unused, spks of the given `keychain`. - /// - /// # Panics - /// - /// This will panic if the given `keychain`'s descriptor does not exist. + /// Returns None if the provided keychain doesn't exist. pub fn unused_keychain_spks( &self, keychain: &K, - ) -> impl DoubleEndedIterator + Clone { - let desc_id = self - .keychains_to_descriptors - .get(keychain) - .map(|(desc_id, _)| desc_id) - .cloned() - .unwrap_or( - sha256::Hash::from_byte_array([0; 32]) - //.to_byte_array() - .into(), - ); + ) -> Option + Clone> { + let desc_id = self.keychains_to_descriptors.get(keychain)?.0; let next_i = self.last_revealed.get(&desc_id).map_or(0, |&i| i + 1); - self.inner - .unused_spks((desc_id, u32::MIN)..(desc_id, next_i)) - .map(|((_, i), spk)| (*i, spk)) + Some( + self.inner + .unused_spks((desc_id, u32::MIN)..(desc_id, next_i)) + .map(|((_, i), spk)| (*i, spk)), + ) } /// Get the next derivation index for `keychain`. The next index is the index after the last revealed @@ -608,20 +597,15 @@ impl KeychainTxOutIndex { /// /// Not checking the second field of the tuple may result in address reuse. /// - /// # Panics - /// - /// Panics if the `keychain` does not exist. - pub fn next_index(&self, keychain: &K) -> (u32, bool) { - let (descriptor_id, descriptor) = self - .keychains_to_descriptors - .get(keychain) - .expect("must exist"); + /// Returns None if the provided `keychain` doesn't exist. + pub fn next_index(&self, keychain: &K) -> Option<(u32, bool)> { + let (descriptor_id, descriptor) = self.keychains_to_descriptors.get(keychain)?; let last_index = self.last_revealed.get(descriptor_id).cloned(); // we can only get the next index if the wildcard exists. let has_wildcard = descriptor.has_wildcard(); - match last_index { + Some(match last_index { // if there is no index, next_index is always 0. None => (0, true), // descriptors without wildcards can only have one index. @@ -633,7 +617,7 @@ impl KeychainTxOutIndex { Some(index) if index == BIP32_MAX_INDEX => (index, false), // get the next derivation index. Some(index) => (index + 1, true), - } + }) } /// Get the last derivation index that is revealed for each keychain. @@ -649,25 +633,14 @@ impl KeychainTxOutIndex { .collect() } - /// Get the last derivation index revealed for `keychain`. - /// - /// # Panics - /// - /// Panics if the `keychain` does not exist. + /// Get the last derivation index revealed for `keychain`. Returns None if the keychain doesn't + /// exist, or if the keychain doesn't have any revealed scripts. pub fn last_revealed_index(&self, keychain: &K) -> Option { - let descriptor_id = self - .keychains_to_descriptors - .get(keychain) - .expect("keychain must exist") - .0; + let descriptor_id = self.keychains_to_descriptors.get(keychain)?.0; self.last_revealed.get(&descriptor_id).cloned() } /// Convenience method to call [`Self::reveal_to_target`] on multiple keychains. - /// - /// # Panics - /// - /// Panics if any keychain in `keychains` does not exist. pub fn reveal_to_target_multi( &mut self, keychains: &BTreeMap, @@ -679,10 +652,11 @@ impl KeychainTxOutIndex { let mut spks = BTreeMap::new(); for (keychain, &index) in keychains { - let (new_spks, new_changeset) = self.reveal_to_target(keychain, index); - if !new_changeset.is_empty() { - spks.insert(keychain.clone(), new_spks); - changeset.append(new_changeset.clone()); + if let Some((new_spks, new_changeset)) = self.reveal_to_target(keychain, index) { + if !new_changeset.is_empty() { + spks.insert(keychain.clone(), new_spks); + changeset.append(new_changeset.clone()); + } } } @@ -700,21 +674,16 @@ impl KeychainTxOutIndex { /// [`super::ChangeSet`], which reports updates to the latest revealed index. If no new script /// pubkeys are revealed, then both of these will be empty. /// - /// # Panics - /// - /// Panics if `keychain` does not exist. + /// Returns None if the provided `keychain` doesn't exist. pub fn reveal_to_target( &mut self, keychain: &K, target_index: u32, - ) -> ( + ) -> Option<( SpkIterator>, super::ChangeSet, - ) { - let (descriptor_id, descriptor) = self - .keychains_to_descriptors - .get(keychain) - .expect("must exist"); + )> { + let (descriptor_id, descriptor) = self.keychains_to_descriptors.get(keychain)?; // Cloning since I need to modify self.inner, and I can't do that while // I'm borrowing descriptor_id and descriptor let (descriptor_id, descriptor) = (*descriptor_id, descriptor.clone()); @@ -726,14 +695,16 @@ impl KeychainTxOutIndex { .get(&descriptor_id) .map_or(0, |index| *index + 1); - debug_assert!(next_reveal_index + self.lookahead >= self.next_store_index(keychain)); + debug_assert!( + next_reveal_index + self.lookahead >= self.next_store_index(keychain).unwrap_or(0) + ); // If the target_index is already revealed, we are done if next_reveal_index > target_index { - return ( + return Some(( SpkIterator::new_with_range(descriptor, next_reveal_index..next_reveal_index), super::ChangeSet::default(), - ); + )); } // We range over the indexes that are not stored and insert their spks in the index. @@ -751,42 +722,41 @@ impl KeychainTxOutIndex { let _old_index = self.last_revealed.insert(descriptor_id, target_index); debug_assert!(_old_index < Some(target_index)); - ( + Some(( SpkIterator::new_with_range(descriptor, next_reveal_index..target_index + 1), super::ChangeSet { keychains_added: BTreeMap::new(), last_revealed: core::iter::once((descriptor_id, target_index)).collect(), }, - ) + )) } /// Attempts to reveal the next script pubkey for `keychain`. /// /// Returns the derivation index of the revealed script pubkey, the revealed script pubkey and a /// [`super::ChangeSet`] which represents changes in the last revealed index (if any). + /// Returns None if the provided keychain doesn't exist. /// /// When a new script cannot be revealed, we return the last revealed script and an empty /// [`super::ChangeSet`]. There are two scenarios when a new script pubkey cannot be derived: /// /// 1. The descriptor has no wildcard and already has one script revealed. /// 2. The descriptor has already revealed scripts up to the numeric bound. - /// - /// # Panics - /// - /// Panics if the `keychain` does not exist. - pub fn reveal_next_spk(&mut self, keychain: &K) -> ((u32, &Script), super::ChangeSet) { - let descriptor_id = self - .keychains_to_descriptors - .get(keychain) - .expect("Must exist") - .0; - let (next_index, _) = self.next_index(keychain); - let changeset = self.reveal_to_target(keychain, next_index).1; + pub fn reveal_next_spk( + &mut self, + keychain: &K, + ) -> Option<((u32, &Script), super::ChangeSet)> { + let descriptor_id = self.keychains_to_descriptors.get(keychain)?.0; + let (next_index, _) = self.next_index(keychain).expect("We know keychain exists"); + let changeset = self + .reveal_to_target(keychain, next_index) + .expect("We know keychain exists") + .1; let script = self .inner .spk_at_index(&(descriptor_id, next_index)) .expect("script must already be stored"); - ((next_index, script), changeset) + Some(((next_index, script), changeset)) } /// Gets the next unused script pubkey in the keychain. I.e., the script pubkey with the lowest @@ -798,56 +768,50 @@ impl KeychainTxOutIndex { /// has used all scripts up to the derivation bounds, then the last derived script pubkey will be /// returned. /// - /// # Panics - /// - /// Panics if `keychain` has never been added to the index - pub fn next_unused_spk(&mut self, keychain: &K) -> ((u32, &Script), super::ChangeSet) { - let need_new = self.unused_keychain_spks(keychain).next().is_none(); + /// Returns None if the provided keychain doesn't exist. + pub fn next_unused_spk( + &mut self, + keychain: &K, + ) -> Option<((u32, &Script), super::ChangeSet)> { + let need_new = self.unused_keychain_spks(keychain)?.next().is_none(); // this rather strange branch is needed because of some lifetime issues if need_new { self.reveal_next_spk(keychain) } else { - ( + Some(( self.unused_keychain_spks(keychain) + .expect("We already know keychain exists") .next() .expect("we already know next exists"), super::ChangeSet::default(), - ) + )) } } /// Iterate over all [`OutPoint`]s that point to `TxOut`s with script pubkeys derived from /// `keychain`. /// + /// Returns None if the provided keychain doesn't exist. + /// /// Use [`keychain_outpoints_in_range`](KeychainTxOutIndex::keychain_outpoints_in_range) to /// iterate over a specific derivation range. - /// - /// # Panics - /// - /// Panics if `keychain` has never been added to the index pub fn keychain_outpoints( &self, keychain: &K, - ) -> impl DoubleEndedIterator + '_ { + ) -> Option + '_> { self.keychain_outpoints_in_range(keychain, ..) } /// Iterate over [`OutPoint`]s that point to `TxOut`s with script pubkeys derived from /// `keychain` in a given derivation `range`. /// - /// # Panics - /// - /// Panics if `keychain` has never been added to the index + /// Returns None if the provided keychain doesn't exist. pub fn keychain_outpoints_in_range( &self, keychain: &K, range: impl RangeBounds, - ) -> impl DoubleEndedIterator + '_ { - let descriptor_id = self - .keychains_to_descriptors - .get(keychain) - .expect("Must exist") - .0; + ) -> Option + '_> { + let descriptor_id = self.keychains_to_descriptors.get(keychain)?.0; let start = match range.start_bound() { Bound::Included(i) => Bound::Included((descriptor_id, *i)), Bound::Excluded(i) => Bound::Excluded((descriptor_id, *i)), @@ -858,15 +822,17 @@ impl KeychainTxOutIndex { Bound::Excluded(i) => Bound::Excluded((descriptor_id, *i)), Bound::Unbounded => Bound::Unbounded, }; - self.inner - .outputs_in_range((start, end)) - .map(|((_, i), op)| (*i, op)) + Some( + self.inner + .outputs_in_range((start, end)) + .map(|((_, i), op)| (*i, op)), + ) } /// Returns the highest derivation index of the `keychain` where [`KeychainTxOutIndex`] has /// found a [`TxOut`] with it's script pubkey. pub fn last_used_index(&self, keychain: &K) -> Option { - self.keychain_outpoints(keychain).last().map(|(i, _)| i) + self.keychain_outpoints(keychain)?.last().map(|(i, _)| i) } /// Returns the highest derivation index of each keychain that [`KeychainTxOutIndex`] has found @@ -881,12 +847,12 @@ impl KeychainTxOutIndex { .collect() } - /// Applies the derivation changeset to the [`KeychainTxOutIndex`], extending the number of - /// derived scripts per keychain, as specified in the `changeset`. - /// - /// # Panics - /// - /// This will panic if a different `descriptor` is introduced to the same `keychain`. + /// Applies the derivation changeset to the [`KeychainTxOutIndex`], as specified in the + /// [`ChangeSet::append`] documentation: + /// - Extends the number of derived scripts per keychain + /// - Adds new descriptors introduced + /// - If a descriptor is introduced for a keychain that already had a descriptor, overwrites + /// the old descriptor pub fn apply_changeset(&mut self, changeset: super::ChangeSet) { let ChangeSet { keychains_added, diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index 4cff93094d..5117f60d93 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -148,14 +148,20 @@ fn test_list_owned_txouts() { { // we need to scope here to take immutanble reference of the graph for _ in 0..10 { - let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_1".to_string()); + let ((_, script), _) = graph + .index + .reveal_next_spk(&"keychain_1".to_string()) + .unwrap(); // TODO Assert indexes trusted_spks.push(script.to_owned()); } } { for _ in 0..10 { - let ((_, script), _) = graph.index.reveal_next_spk(&"keychain_2".to_string()); + let ((_, script), _) = graph + .index + .reveal_next_spk(&"keychain_2".to_string()) + .unwrap(); untrusted_spks.push(script.to_owned()); } } diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index ad0a43ef7b..93722e4137 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -188,8 +188,9 @@ fn test_lookahead() { // - scripts cached in spk_txout_index should increase correctly // - stored scripts of external keychain should be of expected counts for index in (0..20).skip_while(|i| i % 2 == 1) { - let (revealed_spks, revealed_changeset) = - txout_index.reveal_to_target(&TestKeychain::External, index); + let (revealed_spks, revealed_changeset) = txout_index + .reveal_to_target(&TestKeychain::External, index) + .unwrap(); assert_eq!( revealed_spks.collect::>(), vec![(index, spk_at_index(&external_descriptor, index))], @@ -208,24 +209,28 @@ fn test_lookahead() { assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::External) + .unwrap() .count(), index as usize + 1, ); assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::Internal) + .unwrap() .count(), 0, ); assert_eq!( txout_index .unused_keychain_spks(&TestKeychain::External) + .unwrap() .count(), index as usize + 1, ); assert_eq!( txout_index .unused_keychain_spks(&TestKeychain::Internal) + .unwrap() .count(), 0, ); @@ -238,8 +243,9 @@ fn test_lookahead() { // - derivation index is set ahead of current derivation index + lookahead // expect: // - scripts cached in spk_txout_index should increase correctly, a.k.a. no scripts are skipped - let (revealed_spks, revealed_changeset) = - txout_index.reveal_to_target(&TestKeychain::Internal, 24); + let (revealed_spks, revealed_changeset) = txout_index + .reveal_to_target(&TestKeychain::Internal, 24) + .unwrap(); assert_eq!( revealed_spks.collect::>(), (0..=24) @@ -260,6 +266,7 @@ fn test_lookahead() { assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::Internal) + .unwrap() .count(), 25, ); @@ -312,12 +319,14 @@ fn test_lookahead() { assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::External) + .unwrap() .count(), last_external_index as usize + 1, ); assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::Internal) + .unwrap() .count(), last_internal_index as usize + 1, ); @@ -401,11 +410,11 @@ fn test_wildcard_derivations() { // - next_derivation_index() == (0, true) // - derive_new() == ((0, ), keychain::ChangeSet) // - next_unused() == ((0, ), keychain::ChangeSet:is_empty()) - assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true)); - let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); + assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (0, true)); + let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap(); assert_eq!(spk, (0_u32, external_spk_0.as_script())); assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 0)].into()); - let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); + let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap(); assert_eq!(spk, (0_u32, external_spk_0.as_script())); assert_eq!(&changeset.last_revealed, &[].into()); @@ -423,14 +432,14 @@ fn test_wildcard_derivations() { .chain([17, 20, 23]) .for_each(|index| assert!(txout_index.mark_used(TestKeychain::External, index))); - assert_eq!(txout_index.next_index(&TestKeychain::External), (26, true)); + assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (26, true)); - let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); + let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap(); assert_eq!(spk, (26, external_spk_26.as_script())); assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 26)].into()); - let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); + let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap(); assert_eq!(spk, (16, external_spk_16.as_script())); assert_eq!(&changeset.last_revealed, &[].into()); @@ -440,7 +449,7 @@ fn test_wildcard_derivations() { txout_index.mark_used(TestKeychain::External, index); }); - let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); + let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap(); assert_eq!(spk, (27, external_spk_27.as_script())); assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 27)].into()); } @@ -465,15 +474,22 @@ fn test_non_wildcard_derivations() { // - next derivation index should be new // - when we derive a new script, script @ index 0 // - when we get the next unused script, script @ index 0 - assert_eq!(txout_index.next_index(&TestKeychain::External), (0, true)); - let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); + assert_eq!( + txout_index.next_index(&TestKeychain::External).unwrap(), + (0, true) + ); + let (spk, changeset) = txout_index + .reveal_next_spk(&TestKeychain::External) + .unwrap(); assert_eq!(spk, (0, external_spk.as_script())); assert_eq!( &changeset.last_revealed, &[(no_wildcard_descriptor.descriptor_id(), 0)].into() ); - let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); + let (spk, changeset) = txout_index + .next_unused_spk(&TestKeychain::External) + .unwrap(); assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(&changeset.last_revealed, &[].into()); @@ -483,18 +499,26 @@ fn test_non_wildcard_derivations() { // - next derivation index should not be new // - derive new and next unused should return the old script // - store_up_to should not panic and return empty changeset - assert_eq!(txout_index.next_index(&TestKeychain::External), (0, false)); + assert_eq!( + txout_index.next_index(&TestKeychain::External).unwrap(), + (0, false) + ); txout_index.mark_used(TestKeychain::External, 0); - let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External); + let (spk, changeset) = txout_index + .reveal_next_spk(&TestKeychain::External) + .unwrap(); assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(&changeset.last_revealed, &[].into()); - let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External); + let (spk, changeset) = txout_index + .next_unused_spk(&TestKeychain::External) + .unwrap(); assert_eq!(spk, (0, external_spk.as_script())); assert_eq!(&changeset.last_revealed, &[].into()); - let (revealed_spks, revealed_changeset) = - txout_index.reveal_to_target(&TestKeychain::External, 200); + let (revealed_spks, revealed_changeset) = txout_index + .reveal_to_target(&TestKeychain::External, 200) + .unwrap(); assert_eq!(revealed_spks.count(), 0); assert!(revealed_changeset.is_empty()); @@ -502,6 +526,7 @@ fn test_non_wildcard_derivations() { assert_eq!( txout_index .revealed_keychain_spks(&TestKeychain::External) + .unwrap() .count(), 1, ); diff --git a/example-crates/example_cli/src/lib.rs b/example-crates/example_cli/src/lib.rs index 8ea2000467..1bc2b6afa6 100644 --- a/example-crates/example_cli/src/lib.rs +++ b/example-crates/example_cli/src/lib.rs @@ -257,8 +257,10 @@ where Keychain::External }; - let ((change_index, change_script), change_changeset) = - graph.index.next_unused_spk(&internal_keychain); + let ((change_index, change_script), change_changeset) = graph + .index + .next_unused_spk(&internal_keychain) + .expect("Must exist"); changeset.append(change_changeset); // Clone to drop the immutable reference. @@ -470,7 +472,8 @@ where _ => unreachable!("only these two variants exist in match arm"), }; - let ((spk_i, spk), index_changeset) = spk_chooser(index, &Keychain::External); + let ((spk_i, spk), index_changeset) = + spk_chooser(index, &Keychain::External).expect("Must exist"); let db = &mut *db.lock().unwrap(); db.stage_and_commit(C::from(( local_chain::ChangeSet::default(), @@ -492,7 +495,10 @@ where true => Keychain::Internal, false => Keychain::External, }; - for (spk_i, spk) in index.revealed_keychain_spks(&target_keychain) { + for (spk_i, spk) in index + .revealed_keychain_spks(&target_keychain) + .expect("Must exist") + { let address = Address::from_script(spk, network) .expect("should always be able to derive address"); println!(