Skip to content

Commit

Permalink
redo canonical benchmarks using TxTemplate
Browse files Browse the repository at this point in the history
- use TxTemplate to setup test scenarios
- add generated files to gitignore

[Ticket: X]
  • Loading branch information
tvpeter committed Jan 17, 2025
1 parent afe0f79 commit d121446
Show file tree
Hide file tree
Showing 2 changed files with 266 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ Cargo.lock
# Example persisted files.
*.db
*.sqlite*

# Canonical benchmark generated files
crates/chain/target
267 changes: 263 additions & 4 deletions crates/chain/benches/canonicalization.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use bdk_chain::{keychain_txout::KeychainTxOutIndex, local_chain::LocalChain, IndexedTxGraph};
use bdk_core::{BlockId, CheckPoint};
use bdk_core::{ConfirmationBlockTime, TxUpdate};
use bdk_testenv::hash;
use bdk_testenv::tx_template::{init_graph, TxInTemplate, TxOutTemplate, TxTemplate};
use bdk_testenv::utils::DESCRIPTORS;
use bdk_testenv::{block_id, hash, local_chain};
use bitcoin::{
absolute, constants, hashes::Hash, key::Secp256k1, transaction, Amount, BlockHash, Network,
OutPoint, ScriptBuf, Transaction, TxIn, TxOut,
Expand Down Expand Up @@ -241,10 +243,267 @@ pub fn nested_conflicts(c: &mut Criterion) {
});
}

// start of using TxTemplate
fn initialize_graph_and_keychain() -> (KeychainTxGraph, LocalChain) {
let chain = local_chain![(0, hash!("genesis")), (100, hash!("abcd"))];

let mut keychain_index = KeychainTxOutIndex::new(10);
let (desc, _) = Descriptor::parse_descriptor(&Secp256k1::new(), DESCRIPTORS[2]).unwrap();
keychain_index.insert_descriptor((), desc).unwrap();

let new_graph = KeychainTxGraph::new(keychain_index);
(new_graph, chain)
}

fn setup_many_conflicting_unconfirmed(tx_count: u32) -> (KeychainTxGraph, LocalChain) {
let (mut tx_graph, chain) = initialize_graph_and_keychain();
let mut templates = Vec::new();

templates.push(TxTemplate {
tx_name: "ancestor_tx".into(),
inputs: vec![TxInTemplate::Bogus],
outputs: vec![TxOutTemplate::new(Amount::ONE_BTC.to_sat(), Some(0))],
anchors: vec![block_id!(100, "abcd")],
last_seen: None,
});

for i in 1..=tx_count {
templates.push(TxTemplate {
tx_name: format!("conflict_tx_{}", i).into(),
inputs: vec![TxInTemplate::PrevTx("ancestor_tx".into(), 0)],
outputs: vec![TxOutTemplate::new(
Amount::ONE_BTC.to_sat() - (i as u64 * 10),
Some(1),
)],
anchors: vec![],
last_seen: Some(i as u64),
});
}

let (graph, _, _) = init_graph(templates);
let _ = tx_graph.batch_insert_unconfirmed(graph.full_txs().map(|tx_node| {
(
tx_node.tx,
tx_node.last_seen_unconfirmed.unwrap_or_default(),
)
}));

(tx_graph, chain)
}

/// Utility function to create a benchmark-ready graph with a chain of unconfirmed transactions
fn setup_many_chained_unconfirmed(tx_chain_count: u32) -> (KeychainTxGraph, LocalChain) {
let mut templates = Vec::new();
let (mut tx_graph, chain) = initialize_graph_and_keychain();

templates.push(TxTemplate {
tx_name: "ancestor_tx".into(),
inputs: vec![TxInTemplate::Bogus],
outputs: vec![TxOutTemplate::new(Amount::ONE_BTC.to_sat(), Some(0))],
anchors: vec![block_id!(100, "abcd")],
last_seen: None,
});

for i in 0..tx_chain_count {
templates.push(TxTemplate {
tx_name: format!("chain_tx_{}", i).into(),
inputs: if i == 0 {
vec![TxInTemplate::PrevTx("ancestor_tx".into(), 0)]
} else {
vec![TxInTemplate::PrevTx(
format!("chain_tx_{}", i - 1).into(),
0,
)]
},
outputs: vec![TxOutTemplate::new(Amount::ONE_BTC.to_sat(), Some(1))],
anchors: vec![],
last_seen: Some(i as u64),
});
}

let (graph, _, _) = init_graph(templates);
let _ = tx_graph.batch_insert_unconfirmed(graph.full_txs().map(|tx_node| {
(
tx_node.tx,
tx_node.last_seen_unconfirmed.unwrap_or_default(),
)
}));

(tx_graph, chain)
}

