Skip to content

Commit 5f75dd9

Browse files
committed
Benchmark payments across stores
Run the existing payments benchmark once per configured store backend so filesystem, SQLite, and optional PostgreSQL results are reported under the same payment flow.
1 parent 7564150 commit 5f75dd9

3 files changed

Lines changed: 116 additions & 57 deletions

File tree

benches/payments.rs

Lines changed: 89 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ use tokio::task::{self};
1818

1919
use crate::common::open_channel_push_amt;
2020

21+
#[derive(Clone, Copy)]
22+
struct StoreBenchConfig {
23+
name: &'static str,
24+
store_type: common::TestStoreType,
25+
}
26+
2127
fn spawn_payment(node_a: Arc<Node>, node_b: Arc<Node>, amount_msat: u64) {
2228
let mut preimage_bytes = [0u8; 32];
2329
rand::rng().fill_bytes(&mut preimage_bytes);
@@ -121,74 +127,100 @@ fn payment_benchmark(c: &mut Criterion) {
121127
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
122128
let chain_source = random_chain_source(&bitcoind, &electrsd);
123129

124-
let (node_a, node_b) = setup_two_nodes_with_store(
125-
&chain_source,
126-
false,
127-
true,
128-
false,
129-
common::TestStoreType::Sqlite,
130-
);
130+
let store_configs = store_bench_configs();
131131

132132
let runtime =
133133
tokio::runtime::Builder::new_multi_thread().worker_threads(4).enable_all().build().unwrap();
134134

135-
let node_a = Arc::new(node_a);
136-
let node_b = Arc::new(node_b);
137-
138-
// Fund the nodes and setup a channel between them. The criterion function cannot be async, so we need to execute
139-
// the setup using a runtime.
140-
let node_a_cloned = Arc::clone(&node_a);
141-
let node_b_cloned = Arc::clone(&node_b);
142-
runtime.block_on(async move {
143-
let address_a = node_a_cloned.onchain_payment().new_address().unwrap();
144-
let premine_sat = 25_000_000;
145-
premine_and_distribute_funds(
146-
&bitcoind.client,
147-
&electrsd.client,
148-
vec![address_a],
149-
Amount::from_sat(premine_sat),
150-
)
151-
.await;
152-
node_a_cloned.sync_wallets().unwrap();
153-
node_b_cloned.sync_wallets().unwrap();
154-
open_channel_push_amt(
155-
&node_a_cloned,
156-
&node_b_cloned,
157-
16_000_000,
158-
Some(1_000_000_000),
159-
false,
160-
&electrsd,
161-
)
162-
.await;
163-
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
164-
node_a_cloned.sync_wallets().unwrap();
165-
node_b_cloned.sync_wallets().unwrap();
166-
expect_channel_ready_event!(node_a_cloned, node_b_cloned.node_id());
167-
expect_channel_ready_event!(node_b_cloned, node_a_cloned.node_id());
168-
});
169-
170135
let mut group = c.benchmark_group("payments");
171136
group.sample_size(10);
172137

173-
group.bench_function("payments", |b| {
174-
// Use custom timing so that sending back the money at the end of each iteration isn't included in the
175-
// measurement.
176-
b.to_async(&runtime).iter_custom(|iter| {
138+
for store_config in store_configs {
139+
let (node_a, node_b) =
140+
setup_two_nodes_with_store(&chain_source, false, true, false, store_config.store_type);
141+
142+
let node_a = Arc::new(node_a);
143+
let node_b = Arc::new(node_b);
144+
145+
// Fund the nodes and setup a channel between them. The criterion function cannot be async,
146+
// so we need to execute the setup using a runtime.
147+
let node_a_cloned = Arc::clone(&node_a);
148+
let node_b_cloned = Arc::clone(&node_b);
149+
runtime.block_on(async {
150+
let address_a = node_a_cloned.onchain_payment().new_address().unwrap();
151+
let premine_sat = 25_000_000;
152+
premine_and_distribute_funds(
153+
&bitcoind.client,
154+
&electrsd.client,
155+
vec![address_a],
156+
Amount::from_sat(premine_sat),
157+
)
158+
.await;
159+
node_a_cloned.sync_wallets().unwrap();
160+
node_b_cloned.sync_wallets().unwrap();
161+
open_channel_push_amt(
162+
&node_a_cloned,
163+
&node_b_cloned,
164+
16_000_000,
165+
Some(1_000_000_000),
166+
false,
167+
&electrsd,
168+
)
169+
.await;
170+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
171+
node_a_cloned.sync_wallets().unwrap();
172+
node_b_cloned.sync_wallets().unwrap();
173+
expect_channel_ready_event!(node_a_cloned, node_b_cloned.node_id());
174+
expect_channel_ready_event!(node_b_cloned, node_a_cloned.node_id());
175+
});
176+
177+
group.bench_function(store_config.name, |b| {
178+
// Use custom timing so that sending back the money at the end of each iteration isn't
179+
// included in the measurement.
177180
let node_a = Arc::clone(&node_a);
178181
let node_b = Arc::clone(&node_b);
179-
180-
async move {
181-
let mut total = Duration::ZERO;
182-
for _i in 0..iter {
183-
let node_a = Arc::clone(&node_a);
184-
let node_b = Arc::clone(&node_b);
185-
186-
total += send_payments(node_a, node_b).await;
182+
b.to_async(&runtime).iter_custom(|iter| {
183+
let node_a = Arc::clone(&node_a);
184+
let node_b = Arc::clone(&node_b);
185+
186+
async move {
187+
let mut total = Duration::ZERO;
188+
for _i in 0..iter {
189+
let node_a = Arc::clone(&node_a);
190+
let node_b = Arc::clone(&node_b);
191+
192+
total += send_payments(node_a, node_b).await;
193+
}
194+
total
187195
}
188-
total
189-
}
196+
});
190197
});
191-
});
198+
}
199+
}
200+
201+
fn store_bench_configs() -> Vec<StoreBenchConfig> {
202+
#[cfg(not(feature = "postgres"))]
203+
{
204+
vec![
205+
StoreBenchConfig { name: "sqlite", store_type: common::TestStoreType::Sqlite },
206+
StoreBenchConfig {
207+
name: "filesystem",
208+
store_type: common::TestStoreType::FilesystemStore,
209+
},
210+
]
211+
}
212+
213+
#[cfg(feature = "postgres")]
214+
{
215+
vec![
216+
StoreBenchConfig { name: "sqlite", store_type: common::TestStoreType::Sqlite },
217+
StoreBenchConfig {
218+
name: "filesystem",
219+
store_type: common::TestStoreType::FilesystemStore,
220+
},
221+
StoreBenchConfig { name: "postgres", store_type: common::TestStoreType::Postgres },
222+
]
223+
}
192224
}
193225

194226
criterion_group!(benches, payment_benchmark);

tests/common/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,8 @@ pub(crate) enum TestStoreType {
417417
TestSyncStore,
418418
Sqlite,
419419
FilesystemStore,
420+
#[cfg(feature = "postgres")]
421+
Postgres,
420422
}
421423

422424
impl Default for TestStoreType {
@@ -596,6 +598,29 @@ pub(crate) fn setup_node(chain_source: &TestChainSource, config: TestConfig) ->
596598
TestStoreType::FilesystemStore => {
597599
builder.build_with_fs_store(config.node_entropy.into()).unwrap()
598600
},
601+
#[cfg(feature = "postgres")]
602+
TestStoreType::Postgres => {
603+
let table_name = format!(
604+
"test_{}",
605+
config
606+
.node_config
607+
.storage_dir_path
608+
.chars()
609+
.filter(|c| c.is_ascii_alphanumeric())
610+
.collect::<String>()
611+
);
612+
let connection_string = std::env::var("TEST_POSTGRES_URL")
613+
.unwrap_or_else(|_| "host=localhost user=postgres password=postgres".to_string());
614+
builder
615+
.build_with_postgres_store(
616+
config.node_entropy.into(),
617+
connection_string,
618+
None,
619+
Some(table_name),
620+
None,
621+
)
622+
.unwrap()
623+
},
599624
};
600625

601626
if config.recovery_mode {

tests/integration_tests_rust.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2568,6 +2568,8 @@ async fn build_0_7_0_node(
25682568
TestStoreType::FilesystemStore => builder_old.build_with_fs_store().unwrap(),
25692569
TestStoreType::Sqlite => builder_old.build().unwrap(),
25702570
TestStoreType::TestSyncStore => panic!("TestSyncStore not supported in v0.7.0 builder"),
2571+
#[cfg(feature = "postgres")]
2572+
TestStoreType::Postgres => panic!("Postgres not supported in v0.7.0 builder"),
25712573
};
25722574

25732575
node_old.start().unwrap();

0 commit comments

Comments
 (0)