Skip to content

Commit ede415f

Browse files
authored
Merge pull request #551 from tnull/2025-06-upgrade-to-bdk-2.0
Upgrade to BDK 2.0
2 parents 7977b04 + e6fa232 commit ede415f

File tree

5 files changed

+91
-20
lines changed

5 files changed

+91
-20
lines changed

Cargo.toml

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,23 +61,28 @@ lightning-liquidity = { version = "0.1.0", features = ["std"] }
6161
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync", features = ["esplora-async-https", "electrum", "time"] }
6262
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity", features = ["std"] }
6363

64-
bdk_chain = { version = "0.21.1", default-features = false, features = ["std"] }
65-
bdk_esplora = { version = "0.20.1", default-features = false, features = ["async-https-rustls", "tokio"]}
66-
bdk_electrum = { version = "0.20.1", default-features = false, features = ["use-rustls"]}
67-
bdk_wallet = { version = "1.0.0", default-features = false, features = ["std", "keys-bip39"]}
64+
bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] }
65+
bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]}
66+
bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls"]}
67+
bdk_wallet = { version = "2.0.0", default-features = false, features = ["std", "keys-bip39"]}
6868

69-
reqwest = { version = "0.11", default-features = false, features = ["json", "rustls-tls"] }
69+
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] }
7070
rusqlite = { version = "0.31.0", features = ["bundled"] }
71-
bitcoin = "0.32.2"
71+
bitcoin = "0.32.4"
7272
bip39 = "2.0.0"
7373
bip21 = { version = "0.5", features = ["std"], default-features = false }
7474

7575
base64 = { version = "0.22.1", default-features = false, features = ["std"] }
7676
rand = "0.8.5"
7777
chrono = { version = "0.4", default-features = false, features = ["clock"] }
7878
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros" ] }
79-
esplora-client = { version = "0.11", default-features = false, features = ["tokio", "async-https-rustls"] }
80-
electrum-client = { version = "0.22.0", default-features = true }
79+
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"] }
80+
81+
# FIXME: This was introduced to decouple the `bdk_esplora` and
82+
# `lightning-transaction-sync` APIs. We should drop it as part of the upgrade
83+
# to LDK 0.2.
84+
esplora-client_0_11 = { package = "esplora-client", version = "0.11", default-features = false, features = ["tokio", "async-https-rustls"] }
85+
electrum-client = { version = "0.23.1", default-features = true }
8186
libc = "0.2"
8287
uniffi = { version = "0.27.3", features = ["build"], optional = true }
8388
serde = { version = "1.0.210", default-features = false, features = ["std", "derive"] }
@@ -98,10 +103,10 @@ proptest = "1.0.0"
98103
regex = "1.5.6"
99104

