Skip to content

Commit 939051a

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 64e3154 commit 939051a

4 files changed

Lines changed: 36 additions & 78 deletions

File tree

Cargo.toml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ default = []
3939
#lightning-liquidity = { version = "0.2.0", features = ["std"] }
4040
#lightning-macros = { version = "0.2.0" }
4141

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

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

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

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

src/builder.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use bdk_wallet::{KeychainKind, Wallet as BdkWallet};
1818
use bitcoin::bip32::{ChildNumber, Xpriv};
1919
use bitcoin::key::Secp256k1;
2020
use bitcoin::secp256k1::PublicKey;
21-
use bitcoin::{BlockHash, Network};
21+
use bitcoin::Network;
2222
use bitcoin_payment_instructions::onion_message_resolver::LDKOnionMessageDNSSECHrnResolver;
2323
use lightning::chain::{chainmonitor, BestBlock};
2424
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs};
@@ -1686,8 +1686,8 @@ fn build_with_store_internal(
16861686
user_config,
16871687
channel_monitor_references,
16881688
);
1689-
let (_hash, channel_manager) =
1690-
<(BlockHash, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
1689+
let (_best_block, channel_manager) =
1690+
<(BestBlock, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
16911691
log_error!(logger, "Failed to read channel manager from store: {}", e);
16921692
BuildError::ReadFailed
16931693
})?;

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!(
@@ -397,7 +389,6 @@ impl BitcoindChainSource {
397389
let chain_tip =
398390
if let Some(tip) = latest_chain_tip_opt { tip } else { self.poll_chain_tip().await? };
399391

400-
let mut locked_header_cache = self.header_cache.lock().await;
401392
let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network);
402393
let chain_listener = ChainListener {
403394
onchain_wallet: Arc::clone(&onchain_wallet),
@@ -406,7 +397,7 @@ impl BitcoindChainSource {
406397
output_sweeper,
407398
};
408399
let mut spv_client =
409-
SpvClient::new(chain_tip, chain_poller, &mut *locked_header_cache, &chain_listener);
400+
SpvClient::new(chain_tip, chain_poller, HeaderCache::new(), &chain_listener);
410401

411402
let now = SystemTime::now();
412403
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: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,14 @@ 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+
let parent = child.prev().filter(|cp| cp.height() + 1 == child.height())?;
145+
current_block = Some(parent.clone());
146+
Some(parent.hash())
147+
});
148+
BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height(), previous_blocks }
142149
}
143150

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

0 commit comments

Comments
 (0)