Skip to content

Commit 9bafa56

Browse files
committed
Introduce OffersMessageFlow
1 parent b3d3560 commit 9bafa56

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

lightning/src/offers/flow.rs

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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::routing::router::Router;
30+
use crate::sign::EntropySource;
31+
use crate::sync::{Mutex, RwLock};
32+
33+
#[cfg(feature = "dnssec")]
34+
use crate::onion_message::dns_resolution::DNSResolverMessage;
35+
36+
/// A Bolt12 Offers code and flow utility provider, which facilitates utilities for
37+
/// Bolt12 builder generation, and Onion message handling.
38+
///
39+
/// [`OffersMessageFlow`] is parameterized by a number of components to achieve this.
40+
///
41+
/// - [`EntropySource`] for providing random data needed for cryptographic operations
42+
/// - [`MessageRouter`] for finding message paths when initiating and retrying onion messages
43+
/// - [`Router`] for finding payment paths when initiating Botl12 payments.
44+
pub struct OffersMessageFlow<ES: Deref, MR: Deref, R: Deref>
45+
where
46+
ES::Target: EntropySource,
47+
MR::Target: MessageRouter,
48+
R::Target: Router,
49+
{
50+
chain_hash: ChainHash,
51+
best_block: RwLock<BestBlock>,
52+
53+
our_network_pubkey: PublicKey,
54+
highest_seen_timestamp: AtomicUsize,
55+
inbound_payment_key: inbound_payment::ExpandedKey,
56+
57+
secp_ctx: Secp256k1<secp256k1::All>,
58+
entropy_source: ES,
59+
60+
message_router: MR,
61+
router: R,
62+
63+
#[cfg(not(any(test, feature = "_test_utils")))]
64+
pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
65+
#[cfg(any(test, feature = "_test_utils"))]
66+
pub(crate) pending_offers_messages: Mutex<Vec<(OffersMessage, MessageSendInstructions)>>,
67+
68+
pending_async_payments_messages: Mutex<Vec<(AsyncPaymentsMessage, MessageSendInstructions)>>,
69+
70+
#[cfg(feature = "dnssec")]
71+
pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
72+
}
73+
74+
impl<ES: Deref, MR: Deref, R: Deref> OffersMessageFlow<ES, MR, R>
75+
where
76+
ES::Target: EntropySource,
77+
MR::Target: MessageRouter,
78+
R::Target: Router,
79+
{
80+
/// Creates a new [`OffersMessageFlow`]
81+
pub fn new(
82+
chain_hash: ChainHash, best_block: BestBlock, our_network_pubkey: PublicKey,
83+
current_timestamp: u32, inbound_payment_key: inbound_payment::ExpandedKey,
84+
entropy_source: ES, message_router: MR, router: R,
85+
) -> Self {
86+
let mut secp_ctx = Secp256k1::new();
87+
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
88+
89+
Self {
90+
chain_hash,
91+
best_block: RwLock::new(best_block),
92+
93+
our_network_pubkey,
94+
highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
95+
inbound_payment_key,
96+
97+
secp_ctx,
98+
entropy_source,
99+
100+
message_router,
101+
router,
102+
103+
pending_offers_messages: Mutex::new(Vec::new()),
104+
pending_async_payments_messages: Mutex::new(Vec::new()),
105+
#[cfg(feature = "dnssec")]
106+
pending_dns_onion_messages: Mutex::new(Vec::new()),
107+
}
108+
}
109+
110+
/// Gets the node_id held by this [`OffersMessageFlow`]`
111+
pub fn get_our_node_id(&self) -> PublicKey {
112+
self.our_network_pubkey
113+
}
114+
115+
fn duration_since_epoch(&self) -> Duration {
116+
#[cfg(not(feature = "std"))]
117+
let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
118+
#[cfg(feature = "std")]
119+
let now = std::time::SystemTime::now()
120+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
121+
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
122+
now
123+
}
124+
125+
fn best_block_updated(&self, header: &Header) {
126+
macro_rules! max_time {
127+
($timestamp: expr) => {
128+
loop {
129+
// Update $timestamp to be the max of its current value and the block
130+
// timestamp. This should keep us close to the current time without relying on
131+
// having an explicit local time source.
132+
// Just in case we end up in a race, we loop until we either successfully
133+
// update $timestamp or decide we don't need to.
134+
let old_serial = $timestamp.load(Ordering::Acquire);
135+
if old_serial >= header.time as usize {
136+
break;
137+
}
138+
if $timestamp
139+
.compare_exchange(
140+
old_serial,
141+
header.time as usize,
142+
Ordering::AcqRel,
143+
Ordering::Relaxed,
144+
)
145+
.is_ok()
146+
{
147+
break;
148+
}
149+
}
150+
};
151+
}
152+
153+
max_time!(self.highest_seen_timestamp);
154+
}
155+
}

lightning/src/offers/mod.rs

+1
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)