Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ members = [
"crates/file_store",
"crates/electrum",
"crates/esplora",
"crates/bitcoind_rpc",
"example-crates/example_cli",
"example-crates/example_electrum",
"example-crates/example_rpc",
"example-crates/wallet_electrum",
"example-crates/wallet_esplora",
"example-crates/wallet_esplora_async",
Expand Down
2 changes: 1 addition & 1 deletion crates/bdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ dev-getrandom-wasm = ["getrandom/js"]
lazy_static = "1.4"
env_logger = "0.7"
# Move back to importing from rust-bitcoin once https://github.com/rust-bitcoin/rust-bitcoin/pull/1342 is released
base64 = "^0.13"
base64 = "^0.21"
assert_matches = "1.5.0"

[package.metadata.docs.rs]
Expand Down
70 changes: 38 additions & 32 deletions crates/bdk/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub use bdk_chain::keychain::Balance;
use bdk_chain::{
indexed_tx_graph::IndexedAdditions,
keychain::{KeychainTxOutIndex, LocalChangeSet, LocalUpdate},
local_chain::{self, LocalChain, UpdateNotConnectedError},
local_chain::{self, CannotConnectError, CheckPoint, CheckPointIter, LocalChain},
tx_graph::{CanonicalTx, TxGraph},
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
IndexedTxGraph, Persist, PersistBackend,
Expand All @@ -32,8 +32,8 @@ use bitcoin::consensus::encode::serialize;
use bitcoin::secp256k1::Secp256k1;
use bitcoin::util::psbt;
use bitcoin::{
Address, BlockHash, EcdsaSighashType, LockTime, Network, OutPoint, SchnorrSighashType, Script,
Sequence, Transaction, TxOut, Txid, Witness,
Address, EcdsaSighashType, LockTime, Network, OutPoint, SchnorrSighashType, Script, Sequence,
Transaction, TxOut, Txid, Witness,
};
use core::fmt;
use core::ops::Deref;
Expand Down Expand Up @@ -245,7 +245,7 @@ impl<D> Wallet<D> {
};

let changeset = db.load_from_persistence().map_err(NewError::Persist)?;
chain.apply_changeset(changeset.chain_changeset);
chain.apply_changeset(&changeset.chain_changeset);
indexed_graph.apply_additions(changeset.indexed_additions);

let persist = Persist::new(db);
Expand Down Expand Up @@ -370,19 +370,19 @@ impl<D> Wallet<D> {
.graph()
.filter_chain_unspents(
&self.chain,
self.chain.tip().unwrap_or_default(),
self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default(),
self.indexed_graph.index.outpoints().iter().cloned(),
)
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
}

/// Get all the checkpoints the wallet is currently storing indexed by height.
pub fn checkpoints(&self) -> &BTreeMap<u32, BlockHash> {
self.chain.blocks()
pub fn checkpoints(&self) -> CheckPointIter {
self.chain.iter_checkpoints(None)
}

/// Returns the latest checkpoint.
pub fn latest_checkpoint(&self) -> Option<BlockId> {
pub fn latest_checkpoint(&self) -> Option<CheckPoint> {
self.chain.tip()
}

Expand Down Expand Up @@ -420,7 +420,7 @@ impl<D> Wallet<D> {
.graph()
.filter_chain_unspents(
&self.chain,
self.chain.tip().unwrap_or_default(),
self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default(),
core::iter::once((spk_i, op)),
)
.map(|((k, i), full_txo)| new_local_utxo(k, i, full_txo))
Expand All @@ -437,7 +437,7 @@ impl<D> Wallet<D> {
let canonical_tx = CanonicalTx {
observed_as: graph.get_chain_position(
&self.chain,
self.chain.tip().unwrap_or_default(),
self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default(),
txid,
)?,
node: graph.get_tx_node(txid)?,
Expand All @@ -460,7 +460,7 @@ impl<D> Wallet<D> {
pub fn insert_checkpoint(
&mut self,
block_id: BlockId,
) -> Result<bool, local_chain::InsertBlockNotMatchingError>
) -> Result<bool, local_chain::InsertBlockError>
where
D: PersistBackend<ChangeSet>,
{
Expand Down Expand Up @@ -500,18 +500,15 @@ impl<D> Wallet<D> {
// anchor tx to checkpoint with lowest height that is >= position's height
let anchor = self
.chain
.blocks()
.checkpoints()
.range(height..)
.next()
.ok_or(InsertTxError::ConfirmationHeightCannotBeGreaterThanTip {
tip_height: self.chain.tip().map(|b| b.height),
tip_height: self.chain.tip().map(|b| b.height()),
tx_height: height,
})
.map(|(&anchor_height, &anchor_hash)| ConfirmationTimeAnchor {
anchor_block: BlockId {
height: anchor_height,
hash: anchor_hash,
},
.map(|(&_, cp)| ConfirmationTimeAnchor {
anchor_block: cp.block_id(),
confirmation_height: height,
confirmation_time: time,
})?;
Expand All @@ -531,17 +528,18 @@ impl<D> Wallet<D> {
pub fn transactions(
&self,
) -> impl Iterator<Item = CanonicalTx<'_, Transaction, ConfirmationTimeAnchor>> + '_ {
self.indexed_graph
.graph()
.list_chain_txs(&self.chain, self.chain.tip().unwrap_or_default())
self.indexed_graph.graph().list_chain_txs(
&self.chain,
self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default(),
)
}

/// Return the balance, separated into available, trusted-pending, untrusted-pending and immature
/// values.
pub fn get_balance(&self) -> Balance {
self.indexed_graph.graph().balance(
&self.chain,
self.chain.tip().unwrap_or_default(),
self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default(),
self.indexed_graph.index.outpoints().iter().cloned(),
|&(k, _), _| k == KeychainKind::Internal,
)
Expand Down Expand Up @@ -715,8 +713,7 @@ impl<D> Wallet<D> {
None => self
.chain
.tip()
.and_then(|cp| cp.height.into())
.map(|height| LockTime::from_height(height).expect("Invalid height")),
.map(|cp| LockTime::from_height(cp.height()).expect("Invalid height")),
h => h,
};

Expand Down Expand Up @@ -1030,7 +1027,7 @@ impl<D> Wallet<D> {
) -> Result<TxBuilder<'_, D, DefaultCoinSelectionAlgorithm, BumpFee>, Error> {
let graph = self.indexed_graph.graph();
let txout_index = &self.indexed_graph.index;
let chain_tip = self.chain.tip().unwrap_or_default();
let chain_tip = self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default();

let mut tx = graph
.get_tx(txid)
Expand Down Expand Up @@ -1265,7 +1262,7 @@ impl<D> Wallet<D> {
psbt: &mut psbt::PartiallySignedTransaction,
sign_options: SignOptions,
) -> Result<bool, Error> {
let chain_tip = self.chain.tip().unwrap_or_default();
let chain_tip = self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default();

let tx = &psbt.unsigned_tx;
let mut finished = true;
Expand All @@ -1288,7 +1285,7 @@ impl<D> Wallet<D> {
});
let current_height = sign_options
.assume_height
.or(self.chain.tip().map(|b| b.height));
.or(self.chain.tip().map(|b| b.height()));

debug!(
"Input #{} - {}, using `confirmation_height` = {:?}, `current_height` = {:?}",
Expand Down Expand Up @@ -1433,7 +1430,7 @@ impl<D> Wallet<D> {
must_only_use_confirmed_tx: bool,
current_height: Option<u32>,
) -> (Vec<WeightedUtxo>, Vec<WeightedUtxo>) {
let chain_tip = self.chain.tip().unwrap_or_default();
let chain_tip = self.chain.tip().map(|cp| cp.block_id()).unwrap_or_default();
// must_spend <- manually selected utxos
// may_spend <- all other available utxos
let mut may_spend = self.get_available_utxos();
Expand Down Expand Up @@ -1697,24 +1694,33 @@ impl<D> Wallet<D> {
}

/// Applies an update to the wallet and stages the changes (but does not [`commit`] them).
/// Returns whether the `update` resulted in any changes.
///
/// This returns whether the `update` resulted in any changes.
/// If `prune` is set, irrelevant transactions are pruned. Relevant transactions change the UTXO
/// set of tracked script pubkeys (script pubkeys derived from tracked descriptors).
///
/// Usually you create an `update` by interacting with some blockchain data source and inserting
/// transactions related to your wallet into it.
///
/// [`commit`]: Self::commit
pub fn apply_update(&mut self, update: Update) -> Result<bool, UpdateNotConnectedError>
pub fn apply_update(&mut self, update: Update, prune: bool) -> Result<bool, CannotConnectError>
where
D: PersistBackend<ChangeSet>,
{
let mut changeset: ChangeSet = self.chain.apply_update(update.chain)?.into();
let mut changeset = ChangeSet::from(self.chain.update(update.tip)?);
let (_, index_additions) = self
.indexed_graph
.index
.reveal_to_target_multi(&update.keychain);
changeset.append(ChangeSet::from(IndexedAdditions::from(index_additions)));
changeset.append(self.indexed_graph.apply_update(update.graph).into());
changeset.append(
if prune {
self.indexed_graph.prune_and_apply_update(update.graph)
} else {
self.indexed_graph.apply_update(update.graph)
}
.into(),
);

let changed = !changeset.is_empty();
self.persist.stage(changeset);
Expand Down
9 changes: 6 additions & 3 deletions crates/bdk/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ fn receive_output(wallet: &mut Wallet, value: u64, height: ConfirmationTime) ->

fn receive_output_in_latest_block(wallet: &mut Wallet, value: u64) -> OutPoint {
let height = match wallet.latest_checkpoint() {
Some(BlockId { height, .. }) => ConfirmationTime::Confirmed { height, time: 0 },
Some(cp) => ConfirmationTime::Confirmed {
height: cp.height(),
time: 0,
},
None => ConfirmationTime::Unconfirmed { last_seen: 0 },
};
receive_output(wallet, value, height)
Expand Down Expand Up @@ -222,7 +225,7 @@ fn test_create_tx_fee_sniping_locktime_last_sync() {
// If there's no current_height we're left with using the last sync height
assert_eq!(
psbt.unsigned_tx.lock_time.0,
wallet.latest_checkpoint().unwrap().height
wallet.latest_checkpoint().unwrap().height()
);
}

Expand Down Expand Up @@ -1482,7 +1485,7 @@ fn test_bump_fee_drain_wallet() {
.insert_tx(
tx.clone(),
ConfirmationTime::Confirmed {
height: wallet.latest_checkpoint().unwrap().height,
height: wallet.latest_checkpoint().unwrap().height(),
time: 42_000,
},
)
Expand Down
11 changes: 11 additions & 0 deletions crates/bitcoind_rpc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "bdk_bitcoind_rpc"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
bdk_chain = { path = "../chain", version = "0.4.0", features = ["serde", "miniscript"] }
bitcoincore-rpc = { version = "0.16" }
anyhow = { version = "1" }
Loading