2024-06-28 09:07:36 -04:00
//! [`KeychainTxOutIndex`] controls how script pubkeys are revealed for multiple keychains and
//! indexes [`TxOut`]s with them.
2023-03-01 11:09:08 +01:00
use crate ::{
collections ::* ,
miniscript ::{ Descriptor , DescriptorPublicKey } ,
2023-03-22 17:00:08 +08:00
spk_iter ::BIP32_MAX_INDEX ,
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
spk_txout ::SpkTxOutIndex ,
DescriptorExt , DescriptorId , Indexed , Indexer , KeychainIndexed , SpkIterator ,
2023-03-01 11:09:08 +01:00
} ;
2024-06-06 10:17:55 +10:00
use alloc ::{ borrow ::ToOwned , vec ::Vec } ;
2024-06-28 09:07:36 -04:00
use bitcoin ::{ Amount , OutPoint , Script , ScriptBuf , SignedAmount , Transaction , TxOut , Txid } ;
2024-01-18 14:30:29 +08:00
use core ::{
fmt ::Debug ,
ops ::{ Bound , RangeBounds } ,
} ;
2023-03-01 11:09:08 +01:00
2024-07-04 22:09:04 +08:00
use crate ::Merge ;
2023-04-05 17:29:20 +08:00
2024-06-06 13:12:38 +10:00
/// The default lookahead for a [`KeychainTxOutIndex`]
pub const DEFAULT_LOOKAHEAD : u32 = 25 ;
2023-11-28 18:08:49 +01:00
2024-01-17 13:30:28 +08:00
/// [`KeychainTxOutIndex`] controls how script pubkeys are revealed for multiple keychains, and
/// indexes [`TxOut`]s with them.
2023-03-01 11:09:08 +01:00
///
2024-01-17 13:30:28 +08:00
/// A single keychain is a chain of script pubkeys derived from a single [`Descriptor`]. Keychains
/// are identified using the `K` generic. Script pubkeys are identified by the keychain that they
/// are derived from `K`, as well as the derivation index `u32`.
2023-03-01 11:09:08 +01:00
///
2024-06-07 16:08:59 +10:00
/// There is a strict 1-to-1 relationship between descriptors and keychains. Each keychain has one
/// and only one descriptor and each descriptor has one and only one keychain. The
2024-06-11 14:29:26 +10:00
/// [`insert_descriptor`] method will return an error if you try and violate this invariant. This
/// rule is a proxy for a stronger rule: no two descriptors should produce the same script pubkey.
2024-06-12 21:50:03 +08:00
/// Having two descriptors produce the same script pubkey should cause whichever keychain derives
/// the script pubkey first to be the effective owner of it but you should not rely on this
/// behaviour. ⚠ It is up you, the developer, not to violate this invariant.
2024-06-07 16:08:59 +10:00
///
2024-01-17 13:30:28 +08:00
/// # Revealed script pubkeys
2023-03-01 11:09:08 +01:00
///
2024-01-17 13:30:28 +08:00
/// Tracking how script pubkeys are revealed is useful for collecting chain data. For example, if
/// the user has requested 5 script pubkeys (to receive money with), we only need to use those
/// script pubkeys to scan for chain data.
///
/// Call [`reveal_to_target`] or [`reveal_next_spk`] to reveal more script pubkeys.
/// Call [`revealed_keychain_spks`] or [`revealed_spks`] to iterate through revealed script pubkeys.
///
/// # Lookahead script pubkeys
///
/// When an user first recovers a wallet (i.e. from a recovery phrase and/or descriptor), we will
/// NOT have knowledge of which script pubkeys are revealed. So when we index a transaction or
/// txout (using [`index_tx`]/[`index_txout`]) we scan the txouts against script pubkeys derived
/// above the last revealed index. These additionally-derived script pubkeys are called the
/// lookahead.
///
2024-06-06 13:12:38 +10:00
/// The [`KeychainTxOutIndex`] is constructed with the `lookahead` and cannot be altered. See
/// [`DEFAULT_LOOKAHEAD`] for the value used in the `Default` implementation. Use [`new`] to set a
/// custom `lookahead`.
2024-01-17 13:30:28 +08:00
///
/// # Unbounded script pubkey iterator
///
/// For script-pubkey-based chain sources (such as Electrum/Esplora), an initial scan is best done
/// by iterating though derived script pubkeys one by one and requesting transaction histories for
/// each script pubkey. We will stop after x-number of script pubkeys have empty histories. An
2024-06-06 13:12:38 +10:00
/// unbounded script pubkey iterator is useful to pass to such a chain source because it doesn't
/// require holding a reference to the index.
2024-01-17 13:30:28 +08:00
///
/// Call [`unbounded_spk_iter`] to get an unbounded script pubkey iterator for a given keychain.
/// Call [`all_unbounded_spk_iters`] to get unbounded script pubkey iterators for all keychains.
///
/// # Change sets
///
2024-06-06 10:17:55 +10:00
/// Methods that can update the last revealed index or add keychains will return [`ChangeSet`] to report
2024-06-07 12:29:58 +10:00
/// these changes. This should be persisted for future recovery.
2023-03-01 11:09:08 +01:00
///
/// ## Synopsis
///
/// ```
2024-06-28 09:07:36 -04:00
/// use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
2023-03-01 11:09:08 +01:00
/// # use bdk_chain::{ miniscript::{Descriptor, DescriptorPublicKey} };
/// # use core::str::FromStr;
///
/// // imagine our service has internal and external addresses but also addresses for users
/// #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
/// enum MyKeychain {
/// External,
/// Internal,
/// MyAppUser {
/// user_id: u32
/// }
/// }
///
/// let mut txout_index = KeychainTxOutIndex::<MyKeychain>::default();
///
/// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
/// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
/// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
2024-01-15 18:52:03 +01:00
/// # let (descriptor_42, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/2/*)").unwrap();
2024-06-06 13:12:38 +10:00
/// let _ = txout_index.insert_descriptor(MyKeychain::External, external_descriptor)?;
/// let _ = txout_index.insert_descriptor(MyKeychain::Internal, internal_descriptor)?;
/// let _ = txout_index.insert_descriptor(MyKeychain::MyAppUser { user_id: 42 }, descriptor_42)?;
2023-03-01 11:09:08 +01:00
///
/// let new_spk_for_user = txout_index.reveal_next_spk(&MyKeychain::MyAppUser{ user_id: 42 });
2024-06-28 09:07:36 -04:00
/// # Ok::<_, bdk_chain::indexer::keychain_txout::InsertDescriptorError<_>>(())
2023-03-01 11:09:08 +01:00
/// ```
///
/// [`Ord`]: core::cmp::Ord
/// [`SpkTxOutIndex`]: crate::spk_txout_index::SpkTxOutIndex
/// [`Descriptor`]: crate::miniscript::Descriptor
2024-06-07 16:08:59 +10:00
/// [`reveal_to_target`]: Self::reveal_to_target
/// [`reveal_next_spk`]: Self::reveal_next_spk
/// [`revealed_keychain_spks`]: Self::revealed_keychain_spks
/// [`revealed_spks`]: Self::revealed_spks
/// [`index_tx`]: Self::index_tx
/// [`index_txout`]: Self::index_txout
/// [`new`]: Self::new
/// [`unbounded_spk_iter`]: Self::unbounded_spk_iter
/// [`all_unbounded_spk_iters`]: Self::all_unbounded_spk_iters
/// [`outpoints`]: Self::outpoints
/// [`txouts`]: Self::txouts
/// [`unused_spks`]: Self::unused_spks
/// [`insert_descriptor`]: Self::insert_descriptor
2023-03-01 11:09:08 +01:00
#[ derive(Clone, Debug) ]
pub struct KeychainTxOutIndex < K > {
2024-06-06 10:17:55 +10:00
inner : SpkTxOutIndex < ( K , u32 ) > ,
2024-06-12 22:19:54 +08:00
keychain_to_descriptor_id : BTreeMap < K , DescriptorId > ,
descriptor_id_to_keychain : HashMap < DescriptorId , K > ,
descriptors : HashMap < DescriptorId , Descriptor < DescriptorPublicKey > > ,
2024-06-06 10:17:55 +10:00
last_revealed : HashMap < DescriptorId , u32 > ,
2023-11-28 18:08:49 +01:00
lookahead : u32 ,
2023-03-01 11:09:08 +01:00
}
impl < K > Default for KeychainTxOutIndex < K > {
fn default ( ) -> Self {
2023-11-28 18:08:49 +01:00
Self ::new ( DEFAULT_LOOKAHEAD )
2023-03-01 11:09:08 +01:00
}
}
2023-05-03 15:20:49 +08:00
impl < K : Clone + Ord + Debug > Indexer for KeychainTxOutIndex < K > {
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
type ChangeSet = ChangeSet ;
2023-03-24 15:47:39 +08:00
2023-08-07 17:43:17 +02:00
fn index_txout ( & mut self , outpoint : OutPoint , txout : & TxOut ) -> Self ::ChangeSet {
2024-06-06 10:17:55 +10:00
let mut changeset = ChangeSet ::default ( ) ;
2024-06-11 11:48:32 +10:00
if let Some ( ( keychain , index ) ) = self . inner . scan_txout ( outpoint , txout ) . cloned ( ) {
2024-06-06 10:17:55 +10:00
let did = self
2024-06-12 22:19:54 +08:00
. keychain_to_descriptor_id
2024-06-11 11:48:32 +10:00
. get ( & keychain )
2024-06-06 10:17:55 +10:00
. expect ( " invariant " ) ;
2024-06-11 11:48:32 +10:00
if self . last_revealed . get ( did ) < Some ( & index ) {
self . last_revealed . insert ( * did , index ) ;
changeset . last_revealed . insert ( * did , index ) ;
2024-06-11 14:55:06 +10:00
self . replenish_inner_index ( * did , & keychain , self . lookahead ) ;
2024-01-15 18:52:03 +01:00
}
2023-08-25 12:52:09 +03:00
}
2024-06-06 10:17:55 +10:00
changeset
2023-03-24 15:47:39 +08:00
}
2023-08-07 17:43:17 +02:00
fn index_tx ( & mut self , tx : & bitcoin ::Transaction ) -> Self ::ChangeSet {
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
let mut changeset = ChangeSet ::default ( ) ;
2024-06-13 22:56:19 +08:00
let txid = tx . compute_txid ( ) ;
2023-08-25 12:52:09 +03:00
for ( op , txout ) in tx . output . iter ( ) . enumerate ( ) {
2024-07-04 22:09:04 +08:00
changeset . merge ( self . index_txout ( OutPoint ::new ( txid , op as u32 ) , txout ) ) ;
2023-08-25 12:52:09 +03:00
}
changeset
2023-03-24 15:47:39 +08:00
}
2023-08-16 17:39:35 +02:00
fn initial_changeset ( & self ) -> Self ::ChangeSet {
2024-06-06 10:17:55 +10:00
ChangeSet {
last_revealed : self . last_revealed . clone ( ) . into_iter ( ) . collect ( ) ,
2024-01-15 18:52:03 +01:00
}
2023-08-16 17:39:35 +02:00
}
2023-08-07 17:43:17 +02:00
fn apply_changeset ( & mut self , changeset : Self ::ChangeSet ) {
self . apply_changeset ( changeset )
2023-03-27 15:36:37 +08:00
}
2023-04-05 18:17:08 +08:00
fn is_tx_relevant ( & self , tx : & bitcoin ::Transaction ) -> bool {
2024-01-13 20:04:49 +08:00
self . inner . is_relevant ( tx )
2023-03-26 11:24:30 +08:00
}
2023-03-24 15:47:39 +08:00
}
2023-11-28 18:08:49 +01:00
impl < K > KeychainTxOutIndex < K > {
/// Construct a [`KeychainTxOutIndex`] with the given `lookahead`.
///
2023-12-29 16:40:48 +11:00
/// The `lookahead` is the number of script pubkeys to derive and cache from the internal
/// descriptors over and above the last revealed script index. Without a lookahead the index
/// will miss outputs you own when processing transactions whose output script pubkeys lie
/// beyond the last revealed index. In certain situations, such as when performing an initial
/// scan of the blockchain during wallet import, it may be uncertain or unknown what the index
/// of the last revealed script pubkey actually is.
2024-01-17 13:30:28 +08:00
///
/// Refer to [struct-level docs](KeychainTxOutIndex) for more about `lookahead`.
2023-11-28 18:08:49 +01:00
pub fn new ( lookahead : u32 ) -> Self {
Self {
inner : SpkTxOutIndex ::default ( ) ,
2024-06-12 22:19:54 +08:00
keychain_to_descriptor_id : Default ::default ( ) ,
descriptors : Default ::default ( ) ,
descriptor_id_to_keychain : Default ::default ( ) ,
2024-06-06 10:17:55 +10:00
last_revealed : Default ::default ( ) ,
2023-11-28 18:08:49 +01:00
lookahead ,
}
}
}
2024-01-13 20:04:49 +08:00
/// Methods that are *re-exposed* from the internal [`SpkTxOutIndex`].
2023-03-01 11:09:08 +01:00
impl < K : Clone + Ord + Debug > KeychainTxOutIndex < K > {
/// Return a reference to the internal [`SpkTxOutIndex`].
2024-01-13 20:04:49 +08:00
///
2024-06-01 00:06:20 -05:00
/// **WARNING**: The internal index will contain lookahead spks. Refer to
2024-01-17 13:30:28 +08:00
/// [struct-level docs](KeychainTxOutIndex) for more about `lookahead`.
2024-06-06 10:17:55 +10:00
pub fn inner ( & self ) -> & SpkTxOutIndex < ( K , u32 ) > {
2023-03-01 11:09:08 +01:00
& self . inner
}
2024-01-15 18:52:03 +01:00
/// Get the set of indexed outpoints, corresponding to tracked keychains.
2024-06-07 12:29:58 +10:00
pub fn outpoints ( & self ) -> & BTreeSet < KeychainIndexed < K , OutPoint > > {
2024-06-06 10:17:55 +10:00
self . inner . outpoints ( )
2023-05-10 14:14:29 +08:00
}
2024-01-18 14:30:29 +08:00
/// Iterate over known txouts that spend to tracked script pubkeys.
2024-06-07 12:29:58 +10:00
pub fn txouts (
& self ,
) -> impl DoubleEndedIterator < Item = KeychainIndexed < K , ( OutPoint , & TxOut ) > > + ExactSizeIterator
{
self . inner
. txouts ( )
. map ( | ( index , op , txout ) | ( index . clone ( ) , ( op , txout ) ) )
2024-01-18 14:30:29 +08:00
}
/// Finds all txouts on a transaction that has previously been scanned and indexed.
pub fn txouts_in_tx (
& self ,
txid : Txid ,
2024-06-07 12:29:58 +10:00
) -> impl DoubleEndedIterator < Item = KeychainIndexed < K , ( OutPoint , & TxOut ) > > {
self . inner
. txouts_in_tx ( txid )
. map ( | ( index , op , txout ) | ( index . clone ( ) , ( op , txout ) ) )
2024-01-18 14:30:29 +08:00
}
2024-01-15 18:52:03 +01:00
/// Return the [`TxOut`] of `outpoint` if it has been indexed, and if it corresponds to a
/// tracked keychain.
2024-01-13 20:04:49 +08:00
///
/// The associated keychain and keychain index of the txout's spk is also returned.
///
/// This calls [`SpkTxOutIndex::txout`] internally.
2024-06-07 12:29:58 +10:00
pub fn txout ( & self , outpoint : OutPoint ) -> Option < KeychainIndexed < K , & TxOut > > {
self . inner
. txout ( outpoint )
. map ( | ( index , txout ) | ( index . clone ( ) , txout ) )
2024-01-13 20:04:49 +08:00
}
/// 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 > {
2024-06-06 10:17:55 +10:00
self . inner . spk_at_index ( & ( keychain . clone ( ) , index ) )
2024-01-13 20:04:49 +08:00
}
/// Returns the keychain and keychain index associated with the spk.
///
/// This calls [`SpkTxOutIndex::index_of_spk`] internally.
2024-06-06 10:17:55 +10:00
pub fn index_of_spk ( & self , script : & Script ) -> Option < & ( K , u32 ) > {
self . inner . index_of_spk ( script )
2024-01-13 20:04:49 +08:00
}
/// Returns whether the spk under the `keychain`'s `index` has been used.
///
/// Here, "unused" means that after the script pubkey was stored in the index, the index has
/// never scanned a transaction output with it.
///
/// This calls [`SpkTxOutIndex::is_used`] internally.
pub fn is_used ( & self , keychain : K , index : u32 ) -> bool {
2024-06-06 10:17:55 +10:00
self . inner . is_used ( & ( keychain , index ) )
2024-01-13 20:04:49 +08:00
}
/// Marks the script pubkey at `index` as used even though the tracker hasn't seen an output
/// with it.
///
/// This only has an effect when the `index` had been added to `self` already and was unused.
///
2024-01-15 18:52:03 +01:00
/// Returns whether the spk under the given `keychain` and `index` is successfully
/// marked as used. Returns false either when there is no descriptor under the given
/// keychain, or when the spk is already marked as used.
2024-01-13 20:04:49 +08:00
///
/// This is useful when you want to reserve a script pubkey for something but don't want to add
/// the transaction output using it to the index yet. Other callers will consider `index` on
/// `keychain` used until you call [`unmark_used`].
///
/// This calls [`SpkTxOutIndex::mark_used`] internally.
///
/// [`unmark_used`]: Self::unmark_used
pub fn mark_used ( & mut self , keychain : K , index : u32 ) -> bool {
2024-06-06 10:17:55 +10:00
self . inner . mark_used ( & ( keychain , index ) )
2024-01-13 20:04:49 +08:00
}
/// Undoes the effect of [`mark_used`]. Returns whether the `index` is inserted back into
/// `unused`.
///
/// Note that if `self` has scanned an output with this script pubkey, then this will have no
/// effect.
///
/// This calls [`SpkTxOutIndex::unmark_used`] internally.
///
/// [`mark_used`]: Self::mark_used
pub fn unmark_used ( & mut self , keychain : K , index : u32 ) -> bool {
2024-06-06 10:17:55 +10:00
self . inner . unmark_used ( & ( keychain , index ) )
2024-01-13 20:04:49 +08:00
}
2024-02-06 17:31:22 +11:00
/// Computes the total value transfer effect `tx` has on the script pubkeys belonging to the
/// keychains in `range`. Value is *sent* when a script pubkey in the `range` is on an input and
/// *received* when it is on an output. For `sent` to be computed correctly, the output being
/// spent must have already been scanned by the index. Calculating received just uses the
/// [`Transaction`] outputs directly, so it will be correct even if it has not been scanned.
2024-04-26 11:17:23 -03:00
pub fn sent_and_received (
& self ,
tx : & Transaction ,
range : impl RangeBounds < K > ,
) -> ( Amount , Amount ) {
2024-02-06 17:31:22 +11:00
self . inner
2024-01-15 18:52:03 +01:00
. sent_and_received ( tx , self . map_to_inner_bounds ( range ) )
2024-01-13 20:04:49 +08:00
}
/// Computes the net value that this transaction gives to the script pubkeys in the index and
/// *takes* from the transaction outputs in the index. Shorthand for calling
/// [`sent_and_received`] and subtracting sent from received.
///
/// This calls [`SpkTxOutIndex::net_value`] internally.
///
/// [`sent_and_received`]: Self::sent_and_received
2024-04-26 11:17:23 -03:00
pub fn net_value ( & self , tx : & Transaction , range : impl RangeBounds < K > ) -> SignedAmount {
2024-01-15 18:52:03 +01:00
self . inner . net_value ( tx , self . map_to_inner_bounds ( range ) )
2024-01-13 20:04:49 +08:00
}
}
impl < K : Clone + Ord + Debug > KeychainTxOutIndex < K > {
2024-06-12 21:50:03 +08:00
/// Return all keychains and their corresponding descriptors.
2024-01-15 18:52:03 +01:00
pub fn keychains (
& self ,
) -> impl DoubleEndedIterator < Item = ( & K , & Descriptor < DescriptorPublicKey > ) > + ExactSizeIterator + '_
{
2024-06-12 22:19:54 +08:00
self . keychain_to_descriptor_id
. iter ( )
. map ( | ( k , did ) | ( k , self . descriptors . get ( did ) . expect ( " invariant " ) ) )
2023-03-01 11:09:08 +01:00
}
2024-01-15 18:52:03 +01:00
/// Insert a descriptor with a keychain associated to it.
2023-03-01 11:09:08 +01:00
///
2024-06-07 12:29:58 +10:00
/// Adding a descriptor means you will be able to derive new script pubkeys under it and the
/// txout index will discover transaction outputs with those script pubkeys (once they've been
/// derived and added to the index).
2023-03-01 11:09:08 +01:00
///
2024-06-07 12:29:58 +10:00
/// keychain <-> descriptor is a one-to-one mapping that cannot be changed. Attempting to do so
/// will return a [`InsertDescriptorError<K>`].
2024-06-25 10:51:51 -05:00
///
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
/// [`KeychainTxOutIndex`] will prevent you from inserting two descriptors which derive the same
2024-06-25 10:51:51 -05:00
/// script pubkey at index 0, but it's up to you to ensure that descriptors don't collide at
/// other indices. If they do nothing catastrophic happens at the `KeychainTxOutIndex` level
/// (one keychain just becomes the defacto owner of that spk arbitrarily) but this may have
/// subtle implications up the application stack like one UTXO being missing from one keychain
/// because it has been assigned to another which produces the same script pubkey.
2024-01-15 18:52:03 +01:00
pub fn insert_descriptor (
& mut self ,
keychain : K ,
descriptor : Descriptor < DescriptorPublicKey > ,
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
) -> Result < bool , InsertDescriptorError < K > > {
2024-06-11 14:55:06 +10:00
let did = descriptor . descriptor_id ( ) ;
2024-06-12 22:19:54 +08:00
if ! self . keychain_to_descriptor_id . contains_key ( & keychain )
& & ! self . descriptor_id_to_keychain . contains_key ( & did )
2024-06-06 10:17:55 +10:00
{
2024-06-12 22:19:54 +08:00
self . descriptors . insert ( did , descriptor . clone ( ) ) ;
self . keychain_to_descriptor_id . insert ( keychain . clone ( ) , did ) ;
self . descriptor_id_to_keychain . insert ( did , keychain . clone ( ) ) ;
2024-06-11 14:55:06 +10:00
self . replenish_inner_index ( did , & keychain , self . lookahead ) ;
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
return Ok ( true ) ;
}
if let Some ( existing_desc_id ) = self . keychain_to_descriptor_id . get ( & keychain ) {
let descriptor = self . descriptors . get ( existing_desc_id ) . expect ( " invariant " ) ;
if * existing_desc_id ! = did {
return Err ( InsertDescriptorError ::KeychainAlreadyAssigned {
existing_assignment : descriptor . clone ( ) ,
keychain ,
} ) ;
2024-06-06 10:17:55 +10:00
}
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
}
2024-05-06 19:21:13 +08:00
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
if let Some ( existing_keychain ) = self . descriptor_id_to_keychain . get ( & did ) {
let descriptor = self . descriptors . get ( & did ) . expect ( " invariant " ) . clone ( ) ;
2024-06-06 10:17:55 +10:00
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
if * existing_keychain ! = keychain {
return Err ( InsertDescriptorError ::DescriptorAlreadyAssigned {
existing_assignment : existing_keychain . clone ( ) ,
descriptor ,
} ) ;
2024-01-15 18:52:03 +01:00
}
}
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
Ok ( false )
2024-01-15 18:52:03 +01:00
}
/// 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 > > {
2024-06-12 22:19:54 +08:00
let did = self . keychain_to_descriptor_id . get ( keychain ) ? ;
self . descriptors . get ( did )
2023-03-01 11:09:08 +01:00
}
2023-11-28 18:08:49 +01:00
/// Get the lookahead setting.
2023-03-01 11:09:08 +01:00
///
2023-11-28 18:08:49 +01:00
/// Refer to [`new`] for more information on the `lookahead`.
2023-03-01 11:09:08 +01:00
///
2023-11-28 18:08:49 +01:00
/// [`new`]: Self::new
pub fn lookahead ( & self ) -> u32 {
self . lookahead
2023-03-01 11:09:08 +01:00
}
2024-02-17 02:20:44 +08:00
/// Store lookahead scripts until `target_index` (inclusive).
2023-03-01 11:09:08 +01:00
///
2024-02-17 02:20:44 +08:00
/// This does not change the global `lookahead` setting.
2023-03-01 11:09:08 +01:00
pub fn lookahead_to_target ( & mut self , keychain : & K , target_index : u32 ) {
2024-01-15 18:52:03 +01:00
if let Some ( ( next_index , _ ) ) = self . next_index ( keychain ) {
let temp_lookahead = ( target_index + 1 )
. checked_sub ( next_index )
. filter ( | & index | index > 0 ) ;
2024-02-17 02:20:44 +08:00
2024-01-15 18:52:03 +01:00
if let Some ( temp_lookahead ) = temp_lookahead {
2024-06-11 14:55:06 +10:00
self . replenish_inner_index_keychain ( keychain , temp_lookahead ) ;
2024-01-15 18:52:03 +01:00
}
2023-03-01 11:09:08 +01:00
}
}
2024-06-11 14:55:06 +10:00
fn replenish_inner_index_did ( & mut self , did : DescriptorId , lookahead : u32 ) {
2024-06-12 22:19:54 +08:00
if let Some ( keychain ) = self . descriptor_id_to_keychain . get ( & did ) . cloned ( ) {
2024-06-11 14:55:06 +10:00
self . replenish_inner_index ( did , & keychain , lookahead ) ;
2024-06-06 10:17:55 +10:00
}
}
2024-01-15 18:52:03 +01:00
2024-06-11 14:55:06 +10:00
fn replenish_inner_index_keychain ( & mut self , keychain : & K , lookahead : u32 ) {
2024-06-12 22:19:54 +08:00
if let Some ( did ) = self . keychain_to_descriptor_id . get ( keychain ) {
2024-06-11 14:55:06 +10:00
self . replenish_inner_index ( * did , keychain , lookahead ) ;
2024-06-11 11:48:32 +10:00
}
}
2024-06-11 14:55:06 +10:00
/// Syncs the state of the inner spk index after changes to a keychain
fn replenish_inner_index ( & mut self , did : DescriptorId , keychain : & K , lookahead : u32 ) {
2024-06-12 22:19:54 +08:00
let descriptor = self . descriptors . get ( & did ) . expect ( " invariant " ) ;
2024-06-11 11:48:32 +10:00
let next_store_index = self
. inner
. all_spks ( )
. range ( & ( keychain . clone ( ) , u32 ::MIN ) ..= & ( keychain . clone ( ) , u32 ::MAX ) )
. last ( )
. map_or ( 0 , | ( ( _ , index ) , _ ) | * index + 1 ) ;
let next_reveal_index = self . last_revealed . get ( & did ) . map_or ( 0 , | v | * v + 1 ) ;
for ( new_index , new_spk ) in
SpkIterator ::new_with_range ( descriptor , next_store_index .. next_reveal_index + lookahead )
{
let _inserted = self
2024-06-06 10:17:55 +10:00
. inner
2024-06-11 11:48:32 +10:00
. insert_spk ( ( keychain . clone ( ) , 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 ) ;
2023-03-01 11:09:08 +01:00
}
}
2024-01-15 18:52:03 +01:00
/// 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 < SpkIterator < Descriptor < DescriptorPublicKey > > > {
2024-06-06 10:17:55 +10:00
let descriptor = self . get_descriptor ( keychain ) ? . clone ( ) ;
2024-01-15 18:52:03 +01:00
Some ( SpkIterator ::new ( descriptor ) )
2024-01-13 20:04:49 +08:00
}
/// Get unbounded spk iterators for all keychains.
pub fn all_unbounded_spk_iters (
2023-03-01 11:09:08 +01:00
& self ,
2023-03-22 17:00:08 +08:00
) -> BTreeMap < K , SpkIterator < Descriptor < DescriptorPublicKey > > > {
2024-06-12 22:19:54 +08:00
self . keychain_to_descriptor_id
2023-03-01 11:09:08 +01:00
. iter ( )
2024-06-06 10:17:55 +10:00
. map ( | ( k , did ) | {
(
k . clone ( ) ,
2024-06-12 22:19:54 +08:00
SpkIterator ::new ( self . descriptors . get ( did ) . expect ( " invariant " ) . clone ( ) ) ,
2024-06-06 10:17:55 +10:00
)
} )
2023-03-01 11:09:08 +01:00
. collect ( )
}
2024-02-06 17:31:22 +11:00
/// Iterate over revealed spks of keychains in `range`
pub fn revealed_spks (
& self ,
range : impl RangeBounds < K > ,
2024-06-07 12:29:58 +10:00
) -> impl Iterator < Item = KeychainIndexed < K , & Script > > {
2024-06-06 10:17:55 +10:00
let start = range . start_bound ( ) ;
let end = range . end_bound ( ) ;
let mut iter_last_revealed = self
2024-06-12 22:19:54 +08:00
. keychain_to_descriptor_id
2024-06-06 10:17:55 +10:00
. range ( ( start , end ) )
. map ( | ( k , did ) | ( k , self . last_revealed . get ( did ) . cloned ( ) ) ) ;
let mut iter_spks = self
. inner
. all_spks ( )
. range ( self . map_to_inner_bounds ( ( start , end ) ) ) ;
let mut current_keychain = iter_last_revealed . next ( ) ;
// The reason we need a tricky algorithm is because of the "lookahead" feature which means
// that some of the spks in the SpkTxoutIndex will not have been revealed yet. So we need to
// filter out those spks that are above the last_revealed for that keychain. To do this we
// iterate through the last_revealed for each keychain and the spks for each keychain in
// tandem. This minimizes BTreeMap queries.
core ::iter ::from_fn ( move | | loop {
2024-06-07 12:29:58 +10:00
let ( ( keychain , index ) , spk ) = iter_spks . next ( ) ? ;
2024-06-06 10:17:55 +10:00
// We need to find the last revealed that matches the current spk we are considering so
// we skip ahead.
while current_keychain ? . 0 < keychain {
current_keychain = iter_last_revealed . next ( ) ;
}
let ( current_keychain , last_revealed ) = current_keychain ? ;
if current_keychain = = keychain & & Some ( * index ) < = last_revealed {
2024-06-07 12:29:58 +10:00
break Some ( ( ( keychain . clone ( ) , * index ) , spk . as_script ( ) ) ) ;
2024-06-06 10:17:55 +10:00
}
} )
2023-03-01 11:09:08 +01:00
}
2024-06-06 10:17:55 +10:00
/// Iterate over revealed spks of the given `keychain` with ascending indices.
///
/// 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.
2024-02-06 17:31:22 +11:00
pub fn revealed_keychain_spks < ' a > (
& ' a self ,
keychain : & ' a K ,
2024-06-07 12:29:58 +10:00
) -> impl DoubleEndedIterator < Item = Indexed < & Script > > + ' a {
2024-06-06 10:17:55 +10:00
let end = self
. last_revealed_index ( keychain )
. 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 ( ) ) )
2023-03-01 11:09:08 +01:00
}
2024-01-13 20:04:49 +08:00
/// Iterate over revealed, but unused, spks of all keychains.
2024-06-07 12:29:58 +10:00
pub fn unused_spks (
& self ,
) -> impl DoubleEndedIterator < Item = KeychainIndexed < K , & Script > > + Clone {
2024-06-12 22:19:54 +08:00
self . keychain_to_descriptor_id . keys ( ) . flat_map ( | keychain | {
self . unused_keychain_spks ( keychain )
. map ( | ( i , spk ) | ( ( keychain . clone ( ) , i ) , spk ) )
} )
2024-01-13 20:04:49 +08:00
}
/// Iterate over revealed, but unused, spks of the given `keychain`.
2024-01-15 18:52:03 +01:00
/// Returns an empty iterator if the provided keychain doesn't exist.
2024-01-13 20:04:49 +08:00
pub fn unused_keychain_spks (
2023-03-01 11:09:08 +01:00
& self ,
keychain : & K ,
2024-06-07 12:29:58 +10:00
) -> impl DoubleEndedIterator < Item = Indexed < & Script > > + Clone {
2024-06-12 22:19:54 +08:00
let end = match self . keychain_to_descriptor_id . get ( keychain ) {
2024-06-06 10:17:55 +10:00
Some ( did ) = > self . last_revealed . get ( did ) . map ( | v | * v + 1 ) . unwrap_or ( 0 ) ,
None = > 0 ,
} ;
2023-03-01 11:09:08 +01:00
self . inner
2024-06-06 10:17:55 +10:00
. unused_spks ( ( keychain . clone ( ) , 0 ) .. ( keychain . clone ( ) , end ) )
2024-01-13 20:04:49 +08:00
. map ( | ( ( _ , i ) , spk ) | ( * i , spk ) )
2023-03-01 11:09:08 +01:00
}
2023-03-10 23:23:29 +05:30
/// Get the next derivation index for `keychain`. The next index is the index after the last revealed
2023-03-01 11:09:08 +01:00
/// derivation index.
///
/// The second field in the returned tuple represents whether the next derivation index is new.
/// There are two scenarios where the next derivation index is reused (not new):
///
/// 1. The keychain's descriptor has no wildcard, and a script has already been revealed.
/// 2. The number of revealed scripts has already reached 2^31 (refer to BIP-32).
///
/// Not checking the second field of the tuple may result in address reuse.
///
2024-01-15 18:52:03 +01:00
/// Returns None if the provided `keychain` doesn't exist.
pub fn next_index ( & self , keychain : & K ) -> Option < ( u32 , bool ) > {
2024-06-12 22:19:54 +08:00
let did = self . keychain_to_descriptor_id . get ( keychain ) ? ;
2024-06-06 10:17:55 +10:00
let last_index = self . last_revealed . get ( did ) . cloned ( ) ;
2024-06-12 22:19:54 +08:00
let descriptor = self . descriptors . get ( did ) . expect ( " invariant " ) ;
2023-03-01 11:09:08 +01:00
2023-03-10 23:23:29 +05:30
// we can only get the next index if the wildcard exists.
2023-03-01 11:09:08 +01:00
let has_wildcard = descriptor . has_wildcard ( ) ;
2024-01-15 18:52:03 +01:00
Some ( match last_index {
2023-03-10 23:23:29 +05:30
// if there is no index, next_index is always 0.
2023-03-01 11:09:08 +01:00
None = > ( 0 , true ) ,
2023-03-10 23:23:29 +05:30
// descriptors without wildcards can only have one index.
2023-03-01 11:09:08 +01:00
Some ( _ ) if ! has_wildcard = > ( 0 , false ) ,
2023-03-10 23:23:29 +05:30
// derivation index must be < 2^31 (BIP-32).
2023-03-01 11:09:08 +01:00
Some ( index ) if index > BIP32_MAX_INDEX = > {
unreachable! ( " index is out of bounds " )
}
Some ( index ) if index = = BIP32_MAX_INDEX = > ( index , false ) ,
2023-03-10 23:23:29 +05:30
// get the next derivation index.
2023-03-01 11:09:08 +01:00
Some ( index ) = > ( index + 1 , true ) ,
2024-01-15 18:52:03 +01:00
} )
2023-03-01 11:09:08 +01:00
}
/// Get the last derivation index that is revealed for each keychain.
///
/// Keychains with no revealed indices will not be included in the returned [`BTreeMap`].
2024-01-15 18:52:03 +01:00
pub fn last_revealed_indices ( & self ) -> BTreeMap < K , u32 > {
self . last_revealed
. iter ( )
2024-05-06 19:21:13 +08:00
. filter_map ( | ( desc_id , index ) | {
2024-06-12 22:19:54 +08:00
let keychain = self . descriptor_id_to_keychain . get ( desc_id ) ? ;
2024-05-06 19:21:13 +08:00
Some ( ( keychain . clone ( ) , * index ) )
2024-01-15 18:52:03 +01:00
} )
. collect ( )
2023-03-01 11:09:08 +01:00
}
2024-01-15 18:52:03 +01:00
/// 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.
2023-03-01 11:09:08 +01:00
pub fn last_revealed_index ( & self , keychain : & K ) -> Option < u32 > {
2024-06-12 22:19:54 +08:00
let descriptor_id = self . keychain_to_descriptor_id . get ( keychain ) ? ;
2024-06-06 10:17:55 +10:00
self . last_revealed . get ( descriptor_id ) . cloned ( )
2023-03-01 11:09:08 +01:00
}
/// Convenience method to call [`Self::reveal_to_target`] on multiple keychains.
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
pub fn reveal_to_target_multi ( & mut self , keychains : & BTreeMap < K , u32 > ) -> ChangeSet {
2024-06-06 10:17:55 +10:00
let mut changeset = ChangeSet ::default ( ) ;
2023-03-01 11:09:08 +01:00
for ( keychain , & index ) in keychains {
2024-06-06 10:17:55 +10:00
if let Some ( ( _ , new_changeset ) ) = self . reveal_to_target ( keychain , index ) {
2024-07-04 22:09:04 +08:00
changeset . merge ( new_changeset ) ;
2023-03-01 11:09:08 +01:00
}
}
2024-06-06 10:17:55 +10:00
changeset
2024-01-15 18:52:03 +01:00
}
/// Reveals script pubkeys of the `keychain`'s descriptor **up to and including** the
/// `target_index`.
///
/// If the `target_index` cannot be reached (due to the descriptor having no wildcard and/or
/// the `target_index` is in the hardened index range), this method will make a best-effort and
/// reveal up to the last possible index.
///
2024-06-06 10:17:55 +10:00
/// This returns list of newly revealed indices (alongside their scripts) and a
/// [`ChangeSet`], which reports updates to the latest revealed index. If no new script
2024-01-15 18:52:03 +01:00
/// pubkeys are revealed, then both of these will be empty.
///
/// Returns None if the provided `keychain` doesn't exist.
2024-06-11 14:55:06 +10:00
#[ must_use ]
2024-01-15 18:52:03 +01:00
pub fn reveal_to_target (
& mut self ,
keychain : & K ,
target_index : u32 ,
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
) -> Option < ( Vec < Indexed < ScriptBuf > > , ChangeSet ) > {
2024-06-06 10:17:55 +10:00
let mut changeset = ChangeSet ::default ( ) ;
2024-06-07 12:29:58 +10:00
let mut spks : Vec < Indexed < ScriptBuf > > = vec! [ ] ;
2024-06-06 10:17:55 +10:00
while let Some ( ( i , new ) ) = self . next_index ( keychain ) {
if ! new | | i > target_index {
break ;
}
match self . reveal_next_spk ( keychain ) {
Some ( ( ( i , spk ) , change ) ) = > {
2024-06-07 12:29:58 +10:00
spks . push ( ( i , spk ) ) ;
2024-07-04 22:09:04 +08:00
changeset . merge ( change ) ;
2024-06-06 10:17:55 +10:00
}
None = > break ,
}
}
Some ( ( spks , changeset ) )
2023-03-01 11:09:08 +01:00
}
/// Attempts to reveal the next script pubkey for `keychain`.
///
/// Returns the derivation index of the revealed script pubkey, the revealed script pubkey and a
2024-06-06 10:17:55 +10:00
/// [`ChangeSet`] which represents changes in the last revealed index (if any).
2024-01-15 18:52:03 +01:00
/// Returns None if the provided keychain doesn't exist.
2023-03-01 11:09:08 +01:00
///
/// When a new script cannot be revealed, we return the last revealed script and an empty
2024-06-06 10:17:55 +10:00
/// [`ChangeSet`]. There are two scenarios when a new script pubkey cannot be derived:
2023-03-01 11:09:08 +01:00
///
/// 1. The descriptor has no wildcard and already has one script revealed.
/// 2. The descriptor has already revealed scripts up to the numeric bound.
2024-01-15 18:52:03 +01:00
/// 3. There is no descriptor associated with the given keychain.
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
pub fn reveal_next_spk ( & mut self , keychain : & K ) -> Option < ( Indexed < ScriptBuf > , ChangeSet ) > {
2024-06-06 10:17:55 +10:00
let ( next_index , new ) = self . next_index ( keychain ) ? ;
let mut changeset = ChangeSet ::default ( ) ;
if new {
2024-06-12 22:19:54 +08:00
let did = self . keychain_to_descriptor_id . get ( keychain ) ? ;
2024-06-06 10:17:55 +10:00
self . last_revealed . insert ( * did , next_index ) ;
changeset . last_revealed . insert ( * did , next_index ) ;
2024-06-11 14:55:06 +10:00
self . replenish_inner_index ( * did , keychain , self . lookahead ) ;
2024-06-06 10:17:55 +10:00
}
2023-03-01 11:09:08 +01:00
let script = self
. inner
2024-06-06 10:17:55 +10:00
. spk_at_index ( & ( keychain . clone ( ) , next_index ) )
. expect ( " we just inserted it " ) ;
2024-06-07 12:29:58 +10:00
Some ( ( ( next_index , script . into ( ) ) , changeset ) )
2023-03-01 11:09:08 +01:00
}
2023-03-10 23:23:29 +05:30
/// Gets the next unused script pubkey in the keychain. I.e., the script pubkey with the lowest
2023-03-01 11:09:08 +01:00
/// index that has not been used yet.
///
/// This will derive and reveal a new script pubkey if no more unused script pubkeys exist.
///
2023-03-10 23:23:29 +05:30
/// If the descriptor has no wildcard and already has a used script pubkey or if a descriptor
/// has used all scripts up to the derivation bounds, then the last derived script pubkey will be
2023-03-01 11:09:08 +01:00
/// returned.
///
2024-06-07 12:29:58 +10:00
/// Returns `None` if there are no script pubkeys that have been used and no new script pubkey
/// could be revealed (see [`reveal_next_spk`] for when this happens).
///
/// [`reveal_next_spk`]: Self::reveal_next_spk
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
pub fn next_unused_spk ( & mut self , keychain : & K ) -> Option < ( Indexed < ScriptBuf > , ChangeSet ) > {
2024-06-07 12:29:58 +10:00
let next_unused = self
. unused_keychain_spks ( keychain )
. next ( )
. map ( | ( i , spk ) | ( ( i , spk . to_owned ( ) ) , ChangeSet ::default ( ) ) ) ;
next_unused . or_else ( | | self . reveal_next_spk ( keychain ) )
2023-03-01 11:09:08 +01:00
}
2024-02-06 17:31:22 +11:00
/// Iterate over all [`OutPoint`]s that have `TxOut`s with script pubkeys derived from
2023-03-01 11:09:08 +01:00
/// `keychain`.
2024-02-06 17:31:22 +11:00
pub fn keychain_outpoints < ' a > (
& ' a self ,
keychain : & ' a K ,
2024-06-07 12:29:58 +10:00
) -> impl DoubleEndedIterator < Item = Indexed < OutPoint > > + ' a {
2024-02-06 17:31:22 +11:00
self . keychain_outpoints_in_range ( keychain ..= keychain )
2024-06-07 12:29:58 +10:00
. map ( | ( ( _ , i ) , op ) | ( i , op ) )
2024-02-06 17:31:22 +11:00
}
/// Iterate over [`OutPoint`]s that have script pubkeys derived from keychains in `range`.
pub fn keychain_outpoints_in_range < ' a > (
& ' a self ,
range : impl RangeBounds < K > + ' a ,
2024-06-07 12:29:58 +10:00
) -> impl DoubleEndedIterator < Item = KeychainIndexed < K , OutPoint > > + ' a {
self . inner
. outputs_in_range ( self . map_to_inner_bounds ( range ) )
. map ( | ( ( k , i ) , op ) | ( ( k . clone ( ) , * i ) , op ) )
2024-01-18 14:30:29 +08:00
}
2024-06-06 10:17:55 +10:00
fn map_to_inner_bounds ( & self , bound : impl RangeBounds < K > ) -> impl RangeBounds < ( K , u32 ) > {
2024-02-06 17:31:22 +11:00
let start = match bound . start_bound ( ) {
2024-06-06 10:17:55 +10:00
Bound ::Included ( keychain ) = > Bound ::Included ( ( keychain . clone ( ) , u32 ::MIN ) ) ,
Bound ::Excluded ( keychain ) = > Bound ::Excluded ( ( keychain . clone ( ) , u32 ::MAX ) ) ,
2024-01-18 14:30:29 +08:00
Bound ::Unbounded = > Bound ::Unbounded ,
} ;
2024-02-06 17:31:22 +11:00
let end = match bound . end_bound ( ) {
2024-06-06 10:17:55 +10:00
Bound ::Included ( keychain ) = > Bound ::Included ( ( keychain . clone ( ) , u32 ::MAX ) ) ,
Bound ::Excluded ( keychain ) = > Bound ::Excluded ( ( keychain . clone ( ) , u32 ::MIN ) ) ,
2024-01-18 14:30:29 +08:00
Bound ::Unbounded = > Bound ::Unbounded ,
} ;
2024-02-06 17:31:22 +11:00
( start , end )
2023-03-01 11:09:08 +01:00
}
/// 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 > {
2024-01-13 20:04:49 +08:00
self . keychain_outpoints ( keychain ) . last ( ) . map ( | ( i , _ ) | i )
2023-03-01 11:09:08 +01:00
}
/// Returns the highest derivation index of each keychain that [`KeychainTxOutIndex`] has found
/// a [`TxOut`] with it's script pubkey.
pub fn last_used_indices ( & self ) -> BTreeMap < K , u32 > {
2024-06-12 22:19:54 +08:00
self . keychain_to_descriptor_id
2023-03-01 11:09:08 +01:00
. iter ( )
. filter_map ( | ( keychain , _ ) | {
self . last_used_index ( keychain )
. map ( | index | ( keychain . clone ( ) , index ) )
} )
. collect ( )
}
2024-06-07 16:08:59 +10:00
/// Applies the `ChangeSet<K>` to the [`KeychainTxOutIndex<K>`]
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
pub fn apply_changeset ( & mut self , changeset : ChangeSet ) {
for ( & desc_id , & index ) in & changeset . last_revealed {
2024-06-06 10:17:55 +10:00
let v = self . last_revealed . entry ( desc_id ) . or_default ( ) ;
* v = index . max ( * v ) ;
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
self . replenish_inner_index_did ( desc_id , self . lookahead ) ;
2024-06-06 10:17:55 +10:00
}
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
}
}
2024-06-06 10:17:55 +10:00
#[ derive(Clone, Debug, PartialEq) ]
/// Error returned from [`KeychainTxOutIndex::insert_descriptor`]
pub enum InsertDescriptorError < K > {
/// The descriptor has already been assigned to a keychain so you can't assign it to another
DescriptorAlreadyAssigned {
/// The descriptor you have attempted to reassign
descriptor : Descriptor < DescriptorPublicKey > ,
/// The keychain that the descriptor is already assigned to
existing_assignment : K ,
} ,
/// The keychain is already assigned to a descriptor so you can't reassign it
KeychainAlreadyAssigned {
/// The keychain that you have attempted to reassign
keychain : K ,
/// The descriptor that the keychain is already assigned to
existing_assignment : Descriptor < DescriptorPublicKey > ,
} ,
}
impl < K : core ::fmt ::Debug > core ::fmt ::Display for InsertDescriptorError < K > {
fn fmt ( & self , f : & mut core ::fmt ::Formatter < '_ > ) -> core ::fmt ::Result {
match self {
InsertDescriptorError ::DescriptorAlreadyAssigned {
existing_assignment : existing ,
descriptor ,
} = > {
write! (
f ,
" attempt to re-assign descriptor {descriptor:?} already assigned to {existing:?} "
)
}
InsertDescriptorError ::KeychainAlreadyAssigned {
existing_assignment : existing ,
keychain ,
} = > {
write! (
f ,
" attempt to re-assign keychain {keychain:?} already assigned to {existing:?} "
)
}
}
}
}
#[ cfg(feature = " std " ) ]
impl < K : core ::fmt ::Debug > std ::error ::Error for InsertDescriptorError < K > { }
2024-06-07 16:08:59 +10:00
/// Represents updates to the derivation index of a [`KeychainTxOutIndex`].
/// It maps each keychain `K` to a descriptor and its last revealed index.
///
/// It can be applied to [`KeychainTxOutIndex`] with [`apply_changeset`].
///
2024-07-04 22:09:04 +08:00
/// The `last_revealed` field is monotone in that [`merge`] will never decrease it.
2024-06-07 16:08:59 +10:00
/// `keychains_added` is *not* monotone, once it is set any attempt to change it is subject to the
/// same *one-to-one* keychain <-> descriptor mapping invariant as [`KeychainTxOutIndex`] itself.
///
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
/// [`KeychainTxOutIndex`]: crate::keychain_txout::KeychainTxOutIndex
/// [`apply_changeset`]: crate::keychain_txout::KeychainTxOutIndex::apply_changeset
/// [`merge`]: Self::merge
#[ derive(Clone, Debug, Default, PartialEq) ]
2024-06-07 16:08:59 +10:00
#[ cfg_attr(
feature = " serde " ,
derive ( serde ::Deserialize , serde ::Serialize ) ,
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
serde ( crate = " serde_crate " )
2024-06-07 16:08:59 +10:00
) ]
#[ must_use ]
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
pub struct ChangeSet {
2024-06-07 16:08:59 +10:00
/// Contains for each descriptor_id the last revealed index of derivation
pub last_revealed : BTreeMap < DescriptorId , u32 > ,
}
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
impl Merge for ChangeSet {
/// Merge another [`ChangeSet`] into self.
2024-07-04 22:09:04 +08:00
fn merge ( & mut self , other : Self ) {
2024-06-07 16:08:59 +10:00
// for `last_revealed`, entries of `other` will take precedence ONLY if it is greater than
// what was originally in `self`.
for ( desc_id , index ) in other . last_revealed {
use crate ::collections ::btree_map ::Entry ;
match self . last_revealed . entry ( desc_id ) {
Entry ::Vacant ( entry ) = > {
entry . insert ( index ) ;
}
Entry ::Occupied ( mut entry ) = > {
if * entry . get ( ) < index {
entry . insert ( index ) ;
}
}
}
}
}
/// Returns whether the changeset are empty.
fn is_empty ( & self ) -> bool {
feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in
`bdk_sqlite`), we have a schema per changeset type for more flexiblity.
* rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore).
* add `sqlite` feature on `bdk_chain` which adds methods on each
changeset type for initializing tables, loading the changeset and
writing.
Rework changesets: Some callers may want to use `KeychainTxOutIndex`
where `K` may change per descriptor on every run. So we only want to
persist the last revealed indices by `DescriptorId` (which uniquely-ish
identifies the descriptor).
* rm `keychain_added` field from `keychain_txout`'s changeset.
* Add `keychain_added` to `CombinedChangeSet` (which is renamed to
`WalletChangeSet`).
Rework persistence: add back some safety and convenience when persisting
our types. Working with changeset directly (as we were doing before) can
be cumbersome.
* Intoduce `struct Persisted<T>` which wraps a type `T` which stores
staged changes to it. This adds safety when creating and or loading
`T` from db.
* `struct Persisted<T>` methods, `create`, `load` and `persist`, are
avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db`
represents the database connection and `PersistWith` should be
implemented per database-type.
* For async, we have `trait PersistedAsyncWith<Db>`.
* `Wallet` has impls of `PersistedWith<rusqlite::Connection>`,
`PersistedWith<rusqlite::Transaction>` and
`PersistedWith<bdk_file_store::Store>` by default.
Rework wallet-construction: Before, we had multiple methods for loading
and creating with different input-counts so it would be unwieldly to add
more parameters in the future. This also makes it difficult to impl
`PersistWith` (which has a single method for `load` that takes in
`PersistWith::LoadParams` and a single method for `create` that takes in
`PersistWith::CreateParams`).
* Introduce a builder pattern when constructing a `Wallet`. For loading
from persistence or `ChangeSet`, we have `LoadParams`. For creating a
new wallet, we have `CreateParams`.
2024-07-11 04:49:01 +00:00
self . last_revealed . is_empty ( )
2024-06-11 14:55:06 +10:00
}
}