/// Utility function to create a benchmark-ready graph with nested conflicting transactions
fn setup_nested_conflicts(
graph_depth: usize,
conflicts_per_output: usize,
) -> (KeychainTxGraph, LocalChain) {
let mut templates = Vec::new();
let (mut tx_graph, chain) = initialize_graph_and_keychain();

templates.push(TxTemplate {
tx_name: "ancestor_tx".into(),
inputs: vec![TxInTemplate::Bogus],
outputs: vec![TxOutTemplate::new(Amount::ONE_BTC.to_sat(), Some(0))],
anchors: vec![block_id!(100, "abcd")],
last_seen: None,
});

let mut previous_outputs = vec!["ancestor_tx".to_string()];

for depth in 1..graph_depth {
let mut next_outputs = Vec::new();
for previous_output_name in previous_outputs.drain(..) {
for conflict_i in 1..=conflicts_per_output {
let tx_name = format!("depth_{}_conflict_{}", depth, conflict_i);
let mut last_seen = depth * conflict_i;
if last_seen % 2 == 0 {
last_seen /= 2;
}

templates.push(TxTemplate {
tx_name: tx_name.clone().into(),
inputs: vec![TxInTemplate::PrevTx(previous_output_name.clone().into(), 0)],
outputs: vec![TxOutTemplate::new(
Amount::ONE_BTC.to_sat() - (depth as u64 * 200 - conflict_i as u64),
Some((depth + conflict_i) as u32),
)],
anchors: vec![],
last_seen: Some(last_seen as u64),
});

next_outputs.push(tx_name);
}
}
previous_outputs = next_outputs;
}

let (graph, _, _) = init_graph(templates);
let _ = tx_graph.batch_insert_unconfirmed(graph.full_txs().map(|tx_node| {
(
tx_node.tx,
tx_node.last_seen_unconfirmed.unwrap_or_default(),
)
}));

(tx_graph, chain)
}

/// Benchmark scenario for many conflicting unconfirmed transactions
fn bench_many_conflicting_unconfirmed(c: &mut Criterion) {
const CONFLICTING_TX_COUNT: u32 = 2100;

let (tx_graph, chain) = setup_many_conflicting_unconfirmed(CONFLICTING_TX_COUNT);

c.bench_function("many_conflicting_unconfirmed::list_canonical_txs", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| run_list_canonical_txs(&tx_graph, &chain, 2));
}
});

c.bench_function("many_conflicting_unconfirmed::filter_chain_txouts", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| run_filter_chain_txouts(&tx_graph, &chain, 2));
}
});

c.bench_function(
"many_conflicting_unconfirmed::filter_chain_unspents",
move |b| {
let tx_graph = tx_graph.clone();
b.iter(|| {
run_filter_chain_unspents(&tx_graph, &chain, 1);
});
},
);
}

/// Benchmark scenario for many chained unconfirmed transactions
pub fn bench_many_chained_unconfirmed(c: &mut Criterion) {
const TX_CHAIN_COUNT: u32 = 2100;

let (tx_graph, chain) = setup_many_chained_unconfirmed(TX_CHAIN_COUNT);

c.bench_function("many_chained_unconfirmed::list_canonical_txs", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_list_canonical_txs(&tx_graph, &chain, (TX_CHAIN_COUNT + 1).try_into().unwrap());
});
}
});

c.bench_function("many_chained_unconfirmed::filter_chain_txouts", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_filter_chain_txouts(&tx_graph, &chain, 1);
});
}
});

c.bench_function("many_chained_unconfirmed::filter_chain_unspents", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_filter_chain_unspents(&tx_graph, &chain, 0);
});
}
});
}

/// Benchmark scenario for nested conflicts
pub fn bench_nested_conflicts(c: &mut Criterion) {
const CONFLICTS_PER_OUTPUT: usize = 3;
const GRAPH_DEPTH: usize = 7;

let (tx_graph, chain) = setup_nested_conflicts(GRAPH_DEPTH, CONFLICTS_PER_OUTPUT);

c.bench_function("nested_conflicts_unconfirmed::list_canonical_txs", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_list_canonical_txs(&tx_graph, &chain, GRAPH_DEPTH);
});
}
});

c.bench_function("nested_conflicts_unconfirmed::filter_chain_txouts", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_filter_chain_txouts(&tx_graph, &chain, GRAPH_DEPTH);
});
}
});

c.bench_function("nested_conflicts_unconfirmed::filter_chain_unspents", {
let tx_graph = tx_graph.clone();
let chain = chain.clone();
move |b| {
b.iter(|| {
run_filter_chain_unspents(&tx_graph, &chain, 1);
});
}
});
}
// end of using TxTemplate

criterion_group!(
benches,
many_conflicting_unconfirmed,
many_chained_unconfirmed,
nested_conflicts,
// many_conflicting_unconfirmed,
// many_chained_unconfirmed,
// nested_conflicts,
bench_many_conflicting_unconfirmed,
bench_many_chained_unconfirmed,
bench_nested_conflicts,
);
criterion_main!(benches);

0 comments on commit d121446

Please sign in to comment.