Skip to content

Commit ab0aa16

Browse files
jkczyzclaude
andcommitted
Adapt to lightning-block-sync API changes
Update to use the new HeaderCache type instead of implementing the Cache trait, pass BestBlock instead of BlockHash to synchronize_listeners, and pass HeaderCache by value to SpvClient::new. Also adapt to BestBlock gaining a previous_blocks field and ChannelManager deserialization returning BestBlock instead of BlockHash. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b8123d5 commit ab0aa16

4 files changed

Lines changed: 38 additions & 79 deletions

File tree

Cargo.toml

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ default = []
4040
#lightning-macros = { version = "0.2.0" }
4141
#lightning-dns-resolver = { version = "0.3.0" }
4242

43-
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std"] }
44-
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
45-
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std"] }
46-
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
47-
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["tokio"] }
48-
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
49-
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
50-
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["rest-client", "rpc-client", "tokio"] }
51-
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
52-
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std"] }
53-
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
54-
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6" }
43+
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["std"] }
44+
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
45+
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["std"] }
46+
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
47+
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["tokio"] }
48+
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
49+
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
50+
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["rest-client", "rpc-client", "tokio"] }
51+
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
52+
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["std"] }
53+
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
54+
lightning-dns-resolver = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133" }
5555

5656
bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] }
5757
bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]}
@@ -81,13 +81,13 @@ async-trait = { version = "0.1", default-features = false }
8181
vss-client = { package = "vss-client-ng", version = "0.5" }
8282
prost = { version = "0.11.6", default-features = false}
8383
#bitcoin-payment-instructions = { version = "0.6" }
84-
bitcoin-payment-instructions = { git = "https://github.com/jkczyz/bitcoin-payment-instructions", rev = "a7b32d5fded9bb45f73bf82e6d7187adf705171c" }
84+
bitcoin-payment-instructions = { git = "https://github.com/jkczyz/bitcoin-payment-instructions", rev = "340c535a600f7c43bef4c9f910edac4085f2e70c" }
8585

8686
[target.'cfg(windows)'.dependencies]
8787
winapi = { version = "0.3", features = ["winbase"] }
8888

8989
[dev-dependencies]
90-
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "38a62c32454d3eac22578144c479dbf9a6d9bff6", features = ["std", "_test_utils"] }
90+
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "044f3fab42e3085edecd40f0c9b369093edb7133", features = ["std", "_test_utils"] }
9191
rand = { version = "0.9.2", default-features = false, features = ["std", "thread_rng", "os_rng"] }
9292
proptest = "1.0.0"
9393
regex = "1.5.6"

src/builder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use bdk_wallet::{KeychainKind, Wallet as BdkWallet};
1919
use bitcoin::bip32::{ChildNumber, Xpriv};
2020
use bitcoin::key::Secp256k1;
2121
use bitcoin::secp256k1::PublicKey;
22-
use bitcoin::{BlockHash, Network};
22+
use bitcoin::Network;
2323
use bitcoin_payment_instructions::dns_resolver::DNSHrnResolver;
2424
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
2525
use lightning::chain::{chainmonitor, BestBlock};
@@ -1695,8 +1695,8 @@ fn build_with_store_internal(
16951695
user_config,
16961696
channel_monitor_references,
16971697
);
1698-
let (_hash, channel_manager) =
1699-
<(BlockHash, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
1698+
let (_best_block, channel_manager) =
1699+
<(BestBlock, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
17001700
log_error!(logger, "Failed to read channel manager from store: {}", e);
17011701
BuildError::ReadFailed
17021702
})?;

src/chain/bitcoind.rs

Lines changed: 12 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8-
use std::collections::{HashMap, VecDeque};
8+
use std::collections::HashMap;
99
use std::fmt;
1010
use std::future::Future;
1111
use std::sync::atomic::{AtomicU64, Ordering};
@@ -25,7 +25,7 @@ use lightning_block_sync::poll::{ChainPoller, ChainTip, ValidatedBlockHeader};
2525
use lightning_block_sync::rest::RestClient;
2626
use lightning_block_sync::rpc::{RpcClient, RpcClientError};
2727
use lightning_block_sync::{
28-
BlockData, BlockHeaderData, BlockSource, BlockSourceError, BlockSourceErrorKind, Cache,
28+
BlockData, BlockHeaderData, BlockSource, BlockSourceError, BlockSourceErrorKind, HeaderCache,
2929
SpvClient,
3030
};
3131
use serde::Serialize;
@@ -49,7 +49,6 @@ const CHAIN_POLLING_TIMEOUT_SECS: u64 = 10;
4949

