Skip to content

Commit 147247a

Browse files
authored
Merge pull request #874 from jkczyz/2026-04-block-sync-api
Adapt to `lightning-block-sync` API changes
2 parents c54b9fd + 2ab93c1 commit 147247a

7 files changed

Lines changed: 68 additions & 98 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"

bindings/ldk_node.udl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,12 +233,6 @@ enum NodeError {
233233

234234
typedef dictionary NodeStatus;
235235

236-
[Remote]
237-
dictionary BestBlock {
238-
BlockHash block_hash;
239-
u32 height;
240-
};
241-
242236
typedef enum BuildError;
243237

244238
[Trait, WithForeign]

src/builder.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ 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;
25-
use lightning::chain::{chainmonitor, BestBlock};
25+
use lightning::chain::{chainmonitor, BestBlock as BlockLocator};
2626
use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs};
2727
use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress};
2828
use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler};
@@ -1704,16 +1704,16 @@ fn build_with_store_internal(
17041704
user_config,
17051705
channel_monitor_references,
17061706
);
1707-
let (_hash, channel_manager) =
1708-
<(BlockHash, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
1707+
let (_best_block, channel_manager) =
1708+
<(BlockLocator, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
17091709
log_error!(logger, "Failed to read channel manager from store: {}", e);
17101710
BuildError::ReadFailed
17111711
})?;
17121712
channel_manager
17131713
} else {
17141714
// We're starting a fresh node.
17151715
let best_block =
1716-
chain_tip_opt.unwrap_or_else(|| BestBlock::from_network(config.network));
1716+
chain_tip_opt.unwrap_or_else(|| BlockLocator::from_network(config.network));
17171717

17181718
let chain_params = ChainParameters { network: config.network.into(), best_block };
17191719
channelmanager::ChannelManager::new(

src/chain/bitcoind.rs

Lines changed: 14 additions & 63 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};
@@ -16,7 +16,7 @@ use base64::prelude::BASE64_STANDARD;
1616
use base64::Engine;
1717
use bitcoin::{BlockHash, FeeRate, Network, OutPoint, Transaction, Txid};
1818
use lightning::chain::chaininterface::ConfirmationTarget as LdkConfirmationTarget;
19-
use lightning::chain::{BestBlock, Listen};
19+
use lightning::chain::{BestBlock as BlockLocator, Listen};
2020
use lightning::util::ser::Writeable;
2121
use lightning_block_sync::gossip::UtxoSource;
2222
use lightning_block_sync::http::{HttpClientError, JsonResponse};
@@ -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!(
@@ -333,7 +325,7 @@ impl BitcoindChainSource {
333325
}
334326
}
335327

336-
pub(super) async fn poll_best_block(&self) -> Result<BestBlock, Error> {
328+
pub(super) async fn poll_best_block(&self) -> Result<BlockLocator, Error> {
337329
self.poll_chain_tip().await.map(|tip| tip.to_best_block())
338330
}
339331

@@ -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/chain/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::sync::{Arc, Mutex, RwLock};
1414
use std::time::Duration;
1515

1616
use bitcoin::{Script, Txid};
17-
use lightning::chain::{BestBlock, Filter};
17+
use lightning::chain::{BestBlock as BlockLocator, Filter};
1818

1919
use crate::chain::bitcoind::{BitcoindChainSource, UtxoSourceClient};
2020
use crate::chain::electrum::ElectrumChainSource;
@@ -101,7 +101,7 @@ impl ChainSource {
101101
fee_estimator: Arc<OnchainFeeEstimator>, tx_broadcaster: Arc<Broadcaster>,
102102
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<Logger>,
103103
node_metrics: Arc<RwLock<NodeMetrics>>,
104-
) -> Result<(Self, Option<BestBlock>), ()> {
104+
) -> Result<(Self, Option<BlockLocator>), ()> {
105105
let esplora_chain_source = EsploraChainSource::new(
106106
server_url,
107107
headers,
@@ -122,7 +122,7 @@ impl ChainSource {
122122
fee_estimator: Arc<OnchainFeeEstimator>, tx_broadcaster: Arc<Broadcaster>,
123123
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<Logger>,
124124
node_metrics: Arc<RwLock<NodeMetrics>>,
125-
) -> (Self, Option<BestBlock>) {
125+
) -> (Self, Option<BlockLocator>) {
126126
let electrum_chain_source = ElectrumChainSource::new(
127127
server_url,
128128
sync_config,
@@ -142,7 +142,7 @@ impl ChainSource {
142142
fee_estimator: Arc<OnchainFeeEstimator>, tx_broadcaster: Arc<Broadcaster>,
143143
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<Logger>,
144144
node_metrics: Arc<RwLock<NodeMetrics>>,
145-
) -> (Self, Option<BestBlock>) {
145+
) -> (Self, Option<BlockLocator>) {
146146
let bitcoind_chain_source = BitcoindChainSource::new_rpc(
147147
rpc_host,
148148
rpc_port,
@@ -165,7 +165,7 @@ impl ChainSource {
165165
fee_estimator: Arc<OnchainFeeEstimator>, tx_broadcaster: Arc<Broadcaster>,
166166
kv_store: Arc<DynStore>, config: Arc<Config>, rest_client_config: BitcoindRestClientConfig,
167167
logger: Arc<Logger>, node_metrics: Arc<RwLock<NodeMetrics>>,
168-
) -> (Self, Option<BestBlock>) {
168+
) -> (Self, Option<BlockLocator>) {
169169
let bitcoind_chain_source = BitcoindChainSource::new_rest(
170170
rpc_host,
171171
rpc_port,

src/lib.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance};
117117
pub use bip39;
118118
pub use bitcoin;
119119
use bitcoin::secp256k1::PublicKey;
120+
use bitcoin::BlockHash;
120121
#[cfg(feature = "uniffi")]
121122
pub use bitcoin::FeeRate;
122123
#[cfg(not(feature = "uniffi"))]
@@ -145,7 +146,7 @@ use gossip::GossipSource;
145146
use graph::NetworkGraph;
146147
use io::utils::update_and_persist_node_metrics;
147148
pub use lightning;
148-
use lightning::chain::BestBlock;
149+
use lightning::chain::BestBlock as BlockLocator;
149150
use lightning::impl_writeable_tlv_based;
150151
use lightning::ln::chan_utils::FUNDING_TRANSACTION_WITNESS_WEIGHT;
151152
use lightning::ln::channel_state::ChannelDetails as LdkChannelDetails;
@@ -2056,6 +2057,22 @@ impl Drop for Node {
20562057
}
20572058
}
20582059

2060+
/// The best known block as identified by its hash and height.
2061+
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
2062+
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
2063+
pub struct BestBlock {
2064+
/// The block's hash.
2065+
pub block_hash: BlockHash,
2066+
/// The height at which the block was confirmed.
2067+
pub height: u32,
2068+
}
2069+
2070+
impl From<BlockLocator> for BestBlock {
2071+
fn from(locator: BlockLocator) -> Self {
2072+
Self { block_hash: locator.block_hash, height: locator.height }
2073+
}
2074+
}
2075+
20592076
/// Represents the status of the [`Node`].
20602077
#[derive(Clone, Debug, PartialEq, Eq)]
20612078
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]

0 commit comments

Comments
 (0)