Skip to content

Commit

Permalink
[bdk_chain_redesign] Introduce BlockAnchor trait
Browse files Browse the repository at this point in the history
* Introduce `GraphedTx` struct to access transaction data of graphed
  transactions.
* Ability to insert/access anchors and "seen at" values for graphed
  transactions.
* `Additions` now records changes to anchors and last_seen_at.
  • Loading branch information
evanlinjin committed Mar 24, 2023
1 parent 82f9cad commit 5ae5fe3
Show file tree
Hide file tree
Showing 21 changed files with 584 additions and 298 deletions.
47 changes: 27 additions & 20 deletions crates/bdk/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ pub use bdk_chain::keychain::Balance;
use bdk_chain::{
chain_graph,
keychain::{persist, KeychainChangeSet, KeychainScan, KeychainTracker},
sparse_chain, BlockId, ConfirmationTime,
sparse_chain,
tx_graph::GraphedTx,
BlockId, ConfirmationTime,
};
use bitcoin::consensus::encode::serialize;
use bitcoin::secp256k1::Secp256k1;
Expand Down Expand Up @@ -83,19 +85,19 @@ const COINBASE_MATURITY: u32 = 100;
pub struct Wallet<D = ()> {
signers: Arc<SignersContainer>,
change_signers: Arc<SignersContainer>,
keychain_tracker: KeychainTracker<KeychainKind, ConfirmationTime>,
persist: persist::Persist<KeychainKind, ConfirmationTime, D>,
keychain_tracker: KeychainTracker<KeychainKind, BlockId, ConfirmationTime>,
persist: persist::Persist<KeychainKind, BlockId, ConfirmationTime, D>,
network: Network,
secp: SecpCtx,
}

/// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources.
/// The type parameter `T` indicates the kind of transaction contained in the update. It's usually a [`bitcoin::Transaction`].
pub type Update = KeychainScan<KeychainKind, ConfirmationTime>;
pub type Update = KeychainScan<KeychainKind, BlockId, ConfirmationTime>;
/// Error indicating that something was wrong with an [`Update<T>`].
pub type UpdateError = chain_graph::UpdateError<ConfirmationTime>;
/// The changeset produced internally by applying an update
pub(crate) type ChangeSet = KeychainChangeSet<KeychainKind, ConfirmationTime>;
pub(crate) type ChangeSet = KeychainChangeSet<KeychainKind, BlockId, ConfirmationTime>;

/// The address index selection strategy to use to derived an address from the wallet's external
/// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
Expand Down Expand Up @@ -195,7 +197,7 @@ impl<D> Wallet<D> {
network: Network,
) -> Result<Self, NewError<D::LoadError>>
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
let secp = Secp256k1::new();

Expand Down Expand Up @@ -257,7 +259,7 @@ impl<D> Wallet<D> {
/// (i.e. does not end with /*) then the same address will always be returned for any [`AddressIndex`].
pub fn get_address(&mut self, address_index: AddressIndex) -> AddressInfo
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
self._get_address(address_index, KeychainKind::External)
}
Expand All @@ -271,14 +273,14 @@ impl<D> Wallet<D> {
/// be returned for any [`AddressIndex`].
pub fn get_internal_address(&mut self, address_index: AddressIndex) -> AddressInfo
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
self._get_address(address_index, KeychainKind::Internal)
}

