|
14 | 14 | use core::ops::Deref;
|
15 | 15 | use core::time::Duration;
|
16 | 16 | use core::sync::atomic::{AtomicUsize, Ordering};
|
| 17 | +use crate::sync::RwLock; |
17 | 18 |
|
18 | 19 | use bitcoin::block::Header;
|
19 | 20 | use bitcoin::constants::ChainHash;
|
20 | 21 | use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
|
21 |
| -use bitcoin::network::Network; |
22 | 22 |
|
23 |
| -use crate::blinded_path::message::{AsyncPaymentsContext, BlindedMessagePath, MessageContext, OffersContext}; |
24 |
| -use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentContext}; |
25 |
| -use crate::chain; |
| 23 | +use crate::blinded_path::message::{AsyncPaymentsContext, BlindedMessagePath, MessageContext, MessageForwardNode, OffersContext}; |
| 24 | +use crate::blinded_path::payment::{BlindedPaymentPath, Bolt12OfferContext, Bolt12RefundContext, PaymentConstraints, PaymentContext, UnauthenticatedReceiveTlvs}; |
| 25 | +use crate::chain::{self, BestBlock}; |
| 26 | +use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS; |
26 | 27 | use crate::chain::transaction::TransactionData;
|
27 |
| -use crate::ln::channelmanager::{PaymentId, Verification, OFFERS_MESSAGE_REQUEST_LIMIT}; |
| 28 | +use crate::ln::channel_state::ChannelDetails; |
| 29 | +use crate::ln::channelmanager::{ChainParameters, PaymentId, Verification, CLTV_FAR_FAR_AWAY, MAX_SHORT_LIVED_RELATIVE_EXPIRY, OFFERS_MESSAGE_REQUEST_LIMIT}; |
28 | 30 | use crate::offers::invoice::{Bolt12Invoice, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
|
29 | 31 | use crate::offers::invoice_error::InvoiceError;
|
30 | 32 | use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestBuilder, VerifiedInvoiceRequest};
|
@@ -153,6 +155,7 @@ where
|
153 | 155 | R::Target: Router,
|
154 | 156 | {
|
155 | 157 | chain_hash: ChainHash,
|
| 158 | + best_block: RwLock<BestBlock>, |
156 | 159 |
|
157 | 160 | our_network_pubkey: PublicKey,
|
158 | 161 | highest_seen_timestamp: AtomicUsize,
|
@@ -183,15 +186,16 @@ where
|
183 | 186 | {
|
184 | 187 | /// Creates a new [`OffersMessageFlow`]
|
185 | 188 | pub fn new(
|
186 |
| - network: Network, our_network_pubkey: PublicKey, |
| 189 | + params: ChainParameters, our_network_pubkey: PublicKey, |
187 | 190 | current_timestamp: u32, inbound_payment_key: inbound_payment::ExpandedKey,
|
188 | 191 | entropy_source: ES, message_router: MR, router: R,
|
189 | 192 | ) -> Self {
|
190 | 193 | let mut secp_ctx = Secp256k1::new();
|
191 | 194 | secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
|
192 | 195 |
|
193 | 196 | Self {
|
194 |
| - chain_hash: ChainHash::using_genesis_block(network), |
| 197 | + chain_hash: ChainHash::using_genesis_block(params.network), |
| 198 | + best_block: RwLock::new(params.best_block), |
195 | 199 |
|
196 | 200 | our_network_pubkey,
|
197 | 201 | highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
|
@@ -248,6 +252,101 @@ where
|
248 | 252 | }
|
249 | 253 | }
|
250 | 254 |
|
| 255 | +impl<ES: Deref, MR: Deref, R: Deref> OffersMessageFlow<ES, MR, R> |
| 256 | +where |
| 257 | + ES::Target: EntropySource, |
| 258 | + MR::Target: MessageRouter, |
| 259 | + R::Target: Router, |
| 260 | +{ |
| 261 | + /// Creates a collection of blinded paths by delegating to [`MessageRouter`] based on |
| 262 | + /// the path's intended lifetime. |
| 263 | + /// |
| 264 | + /// Whether or not the path is compact depends on whether the path is short-lived or long-lived, |
| 265 | + /// respectively, based on the given `absolute_expiry` as seconds since the Unix epoch. See |
| 266 | + /// [`MAX_SHORT_LIVED_RELATIVE_EXPIRY`]. |
| 267 | + fn create_blinded_paths_using_absolute_expiry( |
| 268 | + &self, context: OffersContext, absolute_expiry: Option<Duration>, peers: Vec<MessageForwardNode> |
| 269 | + ) -> Result<Vec<BlindedMessagePath>, ()> { |
| 270 | + let now = self.duration_since_epoch(); |
| 271 | + let max_short_lived_absolute_expiry = now.saturating_add(MAX_SHORT_LIVED_RELATIVE_EXPIRY); |
| 272 | + |
| 273 | + if absolute_expiry.unwrap_or(Duration::MAX) <= max_short_lived_absolute_expiry { |
| 274 | + self.create_compact_blinded_paths(peers, context) |
| 275 | + } else { |
| 276 | + self.create_blinded_paths(peers, MessageContext::Offers(context)) |
| 277 | + } |
| 278 | + } |
| 279 | + |
| 280 | + /// Creates a collection of blinded paths by delegating to |
| 281 | + /// [`MessageRouter::create_blinded_paths`]. |
| 282 | + /// |
| 283 | + /// Errors if the `MessageRouter` errors. |
| 284 | + fn create_blinded_paths(&self, peers: Vec<MessageForwardNode>, context: MessageContext) -> Result<Vec<BlindedMessagePath>, ()> { |
| 285 | + let recipient = self.get_our_node_id(); |
| 286 | + let secp_ctx = &self.secp_ctx; |
| 287 | + |
| 288 | + let peers = peers |
| 289 | + .into_iter() |
| 290 | + .map(|node| node.node_id) |
| 291 | + .collect(); |
| 292 | + |
| 293 | + self.message_router |
| 294 | + .create_blinded_paths(recipient, context, peers, secp_ctx) |
| 295 | + .and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(())) |
| 296 | + } |
| 297 | + |
| 298 | + /// Creates a collection of blinded paths by delegating to |
| 299 | + /// [`MessageRouter::create_compact_blinded_paths`]. |
| 300 | + /// |
| 301 | + /// Errors if the `MessageRouter` errors. |
| 302 | + fn create_compact_blinded_paths(&self, peers: Vec<MessageForwardNode>, context: OffersContext) -> Result<Vec<BlindedMessagePath>, ()> { |
| 303 | + let recipient = self.get_our_node_id(); |
| 304 | + let secp_ctx = &self.secp_ctx; |
| 305 | + |
| 306 | + let peers = peers; |
| 307 | + |
| 308 | + self.message_router |
| 309 | + .create_compact_blinded_paths(recipient, MessageContext::Offers(context), peers, secp_ctx) |
| 310 | + .and_then(|paths| (!paths.is_empty()).then(|| paths).ok_or(())) |
| 311 | + } |
| 312 | + |
| 313 | + /// Creates multi-hop blinded payment paths for the given `amount_msats` by delegating to |
| 314 | + /// [`Router::create_blinded_payment_paths`]. |
| 315 | + fn create_blinded_payment_paths( |
| 316 | + &self, usable_channels: Vec<ChannelDetails>, amount_msats: Option<u64>, payment_secret: PaymentSecret, |
| 317 | + payment_context: PaymentContext, relative_expiry_seconds: u32 |
| 318 | + ) -> Result<Vec<BlindedPaymentPath>, ()> { |
| 319 | + let expanded_key = &self.inbound_payment_key; |
| 320 | + let entropy = &*self.entropy_source; |
| 321 | + let secp_ctx = &self.secp_ctx; |
| 322 | + |
| 323 | + let first_hops = usable_channels; |
| 324 | + let payee_node_id = self.get_our_node_id(); |
| 325 | + |
| 326 | + // Assume shorter than usual block times to avoid spuriously failing payments too early. |
| 327 | + const SECONDS_PER_BLOCK: u32 = 9 * 60; |
| 328 | + let relative_expiry_blocks = relative_expiry_seconds / SECONDS_PER_BLOCK; |
| 329 | + let max_cltv_expiry = core::cmp::max(relative_expiry_blocks, CLTV_FAR_FAR_AWAY) |
| 330 | + .saturating_add(LATENCY_GRACE_PERIOD_BLOCKS) |
| 331 | + .saturating_add(self.best_block.read().unwrap().height); |
| 332 | + |
| 333 | + let payee_tlvs = UnauthenticatedReceiveTlvs { |
| 334 | + payment_secret, |
| 335 | + payment_constraints: PaymentConstraints { |
| 336 | + max_cltv_expiry, |
| 337 | + htlc_minimum_msat: 1, |
| 338 | + }, |
| 339 | + payment_context, |
| 340 | + }; |
| 341 | + let nonce = Nonce::from_entropy_source(entropy); |
| 342 | + let payee_tlvs = payee_tlvs.authenticate(nonce, expanded_key); |
| 343 | + |
| 344 | + self.router.create_blinded_payment_paths( |
| 345 | + payee_node_id, first_hops, payee_tlvs, amount_msats, secp_ctx |
| 346 | + ) |
| 347 | + } |
| 348 | +} |
| 349 | + |
251 | 350 | impl<ES: Deref, MR: Deref, R: Deref> chain::Listen for OffersMessageFlow<ES, MR, R>
|
252 | 351 | where
|
253 | 352 | ES::Target: EntropySource,
|
|
0 commit comments