Skip to content

Commit

Permalink
feat(chain)!: wrap TxGraph txs with Arc
Browse files Browse the repository at this point in the history
Wrapping transactions as `Arc<Transaction>` allows us to share
transactions cheaply between the chain-source and receiving structures.
Therefore the chain-source can keep already-fetched transactions (save
bandwidth) and have a shared pointer to the transactions (save memory).

This is better than the current way we do things, which is to refer back
to the receiving structures mid-sync.

Documentation for `TxGraph` is also updated.
  • Loading branch information
evanlinjin committed Mar 15, 2024
1 parent 07be4cc commit ee66da1
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 159 deletions.
18 changes: 10 additions & 8 deletions crates/bdk/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,7 +942,7 @@ impl<D> Wallet<D> {
/// # let mut wallet: Wallet<()> = todo!();
/// # let txid:Txid = todo!();
/// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
/// let fee = wallet.calculate_fee(tx).expect("fee");
/// let fee = wallet.calculate_fee(&tx).expect("fee");
/// ```
///
/// ```rust, no_run
Expand Down Expand Up @@ -973,7 +973,7 @@ impl<D> Wallet<D> {
/// # let mut wallet: Wallet<()> = todo!();
/// # let txid:Txid = todo!();
/// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
/// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
/// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
/// ```
///
/// ```rust, no_run
Expand All @@ -982,7 +982,7 @@ impl<D> Wallet<D> {
/// # let mut wallet: Wallet<()> = todo!();
/// # let mut psbt: PartiallySignedTransaction = todo!();
/// let tx = &psbt.clone().extract_tx();
/// let fee_rate = wallet.calculate_fee_rate(tx).expect("fee rate");
/// let fee_rate = wallet.calculate_fee_rate(&tx).expect("fee rate");
/// ```
/// [`insert_txout`]: Self::insert_txout
pub fn calculate_fee_rate(&self, tx: &Transaction) -> Result<FeeRate, CalculateFeeError> {
Expand All @@ -1006,7 +1006,7 @@ impl<D> Wallet<D> {
/// # let mut wallet: Wallet<()> = todo!();
/// # let txid:Txid = todo!();
/// let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
/// let (sent, received) = wallet.sent_and_received(tx);
/// let (sent, received) = wallet.sent_and_received(&tx);
/// ```
///
/// ```rust, no_run
Expand Down Expand Up @@ -1067,7 +1067,7 @@ impl<D> Wallet<D> {
pub fn get_tx(
&self,
txid: Txid,
) -> Option<CanonicalTx<'_, Transaction, ConfirmationTimeHeightAnchor>> {
) -> Option<CanonicalTx<'_, Arc<Transaction>, ConfirmationTimeHeightAnchor>> {
let graph = self.indexed_graph.graph();

Some(CanonicalTx {
Expand Down Expand Up @@ -1169,7 +1169,8 @@ impl<D> Wallet<D> {
/// Iterate over the transactions in the wallet.
pub fn transactions(
&self,
) -> impl Iterator<Item = CanonicalTx<'_, Transaction, ConfirmationTimeHeightAnchor>> + '_ {
) -> impl Iterator<Item = CanonicalTx<'_, Arc<Transaction>, ConfirmationTimeHeightAnchor>> + '_
{
self.indexed_graph
.graph()
.list_chain_txs(&self.chain, self.chain.tip().block_id())
Expand Down Expand Up @@ -1673,6 +1674,7 @@ impl<D> Wallet<D> {
let mut tx = graph
.get_tx(txid)
.ok_or(BuildFeeBumpError::TransactionNotFound(txid))?
.as_ref()
.clone();

let pos = graph
Expand Down Expand Up @@ -1742,7 +1744,7 @@ impl<D> Wallet<D> {
sequence: Some(txin.sequence),
psbt_input: Box::new(psbt::Input {
witness_utxo: Some(txout.clone()),
non_witness_utxo: Some(prev_tx.clone()),
non_witness_utxo: Some(prev_tx.as_ref().clone()),
..Default::default()
}),
},
Expand Down Expand Up @@ -2283,7 +2285,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.as_ref().clone());
}
}
Ok(psbt_input)
Expand Down
19 changes: 11 additions & 8 deletions crates/bdk/tests/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,12 @@ fn test_get_funded_wallet_sent_and_received() {

let mut tx_amounts: Vec<(Txid, (u64, u64))> = wallet
.transactions()
.map(|ct| (ct.tx_node.txid, wallet.sent_and_received(ct.tx_node.tx)))
.map(|ct| (ct.tx_node.txid, wallet.sent_and_received(&ct.tx_node)))
.collect();
tx_amounts.sort_by(|a1, a2| a1.0.cmp(&a2.0));

let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
let (sent, received) = wallet.sent_and_received(tx);
let (sent, received) = wallet.sent_and_received(&tx);

// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
Expand All @@ -227,7 +227,7 @@ fn test_get_funded_wallet_tx_fees() {
let (wallet, txid) = get_funded_wallet(get_test_wpkh());

let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
let tx_fee = wallet.calculate_fee(tx).expect("transaction fee");
let tx_fee = wallet.calculate_fee(&tx).expect("transaction fee");

// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
Expand All @@ -240,7 +240,9 @@ fn test_get_funded_wallet_tx_fee_rate() {
let (wallet, txid) = get_funded_wallet(get_test_wpkh());

let tx = wallet.get_tx(txid).expect("transaction").tx_node.tx;
let tx_fee_rate = wallet.calculate_fee_rate(tx).expect("transaction fee rate");
let tx_fee_rate = wallet
.calculate_fee_rate(&tx)
.expect("transaction fee rate");

// The funded wallet contains a tx with a 76_000 sats input and two outputs, one spending 25_000
// to a foreign address and one returning 50_000 back to the wallet as change. The remaining 1000
Expand Down Expand Up @@ -1301,7 +1303,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
.add_foreign_utxo(
utxo2.outpoint,
psbt::Input {
non_witness_utxo: Some(tx1),
non_witness_utxo: Some(tx1.as_ref().clone()),
..Default::default()
},
satisfaction_weight
Expand All @@ -1314,7 +1316,7 @@ fn test_add_foreign_utxo_where_outpoint_doesnt_match_psbt_input() {
.add_foreign_utxo(
utxo2.outpoint,
psbt::Input {
non_witness_utxo: Some(tx2),
non_witness_utxo: Some(tx2.as_ref().clone()),
..Default::default()
},
satisfaction_weight
Expand Down Expand Up @@ -1378,7 +1380,7 @@ fn test_add_foreign_utxo_only_witness_utxo() {
let mut builder = builder.clone();
let tx2 = wallet2.get_tx(txid2).unwrap().tx_node.tx;
let psbt_input = psbt::Input {
non_witness_utxo: Some(tx2.clone()),
non_witness_utxo: Some(tx2.as_ref().clone()),
..Default::default()
};
builder
Expand Down Expand Up @@ -3006,7 +3008,8 @@ fn test_taproot_sign_using_non_witness_utxo() {
let mut psbt = builder.finish().unwrap();

psbt.inputs[0].witness_utxo = None;
psbt.inputs[0].non_witness_utxo = Some(wallet.get_tx(prev_txid).unwrap().tx_node.tx.clone());
psbt.inputs[0].non_witness_utxo =
Some(wallet.get_tx(prev_txid).unwrap().tx_node.as_ref().clone());
assert!(
psbt.inputs[0].non_witness_utxo.is_some(),
"Previous tx should be present in the database"
Expand Down
2 changes: 1 addition & 1 deletion crates/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ readme = "README.md"
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
bitcoin = { version = "0.30.0", default-features = false }
serde_crate = { package = "serde", version = "1", optional = true, features = ["derive"] }
serde_crate = { package = "serde", version = "1", optional = true, features = ["derive", "rc"] }

# Use hashbrown as a feature flag to have HashSet and HashMap from it.
hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
Expand Down
Loading

0 comments on commit ee66da1

Please sign in to comment.