Skip to content

Commit 84cbadc

Browse files
committed
Introduce OffersMessageFlow
`OffersMessageFlow` is a mid-level abstraction for handling BOLT12 messages and flow control. It provides utilities to help implement Offer Message Handlers in a cleaner, more modular way. The core motivation is to decouple Onion Messaging logic from `ChannelManager`, reducing its responsibilities and code overhead. This separation improves clarity, maintainability, and lays the groundwork for giving users greater flexibility in customizing their BOLT12 message flows.
1 parent 7624f08 commit 84cbadc

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

lightning/src/offers/flow.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// This file is Copyright its original authors, visible in version control
2+
// history.
3+
//
4+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5+
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7+
// You may not use this file except in accordance with one or both of these
8+
// licenses.
9+
10+
//! Provides data structures and functions for creating and managing Offers messages,
11+
//! facilitating communication, and handling Bolt12 messages and payments.
12+
13+
use core::ops::Deref;
14+
use core::sync::atomic::{AtomicUsize, Ordering};
15+
use core::time::Duration;
16+
17+
use bitcoin::block::Header;
18+
use bitcoin::constants::ChainHash;
19+
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
20+
21+
#[allow(unused_imports)]
22+
use crate::prelude::*;
23+
24+
use crate::chain::BestBlock;
25+
use crate::ln::inbound_payment;
26+
use crate::onion_message::async_payments::AsyncPaymentsMessage;
27+
use crate::onion_message::messenger::{MessageRouter, MessageSendInstructions};
28+
use crate::onion_message::offers::OffersMessage;
29+
use crate::sync::{Mutex, RwLock};
30+
31+
#[cfg(feature = "dnssec")]
32+
use crate::onion_message::dns_resolution::{DNSResolverMessage, OMNameResolver};
33+
34+
/// A Bolt12 Offers code and flow utility provider, which facilitates utilities for
35+
/// Bolt12 builder generation, and Onion message handling.
36+
///
37+
/// [`OffersMessageFlow`] is parameterized by a [`MessageRouter`], which is responsible
38+
/// for finding message paths when initiating and retrying onion messages.
39+
pub struct OffersMessageFlow<MR: Deref>
40+
where
41+
MR::Target: MessageRouter,
42+
{
43+
chain_hash: ChainHash,
44+
best_block: RwLock<BestBlock>,
45+
46+
our_network_pubkey: PublicKey,
47+
highest_seen_timestamp: AtomicUsize,
48+
inbound_payment_key: inbound_payment::ExpandedKey,
49+
50+
secp_ctx: Secp256k1<secp256k1::All>,
51+
message_router: MR,
52+
53+
#[cfg(not(any(test, feature = "_test_utils")))]
54+
pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
55+
#[cfg(any(test, feature = "_test_utils"))]
56+
pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
57+
58+
pending_async_payments_messages: Mutex<Vec<(AsyncPaymentsMessage, MessageSendInstructions)>>,
59+
60+
#[cfg(feature = "dnssec")]
61+
pub(crate) hrn_resolver: OMNameResolver,
62+
#[cfg(feature = "dnssec")]
63+
pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
64+
}
65+
66+
impl<MR: Deref> OffersMessageFlow<MR>
67+
where
68+
MR::Target: MessageRouter,
69+
{
70+
/// Creates a new [`OffersMessageFlow`]
71+
pub fn new(
72+
chain_hash: ChainHash, best_block: BestBlock, our_network_pubkey: PublicKey,
73+
current_timestamp: u32, inbound_payment_key: inbound_payment::ExpandedKey,
74+
secp_ctx: Secp256k1<secp256k1::All>, message_router: MR,
75+
) -> Self {
76+
Self {
77+
chain_hash,
78+
best_block: RwLock::new(best_block),
79+
80+
our_network_pubkey,
81+
highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
82+
inbound_payment_key,
83+
84+
secp_ctx,
85+
message_router,
86+
87+
pending_offers_messages: Mutex::new(Vec::new()),
88+
pending_async_payments_messages: Mutex::new(Vec::new()),
89+
90+
#[cfg(feature = "dnssec")]
91+
hrn_resolver: OMNameResolver::new(current_timestamp, best_block.height),
92+
#[cfg(feature = "dnssec")]
93+
pending_dns_onion_messages: Mutex::new(Vec::new()),
94+
}
95+
}
96+
97+
/// Gets the node_id held by this [`OffersMessageFlow`]`
98+
pub fn get_our_node_id(&self) -> PublicKey {
99+
self.our_network_pubkey
100+
}
101+
102+
fn duration_since_epoch(&self) -> Duration {
103+
#[cfg(not(feature = "std"))]
104+
let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
105+
#[cfg(feature = "std")]
106+
let now = std::time::SystemTime::now()
107+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
108+
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
109+
now
110+
}
111+
112+
/// Notifies the [`OffersMessageFlow`] that a new block has been observed.
113+
///
114+
/// This allows the flow to keep in sync with the latest block timestamp,
115+
/// which may be used for time-sensitive operations.
116+
pub fn best_block_updated(&self, header: &Header) {
117+
let timestamp = &self.highest_seen_timestamp;
118+
loop {
119+
// Update timestamp to be the max of its current value and the block
120+
// timestamp. This should keep us close to the current time without relying on
121+
// having an explicit local time source.
122+
// Just in case we end up in a race, we loop until we either successfully
123+
// update timestamp or decide we don't need to.
124+
let old_serial = timestamp.load(Ordering::Acquire);
125+
if old_serial >= header.time as usize {
126+
break;
127+
}
128+
if timestamp
129+
.compare_exchange(
130+
old_serial,
131+
header.time as usize,
132+
Ordering::AcqRel,
133+
Ordering::Relaxed,
134+
)
135+
.is_ok()
136+
{
137+
break;
138+
}
139+
}
140+
}
141+
}

lightning/src/offers/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
1515
#[macro_use]
1616
pub mod offer;
17+
pub mod flow;
1718

1819
pub mod invoice;
1920
pub mod invoice_error;

0 commit comments

Comments
 (0)