feat(chain)!: Implement ConfirmationBlockTime
Both `bdk_electrum` and `bdk_esplora` now report the exact block that the transaction is in, which removes the need for having the old `ConfirmationTimeHeightAnchor` and `ConfirmationHeightAnchor`. This PR introduces a new, simpler anchor type that can be modified to support additional data in the future.
This commit is contained in:
parent
e761adf481
commit
1a62488abf
@ -74,11 +74,11 @@ impl ConfirmationTime {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ChainPosition<ConfirmationTimeHeightAnchor>> for ConfirmationTime {
|
impl From<ChainPosition<ConfirmationBlockTime>> for ConfirmationTime {
|
||||||
fn from(observed_as: ChainPosition<ConfirmationTimeHeightAnchor>) -> Self {
|
fn from(observed_as: ChainPosition<ConfirmationBlockTime>) -> Self {
|
||||||
match observed_as {
|
match observed_as {
|
||||||
ChainPosition::Confirmed(a) => Self::Confirmed {
|
ChainPosition::Confirmed(a) => Self::Confirmed {
|
||||||
height: a.confirmation_height,
|
height: a.block_id.height,
|
||||||
time: a.confirmation_time,
|
time: a.confirmation_time,
|
||||||
},
|
},
|
||||||
ChainPosition::Unconfirmed(last_seen) => Self::Unconfirmed { last_seen },
|
ChainPosition::Unconfirmed(last_seen) => Self::Unconfirmed { last_seen },
|
||||||
@ -145,9 +145,7 @@ impl From<(&u32, &BlockHash)> for BlockId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An [`Anchor`] implementation that also records the exact confirmation height of the transaction.
|
/// An [`Anchor`] implementation that also records the exact confirmation time of the transaction.
|
||||||
///
|
|
||||||
/// Note that the confirmation block and the anchor block can be different here.
|
|
||||||
///
|
///
|
||||||
/// Refer to [`Anchor`] for more details.
|
/// Refer to [`Anchor`] for more details.
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
|
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
|
||||||
@ -156,70 +154,27 @@ impl From<(&u32, &BlockHash)> for BlockId {
|
|||||||
derive(serde::Deserialize, serde::Serialize),
|
derive(serde::Deserialize, serde::Serialize),
|
||||||
serde(crate = "serde_crate")
|
serde(crate = "serde_crate")
|
||||||
)]
|
)]
|
||||||
pub struct ConfirmationHeightAnchor {
|
pub struct ConfirmationBlockTime {
|
||||||
/// The exact confirmation height of the transaction.
|
|
||||||
///
|
|
||||||
/// It is assumed that this value is never larger than the height of the anchor block.
|
|
||||||
pub confirmation_height: u32,
|
|
||||||
/// The anchor block.
|
/// The anchor block.
|
||||||
pub anchor_block: BlockId,
|
pub block_id: BlockId,
|
||||||
}
|
|
||||||
|
|
||||||
impl Anchor for ConfirmationHeightAnchor {
|
|
||||||
fn anchor_block(&self) -> BlockId {
|
|
||||||
self.anchor_block
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confirmation_height_upper_bound(&self) -> u32 {
|
|
||||||
self.confirmation_height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnchorFromBlockPosition for ConfirmationHeightAnchor {
|
|
||||||
fn from_block_position(_block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
anchor_block: block_id,
|
|
||||||
confirmation_height: block_id.height,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An [`Anchor`] implementation that also records the exact confirmation time and height of the
|
|
||||||
/// transaction.
|
|
||||||
///
|
|
||||||
/// Note that the confirmation block and the anchor block can be different here.
|
|
||||||
///
|
|
||||||
/// Refer to [`Anchor`] for more details.
|
|
||||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "serde",
|
|
||||||
derive(serde::Deserialize, serde::Serialize),
|
|
||||||
serde(crate = "serde_crate")
|
|
||||||
)]
|
|
||||||
pub struct ConfirmationTimeHeightAnchor {
|
|
||||||
/// The confirmation height of the transaction being anchored.
|
|
||||||
pub confirmation_height: u32,
|
|
||||||
/// The confirmation time of the transaction being anchored.
|
/// The confirmation time of the transaction being anchored.
|
||||||
pub confirmation_time: u64,
|
pub confirmation_time: u64,
|
||||||
/// The anchor block.
|
|
||||||
pub anchor_block: BlockId,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Anchor for ConfirmationTimeHeightAnchor {
|
impl Anchor for ConfirmationBlockTime {
|
||||||
fn anchor_block(&self) -> BlockId {
|
fn anchor_block(&self) -> BlockId {
|
||||||
self.anchor_block
|
self.block_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirmation_height_upper_bound(&self) -> u32 {
|
fn confirmation_height_upper_bound(&self) -> u32 {
|
||||||
self.confirmation_height
|
self.block_id.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AnchorFromBlockPosition for ConfirmationTimeHeightAnchor {
|
impl AnchorFromBlockPosition for ConfirmationBlockTime {
|
||||||
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
|
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
anchor_block: block_id,
|
block_id,
|
||||||
confirmation_height: block_id.height,
|
|
||||||
confirmation_time: block.header.time as _,
|
confirmation_time: block.header.time as _,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -305,19 +260,19 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn chain_position_ord() {
|
fn chain_position_ord() {
|
||||||
let unconf1 = ChainPosition::<ConfirmationHeightAnchor>::Unconfirmed(10);
|
let unconf1 = ChainPosition::<ConfirmationBlockTime>::Unconfirmed(10);
|
||||||
let unconf2 = ChainPosition::<ConfirmationHeightAnchor>::Unconfirmed(20);
|
let unconf2 = ChainPosition::<ConfirmationBlockTime>::Unconfirmed(20);
|
||||||
let conf1 = ChainPosition::Confirmed(ConfirmationHeightAnchor {
|
let conf1 = ChainPosition::Confirmed(ConfirmationBlockTime {
|
||||||
confirmation_height: 9,
|
confirmation_time: 20,
|
||||||
anchor_block: BlockId {
|
block_id: BlockId {
|
||||||
height: 20,
|
height: 9,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
let conf2 = ChainPosition::Confirmed(ConfirmationHeightAnchor {
|
let conf2 = ChainPosition::Confirmed(ConfirmationBlockTime {
|
||||||
confirmation_height: 12,
|
confirmation_time: 15,
|
||||||
anchor_block: BlockId {
|
block_id: BlockId {
|
||||||
height: 15,
|
height: 12,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Helper types for spk-based blockchain clients.
|
//! Helper types for spk-based blockchain clients.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
collections::BTreeMap, local_chain::CheckPoint, ConfirmationTimeHeightAnchor, Indexed, TxGraph,
|
collections::BTreeMap, local_chain::CheckPoint, ConfirmationBlockTime, Indexed, TxGraph,
|
||||||
};
|
};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
|
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
|
||||||
@ -176,7 +176,7 @@ impl SyncRequest {
|
|||||||
/// Data returned from a spk-based blockchain client sync.
|
/// Data returned from a spk-based blockchain client sync.
|
||||||
///
|
///
|
||||||
/// See also [`SyncRequest`].
|
/// See also [`SyncRequest`].
|
||||||
pub struct SyncResult<A = ConfirmationTimeHeightAnchor> {
|
pub struct SyncResult<A = ConfirmationBlockTime> {
|
||||||
/// The update to apply to the receiving [`TxGraph`].
|
/// The update to apply to the receiving [`TxGraph`].
|
||||||
pub graph_update: TxGraph<A>,
|
pub graph_update: TxGraph<A>,
|
||||||
/// The update to apply to the receiving [`LocalChain`](crate::local_chain::LocalChain).
|
/// The update to apply to the receiving [`LocalChain`](crate::local_chain::LocalChain).
|
||||||
@ -317,7 +317,7 @@ impl<K: Ord + Clone> FullScanRequest<K> {
|
|||||||
/// Data returned from a spk-based blockchain client full scan.
|
/// Data returned from a spk-based blockchain client full scan.
|
||||||
///
|
///
|
||||||
/// See also [`FullScanRequest`].
|
/// See also [`FullScanRequest`].
|
||||||
pub struct FullScanResult<K, A = ConfirmationTimeHeightAnchor> {
|
pub struct FullScanResult<K, A = ConfirmationBlockTime> {
|
||||||
/// The update to apply to the receiving [`LocalChain`](crate::local_chain::LocalChain).
|
/// The update to apply to the receiving [`LocalChain`](crate::local_chain::LocalChain).
|
||||||
pub graph_update: TxGraph<A>,
|
pub graph_update: TxGraph<A>,
|
||||||
/// The update to apply to the receiving [`TxGraph`].
|
/// The update to apply to the receiving [`TxGraph`].
|
||||||
|
@ -20,8 +20,7 @@ use alloc::vec::Vec;
|
|||||||
/// # use bdk_chain::local_chain::LocalChain;
|
/// # use bdk_chain::local_chain::LocalChain;
|
||||||
/// # use bdk_chain::tx_graph::TxGraph;
|
/// # use bdk_chain::tx_graph::TxGraph;
|
||||||
/// # use bdk_chain::BlockId;
|
/// # use bdk_chain::BlockId;
|
||||||
/// # use bdk_chain::ConfirmationHeightAnchor;
|
/// # use bdk_chain::ConfirmationBlockTime;
|
||||||
/// # use bdk_chain::ConfirmationTimeHeightAnchor;
|
|
||||||
/// # use bdk_chain::example_utils::*;
|
/// # use bdk_chain::example_utils::*;
|
||||||
/// # use bitcoin::hashes::Hash;
|
/// # use bitcoin::hashes::Hash;
|
||||||
/// // Initialize the local chain with two blocks.
|
/// // Initialize the local chain with two blocks.
|
||||||
@ -50,39 +49,19 @@ use alloc::vec::Vec;
|
|||||||
/// },
|
/// },
|
||||||
/// );
|
/// );
|
||||||
///
|
///
|
||||||
/// // Insert `tx` into a `TxGraph` that uses `ConfirmationHeightAnchor` as the anchor type.
|
/// // Insert `tx` into a `TxGraph` that uses `ConfirmationBlockTime` as the anchor type.
|
||||||
/// // This anchor records the anchor block and the confirmation height of the transaction.
|
/// // This anchor records the anchor block and the confirmation time of the transaction. When a
|
||||||
/// // When a transaction is anchored with `ConfirmationHeightAnchor`, the anchor block and
|
/// // transaction is anchored with `ConfirmationBlockTime`, the anchor block and confirmation block
|
||||||
/// // confirmation block can be different. However, the confirmation block cannot be higher than
|
/// // of the transaction is the same block.
|
||||||
/// // the anchor block and both blocks must be in the same chain for the anchor to be valid.
|
/// let mut graph_c = TxGraph::<ConfirmationBlockTime>::default();
|
||||||
/// let mut graph_b = TxGraph::<ConfirmationHeightAnchor>::default();
|
|
||||||
/// let _ = graph_b.insert_tx(tx.clone());
|
|
||||||
/// graph_b.insert_anchor(
|
|
||||||
/// tx.compute_txid(),
|
|
||||||
/// ConfirmationHeightAnchor {
|
|
||||||
/// anchor_block: BlockId {
|
|
||||||
/// height: 2,
|
|
||||||
/// hash: Hash::hash("second".as_bytes()),
|
|
||||||
/// },
|
|
||||||
/// confirmation_height: 1,
|
|
||||||
/// },
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// // Insert `tx` into a `TxGraph` that uses `ConfirmationTimeHeightAnchor` as the anchor type.
|
|
||||||
/// // This anchor records the anchor block, the confirmation height and time of the transaction.
|
|
||||||
/// // When a transaction is anchored with `ConfirmationTimeHeightAnchor`, the anchor block and
|
|
||||||
/// // confirmation block can be different. However, the confirmation block cannot be higher than
|
|
||||||
/// // the anchor block and both blocks must be in the same chain for the anchor to be valid.
|
|
||||||
/// let mut graph_c = TxGraph::<ConfirmationTimeHeightAnchor>::default();
|
|
||||||
/// let _ = graph_c.insert_tx(tx.clone());
|
/// let _ = graph_c.insert_tx(tx.clone());
|
||||||
/// graph_c.insert_anchor(
|
/// graph_c.insert_anchor(
|
||||||
/// tx.compute_txid(),
|
/// tx.compute_txid(),
|
||||||
/// ConfirmationTimeHeightAnchor {
|
/// ConfirmationBlockTime {
|
||||||
/// anchor_block: BlockId {
|
/// block_id: BlockId {
|
||||||
/// height: 2,
|
/// height: 2,
|
||||||
/// hash: Hash::hash("third".as_bytes()),
|
/// hash: Hash::hash("third".as_bytes()),
|
||||||
/// },
|
/// },
|
||||||
/// confirmation_height: 1,
|
|
||||||
/// confirmation_time: 123,
|
/// confirmation_time: 123,
|
||||||
/// },
|
/// },
|
||||||
/// );
|
/// );
|
||||||
|
@ -10,7 +10,7 @@ use bdk_chain::{
|
|||||||
indexed_tx_graph::{self, IndexedTxGraph},
|
indexed_tx_graph::{self, IndexedTxGraph},
|
||||||
indexer::keychain_txout::KeychainTxOutIndex,
|
indexer::keychain_txout::KeychainTxOutIndex,
|
||||||
local_chain::LocalChain,
|
local_chain::LocalChain,
|
||||||
tx_graph, Balance, ChainPosition, ConfirmationHeightAnchor, DescriptorExt, Merge,
|
tx_graph, Balance, ChainPosition, ConfirmationBlockTime, DescriptorExt, Merge,
|
||||||
};
|
};
|
||||||
use bitcoin::{
|
use bitcoin::{
|
||||||
secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
|
secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
|
||||||
@ -32,7 +32,7 @@ fn insert_relevant_txs() {
|
|||||||
let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey();
|
let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey();
|
||||||
let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey();
|
let spk_1 = descriptor.at_derivation_index(9).unwrap().script_pubkey();
|
||||||
|
|
||||||
let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<()>>::new(
|
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, KeychainTxOutIndex<()>>::new(
|
||||||
KeychainTxOutIndex::new(10),
|
KeychainTxOutIndex::new(10),
|
||||||
);
|
);
|
||||||
let _ = graph
|
let _ = graph
|
||||||
@ -140,7 +140,7 @@ fn test_list_owned_txouts() {
|
|||||||
let (desc_2, _) =
|
let (desc_2, _) =
|
||||||
Descriptor::parse_descriptor(&Secp256k1::signing_only(), common::DESCRIPTORS[3]).unwrap();
|
Descriptor::parse_descriptor(&Secp256k1::signing_only(), common::DESCRIPTORS[3]).unwrap();
|
||||||
|
|
||||||
let mut graph = IndexedTxGraph::<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>::new(
|
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, KeychainTxOutIndex<String>>::new(
|
||||||
KeychainTxOutIndex::new(10),
|
KeychainTxOutIndex::new(10),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -250,9 +250,9 @@ fn test_list_owned_txouts() {
|
|||||||
local_chain
|
local_chain
|
||||||
.get(height)
|
.get(height)
|
||||||
.map(|cp| cp.block_id())
|
.map(|cp| cp.block_id())
|
||||||
.map(|anchor_block| ConfirmationHeightAnchor {
|
.map(|block_id| ConfirmationBlockTime {
|
||||||
anchor_block,
|
block_id,
|
||||||
confirmation_height: anchor_block.height,
|
confirmation_time: 100,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
@ -261,8 +261,7 @@ fn test_list_owned_txouts() {
|
|||||||
|
|
||||||
// A helper lambda to extract and filter data from the graph.
|
// A helper lambda to extract and filter data from the graph.
|
||||||
let fetch =
|
let fetch =
|
||||||
|height: u32,
|
|height: u32, graph: &IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<String>>| {
|
||||||
graph: &IndexedTxGraph<ConfirmationHeightAnchor, KeychainTxOutIndex<String>>| {
|
|
||||||
let chain_tip = local_chain
|
let chain_tip = local_chain
|
||||||
.get(height)
|
.get(height)
|
||||||
.map(|cp| cp.block_id())
|
.map(|cp| cp.block_id())
|
||||||
|
@ -7,7 +7,7 @@ use bdk_chain::{
|
|||||||
collections::*,
|
collections::*,
|
||||||
local_chain::LocalChain,
|
local_chain::LocalChain,
|
||||||
tx_graph::{ChangeSet, TxGraph},
|
tx_graph::{ChangeSet, TxGraph},
|
||||||
Anchor, BlockId, ChainOracle, ChainPosition, ConfirmationHeightAnchor, Merge,
|
Anchor, BlockId, ChainOracle, ChainPosition, ConfirmationBlockTime, Merge,
|
||||||
};
|
};
|
||||||
use bitcoin::{
|
use bitcoin::{
|
||||||
absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, SignedAmount,
|
absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, SignedAmount,
|
||||||
@ -935,7 +935,7 @@ fn test_chain_spends() {
|
|||||||
..common::new_tx(0)
|
..common::new_tx(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut graph = TxGraph::<ConfirmationHeightAnchor>::default();
|
let mut graph = TxGraph::<ConfirmationBlockTime>::default();
|
||||||
|
|
||||||
let _ = graph.insert_tx(tx_0.clone());
|
let _ = graph.insert_tx(tx_0.clone());
|
||||||
let _ = graph.insert_tx(tx_1.clone());
|
let _ = graph.insert_tx(tx_1.clone());
|
||||||
@ -944,9 +944,9 @@ fn test_chain_spends() {
|
|||||||
for (ht, tx) in [(95, &tx_0), (98, &tx_1)] {
|
for (ht, tx) in [(95, &tx_0), (98, &tx_1)] {
|
||||||
let _ = graph.insert_anchor(
|
let _ = graph.insert_anchor(
|
||||||
tx.compute_txid(),
|
tx.compute_txid(),
|
||||||
ConfirmationHeightAnchor {
|
ConfirmationBlockTime {
|
||||||
anchor_block: tip.block_id(),
|
block_id: tip.get(ht).unwrap().block_id(),
|
||||||
confirmation_height: ht,
|
confirmation_time: 100,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -959,9 +959,12 @@ fn test_chain_spends() {
|
|||||||
OutPoint::new(tx_0.compute_txid(), 0)
|
OutPoint::new(tx_0.compute_txid(), 0)
|
||||||
),
|
),
|
||||||
Some((
|
Some((
|
||||||
ChainPosition::Confirmed(&ConfirmationHeightAnchor {
|
ChainPosition::Confirmed(&ConfirmationBlockTime {
|
||||||
anchor_block: tip.block_id(),
|
block_id: BlockId {
|
||||||
confirmation_height: 98
|
hash: tip.get(98).unwrap().hash(),
|
||||||
|
height: 98,
|
||||||
|
},
|
||||||
|
confirmation_time: 100
|
||||||
}),
|
}),
|
||||||
tx_1.compute_txid(),
|
tx_1.compute_txid(),
|
||||||
)),
|
)),
|
||||||
@ -971,9 +974,12 @@ fn test_chain_spends() {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
graph.get_chain_position(&local_chain, tip.block_id(), tx_0.compute_txid()),
|
graph.get_chain_position(&local_chain, tip.block_id(), tx_0.compute_txid()),
|
||||||
// Some(ObservedAs::Confirmed(&local_chain.get_block(95).expect("block expected"))),
|
// Some(ObservedAs::Confirmed(&local_chain.get_block(95).expect("block expected"))),
|
||||||
Some(ChainPosition::Confirmed(&ConfirmationHeightAnchor {
|
Some(ChainPosition::Confirmed(&ConfirmationBlockTime {
|
||||||
anchor_block: tip.block_id(),
|
block_id: BlockId {
|
||||||
confirmation_height: 95
|
hash: tip.get(95).unwrap().hash(),
|
||||||
|
height: 95,
|
||||||
|
},
|
||||||
|
confirmation_time: 100
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use bdk_chain::{
|
|||||||
local_chain::CheckPoint,
|
local_chain::CheckPoint,
|
||||||
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
||||||
tx_graph::TxGraph,
|
tx_graph::TxGraph,
|
||||||
Anchor, BlockId, ConfirmationTimeHeightAnchor,
|
Anchor, BlockId, ConfirmationBlockTime,
|
||||||
};
|
};
|
||||||
use electrum_client::{ElectrumApi, Error, HeaderNotification};
|
use electrum_client::{ElectrumApi, Error, HeaderNotification};
|
||||||
use std::{
|
use std::{
|
||||||
@ -123,12 +123,12 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
) -> Result<FullScanResult<K>, Error> {
|
) -> Result<FullScanResult<K>, Error> {
|
||||||
let (tip, latest_blocks) =
|
let (tip, latest_blocks) =
|
||||||
fetch_tip_and_latest_blocks(&self.inner, request.chain_tip.clone())?;
|
fetch_tip_and_latest_blocks(&self.inner, request.chain_tip.clone())?;
|
||||||
let mut graph_update = TxGraph::<ConfirmationTimeHeightAnchor>::default();
|
let mut graph_update = TxGraph::<ConfirmationBlockTime>::default();
|
||||||
let mut last_active_indices = BTreeMap::<K, u32>::new();
|
let mut last_active_indices = BTreeMap::<K, u32>::new();
|
||||||
|
|
||||||
for (keychain, keychain_spks) in request.spks_by_keychain {
|
for (keychain, spks) in request.spks_by_keychain {
|
||||||
if let Some(last_active_index) =
|
if let Some(last_active_index) =
|
||||||
self.populate_with_spks(&mut graph_update, keychain_spks, stop_gap, batch_size)?
|
self.populate_with_spks(&mut graph_update, spks, stop_gap, batch_size)?
|
||||||
{
|
{
|
||||||
last_active_indices.insert(keychain, last_active_index);
|
last_active_indices.insert(keychain, last_active_index);
|
||||||
}
|
}
|
||||||
@ -199,17 +199,15 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
/// Transactions that contains an output with requested spk, or spends form an output with
|
/// Transactions that contains an output with requested spk, or spends form an output with
|
||||||
/// requested spk will be added to `graph_update`. Anchors of the aforementioned transactions are
|
/// requested spk will be added to `graph_update`. Anchors of the aforementioned transactions are
|
||||||
/// also included.
|
/// also included.
|
||||||
///
|
fn populate_with_spks(
|
||||||
/// Checkpoints (in `cps`) are used to create anchors. The `tx_cache` is self-explanatory.
|
|
||||||
fn populate_with_spks<I: Ord + Clone>(
|
|
||||||
&self,
|
&self,
|
||||||
graph_update: &mut TxGraph<ConfirmationTimeHeightAnchor>,
|
graph_update: &mut TxGraph<ConfirmationBlockTime>,
|
||||||
mut spks: impl Iterator<Item = (I, ScriptBuf)>,
|
mut spks: impl Iterator<Item = (u32, ScriptBuf)>,
|
||||||
stop_gap: usize,
|
stop_gap: usize,
|
||||||
batch_size: usize,
|
batch_size: usize,
|
||||||
) -> Result<Option<I>, Error> {
|
) -> Result<Option<u32>, Error> {
|
||||||
let mut unused_spk_count = 0_usize;
|
let mut unused_spk_count = 0_usize;
|
||||||
let mut last_active_index = Option::<I>::None;
|
let mut last_active_index = Option::<u32>::None;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let spks = (0..batch_size)
|
let spks = (0..batch_size)
|
||||||
@ -225,8 +223,8 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
|
|
||||||
for ((spk_index, _spk), spk_history) in spks.into_iter().zip(spk_histories) {
|
for ((spk_index, _spk), spk_history) in spks.into_iter().zip(spk_histories) {
|
||||||
if spk_history.is_empty() {
|
if spk_history.is_empty() {
|
||||||
unused_spk_count += 1;
|
unused_spk_count = unused_spk_count.saturating_add(1);
|
||||||
if unused_spk_count > stop_gap {
|
if unused_spk_count >= stop_gap {
|
||||||
return Ok(last_active_index);
|
return Ok(last_active_index);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@ -247,11 +245,9 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
///
|
///
|
||||||
/// Transactions in which the outpoint resides, and transactions that spend from the outpoint are
|
/// Transactions in which the outpoint resides, and transactions that spend from the outpoint are
|
||||||
/// included. Anchors of the aforementioned transactions are included.
|
/// included. Anchors of the aforementioned transactions are included.
|
||||||
///
|
|
||||||
/// Checkpoints (in `cps`) are used to create anchors. The `tx_cache` is self-explanatory.
|
|
||||||
fn populate_with_outpoints(
|
fn populate_with_outpoints(
|
||||||
&self,
|
&self,
|
||||||
graph_update: &mut TxGraph<ConfirmationTimeHeightAnchor>,
|
graph_update: &mut TxGraph<ConfirmationBlockTime>,
|
||||||
outpoints: impl IntoIterator<Item = OutPoint>,
|
outpoints: impl IntoIterator<Item = OutPoint>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for outpoint in outpoints {
|
for outpoint in outpoints {
|
||||||
@ -299,7 +295,7 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
/// Populate the `graph_update` with transactions/anchors of the provided `txids`.
|
/// Populate the `graph_update` with transactions/anchors of the provided `txids`.
|
||||||
fn populate_with_txids(
|
fn populate_with_txids(
|
||||||
&self,
|
&self,
|
||||||
graph_update: &mut TxGraph<ConfirmationTimeHeightAnchor>,
|
graph_update: &mut TxGraph<ConfirmationBlockTime>,
|
||||||
txids: impl IntoIterator<Item = Txid>,
|
txids: impl IntoIterator<Item = Txid>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
for txid in txids {
|
for txid in txids {
|
||||||
@ -335,7 +331,7 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
// An anchor is inserted if the transaction is validated to be in a confirmed block.
|
// An anchor is inserted if the transaction is validated to be in a confirmed block.
|
||||||
fn validate_merkle_for_anchor(
|
fn validate_merkle_for_anchor(
|
||||||
&self,
|
&self,
|
||||||
graph_update: &mut TxGraph<ConfirmationTimeHeightAnchor>,
|
graph_update: &mut TxGraph<ConfirmationBlockTime>,
|
||||||
txid: Txid,
|
txid: Txid,
|
||||||
confirmation_height: i32,
|
confirmation_height: i32,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
@ -364,10 +360,9 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
if is_confirmed_tx {
|
if is_confirmed_tx {
|
||||||
let _ = graph_update.insert_anchor(
|
let _ = graph_update.insert_anchor(
|
||||||
txid,
|
txid,
|
||||||
ConfirmationTimeHeightAnchor {
|
ConfirmationBlockTime {
|
||||||
confirmation_height: merkle_res.block_height as u32,
|
|
||||||
confirmation_time: header.time as u64,
|
confirmation_time: header.time as u64,
|
||||||
anchor_block: BlockId {
|
block_id: BlockId {
|
||||||
height: merkle_res.block_height as u32,
|
height: merkle_res.block_height as u32,
|
||||||
hash: header.block_hash(),
|
hash: header.block_hash(),
|
||||||
},
|
},
|
||||||
@ -382,7 +377,7 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
|
|||||||
// which we do not have by default. This data is needed to calculate the transaction fee.
|
// which we do not have by default. This data is needed to calculate the transaction fee.
|
||||||
fn fetch_prev_txout(
|
fn fetch_prev_txout(
|
||||||
&self,
|
&self,
|
||||||
graph_update: &mut TxGraph<ConfirmationTimeHeightAnchor>,
|
graph_update: &mut TxGraph<ConfirmationBlockTime>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let full_txs: Vec<Arc<Transaction>> =
|
let full_txs: Vec<Arc<Transaction>> =
|
||||||
graph_update.full_txs().map(|tx_node| tx_node.tx).collect();
|
graph_update.full_txs().map(|tx_node| tx_node.tx).collect();
|
||||||
@ -454,11 +449,13 @@ fn fetch_tip_and_latest_blocks(
|
|||||||
let agreement_height = agreement_cp.as_ref().map(CheckPoint::height);
|
let agreement_height = agreement_cp.as_ref().map(CheckPoint::height);
|
||||||
|
|
||||||
let new_tip = new_blocks
|
let new_tip = new_blocks
|
||||||
.clone()
|
.iter()
|
||||||
.into_iter()
|
|
||||||
// Prune `new_blocks` to only include blocks that are actually new.
|
// Prune `new_blocks` to only include blocks that are actually new.
|
||||||
.filter(|(height, _)| Some(*height) > agreement_height)
|
.filter(|(height, _)| Some(*<&u32>::clone(height)) > agreement_height)
|
||||||
.map(|(height, hash)| BlockId { height, hash })
|
.map(|(height, hash)| BlockId {
|
||||||
|
height: *height,
|
||||||
|
hash: *hash,
|
||||||
|
})
|
||||||
.fold(agreement_cp, |prev_cp, block| {
|
.fold(agreement_cp, |prev_cp, block| {
|
||||||
Some(match prev_cp {
|
Some(match prev_cp {
|
||||||
Some(cp) => cp.push(block).expect("must extend checkpoint"),
|
Some(cp) => cp.push(block).expect("must extend checkpoint"),
|
||||||
|
@ -2,7 +2,7 @@ use bdk_chain::{
|
|||||||
bitcoin::{hashes::Hash, Address, Amount, ScriptBuf, Txid, WScriptHash},
|
bitcoin::{hashes::Hash, Address, Amount, ScriptBuf, Txid, WScriptHash},
|
||||||
local_chain::LocalChain,
|
local_chain::LocalChain,
|
||||||
spk_client::{FullScanRequest, SyncRequest},
|
spk_client::{FullScanRequest, SyncRequest},
|
||||||
Balance, ConfirmationTimeHeightAnchor, IndexedTxGraph, SpkTxOutIndex,
|
Balance, ConfirmationBlockTime, IndexedTxGraph, SpkTxOutIndex,
|
||||||
};
|
};
|
||||||
use bdk_electrum::BdkElectrumClient;
|
use bdk_electrum::BdkElectrumClient;
|
||||||
use bdk_testenv::{anyhow, bitcoincore_rpc::RpcApi, TestEnv};
|
use bdk_testenv::{anyhow, bitcoincore_rpc::RpcApi, TestEnv};
|
||||||
@ -11,7 +11,7 @@ use std::str::FromStr;
|
|||||||
|
|
||||||
fn get_balance(
|
fn get_balance(
|
||||||
recv_chain: &LocalChain,
|
recv_chain: &LocalChain,
|
||||||
recv_graph: &IndexedTxGraph<ConfirmationTimeHeightAnchor, SpkTxOutIndex<()>>,
|
recv_graph: &IndexedTxGraph<ConfirmationBlockTime, SpkTxOutIndex<()>>,
|
||||||
) -> anyhow::Result<Balance> {
|
) -> anyhow::Result<Balance> {
|
||||||
let chain_tip = recv_chain.tip().block_id();
|
let chain_tip = recv_chain.tip().block_id();
|
||||||
let outpoints = recv_graph.index.outpoints().clone();
|
let outpoints = recv_graph.index.outpoints().clone();
|
||||||
@ -262,7 +262,7 @@ fn scan_detects_confirmed_tx() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
// Setup receiver.
|
// Setup receiver.
|
||||||
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.bitcoind.client.get_block_hash(0)?);
|
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.bitcoind.client.get_block_hash(0)?);
|
||||||
let mut recv_graph = IndexedTxGraph::<ConfirmationTimeHeightAnchor, _>::new({
|
let mut recv_graph = IndexedTxGraph::<ConfirmationBlockTime, _>::new({
|
||||||
let mut recv_index = SpkTxOutIndex::default();
|
let mut recv_index = SpkTxOutIndex::default();
|
||||||
recv_index.insert_spk((), spk_to_track.clone());
|
recv_index.insert_spk((), spk_to_track.clone());
|
||||||
recv_index
|
recv_index
|
||||||
@ -352,7 +352,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
// Setup receiver.
|
// Setup receiver.
|
||||||
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.bitcoind.client.get_block_hash(0)?);
|
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.bitcoind.client.get_block_hash(0)?);
|
||||||
let mut recv_graph = IndexedTxGraph::<ConfirmationTimeHeightAnchor, _>::new({
|
let mut recv_graph = IndexedTxGraph::<ConfirmationBlockTime, _>::new({
|
||||||
let mut recv_index = SpkTxOutIndex::default();
|
let mut recv_index = SpkTxOutIndex::default();
|
||||||
recv_index.insert_spk((), spk_to_track.clone());
|
recv_index.insert_spk((), spk_to_track.clone());
|
||||||
recv_index
|
recv_index
|
||||||
@ -362,9 +362,11 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
|
|||||||
env.mine_blocks(101, Some(addr_to_mine))?;
|
env.mine_blocks(101, Some(addr_to_mine))?;
|
||||||
|
|
||||||
// Create transactions that are tracked by our receiver.
|
// Create transactions that are tracked by our receiver.
|
||||||
|
let mut txids = vec![];
|
||||||
|
let mut hashes = vec![];
|
||||||
for _ in 0..REORG_COUNT {
|
for _ in 0..REORG_COUNT {
|
||||||
env.send(&addr_to_track, SEND_AMOUNT)?;
|
txids.push(env.send(&addr_to_track, SEND_AMOUNT)?);
|
||||||
env.mine_blocks(1, None)?;
|
hashes.extend(env.mine_blocks(1, None)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync up to tip.
|
// Sync up to tip.
|
||||||
@ -382,6 +384,13 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
// Retain a snapshot of all anchors before reorg process.
|
// Retain a snapshot of all anchors before reorg process.
|
||||||
let initial_anchors = update.graph_update.all_anchors();
|
let initial_anchors = update.graph_update.all_anchors();
|
||||||
|
let anchors: Vec<_> = initial_anchors.iter().cloned().collect();
|
||||||
|
assert_eq!(anchors.len(), REORG_COUNT);
|
||||||
|
for i in 0..REORG_COUNT {
|
||||||
|
let (anchor, txid) = anchors[i];
|
||||||
|
assert_eq!(anchor.block_id.hash, hashes[i]);
|
||||||
|
assert_eq!(txid, txids[i]);
|
||||||
|
}
|
||||||
|
|
||||||
// Check if initial balance is correct.
|
// Check if initial balance is correct.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -6,7 +6,7 @@ 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, ConfirmationBlockTime, TxGraph,
|
||||||
};
|
};
|
||||||
use bdk_chain::{Anchor, Indexed};
|
use bdk_chain::{Anchor, Indexed};
|
||||||
use esplora_client::{Amount, TxStatus};
|
use esplora_client::{Amount, TxStatus};
|
||||||
@ -240,10 +240,10 @@ async fn full_scan_for_index_and_graph<K: Ord + Clone + Send>(
|
|||||||
>,
|
>,
|
||||||
stop_gap: usize,
|
stop_gap: usize,
|
||||||
parallel_requests: usize,
|
parallel_requests: usize,
|
||||||
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> {
|
) -> Result<(TxGraph<ConfirmationBlockTime>, BTreeMap<K, u32>), Error> {
|
||||||
type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>);
|
type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>);
|
||||||
let parallel_requests = Ord::max(parallel_requests, 1);
|
let parallel_requests = Ord::max(parallel_requests, 1);
|
||||||
let mut graph = TxGraph::<ConfirmationTimeHeightAnchor>::default();
|
let mut graph = TxGraph::<ConfirmationBlockTime>::default();
|
||||||
let mut last_active_indexes = BTreeMap::<K, u32>::new();
|
let mut last_active_indexes = BTreeMap::<K, u32>::new();
|
||||||
|
|
||||||
for (keychain, spks) in keychain_spks {
|
for (keychain, spks) in keychain_spks {
|
||||||
@ -333,7 +333,7 @@ async fn sync_for_index_and_graph(
|
|||||||
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
|
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
|
||||||
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
|
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
|
||||||
parallel_requests: usize,
|
parallel_requests: usize,
|
||||||
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> {
|
) -> Result<TxGraph<ConfirmationBlockTime>, Error> {
|
||||||
let mut graph = full_scan_for_index_and_graph(
|
let mut graph = full_scan_for_index_and_graph(
|
||||||
client,
|
client,
|
||||||
[(
|
[(
|
||||||
|
@ -6,7 +6,7 @@ use bdk_chain::spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncRe
|
|||||||
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, ConfirmationBlockTime, TxGraph,
|
||||||
};
|
};
|
||||||
use bdk_chain::{Anchor, Indexed};
|
use bdk_chain::{Anchor, Indexed};
|
||||||
use esplora_client::TxStatus;
|
use esplora_client::TxStatus;
|
||||||
@ -219,10 +219,10 @@ fn full_scan_for_index_and_graph_blocking<K: Ord + Clone>(
|
|||||||
keychain_spks: BTreeMap<K, impl IntoIterator<Item = Indexed<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<ConfirmationBlockTime>, BTreeMap<K, u32>), Error> {
|
||||||
type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>);
|
type TxsOfSpkIndex = (u32, Vec<esplora_client::Tx>);
|
||||||
let parallel_requests = Ord::max(parallel_requests, 1);
|
let parallel_requests = Ord::max(parallel_requests, 1);
|
||||||
let mut tx_graph = TxGraph::<ConfirmationTimeHeightAnchor>::default();
|
let mut tx_graph = TxGraph::<ConfirmationBlockTime>::default();
|
||||||
let mut last_active_indices = BTreeMap::<K, u32>::new();
|
let mut last_active_indices = BTreeMap::<K, u32>::new();
|
||||||
|
|
||||||
for (keychain, spks) in keychain_spks {
|
for (keychain, spks) in keychain_spks {
|
||||||
@ -315,7 +315,7 @@ fn sync_for_index_and_graph_blocking(
|
|||||||
txids: impl IntoIterator<Item = Txid>,
|
txids: impl IntoIterator<Item = Txid>,
|
||||||
outpoints: impl IntoIterator<Item = OutPoint>,
|
outpoints: impl IntoIterator<Item = OutPoint>,
|
||||||
parallel_requests: usize,
|
parallel_requests: usize,
|
||||||
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> {
|
) -> Result<TxGraph<ConfirmationBlockTime>, Error> {
|
||||||
let (mut tx_graph, _) = full_scan_for_index_and_graph_blocking(
|
let (mut tx_graph, _) = full_scan_for_index_and_graph_blocking(
|
||||||
client,
|
client,
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
//! [`TxGraph`]: bdk_chain::tx_graph::TxGraph
|
//! [`TxGraph`]: bdk_chain::tx_graph::TxGraph
|
||||||
//! [`example_esplora`]: https://github.com/bitcoindevkit/bdk/tree/master/example-crates/example_esplora
|
//! [`example_esplora`]: https://github.com/bitcoindevkit/bdk/tree/master/example-crates/example_esplora
|
||||||
|
|
||||||
use bdk_chain::{BlockId, ConfirmationTimeHeightAnchor};
|
use bdk_chain::{BlockId, ConfirmationBlockTime};
|
||||||
use esplora_client::TxStatus;
|
use esplora_client::TxStatus;
|
||||||
|
|
||||||
pub use esplora_client;
|
pub use esplora_client;
|
||||||
@ -31,7 +31,7 @@ mod async_ext;
|
|||||||
#[cfg(feature = "async")]
|
#[cfg(feature = "async")]
|
||||||
pub use async_ext::*;
|
pub use async_ext::*;
|
||||||
|
|
||||||
fn anchor_from_status(status: &TxStatus) -> Option<ConfirmationTimeHeightAnchor> {
|
fn anchor_from_status(status: &TxStatus) -> Option<ConfirmationBlockTime> {
|
||||||
if let TxStatus {
|
if let TxStatus {
|
||||||
block_height: Some(height),
|
block_height: Some(height),
|
||||||
block_hash: Some(hash),
|
block_hash: Some(hash),
|
||||||
@ -39,9 +39,8 @@ fn anchor_from_status(status: &TxStatus) -> Option<ConfirmationTimeHeightAnchor>
|
|||||||
..
|
..
|
||||||
} = status.clone()
|
} = status.clone()
|
||||||
{
|
{
|
||||||
Some(ConfirmationTimeHeightAnchor {
|
Some(ConfirmationBlockTime {
|
||||||
anchor_block: BlockId { height, hash },
|
block_id: BlockId { height, hash },
|
||||||
confirmation_height: height,
|
|
||||||
confirmation_time: time,
|
confirmation_time: time,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -547,10 +547,7 @@ mod test {
|
|||||||
use bdk_chain::bitcoin::{secp256k1, BlockHash, OutPoint};
|
use bdk_chain::bitcoin::{secp256k1, BlockHash, OutPoint};
|
||||||
use bdk_chain::miniscript::Descriptor;
|
use bdk_chain::miniscript::Descriptor;
|
||||||
use bdk_chain::CombinedChangeSet;
|
use bdk_chain::CombinedChangeSet;
|
||||||
use bdk_chain::{
|
use bdk_chain::{indexed_tx_graph, tx_graph, BlockId, ConfirmationBlockTime, DescriptorExt};
|
||||||
indexed_tx_graph, tx_graph, BlockId, ConfirmationHeightAnchor,
|
|
||||||
ConfirmationTimeHeightAnchor, DescriptorExt,
|
|
||||||
};
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
@ -561,37 +558,15 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn insert_and_load_aggregate_changesets_with_confirmation_time_height_anchor() {
|
fn insert_and_load_aggregate_changesets_with_confirmation_block_time_anchor() {
|
||||||
let (test_changesets, agg_test_changesets) =
|
let (test_changesets, agg_test_changesets) =
|
||||||
create_test_changesets(&|height, time, hash| ConfirmationTimeHeightAnchor {
|
create_test_changesets(&|height, time, hash| ConfirmationBlockTime {
|
||||||
confirmation_height: height,
|
|
||||||
confirmation_time: time,
|
confirmation_time: time,
|
||||||
anchor_block: (height, hash).into(),
|
block_id: (height, hash).into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let conn = Connection::open_in_memory().expect("in memory connection");
|
let conn = Connection::open_in_memory().expect("in memory connection");
|
||||||
let mut store = Store::<Keychain, ConfirmationTimeHeightAnchor>::new(conn)
|
let mut store = Store::<Keychain, ConfirmationBlockTime>::new(conn)
|
||||||
.expect("create new memory db store");
|
|
||||||
|
|
||||||
test_changesets.iter().for_each(|changeset| {
|
|
||||||
store.write(changeset).expect("write changeset");
|
|
||||||
});
|
|
||||||
|
|
||||||
let agg_changeset = store.read().expect("aggregated changeset");
|
|
||||||
|
|
||||||
assert_eq!(agg_changeset, Some(agg_test_changesets));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn insert_and_load_aggregate_changesets_with_confirmation_height_anchor() {
|
|
||||||
let (test_changesets, agg_test_changesets) =
|
|
||||||
create_test_changesets(&|height, _time, hash| ConfirmationHeightAnchor {
|
|
||||||
confirmation_height: height,
|
|
||||||
anchor_block: (height, hash).into(),
|
|
||||||
});
|
|
||||||
|
|
||||||
let conn = Connection::open_in_memory().expect("in memory connection");
|
|
||||||
let mut store = Store::<Keychain, ConfirmationHeightAnchor>::new(conn)
|
|
||||||
.expect("create new memory db store");
|
.expect("create new memory db store");
|
||||||
|
|
||||||
test_changesets.iter().for_each(|changeset| {
|
test_changesets.iter().for_each(|changeset| {
|
||||||
|
@ -128,7 +128,7 @@ impl FullyNodedExport {
|
|||||||
let blockheight = if include_blockheight {
|
let blockheight = if include_blockheight {
|
||||||
wallet.transactions().next().map_or(0, |canonical_tx| {
|
wallet.transactions().next().map_or(0, |canonical_tx| {
|
||||||
match canonical_tx.chain_position {
|
match canonical_tx.chain_position {
|
||||||
bdk_chain::ChainPosition::Confirmed(a) => a.confirmation_height,
|
bdk_chain::ChainPosition::Confirmed(a) => a.block_id.height,
|
||||||
bdk_chain::ChainPosition::Unconfirmed(_) => 0,
|
bdk_chain::ChainPosition::Unconfirmed(_) => 0,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -214,7 +214,7 @@ mod test {
|
|||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use crate::std::string::ToString;
|
use crate::std::string::ToString;
|
||||||
use bdk_chain::{BlockId, ConfirmationTimeHeightAnchor};
|
use bdk_chain::{BlockId, ConfirmationBlockTime};
|
||||||
use bitcoin::hashes::Hash;
|
use bitcoin::hashes::Hash;
|
||||||
use bitcoin::{transaction, BlockHash, Network, Transaction};
|
use bitcoin::{transaction, BlockHash, Network, Transaction};
|
||||||
|
|
||||||
@ -233,15 +233,20 @@ mod test {
|
|||||||
};
|
};
|
||||||
let txid = transaction.compute_txid();
|
let txid = transaction.compute_txid();
|
||||||
let block_id = BlockId {
|
let block_id = BlockId {
|
||||||
height: 5001,
|
height: 5000,
|
||||||
hash: BlockHash::all_zeros(),
|
hash: BlockHash::all_zeros(),
|
||||||
};
|
};
|
||||||
wallet.insert_checkpoint(block_id).unwrap();
|
wallet.insert_checkpoint(block_id).unwrap();
|
||||||
|
wallet
|
||||||
|
.insert_checkpoint(BlockId {
|
||||||
|
height: 5001,
|
||||||
|
hash: BlockHash::all_zeros(),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
wallet.insert_tx(transaction);
|
wallet.insert_tx(transaction);
|
||||||
let anchor = ConfirmationTimeHeightAnchor {
|
let anchor = ConfirmationBlockTime {
|
||||||
confirmation_height: 5000,
|
|
||||||
confirmation_time: 0,
|
confirmation_time: 0,
|
||||||
anchor_block: block_id,
|
block_id,
|
||||||
};
|
};
|
||||||
let mut graph = TxGraph::default();
|
let mut graph = TxGraph::default();
|
||||||
let _ = graph.insert_anchor(txid, anchor);
|
let _ = graph.insert_anchor(txid, anchor);
|
||||||
|
@ -28,7 +28,7 @@ use bdk_chain::{
|
|||||||
},
|
},
|
||||||
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
|
||||||
tx_graph::{CanonicalTx, TxGraph, TxNode},
|
tx_graph::{CanonicalTx, TxGraph, TxNode},
|
||||||
BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut, Indexed,
|
BlockId, ChainPosition, ConfirmationBlockTime, ConfirmationTime, FullTxOut, Indexed,
|
||||||
IndexedTxGraph, Merge,
|
IndexedTxGraph, Merge,
|
||||||
};
|
};
|
||||||
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
||||||
@ -104,7 +104,7 @@ pub struct Wallet {
|
|||||||
signers: Arc<SignersContainer>,
|
signers: Arc<SignersContainer>,
|
||||||
change_signers: Arc<SignersContainer>,
|
change_signers: Arc<SignersContainer>,
|
||||||
chain: LocalChain,
|
chain: LocalChain,
|
||||||
indexed_graph: IndexedTxGraph<ConfirmationTimeHeightAnchor, KeychainTxOutIndex<KeychainKind>>,
|
indexed_graph: IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<KeychainKind>>,
|
||||||
stage: ChangeSet,
|
stage: ChangeSet,
|
||||||
network: Network,
|
network: Network,
|
||||||
secp: SecpCtx,
|
secp: SecpCtx,
|
||||||
@ -120,7 +120,7 @@ pub struct Update {
|
|||||||
pub last_active_indices: BTreeMap<KeychainKind, u32>,
|
pub last_active_indices: BTreeMap<KeychainKind, u32>,
|
||||||
|
|
||||||
/// Update for the wallet's internal [`TxGraph`].
|
/// Update for the wallet's internal [`TxGraph`].
|
||||||
pub graph: TxGraph<ConfirmationTimeHeightAnchor>,
|
pub graph: TxGraph<ConfirmationBlockTime>,
|
||||||
|
|
||||||
/// Update for the wallet's internal [`LocalChain`].
|
/// Update for the wallet's internal [`LocalChain`].
|
||||||
///
|
///
|
||||||
@ -149,7 +149,7 @@ impl From<SyncResult> for Update {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The changes made to a wallet by applying an [`Update`].
|
/// The changes made to a wallet by applying an [`Update`].
|
||||||
pub type ChangeSet = bdk_chain::CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>;
|
pub type ChangeSet = bdk_chain::CombinedChangeSet<KeychainKind, ConfirmationBlockTime>;
|
||||||
|
|
||||||
/// A derived address and the index it was found at.
|
/// A derived address and the index it was found at.
|
||||||
/// For convenience this automatically derefs to `Address`
|
/// For convenience this automatically derefs to `Address`
|
||||||
@ -1007,7 +1007,7 @@ impl Wallet {
|
|||||||
/// match canonical_tx.chain_position {
|
/// match canonical_tx.chain_position {
|
||||||
/// ChainPosition::Confirmed(anchor) => println!(
|
/// ChainPosition::Confirmed(anchor) => println!(
|
||||||
/// "tx is confirmed at height {}, we know this since {}:{} is in the best chain",
|
/// "tx is confirmed at height {}, we know this since {}:{} is in the best chain",
|
||||||
/// anchor.confirmation_height, anchor.anchor_block.height, anchor.anchor_block.hash,
|
/// anchor.block_id.height, anchor.block_id.height, anchor.block_id.hash,
|
||||||
/// ),
|
/// ),
|
||||||
/// ChainPosition::Unconfirmed(last_seen) => println!(
|
/// ChainPosition::Unconfirmed(last_seen) => println!(
|
||||||
/// "tx is last seen at {}, it is unconfirmed as it is not anchored in the best chain",
|
/// "tx is last seen at {}, it is unconfirmed as it is not anchored in the best chain",
|
||||||
@ -1020,7 +1020,7 @@ impl Wallet {
|
|||||||
pub fn get_tx(
|
pub fn get_tx(
|
||||||
&self,
|
&self,
|
||||||
txid: Txid,
|
txid: Txid,
|
||||||
) -> Option<CanonicalTx<'_, Arc<Transaction>, ConfirmationTimeHeightAnchor>> {
|
) -> Option<CanonicalTx<'_, Arc<Transaction>, ConfirmationBlockTime>> {
|
||||||
let graph = self.indexed_graph.graph();
|
let graph = self.indexed_graph.graph();
|
||||||
|
|
||||||
Some(CanonicalTx {
|
Some(CanonicalTx {
|
||||||
@ -1076,8 +1076,7 @@ impl Wallet {
|
|||||||
/// Iterate over the transactions in the wallet.
|
/// Iterate over the transactions in the wallet.
|
||||||
pub fn transactions(
|
pub fn transactions(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = CanonicalTx<'_, Arc<Transaction>, ConfirmationTimeHeightAnchor>> + '_
|
) -> impl Iterator<Item = CanonicalTx<'_, Arc<Transaction>, ConfirmationBlockTime>> + '_ {
|
||||||
{
|
|
||||||
self.indexed_graph
|
self.indexed_graph
|
||||||
.graph()
|
.graph()
|
||||||
.list_canonical_txs(&self.chain, self.chain.tip().block_id())
|
.list_canonical_txs(&self.chain, self.chain.tip().block_id())
|
||||||
@ -1807,7 +1806,7 @@ impl Wallet {
|
|||||||
.graph()
|
.graph()
|
||||||
.get_chain_position(&self.chain, chain_tip, input.previous_output.txid)
|
.get_chain_position(&self.chain, chain_tip, input.previous_output.txid)
|
||||||
.map(|chain_position| match chain_position {
|
.map(|chain_position| match chain_position {
|
||||||
ChainPosition::Confirmed(a) => a.confirmation_height,
|
ChainPosition::Confirmed(a) => a.block_id.height,
|
||||||
ChainPosition::Unconfirmed(_) => u32::MAX,
|
ChainPosition::Unconfirmed(_) => u32::MAX,
|
||||||
});
|
});
|
||||||
let current_height = sign_options
|
let current_height = sign_options
|
||||||
@ -2245,7 +2244,7 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference to the inner [`TxGraph`].
|
/// Get a reference to the inner [`TxGraph`].
|
||||||
pub fn tx_graph(&self) -> &TxGraph<ConfirmationTimeHeightAnchor> {
|
pub fn tx_graph(&self) -> &TxGraph<ConfirmationBlockTime> {
|
||||||
self.indexed_graph.graph()
|
self.indexed_graph.graph()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2253,7 +2252,7 @@ impl Wallet {
|
|||||||
/// because they haven't been broadcast.
|
/// because they haven't been broadcast.
|
||||||
pub fn unbroadcast_transactions(
|
pub fn unbroadcast_transactions(
|
||||||
&self,
|
&self,
|
||||||
) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, ConfirmationTimeHeightAnchor>> {
|
) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, ConfirmationBlockTime>> {
|
||||||
self.tx_graph().txs_with_no_anchor_or_last_seen()
|
self.tx_graph().txs_with_no_anchor_or_last_seen()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2373,8 +2372,8 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationTimeHeightAnchor>> for Wallet {
|
impl AsRef<bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime>> for Wallet {
|
||||||
fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph<ConfirmationTimeHeightAnchor> {
|
fn as_ref(&self) -> &bdk_chain::tx_graph::TxGraph<ConfirmationBlockTime> {
|
||||||
self.indexed_graph.graph()
|
self.indexed_graph.graph()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2413,7 +2412,7 @@ where
|
|||||||
fn new_local_utxo(
|
fn new_local_utxo(
|
||||||
keychain: KeychainKind,
|
keychain: KeychainKind,
|
||||||
derivation_index: u32,
|
derivation_index: u32,
|
||||||
full_txo: FullTxOut<ConfirmationTimeHeightAnchor>,
|
full_txo: FullTxOut<ConfirmationBlockTime>,
|
||||||
) -> LocalOutput {
|
) -> LocalOutput {
|
||||||
LocalOutput {
|
LocalOutput {
|
||||||
outpoint: full_txo.outpoint,
|
outpoint: full_txo.outpoint,
|
||||||
@ -2476,7 +2475,7 @@ macro_rules! floating_rate {
|
|||||||
macro_rules! doctest_wallet {
|
macro_rules! doctest_wallet {
|
||||||
() => {{
|
() => {{
|
||||||
use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
|
use $crate::bitcoin::{BlockHash, Transaction, absolute, TxOut, Network, hashes::Hash};
|
||||||
use $crate::chain::{ConfirmationTimeHeightAnchor, BlockId, TxGraph};
|
use $crate::chain::{ConfirmationBlockTime, BlockId, TxGraph};
|
||||||
use $crate::wallet::{Update, Wallet};
|
use $crate::wallet::{Update, Wallet};
|
||||||
use $crate::KeychainKind;
|
use $crate::KeychainKind;
|
||||||
let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
|
let descriptor = "tr([73c5da0a/86'/0'/0']tprv8fMn4hSKPRC1oaCPqxDb1JWtgkpeiQvZhsr8W2xuy3GEMkzoArcAWTfJxYb6Wj8XNNDWEjfYKK4wGQXh3ZUXhDF2NcnsALpWTeSwarJt7Vc/0/*)";
|
||||||
@ -2499,13 +2498,13 @@ macro_rules! doctest_wallet {
|
|||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
let txid = tx.txid();
|
let txid = tx.txid();
|
||||||
let block = BlockId { height: 1_000, hash: BlockHash::all_zeros() };
|
let block_id = BlockId { height: 500, hash: BlockHash::all_zeros() };
|
||||||
let _ = wallet.insert_checkpoint(block);
|
let _ = wallet.insert_checkpoint(block_id);
|
||||||
|
let _ = wallet.insert_checkpoint(BlockId { height: 1_000, hash: BlockHash::all_zeros() });
|
||||||
let _ = wallet.insert_tx(tx);
|
let _ = wallet.insert_tx(tx);
|
||||||
let anchor = ConfirmationTimeHeightAnchor {
|
let anchor = ConfirmationBlockTime {
|
||||||
confirmation_height: 500,
|
|
||||||
confirmation_time: 50_000,
|
confirmation_time: 50_000,
|
||||||
anchor_block: block,
|
block_id,
|
||||||
};
|
};
|
||||||
let mut graph = TxGraph::default();
|
let mut graph = TxGraph::default();
|
||||||
let _ = graph.insert_anchor(txid, anchor);
|
let _ = graph.insert_anchor(txid, anchor);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use bdk_chain::{BlockId, ConfirmationTime, ConfirmationTimeHeightAnchor, TxGraph};
|
use bdk_chain::{BlockId, ConfirmationBlockTime, ConfirmationTime, TxGraph};
|
||||||
use bdk_wallet::{
|
use bdk_wallet::{
|
||||||
wallet::{Update, Wallet},
|
wallet::{Update, Wallet},
|
||||||
KeychainKind, LocalOutput,
|
KeychainKind, LocalOutput,
|
||||||
@ -65,6 +65,12 @@ pub fn get_funded_wallet_with_change(descriptor: &str, change: &str) -> (Wallet,
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
wallet
|
||||||
|
.insert_checkpoint(BlockId {
|
||||||
|
height: 42,
|
||||||
|
hash: BlockHash::all_zeros(),
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
wallet
|
wallet
|
||||||
.insert_checkpoint(BlockId {
|
.insert_checkpoint(BlockId {
|
||||||
height: 1_000,
|
height: 1_000,
|
||||||
@ -205,9 +211,8 @@ pub fn insert_anchor_from_conf(wallet: &mut Wallet, txid: Txid, position: Confir
|
|||||||
.local_chain()
|
.local_chain()
|
||||||
.range(height..)
|
.range(height..)
|
||||||
.last()
|
.last()
|
||||||
.map(|anchor_cp| ConfirmationTimeHeightAnchor {
|
.map(|anchor_cp| ConfirmationBlockTime {
|
||||||
anchor_block: anchor_cp.block_id(),
|
block_id: anchor_cp.block_id(),
|
||||||
confirmation_height: height,
|
|
||||||
confirmation_time: time,
|
confirmation_time: time,
|
||||||
})
|
})
|
||||||
.expect("confirmation height cannot be greater than tip");
|
.expect("confirmation height cannot be greater than tip");
|
||||||
|
@ -16,7 +16,7 @@ use bdk_chain::{
|
|||||||
indexed_tx_graph,
|
indexed_tx_graph,
|
||||||
indexer::keychain_txout,
|
indexer::keychain_txout,
|
||||||
local_chain::{self, LocalChain},
|
local_chain::{self, LocalChain},
|
||||||
ConfirmationTimeHeightAnchor, IndexedTxGraph, Merge,
|
ConfirmationBlockTime, IndexedTxGraph, Merge,
|
||||||
};
|
};
|
||||||
use example_cli::{
|
use example_cli::{
|
||||||
anyhow,
|
anyhow,
|
||||||
@ -38,7 +38,7 @@ const DB_COMMIT_DELAY: Duration = Duration::from_secs(60);
|
|||||||
|
|
||||||
type ChangeSet = (
|
type ChangeSet = (
|
||||||
local_chain::ChangeSet,
|
local_chain::ChangeSet,
|
||||||
indexed_tx_graph::ChangeSet<ConfirmationTimeHeightAnchor, keychain_txout::ChangeSet<Keychain>>,
|
indexed_tx_graph::ChangeSet<ConfirmationBlockTime, keychain_txout::ChangeSet<Keychain>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -10,7 +10,7 @@ use bdk_chain::{
|
|||||||
indexer::keychain_txout,
|
indexer::keychain_txout,
|
||||||
local_chain::{self, LocalChain},
|
local_chain::{self, LocalChain},
|
||||||
spk_client::{FullScanRequest, SyncRequest},
|
spk_client::{FullScanRequest, SyncRequest},
|
||||||
ConfirmationHeightAnchor, Merge,
|
ConfirmationBlockTime, Merge,
|
||||||
};
|
};
|
||||||
use bdk_electrum::{
|
use bdk_electrum::{
|
||||||
electrum_client::{self, Client, ElectrumApi},
|
electrum_client::{self, Client, ElectrumApi},
|
||||||
@ -100,7 +100,7 @@ pub struct ScanOptions {
|
|||||||
|
|
||||||
type ChangeSet = (
|
type ChangeSet = (
|
||||||
local_chain::ChangeSet,
|
local_chain::ChangeSet,
|
||||||
indexed_tx_graph::ChangeSet<ConfirmationHeightAnchor, keychain_txout::ChangeSet<Keychain>>,
|
indexed_tx_graph::ChangeSet<ConfirmationBlockTime, keychain_txout::ChangeSet<Keychain>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@ -338,17 +338,12 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let chain_changeset = chain.apply_update(chain_update)?;
|
let chain_changeset = chain.apply_update(chain_update)?;
|
||||||
|
|
||||||
let mut indexed_tx_graph_changeset =
|
let mut indexed_tx_graph_changeset =
|
||||||
indexed_tx_graph::ChangeSet::<ConfirmationHeightAnchor, _>::default();
|
indexed_tx_graph::ChangeSet::<ConfirmationBlockTime, _>::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.merge(keychain_changeset.into());
|
indexed_tx_graph_changeset.merge(keychain_changeset.into());
|
||||||
}
|
}
|
||||||
indexed_tx_graph_changeset.merge(graph.apply_update(graph_update.map_anchors(|a| {
|
indexed_tx_graph_changeset.merge(graph.apply_update(graph_update));
|
||||||
ConfirmationHeightAnchor {
|
|
||||||
confirmation_height: a.confirmation_height,
|
|
||||||
anchor_block: a.anchor_block,
|
|
||||||
}
|
|
||||||
})));
|
|
||||||
|
|
||||||
(chain_changeset, indexed_tx_graph_changeset)
|
(chain_changeset, indexed_tx_graph_changeset)
|
||||||
};
|
};
|
||||||
|
@ -10,7 +10,7 @@ use bdk_chain::{
|
|||||||
indexer::keychain_txout,
|
indexer::keychain_txout,
|
||||||
local_chain::{self, LocalChain},
|
local_chain::{self, LocalChain},
|
||||||
spk_client::{FullScanRequest, SyncRequest},
|
spk_client::{FullScanRequest, SyncRequest},
|
||||||
ConfirmationTimeHeightAnchor, Merge,
|
ConfirmationBlockTime, Merge,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bdk_esplora::{esplora_client, EsploraExt};
|
use bdk_esplora::{esplora_client, EsploraExt};
|
||||||
@ -26,7 +26,7 @@ const DB_PATH: &str = ".bdk_esplora_example.db";
|
|||||||
|
|
||||||
type ChangeSet = (
|
type ChangeSet = (
|
||||||
local_chain::ChangeSet,
|
local_chain::ChangeSet,
|
||||||
indexed_tx_graph::ChangeSet<ConfirmationTimeHeightAnchor, keychain_txout::ChangeSet<Keychain>>,
|
indexed_tx_graph::ChangeSet<ConfirmationBlockTime, keychain_txout::ChangeSet<Keychain>>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Subcommand, Debug, Clone)]
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user