fn _get_address(&mut self, address_index: AddressIndex, keychain: KeychainKind) -> AddressInfo
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
let keychain = self.map_keychain(keychain);
let txout_index = &mut self.keychain_tracker.txout_index;
Expand Down Expand Up @@ -453,7 +455,11 @@ impl<D> Wallet<D> {
let fee = inputs.map(|inputs| inputs.saturating_sub(outputs));

Some(TransactionDetails {
transaction: if include_raw { Some(tx.clone()) } else { None },
transaction: if include_raw {
Some(tx.tx.clone())
} else {
None
},
txid,
received,
sent,
Expand Down Expand Up @@ -518,7 +524,8 @@ impl<D> Wallet<D> {
/// unconfirmed transactions last.
pub fn transactions(
&self,
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, &Transaction)> + '_ {
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, GraphedTx<'_, Transaction, BlockId>)> + '_
{
self.keychain_tracker
.chain_graph()
.transactions_in_chain()
Expand Down Expand Up @@ -613,7 +620,7 @@ impl<D> Wallet<D> {
params: TxParams,
) -> Result<(psbt::PartiallySignedTransaction, TransactionDetails), Error>
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
let external_descriptor = self
.keychain_tracker
Expand Down Expand Up @@ -1027,7 +1034,7 @@ impl<D> Wallet<D> {
Some((ConfirmationTime::Confirmed { .. }, _tx)) => {
return Err(Error::TransactionConfirmed)
}
Some((_, tx)) => tx.clone(),
Some((_, tx)) => tx.tx.clone(),
};

if !tx
Expand Down Expand Up @@ -1085,7 +1092,7 @@ impl<D> Wallet<D> {
outpoint: txin.previous_output,
psbt_input: Box::new(psbt::Input {
witness_utxo: Some(txout.clone()),
non_witness_utxo: Some(prev_tx.clone()),
non_witness_utxo: Some(prev_tx.tx.clone()),
..Default::default()
}),
},
Expand Down Expand Up @@ -1613,7 +1620,7 @@ impl<D> Wallet<D> {
psbt_input.witness_utxo = Some(prev_tx.output[prev_output.vout as usize].clone());
}
if !desc.is_taproot() && (!desc.is_witness() || !only_witness_utxo) {
psbt_input.non_witness_utxo = Some(prev_tx.clone());
psbt_input.non_witness_utxo = Some(prev_tx.tx.clone());
}
}
Ok(psbt_input)
Expand Down Expand Up @@ -1687,7 +1694,7 @@ impl<D> Wallet<D> {
/// [`commit`]: Self::commit
pub fn apply_update(&mut self, update: Update) -> Result<(), UpdateError>
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
let changeset = self.keychain_tracker.apply_update(update)?;
self.persist.stage(changeset);
Expand All @@ -1699,7 +1706,7 @@ impl<D> Wallet<D> {
/// [`staged`]: Self::staged
pub fn commit(&mut self) -> Result<(), D::WriteError>
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
self.persist.commit()
}
Expand All @@ -1717,7 +1724,7 @@ impl<D> Wallet<D> {
}

/// Get a reference to the inner [`ChainGraph`](bdk_chain::chain_graph::ChainGraph).
pub fn as_chain_graph(&self) -> &bdk_chain::chain_graph::ChainGraph<ConfirmationTime> {
pub fn as_chain_graph(&self) -> &bdk_chain::chain_graph::ChainGraph<BlockId, ConfirmationTime> {
self.keychain_tracker.chain_graph()
}
}
Expand All @@ -1728,8 +1735,8 @@ impl<D> AsRef<bdk_chain::tx_graph::TxGraph> for Wallet<D> {
}
}

impl<D> AsRef<bdk_chain::chain_graph::ChainGraph<ConfirmationTime>> for Wallet<D> {
fn as_ref(&self) -> &bdk_chain::chain_graph::ChainGraph<ConfirmationTime> {
impl<D> AsRef<bdk_chain::chain_graph::ChainGraph<BlockId, ConfirmationTime>> for Wallet<D> {
fn as_ref(&self) -> &bdk_chain::chain_graph::ChainGraph<BlockId, ConfirmationTime> {
self.keychain_tracker.chain_graph()
}
}
Expand Down
3 changes: 2 additions & 1 deletion crates/bdk/src/wallet/tx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use crate::collections::BTreeMap;
use crate::collections::HashSet;
use alloc::{boxed::Box, rc::Rc, string::String, vec::Vec};
use bdk_chain::BlockId;
use bdk_chain::ConfirmationTime;
use core::cell::RefCell;
use core::marker::PhantomData;
Expand Down Expand Up @@ -526,7 +527,7 @@ impl<'a, D, Cs: CoinSelectionAlgorithm, Ctx: TxBuilderContext> TxBuilder<'a, D,
/// [`BIP174`]: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki
pub fn finish(self) -> Result<(Psbt, TransactionDetails), Error>
where
D: persist::PersistBackend<KeychainKind, ConfirmationTime>,
D: persist::PersistBackend<KeychainKind, BlockId, ConfirmationTime>,
{
self.wallet
.borrow_mut()
Expand Down
10 changes: 8 additions & 2 deletions crates/chain/src/chain_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use bitcoin::{hashes::Hash, BlockHash, OutPoint, TxOut, Txid};

use crate::{
sparse_chain::{self, ChainPosition},
COINBASE_MATURITY,
BlockAnchor, COINBASE_MATURITY,
};

/// Represents the height at which a transaction is confirmed.
Expand Down Expand Up @@ -118,7 +118,7 @@ impl ConfirmationTime {
}

/// A reference to a block in the canonical chain.
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
Expand All @@ -140,6 +140,12 @@ impl Default for BlockId {
}
}

impl BlockAnchor for BlockId {
fn anchor_block(&self) -> BlockId {
*self
}
}

impl From<(u32, BlockHash)> for BlockId {
fn from((height, hash): (u32, BlockHash)) -> Self {
Self { height, hash }
Expand Down
Loading

0 comments on commit 5ae5fe3

Please sign in to comment.