Skip to content

Commit 1f43163

Browse files
committed
wip: add bench tests
1 parent 27a0c9b commit 1f43163

File tree

2 files changed

+136
-48
lines changed

2 files changed

+136
-48
lines changed

bench/benches/bench.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@ extern crate criterion;
33

44
use criterion::{criterion_group, criterion_main};
55

6-
criterion_group!(benches, bdk_chain::tx_graph::bench::filter_chain_unspents);
6+
criterion_group!(benches,
7+
bdk_chain::tx_graph::bench::filter_chain_unspents,
8+
bdk_chain::tx_graph::bench::list_canonical_txs,
9+
);
710
criterion_main!(benches);

crates/chain/src/tx_graph.rs

Lines changed: 132 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,67 +1554,55 @@ fn tx_outpoint_range(txid: Txid) -> RangeInclusive<OutPoint> {
15541554
OutPoint::new(txid, u32::MIN)..=OutPoint::new(txid, u32::MAX)
15551555
}
15561556

1557-
/// Bench
1558-
#[allow(unused)]
1559-
#[allow(missing_docs)]
15601557
#[cfg(bdk_bench)]
1561-
pub mod bench {
1562-
use std::str::FromStr;
1563-
1558+
mod bench_util {
15641559
use bdk_core::{CheckPoint, ConfirmationBlockTime};
1565-
use bitcoin::absolute;
1566-
use bitcoin::hashes::Hash;
1567-
use bitcoin::transaction;
1568-
use bitcoin::{Address, BlockHash, Network, TxIn};
1569-
use criterion::Criterion;
1570-
use miniscript::Descriptor;
1571-
use miniscript::DescriptorPublicKey;
1560+
use bitcoin::{
1561+
absolute, constants, hashes::Hash, secp256k1::Secp256k1, transaction, BlockHash, Network,
1562+
TxIn,
1563+
};
1564+
use miniscript::{Descriptor, DescriptorPublicKey};
15721565

15731566
use super::*;
15741567
use crate::keychain_txout::KeychainTxOutIndex;
15751568
use crate::local_chain::LocalChain;
15761569
use crate::IndexedTxGraph;
15771570

15781571
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1579-
enum Keychain {
1572+
pub enum Keychain {
15801573
External,
15811574
}
15821575

15831576
const EXTERNAL: &str = "tr([ab28dc00/86h/1h/0h]tpubDCdDtzAMZZrkwKBxwNcGCqe4FRydeD9rfMisoi7qLdraG79YohRfPW4YgdKQhpgASdvh612xXNY5xYzoqnyCgPbkpK4LSVcH5Xv4cK7johH/0/*)";
15841577

1585-
fn get_params() -> (
1586-
IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<Keychain>>,
1587-
LocalChain,
1588-
) {
1589-
let genesis = bitcoin::constants::genesis_block(Network::Regtest).block_hash();
1578+
type KeychainTxGraph = IndexedTxGraph<ConfirmationBlockTime, KeychainTxOutIndex<Keychain>>;
1579+
1580+
pub fn init_graph_chain() -> (KeychainTxGraph, LocalChain) {
1581+
let genesis = constants::genesis_block(Network::Regtest).block_hash();
15901582
let block_0 = BlockId {
15911583
height: 0,
15921584
hash: genesis,
15931585
};
1586+
// chain tip 100
15941587
let mut cp = CheckPoint::new(block_0);
1595-
let block_100 = BlockId {
1588+
let chain_tip = BlockId {
15961589
height: 100,
15971590
hash: BlockHash::all_zeros(),
15981591
};
1599-
cp = cp.push(block_100).unwrap();
1592+
cp = cp.push(chain_tip).unwrap();
16001593
let chain = LocalChain::from_tip(cp).unwrap();
16011594

1602-
let mut graph = IndexedTxGraph::new({
1603-
let mut index = KeychainTxOutIndex::new(10);
1604-
index
1605-
.insert_descriptor(Keychain::External, parse_descriptor(EXTERNAL))
1606-
.unwrap();
1607-
index
1608-
});
1595+
let desc = parse_descriptor(EXTERNAL);
1596+
let spk_0 = desc.at_derivation_index(0).unwrap().script_pubkey();
1597+
let mut index = KeychainTxOutIndex::new(10);
1598+
index.insert_descriptor(Keychain::External, desc).unwrap();
1599+
let mut graph = IndexedTxGraph::new(index);
16091600

1610-
// insert funding tx (coinbase)
1611-
let addr_0 =
1612-
Address::from_str("bcrt1plhmjhj75nut38qwwm5w7xqysy25xhd4ckuv7zu5tey3nkmcwh3cqvan5mz")
1613-
.unwrap()
1614-
.assume_checked();
1601+
// insert funding tx (coinbase) confirmed at chain tip
16151602
let tx_0 = Transaction {
1603+
input: vec![TxIn::default()],
16161604
output: vec![TxOut {
1617-
script_pubkey: addr_0.script_pubkey(),
1605+
script_pubkey: spk_0.clone(),
16181606
value: Amount::ONE_BTC,
16191607
}],
16201608
..new_tx(0)
@@ -1624,43 +1612,140 @@ pub mod bench {
16241612
let _ = graph.insert_anchor(
16251613
txid_0,
16261614
ConfirmationBlockTime {
1627-
block_id: block_100,
1615+
block_id: chain_tip,
16281616
confirmation_time: 100,
16291617
},
16301618
);
16311619

16321620
(graph, chain)
16331621
}
16341622

1635-
fn parse_descriptor(s: &str) -> miniscript::Descriptor<DescriptorPublicKey> {
1636-
<Descriptor<DescriptorPublicKey>>::parse_descriptor(
1637-
&bitcoin::secp256k1::Secp256k1::new(),
1638-
s,
1639-
)
1640-
.unwrap()
1641-
.0
1623+
/// Add `n` conflicts to `graph` that spend the given `previous_output`, incrementing
1624+
/// the tx last-seen on each iteration.
1625+
pub fn add_conflicts(n: u32, graph: &mut KeychainTxGraph, previous_output: OutPoint) {
1626+
let spk_1 = parse_descriptor(EXTERNAL)
1627+
.at_derivation_index(1)
1628+
.unwrap()
1629+
.script_pubkey();
1630+
for i in 1..n + 1 {
1631+
let value = Amount::ONE_BTC - Amount::from_sat(i as u64 * 10);
1632+
let tx = Transaction {
1633+
input: vec![TxIn {
1634+
previous_output,
1635+
..Default::default()
1636+
}],
1637+
output: vec![TxOut {
1638+
value,
1639+
script_pubkey: spk_1.clone(),
1640+
}],
1641+
..new_tx(i)
1642+
};
1643+
let txid = tx.compute_txid();
1644+
let _ = graph.insert_tx(tx);
1645+
let _ = graph.insert_seen_at(txid, i as u64);
1646+
}
16421647
}
16431648

1644-
fn new_tx(lt: u32) -> Transaction {
1649+
/// Apply a chain of `n` unconfirmed txs where each subsequent
1650+
/// tx spends the output of the previous one.
1651+
pub fn chain_unconfirmed(n: u32, graph: &mut KeychainTxGraph) {
1652+
let (mut previous_output, txout) = graph
1653+
.graph()
1654+
.all_txouts()
1655+
.find(|(_, txout)| txout.value == Amount::ONE_BTC)
1656+
.expect("initial graph should have txout");
1657+
let init_amount = txout.value;
1658+
let fee = Amount::from_sat(1000);
1659+
1660+
let desc = graph.index.get_descriptor(Keychain::External).unwrap();
1661+
let spks: Vec<_> = (0..n)
1662+
.map(|i| desc.at_derivation_index(i).unwrap().script_pubkey())
1663+
.collect();
1664+
1665+
for i in 0..n {
1666+
// create tx
1667+
let tx = Transaction {
1668+
input: vec![TxIn {
1669+
previous_output,
1670+
..Default::default()
1671+
}],
1672+
output: vec![TxOut {
1673+
value: init_amount - (fee * (i as u64 + 1)),
1674+
script_pubkey: spks[i as usize].clone(),
1675+
}],
1676+
..new_tx(i)
1677+
};
1678+
let txid = tx.compute_txid();
1679+
let update = TxUpdate {
1680+
txs: vec![Arc::new(tx)],
1681+
..Default::default()
1682+
};
1683+
let _ = graph.apply_update_at(update, Some(21));
1684+
// store the next prevout
1685+
previous_output = OutPoint::new(txid, 0);
1686+
}
1687+
}
1688+
1689+
pub fn parse_descriptor(s: &str) -> Descriptor<DescriptorPublicKey> {
1690+
<Descriptor<DescriptorPublicKey>>::parse_descriptor(&Secp256k1::new(), s)
1691+
.unwrap()
1692+
.0
1693+
}
1694+
1695+
pub fn new_tx(lt: u32) -> Transaction {
16451696
Transaction {
16461697
version: transaction::Version::TWO,
16471698
lock_time: absolute::LockTime::from_consensus(lt),
16481699
input: vec![],
16491700
output: vec![],
16501701
}
16511702
}
1703+
}
16521704

1705+
/// Bench
1706+
#[cfg(bdk_bench)]
1707+
#[allow(missing_docs)]
1708+
pub mod bench {
1709+
use std::hint::black_box;
1710+
1711+
use criterion::Criterion;
1712+
1713+
use super::*;
1714+
use crate::tx_graph::bench_util::*;
1715+
1716+
#[inline(never)]
16531717
pub fn filter_chain_unspents(bench: &mut Criterion) {
1654-
let (graph, chain) = get_params();
1655-
// TODO: insert conflicts
1718+
let (mut graph, chain) = black_box(init_graph_chain());
1719+
let txouts: Vec<_> = graph.graph().all_txouts().collect();
1720+
assert_eq!(txouts.len(), 1);
1721+
let prevout = txouts.iter().next().unwrap().0;
1722+
black_box(add_conflicts(1000, &mut graph, prevout));
1723+
16561724
bench.bench_function("filter_chain_unspents", |b| {
16571725
b.iter(|| {
1658-
TxGraph::filter_chain_unspents(
1726+
let unspent = TxGraph::filter_chain_unspents(
16591727
graph.graph(),
16601728
&chain,
16611729
chain.tip().block_id(),
16621730
graph.index.outpoints().clone(),
1663-
)
1731+
);
1732+
assert_eq!(unspent.count(), 1);
1733+
})
1734+
});
1735+
}
1736+
1737+
#[inline(never)]
1738+
pub fn list_canonical_txs(bench: &mut Criterion) {
1739+
let (mut graph, chain) = black_box(init_graph_chain());
1740+
assert_eq!(graph.graph().txs.len(), 1);
1741+
black_box(chain_unconfirmed(100, &mut graph));
1742+
1743+
bench.bench_function("list_canonical_txs", |b| {
1744+
b.iter(|| {
1745+
let txs = graph
1746+
.graph()
1747+
.list_canonical_txs(&chain, chain.tip().block_id());
1748+
assert_eq!(txs.count(), 100 + 1);
16641749
})
16651750
});
16661751
}

0 commit comments

Comments
 (0)