Skip to content

Commit 312b662

Browse files
feat: add BOLT12 payer proof support
Add payer-proof creation for outbound BOLT12 payments, persist the invoice context needed to build the proof, and expose the new types through the public and UniFFI surfaces. AI-assisted-by: Codex
1 parent e94f80f commit 312b662

14 files changed

Lines changed: 576 additions & 59 deletions

File tree

Cargo.toml

Lines changed: 24 additions & 24 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 = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] }
43-
lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" }
44-
lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] }
45-
lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" }
46-
lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["tokio"] }
47-
lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" }
48-
lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" }
49-
lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["rest-client", "rpc-client", "tokio"] }
50-
lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
51-
lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] }
52-
lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" }
42+
lightning = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["std"] }
43+
lightning-types = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
44+
lightning-invoice = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["std"] }
45+
lightning-net-tokio = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
46+
lightning-persister = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["tokio"] }
47+
lightning-background-processor = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
48+
lightning-rapid-gossip-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
49+
lightning-block-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["rest-client", "rpc-client", "tokio"] }
50+
lightning-transaction-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["esplora-async-https", "time", "electrum-rustls-ring"] }
51+
lightning-liquidity = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", features = ["std"] }
52+
lightning-macros = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
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"]}
@@ -85,7 +85,7 @@ bitcoin-payment-instructions = { git = "https://github.com/jkczyz/bitcoin-paymen
8585
winapi = { version = "0.3", features = ["winbase"] }
8686

8787
[dev-dependencies]
88-
lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std", "_test_utils"] }
88+
lightning = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3", 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"
@@ -171,15 +171,15 @@ harness = false
171171
#vss-client-ng = { path = "../vss-client" }
172172
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
173173
#
174-
#[patch."https://github.com/lightningdevkit/rust-lightning"]
175-
#lightning = { path = "../rust-lightning/lightning" }
176-
#lightning-types = { path = "../rust-lightning/lightning-types" }
177-
#lightning-invoice = { path = "../rust-lightning/lightning-invoice" }
178-
#lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
179-
#lightning-persister = { path = "../rust-lightning/lightning-persister" }
180-
#lightning-background-processor = { path = "../rust-lightning/lightning-background-processor" }
181-
#lightning-rapid-gossip-sync = { path = "../rust-lightning/lightning-rapid-gossip-sync" }
182-
#lightning-block-sync = { path = "../rust-lightning/lightning-block-sync" }
183-
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
184-
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
185-
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
174+
[patch."https://github.com/lightningdevkit/rust-lightning"]
175+
lightning = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
176+
lightning-types = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
177+
lightning-invoice = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
178+
lightning-net-tokio = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
179+
lightning-persister = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
180+
lightning-background-processor = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
181+
lightning-rapid-gossip-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
182+
lightning-block-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
183+
lightning-transaction-sync = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
184+
lightning-liquidity = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }
185+
lightning-macros = { git = "https://github.com/vincenzopalazzo/rust-lightning", rev = "96f1d193b75cf9534def6cc2b3e65f1aaea5d4e3" }

