Skip to content

Commit 8adea39

Browse files
committed
Introduce OffersMessageFlow
1 parent 287c932 commit 8adea39

File tree

1 file changed

+104
-4
lines changed

1 file changed

+104
-4
lines changed

lightning/src/offers/flow.rs

+104-4
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@
1313

1414
use core::ops::Deref;
1515
use core::time::Duration;
16+
use core::sync::atomic::{AtomicUsize, Ordering};
1617

17-
use bitcoin::secp256k1;
18+
use bitcoin::block::Header;
19+
use bitcoin::constants::ChainHash;
20+
use bitcoin::secp256k1::{self, PublicKey, Secp256k1};
21+
use bitcoin::network::Network;
1822

1923
use crate::blinded_path::message::{AsyncPaymentsContext, BlindedMessagePath, OffersContext};
2024
use crate::blinded_path::payment::{BlindedPaymentPath, PaymentContext};
2125
use crate::chain;
26+
use crate::chain::transaction::TransactionData;
2227
use crate::ln::channelmanager::PaymentId;
2328
use crate::offers::invoice::{Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder};
2429
use crate::offers::invoice_error::InvoiceError;
@@ -33,6 +38,9 @@ use crate::onion_message::messenger::{Destination, MessageSendInstructions};
3338
use crate::onion_message::offers::OffersMessage;
3439
use crate::sign::NodeSigner;
3540
use crate::types::payment::{PaymentHash, PaymentSecret};
41+
use crate::sign::EntropySource;
42+
use crate::sync::Mutex;
43+
use crate::ln::inbound_payment;
3644

3745
#[cfg(async_payments)]
3846
use {
@@ -55,7 +63,7 @@ pub trait Flow: chain::Listen {
5563
fn verify_async_context(&self, context: AsyncPaymentsContext) -> Result<Option<PaymentId>, ()>;
5664

5765
fn create_offer_builder<F>(
58-
&self, absolute_expiry: Option<Duration>, paths: F,
66+
&self, absolute_expiry: Option<Duration>, nonce: Option<Nonce>, paths: F,
5967
) -> Result<OfferBuilder<DerivedMetadata, secp256k1::All>, Bolt12SemanticError>
6068
where
6169
F: Fn(OffersContext) -> Result<Vec<BlindedMessagePath>, ()>;
@@ -87,7 +95,7 @@ pub trait Flow: chain::Listen {
8795
F: Fn(PaymentContext) -> Result<Vec<BlindedPaymentPath>, ()>;
8896

8997
fn create_invoice_from_invoice_request<NS: Deref, F>(
90-
self, signer: NS, invoice_request: VerifiedInvoiceRequest, payment_hash: PaymentHash, payment_paths: F,
98+
&self, signer: &NS, invoice_request: VerifiedInvoiceRequest, payment_hash: PaymentHash, payment_paths: F,
9199
) -> Result<Bolt12Invoice, InvoiceError>
92100
where
93101
NS::Target: NodeSigner,
@@ -124,7 +132,6 @@ pub trait Flow: chain::Listen {
124132
&self,
125133
) -> Vec<(OffersMessage, MessageSendInstructions)>;
126134

127-
#[cfg(async_payments)]
128135
fn get_and_clear_pending_async_messages(
129136
&self,
130137
) -> Vec<(AsyncPaymentsMessage, MessageSendInstructions)>;
@@ -133,4 +140,97 @@ pub trait Flow: chain::Listen {
133140
fn get_and_clear_pending_dns_messages(
134141
&self,
135142
) -> Vec<(DNSResolverMessage, MessageSendInstructions)>;
143+
}
144+
145+
146+
pub struct OffersMessageFlow<ES: Deref>
147+
where
148+
ES::Target: EntropySource,
149+
{
150+
chain_hash: ChainHash,
151+
152+
our_network_pubkey: PublicKey,
153+
highest_seen_timestamp: AtomicUsize,
154+
inbound_payment_key: inbound_payment::ExpandedKey,
155+
156+
secp_ctx: Secp256k1<secp256k1::All>,
157+
entropy_source: ES,
158+
159+
#[cfg(not(any(test, feature = "_test_utils")))]
160+
pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
161+
#[cfg(any(test, feature = "_test_utils"))]
162+
pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
163+
164+
pending_async_payments_messages: Mutex<Vec<(AsyncPaymentsMessage, MessageSendInstructions)>>,
165+
166+
#[cfg(feature = "dnssec")]
167+
pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
168+
}
169+
170+
impl<ES: Deref> OffersMessageFlow<ES>
171+
where
172+
ES::Target: EntropySource,
173+
{
174+
/// Creates a new [`OffersMessageFlow`]
175+
pub fn new(
176+
network: Network, our_network_pubkey: PublicKey,
177+
current_timestamp: u32, inbound_payment_key: inbound_payment::ExpandedKey,
178+
entropy_source: ES,
179+
) -> Self {
180+
let mut secp_ctx = Secp256k1::new();
181+
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
182+
183+
Self {
184+
chain_hash: ChainHash::using_genesis_block(network),
185+
186+
our_network_pubkey,
187+
highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
188+
inbound_payment_key,
189+
190+
secp_ctx,
191+
entropy_source,
192+
193+
pending_offers_messages: Mutex::new(Vec::new()),
194+
pending_async_payments_messages: Mutex::new(Vec::new()),
195+
#[cfg(feature = "dnssec")]
196+
pending_dns_onion_messages: Mutex::new(Vec::new()),
197+
}
198+
}
199+
200+
/// Gets the node_id held by this OffersMessageFlow
201+
pub fn get_our_node_id(&self) -> PublicKey {
202+
self.our_network_pubkey
203+
}
204+
205+
fn best_block_updated(&self, header: &Header) {
206+
macro_rules! max_time {
207+
($timestamp: expr) => {
208+
loop {
209+
// Update $timestamp to be the max of its current value and the block
210+
// timestamp. This should keep us close to the current time without relying on
211+
// having an explicit local time source.
212+
// Just in case we end up in a race, we loop until we either successfully
213+
// update $timestamp or decide we don't need to.
214+
let old_serial = $timestamp.load(Ordering::Acquire);
215+
if old_serial >= header.time as usize { break; }
216+
if $timestamp.compare_exchange(old_serial, header.time as usize, Ordering::AcqRel, Ordering::Relaxed).is_ok() {
217+
break;
218+
}
219+
}
220+
}
221+
}
222+
223+
max_time!(self.highest_seen_timestamp);
224+
}
225+
}
226+
227+
impl<ES: Deref> chain::Listen for OffersMessageFlow<ES>
228+
where
229+
ES::Target: EntropySource,
230+
{
231+
fn filtered_block_connected(&self, header: &Header, _txdata: &TransactionData, _height: u32) {
232+
self.best_block_updated(header);
233+
}
234+
235+
fn block_disconnected(&self, _header: &Header, _height: u32) {}
136236
}

0 commit comments

Comments
 (0)