Skip to content

Commit b55de44

Browse files
authored
Merge pull request #769 from tnull/2026-01-test-setup
Randomize chain source selection in tests
2 parents 3363c9b + 594e1fb commit b55de44

File tree

9 files changed

+316
-158
lines changed

9 files changed

+316
-158
lines changed

benches/payments.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use bitcoin::hex::DisplayHex;
88
use bitcoin::Amount;
99
use common::{
1010
expect_channel_ready_event, generate_blocks_and_wait, premine_and_distribute_funds,
11-
setup_bitcoind_and_electrsd, setup_two_nodes_with_store, TestChainSource,
11+
random_chain_source, setup_bitcoind_and_electrsd, setup_two_nodes_with_store,
1212
};
1313
use criterion::{criterion_group, criterion_main, Criterion};
1414
use ldk_node::{Event, Node};
@@ -119,7 +119,7 @@ async fn send_payments(node_a: Arc<Node>, node_b: Arc<Node>) -> std::time::Durat
119119
fn payment_benchmark(c: &mut Criterion) {
120120
// Set up two nodes. Because this is slow, we reuse the same nodes for each sample.
121121
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
122-
let chain_source = TestChainSource::Esplora(&electrsd);
122+
let chain_source = random_chain_source(&bitcoind, &electrsd);
123123

124124
let (node_a, node_b) = setup_two_nodes_with_store(
125125
&chain_source,

bindings/ldk_node.udl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ interface Builder {
129129
void set_node_alias(string node_alias);
130130
[Throws=BuildError]
131131
void set_async_payments_role(AsyncPaymentsRole? role);
132+
void set_wallet_recovery_mode();
132133
[Throws=BuildError]
133134
Node build(NodeEntropy node_entropy);
134135
[Throws=BuildError]

src/builder.rs

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ pub struct NodeBuilder {
244244
async_payments_role: Option<AsyncPaymentsRole>,
245245
runtime_handle: Option<tokio::runtime::Handle>,
246246
pathfinding_scores_sync_config: Option<PathfindingScoresSyncConfig>,
247+
recovery_mode: bool,
247248
}
248249

249250
impl NodeBuilder {
@@ -261,6 +262,7 @@ impl NodeBuilder {
261262
let log_writer_config = None;
262263
let runtime_handle = None;
263264
let pathfinding_scores_sync_config = None;
265+
let recovery_mode = false;
264266
Self {
265267
config,
266268
chain_data_source_config,
@@ -270,6 +272,7 @@ impl NodeBuilder {
270272
runtime_handle,
271273
async_payments_role: None,
272274
pathfinding_scores_sync_config,
275+
recovery_mode,
273276
}
274277
}
275278

@@ -544,6 +547,16 @@ impl NodeBuilder {
544547
Ok(self)
545548
}
546549

550+
/// Configures the [`Node`] to resync chain data from genesis on first startup, recovering any
551+
/// historical wallet funds.
552+
///
553+
/// This should only be set on first startup when importing an older wallet from a previously
554+
/// used [`NodeEntropy`].
555+
pub fn set_wallet_recovery_mode(&mut self) -> &mut Self {
556+
self.recovery_mode = true;
557+
self
558+
}
559+
547560
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
548561
/// previously configured.
549562
pub fn build(&self, node_entropy: NodeEntropy) -> Result<Node, BuildError> {
@@ -679,6 +692,7 @@ impl NodeBuilder {
679692
self.liquidity_source_config.as_ref(),
680693
self.pathfinding_scores_sync_config.as_ref(),
681694
self.async_payments_role,
695+
self.recovery_mode,
682696
seed_bytes,
683697
runtime,
684698
logger,
@@ -919,6 +933,15 @@ impl ArcedNodeBuilder {
919933
self.inner.write().unwrap().set_async_payments_role(role).map(|_| ())
920934
}
921935

936+
/// Configures the [`Node`] to resync chain data from genesis on first startup, recovering any
937+
/// historical wallet funds.
938+
///
939+
/// This should only be set on first startup when importing an older wallet from a previously
940+
/// used [`NodeEntropy`].
941+
pub fn set_wallet_recovery_mode(&self) {
942+
self.inner.write().unwrap().set_wallet_recovery_mode();
943+
}
944+
922945
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
923946
/// previously configured.
924947
pub fn build(&self, node_entropy: Arc<NodeEntropy>) -> Result<Arc<Node>, BuildError> {
@@ -1033,8 +1056,8 @@ fn build_with_store_internal(
10331056
gossip_source_config: Option<&GossipSourceConfig>,
10341057
liquidity_source_config: Option<&LiquiditySourceConfig>,
10351058
pathfinding_scores_sync_config: Option<&PathfindingScoresSyncConfig>,
1036-
async_payments_role: Option<AsyncPaymentsRole>, seed_bytes: [u8; 64], runtime: Arc<Runtime>,
1037-
logger: Arc<Logger>, kv_store: Arc<DynStore>,
1059+
async_payments_role: Option<AsyncPaymentsRole>, recovery_mode: bool, seed_bytes: [u8; 64],
1060+
runtime: Arc<Runtime>, logger: Arc<Logger>, kv_store: Arc<DynStore>,
10381061
) -> Result<Node, BuildError> {
10391062
optionally_install_rustls_cryptoprovider();
10401063

@@ -1230,19 +1253,23 @@ fn build_with_store_internal(
12301253
BuildError::WalletSetupFailed
12311254
})?;
12321255

1233-
if let Some(best_block) = chain_tip_opt {
1234-
// Insert the first checkpoint if we have it, to avoid resyncing from genesis.
1235-
// TODO: Use a proper wallet birthday once BDK supports it.
1236-
let mut latest_checkpoint = wallet.latest_checkpoint();
1237-
let block_id =
1238-
bdk_chain::BlockId { height: best_block.height, hash: best_block.block_hash };
1239-
latest_checkpoint = latest_checkpoint.insert(block_id);
1240-
let update =
1241-
bdk_wallet::Update { chain: Some(latest_checkpoint), ..Default::default() };
1242-
wallet.apply_update(update).map_err(|e| {
1243-
log_error!(logger, "Failed to apply checkpoint during wallet setup: {}", e);
1244-
BuildError::WalletSetupFailed
1245-
})?;
1256+
if !recovery_mode {
1257+
if let Some(best_block) = chain_tip_opt {
1258+
// Insert the first checkpoint if we have it, to avoid resyncing from genesis.
1259+
// TODO: Use a proper wallet birthday once BDK supports it.
1260+
let mut latest_checkpoint = wallet.latest_checkpoint();
1261+
let block_id = bdk_chain::BlockId {
1262+
height: best_block.height,
1263+
hash: best_block.block_hash,
1264+
};
1265+
latest_checkpoint = latest_checkpoint.insert(block_id);
1266+
let update =
1267+
bdk_wallet::Update { chain: Some(latest_checkpoint), ..Default::default() };
1268+
wallet.apply_update(update).map_err(|e| {
1269+
log_error!(logger, "Failed to apply checkpoint during wallet setup: {}", e);
1270+
BuildError::WalletSetupFailed
1271+
})?;
1272+
}
12461273
}
12471274
wallet
12481275
},
@@ -1267,6 +1294,7 @@ fn build_with_store_internal(
12671294
wallet_persister,
12681295
Arc::clone(&tx_broadcaster),
12691296
Arc::clone(&fee_estimator),
1297+
Arc::clone(&chain_source),
12701298
Arc::clone(&payment_store),
12711299
Arc::clone(&config),
12721300
Arc::clone(&logger),

src/chain/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ mod electrum;
1010
mod esplora;
1111

1212
use std::collections::HashMap;
13-
use std::sync::{Arc, RwLock};
13+
use std::sync::{Arc, Mutex, RwLock};
1414
use std::time::Duration;
1515

1616
use bitcoin::{Script, Txid};
@@ -84,6 +84,7 @@ impl WalletSyncStatus {
8484

8585
pub(crate) struct ChainSource {
8686
kind: ChainSourceKind,
87+
registered_txids: Mutex<Vec<Txid>>,
8788
tx_broadcaster: Arc<Broadcaster>,
8889
logger: Arc<Logger>,
8990
}
@@ -112,7 +113,8 @@ impl ChainSource {
112113
node_metrics,
113114
);
114115
let kind = ChainSourceKind::Esplora(esplora_chain_source);
115-
(Self { kind, tx_broadcaster, logger }, None)
116+
let registered_txids = Mutex::new(Vec::new());
117+
(Self { kind, registered_txids, tx_broadcaster, logger }, None)
116118
}
117119

118120
pub(crate) fn new_electrum(
@@ -131,7 +133,8 @@ impl ChainSource {
131133
node_metrics,
132134
);
133135
let kind = ChainSourceKind::Electrum(electrum_chain_source);
134-
(Self { kind, tx_broadcaster, logger }, None)
136+
let registered_txids = Mutex::new(Vec::new());
137+
(Self { kind, registered_txids, tx_broadcaster, logger }, None)
135138
}
136139

137140
pub(crate) async fn new_bitcoind_rpc(
@@ -153,7 +156,8 @@ impl ChainSource {
153156
);
154157
let best_block = bitcoind_chain_source.poll_best_block().await.ok();
155158
let kind = ChainSourceKind::Bitcoind(bitcoind_chain_source);
156-
(Self { kind, tx_broadcaster, logger }, best_block)
159+
let registered_txids = Mutex::new(Vec::new());
160+
(Self { kind, registered_txids, tx_broadcaster, logger }, best_block)
157161
}
158162

159163
pub(crate) async fn new_bitcoind_rest(
@@ -176,7 +180,8 @@ impl ChainSource {
176180
);
177181
let best_block = bitcoind_chain_source.poll_best_block().await.ok();
178182
let kind = ChainSourceKind::Bitcoind(bitcoind_chain_source);
179-
(Self { kind, tx_broadcaster, logger }, best_block)
183+
let registered_txids = Mutex::new(Vec::new());
184+
(Self { kind, registered_txids, tx_broadcaster, logger }, best_block)
180185
}
181186

182187
pub(crate) fn start(&self, runtime: Arc<Runtime>) -> Result<(), Error> {
@@ -209,6 +214,10 @@ impl ChainSource {
209214
}
210215
}
211216

217+
pub(crate) fn registered_txids(&self) -> Vec<Txid> {
218+
self.registered_txids.lock().unwrap().clone()
219+
}
220+
212221
pub(crate) fn is_transaction_based(&self) -> bool {
213222
match &self.kind {
214223
ChainSourceKind::Esplora(_) => true,
@@ -463,6 +472,7 @@ impl ChainSource {
463472

464473
impl Filter for ChainSource {
465474
fn register_tx(&self, txid: &Txid, script_pubkey: &Script) {
475+
self.registered_txids.lock().unwrap().push(*txid);
466476
match &self.kind {
467477
ChainSourceKind::Esplora(esplora_chain_source) => {
468478
esplora_chain_source.register_tx(txid, script_pubkey)

src/lib.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,10 +1329,6 @@ impl Node {
13291329
Error::ChannelSplicingFailed
13301330
})?;
13311331

1332-
// insert channel's funding utxo into the wallet so we can later calculate fees
1333-
// correctly when viewing this splice-in.
1334-
self.wallet.insert_txo(funding_txo.into_bitcoin_outpoint(), funding_output)?;
1335-
13361332
let change_address = self.wallet.get_new_internal_address()?;
13371333

13381334
let contribution = SpliceContribution::splice_in(
@@ -1426,18 +1422,6 @@ impl Node {
14261422
},
14271423
};
14281424

1429-
let funding_txo = channel_details.funding_txo.ok_or_else(|| {
1430-
log_error!(self.logger, "Failed to splice channel: channel not yet ready",);
1431-
Error::ChannelSplicingFailed
1432-
})?;
1433-
1434-
let funding_output = channel_details.get_funding_output().ok_or_else(|| {
1435-
log_error!(self.logger, "Failed to splice channel: channel not yet ready");
1436-
Error::ChannelSplicingFailed
1437-
})?;
1438-
1439-
self.wallet.insert_txo(funding_txo.into_bitcoin_outpoint(), funding_output)?;
1440-
14411425
self.channel_manager
14421426
.splice_channel(
14431427
&channel_details.channel_id,

0 commit comments

Comments
 (0)