5050
pub(super) struct BitcoindChainSource {
5151
api_client: Arc<BitcoindClient>,
52-
header_cache: tokio::sync::Mutex<BoundedHeaderCache>,
5352
latest_chain_tip: RwLock<Option<ValidatedBlockHeader>>,
5453
wallet_polling_status: Mutex<WalletSyncStatus>,
5554
fee_estimator: Arc<OnchainFeeEstimator>,
@@ -72,12 +71,10 @@ impl BitcoindChainSource {
7271
rpc_password.clone(),
7372
));
7473

75-
let header_cache = tokio::sync::Mutex::new(BoundedHeaderCache::new());
7674
let latest_chain_tip = RwLock::new(None);
7775
let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed);
7876
Self {
7977
api_client,
80-
header_cache,
8178
latest_chain_tip,
8279
wallet_polling_status,
8380
fee_estimator,
@@ -103,13 +100,11 @@ impl BitcoindChainSource {
103100
rpc_password,
104101
));
105102

106-
let header_cache = tokio::sync::Mutex::new(BoundedHeaderCache::new());
107103
let latest_chain_tip = RwLock::new(None);
108104
let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed);
109105

110106
Self {
111107
api_client,
112-
header_cache,
113108
latest_chain_tip,
114109
wallet_polling_status,
115110
fee_estimator,
@@ -153,46 +148,43 @@ impl BitcoindChainSource {
153148
return;
154149
}
155150

156-
let channel_manager_best_block_hash = channel_manager.current_best_block().block_hash;
157-
let sweeper_best_block_hash = output_sweeper.current_best_block().block_hash;
158-
let onchain_wallet_best_block_hash = onchain_wallet.current_best_block().block_hash;
151+
let onchain_wallet_best_block = onchain_wallet.current_best_block();
152+
let channel_manager_best_block = channel_manager.current_best_block();
153+
let sweeper_best_block = output_sweeper.current_best_block();
159154

160155
let mut chain_listeners = vec![
161-
(onchain_wallet_best_block_hash, &*onchain_wallet as &(dyn Listen + Send + Sync)),
162-
(channel_manager_best_block_hash, &*channel_manager as &(dyn Listen + Send + Sync)),
163-
(sweeper_best_block_hash, &*output_sweeper as &(dyn Listen + Send + Sync)),
156+
(onchain_wallet_best_block, &*onchain_wallet as &(dyn Listen + Send + Sync)),
157+
(channel_manager_best_block, &*channel_manager as &(dyn Listen + Send + Sync)),
158+
(sweeper_best_block, &*output_sweeper as &(dyn Listen + Send + Sync)),
164159
];
165160

166161
// TODO: Eventually we might want to see if we can synchronize `ChannelMonitor`s
167162
// before giving them to `ChainMonitor` it the first place. However, this isn't
168163
// trivial as we load them on initialization (in the `Builder`) and only gain
169164
// network access during `start`. For now, we just make sure we get the worst known
170165
// block hash and sychronize them via `ChainMonitor`.
171-
if let Some(worst_channel_monitor_block_hash) = chain_monitor
166+
if let Some(worst_channel_monitor_best_block) = chain_monitor
172167
.list_monitors()
173168
.iter()
174169
.flat_map(|channel_id| chain_monitor.get_monitor(*channel_id))
175170
.map(|m| m.current_best_block())
176171
.min_by_key(|b| b.height)
177-
.map(|b| b.block_hash)
178172
{
179173
chain_listeners.push((
180-
worst_channel_monitor_block_hash,
174+
worst_channel_monitor_best_block,
181175
&*chain_monitor as &(dyn Listen + Send + Sync),
182176
));
183177
}
184178

185-
let mut locked_header_cache = self.header_cache.lock().await;
186179
let now = SystemTime::now();
187180
match synchronize_listeners(
188181
self.api_client.as_ref(),
189182
self.config.network,
190-
&mut *locked_header_cache,
191183
chain_listeners.clone(),
192184
)
193185
.await
194186
{
195-
Ok(chain_tip) => {
187+
Ok((_header_cache, chain_tip)) => {
196188
{
197189
let elapsed_ms = now.elapsed().map(|d| d.as_millis()).unwrap_or(0);
198190
log_info!(
@@ -400,7 +392,6 @@ impl BitcoindChainSource {
400392
let chain_tip =
401393
if let Some(tip) = latest_chain_tip_opt { tip } else { self.poll_chain_tip().await? };
402394

403-
let mut locked_header_cache = self.header_cache.lock().await;
404395
let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network);
405396
let chain_listener = ChainListener {
406397
onchain_wallet: Arc::clone(&onchain_wallet),
@@ -409,7 +400,7 @@ impl BitcoindChainSource {
409400
output_sweeper,
410401
};
411402
let mut spv_client =
412-
SpvClient::new(chain_tip, chain_poller, &mut *locked_header_cache, &chain_listener);
403+
SpvClient::new(chain_tip, chain_poller, HeaderCache::new(), &chain_listener);
413404

414405
let now = SystemTime::now();
415406
match spv_client.poll_best_tip().await {
@@ -1350,46 +1341,6 @@ pub(crate) enum FeeRateEstimationMode {
13501341
Conservative,
13511342
}
13521343

1353-
const MAX_HEADER_CACHE_ENTRIES: usize = 100;
1354-
1355-
pub(crate) struct BoundedHeaderCache {
1356-
header_map: HashMap<BlockHash, ValidatedBlockHeader>,
1357-
recently_seen: VecDeque<BlockHash>,
1358-
}
1359-
1360-
impl BoundedHeaderCache {
1361-
pub(crate) fn new() -> Self {
1362-
let header_map = HashMap::new();
1363-
let recently_seen = VecDeque::new();
1364-
Self { header_map, recently_seen }
1365-
}
1366-
}
1367-
1368-
impl Cache for BoundedHeaderCache {
1369-
fn look_up(&self, block_hash: &BlockHash) -> Option<&ValidatedBlockHeader> {
1370-
self.header_map.get(block_hash)
1371-
}
1372-
1373-
fn block_connected(&mut self, block_hash: BlockHash, block_header: ValidatedBlockHeader) {
1374-
self.recently_seen.push_back(block_hash);
1375-
self.header_map.insert(block_hash, block_header);
1376-
1377-
if self.header_map.len() >= MAX_HEADER_CACHE_ENTRIES {
1378-
// Keep dropping old entries until we've actually removed a header entry.
1379-
while let Some(oldest_entry) = self.recently_seen.pop_front() {
1380-
if self.header_map.remove(&oldest_entry).is_some() {
1381-
break;
1382-
}
1383-
}
1384-
}
1385-
}
1386-
1387-
fn block_disconnected(&mut self, block_hash: &BlockHash) -> Option<ValidatedBlockHeader> {
1388-
self.recently_seen.retain(|e| e != block_hash);
1389-
self.header_map.remove(block_hash)
1390-
}
1391-
}
1392-
13931344
pub(crate) struct ChainListener {
13941345
pub(crate) onchain_wallet: Arc<Wallet>,
13951346
pub(crate) channel_manager: Arc<ChannelManager>,

src/wallet/mod.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,15 @@ impl Wallet {
138138

139139
pub(crate) fn current_best_block(&self) -> BestBlock {
140140
let checkpoint = self.inner.lock().expect("lock").latest_checkpoint();
141-
BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height() }
141+
let mut current_block = Some(checkpoint.clone());
142+
let previous_blocks = std::array::from_fn(|_| {
143+
let child = current_block.take()?;
144+
// BDK's checkpoint chain may be sparse; only accept contiguous parents.
145+
let parent = child.prev().filter(|cp| cp.height() + 1 == child.height())?;
146+
current_block = Some(parent.clone());
147+
Some(parent.hash())
148+
});
149+
BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height(), previous_blocks }
142150
}
143151

144152
pub(crate) fn apply_update(&self, update: impl Into<Update>) -> Result<(), Error> {

0 commit comments

Comments
 (0)