bindings/ldk_node.udl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ enum NodeError {
179179
"FeerateEstimationUpdateTimeout",
180180
"WalletOperationFailed",
181181
"WalletOperationTimeout",
182+
"PayerProofCreationFailed",
183+
"PayerProofUnavailable",
182184
"OnchainTxSigningFailed",
183185
"TxSyncFailed",
184186
"TxSyncTimeout",
@@ -219,6 +221,7 @@ enum NodeError {
219221
"LnurlAuthFailed",
220222
"LnurlAuthTimeout",
221223
"InvalidLnurl",
224+
"InvalidPayerProof",
222225
};
223226

224227
typedef dictionary NodeStatus;

src/builder.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,14 @@ use crate::gossip::GossipSource;
5656
use crate::io::sqlite_store::SqliteStore;
5757
use crate::io::utils::{
5858
read_event_queue, read_external_pathfinding_scores_from_cache, read_network_graph,
59-
read_node_metrics, read_output_sweeper, read_payments, read_peer_info, read_pending_payments,
60-
read_scorer, write_node_metrics,
59+
read_node_metrics, read_output_sweeper, read_payer_proof_contexts, read_payments,
60+
read_peer_info, read_pending_payments, read_scorer, write_node_metrics,
6161
};
6262
use crate::io::vss_store::VssStoreBuilder;
6363
use crate::io::{
64-
self, PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
64+
self, PAYER_PROOF_CONTEXT_PERSISTENCE_PRIMARY_NAMESPACE,
65+
PAYER_PROOF_CONTEXT_PERSISTENCE_SECONDARY_NAMESPACE,
66+
PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
6567
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
6668
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
6769
};
@@ -77,8 +79,8 @@ use crate::runtime::{Runtime, RuntimeSpawner};
7779
use crate::tx_broadcaster::TransactionBroadcaster;
7880
use crate::types::{
7981
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreWrapper, GossipSync, Graph,
80-
KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, PendingPaymentStore,
81-
Persister, SyncAndAsyncKVStore,
82+
KeysManager, MessageRouter, OnionMessenger, PayerProofContextStore, PaymentStore, PeerManager,
83+
PendingPaymentStore, Persister, SyncAndAsyncKVStore,
8284
};
8385
use crate::wallet::persist::KVStoreWalletPersister;
8486
use crate::wallet::Wallet;
@@ -1081,14 +1083,19 @@ fn build_with_store_internal(
10811083

10821084
let kv_store_ref = Arc::clone(&kv_store);
10831085
let logger_ref = Arc::clone(&logger);
1084-
let (payment_store_res, node_metris_res, pending_payment_store_res) =
1085-
runtime.block_on(async move {
1086-
tokio::join!(
1087-
read_payments(&*kv_store_ref, Arc::clone(&logger_ref)),
1088-
read_node_metrics(&*kv_store_ref, Arc::clone(&logger_ref)),
1089-
read_pending_payments(&*kv_store_ref, Arc::clone(&logger_ref))
1090-
)
1091-
});
1086+
let (
1087+
payment_store_res,
1088+
node_metris_res,
1089+
pending_payment_store_res,
1090+
payer_proof_context_store_res,
1091+
) = runtime.block_on(async move {
1092+
tokio::join!(
1093+
read_payments(&*kv_store_ref, Arc::clone(&logger_ref)),
1094+
read_node_metrics(&*kv_store_ref, Arc::clone(&logger_ref)),
1095+
read_pending_payments(&*kv_store_ref, Arc::clone(&logger_ref)),
1096+
read_payer_proof_contexts(&*kv_store_ref, Arc::clone(&logger_ref))
1097+
)
1098+
});
10921099

10931100
// Initialize the status fields.
10941101
let node_metrics = match node_metris_res {
@@ -1117,6 +1124,20 @@ fn build_with_store_internal(
11171124
},
11181125
};
11191126

1127+
let payer_proof_context_store = match payer_proof_context_store_res {
1128+
Ok(contexts) => Arc::new(PayerProofContextStore::new(
1129+
contexts,
1130+
PAYER_PROOF_CONTEXT_PERSISTENCE_PRIMARY_NAMESPACE.to_string(),
1131+
PAYER_PROOF_CONTEXT_PERSISTENCE_SECONDARY_NAMESPACE.to_string(),
1132+
Arc::clone(&kv_store),
1133+
Arc::clone(&logger),
1134+
)),
1135+
Err(e) => {
1136+
log_error!(logger, "Failed to read payer proof contexts from store: {}", e);
1137+
return Err(BuildError::ReadFailed);
1138+
},
1139+
};
1140+
11201141
let (chain_source, chain_tip_opt) = match chain_data_source_config {
11211142
Some(ChainDataSourceConfig::Esplora { server_url, headers, sync_config }) => {
11221143
let sync_config = sync_config.unwrap_or(EsploraSyncConfig::default());
@@ -1810,6 +1831,7 @@ fn build_with_store_internal(
18101831
scorer,
18111832
peer_store,
18121833
payment_store,
1834+
payer_proof_context_store,
18131835
lnurl_auth,
18141836
is_running,
18151837
node_metrics,

src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ pub(crate) fn default_user_config(config: &Config) -> UserConfig {
338338
user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx =
339339
config.anchor_channels_config.is_some();
340340
user_config.reject_inbound_splices = false;
341+
user_config.manually_handle_bolt12_invoices = true;
341342

342343
if may_announce_channel(config).is_err() {
343344
user_config.accept_forwards_to_priv_channels = false;

src/error.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ pub enum Error {
5757
WalletOperationFailed,
5858
/// A wallet operation timed out.
5959
WalletOperationTimeout,
60+
/// Creating a payer proof failed.
61+
PayerProofCreationFailed,
62+
/// A payer proof is unavailable for the requested payment.
63+
PayerProofUnavailable,
6064
/// A signing operation for transaction failed.
6165
OnchainTxSigningFailed,
6266
/// A transaction sync operation failed.
@@ -137,6 +141,8 @@ pub enum Error {
137141
LnurlAuthTimeout,
138142
/// The provided lnurl is invalid.
139143
InvalidLnurl,
144+
/// The provided payer proof is invalid.
145+
InvalidPayerProof,
140146
}
141147

142148
impl fmt::Display for Error {
@@ -168,6 +174,10 @@ impl fmt::Display for Error {
168174
},
169175
Self::WalletOperationFailed => write!(f, "Failed to conduct wallet operation."),
170176
Self::WalletOperationTimeout => write!(f, "A wallet operation timed out."),
177+
Self::PayerProofCreationFailed => write!(f, "Failed to create payer proof."),
178+
Self::PayerProofUnavailable => {
179+
write!(f, "A payer proof is unavailable for the requested payment.")
180+
},
171181
Self::OnchainTxSigningFailed => write!(f, "Failed to sign given transaction."),
172182
Self::TxSyncFailed => write!(f, "Failed to sync transactions."),
173183
Self::TxSyncTimeout => write!(f, "Syncing transactions timed out."),
@@ -222,6 +232,7 @@ impl fmt::Display for Error {
222232
Self::LnurlAuthFailed => write!(f, "LNURL-auth authentication failed."),
223233
Self::LnurlAuthTimeout => write!(f, "LNURL-auth authentication timed out."),
224234
Self::InvalidLnurl => write!(f, "The provided lnurl is invalid."),
235+
Self::InvalidPayerProof => write!(f, "The provided payer proof is invalid."),
225236
}
226237
}
227238
}

0 commit comments

Comments
 (0)