Skip to content

Commit e761270

Browse files
committed
Introduce OffersMessageFlow
1 parent b3d3560 commit e761270

File tree

2 files changed

+153
-0
lines changed

2 files changed

+153
-0
lines changed

lightning/src/offers/flow.rs

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

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)