Merge bitcoindevkit/bdk#1463: No descriptor ids in spk txout index
8dd174479f9719309663ed979a5b4b86aca0a6e9 refactor(chain): compute txid once for `KeychainTxOutIndex::index_tx` (志宇) 639d735ca0ae54d8b2c3bc28241032154b94d45e refactor(chain): change field names to be more sane (志宇) 5a02f40122f1bfa06c80bac93f68f5799225d133 docs(chain): fix docs (志宇) c77e12bae7f465ec7fb08b8be16d99793c757cf0 refactor(chain): `KeychainTxOutIndex` use `HashMap` for fields (志宇) 4d3846abf4f59b4a97bb825281655a6b67275603 chore(chain): s/replenish_lookahead/replenish_inner_index/ (LLFourn) 8779afdb0bf4e9b1004f47f86a770d25938d206d chore(chain): document insert_descriptor invariants better (LLFourn) 69f2a695f7dc25478489080598fea0813ea7d93d refactor(chain): improve replenish lookeahd internals (LLFourn) 5a584d0fd8c138757a10c7af93ec9e09523317e1 chore(chain): Fix Indexed and KeychainIndexed documentaion (Lloyd Fournier) b8ba5a02066fad7ab2ce276ba071385cd1dbbe3a chore(chain): Improve documentation of keychain::ChangeSet (LLFourn) 101a09a97fa5e8d675c13396b9a800665b1b6c22 chore(chain): Standardise KeychainTxOutIndex return types (LLFourn) bce070b1d662db7ac120e1d236fdda51842ad738 chore(chain): add type IndexSpk, fix clippy type complexity warning (Steve Myers) 4d2442c37f5c1bd822795271a79676d1ffbe7916 chore(chain): misc docs and insert_descriptor fixes (LLFourn) bc2a8be97919f0d09b61438527bda24796bcec94 refactor(keychain): Fix KeychainTxOutIndex range queries (LLFourn) 3b2ff0cc953204c9925ace8e2f0bbef409c63ad5 Write failing test for keychain range querying (LLFourn) Pull request description: Fixes #1459 This reverts part of the changes in #1203. There the `SpkTxOutIndex<(K,u32)>` was changed to `SpkTxOutIndex<(DescriptorId, u32>)`. This led to a complicated translation logic in `KeychainTxOutIndex` (where the API is based on `K`) to transform calls to it to calls to the underlying `SpkTxOutIndex` (which now indexes by `DescriptorId`). The translation layer was broken when it came to translating range queries from the `KeychainTxOutIndex`. My solution was just to revert this part of the change and remove the need for a translation layer (almost) altogether. A thin translation layer remains to ensure that un-revealed spks are filtered out before being returned from the `KeychainTxOutIndex` methods. I feel like this PR could be extended to include a bunch of ergonomics improvements that are easier to implement now. But I think that's the point of https://github.com/bitcoindevkit/bdk/pull/1451 so I held off and should probably go and scope creep that one instead. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### Bugfixes: * [x] This pull request breaks the existing API * [x] I've added tests to reproduce the issue which are now passing * [x] I'm linking the issue being fixed by this PR ACKs for top commit: evanlinjin: ACK 8dd174479f9719309663ed979a5b4b86aca0a6e9 Tree-SHA512: 283e6b6d4218902298e2e848fe847a6c85e27af4eee3e4337e3dad6eacf9beaa08ac99b1dce7b6fb199ca53931e543ea365728a81c41567a2e510cce77b12ac0
This commit is contained in:
commit
1c593a34ee
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#[cfg(feature = "miniscript")]
|
#[cfg(feature = "miniscript")]
|
||||||
mod txout_index;
|
mod txout_index;
|
||||||
use bitcoin::Amount;
|
use bitcoin::{Amount, ScriptBuf};
|
||||||
#[cfg(feature = "miniscript")]
|
#[cfg(feature = "miniscript")]
|
||||||
pub use txout_index::*;
|
pub use txout_index::*;
|
||||||
|
|
||||||
@ -49,6 +49,11 @@ impl Balance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A tuple of keychain index and `T` representing the indexed value.
|
||||||
|
pub type Indexed<T> = (u32, T);
|
||||||
|
/// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them.
|
||||||
|
pub type KeychainIndexed<K, T> = ((K, u32), T);
|
||||||
|
|
||||||
impl core::fmt::Display for Balance {
|
impl core::fmt::Display for Balance {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -28,6 +28,7 @@ pub use chain_data::*;
|
|||||||
pub mod indexed_tx_graph;
|
pub mod indexed_tx_graph;
|
||||||
pub use indexed_tx_graph::IndexedTxGraph;
|
pub use indexed_tx_graph::IndexedTxGraph;
|
||||||
pub mod keychain;
|
pub mod keychain;
|
||||||
|
pub use keychain::{Indexed, KeychainIndexed};
|
||||||
pub mod local_chain;
|
pub mod local_chain;
|
||||||
mod tx_data_traits;
|
mod tx_data_traits;
|
||||||
pub mod tx_graph;
|
pub mod tx_graph;
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
//! Helper types for spk-based blockchain clients.
|
//! Helper types for spk-based blockchain clients.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collections::BTreeMap, local_chain::CheckPoint, ConfirmationTimeHeightAnchor, TxGraph,
|
collections::BTreeMap, keychain::Indexed, local_chain::CheckPoint,
|
||||||
|
ConfirmationTimeHeightAnchor, TxGraph,
|
||||||
};
|
};
|
||||||
use alloc::{boxed::Box, vec::Vec};
|
use alloc::{boxed::Box, vec::Vec};
|
||||||
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
|
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
|
||||||
@ -166,7 +167,7 @@ impl SyncRequest {
|
|||||||
self.chain_spks(
|
self.chain_spks(
|
||||||
index
|
index
|
||||||
.revealed_spks(spk_range)
|
.revealed_spks(spk_range)
|
||||||
.map(|(_, _, spk)| spk.to_owned())
|
.map(|(_, spk)| spk.to_owned())
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -195,7 +196,7 @@ pub struct FullScanRequest<K> {
|
|||||||
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
|
/// [`LocalChain::tip`]: crate::local_chain::LocalChain::tip
|
||||||
pub chain_tip: CheckPoint,
|
pub chain_tip: CheckPoint,
|
||||||
/// Iterators of script pubkeys indexed by the keychain index.
|
/// Iterators of script pubkeys indexed by the keychain index.
|
||||||
pub spks_by_keychain: BTreeMap<K, Box<dyn Iterator<Item = (u32, ScriptBuf)> + Send>>,
|
pub spks_by_keychain: BTreeMap<K, Box<dyn Iterator<Item = Indexed<ScriptBuf>> + Send>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<K: Ord + Clone> FullScanRequest<K> {
|
impl<K: Ord + Clone> FullScanRequest<K> {
|
||||||
@ -238,7 +239,7 @@ impl<K: Ord + Clone> FullScanRequest<K> {
|
|||||||
pub fn set_spks_for_keychain(
|
pub fn set_spks_for_keychain(
|
||||||
mut self,
|
mut self,
|
||||||
keychain: K,
|
keychain: K,
|
||||||
spks: impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send + 'static>,
|
spks: impl IntoIterator<IntoIter = impl Iterator<Item = Indexed<ScriptBuf>> + Send + 'static>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
self.spks_by_keychain
|
self.spks_by_keychain
|
||||||
.insert(keychain, Box::new(spks.into_iter()));
|
.insert(keychain, Box::new(spks.into_iter()));
|
||||||
@ -252,7 +253,7 @@ impl<K: Ord + Clone> FullScanRequest<K> {
|
|||||||
pub fn chain_spks_for_keychain(
|
pub fn chain_spks_for_keychain(
|
||||||
mut self,
|
mut self,
|
||||||
keychain: K,
|
keychain: K,
|
||||||
spks: impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send + 'static>,
|
spks: impl IntoIterator<IntoIter = impl Iterator<Item = Indexed<ScriptBuf>> + Send + 'static>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
match self.spks_by_keychain.remove(&keychain) {
|
match self.spks_by_keychain.remove(&keychain) {
|
||||||
// clippy here suggests to remove `into_iter` from `spks.into_iter()`, but doing so
|
// clippy here suggests to remove `into_iter` from `spks.into_iter()`, but doing so
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
bitcoin::{secp256k1::Secp256k1, ScriptBuf},
|
bitcoin::{secp256k1::Secp256k1, ScriptBuf},
|
||||||
|
keychain::Indexed,
|
||||||
miniscript::{Descriptor, DescriptorPublicKey},
|
miniscript::{Descriptor, DescriptorPublicKey},
|
||||||
};
|
};
|
||||||
use core::{borrow::Borrow, ops::Bound, ops::RangeBounds};
|
use core::{borrow::Borrow, ops::Bound, ops::RangeBounds};
|
||||||
@ -97,7 +98,7 @@ impl<D> Iterator for SpkIterator<D>
|
|||||||
where
|
where
|
||||||
D: Borrow<Descriptor<DescriptorPublicKey>>,
|
D: Borrow<Descriptor<DescriptorPublicKey>>,
|
||||||
{
|
{
|
||||||
type Item = (u32, ScriptBuf);
|
type Item = Indexed<ScriptBuf>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
// For non-wildcard descriptors, we expect the first element to be Some((0, spk)), then None after.
|
// For non-wildcard descriptors, we expect the first element to be Some((0, spk)), then None after.
|
||||||
@ -158,8 +159,12 @@ mod test {
|
|||||||
let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
|
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();
|
let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
|
||||||
|
|
||||||
let _ = txout_index.insert_descriptor(TestKeychain::External, external_descriptor.clone());
|
let _ = txout_index
|
||||||
let _ = txout_index.insert_descriptor(TestKeychain::Internal, internal_descriptor.clone());
|
.insert_descriptor(TestKeychain::External, external_descriptor.clone())
|
||||||
|
.unwrap();
|
||||||
|
let _ = txout_index
|
||||||
|
.insert_descriptor(TestKeychain::Internal, internal_descriptor.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
(txout_index, external_descriptor, internal_descriptor)
|
(txout_index, external_descriptor, internal_descriptor)
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ impl<I> Default for SpkTxOutIndex<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Clone + Ord> Indexer for SpkTxOutIndex<I> {
|
impl<I: Clone + Ord + core::fmt::Debug> Indexer for SpkTxOutIndex<I> {
|
||||||
type ChangeSet = ();
|
type ChangeSet = ();
|
||||||
|
|
||||||
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet {
|
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet {
|
||||||
@ -76,7 +76,7 @@ impl<I: Clone + Ord> Indexer for SpkTxOutIndex<I> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: Clone + Ord> SpkTxOutIndex<I> {
|
impl<I: Clone + Ord + core::fmt::Debug> SpkTxOutIndex<I> {
|
||||||
/// Scans a transaction's outputs for matching script pubkeys.
|
/// Scans a transaction's outputs for matching script pubkeys.
|
||||||
///
|
///
|
||||||
/// Typically, this is used in two situations:
|
/// Typically, this is used in two situations:
|
||||||
|
@ -10,7 +10,7 @@ use bdk_chain::{
|
|||||||
indexed_tx_graph::{self, IndexedTxGraph},
|
indexed_tx_graph::{self, IndexedTxGraph},
|
||||||
keychain::{self, Balance, KeychainTxOutIndex},
|
keychain::{self, Balance, KeychainTxOutIndex},
|
||||||
local_chain::LocalChain,
|
local_chain::LocalChain,
|
||||||
tx_graph, ChainPosition, ConfirmationHeightAnchor, DescriptorExt,
|
tx_graph, Append, ChainPosition, ConfirmationHeightAnchor, DescriptorExt,
|
||||||
};
|
};
|
||||||
use bitcoin::{
|
use bitcoin::{
|
||||||
secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
|
secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
|
||||||
@ -34,7 +34,10 @@ fn insert_relevant_txs() {
|
|||||||
let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::new(
|
let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::new(
|
||||||
KeychainTxOutIndex::new(10),
|
KeychainTxOutIndex::new(10),
|
||||||
);
|
);
|
||||||
let _ = graph.index.insert_descriptor((), descriptor.clone());
|
let _ = graph
|
||||||
|
.index
|
||||||
|
.insert_descriptor((), descriptor.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let tx_a = Transaction {
|
let tx_a = Transaction {
|
||||||
output: vec![
|
output: vec![
|
||||||
@ -140,8 +143,16 @@ fn test_list_owned_txouts() {
|
|||||||
KeychainTxOutIndex::new(10),
|
KeychainTxOutIndex::new(10),
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = graph.index.insert_descriptor("keychain_1".into(), desc_1);
|
assert!(!graph
|
||||||
let _ = graph.index.insert_descriptor("keychain_2".into(), desc_2);
|
.index
|
||||||
|
.insert_descriptor("keychain_1".into(), desc_1)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
assert!(!graph
|
||||||
|
.index
|
||||||
|
.insert_descriptor("keychain_2".into(), desc_2)
|
||||||
|
.unwrap()
|
||||||
|
.is_empty());
|
||||||
|
|
||||||
// Get trusted and untrusted addresses
|
// Get trusted and untrusted addresses
|
||||||
|
|
||||||
@ -257,18 +268,26 @@ fn test_list_owned_txouts() {
|
|||||||
.unwrap_or_else(|| panic!("block must exist at {}", height));
|
.unwrap_or_else(|| panic!("block must exist at {}", height));
|
||||||
let txouts = graph
|
let txouts = graph
|
||||||
.graph()
|
.graph()
|
||||||
.filter_chain_txouts(&local_chain, chain_tip, graph.index.outpoints())
|
.filter_chain_txouts(
|
||||||
|
&local_chain,
|
||||||
|
chain_tip,
|
||||||
|
graph.index.outpoints().iter().cloned(),
|
||||||
|
)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let utxos = graph
|
let utxos = graph
|
||||||
.graph()
|
.graph()
|
||||||
.filter_chain_unspents(&local_chain, chain_tip, graph.index.outpoints())
|
.filter_chain_unspents(
|
||||||
|
&local_chain,
|
||||||
|
chain_tip,
|
||||||
|
graph.index.outpoints().iter().cloned(),
|
||||||
|
)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let balance = graph.graph().balance(
|
let balance = graph.graph().balance(
|
||||||
&local_chain,
|
&local_chain,
|
||||||
chain_tip,
|
chain_tip,
|
||||||
graph.index.outpoints(),
|
graph.index.outpoints().iter().cloned(),
|
||||||
|_, spk: &Script| trusted_spks.contains(&spk.to_owned()),
|
|_, spk: &Script| trusted_spks.contains(&spk.to_owned()),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -34,8 +34,12 @@ fn init_txout_index(
|
|||||||
) -> bdk_chain::keychain::KeychainTxOutIndex<TestKeychain> {
|
) -> bdk_chain::keychain::KeychainTxOutIndex<TestKeychain> {
|
||||||
let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::new(lookahead);
|
let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::new(lookahead);
|
||||||
|
|
||||||
let _ = txout_index.insert_descriptor(TestKeychain::External, external_descriptor);
|
let _ = txout_index
|
||||||
let _ = txout_index.insert_descriptor(TestKeychain::Internal, internal_descriptor);
|
.insert_descriptor(TestKeychain::External, external_descriptor)
|
||||||
|
.unwrap();
|
||||||
|
let _ = txout_index
|
||||||
|
.insert_descriptor(TestKeychain::Internal, internal_descriptor)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
txout_index
|
txout_index
|
||||||
}
|
}
|
||||||
@ -98,7 +102,7 @@ fn append_changesets_check_last_revealed() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_apply_changeset_with_different_descriptors_to_same_keychain() {
|
fn when_apply_contradictory_changesets_they_are_ignored() {
|
||||||
let external_descriptor = parse_descriptor(DESCRIPTORS[0]);
|
let external_descriptor = parse_descriptor(DESCRIPTORS[0]);
|
||||||
let internal_descriptor = parse_descriptor(DESCRIPTORS[1]);
|
let internal_descriptor = parse_descriptor(DESCRIPTORS[1]);
|
||||||
let mut txout_index =
|
let mut txout_index =
|
||||||
@ -120,7 +124,7 @@ fn test_apply_changeset_with_different_descriptors_to_same_keychain() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.keychains().collect::<Vec<_>>(),
|
txout_index.keychains().collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(&TestKeychain::External, &internal_descriptor),
|
(&TestKeychain::External, &external_descriptor),
|
||||||
(&TestKeychain::Internal, &internal_descriptor)
|
(&TestKeychain::Internal, &internal_descriptor)
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
@ -134,8 +138,8 @@ fn test_apply_changeset_with_different_descriptors_to_same_keychain() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.keychains().collect::<Vec<_>>(),
|
txout_index.keychains().collect::<Vec<_>>(),
|
||||||
vec![
|
vec![
|
||||||
(&TestKeychain::External, &internal_descriptor),
|
(&TestKeychain::External, &external_descriptor),
|
||||||
(&TestKeychain::Internal, &external_descriptor)
|
(&TestKeychain::Internal, &internal_descriptor)
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -156,7 +160,7 @@ fn test_set_all_derivation_indices() {
|
|||||||
]
|
]
|
||||||
.into();
|
.into();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.reveal_to_target_multi(&derive_to).1,
|
txout_index.reveal_to_target_multi(&derive_to),
|
||||||
ChangeSet {
|
ChangeSet {
|
||||||
keychains_added: BTreeMap::new(),
|
keychains_added: BTreeMap::new(),
|
||||||
last_revealed: last_revealed.clone()
|
last_revealed: last_revealed.clone()
|
||||||
@ -164,7 +168,7 @@ fn test_set_all_derivation_indices() {
|
|||||||
);
|
);
|
||||||
assert_eq!(txout_index.last_revealed_indices(), derive_to);
|
assert_eq!(txout_index.last_revealed_indices(), derive_to);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.reveal_to_target_multi(&derive_to).1,
|
txout_index.reveal_to_target_multi(&derive_to),
|
||||||
keychain::ChangeSet::default(),
|
keychain::ChangeSet::default(),
|
||||||
"no changes if we set to the same thing"
|
"no changes if we set to the same thing"
|
||||||
);
|
);
|
||||||
@ -190,7 +194,7 @@ fn test_lookahead() {
|
|||||||
.reveal_to_target(&TestKeychain::External, index)
|
.reveal_to_target(&TestKeychain::External, index)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
revealed_spks.collect::<Vec<_>>(),
|
revealed_spks,
|
||||||
vec![(index, spk_at_index(&external_descriptor, index))],
|
vec![(index, spk_at_index(&external_descriptor, index))],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -241,7 +245,7 @@ fn test_lookahead() {
|
|||||||
.reveal_to_target(&TestKeychain::Internal, 24)
|
.reveal_to_target(&TestKeychain::Internal, 24)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
revealed_spks.collect::<Vec<_>>(),
|
revealed_spks,
|
||||||
(0..=24)
|
(0..=24)
|
||||||
.map(|index| (index, spk_at_index(&internal_descriptor, index)))
|
.map(|index| (index, spk_at_index(&internal_descriptor, index)))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
@ -404,10 +408,10 @@ fn test_wildcard_derivations() {
|
|||||||
// - next_unused() == ((0, <spk>), keychain::ChangeSet:is_empty())
|
// - next_unused() == ((0, <spk>), keychain::ChangeSet:is_empty())
|
||||||
assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (0, true));
|
assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (0, true));
|
||||||
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap();
|
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap();
|
||||||
assert_eq!(spk, (0_u32, external_spk_0.as_script()));
|
assert_eq!(spk, (0_u32, external_spk_0.clone()));
|
||||||
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 0)].into());
|
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 0)].into());
|
||||||
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
||||||
assert_eq!(spk, (0_u32, external_spk_0.as_script()));
|
assert_eq!(spk, (0_u32, external_spk_0.clone()));
|
||||||
assert_eq!(&changeset.last_revealed, &[].into());
|
assert_eq!(&changeset.last_revealed, &[].into());
|
||||||
|
|
||||||
// - derived till 25
|
// - derived till 25
|
||||||
@ -427,12 +431,12 @@ fn test_wildcard_derivations() {
|
|||||||
assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (26, true));
|
assert_eq!(txout_index.next_index(&TestKeychain::External).unwrap(), (26, true));
|
||||||
|
|
||||||
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap();
|
let (spk, changeset) = txout_index.reveal_next_spk(&TestKeychain::External).unwrap();
|
||||||
assert_eq!(spk, (26, external_spk_26.as_script()));
|
assert_eq!(spk, (26, external_spk_26));
|
||||||
|
|
||||||
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 26)].into());
|
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 26)].into());
|
||||||
|
|
||||||
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
||||||
assert_eq!(spk, (16, external_spk_16.as_script()));
|
assert_eq!(spk, (16, external_spk_16));
|
||||||
assert_eq!(&changeset.last_revealed, &[].into());
|
assert_eq!(&changeset.last_revealed, &[].into());
|
||||||
|
|
||||||
// - Use all the derived till 26.
|
// - Use all the derived till 26.
|
||||||
@ -442,7 +446,7 @@ fn test_wildcard_derivations() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
let (spk, changeset) = txout_index.next_unused_spk(&TestKeychain::External).unwrap();
|
||||||
assert_eq!(spk, (27, external_spk_27.as_script()));
|
assert_eq!(spk, (27, external_spk_27));
|
||||||
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 27)].into());
|
assert_eq!(&changeset.last_revealed, &[(external_descriptor.descriptor_id(), 27)].into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,7 +462,9 @@ fn test_non_wildcard_derivations() {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.script_pubkey();
|
.script_pubkey();
|
||||||
|
|
||||||
let _ = txout_index.insert_descriptor(TestKeychain::External, no_wildcard_descriptor.clone());
|
let _ = txout_index
|
||||||
|
.insert_descriptor(TestKeychain::External, no_wildcard_descriptor.clone())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// given:
|
// given:
|
||||||
// - `txout_index` with no stored scripts
|
// - `txout_index` with no stored scripts
|
||||||
@ -473,7 +479,7 @@ fn test_non_wildcard_derivations() {
|
|||||||
let (spk, changeset) = txout_index
|
let (spk, changeset) = txout_index
|
||||||
.reveal_next_spk(&TestKeychain::External)
|
.reveal_next_spk(&TestKeychain::External)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(spk, (0, external_spk.as_script()));
|
assert_eq!(spk, (0, external_spk.clone()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&changeset.last_revealed,
|
&changeset.last_revealed,
|
||||||
&[(no_wildcard_descriptor.descriptor_id(), 0)].into()
|
&[(no_wildcard_descriptor.descriptor_id(), 0)].into()
|
||||||
@ -482,7 +488,7 @@ fn test_non_wildcard_derivations() {
|
|||||||
let (spk, changeset) = txout_index
|
let (spk, changeset) = txout_index
|
||||||
.next_unused_spk(&TestKeychain::External)
|
.next_unused_spk(&TestKeychain::External)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(spk, (0, external_spk.as_script()));
|
assert_eq!(spk, (0, external_spk.clone()));
|
||||||
assert_eq!(&changeset.last_revealed, &[].into());
|
assert_eq!(&changeset.last_revealed, &[].into());
|
||||||
|
|
||||||
// given:
|
// given:
|
||||||
@ -500,18 +506,18 @@ fn test_non_wildcard_derivations() {
|
|||||||
let (spk, changeset) = txout_index
|
let (spk, changeset) = txout_index
|
||||||
.reveal_next_spk(&TestKeychain::External)
|
.reveal_next_spk(&TestKeychain::External)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(spk, (0, external_spk.as_script()));
|
assert_eq!(spk, (0, external_spk.clone()));
|
||||||
assert_eq!(&changeset.last_revealed, &[].into());
|
assert_eq!(&changeset.last_revealed, &[].into());
|
||||||
|
|
||||||
let (spk, changeset) = txout_index
|
let (spk, changeset) = txout_index
|
||||||
.next_unused_spk(&TestKeychain::External)
|
.next_unused_spk(&TestKeychain::External)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(spk, (0, external_spk.as_script()));
|
assert_eq!(spk, (0, external_spk.clone()));
|
||||||
assert_eq!(&changeset.last_revealed, &[].into());
|
assert_eq!(&changeset.last_revealed, &[].into());
|
||||||
let (revealed_spks, revealed_changeset) = txout_index
|
let (revealed_spks, revealed_changeset) = txout_index
|
||||||
.reveal_to_target(&TestKeychain::External, 200)
|
.reveal_to_target(&TestKeychain::External, 200)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(revealed_spks.count(), 0);
|
assert_eq!(revealed_spks.len(), 0);
|
||||||
assert!(revealed_changeset.is_empty());
|
assert!(revealed_changeset.is_empty());
|
||||||
|
|
||||||
// we check that spks_of_keychain returns a SpkIterator with just one element
|
// we check that spks_of_keychain returns a SpkIterator with just one element
|
||||||
@ -591,19 +597,17 @@ fn lookahead_to_target() {
|
|||||||
|
|
||||||
let keychain_test_cases = [
|
let keychain_test_cases = [
|
||||||
(
|
(
|
||||||
external_descriptor.descriptor_id(),
|
|
||||||
TestKeychain::External,
|
TestKeychain::External,
|
||||||
t.external_last_revealed,
|
t.external_last_revealed,
|
||||||
t.external_target,
|
t.external_target,
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
internal_descriptor.descriptor_id(),
|
|
||||||
TestKeychain::Internal,
|
TestKeychain::Internal,
|
||||||
t.internal_last_revealed,
|
t.internal_last_revealed,
|
||||||
t.internal_target,
|
t.internal_target,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
for (descriptor_id, keychain, last_revealed, target) in keychain_test_cases {
|
for (keychain, last_revealed, target) in keychain_test_cases {
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
let original_last_stored_index = match last_revealed {
|
let original_last_stored_index = match last_revealed {
|
||||||
Some(last_revealed) => Some(last_revealed + t.lookahead),
|
Some(last_revealed) => Some(last_revealed + t.lookahead),
|
||||||
@ -619,10 +623,10 @@ fn lookahead_to_target() {
|
|||||||
let keys = index
|
let keys = index
|
||||||
.inner()
|
.inner()
|
||||||
.all_spks()
|
.all_spks()
|
||||||
.range((descriptor_id, 0)..=(descriptor_id, u32::MAX))
|
.range((keychain.clone(), 0)..=(keychain.clone(), u32::MAX))
|
||||||
.map(|(k, _)| *k)
|
.map(|(k, _)| k.clone())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let exp_keys = core::iter::repeat(descriptor_id)
|
let exp_keys = core::iter::repeat(keychain)
|
||||||
.zip(0_u32..=exp_last_stored_index)
|
.zip(0_u32..=exp_last_stored_index)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
assert_eq!(keys, exp_keys);
|
assert_eq!(keys, exp_keys);
|
||||||
@ -631,50 +635,6 @@ fn lookahead_to_target() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `::index_txout` should still index txouts with spks derived from descriptors without keychains.
|
|
||||||
/// This includes properly refilling the lookahead for said descriptors.
|
|
||||||
#[test]
|
|
||||||
fn index_txout_after_changing_descriptor_under_keychain() {
|
|
||||||
let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
|
|
||||||
let (desc_a, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, DESCRIPTORS[0])
|
|
||||||
.expect("descriptor 0 must be valid");
|
|
||||||
let (desc_b, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, DESCRIPTORS[1])
|
|
||||||
.expect("descriptor 1 must be valid");
|
|
||||||
let desc_id_a = desc_a.descriptor_id();
|
|
||||||
|
|
||||||
let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<()>::new(10);
|
|
||||||
|
|
||||||
// Introduce `desc_a` under keychain `()` and replace the descriptor.
|
|
||||||
let _ = txout_index.insert_descriptor((), desc_a.clone());
|
|
||||||
let _ = txout_index.insert_descriptor((), desc_b.clone());
|
|
||||||
|
|
||||||
// Loop through spks in intervals of `lookahead` to create outputs with. We should always be
|
|
||||||
// able to index these outputs if `lookahead` is respected.
|
|
||||||
let spk_indices = [9, 19, 29, 39];
|
|
||||||
for i in spk_indices {
|
|
||||||
let spk_at_index = desc_a
|
|
||||||
.at_derivation_index(i)
|
|
||||||
.expect("must derive")
|
|
||||||
.script_pubkey();
|
|
||||||
let index_changeset = txout_index.index_txout(
|
|
||||||
// Use spk derivation index as vout as we just want an unique outpoint.
|
|
||||||
OutPoint::new(h!("mock_tx"), i as _),
|
|
||||||
&TxOut {
|
|
||||||
value: Amount::from_sat(10_000),
|
|
||||||
script_pubkey: spk_at_index,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
index_changeset,
|
|
||||||
bdk_chain::keychain::ChangeSet {
|
|
||||||
keychains_added: BTreeMap::default(),
|
|
||||||
last_revealed: [(desc_id_a, i)].into(),
|
|
||||||
},
|
|
||||||
"must always increase last active if impl respects lookahead"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn insert_descriptor_no_change() {
|
fn insert_descriptor_no_change() {
|
||||||
let secp = Secp256k1::signing_only();
|
let secp = Secp256k1::signing_only();
|
||||||
@ -683,19 +643,20 @@ fn insert_descriptor_no_change() {
|
|||||||
let mut txout_index = KeychainTxOutIndex::<()>::default();
|
let mut txout_index = KeychainTxOutIndex::<()>::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.insert_descriptor((), desc.clone()),
|
txout_index.insert_descriptor((), desc.clone()),
|
||||||
keychain::ChangeSet {
|
Ok(keychain::ChangeSet {
|
||||||
keychains_added: [((), desc.clone())].into(),
|
keychains_added: [((), desc.clone())].into(),
|
||||||
last_revealed: Default::default()
|
last_revealed: Default::default()
|
||||||
},
|
}),
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
txout_index.insert_descriptor((), desc.clone()),
|
txout_index.insert_descriptor((), desc.clone()),
|
||||||
keychain::ChangeSet::default(),
|
Ok(keychain::ChangeSet::default()),
|
||||||
"inserting the same descriptor for keychain should return an empty changeset",
|
"inserting the same descriptor for keychain should return an empty changeset",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() {
|
fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() {
|
||||||
let desc = parse_descriptor(DESCRIPTORS[0]);
|
let desc = parse_descriptor(DESCRIPTORS[0]);
|
||||||
let changesets: &[ChangeSet<TestKeychain>] = &[
|
let changesets: &[ChangeSet<TestKeychain>] = &[
|
||||||
@ -743,37 +704,60 @@ fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the same descriptor is associated with various keychains,
|
|
||||||
// index methods only return the highest keychain by Ord
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_only_highest_ord_keychain_is_returned() {
|
fn assigning_same_descriptor_to_multiple_keychains_should_error() {
|
||||||
let desc = parse_descriptor(DESCRIPTORS[0]);
|
let desc = parse_descriptor(DESCRIPTORS[0]);
|
||||||
|
|
||||||
let mut indexer = KeychainTxOutIndex::<TestKeychain>::new(0);
|
let mut indexer = KeychainTxOutIndex::<TestKeychain>::new(0);
|
||||||
let _ = indexer.insert_descriptor(TestKeychain::Internal, desc.clone());
|
let _ = indexer
|
||||||
let _ = indexer.insert_descriptor(TestKeychain::External, desc);
|
.insert_descriptor(TestKeychain::Internal, desc.clone())
|
||||||
|
.unwrap();
|
||||||
|
assert!(indexer
|
||||||
|
.insert_descriptor(TestKeychain::External, desc)
|
||||||
|
.is_err())
|
||||||
|
}
|
||||||
|
|
||||||
// reveal_next_spk will work with either keychain
|
#[test]
|
||||||
let spk0: ScriptBuf = indexer
|
fn reassigning_keychain_to_a_new_descriptor_should_error() {
|
||||||
.reveal_next_spk(&TestKeychain::External)
|
let desc1 = parse_descriptor(DESCRIPTORS[0]);
|
||||||
.unwrap()
|
let desc2 = parse_descriptor(DESCRIPTORS[1]);
|
||||||
.0
|
let mut indexer = KeychainTxOutIndex::<TestKeychain>::new(0);
|
||||||
.1
|
let _ = indexer.insert_descriptor(TestKeychain::Internal, desc1);
|
||||||
.into();
|
assert!(indexer
|
||||||
let spk1: ScriptBuf = indexer
|
.insert_descriptor(TestKeychain::Internal, desc2)
|
||||||
.reveal_next_spk(&TestKeychain::Internal)
|
.is_err());
|
||||||
.unwrap()
|
}
|
||||||
.0
|
|
||||||
.1
|
|
||||||
.into();
|
|
||||||
|
|
||||||
// index_of_spk will always return External
|
#[test]
|
||||||
|
fn when_querying_over_a_range_of_keychains_the_utxos_should_show_up() {
|
||||||
|
let mut indexer = KeychainTxOutIndex::<usize>::new(0);
|
||||||
|
let mut tx = common::new_tx(0);
|
||||||
|
|
||||||
|
for (i, descriptor) in DESCRIPTORS.iter().enumerate() {
|
||||||
|
let descriptor = parse_descriptor(descriptor);
|
||||||
|
let _ = indexer.insert_descriptor(i, descriptor.clone()).unwrap();
|
||||||
|
if i != 4 {
|
||||||
|
// skip one in the middle to see if uncovers any bugs
|
||||||
|
indexer.reveal_next_spk(&i);
|
||||||
|
}
|
||||||
|
tx.output.push(TxOut {
|
||||||
|
script_pubkey: descriptor.at_derivation_index(0).unwrap().script_pubkey(),
|
||||||
|
value: Amount::from_sat(10_000),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let n_spks = DESCRIPTORS.len() - /*we skipped one*/ 1;
|
||||||
|
|
||||||
|
let _ = indexer.index_tx(&tx);
|
||||||
|
assert_eq!(indexer.outpoints().len(), n_spks);
|
||||||
|
|
||||||
|
assert_eq!(indexer.revealed_spks(0..DESCRIPTORS.len()).count(), n_spks);
|
||||||
|
assert_eq!(indexer.revealed_spks(1..4).count(), 4 - 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
indexer.index_of_spk(&spk0),
|
indexer.net_value(&tx, 0..DESCRIPTORS.len()).to_sat(),
|
||||||
Some((TestKeychain::External, 0))
|
(10_000 * n_spks) as i64
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
indexer.index_of_spk(&spk1),
|
indexer.net_value(&tx, 3..6).to_sat(),
|
||||||
Some((TestKeychain::External, 1))
|
(10_000 * (6 - 3 - /*the skipped one*/ 1)) as i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,13 @@ use std::collections::BTreeSet;
|
|||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
|
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
|
||||||
use bdk_chain::Anchor;
|
|
||||||
use bdk_chain::{
|
use bdk_chain::{
|
||||||
bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
|
bitcoin::{BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
local_chain::CheckPoint,
|
local_chain::CheckPoint,
|
||||||
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
|
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
|
||||||
};
|
};
|
||||||
|
use bdk_chain::{Anchor, Indexed};
|
||||||
use esplora_client::{Amount, TxStatus};
|
use esplora_client::{Amount, TxStatus};
|
||||||
use futures::{stream::FuturesOrdered, TryStreamExt};
|
use futures::{stream::FuturesOrdered, TryStreamExt};
|
||||||
|
|
||||||
@ -236,7 +236,7 @@ async fn full_scan_for_index_and_graph<K: Ord + Clone + Send>(
|
|||||||
client: &esplora_client::AsyncClient,
|
client: &esplora_client::AsyncClient,
|
||||||
keychain_spks: BTreeMap<
|
keychain_spks: BTreeMap<
|
||||||
K,
|
K,
|
||||||
impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send> + Send,
|
impl IntoIterator<IntoIter = impl Iterator<Item = Indexed<ScriptBuf>> + Send> + Send,
|
||||||
>,
|
>,
|
||||||
stop_gap: usize,
|
stop_gap: usize,
|
||||||
parallel_requests: usize,
|
parallel_requests: usize,
|
||||||
|
@ -4,12 +4,12 @@ use std::usize;
|
|||||||
|
|
||||||
use bdk_chain::collections::BTreeMap;
|
use bdk_chain::collections::BTreeMap;
|
||||||
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
|
use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult};
|
||||||
use bdk_chain::Anchor;
|
|
||||||
use bdk_chain::{
|
use bdk_chain::{
|
||||||
bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
|
bitcoin::{Amount, BlockHash, OutPoint, ScriptBuf, TxOut, Txid},
|
||||||
local_chain::CheckPoint,
|
local_chain::CheckPoint,
|
||||||
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
|
BlockId, ConfirmationTimeHeightAnchor, TxGraph,
|
||||||
};
|
};
|
||||||
|
use bdk_chain::{Anchor, Indexed};
|
||||||
use esplora_client::TxStatus;
|
use esplora_client::TxStatus;
|
||||||
|
|
||||||
use crate::anchor_from_status;
|
use crate::anchor_from_status;
|
||||||
@ -217,7 +217,7 @@ fn chain_update<A: Anchor>(
|
|||||||
/// [`KeychainTxOutIndex`](bdk_chain::keychain::KeychainTxOutIndex).
|
/// [`KeychainTxOutIndex`](bdk_chain::keychain::KeychainTxOutIndex).
|
||||||
fn full_scan_for_index_and_graph_blocking<K: Ord + Clone>(
|
fn full_scan_for_index_and_graph_blocking<K: Ord + Clone>(
|
||||||
client: &esplora_client::BlockingClient,
|
client: &esplora_client::BlockingClient,
|
||||||
keychain_spks: BTreeMap<K, impl IntoIterator<Item = (u32, ScriptBuf)>>,
|
keychain_spks: BTreeMap<K, impl IntoIterator<Item = Indexed<ScriptBuf>>>,
|
||||||
stop_gap: usize,
|
stop_gap: usize,
|
||||||
parallel_requests: usize,
|
parallel_requests: usize,
|
||||||
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> {
|
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> {
|
||||||
|
@ -23,7 +23,6 @@ pub enum Error {
|
|||||||
HardenedDerivationXpub,
|
HardenedDerivationXpub,
|
||||||
/// The descriptor contains multipath keys
|
/// The descriptor contains multipath keys
|
||||||
MultiPath,
|
MultiPath,
|
||||||
|
|
||||||
/// Error thrown while working with [`keys`](crate::keys)
|
/// Error thrown while working with [`keys`](crate::keys)
|
||||||
Key(crate::keys::KeyError),
|
Key(crate::keys::KeyError),
|
||||||
/// Error while extracting and manipulating policies
|
/// Error while extracting and manipulating policies
|
||||||
|
@ -29,7 +29,7 @@ use bdk_chain::{
|
|||||||
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
||||||
tx_graph::{CanonicalTx, TxGraph},
|
tx_graph::{CanonicalTx, TxGraph},
|
||||||
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
|
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
|
||||||
IndexedTxGraph,
|
Indexed, IndexedTxGraph,
|
||||||
};
|
};
|
||||||
use bdk_persist::{Persist, PersistBackend};
|
use bdk_persist::{Persist, PersistBackend};
|
||||||
use bitcoin::secp256k1::{All, Secp256k1};
|
use bitcoin::secp256k1::{All, Secp256k1};
|
||||||
@ -752,7 +752,8 @@ impl Wallet {
|
|||||||
|
|
||||||
Ok(AddressInfo {
|
Ok(AddressInfo {
|
||||||
index,
|
index,
|
||||||
address: Address::from_script(spk, self.network).expect("must have address form"),
|
address: Address::from_script(spk.as_script(), self.network)
|
||||||
|
.expect("must have address form"),
|
||||||
keychain,
|
keychain,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -772,7 +773,7 @@ impl Wallet {
|
|||||||
keychain: KeychainKind,
|
keychain: KeychainKind,
|
||||||
index: u32,
|
index: u32,
|
||||||
) -> anyhow::Result<impl Iterator<Item = AddressInfo> + '_> {
|
) -> anyhow::Result<impl Iterator<Item = AddressInfo> + '_> {
|
||||||
let (spk_iter, index_changeset) = self
|
let (spks, index_changeset) = self
|
||||||
.indexed_graph
|
.indexed_graph
|
||||||
.index
|
.index
|
||||||
.reveal_to_target(&keychain, index)
|
.reveal_to_target(&keychain, index)
|
||||||
@ -781,7 +782,7 @@ impl Wallet {
|
|||||||
self.persist
|
self.persist
|
||||||
.stage_and_commit(indexed_tx_graph::ChangeSet::from(index_changeset).into())?;
|
.stage_and_commit(indexed_tx_graph::ChangeSet::from(index_changeset).into())?;
|
||||||
|
|
||||||
Ok(spk_iter.map(move |(index, spk)| AddressInfo {
|
Ok(spks.into_iter().map(move |(index, spk)| AddressInfo {
|
||||||
index,
|
index,
|
||||||
address: Address::from_script(&spk, self.network).expect("must have address form"),
|
address: Address::from_script(&spk, self.network).expect("must have address form"),
|
||||||
keychain,
|
keychain,
|
||||||
@ -809,7 +810,8 @@ impl Wallet {
|
|||||||
|
|
||||||
Ok(AddressInfo {
|
Ok(AddressInfo {
|
||||||
index,
|
index,
|
||||||
address: Address::from_script(spk, self.network).expect("must have address form"),
|
address: Address::from_script(spk.as_script(), self.network)
|
||||||
|
.expect("must have address form"),
|
||||||
keychain,
|
keychain,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -861,7 +863,7 @@ impl Wallet {
|
|||||||
///
|
///
|
||||||
/// Will only return `Some(_)` if the wallet has given out the spk.
|
/// Will only return `Some(_)` if the wallet has given out the spk.
|
||||||
pub fn derivation_of_spk(&self, spk: &Script) -> Option<(KeychainKind, u32)> {
|
pub fn derivation_of_spk(&self, spk: &Script) -> Option<(KeychainKind, u32)> {
|
||||||
self.indexed_graph.index.index_of_spk(spk)
|
self.indexed_graph.index.index_of_spk(spk).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the list of unspent outputs of this wallet
|
/// Return the list of unspent outputs of this wallet
|
||||||
@ -871,7 +873,7 @@ impl Wallet {
|
|||||||
.filter_chain_unspents(
|
.filter_chain_unspents(
|
||||||
&self.chain,
|
&self.chain,
|
||||||
self.chain.tip().block_id(),
|
self.chain.tip().block_id(),
|
||||||
self.indexed_graph.index.outpoints(),
|
self.indexed_graph.index.outpoints().iter().cloned(),
|
||||||
)
|
)
|
||||||
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
|
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
|
||||||
}
|
}
|
||||||
@ -885,7 +887,7 @@ impl Wallet {
|
|||||||
.filter_chain_txouts(
|
.filter_chain_txouts(
|
||||||
&self.chain,
|
&self.chain,
|
||||||
self.chain.tip().block_id(),
|
self.chain.tip().block_id(),
|
||||||
self.indexed_graph.index.outpoints(),
|
self.indexed_graph.index.outpoints().iter().cloned(),
|
||||||
)
|
)
|
||||||
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
|
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
|
||||||
}
|
}
|
||||||
@ -910,7 +912,7 @@ impl Wallet {
|
|||||||
/// script pubkeys the wallet is storing internally).
|
/// script pubkeys the wallet is storing internally).
|
||||||
pub fn all_unbounded_spk_iters(
|
pub fn all_unbounded_spk_iters(
|
||||||
&self,
|
&self,
|
||||||
) -> BTreeMap<KeychainKind, impl Iterator<Item = (u32, ScriptBuf)> + Clone> {
|
) -> BTreeMap<KeychainKind, impl Iterator<Item = Indexed<ScriptBuf>> + Clone> {
|
||||||
self.indexed_graph.index.all_unbounded_spk_iters()
|
self.indexed_graph.index.all_unbounded_spk_iters()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -922,7 +924,7 @@ impl Wallet {
|
|||||||
pub fn unbounded_spk_iter(
|
pub fn unbounded_spk_iter(
|
||||||
&self,
|
&self,
|
||||||
keychain: KeychainKind,
|
keychain: KeychainKind,
|
||||||
) -> impl Iterator<Item = (u32, ScriptBuf)> + Clone {
|
) -> impl Iterator<Item = Indexed<ScriptBuf>> + Clone {
|
||||||
self.indexed_graph
|
self.indexed_graph
|
||||||
.index
|
.index
|
||||||
.unbounded_spk_iter(&keychain)
|
.unbounded_spk_iter(&keychain)
|
||||||
@ -932,7 +934,7 @@ impl Wallet {
|
|||||||
/// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
|
/// Returns the utxo owned by this wallet corresponding to `outpoint` if it exists in the
|
||||||
/// wallet's database.
|
/// wallet's database.
|
||||||
pub fn get_utxo(&self, op: OutPoint) -> Option<LocalOutput> {
|
pub fn get_utxo(&self, op: OutPoint) -> Option<LocalOutput> {
|
||||||
let (keychain, index, _) = self.indexed_graph.index.txout(op)?;
|
let ((keychain, index), _) = self.indexed_graph.index.txout(op)?;
|
||||||
self.indexed_graph
|
self.indexed_graph
|
||||||
.graph()
|
.graph()
|
||||||
.filter_chain_unspents(
|
.filter_chain_unspents(
|
||||||
@ -1207,7 +1209,7 @@ impl Wallet {
|
|||||||
self.indexed_graph.graph().balance(
|
self.indexed_graph.graph().balance(
|
||||||
&self.chain,
|
&self.chain,
|
||||||
self.chain.tip().block_id(),
|
self.chain.tip().block_id(),
|
||||||
self.indexed_graph.index.outpoints(),
|
self.indexed_graph.index.outpoints().iter().cloned(),
|
||||||
|&(k, _), _| k == KeychainKind::Internal,
|
|&(k, _), _| k == KeychainKind::Internal,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1511,7 +1513,6 @@ impl Wallet {
|
|||||||
.index
|
.index
|
||||||
.next_unused_spk(&change_keychain)
|
.next_unused_spk(&change_keychain)
|
||||||
.expect("keychain must exist");
|
.expect("keychain must exist");
|
||||||
let spk = spk.into();
|
|
||||||
self.indexed_graph.index.mark_used(change_keychain, index);
|
self.indexed_graph.index.mark_used(change_keychain, index);
|
||||||
self.persist
|
self.persist
|
||||||
.stage(ChangeSet::from(indexed_tx_graph::ChangeSet::from(
|
.stage(ChangeSet::from(indexed_tx_graph::ChangeSet::from(
|
||||||
@ -1699,7 +1700,7 @@ impl Wallet {
|
|||||||
.into();
|
.into();
|
||||||
|
|
||||||
let weighted_utxo = match txout_index.index_of_spk(&txout.script_pubkey) {
|
let weighted_utxo = match txout_index.index_of_spk(&txout.script_pubkey) {
|
||||||
Some((keychain, derivation_index)) => {
|
Some(&(keychain, derivation_index)) => {
|
||||||
let satisfaction_weight = self
|
let satisfaction_weight = self
|
||||||
.get_descriptor_for_keychain(keychain)
|
.get_descriptor_for_keychain(keychain)
|
||||||
.max_weight_to_satisfy()
|
.max_weight_to_satisfy()
|
||||||
@ -1744,7 +1745,7 @@ impl Wallet {
|
|||||||
for (index, txout) in tx.output.iter().enumerate() {
|
for (index, txout) in tx.output.iter().enumerate() {
|
||||||
let change_keychain = KeychainKind::Internal;
|
let change_keychain = KeychainKind::Internal;
|
||||||
match txout_index.index_of_spk(&txout.script_pubkey) {
|
match txout_index.index_of_spk(&txout.script_pubkey) {
|
||||||
Some((keychain, _)) if keychain == change_keychain => {
|
Some((keychain, _)) if *keychain == change_keychain => {
|
||||||
change_index = Some(index)
|
change_index = Some(index)
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -2015,13 +2016,13 @@ impl Wallet {
|
|||||||
if let Some((keychain, index)) = txout_index.index_of_spk(&txout.script_pubkey) {
|
if let Some((keychain, index)) = txout_index.index_of_spk(&txout.script_pubkey) {
|
||||||
// NOTE: unmark_used will **not** make something unused if it has actually been used
|
// NOTE: unmark_used will **not** make something unused if it has actually been used
|
||||||
// by a tx in the tracker. It only removes the superficial marking.
|
// by a tx in the tracker. It only removes the superficial marking.
|
||||||
txout_index.unmark_used(keychain, index);
|
txout_index.unmark_used(*keychain, *index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_descriptor_for_txout(&self, txout: &TxOut) -> Option<DerivedDescriptor> {
|
fn get_descriptor_for_txout(&self, txout: &TxOut) -> Option<DerivedDescriptor> {
|
||||||
let (keychain, child) = self
|
let &(keychain, child) = self
|
||||||
.indexed_graph
|
.indexed_graph
|
||||||
.index
|
.index
|
||||||
.index_of_spk(&txout.script_pubkey)?;
|
.index_of_spk(&txout.script_pubkey)?;
|
||||||
@ -2237,7 +2238,7 @@ impl Wallet {
|
|||||||
) -> Result<psbt::Input, CreateTxError> {
|
) -> Result<psbt::Input, CreateTxError> {
|
||||||
// Try to find the prev_script in our db to figure out if this is internal or external,
|
// Try to find the prev_script in our db to figure out if this is internal or external,
|
||||||
// and the derivation index
|
// and the derivation index
|
||||||
let (keychain, child) = self
|
let &(keychain, child) = self
|
||||||
.indexed_graph
|
.indexed_graph
|
||||||
.index
|
.index
|
||||||
.index_of_spk(&utxo.txout.script_pubkey)
|
.index_of_spk(&utxo.txout.script_pubkey)
|
||||||
@ -2285,7 +2286,7 @@ impl Wallet {
|
|||||||
|
|
||||||
// Try to figure out the keychain and derivation for every input and output
|
// Try to figure out the keychain and derivation for every input and output
|
||||||
for (is_input, index, out) in utxos.into_iter() {
|
for (is_input, index, out) in utxos.into_iter() {
|
||||||
if let Some((keychain, child)) =
|
if let Some(&(keychain, child)) =
|
||||||
self.indexed_graph.index.index_of_spk(&out.script_pubkey)
|
self.indexed_graph.index.index_of_spk(&out.script_pubkey)
|
||||||
{
|
{
|
||||||
let desc = self.get_descriptor_for_keychain(keychain);
|
let desc = self.get_descriptor_for_keychain(keychain);
|
||||||
@ -2331,7 +2332,7 @@ impl Wallet {
|
|||||||
None => ChangeSet::default(),
|
None => ChangeSet::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, index_changeset) = self
|
let index_changeset = self
|
||||||
.indexed_graph
|
.indexed_graph
|
||||||
.index
|
.index
|
||||||
.reveal_to_target_multi(&update.last_active_indices);
|
.reveal_to_target_multi(&update.last_active_indices);
|
||||||
@ -2536,17 +2537,27 @@ fn create_signers<E: IntoWalletDescriptor>(
|
|||||||
) -> Result<(Arc<SignersContainer>, Arc<SignersContainer>), DescriptorError> {
|
) -> Result<(Arc<SignersContainer>, Arc<SignersContainer>), DescriptorError> {
|
||||||
let descriptor = into_wallet_descriptor_checked(descriptor, secp, network)?;
|
let descriptor = into_wallet_descriptor_checked(descriptor, secp, network)?;
|
||||||
let change_descriptor = into_wallet_descriptor_checked(change_descriptor, secp, network)?;
|
let change_descriptor = into_wallet_descriptor_checked(change_descriptor, secp, network)?;
|
||||||
if descriptor.0 == change_descriptor.0 {
|
|
||||||
return Err(DescriptorError::ExternalAndInternalAreTheSame);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (descriptor, keymap) = descriptor;
|
let (descriptor, keymap) = descriptor;
|
||||||
let signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
|
let signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
|
||||||
let _ = index.insert_descriptor(KeychainKind::External, descriptor);
|
let _ = index
|
||||||
|
.insert_descriptor(KeychainKind::External, descriptor)
|
||||||
|
.expect("this is the first descriptor we're inserting");
|
||||||
|
|
||||||
let (descriptor, keymap) = change_descriptor;
|
let (descriptor, keymap) = change_descriptor;
|
||||||
let change_signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
|
let change_signers = Arc::new(SignersContainer::build(keymap, &descriptor, secp));
|
||||||
let _ = index.insert_descriptor(KeychainKind::Internal, descriptor);
|
let _ = index
|
||||||
|
.insert_descriptor(KeychainKind::Internal, descriptor)
|
||||||
|
.map_err(|e| {
|
||||||
|
use bdk_chain::keychain::InsertDescriptorError;
|
||||||
|
match e {
|
||||||
|
InsertDescriptorError::DescriptorAlreadyAssigned { .. } => {
|
||||||
|
crate::descriptor::error::Error::ExternalAndInternalAreTheSame
|
||||||
|
}
|
||||||
|
InsertDescriptorError::KeychainAlreadyAssigned { .. } => {
|
||||||
|
unreachable!("this is the first time we're assigning internal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok((signers, change_signers))
|
Ok((signers, change_signers))
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
graph.graph().balance(
|
graph.graph().balance(
|
||||||
&*chain,
|
&*chain,
|
||||||
synced_to.block_id(),
|
synced_to.block_id(),
|
||||||
graph.index.outpoints(),
|
graph.index.outpoints().iter().cloned(),
|
||||||
|(k, _), _| k == &Keychain::Internal,
|
|(k, _), _| k == &Keychain::Internal,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -336,7 +336,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
graph.graph().balance(
|
graph.graph().balance(
|
||||||
&*chain,
|
&*chain,
|
||||||
synced_to.block_id(),
|
synced_to.block_id(),
|
||||||
graph.index.outpoints(),
|
graph.index.outpoints().iter().cloned(),
|
||||||
|(k, _), _| k == &Keychain::Internal,
|
|(k, _), _| k == &Keychain::Internal,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -265,9 +265,6 @@ where
|
|||||||
.expect("Must exist");
|
.expect("Must exist");
|
||||||
changeset.append(change_changeset);
|
changeset.append(change_changeset);
|
||||||
|
|
||||||
// Clone to drop the immutable reference.
|
|
||||||
let change_script = change_script.into();
|
|
||||||
|
|
||||||
let change_plan = bdk_tmp_plan::plan_satisfaction(
|
let change_plan = bdk_tmp_plan::plan_satisfaction(
|
||||||
&graph
|
&graph
|
||||||
.index
|
.index
|
||||||
@ -427,7 +424,7 @@ pub fn planned_utxos<A: Anchor, O: ChainOracle, K: Clone + bdk_tmp_plan::CanDeri
|
|||||||
let outpoints = graph.index.outpoints();
|
let outpoints = graph.index.outpoints();
|
||||||
graph
|
graph
|
||||||
.graph()
|
.graph()
|
||||||
.try_filter_chain_unspents(chain, chain_tip, outpoints)
|
.try_filter_chain_unspents(chain, chain_tip, outpoints.iter().cloned())
|
||||||
.filter_map(|r| -> Option<Result<PlannedUtxo<K, A>, _>> {
|
.filter_map(|r| -> Option<Result<PlannedUtxo<K, A>, _>> {
|
||||||
let (k, i, full_txo) = match r {
|
let (k, i, full_txo) = match r {
|
||||||
Err(err) => return Some(Err(err)),
|
Err(err) => return Some(Err(err)),
|
||||||
@ -481,8 +478,8 @@ where
|
|||||||
local_chain::ChangeSet::default(),
|
local_chain::ChangeSet::default(),
|
||||||
indexed_tx_graph::ChangeSet::from(index_changeset),
|
indexed_tx_graph::ChangeSet::from(index_changeset),
|
||||||
)))?;
|
)))?;
|
||||||
let addr =
|
let addr = Address::from_script(spk.as_script(), network)
|
||||||
Address::from_script(spk, network).context("failed to derive address")?;
|
.context("failed to derive address")?;
|
||||||
println!("[address @ {}] {}", spk_i, addr);
|
println!("[address @ {}] {}", spk_i, addr);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -527,7 +524,7 @@ where
|
|||||||
let balance = graph.graph().try_balance(
|
let balance = graph.graph().try_balance(
|
||||||
chain,
|
chain,
|
||||||
chain.get_chain_tip()?,
|
chain.get_chain_tip()?,
|
||||||
graph.index.outpoints(),
|
graph.index.outpoints().iter().cloned(),
|
||||||
|(k, _), _| k == &Keychain::Internal,
|
|(k, _), _| k == &Keychain::Internal,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -568,7 +565,7 @@ where
|
|||||||
} => {
|
} => {
|
||||||
let txouts = graph
|
let txouts = graph
|
||||||
.graph()
|
.graph()
|
||||||
.try_filter_chain_txouts(chain, chain_tip, outpoints)
|
.try_filter_chain_txouts(chain, chain_tip, outpoints.iter().cloned())
|
||||||
.filter(|r| match r {
|
.filter(|r| match r {
|
||||||
Ok((_, full_txo)) => match (spent, unspent) {
|
Ok((_, full_txo)) => match (spent, unspent) {
|
||||||
(true, false) => full_txo.spent_by.is_some(),
|
(true, false) => full_txo.spent_by.is_some(),
|
||||||
@ -709,7 +706,7 @@ where
|
|||||||
// them in the index here. However, the keymap is not stored in the database.
|
// them in the index here. However, the keymap is not stored in the database.
|
||||||
let (descriptor, mut keymap) =
|
let (descriptor, mut keymap) =
|
||||||
Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, &args.descriptor)?;
|
Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, &args.descriptor)?;
|
||||||
let _ = index.insert_descriptor(Keychain::External, descriptor);
|
let _ = index.insert_descriptor(Keychain::External, descriptor)?;
|
||||||
|
|
||||||
if let Some((internal_descriptor, internal_keymap)) = args
|
if let Some((internal_descriptor, internal_keymap)) = args
|
||||||
.change_descriptor
|
.change_descriptor
|
||||||
@ -718,7 +715,7 @@ where
|
|||||||
.transpose()?
|
.transpose()?
|
||||||
{
|
{
|
||||||
keymap.extend(internal_keymap);
|
keymap.extend(internal_keymap);
|
||||||
let _ = index.insert_descriptor(Keychain::Internal, internal_descriptor);
|
let _ = index.insert_descriptor(Keychain::Internal, internal_descriptor)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut db_backend = match Store::<C>::open_or_create_new(db_magic, &args.db_path) {
|
let mut db_backend = match Store::<C>::open_or_create_new(db_magic, &args.db_path) {
|
||||||
|
@ -228,9 +228,9 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let all_spks = graph
|
let all_spks = graph
|
||||||
.index
|
.index
|
||||||
.revealed_spks(..)
|
.revealed_spks(..)
|
||||||
.map(|(k, i, spk)| (k.to_owned(), i, spk.to_owned()))
|
.map(|(index, spk)| (index, spk.to_owned()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request = request.chain_spks(all_spks.into_iter().map(|(k, spk_i, spk)| {
|
request = request.chain_spks(all_spks.into_iter().map(|((k, spk_i), spk)| {
|
||||||
eprint!("Scanning {}: {}", k, spk_i);
|
eprint!("Scanning {}: {}", k, spk_i);
|
||||||
spk
|
spk
|
||||||
}));
|
}));
|
||||||
@ -239,10 +239,10 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let unused_spks = graph
|
let unused_spks = graph
|
||||||
.index
|
.index
|
||||||
.unused_spks()
|
.unused_spks()
|
||||||
.map(|(k, i, spk)| (k, i, spk.to_owned()))
|
.map(|(index, spk)| (index, spk.to_owned()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request =
|
request =
|
||||||
request.chain_spks(unused_spks.into_iter().map(move |(k, spk_i, spk)| {
|
request.chain_spks(unused_spks.into_iter().map(move |((k, spk_i), spk)| {
|
||||||
eprint!(
|
eprint!(
|
||||||
"Checking if address {} {}:{} has been used",
|
"Checking if address {} {}:{} has been used",
|
||||||
Address::from_script(&spk, args.network).unwrap(),
|
Address::from_script(&spk, args.network).unwrap(),
|
||||||
@ -258,7 +258,11 @@ fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let utxos = graph
|
let utxos = graph
|
||||||
.graph()
|
.graph()
|
||||||
.filter_chain_unspents(&*chain, chain_tip.block_id(), init_outpoints)
|
.filter_chain_unspents(
|
||||||
|
&*chain,
|
||||||
|
chain_tip.block_id(),
|
||||||
|
init_outpoints.iter().cloned(),
|
||||||
|
)
|
||||||
.map(|(_, utxo)| utxo)
|
.map(|(_, utxo)| utxo)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request = request.chain_outpoints(utxos.into_iter().map(|utxo| {
|
request = request.chain_outpoints(utxos.into_iter().map(|utxo| {
|
||||||
@ -338,7 +342,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let mut indexed_tx_graph_changeset =
|
let mut indexed_tx_graph_changeset =
|
||||||
indexed_tx_graph::ChangeSet::<ConfirmationHeightAnchor, _>::default();
|
indexed_tx_graph::ChangeSet::<ConfirmationHeightAnchor, _>::default();
|
||||||
if let Some(keychain_update) = keychain_update {
|
if let Some(keychain_update) = keychain_update {
|
||||||
let (_, keychain_changeset) = graph.index.reveal_to_target_multi(&keychain_update);
|
let keychain_changeset = graph.index.reveal_to_target_multi(&keychain_update);
|
||||||
indexed_tx_graph_changeset.append(keychain_changeset.into());
|
indexed_tx_graph_changeset.append(keychain_changeset.into());
|
||||||
}
|
}
|
||||||
indexed_tx_graph_changeset.append(graph.apply_update(graph_update));
|
indexed_tx_graph_changeset.append(graph.apply_update(graph_update));
|
||||||
|
@ -204,7 +204,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
// addresses derived so we need to derive up to last active addresses the scan found
|
// addresses derived so we need to derive up to last active addresses the scan found
|
||||||
// before adding the transactions.
|
// before adding the transactions.
|
||||||
(chain.apply_update(update.chain_update)?, {
|
(chain.apply_update(update.chain_update)?, {
|
||||||
let (_, index_changeset) = graph
|
let index_changeset = graph
|
||||||
.index
|
.index
|
||||||
.reveal_to_target_multi(&update.last_active_indices);
|
.reveal_to_target_multi(&update.last_active_indices);
|
||||||
let mut indexed_tx_graph_changeset = graph.apply_update(update.graph_update);
|
let mut indexed_tx_graph_changeset = graph.apply_update(update.graph_update);
|
||||||
@ -245,7 +245,7 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let all_spks = graph
|
let all_spks = graph
|
||||||
.index
|
.index
|
||||||
.revealed_spks(..)
|
.revealed_spks(..)
|
||||||
.map(|(k, i, spk)| (k.to_owned(), i, spk.to_owned()))
|
.map(|((k, i), spk)| (k, i, spk.to_owned()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request = request.chain_spks(all_spks.into_iter().map(|(k, i, spk)| {
|
request = request.chain_spks(all_spks.into_iter().map(|(k, i, spk)| {
|
||||||
eprint!("scanning {}:{}", k, i);
|
eprint!("scanning {}:{}", k, i);
|
||||||
@ -258,10 +258,10 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let unused_spks = graph
|
let unused_spks = graph
|
||||||
.index
|
.index
|
||||||
.unused_spks()
|
.unused_spks()
|
||||||
.map(|(k, i, spk)| (k, i, spk.to_owned()))
|
.map(|(index, spk)| (index, spk.to_owned()))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request =
|
request =
|
||||||
request.chain_spks(unused_spks.into_iter().map(move |(k, i, spk)| {
|
request.chain_spks(unused_spks.into_iter().map(move |((k, i), spk)| {
|
||||||
eprint!(
|
eprint!(
|
||||||
"Checking if address {} {}:{} has been used",
|
"Checking if address {} {}:{} has been used",
|
||||||
Address::from_script(&spk, args.network).unwrap(),
|
Address::from_script(&spk, args.network).unwrap(),
|
||||||
@ -280,7 +280,11 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let init_outpoints = graph.index.outpoints();
|
let init_outpoints = graph.index.outpoints();
|
||||||
let utxos = graph
|
let utxos = graph
|
||||||
.graph()
|
.graph()
|
||||||
.filter_chain_unspents(&*chain, local_tip.block_id(), init_outpoints)
|
.filter_chain_unspents(
|
||||||
|
&*chain,
|
||||||
|
local_tip.block_id(),
|
||||||
|
init_outpoints.iter().cloned(),
|
||||||
|
)
|
||||||
.map(|(_, utxo)| utxo)
|
.map(|(_, utxo)| utxo)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
request = request.chain_outpoints(
|
request = request.chain_outpoints(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user