Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change methods of IndexedTxGraph/TxGraph/Wallet that insert txs to be more generic #1586

Merged
merged 3 commits into from
Sep 9, 2024
Merged
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
48 changes: 24 additions & 24 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//! [`IndexedTxGraph`] documentation for more.
use core::fmt::Debug;

use alloc::vec::Vec;
use alloc::{sync::Arc, vec::Vec};
use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};

use crate::{
Expand Down Expand Up @@ -133,13 +133,10 @@ where
}

/// Insert and index a transaction into the graph.
pub fn insert_tx(&mut self, tx: Transaction) -> ChangeSet<A, I::ChangeSet> {
let graph = self.graph.insert_tx(tx);
let indexer = self.index_tx_graph_changeset(&graph);
ChangeSet {
tx_graph: graph,
indexer,
}
pub fn insert_tx<T: Into<Arc<Transaction>>>(&mut self, tx: T) -> ChangeSet<A, I::ChangeSet> {
let tx_graph = self.graph.insert_tx(tx);
let indexer = self.index_tx_graph_changeset(&tx_graph);
ChangeSet { tx_graph, indexer }
}

/// Insert an `anchor` for a given transaction.
Expand All @@ -159,38 +156,38 @@ where
///
/// Relevancy is determined by the [`Indexer::is_tx_relevant`] implementation of `I`. Irrelevant
/// transactions in `txs` will be ignored. `txs` do not need to be in topological order.
pub fn batch_insert_relevant<'t>(
pub fn batch_insert_relevant<T: Into<Arc<Transaction>>>(
&mut self,
txs: impl IntoIterator<Item = (&'t Transaction, impl IntoIterator<Item = A>)>,
txs: impl IntoIterator<Item = (T, impl IntoIterator<Item = A>)>,
) -> ChangeSet<A, I::ChangeSet> {
// The algorithm below allows for non-topologically ordered transactions by using two loops.
// This is achieved by:
// 1. insert all txs into the index. If they are irrelevant then that's fine it will just
// not store anything about them.
// 2. decide whether to insert them into the graph depending on whether `is_tx_relevant`
// returns true or not. (in a second loop).
let txs = txs.into_iter().collect::<Vec<_>>();
let txs = txs
.into_iter()
.map(|(tx, anchors)| (<T as Into<Arc<Transaction>>>::into(tx), anchors))
.collect::<Vec<_>>();

let mut indexer = I::ChangeSet::default();
for (tx, _) in &txs {
indexer.merge(self.index.index_tx(tx));
}

let mut graph = tx_graph::ChangeSet::default();
let mut tx_graph = tx_graph::ChangeSet::default();
for (tx, anchors) in txs {
if self.index.is_tx_relevant(tx) {
if self.index.is_tx_relevant(&tx) {
let txid = tx.compute_txid();
graph.merge(self.graph.insert_tx(tx.clone()));
tx_graph.merge(self.graph.insert_tx(tx.clone()));
for anchor in anchors {
graph.merge(self.graph.insert_anchor(txid, anchor));
tx_graph.merge(self.graph.insert_anchor(txid, anchor));
}
}
}

ChangeSet {
tx_graph: graph,
indexer,
}
ChangeSet { tx_graph, indexer }
}

/// Batch insert unconfirmed transactions, filtering out those that are irrelevant.
Expand All @@ -201,17 +198,20 @@ where
/// Items of `txs` are tuples containing the transaction and a *last seen* timestamp. The
/// *last seen* communicates when the transaction is last seen in the mempool which is used for
/// conflict-resolution in [`TxGraph`] (refer to [`TxGraph::insert_seen_at`] for details).
pub fn batch_insert_relevant_unconfirmed<'t>(
pub fn batch_insert_relevant_unconfirmed<T: Into<Arc<Transaction>>>(
&mut self,
unconfirmed_txs: impl IntoIterator<Item = (&'t Transaction, u64)>,
unconfirmed_txs: impl IntoIterator<Item = (T, u64)>,
) -> ChangeSet<A, I::ChangeSet> {
// The algorithm below allows for non-topologically ordered transactions by using two loops.
// This is achieved by:
// 1. insert all txs into the index. If they are irrelevant then that's fine it will just
// not store anything about them.
// 2. decide whether to insert them into the graph depending on whether `is_tx_relevant`
// returns true or not. (in a second loop).
let txs = unconfirmed_txs.into_iter().collect::<Vec<_>>();
let txs = unconfirmed_txs
.into_iter()
.map(|(tx, last_seen)| (<T as Into<Arc<Transaction>>>::into(tx), last_seen))
.collect::<Vec<_>>();

let mut indexer = I::ChangeSet::default();
for (tx, _) in &txs {
Expand Down Expand Up @@ -239,9 +239,9 @@ where
/// To filter out irrelevant transactions, use [`batch_insert_relevant_unconfirmed`] instead.
///
/// [`batch_insert_relevant_unconfirmed`]: IndexedTxGraph::batch_insert_relevant_unconfirmed
pub fn batch_insert_unconfirmed(
pub fn batch_insert_unconfirmed<T: Into<Arc<Transaction>>>(
&mut self,
txs: impl IntoIterator<Item = (Transaction, u64)>,
txs: impl IntoIterator<Item = (T, u64)>,
) -> ChangeSet<A, I::ChangeSet> {
let graph = self.graph.batch_insert_unconfirmed(txs);
let indexer = self.index_tx_graph_changeset(&graph);
Expand Down
5 changes: 3 additions & 2 deletions crates/chain/src/tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,13 @@ impl<A: Clone + Ord> TxGraph<A> {
/// Items of `txs` are tuples containing the transaction and a *last seen* timestamp. The
/// *last seen* communicates when the transaction is last seen in mempool which is used for
/// conflict-resolution (refer to [`TxGraph::insert_seen_at`] for details).
pub fn batch_insert_unconfirmed(
pub fn batch_insert_unconfirmed<T: Into<Arc<Transaction>>>(
&mut self,
txs: impl IntoIterator<Item = (Transaction, u64)>,
txs: impl IntoIterator<Item = (T, u64)>,
) -> ChangeSet<A> {
let mut changeset = ChangeSet::<A>::default();
for (tx, seen_at) in txs {
let tx: Arc<Transaction> = tx.into();
changeset.merge(self.insert_seen_at(tx.compute_txid(), seen_at));
changeset.merge(self.insert_tx(tx));
}
Expand Down
9 changes: 5 additions & 4 deletions crates/chain/tests/test_indexed_tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn insert_relevant_txs() {
};

assert_eq!(
graph.batch_insert_relevant(txs.iter().map(|tx| (tx, None))),
graph.batch_insert_relevant(txs.iter().cloned().map(|tx| (tx, None))),
changeset,
);

Expand Down Expand Up @@ -237,10 +237,10 @@ fn test_list_owned_txouts() {
// Insert unconfirmed txs with a last_seen timestamp

let _ =
graph.batch_insert_relevant([&tx1, &tx2, &tx3, &tx6].iter().enumerate().map(|(i, tx)| {
graph.batch_insert_relevant([&tx1, &tx2, &tx3, &tx6].iter().enumerate().map(|(i, &tx)| {
let height = i as u32;
(
*tx,
tx.clone(),
local_chain
.get(height)
.map(|cp| cp.block_id())
Expand All @@ -251,7 +251,8 @@ fn test_list_owned_txouts() {
)
}));

let _ = graph.batch_insert_relevant_unconfirmed([&tx4, &tx5].iter().map(|tx| (*tx, 100)));
let _ =
graph.batch_insert_relevant_unconfirmed([&tx4, &tx5].iter().map(|&tx| (tx.clone(), 100)));

// A helper lambda to extract and filter data from the graph.
let fetch =
Expand Down
6 changes: 3 additions & 3 deletions crates/wallet/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1093,7 +1093,7 @@ impl Wallet {
/// By default the inserted `tx` won't be considered "canonical" because it's not known
/// whether the transaction exists in the best chain. To know whether it exists, the tx
/// must be broadcast to the network and the wallet synced via a chain source.
pub fn insert_tx(&mut self, tx: Transaction) -> bool {
pub fn insert_tx<T: Into<Arc<Transaction>>>(&mut self, tx: T) -> bool {
let mut changeset = ChangeSet::default();
changeset.merge(self.indexed_graph.insert_tx(tx).into());
let ret = !changeset.is_empty();
Expand Down Expand Up @@ -2441,9 +2441,9 @@ impl Wallet {
/// **WARNING**: You must persist the changes resulting from one or more calls to this method
/// if you need the applied unconfirmed transactions to be reloaded after closing the wallet.
/// See [`Wallet::reveal_next_address`].
pub fn apply_unconfirmed_txs<'t>(
pub fn apply_unconfirmed_txs<T: Into<Arc<Transaction>>>(
&mut self,
unconfirmed_txs: impl IntoIterator<Item = (&'t Transaction, u64)>,
unconfirmed_txs: impl IntoIterator<Item = (T, u64)>,
) {
let indexed_graph_changeset = self
.indexed_graph
Expand Down
11 changes: 5 additions & 6 deletions example-crates/example_bitcoind_rpc_polling/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,9 +201,10 @@ fn main() -> anyhow::Result<()> {
}

let mempool_txs = emitter.mempool()?;
let graph_changeset = graph.lock().unwrap().batch_insert_relevant_unconfirmed(
mempool_txs.iter().map(|(tx, time)| (tx, *time)),
);
let graph_changeset = graph
.lock()
.unwrap()
.batch_insert_relevant_unconfirmed(mempool_txs);
{
let db = &mut *db.lock().unwrap();
db_stage.merge(ChangeSet {
Expand Down Expand Up @@ -286,9 +287,7 @@ fn main() -> anyhow::Result<()> {
(chain_changeset, graph_changeset)
}
Emission::Mempool(mempool_txs) => {
let graph_changeset = graph.batch_insert_relevant_unconfirmed(
mempool_txs.iter().map(|(tx, time)| (tx, *time)),
);
let graph_changeset = graph.batch_insert_relevant_unconfirmed(mempool_txs);
(local_chain::ChangeSet::default(), graph_changeset)
}
Emission::Tip(h) => {
Expand Down
2 changes: 1 addition & 1 deletion example-crates/wallet_rpc/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ fn main() -> anyhow::Result<()> {
}
Emission::Mempool(mempool_emission) => {
let start_apply_mempool = Instant::now();
wallet.apply_unconfirmed_txs(mempool_emission.iter().map(|(tx, time)| (tx, *time)));
wallet.apply_unconfirmed_txs(mempool_emission);
wallet.persist(&mut db)?;
println!(
"Applied unconfirmed transactions in {}s",
Expand Down
Loading