Skip to content

Commit b9970ff

Browse files
committed
Define an OfferId for BOLT 12 Offers
Use a merkle root hash of the offer TLV records to define an offer id. Will be included in a BOLT 12 invoice's blinded payment paths in order for the recipient to identify which offer the payment is for.
1 parent 9be364f commit b9970ff

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

lightning/src/offers/merkle.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ impl TaggedHash {
6666
pub fn merkle_root(&self) -> sha256::Hash {
6767
self.merkle_root
6868
}
69+
70+
pub(super) fn to_bytes(&self) -> [u8; 32] {
71+
*self.digest.as_ref()
72+
}
6973
}
7074

7175
impl AsRef<TaggedHash> for TaggedHash {

lightning/src/offers/offer.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ use crate::blinded_path::BlindedPath;
9090
use crate::ln::channelmanager::PaymentId;
9191
use crate::ln::features::OfferFeatures;
9292
use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
93-
use crate::ln::msgs::MAX_VALUE_MSAT;
94-
use crate::offers::merkle::TlvStream;
93+
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
94+
use crate::offers::merkle::{TaggedHash, TlvStream};
9595
use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
9696
use crate::offers::signer::{Metadata, MetadataMaterial, self};
97-
use crate::util::ser::{HighZeroBytesDroppedBigSize, WithoutLength, Writeable, Writer};
97+
use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
9898
use crate::util::string::PrintableString;
9999

100100
#[cfg(not(c_bindings))]
@@ -114,6 +114,31 @@ use std::time::SystemTime;
114114

115115
pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Offer ~~~~~~";
116116

117+
/// An identifier for an [`Offer`] built using [`DerivedMetadata`].
118+
#[derive(Clone, Copy, Debug, PartialEq)]
119+
pub struct OfferId(pub [u8; 32]);
120+
121+
impl OfferId {
122+
const ID_TAG: &'static str = "LDK Offer ID";
123+
124+
fn from_valid_offer_tlv_stream(bytes: &[u8]) -> Self {
125+
let tagged_hash = TaggedHash::new(Self::ID_TAG, &bytes);
126+
Self(tagged_hash.to_bytes())
127+
}
128+
}
129+
130+
impl Writeable for OfferId {
131+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
132+
self.0.write(w)
133+
}
134+
}
135+
136+
impl Readable for OfferId {
137+
fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
138+
Ok(OfferId(Readable::read(r)?))
139+
}
140+
}
141+
117142
/// Builds an [`Offer`] for the "offer to be paid" flow.
118143
///
119144
/// See [module-level documentation] for usage.
@@ -370,12 +395,15 @@ macro_rules! offer_builder_methods { (
370395
let mut bytes = Vec::new();
371396
$self.offer.write(&mut bytes).unwrap();
372397

398+
let id = OfferId::from_valid_offer_tlv_stream(&bytes);
399+
373400
Offer {
374401
bytes,
375402
#[cfg(not(c_bindings))]
376403
contents: $self.offer,
377404
#[cfg(c_bindings)]
378-
contents: $self.offer.clone()
405+
contents: $self.offer.clone(),
406+
id,
379407
}
380408
}
381409
} }
@@ -488,6 +516,7 @@ pub struct Offer {
488516
// fields.
489517
pub(super) bytes: Vec<u8>,
490518
pub(super) contents: OfferContents,
519+
id: OfferId,
491520
}
492521

493522
/// The contents of an [`Offer`], which may be shared with an [`InvoiceRequest`] or a
@@ -577,6 +606,11 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
577606
impl Offer {
578607
offer_accessors!(self, self.contents);
579608

609+
/// Returns the id of the offer.
610+
pub fn id(&self) -> OfferId {
611+
self.id
612+
}
613+
580614
pub(super) fn implied_chain(&self) -> ChainHash {
581615
self.contents.implied_chain()
582616
}
@@ -1002,7 +1036,9 @@ impl TryFrom<Vec<u8>> for Offer {
10021036
let offer = ParsedMessage::<OfferTlvStream>::try_from(bytes)?;
10031037
let ParsedMessage { bytes, tlv_stream } = offer;
10041038
let contents = OfferContents::try_from(tlv_stream)?;
1005-
Ok(Offer { bytes, contents })
1039+
let id = OfferId::from_valid_offer_tlv_stream(&bytes);
1040+
1041+
Ok(Offer { bytes, contents, id })
10061042
}
10071043
}
10081044

0 commit comments

Comments
 (0)