From 16aabce7b372b8760fca1ba2acac585883c2d047 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 28 Dec 2024 00:24:51 +0000 Subject: [PATCH 01/11] Mark `CheckedHrpstringError` instances as no-export The details of these errors aren't particularly relevant, and its not worth the effort of exporting them, so we just mark them no-export here. --- lightning-invoice/src/lib.rs | 5 ++++- lightning/src/offers/parse.rs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lightning-invoice/src/lib.rs b/lightning-invoice/src/lib.rs index 3634d67f1da..47f929377de 100644 --- a/lightning-invoice/src/lib.rs +++ b/lightning-invoice/src/lib.rs @@ -91,7 +91,10 @@ use crate::ser::Base32Iterable; #[allow(missing_docs)] #[derive(PartialEq, Eq, Debug, Clone)] pub enum Bolt11ParseError { - Bech32Error(CheckedHrpstringError), + Bech32Error( + /// This is not exported to bindings users as the details don't matter much + CheckedHrpstringError, + ), ParseAmountError(ParseIntError), MalformedSignature(bitcoin::secp256k1::Error), BadPrefix, diff --git a/lightning/src/offers/parse.rs b/lightning/src/offers/parse.rs index 8e8d01b4e50..99dd1bb938d 100644 --- a/lightning/src/offers/parse.rs +++ b/lightning/src/offers/parse.rs @@ -142,7 +142,10 @@ pub enum Bolt12ParseError { /// being parsed. InvalidBech32Hrp, /// The string could not be bech32 decoded. - Bech32(CheckedHrpstringError), + Bech32( + /// This is not exported to bindings users as the details don't matter much + CheckedHrpstringError, + ), /// The bech32 decoded string could not be decoded as the expected message type. Decode(DecodeError), /// The parsed message has invalid semantics. From 7fb0f2a457bdef4e72a5547f9ace2375fb304fc0 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 19:58:24 +0000 Subject: [PATCH 02/11] Mark BOLT 12 builders no-export in the new `OffersMessageFlow` As move semantics do not map to bindings, the BOLT 12 object builders are marked no-export. In the new `OffersMesageFlow`, here, we also mark the methods which return these builders as no-export. --- lightning/src/offers/flow.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lightning/src/offers/flow.rs b/lightning/src/offers/flow.rs index 74e5f029597..88f0cc5079c 100644 --- a/lightning/src/offers/flow.rs +++ b/lightning/src/offers/flow.rs @@ -597,6 +597,8 @@ where /// /// Returns an error if the parameterized [`Router`] is unable to create a blinded path for the offer. /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. + /// /// [`DefaultMessageRouter`]: crate::onion_message::messenger::DefaultMessageRouter pub fn create_offer_builder( &self, entropy_source: ES, peers: Vec, @@ -618,6 +620,8 @@ where /// This gives users full control over how the [`BlindedMessagePath`] is constructed, /// including the option to omit it entirely. /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. + /// /// See [`Self::create_offer_builder`] for more details on usage. pub fn create_offer_builder_using_router( &self, router: ME, entropy_source: ES, peers: Vec, @@ -644,6 +648,8 @@ where /// 2. Use [`Self::create_static_invoice_builder`] to create a [`StaticInvoice`] from this /// [`Offer`] plus the returned [`Nonce`], and provide the static invoice to the /// aforementioned always-online node. + /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub fn create_async_receive_offer_builder( &self, entropy_source: ES, message_paths_to_always_online_node: Vec, ) -> Result<(OfferBuilder<'_, DerivedMetadata, secp256k1::All>, Nonce), Bolt12SemanticError> @@ -726,6 +732,8 @@ where /// - `amount_msats` is invalid, or /// - The parameterized [`Router`] is unable to create a blinded path for the refund. /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. + /// /// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed /// [`RouteParameters::from_payment_params_and_value`]: crate::routing::router::RouteParameters::from_payment_params_and_value pub fn create_refund_builder( @@ -762,6 +770,8 @@ where /// return an error if the provided [`MessageRouter`] fails to construct a valid /// [`BlindedMessagePath`] for the refund. /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. + /// /// [`Refund`]: crate::offers::refund::Refund /// [`BlindedMessagePath`]: crate::blinded_path::message::BlindedMessagePath /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice @@ -797,6 +807,8 @@ where /// # Nonce /// The nonce is used to create a unique [`InvoiceRequest::payer_metadata`] for the invoice request. /// These will be used to verify the corresponding [`Bolt12Invoice`] when it is received. + /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub fn create_invoice_request_builder<'a>( &'a self, offer: &'a Offer, nonce: Nonce, payment_id: PaymentId, ) -> Result, Bolt12SemanticError> { @@ -812,6 +824,8 @@ where /// Creates a [`StaticInvoiceBuilder`] from the corresponding [`Offer`] and [`Nonce`] that were /// created via [`Self::create_async_receive_offer_builder`]. + /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub fn create_static_invoice_builder<'a, ES: Deref, R: Deref>( &self, router: &R, entropy_source: ES, offer: &'a Offer, offer_nonce: Nonce, payment_secret: PaymentSecret, relative_expiry_secs: u32, @@ -884,6 +898,8 @@ where /// /// Returns an error if the refund targets a different chain or if no valid /// blinded path can be constructed. + /// + /// This is not exported to bindings users as builder patterns don't map outside of move semantics. pub fn create_invoice_builder_from_refund<'a, ES: Deref, R: Deref, F>( &'a self, router: &R, entropy_source: ES, refund: &'a Refund, usable_channels: Vec, get_payment_info: F, From 2bf737cea1e4e5dde69fa1f3f7c28bb888713f20 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 20:00:15 +0000 Subject: [PATCH 03/11] Require the high-level sign traits instead of `SignFn` in bindings Methods like `StaticInvoice::sign` have their own signing-function traits, so there's no actual need to use `SignFn` directly, its just a useful generic wrapper. Sadly, because it uses `AsRef` bounds, which aren't really practical to map in bindings, we can't really expose it directly in bindings. Because there's an alternative and its tricky to expose, we simply mark it no-export here. --- lightning/src/offers/merkle.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lightning/src/offers/merkle.rs b/lightning/src/offers/merkle.rs index 4f27130bcc9..1a38fe5441f 100644 --- a/lightning/src/offers/merkle.rs +++ b/lightning/src/offers/merkle.rs @@ -94,6 +94,9 @@ pub enum SignError { } /// A function for signing a [`TaggedHash`]. +/// +/// This is not exported to bindings users as signing functions should just be used per-signed-type +/// instead. pub trait SignFn> { /// Signs a [`TaggedHash`] computed over the merkle root of `message`'s TLV stream. fn sign(&self, message: &T) -> Result; From 3f82fd613ba10f4e41e211dab113b2d45ad6f84d Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 00:01:15 +0000 Subject: [PATCH 04/11] Mark async traits and structs no-export We do not currently support async traits or methods in our home-grown bindings logic, so here mark them no-export. --- lightning/src/chain/chainmonitor.rs | 4 ++++ lightning/src/events/bump_transaction/mod.rs | 8 ++++++++ lightning/src/sign/mod.rs | 2 ++ lightning/src/util/async_poll.rs | 12 ++++++++++++ lightning/src/util/native_async.rs | 2 ++ lightning/src/util/persist.rs | 5 +++++ lightning/src/util/sweep.rs | 4 ++++ 7 files changed, 37 insertions(+) diff --git a/lightning/src/chain/chainmonitor.rs b/lightning/src/chain/chainmonitor.rs index 62b6c9f5541..d8d6c90921f 100644 --- a/lightning/src/chain/chainmonitor.rs +++ b/lightning/src/chain/chainmonitor.rs @@ -253,6 +253,8 @@ impl Deref for LockedChannelMonitor<'_, Chann /// An unconstructable [`Persist`]er which is used under the hood when you call /// [`ChainMonitor::new_async_beta`]. +/// +/// This is not exported to bindings users as async is not supported outside of Rust. pub struct AsyncPersister< K: Deref + MaybeSend + MaybeSync + 'static, S: FutureSpawner, @@ -431,6 +433,8 @@ impl< /// [`MonitorUpdatingPersisterAsync`] and thus allows persistence to be completed async. /// /// Note that async monitor updating is considered beta, and bugs may be triggered by its use. + /// + /// This is not exported to bindings users as async is not supported outside of Rust. pub fn new_async_beta( chain_source: Option, broadcaster: T, logger: L, feeest: F, persister: MonitorUpdatingPersisterAsync, _entropy_source: ES, diff --git a/lightning/src/events/bump_transaction/mod.rs b/lightning/src/events/bump_transaction/mod.rs index ec55c92c090..58a9b6acebe 100644 --- a/lightning/src/events/bump_transaction/mod.rs +++ b/lightning/src/events/bump_transaction/mod.rs @@ -353,6 +353,8 @@ pub struct CoinSelection { /// which can provide a default implementation of this trait when used with [`Wallet`]. /// /// For a synchronous version of this trait, see [`sync::CoinSelectionSourceSync`]. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait CoinSelectionSource { /// Performs coin selection of a set of UTXOs, with at least 1 confirmation each, that are /// available to spend. Implementations are free to pick their coin selection algorithm of @@ -404,6 +406,8 @@ pub trait CoinSelectionSource { /// provide a default implementation to [`CoinSelectionSource`]. /// /// For a synchronous version of this trait, see [`sync::WalletSourceSync`]. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait WalletSource { /// Returns all UTXOs, with at least 1 confirmation each, that are available to spend. fn list_confirmed_utxos<'a>(&'a self) -> AsyncResult<'a, Vec, ()>; @@ -424,6 +428,8 @@ pub trait WalletSource { /// spends may happen. /// /// For a synchronous version of this wrapper, see [`sync::WalletSync`]. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub struct Wallet where W::Target: WalletSource + MaybeSend, @@ -670,6 +676,8 @@ where /// /// For a synchronous version of this handler, see [`sync::BumpTransactionEventHandlerSync`]. /// +/// This is not exported to bindings users as async is only supported in Rust. +/// /// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction pub struct BumpTransactionEventHandler where diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 88a9f32e466..8a5aceb9a34 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1058,6 +1058,8 @@ pub trait SignerProvider { /// A helper trait that describes an on-chain wallet capable of returning a (change) destination /// script. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait ChangeDestinationSource { /// Returns a script pubkey which can be used as a change destination for /// [`OutputSpender::spend_spendable_outputs`]. diff --git a/lightning/src/util/async_poll.rs b/lightning/src/util/async_poll.rs index 7161bc77123..eefa40d1055 100644 --- a/lightning/src/util/async_poll.rs +++ b/lightning/src/util/async_poll.rs @@ -94,27 +94,39 @@ pub(crate) fn dummy_waker() -> Waker { #[cfg(feature = "std")] /// A type alias for a future that returns a result of type `T` or error `E`. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub type AsyncResult<'a, T, E> = Pin> + 'a + Send>>; #[cfg(not(feature = "std"))] /// A type alias for a future that returns a result of type `T` or error `E`. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub type AsyncResult<'a, T, E> = Pin> + 'a>>; /// Marker trait to optionally implement `Sync` under std. +/// +/// This is not exported to bindings users as async is only supported in Rust. #[cfg(feature = "std")] pub use core::marker::Sync as MaybeSync; #[cfg(not(feature = "std"))] /// Marker trait to optionally implement `Sync` under std. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait MaybeSync {} #[cfg(not(feature = "std"))] impl MaybeSync for T where T: ?Sized {} /// Marker trait to optionally implement `Send` under std. +/// +/// This is not exported to bindings users as async is only supported in Rust. #[cfg(feature = "std")] pub use core::marker::Send as MaybeSend; #[cfg(not(feature = "std"))] /// Marker trait to optionally implement `Send` under std. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait MaybeSend {} #[cfg(not(feature = "std"))] impl MaybeSend for T where T: ?Sized {} diff --git a/lightning/src/util/native_async.rs b/lightning/src/util/native_async.rs index dc26cb42bd0..886146e976d 100644 --- a/lightning/src/util/native_async.rs +++ b/lightning/src/util/native_async.rs @@ -18,6 +18,8 @@ use core::future::Future; use core::pin::Pin; /// A generic trait which is able to spawn futures in the background. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait FutureSpawner: MaybeSend + MaybeSync + 'static { /// Spawns the given future as a background task. /// diff --git a/lightning/src/util/persist.rs b/lightning/src/util/persist.rs index 49addd7dbc3..7be957a1f8a 100644 --- a/lightning/src/util/persist.rs +++ b/lightning/src/util/persist.rs @@ -155,6 +155,7 @@ where } } +/// This is not exported to bindings users as async is only supported in Rust. impl KVStore for KVStoreSyncWrapper where K::Target: KVStoreSync, @@ -213,6 +214,8 @@ where /// **Note:** Users migrating custom persistence backends from the pre-v0.0.117 `KVStorePersister` /// interface can use a concatenation of `[{primary_namespace}/[{secondary_namespace}/]]{key}` to /// recover a `key` compatible with the data model previously assumed by `KVStorePersister::persist`. +/// +/// This is not exported to bindings users as async is only supported in Rust. pub trait KVStore { /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and /// `key`. @@ -717,6 +720,8 @@ where /// Unlike [`MonitorUpdatingPersister`], this does not implement [`Persist`], but is instead used /// directly by the [`ChainMonitor`] via [`ChainMonitor::new_async_beta`]. /// +/// This is not exported to bindings users as async is only supported in Rust. +/// /// [`ChainMonitor`]: crate::chain::chainmonitor::ChainMonitor /// [`ChainMonitor::new_async_beta`]: crate::chain::chainmonitor::ChainMonitor::new_async_beta pub struct MonitorUpdatingPersisterAsync< diff --git a/lightning/src/util/sweep.rs b/lightning/src/util/sweep.rs index 95a7585ecde..a6b11ac67d0 100644 --- a/lightning/src/util/sweep.rs +++ b/lightning/src/util/sweep.rs @@ -329,6 +329,8 @@ impl_writeable_tlv_based_enum!(OutputSpendStatus, /// required to give their chain data sources (i.e., [`Filter`] implementation) to the respective /// constructor. /// +/// This is not exported to bindings users as async is not supported outside of Rust. +/// /// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs pub struct OutputSweeper where @@ -979,6 +981,8 @@ where /// this [`OutputSweeperSync`], fetching an async [`OutputSweeper`] won't accomplish much, all /// the async methods will hang waiting on your sync [`KVStore`] and likely confuse your async /// runtime. This exists primarily for LDK-internal use, including outside of this crate. + /// + /// This is not exported to bindings users as async is not supported outside of Rust. #[doc(hidden)] pub fn sweeper_async( &self, From b07111e330941e4380b1886034bbffd39681dd20 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 14:52:40 +0000 Subject: [PATCH 05/11] Import `ChannelTransactionParameters` from its real path Rather than importing `ChannelTransactionParameters` via the `use` in `lightning::sign`, import it via its real path in `lightning::sign::ecdsa`. This makes reading the code (incredibly marginally) simpler, but also makes the bindings generator happy. --- lightning/src/sign/ecdsa.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lightning/src/sign/ecdsa.rs b/lightning/src/sign/ecdsa.rs index bfa3a27acb1..e13285722af 100644 --- a/lightning/src/sign/ecdsa.rs +++ b/lightning/src/sign/ecdsa.rs @@ -7,7 +7,8 @@ use bitcoin::secp256k1::ecdsa::Signature; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use crate::ln::chan_utils::{ - ClosingTransaction, CommitmentTransaction, HTLCOutputInCommitment, HolderCommitmentTransaction, + ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction, + HTLCOutputInCommitment, HolderCommitmentTransaction, }; use crate::ln::msgs::UnsignedChannelAnnouncement; use crate::types::payment::PaymentPreimage; @@ -15,7 +16,7 @@ use crate::types::payment::PaymentPreimage; #[allow(unused_imports)] use crate::prelude::*; -use crate::sign::{ChannelSigner, ChannelTransactionParameters, HTLCDescriptor}; +use crate::sign::{ChannelSigner, HTLCDescriptor}; /// A trait to sign Lightning channel transactions as described in /// [BOLT 3](https://github.com/lightning/bolts/blob/master/03-transactions.md). From 8eabcc1299470c1478b5c2f4778c40f5ba0487e3 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 00:22:02 +0000 Subject: [PATCH 06/11] Copy no-export tags to new serialization traits In 0.2 we added new `LengthLimitedRead` and `LengthReadable` traits, but forgot to copy the no-export tags from the existing `Read` and `Readable` traits. Here we add the missing tags. --- lightning/src/util/ser.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index d78b3e921cc..f821aa5afc0 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -229,6 +229,8 @@ impl<'a, R: Read> Read for FixedLengthReader<'a, R> { } } +/// This is not exported to bindings users as reads are always from byte arrays, never streams, in +/// bindings. impl<'a, R: Read> LengthLimitedRead for FixedLengthReader<'a, R> { #[inline] fn remaining_bytes(&self) -> u64 { @@ -350,6 +352,9 @@ where /// A [`io::Read`] that limits the amount of bytes that can be read. Implementations should ensure /// that the object being read will only consume a fixed number of bytes from the underlying /// [`io::Read`], see [`FixedLengthReader`] for an example. +/// +/// This is not exported to bindings users as reads are always from byte arrays, never streams, in +/// bindings. pub trait LengthLimitedRead: Read { /// The number of bytes remaining to be read. fn remaining_bytes(&self) -> u64; @@ -379,6 +384,9 @@ where /// /// Any type that implements [`Readable`] also automatically has a [`LengthReadable`] /// implementation, but some types, most notably onion packets, only implement [`LengthReadable`]. +/// +/// This is not exported to bindings users as reads are always from byte arrays, never streams, in +/// bindings. pub trait LengthReadable where Self: Sized, From 126ac5092571d7c738d02fb06b06bd878c1107bd Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 00:14:02 +0000 Subject: [PATCH 07/11] `use` `Vec` from `alloc` rather than the crate prelude This avoids confusing the bindings generator. --- lightning/src/ln/funding.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/funding.rs b/lightning/src/ln/funding.rs index ae7e36ac452..3cabb8201a9 100644 --- a/lightning/src/ln/funding.rs +++ b/lightning/src/ln/funding.rs @@ -9,12 +9,13 @@ //! Types pertaining to funding channels. +use alloc::vec::Vec; + use bitcoin::{Amount, ScriptBuf, SignedAmount, TxOut}; use bitcoin::{Script, Sequence, Transaction, Weight}; use crate::events::bump_transaction::Utxo; use crate::ln::chan_utils::EMPTY_SCRIPT_SIG_WEIGHT; -use crate::prelude::Vec; use crate::sign::{P2TR_KEY_PATH_WITNESS_WEIGHT, P2WPKH_WITNESS_WEIGHT}; /// The components of a splice's funding transaction that are contributed by one party. From c31144718e362826519d38796ce4b1898f3a29f2 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 20:28:58 +0000 Subject: [PATCH 08/11] Copy async docs from async bump transaction objects to sync ones When we added the async traits and wrapper structs for the transaction-bumping logic, we didn't bother copying the documentation to the sync wrappers as we figured the links sufficed. Sadly, however, this means that our bindings logic will have no docs but a broken link to an async object that doesn't exist. Instead, here, we copy the docs from the async objects to the sync ones, at least leaving behind a comment noting that both need updating whenever one gets updated. We also fix one bogus link in `Wallet`'s docs. --- lightning/src/events/bump_transaction/mod.rs | 10 ++- lightning/src/events/bump_transaction/sync.rs | 87 +++++++++++++++++-- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/lightning/src/events/bump_transaction/mod.rs b/lightning/src/events/bump_transaction/mod.rs index 58a9b6acebe..3d9beb82c07 100644 --- a/lightning/src/events/bump_transaction/mod.rs +++ b/lightning/src/events/bump_transaction/mod.rs @@ -355,6 +355,7 @@ pub struct CoinSelection { /// For a synchronous version of this trait, see [`sync::CoinSelectionSourceSync`]. /// /// This is not exported to bindings users as async is only supported in Rust. +// Note that updates to documentation on this trait should be copied to the synchronous version. pub trait CoinSelectionSource { /// Performs coin selection of a set of UTXOs, with at least 1 confirmation each, that are /// available to spend. Implementations are free to pick their coin selection algorithm of @@ -408,6 +409,7 @@ pub trait CoinSelectionSource { /// For a synchronous version of this trait, see [`sync::WalletSourceSync`]. /// /// This is not exported to bindings users as async is only supported in Rust. +// Note that updates to documentation on this trait should be copied to the synchronous version. pub trait WalletSource { /// Returns all UTXOs, with at least 1 confirmation each, that are available to spend. fn list_confirmed_utxos<'a>(&'a self) -> AsyncResult<'a, Vec, ()>; @@ -423,13 +425,14 @@ pub trait WalletSource { fn sign_psbt<'a>(&'a self, psbt: Psbt) -> AsyncResult<'a, Transaction, ()>; } -/// A wrapper over [`WalletSource`] that implements [`CoinSelection`] by preferring UTXOs that would -/// avoid conflicting double spends. If not enough UTXOs are available to do so, conflicting double -/// spends may happen. +/// A wrapper over [`WalletSource`] that implements [`CoinSelectionSource`] by preferring UTXOs +/// that would avoid conflicting double spends. If not enough UTXOs are available to do so, +/// conflicting double spends may happen. /// /// For a synchronous version of this wrapper, see [`sync::WalletSync`]. /// /// This is not exported to bindings users as async is only supported in Rust. +// Note that updates to documentation on this struct should be copied to the synchronous version. pub struct Wallet where W::Target: WalletSource + MaybeSend, @@ -679,6 +682,7 @@ where /// This is not exported to bindings users as async is only supported in Rust. /// /// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction +// Note that updates to documentation on this struct should be copied to the synchronous version. pub struct BumpTransactionEventHandler where B::Target: BroadcasterInterface, diff --git a/lightning/src/events/bump_transaction/sync.rs b/lightning/src/events/bump_transaction/sync.rs index c987b871868..653710a3358 100644 --- a/lightning/src/events/bump_transaction/sync.rs +++ b/lightning/src/events/bump_transaction/sync.rs @@ -28,13 +28,26 @@ use super::{ WalletSource, }; -/// A synchronous version of the [`WalletSource`] trait. +/// An alternative to [`CoinSelectionSourceSync`] that can be implemented and used along +/// [`WalletSync`] to provide a default implementation to [`CoinSelectionSourceSync`]. +/// +/// For an asynchronous version of this trait, see [`WalletSource`]. +// Note that updates to documentation on this trait should be copied to the asynchronous version. pub trait WalletSourceSync { - /// A synchronous version of [`WalletSource::list_confirmed_utxos`]. + /// Returns all UTXOs, with at least 1 confirmation each, that are available to spend. fn list_confirmed_utxos(&self) -> Result, ()>; - /// A synchronous version of [`WalletSource::get_change_script`]. + /// Returns a script to use for change above dust resulting from a successful coin selection + /// attempt. fn get_change_script(&self) -> Result; - /// A Synchronous version of [`WalletSource::sign_psbt`]. + /// Signs and provides the full [`TxIn::script_sig`] and [`TxIn::witness`] for all inputs within + /// the transaction known to the wallet (i.e., any provided via + /// [`WalletSource::list_confirmed_utxos`]). + /// + /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the + /// unsigned transaction and then sign it with your wallet. + /// + /// [`TxIn::script_sig`]: bitcoin::TxIn::script_sig + /// [`TxIn::witness`]: bitcoin::TxIn::witness fn sign_psbt(&self, psbt: Psbt) -> Result; } @@ -74,7 +87,12 @@ where } } -/// A synchronous wrapper around [`Wallet`] to be used in contexts where async is not available. +/// A wrapper over [`WalletSourceSync`] that implements [`CoinSelectionSourceSync`] by preferring +/// UTXOs that would avoid conflicting double spends. If not enough UTXOs are available to do so, +/// conflicting double spends may happen. +/// +/// For an asynchronous version of this wrapper, see [`Wallet`]. +// Note that updates to documentation on this struct should be copied to the asynchronous version. pub struct WalletSync where W::Target: WalletSourceSync + MaybeSend, @@ -136,15 +154,59 @@ where } } -/// A synchronous version of the [`CoinSelectionSource`] trait. +/// An abstraction over a bitcoin wallet that can perform coin selection over a set of UTXOs and can +/// sign for them. The coin selection method aims to mimic Bitcoin Core's `fundrawtransaction` RPC, +/// which most wallets should be able to satisfy. Otherwise, consider implementing +/// [`WalletSourceSync`], which can provide a default implementation of this trait when used with +/// [`WalletSync`]. +/// +/// For an asynchronous version of this trait, see [`CoinSelectionSource`]. +// Note that updates to documentation on this trait should be copied to the asynchronous version. pub trait CoinSelectionSourceSync { - /// A synchronous version of [`CoinSelectionSource::select_confirmed_utxos`]. + /// Performs coin selection of a set of UTXOs, with at least 1 confirmation each, that are + /// available to spend. Implementations are free to pick their coin selection algorithm of + /// choice, as long as the following requirements are met: + /// + /// 1. `must_spend` contains a set of [`Input`]s that must be included in the transaction + /// throughout coin selection, but must not be returned as part of the result. + /// 2. `must_pay_to` contains a set of [`TxOut`]s that must be included in the transaction + /// throughout coin selection. In some cases, like when funding an anchor transaction, this + /// set is empty. Implementations should ensure they handle this correctly on their end, + /// e.g., Bitcoin Core's `fundrawtransaction` RPC requires at least one output to be + /// provided, in which case a zero-value empty OP_RETURN output can be used instead. + /// 3. Enough inputs must be selected/contributed for the resulting transaction (including the + /// inputs and outputs noted above) to meet `target_feerate_sat_per_1000_weight`. + /// 4. The final transaction must have a weight smaller than `max_tx_weight`; if this + /// constraint can't be met, return an `Err`. In the case of counterparty-signed HTLC + /// transactions, we will remove a chunk of HTLCs and try your algorithm again. As for + /// anchor transactions, we will try your coin selection again with the same input-output + /// set when you call [`ChannelMonitor::rebroadcast_pending_claims`], as anchor transactions + /// cannot be downsized. + /// + /// Implementations must take note that [`Input::satisfaction_weight`] only tracks the weight of + /// the input's `script_sig` and `witness`. Some wallets, like Bitcoin Core's, may require + /// providing the full input weight. Failing to do so may lead to underestimating fee bumps and + /// delaying block inclusion. + /// + /// The `claim_id` must map to the set of external UTXOs assigned to the claim, such that they + /// can be re-used within new fee-bumped iterations of the original claiming transaction, + /// ensuring that claims don't double spend each other. If a specific `claim_id` has never had a + /// transaction associated with it, and all of the available UTXOs have already been assigned to + /// other claims, implementations must be willing to double spend their UTXOs. The choice of + /// which UTXOs to double spend is left to the implementation, but it must strive to keep the + /// set of other claims being double spent to a minimum. + /// + /// [`ChannelMonitor::rebroadcast_pending_claims`]: crate::chain::channelmonitor::ChannelMonitor::rebroadcast_pending_claims fn select_confirmed_utxos( &self, claim_id: ClaimId, must_spend: Vec, must_pay_to: &[TxOut], target_feerate_sat_per_1000_weight: u32, max_tx_weight: u64, ) -> Result; - /// A synchronous version of [`CoinSelectionSource::sign_psbt`]. + /// Signs and provides the full witness for all inputs within the transaction known to the + /// trait (i.e., any provided via [`CoinSelectionSourceSync::select_confirmed_utxos`]). + /// + /// If your wallet does not support signing PSBTs you can call `psbt.extract_tx()` to get the + /// unsigned transaction and then sign it with your wallet. fn sign_psbt(&self, psbt: Psbt) -> Result; } @@ -188,7 +250,14 @@ where } } -/// A synchronous wrapper around [`BumpTransactionEventHandler`] to be used in contexts where async is not available. +/// A handler for [`Event::BumpTransaction`] events that sources confirmed UTXOs from a +/// [`CoinSelectionSourceSync`] to fee bump transactions via Child-Pays-For-Parent (CPFP) or +/// Replace-By-Fee (RBF). +/// +/// For an asynchronous version of this handler, see [`BumpTransactionEventHandler`]. +/// +/// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction +// Note that updates to documentation on this struct should be copied to the synchronous version. pub struct BumpTransactionEventHandlerSync where B::Target: BroadcasterInterface, From b55eec774e42de817d7341f69dead2f652a1cd89 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 20:41:30 +0000 Subject: [PATCH 09/11] Provide the same docs in `ChangeDestinationSource` as the sync one --- lightning/src/sign/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 8a5aceb9a34..1d771d22783 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -1071,6 +1071,9 @@ pub trait ChangeDestinationSource { /// A synchronous helper trait that describes an on-chain wallet capable of returning a (change) destination script. pub trait ChangeDestinationSourceSync { + /// Returns a script pubkey which can be used as a change destination for + /// [`OutputSpender::spend_spendable_outputs`]. + /// /// This method should return a different value each time it is called, to avoid linking /// on-chain funds controlled to the same user. fn get_change_destination_script(&self) -> Result; From 9516400dbd266bcefc90c10529a831653d285526 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 20:55:31 +0000 Subject: [PATCH 10/11] Copy async docs from async KVStore to sync one When we added the async trait for `KVStore`, we didn't bother copying the documentation to the sync wrappers as we figured the links sufficed. Sadly, however, this means that our bindings logic will have no docs but a broken link to an async object that doesn't exist. Instead, here, we copy the docs from the async objects to the sync ones, at least leaving behind a comment noting that both need updating whenever one gets updated. --- lightning/src/util/persist.rs | 67 ++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/lightning/src/util/persist.rs b/lightning/src/util/persist.rs index 7be957a1f8a..d00e29e686a 100644 --- a/lightning/src/util/persist.rs +++ b/lightning/src/util/persist.rs @@ -118,21 +118,75 @@ pub const OUTPUT_SWEEPER_PERSISTENCE_KEY: &str = "output_sweeper"; /// updates applied to be current) with another implementation. pub const MONITOR_UPDATING_PERSISTER_PREPEND_SENTINEL: &[u8] = &[0xFF; 2]; -/// A synchronous version of the [`KVStore`] trait. +/// Provides an interface that allows storage and retrieval of persisted values that are associated +/// with given keys. +/// +/// In order to avoid collisions the key space is segmented based on the given `primary_namespace`s +/// and `secondary_namespace`s. Implementations of this trait are free to handle them in different +/// ways, as long as per-namespace key uniqueness is asserted. +/// +/// Keys and namespaces are required to be valid ASCII strings in the range of +/// [`KVSTORE_NAMESPACE_KEY_ALPHABET`] and no longer than [`KVSTORE_NAMESPACE_KEY_MAX_LEN`]. Empty +/// primary namespaces and secondary namespaces (`""`) are assumed to be a valid, however, if +/// `primary_namespace` is empty, `secondary_namespace` is required to be empty, too. This means +/// that concerns should always be separated by primary namespace first, before secondary +/// namespaces are used. While the number of primary namespaces will be relatively small and is +/// determined at compile time, there may be many secondary namespaces per primary namespace. Note +/// that per-namespace uniqueness needs to also hold for keys *and* namespaces in any given +/// namespace, i.e., conflicts between keys and equally named +/// primary namespaces/secondary namespaces must be avoided. +/// +/// **Note:** Users migrating custom persistence backends from the pre-v0.0.117 `KVStorePersister` +/// interface can use a concatenation of `[{primary_namespace}/[{secondary_namespace}/]]{key}` to +/// recover a `key` compatible with the data model previously assumed by `KVStorePersister::persist`. +/// +/// For an asynchronous version of this trait, see [`KVStore`]. +// Note that updates to documentation on this trait should be copied to the asynchronous version. pub trait KVStoreSync { - /// A synchronous version of the [`KVStore::read`] method. + /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and + /// `key`. + /// + /// Returns an [`ErrorKind::NotFound`] if the given `key` could not be found in the given + /// `primary_namespace` and `secondary_namespace`. + /// + /// [`ErrorKind::NotFound`]: io::ErrorKind::NotFound fn read( &self, primary_namespace: &str, secondary_namespace: &str, key: &str, ) -> Result, io::Error>; - /// A synchronous version of the [`KVStore::write`] method. + /// Persists the given data under the given `key`. + /// + /// Will create the given `primary_namespace` and `secondary_namespace` if not already present in the store. fn write( &self, primary_namespace: &str, secondary_namespace: &str, key: &str, buf: Vec, ) -> Result<(), io::Error>; - /// A synchronous version of the [`KVStore::remove`] method. + /// Removes any data that had previously been persisted under the given `key`. + /// + /// If the `lazy` flag is set to `true`, the backend implementation might choose to lazily + /// remove the given `key` at some point in time after the method returns, e.g., as part of an + /// eventual batch deletion of multiple keys. As a consequence, subsequent calls to + /// [`KVStoreSync::list`] might include the removed key until the changes are actually persisted. + /// + /// Note that while setting the `lazy` flag reduces the I/O burden of multiple subsequent + /// `remove` calls, it also influences the atomicity guarantees as lazy `remove`s could + /// potentially get lost on crash after the method returns. Therefore, this flag should only be + /// set for `remove` operations that can be safely replayed at a later time. + /// + /// All removal operations must complete in a consistent total order with [`Self::write`]s + /// to the same key. Whether a removal operation is `lazy` or not, [`Self::write`] operations + /// to the same key which occur before a removal completes must cancel/overwrite the pending + /// removal. + /// + /// Returns successfully if no data will be stored for the given `primary_namespace`, + /// `secondary_namespace`, and `key`, independently of whether it was present before its + /// invokation or not. fn remove( &self, primary_namespace: &str, secondary_namespace: &str, key: &str, lazy: bool, ) -> Result<(), io::Error>; - /// A synchronous version of the [`KVStore::list`] method. + /// Returns a list of keys that are stored under the given `secondary_namespace` in + /// `primary_namespace`. + /// + /// Returns the keys in arbitrary order, so users requiring a particular order need to sort the + /// returned keys. Returns an empty list if `primary_namespace` or `secondary_namespace` is unknown. fn list( &self, primary_namespace: &str, secondary_namespace: &str, ) -> Result, io::Error>; @@ -215,7 +269,10 @@ where /// interface can use a concatenation of `[{primary_namespace}/[{secondary_namespace}/]]{key}` to /// recover a `key` compatible with the data model previously assumed by `KVStorePersister::persist`. /// +/// For a synchronous version of this trait, see [`KVStoreSync`]. +/// /// This is not exported to bindings users as async is only supported in Rust. +// Note that updates to documentation on this trait should be copied to the synchronous version. pub trait KVStore { /// Returns the data stored for the given `primary_namespace`, `secondary_namespace`, and /// `key`. From 4bc993cc7fce2c1c0a0bc1566dcf6318efde47a1 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Mon, 3 Nov 2025 21:16:06 +0000 Subject: [PATCH 11/11] Copy docs from `OutputSweeper` to `OutputSweeperSync` When we added the async wrapper for `OutputSweeper`, we didn't bother copying the documentation to the sync wrappers as we figured the links sufficed. Sadly, however, this means that our bindings logic will have no docs but a broken link to an async object that doesn't exist. Instead, here, we copy the docs from the async objects to the sync ones, at least leaving behind a comment noting that both need updating whenever one gets updated. --- lightning/src/util/sweep.rs | 56 ++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/lightning/src/util/sweep.rs b/lightning/src/util/sweep.rs index a6b11ac67d0..5a1ffad3e04 100644 --- a/lightning/src/util/sweep.rs +++ b/lightning/src/util/sweep.rs @@ -317,10 +317,11 @@ impl_writeable_tlv_based_enum!(OutputSpendStatus, ); /// A utility that keeps track of [`SpendableOutputDescriptor`]s, persists them in a given -/// [`KVStoreSync`] and regularly retries sweeping them based on a callback given to the constructor +/// [`KVStore`] and regularly retries sweeping them based on a callback given to the constructor /// methods. /// -/// Users should call [`Self::track_spendable_outputs`] for any [`SpendableOutputDescriptor`]s received via [`Event::SpendableOutputs`]. +/// Users should call [`Self::track_spendable_outputs`] for any [`SpendableOutputDescriptor`]s +/// received via [`Event::SpendableOutputs`]. /// /// This needs to be notified of chain state changes either via its [`Listen`] or [`Confirm`] /// implementation and hence has to be connected with the utilized chain data sources. @@ -329,9 +330,12 @@ impl_writeable_tlv_based_enum!(OutputSpendStatus, /// required to give their chain data sources (i.e., [`Filter`] implementation) to the respective /// constructor. /// +/// For a synchronous version of this struct, see [`OutputSweeperSync`]. +/// /// This is not exported to bindings users as async is not supported outside of Rust. /// /// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs +// Note that updates to documentation on this struct should be copied to the synchronous version. pub struct OutputSweeper where B::Target: BroadcasterInterface, @@ -878,7 +882,24 @@ where } } -/// A synchronous wrapper around [`OutputSweeper`] to be used in contexts where async is not available. +/// A utility that keeps track of [`SpendableOutputDescriptor`]s, persists them in a given +/// [`KVStoreSync`] and regularly retries sweeping them based on a callback given to the constructor +/// methods. +/// +/// Users should call [`Self::track_spendable_outputs`] for any [`SpendableOutputDescriptor`]s +/// received via [`Event::SpendableOutputs`]. +/// +/// This needs to be notified of chain state changes either via its [`Listen`] or [`Confirm`] +/// implementation and hence has to be connected with the utilized chain data sources. +/// +/// If chain data is provided via the [`Confirm`] interface or via filtered blocks, users are +/// required to give their chain data sources (i.e., [`Filter`] implementation) to the respective +/// constructor. +/// +/// For an asynchronous version of this struct, see [`OutputSweeper`]. +/// +/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs +// Note that updates to documentation on this struct should be copied to the asynchronous version. pub struct OutputSweeperSync where B::Target: BroadcasterInterface, @@ -905,6 +926,9 @@ where O::Target: OutputSpender, { /// Constructs a new [`OutputSweeperSync`] instance. + /// + /// If chain data is provided via the [`Confirm`] interface or via filtered blocks, users also + /// need to register their [`Filter`] implementation via the given `chain_data_source`. pub fn new( best_block: BestBlock, broadcaster: B, fee_estimator: E, chain_data_source: Option, output_spender: O, change_destination_source: D, kv_store: K, logger: L, @@ -927,7 +951,21 @@ where Self { sweeper } } - /// Wrapper around [`OutputSweeper::track_spendable_outputs`]. + /// Tells the sweeper to track the given outputs descriptors. + /// + /// Usually, this should be called based on the values emitted by the + /// [`Event::SpendableOutputs`]. + /// + /// The given `exclude_static_outputs` flag controls whether the sweeper will filter out + /// [`SpendableOutputDescriptor::StaticOutput`]s, which may be handled directly by the on-chain + /// wallet implementation. + /// + /// If `delay_until_height` is set, we will delay the spending until the respective block + /// height is reached. This can be used to batch spends, e.g., to reduce on-chain fees. + /// + /// Returns `Err` on persistence failure, in which case the call may be safely retried. + /// + /// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs pub fn track_spendable_outputs( &self, output_descriptors: Vec, channel_id: Option, exclude_static_outputs: bool, delay_until_height: Option, @@ -949,7 +987,9 @@ where } } - /// Returns a list of the currently tracked spendable outputs. Wraps [`OutputSweeper::tracked_spendable_outputs`]. + /// Returns a list of the currently tracked spendable outputs. + /// + /// Wraps [`OutputSweeper::tracked_spendable_outputs`]. pub fn tracked_spendable_outputs(&self) -> Vec { self.sweeper.tracked_spendable_outputs() } @@ -960,8 +1000,10 @@ where self.sweeper.current_best_block() } - /// Regenerates and broadcasts the spending transaction for any outputs that are pending. Wraps - /// [`OutputSweeper::regenerate_and_broadcast_spend_if_necessary`]. + /// Regenerates and broadcasts the spending transaction for any outputs that are pending. This method will be a + /// no-op if a sweep is already pending. + /// + /// Wraps [`OutputSweeper::regenerate_and_broadcast_spend_if_necessary`]. pub fn regenerate_and_broadcast_spend_if_necessary(&self) -> Result<(), ()> { let mut fut = Box::pin(self.sweeper.regenerate_and_broadcast_spend_if_necessary()); let mut waker = dummy_waker();