100105
[target.'cfg(not(no_download))'.dev-dependencies]
101-
electrsd = { version = "0.33.0", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_27_2"] }
106+
electrsd = { version = "0.34.0", default-features = false, features = ["legacy", "esplora_a33e97e1", "corepc-node_27_2"] }
102107

103108
[target.'cfg(no_download)'.dev-dependencies]
104-
electrsd = { version = "0.33.0", default-features = false, features = ["legacy"] }
109+
electrsd = { version = "0.34.0", default-features = false, features = ["legacy"] }
105110
corepc-node = { version = "0.7.0", default-features = false, features = ["27_2"] }
106111

107112
[target.'cfg(cln_test)'.dev-dependencies]

src/chain/bitcoind_rpc.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,12 +190,24 @@ impl BitcoindRpcClient {
190190
Ok(())
191191
}
192192

193+
/// Returns two `Vec`s:
194+
/// - mempool transactions, alongside their first-seen unix timestamps.
195+
/// - transactions that have been evicted from the mempool, alongside the last time they were seen absent.
196+
pub(crate) async fn get_updated_mempool_transactions(
197+
&self, best_processed_height: u32, unconfirmed_txids: Vec<Txid>,
198+
) -> std::io::Result<(Vec<(Transaction, u64)>, Vec<(Txid, u64)>)> {
199+
let mempool_txs =
200+
self.get_mempool_transactions_and_timestamp_at_height(best_processed_height).await?;
201+
let evicted_txids = self.get_evicted_mempool_txids_and_timestamp(unconfirmed_txids).await?;
202+
Ok((mempool_txs, evicted_txids))
203+
}
204+
193205
/// Get mempool transactions, alongside their first-seen unix timestamps.
194206
///
195207
/// This method is an adapted version of `bdk_bitcoind_rpc::Emitter::mempool`. It emits each
196208
/// transaction only once, unless we cannot assume the transaction's ancestors are already
197209
/// emitted.
198-
pub(crate) async fn get_mempool_transactions_and_timestamp_at_height(
210+
async fn get_mempool_transactions_and_timestamp_at_height(
199211
&self, best_processed_height: u32,
200212
) -> std::io::Result<Vec<(Transaction, u64)>> {
201213
let prev_mempool_time = self.latest_mempool_timestamp.load(Ordering::Relaxed);
@@ -252,6 +264,23 @@ impl BitcoindRpcClient {
252264
}
253265
Ok(txs_to_emit)
254266
}
267+
268+
// Retrieve a list of Txids that have been evicted from the mempool.
269+
//
270+
// To this end, we first update our local mempool_entries_cache and then return all unconfirmed
271+
// wallet `Txid`s that don't appear in the mempool still.
272+
async fn get_evicted_mempool_txids_and_timestamp(
273+
&self, unconfirmed_txids: Vec<Txid>,
274+
) -> std::io::Result<Vec<(Txid, u64)>> {
275+
let latest_mempool_timestamp = self.latest_mempool_timestamp.load(Ordering::Relaxed);
276+
let mempool_entries_cache = self.mempool_entries_cache.lock().await;
277+
let evicted_txids = unconfirmed_txids
278+
.into_iter()
279+
.filter(|txid| mempool_entries_cache.contains_key(txid))
280+
.map(|txid| (txid, latest_mempool_timestamp))
281+
.collect();
282+
Ok(evicted_txids)
283+
}
255284
}
256285

257286
impl BlockSource for BitcoindRpcClient {

src/chain/mod.rs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,18 @@ impl ChainSource {
237237
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<Logger>,
238238
node_metrics: Arc<RwLock<NodeMetrics>>,
239239
) -> Self {
240+
// FIXME / TODO: We introduced this to make `bdk_esplora` work separately without updating
241+
// `lightning-transaction-sync`. We should revert this as part of of the upgrade to LDK 0.2.
242+
let mut client_builder_0_11 = esplora_client_0_11::Builder::new(&server_url);
243+
client_builder_0_11 = client_builder_0_11.timeout(DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS);
244+
let esplora_client_0_11 = client_builder_0_11.build_async().unwrap();
245+
let tx_sync =
246+
Arc::new(EsploraSyncClient::from_client(esplora_client_0_11, Arc::clone(&logger)));
247+
240248
let mut client_builder = esplora_client::Builder::new(&server_url);
241249
client_builder = client_builder.timeout(DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS);
242250
let esplora_client = client_builder.build_async().unwrap();
243-
let tx_sync =
244-
Arc::new(EsploraSyncClient::from_client(esplora_client.clone(), Arc::clone(&logger)));
251+
245252
let onchain_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
246253
let lightning_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
247254
Self::Esplora {
@@ -1088,18 +1095,24 @@ impl ChainSource {
10881095
let cur_height = channel_manager.current_best_block().height;
10891096

10901097
let now = SystemTime::now();
1098+
let unconfirmed_txids = onchain_wallet.get_unconfirmed_txids();
10911099
match bitcoind_rpc_client
1092-
.get_mempool_transactions_and_timestamp_at_height(cur_height)
1100+
.get_updated_mempool_transactions(cur_height, unconfirmed_txids)
10931101
.await
10941102
{
1095-
Ok(unconfirmed_txs) => {
1103+
Ok((unconfirmed_txs, evicted_txids)) => {
10961104
log_trace!(
10971105
logger,
1098-
"Finished polling mempool of size {} in {}ms",
1106+
"Finished polling mempool of size {} and {} evicted transactions in {}ms",
10991107
unconfirmed_txs.len(),
1108+
evicted_txids.len(),
11001109
now.elapsed().unwrap().as_millis()
11011110
);
1102-
let _ = onchain_wallet.apply_unconfirmed_txs(unconfirmed_txs);
1111+
onchain_wallet
1112+
.apply_mempool_txs(unconfirmed_txs, evicted_txids)
1113+
.unwrap_or_else(|e| {
1114+
log_error!(logger, "Failed to apply mempool transactions: {:?}", e);
1115+
});
11031116
},
11041117
Err(e) => {
11051118
log_error!(logger, "Failed to poll for mempool transactions: {:?}", e);

src/wallet/mod.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ where
107107
self.inner.lock().unwrap().tx_graph().full_txs().map(|tx_node| tx_node.tx).collect()
108108
}
109109

110+
pub(crate) fn get_unconfirmed_txids(&self) -> Vec<Txid> {
111+
self.inner
112+
.lock()
113+
.unwrap()
114+
.transactions()
115+
.filter(|t| t.chain_position.is_unconfirmed())
116+
.map(|t| t.tx_node.txid)
117+
.collect()
118+
}
119+
110120
pub(crate) fn current_best_block(&self) -> BestBlock {
111121
let checkpoint = self.inner.lock().unwrap().latest_checkpoint();
112122
BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height() }
@@ -136,11 +146,12 @@ where
136146
}
137147
}
138148

139-
pub(crate) fn apply_unconfirmed_txs(
140-
&self, unconfirmed_txs: Vec<(Transaction, u64)>,
149+
pub(crate) fn apply_mempool_txs(
150+
&self, unconfirmed_txs: Vec<(Transaction, u64)>, evicted_txids: Vec<(Txid, u64)>,
141151
) -> Result<(), Error> {
142152
let mut locked_wallet = self.inner.lock().unwrap();
143153
locked_wallet.apply_unconfirmed_txs(unconfirmed_txs);
154+
locked_wallet.apply_evicted_txs(evicted_txids);
144155

145156
let mut locked_persister = self.persister.lock().unwrap();
146157
locked_wallet.persist(&mut locked_persister).map_err(|e| {

src/wallet/ser.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,9 @@ impl<'a> Writeable for ChangeSetSerWrapper<'a, BdkTxGraphChangeSet<ConfirmationB
107107

108108
encode_tlv_stream!(writer, {
109109
(0, ChangeSetSerWrapper(&self.0.txs), required),
110+
(1, Some(&self.0.first_seen), option),
110111
(2, self.0.txouts, required),
112+
(3, Some(&self.0.last_evicted), option),
111113
(4, ChangeSetSerWrapper(&self.0.anchors), required),
112114
(6, self.0.last_seen, required),
113115
});
@@ -129,10 +131,14 @@ impl Readable for ChangeSetDeserWrapper<BdkTxGraphChangeSet<ConfirmationBlockTim
129131
ChangeSetDeserWrapper<BTreeSet<(ConfirmationBlockTime, Txid)>>,
130132
> = RequiredWrapper(None);
131133
let mut last_seen: RequiredWrapper<BTreeMap<Txid, u64>> = RequiredWrapper(None);
134+
let mut first_seen = None;
135+
let mut last_evicted = None;
132136

133137
decode_tlv_stream!(reader, {
134138
(0, txs, required),
139+
(1, first_seen, option),
135140
(2, txouts, required),
141+
(3, last_evicted, option),
136142
(4, anchors, required),
137143
(6, last_seen, required),
138144
});
@@ -142,6 +148,8 @@ impl Readable for ChangeSetDeserWrapper<BdkTxGraphChangeSet<ConfirmationBlockTim
142148
txouts: txouts.0.unwrap(),
143149
anchors: anchors.0.unwrap().0,
144150
last_seen: last_seen.0.unwrap(),
151+
first_seen: first_seen.unwrap_or_default(),
152+
last_evicted: last_evicted.unwrap_or_default(),
145153
}))
146154
}
147155
}
@@ -260,6 +268,7 @@ impl<'a> Writeable for ChangeSetSerWrapper<'a, BdkIndexerChangeSet> {
260268
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), lightning::io::Error> {
261269
CHANGESET_SERIALIZATION_VERSION.write(writer)?;
262270

271+
// Note we don't persist/use the optional spk_cache currently.
263272
encode_tlv_stream!(writer, { (0, ChangeSetSerWrapper(&self.0.last_revealed), required) });
264273
Ok(())
265274
}
@@ -275,9 +284,13 @@ impl Readable for ChangeSetDeserWrapper<BdkIndexerChangeSet> {
275284
let mut last_revealed: RequiredWrapper<ChangeSetDeserWrapper<BTreeMap<DescriptorId, u32>>> =
276285
RequiredWrapper(None);
277286

287+
// Note we don't persist/use the optional spk_cache currently.
278288
decode_tlv_stream!(reader, { (0, last_revealed, required) });
279289

280-
Ok(Self(BdkIndexerChangeSet { last_revealed: last_revealed.0.unwrap().0 }))
290+
Ok(Self(BdkIndexerChangeSet {
291+
last_revealed: last_revealed.0.unwrap().0,
292+
spk_cache: Default::default(),
293+
}))
281294
}
282295
}
283296

0 commit comments

Comments
 (0)