Skip to content

Commit ea17859

Browse files
jkczyzclaude
andcommitted
Expose a bindings-compatible BestBlock
UniFFI cannot represent the fixed-size array that upstream's BestBlock carries via `previous_blocks`, so NodeStatus.current_best_block was unusable from Swift, Kotlin, and Python once upstream added that field. Introduce a small ldk-node BestBlock with just hash and height — the pieces bindings can handle — and expose it in place of the upstream type on the public API. Generated with assistance from Claude Code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 3de8329 commit ea17859

6 files changed

Lines changed: 32 additions & 21 deletions

File tree

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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use bitcoin::secp256k1::PublicKey;
2222
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};
@@ -1696,15 +1696,15 @@ fn build_with_store_internal(
16961696
channel_monitor_references,
16971697
);
16981698
let (_best_block, channel_manager) =
1699-
<(BestBlock, ChannelManager)>::read(&mut &*reader, read_args).map_err(|e| {
1699+
<(BlockLocator, 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
})?;
17031703
channel_manager
17041704
} else {
17051705
// We're starting a fresh node.
17061706
let best_block =
1707-
chain_tip_opt.unwrap_or_else(|| BestBlock::from_network(config.network));
1707+
chain_tip_opt.unwrap_or_else(|| BlockLocator::from_network(config.network));
17081708

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

src/chain/bitcoind.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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};
@@ -325,7 +325,7 @@ impl BitcoindChainSource {
325325
}
326326
}
327327

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

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))]

src/wallet/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use lightning::chain::chaininterface::{
3535
BroadcasterInterface, INCREMENTAL_RELAY_FEE_SAT_PER_1000_WEIGHT,
3636
};
3737
use lightning::chain::channelmonitor::ANTI_REORG_DELAY;
38-
use lightning::chain::{BestBlock, ClaimId, Listen};
38+
use lightning::chain::{BestBlock as BlockLocator, ClaimId, Listen};
3939
use lightning::ln::channelmanager::PaymentId;
4040
use lightning::ln::funding::FundingTxInput;
4141
use lightning::ln::inbound_payment::ExpandedKey;
@@ -136,7 +136,7 @@ impl Wallet {
136136
.collect()
137137
}
138138

139-
pub(crate) fn current_best_block(&self) -> BestBlock {
139+
pub(crate) fn current_best_block(&self) -> BlockLocator {
140140
let checkpoint = self.inner.lock().expect("lock").latest_checkpoint();
141141
let mut current_block = Some(checkpoint.clone());
142142
let previous_blocks = std::array::from_fn(|_| {
@@ -145,7 +145,7 @@ impl Wallet {
145145
current_block = Some(parent.clone());
146146
Some(parent.hash())
147147
});
148-
BestBlock { block_hash: checkpoint.hash(), height: checkpoint.height(), previous_blocks }
148+
BlockLocator { block_hash: checkpoint.hash(), height: checkpoint.height(), previous_blocks }
149149
}
150150

151151
pub(crate) fn apply_update(&self, update: impl Into<Update>) -> Result<(), Error> {
@@ -1498,7 +1498,7 @@ impl Listen for Wallet {
14981498
};
14991499
}
15001500

1501-
fn blocks_disconnected(&self, _fork_point_block: BestBlock) {
1501+
fn blocks_disconnected(&self, _fork_point_block: BlockLocator) {
15021502
// This is a no-op as we don't have to tell BDK about disconnections. According to the BDK
15031503
// team, it's sufficient in case of a reorg to always connect blocks starting from the last
15041504
// point of disagreement.

0 commit comments

Comments
 (0)