Skip to content

Commit bf48767

Browse files
committed
Introduce OffersMessageFlow
1 parent c1faa6c commit bf48767

File tree

2 files changed

+159
-0
lines changed

2 files changed

+159
-0
lines changed

lightning/src/offers/flow.rs

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
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::transaction::TransactionData;
22+
use crate::chain::{self, BestBlock};
23+
use crate::ln::inbound_payment;
24+
use crate::onion_message::async_payments::AsyncPaymentsMessage;
25+
use crate::onion_message::messenger::{MessageRouter, MessageSendInstructions};
26+
use crate::onion_message::offers::OffersMessage;
27+
use crate::routing::router::Router;
28+
use crate::sign::EntropySource;
29+
use crate::sync::{Mutex, RwLock};
30+
31+
#[cfg(feature = "dnssec")]
32+
use crate::onion_message::dns_resolution::DNSResolverMessage;
33+
34+
pub struct OffersMessageFlow<ES: Deref, MR: Deref, R: Deref>
35+
where
36+
ES::Target: EntropySource,
37+
MR::Target: MessageRouter,
38+
R::Target: Router,
39+
{
40+
chain_hash: ChainHash,
41+
best_block: RwLock<BestBlock>,
42+
43+
our_network_pubkey: PublicKey,
44+
highest_seen_timestamp: AtomicUsize,
45+
inbound_payment_key: inbound_payment::ExpandedKey,
46+
47+
secp_ctx: Secp256k1<secp256k1::All>,
48+
entropy_source: ES,
49+
50+
message_router: MR,
51+
router: R,
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+
pending_dns_onion_messages: Mutex<Vec<(DNSResolverMessage, MessageSendInstructions)>>,
62+
}
63+
64+
impl<ES: Deref, MR: Deref, R: Deref> OffersMessageFlow<ES, MR, R>
65+
where
66+
ES::Target: EntropySource,
67+
MR::Target: MessageRouter,
68+
R::Target: Router,
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+
entropy_source: ES, message_router: MR, router: R,
75+
) -> Self {
76+
let mut secp_ctx = Secp256k1::new();
77+
secp_ctx.seeded_randomize(&entropy_source.get_secure_random_bytes());
78+
79+
Self {
80+
chain_hash,
81+
best_block: RwLock::new(best_block),
82+
83+
our_network_pubkey,
84+
highest_seen_timestamp: AtomicUsize::new(current_timestamp as usize),
85+
inbound_payment_key,
86+
87+
secp_ctx,
88+
entropy_source,
89+
90+
message_router,
91+
router,
92+
93+
pending_offers_messages: Mutex::new(Vec::new()),
94+
pending_async_payments_messages: Mutex::new(Vec::new()),
95+
#[cfg(feature = "dnssec")]
96+
pending_dns_onion_messages: Mutex::new(Vec::new()),
97+
}
98+
}
99+
100+
/// Gets the node_id held by this OffersMessageFlow
101+
pub fn get_our_node_id(&self) -> PublicKey {
102+
self.our_network_pubkey
103+
}
104+
105+
fn duration_since_epoch(&self) -> Duration {
106+
#[cfg(not(feature = "std"))]
107+
let now = Duration::from_secs(self.highest_seen_timestamp.load(Ordering::Acquire) as u64);
108+
#[cfg(feature = "std")]
109+
let now = std::time::SystemTime::now()
110+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
111+
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
112+
now
113+
}
114+
115+
fn best_block_updated(&self, header: &Header) {
116+
macro_rules! max_time {
117+
($timestamp: expr) => {
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+
}
142+
143+
max_time!(self.highest_seen_timestamp);
144+
}
145+
}
146+
147+
impl<ES: Deref, MR: Deref, R: Deref> chain::Listen for OffersMessageFlow<ES, MR, R>
148+
where
149+
ES::Target: EntropySource,
150+
MR::Target: MessageRouter,
151+
R::Target: Router,
152+
{
153+
fn filtered_block_connected(&self, header: &Header, _txdata: &TransactionData, _height: u32) {
154+
self.best_block_updated(header);
155+
}
156+
157+
fn block_disconnected(&self, _header: &Header, _height: u32) {}
158+
}

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)