Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(chain)!: Update KeychainTxOutIndex methods to use owned K and ScriptBuf #1506

Merged
merged 2 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 50 additions & 50 deletions crates/chain/src/indexer/keychain_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{
DescriptorExt, DescriptorId, Indexed, Indexer, KeychainIndexed, SpkIterator,
};
use alloc::{borrow::ToOwned, vec::Vec};
use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
use core::{
fmt::Debug,
ops::{Bound, RangeBounds},
Expand Down Expand Up @@ -99,7 +99,7 @@ pub const DEFAULT_LOOKAHEAD: u32 = 25;
/// let _ = txout_index.insert_descriptor(MyKeychain::Internal, internal_descriptor)?;
/// let _ = txout_index.insert_descriptor(MyKeychain::MyAppUser { user_id: 42 }, descriptor_42)?;
///
/// let new_spk_for_user = txout_index.reveal_next_spk(&MyKeychain::MyAppUser{ user_id: 42 });
/// let new_spk_for_user = txout_index.reveal_next_spk(MyKeychain::MyAppUser{ user_id: 42 });
/// # Ok::<_, bdk_chain::indexer::keychain_txout::InsertDescriptorError<_>>(())
/// ```
///
Expand Down Expand Up @@ -251,14 +251,14 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// Return the script that exists under the given `keychain`'s `index`.
///
/// This calls [`SpkTxOutIndex::spk_at_index`] internally.
pub fn spk_at_index(&self, keychain: K, index: u32) -> Option<&Script> {
pub fn spk_at_index(&self, keychain: K, index: u32) -> Option<ScriptBuf> {
self.inner.spk_at_index(&(keychain.clone(), index))
}

/// Returns the keychain and keychain index associated with the spk.
///
/// This calls [`SpkTxOutIndex::index_of_spk`] internally.
pub fn index_of_spk(&self, script: &Script) -> Option<&(K, u32)> {
pub fn index_of_spk(&self, script: ScriptBuf) -> Option<&(K, u32)> {
self.inner.index_of_spk(script)
}

Expand Down Expand Up @@ -335,11 +335,11 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// Return all keychains and their corresponding descriptors.
pub fn keychains(
&self,
) -> impl DoubleEndedIterator<Item = (&K, &Descriptor<DescriptorPublicKey>)> + ExactSizeIterator + '_
) -> impl DoubleEndedIterator<Item = (K, &Descriptor<DescriptorPublicKey>)> + ExactSizeIterator + '_
{
self.keychain_to_descriptor_id
.iter()
.map(|(k, did)| (k, self.descriptors.get(did).expect("invariant")))
.map(|(k, did)| (k.clone(), self.descriptors.get(did).expect("invariant")))
}

/// Insert a descriptor with a keychain associated to it.
Expand Down Expand Up @@ -399,8 +399,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {

/// Gets the descriptor associated with the keychain. Returns `None` if the keychain doesn't
/// have a descriptor associated with it.
pub fn get_descriptor(&self, keychain: &K) -> Option<&Descriptor<DescriptorPublicKey>> {
let did = self.keychain_to_descriptor_id.get(keychain)?;
pub fn get_descriptor(&self, keychain: K) -> Option<&Descriptor<DescriptorPublicKey>> {
let did = self.keychain_to_descriptor_id.get(&keychain)?;
self.descriptors.get(did)
}

Expand All @@ -416,8 +416,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// Store lookahead scripts until `target_index` (inclusive).
///
/// This does not change the global `lookahead` setting.
pub fn lookahead_to_target(&mut self, keychain: &K, target_index: u32) {
if let Some((next_index, _)) = self.next_index(keychain) {
pub fn lookahead_to_target(&mut self, keychain: K, target_index: u32) {
if let Some((next_index, _)) = self.next_index(keychain.clone()) {
let temp_lookahead = (target_index + 1)
.checked_sub(next_index)
.filter(|&index| index > 0);
Expand All @@ -434,9 +434,9 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
}
}

fn replenish_inner_index_keychain(&mut self, keychain: &K, lookahead: u32) {
if let Some(did) = self.keychain_to_descriptor_id.get(keychain) {
self.replenish_inner_index(*did, keychain, lookahead);
fn replenish_inner_index_keychain(&mut self, keychain: K, lookahead: u32) {
if let Some(did) = self.keychain_to_descriptor_id.get(&keychain) {
self.replenish_inner_index(*did, &keychain, lookahead);
}
}

Expand Down Expand Up @@ -464,7 +464,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// keychain doesn't exist
pub fn unbounded_spk_iter(
&self,
keychain: &K,
keychain: K,
) -> Option<SpkIterator<Descriptor<DescriptorPublicKey>>> {
let descriptor = self.get_descriptor(keychain)?.clone();
Some(SpkIterator::new(descriptor))
Expand All @@ -489,7 +489,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
pub fn revealed_spks(
&self,
range: impl RangeBounds<K>,
) -> impl Iterator<Item = KeychainIndexed<K, &Script>> {
) -> impl Iterator<Item = KeychainIndexed<K, ScriptBuf>> + '_ {
let start = range.start_bound();
let end = range.end_bound();
let mut iter_last_revealed = self
Expand All @@ -516,7 +516,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
let (current_keychain, last_revealed) = current_keychain?;

if current_keychain == keychain && Some(*index) <= last_revealed {
break Some(((keychain.clone(), *index), spk.as_script()));
break Some(((keychain.clone(), *index), spk.clone()));
}
})
}
Expand All @@ -525,37 +525,37 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
///
/// This is a double ended iterator so you can easily reverse it to get an iterator where
/// the script pubkeys that were most recently revealed are first.
pub fn revealed_keychain_spks<'a>(
&'a self,
keychain: &'a K,
) -> impl DoubleEndedIterator<Item = Indexed<&Script>> + 'a {
pub fn revealed_keychain_spks(
&self,
keychain: K,
) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + '_ {
let end = self
.last_revealed_index(keychain)
.last_revealed_index(keychain.clone())
.map(|v| v + 1)
.unwrap_or(0);
self.inner
.all_spks()
.range((keychain.clone(), 0)..(keychain.clone(), end))
.map(|((_, index), spk)| (*index, spk.as_script()))
.map(|((_, index), spk)| (*index, spk.clone()))
}

/// Iterate over revealed, but unused, spks of all keychains.
pub fn unused_spks(
&self,
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, &Script>> + Clone {
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, ScriptBuf>> + Clone + '_ {
self.keychain_to_descriptor_id.keys().flat_map(|keychain| {
self.unused_keychain_spks(keychain)
.map(|(i, spk)| ((keychain.clone(), i), spk))
self.unused_keychain_spks(keychain.clone())
.map(|(i, spk)| ((keychain.clone(), i), spk.clone()))
})
}

/// Iterate over revealed, but unused, spks of the given `keychain`.
/// Returns an empty iterator if the provided keychain doesn't exist.
pub fn unused_keychain_spks(
&self,
keychain: &K,
) -> impl DoubleEndedIterator<Item = Indexed<&Script>> + Clone {
let end = match self.keychain_to_descriptor_id.get(keychain) {
keychain: K,
) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + Clone + '_ {
let end = match self.keychain_to_descriptor_id.get(&keychain) {
Some(did) => self.last_revealed.get(did).map(|v| *v + 1).unwrap_or(0),
None => 0,
};
Expand All @@ -577,8 +577,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// Not checking the second field of the tuple may result in address reuse.
///
/// Returns None if the provided `keychain` doesn't exist.
pub fn next_index(&self, keychain: &K) -> Option<(u32, bool)> {
let did = self.keychain_to_descriptor_id.get(keychain)?;
pub fn next_index(&self, keychain: K) -> Option<(u32, bool)> {
let did = self.keychain_to_descriptor_id.get(&keychain)?;
let last_index = self.last_revealed.get(did).cloned();
let descriptor = self.descriptors.get(did).expect("invariant");

Expand Down Expand Up @@ -615,8 +615,8 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {

/// 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<u32> {
let descriptor_id = self.keychain_to_descriptor_id.get(keychain)?;
pub fn last_revealed_index(&self, keychain: K) -> Option<u32> {
let descriptor_id = self.keychain_to_descriptor_id.get(&keychain)?;
self.last_revealed.get(descriptor_id).cloned()
}

Expand All @@ -625,7 +625,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
let mut changeset = ChangeSet::default();

for (keychain, &index) in keychains {
if let Some((_, new_changeset)) = self.reveal_to_target(keychain, index) {
if let Some((_, new_changeset)) = self.reveal_to_target(keychain.clone(), index) {
changeset.merge(new_changeset);
}
}
Expand All @@ -648,16 +648,16 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
#[must_use]
pub fn reveal_to_target(
&mut self,
keychain: &K,
keychain: K,
target_index: u32,
) -> Option<(Vec<Indexed<ScriptBuf>>, ChangeSet)> {
let mut changeset = ChangeSet::default();
let mut spks: Vec<Indexed<ScriptBuf>> = vec![];
while let Some((i, new)) = self.next_index(keychain) {
while let Some((i, new)) = self.next_index(keychain.clone()) {
if !new || i > target_index {
break;
}
match self.reveal_next_spk(keychain) {
match self.reveal_next_spk(keychain.clone()) {
Some(((i, spk), change)) => {
spks.push((i, spk));
changeset.merge(change);
Expand All @@ -681,21 +681,21 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// 1. The descriptor has no wildcard and already has one script revealed.
/// 2. The descriptor has already revealed scripts up to the numeric bound.
/// 3. There is no descriptor associated with the given keychain.
pub fn reveal_next_spk(&mut self, keychain: &K) -> Option<(Indexed<ScriptBuf>, ChangeSet)> {
let (next_index, new) = self.next_index(keychain)?;
pub fn reveal_next_spk(&mut self, keychain: K) -> Option<(Indexed<ScriptBuf>, ChangeSet)> {
let (next_index, new) = self.next_index(keychain.clone())?;
let mut changeset = ChangeSet::default();

if new {
let did = self.keychain_to_descriptor_id.get(keychain)?;
let did = self.keychain_to_descriptor_id.get(&keychain)?;
self.last_revealed.insert(*did, next_index);
changeset.last_revealed.insert(*did, next_index);
self.replenish_inner_index(*did, keychain, self.lookahead);
self.replenish_inner_index(*did, &keychain, self.lookahead);
}
let script = self
.inner
.spk_at_index(&(keychain.clone(), next_index))
.expect("we just inserted it");
Some(((next_index, script.into()), changeset))
Some(((next_index, script), changeset))
}

/// Gets the next unused script pubkey in the keychain. I.e., the script pubkey with the lowest
Expand All @@ -711,9 +711,9 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
/// could be revealed (see [`reveal_next_spk`] for when this happens).
///
/// [`reveal_next_spk`]: Self::reveal_next_spk
pub fn next_unused_spk(&mut self, keychain: &K) -> Option<(Indexed<ScriptBuf>, ChangeSet)> {
pub fn next_unused_spk(&mut self, keychain: K) -> Option<(Indexed<ScriptBuf>, ChangeSet)> {
let next_unused = self
.unused_keychain_spks(keychain)
.unused_keychain_spks(keychain.clone())
.next()
.map(|(i, spk)| ((i, spk.to_owned()), ChangeSet::default()));

Expand All @@ -722,11 +722,11 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {

/// Iterate over all [`OutPoint`]s that have `TxOut`s with script pubkeys derived from
/// `keychain`.
pub fn keychain_outpoints<'a>(
&'a self,
keychain: &'a K,
) -> impl DoubleEndedIterator<Item = Indexed<OutPoint>> + 'a {
self.keychain_outpoints_in_range(keychain..=keychain)
pub fn keychain_outpoints(
&self,
keychain: K,
) -> impl DoubleEndedIterator<Item = Indexed<OutPoint>> + '_ {
self.keychain_outpoints_in_range(keychain.clone()..=keychain)
.map(|((_, i), op)| (i, op))
}

Expand Down Expand Up @@ -757,7 +757,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {

/// 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<u32> {
pub fn last_used_index(&self, keychain: K) -> Option<u32> {
self.keychain_outpoints(keychain).last().map(|(i, _)| i)
}

Expand All @@ -767,7 +767,7 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
self.keychain_to_descriptor_id
.iter()
.filter_map(|(keychain, _)| {
self.last_used_index(keychain)
self.last_used_index(keychain.clone())
.map(|index| (keychain.clone(), index))
})
.collect()
Expand Down
17 changes: 10 additions & 7 deletions crates/chain/src/indexer/spk_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
Indexer,
};
use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};

/// An index storing [`TxOut`]s that have a script pubkey that matches those in a list.
///
Expand Down Expand Up @@ -176,8 +176,8 @@ impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
/// Returns the script that has been inserted at the `index`.
///
/// If that index hasn't been inserted yet, it will return `None`.
pub fn spk_at_index(&self, index: &I) -> Option<&Script> {
self.spks.get(index).map(|s| s.as_script())
pub fn spk_at_index(&self, index: &I) -> Option<ScriptBuf> {
self.spks.get(index).cloned()
}

/// The script pubkeys that are being tracked by the index.
Expand Down Expand Up @@ -217,7 +217,10 @@ impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
/// let unused_change_spks =
/// txout_index.unused_spks((change_index, u32::MIN)..(change_index, u32::MAX));
/// ```
pub fn unused_spks<R>(&self, range: R) -> impl DoubleEndedIterator<Item = (&I, &Script)> + Clone
pub fn unused_spks<R>(
&self,
range: R,
) -> impl DoubleEndedIterator<Item = (&I, ScriptBuf)> + Clone + '_
where
R: RangeBounds<I>,
{
Expand Down Expand Up @@ -268,8 +271,8 @@ impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
}

/// Returns the index associated with the script pubkey.
pub fn index_of_spk(&self, script: &Script) -> Option<&I> {
self.spk_indices.get(script)
pub fn index_of_spk(&self, script: ScriptBuf) -> Option<&I> {
self.spk_indices.get(script.as_script())
}

/// Computes the total value transfer effect `tx` has on the script pubkeys in `range`. Value is
Expand All @@ -293,7 +296,7 @@ impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
}
}
for txout in &tx.output {
if let Some(index) = self.index_of_spk(&txout.script_pubkey) {
if let Some(index) = self.index_of_spk(txout.script_pubkey.clone()) {
if range.contains(index) {
received += txout.value;
}
Expand Down
8 changes: 4 additions & 4 deletions crates/chain/src/tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ use crate::{
use alloc::collections::vec_deque::VecDeque;
use alloc::sync::Arc;
use alloc::vec::Vec;
use bitcoin::{Amount, OutPoint, Script, SignedAmount, Transaction, TxOut, Txid};
use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
use core::fmt::{self, Formatter};
use core::{
convert::Infallible,
Expand Down Expand Up @@ -1163,7 +1163,7 @@ impl<A: Anchor> TxGraph<A> {
chain: &C,
chain_tip: BlockId,
outpoints: impl IntoIterator<Item = (OI, OutPoint)>,
mut trust_predicate: impl FnMut(&OI, &Script) -> bool,
mut trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool,
) -> Result<Balance, C::Error> {
let mut immature = Amount::ZERO;
let mut trusted_pending = Amount::ZERO;
Expand All @@ -1182,7 +1182,7 @@ impl<A: Anchor> TxGraph<A> {
}
}
ChainPosition::Unconfirmed(_) => {
if trust_predicate(&spk_i, &txout.txout.script_pubkey) {
if trust_predicate(&spk_i, txout.txout.script_pubkey) {
trusted_pending += txout.txout.value;
} else {
untrusted_pending += txout.txout.value;
Expand All @@ -1209,7 +1209,7 @@ impl<A: Anchor> TxGraph<A> {
chain: &C,
chain_tip: BlockId,
outpoints: impl IntoIterator<Item = (OI, OutPoint)>,
trust_predicate: impl FnMut(&OI, &Script) -> bool,
trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool,
) -> Balance {
self.try_balance(chain, chain_tip, outpoints, trust_predicate)
.expect("oracle is infallible")
Expand Down
2 changes: 1 addition & 1 deletion crates/chain/tests/common/tx_template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub fn init_graph<'a, A: Anchor + Clone + 'a>(
},
Some(index) => TxOut {
value: Amount::from_sat(output.value),
script_pubkey: spk_index.spk_at_index(index).unwrap().to_owned(),
script_pubkey: spk_index.spk_at_index(index).unwrap(),
},
})
.collect(),
Expand Down
Loading
Loading