Skip to content

Commit 953fd74

Browse files
committed
WIP: Drop OfferTlvStream
1 parent 5cb3c44 commit 953fd74

File tree

2 files changed

+89
-96
lines changed

2 files changed

+89
-96
lines changed

lightning/src/offers/mod.rs

Lines changed: 83 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@ use core::time::Duration;
2424
use ln::PaymentHash;
2525
use ln::features::OfferFeatures;
2626
use ln::msgs::DecodeError;
27-
use util::ser::{HighZeroBytesDroppedVarInt, Readable, WithLength, WithoutLength};
27+
use util::ser::{HighZeroBytesDroppedVarInt, Readable, WithLength, WithoutLength, Writeable};
2828

2929
use prelude::*;
30+
use io;
3031

3132
#[cfg(feature = "std")]
3233
use std::time::SystemTime;
@@ -123,7 +124,9 @@ impl Offer {
123124
self.signature.as_ref()
124125
}
125126

126-
fn to_tlv_stream(&self) -> OfferTlvStream {
127+
fn write(&self, writer: &mut Vec<u8>) -> Result<(), io::Error> {
128+
let chains = self.chains.clone().map(|chains| WithoutLength(chains));
129+
127130
let (currency, amount) = match self.amount.clone() {
128131
None => (None, None),
129132
Some(Amount::Bitcoin { amount_msats }) => (
@@ -134,33 +137,43 @@ impl Offer {
134137
),
135138
};
136139

140+
let description = Some(WithoutLength(self.description.clone()));
141+
let features = self.features.as_ref();
142+
let absolute_expiry = self.absolute_expiry.map(|d| HighZeroBytesDroppedVarInt(d.as_secs()));
143+
137144
let (paths, node_id) = match self.destination.clone() {
138145
Destination::NodeId(node_id) => (None, Some(node_id)),
139146
Destination::Paths(paths) => (Some(WithoutLength(paths)), None),
140147
};
141148

142-
let (send_invoice, refund_for) = match self.send_invoice.clone() {
149+
let issuer = self.issuer.clone().map(|issuer| WithoutLength(issuer));
150+
let quantity_min = self.quantity_min.map(|quantity| HighZeroBytesDroppedVarInt(quantity));
151+
let quantity_max = self.quantity_max.map(|quantity| HighZeroBytesDroppedVarInt(quantity));
152+
let recurrence = self.recurrence.as_ref();
153+
154+
let (send_invoice, refund_for) = match self.send_invoice {
143155
None => (None, None),
144156
Some(SendInvoice { refund_for }) => (Some(()), refund_for),
145157
};
146158

147-
OfferTlvStream {
148-
chains: self.chains.clone().map(|chains| WithoutLength(chains)),
149-
currency,
150-
amount,
151-
description: Some(WithoutLength(self.description.clone())),
152-
features: self.features.clone(),
153-
absolute_expiry: self.absolute_expiry.map(|d| HighZeroBytesDroppedVarInt(d.as_secs())),
154-
paths,
155-
issuer: self.issuer.clone().map(|issuer| WithoutLength(issuer)),
156-
quantity_min: self.quantity_min.map(|quantity| HighZeroBytesDroppedVarInt(quantity)),
157-
quantity_max: self.quantity_max.map(|quantity| HighZeroBytesDroppedVarInt(quantity)),
158-
recurrence: self.recurrence.clone(),
159-
node_id,
160-
send_invoice,
161-
refund_for,
162-
signature: self.signature,
163-
}
159+
encode_tlv_stream!(writer, {
160+
(2, chains, option),
161+
(6, currency, option),
162+
(8, amount, option),
163+
(10, description, option),
164+
(12, self.features, option),
165+
(14, absolute_expiry, option),
166+
(16, paths, option),
167+
(20, issuer, option),
168+
(22, quantity_min, option),
169+
(24, quantity_max, option),
170+
(26, recurrence, option),
171+
(30, node_id, option),
172+
(34, refund_for, option),
173+
(54, send_invoice, option),
174+
(240, self.signature, option),
175+
});
176+
Ok(())
164177
}
165178
}
166179

@@ -208,45 +221,6 @@ pub struct SendInvoice {
208221
refund_for: Option<PaymentHash>,
209222
}
210223

211-
/// An `offer` TLV stream without any semantic checks, apart from any checks performed when parsing
212-
/// the underlying types.
213-
#[derive(Debug)]
214-
struct OfferTlvStream {
215-
chains: Option<WithoutLength<Vec<BlockHash>>>,
216-
currency: Option<WithoutLength<String>>,
217-
amount: Option<HighZeroBytesDroppedVarInt<u64>>,
218-
description: Option<WithoutLength<String>>,
219-
features: Option<OfferFeatures>,
220-
absolute_expiry: Option<HighZeroBytesDroppedVarInt<u64>>,
221-
paths: Option<WithoutLength<Vec<BlindedPath>>>,
222-
issuer: Option<WithoutLength<String>>,
223-
quantity_min: Option<HighZeroBytesDroppedVarInt<u64>>,
224-
quantity_max: Option<HighZeroBytesDroppedVarInt<u64>>,
225-
recurrence: Option<Recurrence>,
226-
node_id: Option<XOnlyPublicKey>,
227-
send_invoice: Option<()>,
228-
refund_for: Option<PaymentHash>,
229-
signature: Option<Signature>,
230-
}
231-
232-
impl_writeable_tlv_stream!(OfferTlvStream, {
233-
(2, chains, option),
234-
(6, currency, option),
235-
(8, amount, option),
236-
(10, description, option),
237-
(12, features, option),
238-
(14, absolute_expiry, option),
239-
(16, paths, option),
240-
(20, issuer, option),
241-
(22, quantity_min, option),
242-
(24, quantity_max, option),
243-
(26, recurrence, option),
244-
(30, node_id, option),
245-
(34, refund_for, option),
246-
(54, send_invoice, option),
247-
(240, signature, option),
248-
});
249-
250224
#[derive(Clone, Debug)]
251225
///
252226
pub struct BlindedPath {
@@ -273,9 +247,8 @@ struct Recurrence {
273247

274248
impl_writeable!(Recurrence, { time_unit, period });
275249

276-
/// An offer parsed from a bech32-encoded string as a TLV stream and the corresponding bytes. The
277-
/// latter is used for signature verification.
278-
struct ParsedOffer(OfferTlvStream, Vec<u8>);
250+
/// An offer parsed from a bech32-encoded string as serialized bytes.
251+
struct ParsedOffer(Vec<u8>);
279252

280253
/// Error when parsing a bech32 encoded message using [`str::parse`].
281254
#[derive(Debug, PartialEq)]
@@ -337,9 +310,9 @@ impl From<SemanticError> for ParseError {
337310
}
338311
}
339312

340-
impl From<secp256k1::Error> for SemanticError {
313+
impl From<secp256k1::Error> for ParseError {
341314
fn from(error: secp256k1::Error) -> Self {
342-
Self::InvalidSignature(error)
315+
SemanticError::InvalidSignature(error).into()
343316
}
344317
}
345318

@@ -352,13 +325,41 @@ impl FromStr for Offer {
352325
}
353326

354327
impl TryFrom<ParsedOffer> for Offer {
355-
type Error = SemanticError;
328+
type Error = ParseError;
356329

357330
fn try_from(offer: ParsedOffer) -> Result<Self, Self::Error> {
358-
let ParsedOffer(OfferTlvStream {
359-
chains, currency, amount, description, features, absolute_expiry, paths, issuer,
360-
quantity_min, quantity_max, recurrence, node_id, send_invoice, refund_for, signature,
361-
}, data) = offer;
331+
let mut chains: Option<WithoutLength<Vec<BlockHash>>> = None;
332+
let mut currency: Option<WithoutLength<String>> = None;
333+
let mut amount = None;
334+
let mut description: Option<WithoutLength<String>> = None;
335+
let mut features = None;
336+
let mut absolute_expiry: Option<HighZeroBytesDroppedVarInt<u64>> = None;
337+
let mut paths: Option<WithoutLength<Vec<BlindedPath>>> = None;
338+
let mut issuer: Option<WithoutLength<String>> = None;
339+
let mut quantity_min = None;
340+
let mut quantity_max = None;
341+
let mut recurrence = None;
342+
let mut node_id = None;
343+
let mut send_invoice = None;
344+
let mut refund_for = None;
345+
let mut signature = None;
346+
decode_tlv_stream!(&mut &offer.0[..], {
347+
(2, chains, option),
348+
(6, currency, option),
349+
(8, amount, option),
350+
(10, description, option),
351+
(12, features, option),
352+
(14, absolute_expiry, option),
353+
(16, paths, option),
354+
(20, issuer, option),
355+
(22, quantity_min, option),
356+
(24, quantity_max, option),
357+
(26, recurrence, option),
358+
(30, node_id, option),
359+
(34, refund_for, option),
360+
(54, send_invoice, option),
361+
(240, signature, option),
362+
});
362363

363364
let supported_chains = [
364365
genesis_block(Network::Bitcoin).block_hash(),
@@ -371,59 +372,59 @@ impl TryFrom<ParsedOffer> for Offer {
371372
Some(WithoutLength(chains)) => match chains.first() {
372373
None => Some(chains),
373374
Some(chain) if supported_chains.contains(chain) => Some(chains),
374-
_ => return Err(SemanticError::UnsupportedChain),
375+
_ => return Err(SemanticError::UnsupportedChain.into()),
375376
},
376377
};
377378

378379
let amount = match (currency, amount) {
379380
(None, None) => None,
380381
(None, Some(amount_msats)) => Some(Amount::Bitcoin { amount_msats: amount_msats.0 }),
381-
(Some(_), None) => return Err(SemanticError::UnexpectedCurrency),
382+
(Some(_), None) => return Err(SemanticError::UnexpectedCurrency.into()),
382383
(Some(WithoutLength(iso4217_code)), Some(HighZeroBytesDroppedVarInt(amount))) => {
383384
if iso4217_code.len() != ISO4217_CODE_LEN {
384-
return Err(SemanticError::InvalidCurrencyEncoding);
385+
return Err(SemanticError::InvalidCurrencyEncoding.into());
385386
}
386387
Some(Amount::Currency { iso4217_code, amount })
387388
},
388389
};
389390

390391
if description.is_none() {
391-
return Err(SemanticError::MissingDescription);
392+
return Err(SemanticError::MissingDescription.into());
392393
}
393394

394395
let destination = match (node_id, paths) {
395-
(None, None) => return Err(SemanticError::MissingDestination),
396-
(Some(_), Some(_)) => return Err(SemanticError::DuplicateDestination),
396+
(None, None) => return Err(SemanticError::MissingDestination.into()),
397+
(Some(_), Some(_)) => return Err(SemanticError::DuplicateDestination.into()),
397398
(Some(node_id), None) => Destination::NodeId(node_id),
398-
(None, Some(paths)) if paths.0.is_empty() => return Err(SemanticError::MissingPaths),
399+
(None, Some(paths)) if paths.0.is_empty() => return Err(SemanticError::MissingPaths.into()),
399400
(None, Some(WithoutLength(paths))) => Destination::Paths(paths),
400401
};
401402

402403
if let Some(HighZeroBytesDroppedVarInt(quantity_min)) = quantity_min {
403404
if quantity_min < 1 {
404-
return Err(SemanticError::InvalidQuantity);
405+
return Err(SemanticError::InvalidQuantity.into());
405406
}
406407

407408
if let Some(HighZeroBytesDroppedVarInt(quantity_max)) = quantity_max {
408409
if quantity_min > quantity_max {
409-
return Err(SemanticError::InvalidQuantity);
410+
return Err(SemanticError::InvalidQuantity.into());
410411
}
411412
}
412413
}
413414

414415
if let Some(HighZeroBytesDroppedVarInt(quantity_max)) = quantity_max {
415416
if quantity_max < 1 {
416-
return Err(SemanticError::InvalidQuantity);
417+
return Err(SemanticError::InvalidQuantity.into());
417418
}
418419
}
419420

420421
let send_invoice = match (send_invoice, refund_for) {
421422
(None, None) => None,
422-
(None, Some(_)) => return Err(SemanticError::UnexpectedRefund),
423+
(None, Some(_)) => return Err(SemanticError::UnexpectedRefund.into()),
423424
(Some(_), _) => Some(SendInvoice { refund_for }),
424425
};
425426

426-
let id = merkle::root_hash(&data);
427+
let id = merkle::root_hash(&offer.0);
427428
if let Some(signature) = &signature {
428429
let tag = sha256::Hash::hash(concat!("lightning", "offer", "signature").as_bytes());
429430
let message = Message::from_slice(&merkle::tagged_hash(tag, id)).unwrap();
@@ -472,26 +473,18 @@ impl FromStr for ParsedOffer {
472473
}
473474

474475
let data = Vec::<u8>::from_base32(&data)?;
475-
Ok(ParsedOffer(Readable::read(&mut &data[..])?, data))
476+
Ok(ParsedOffer(data))
476477
}
477478
}
478479

479480
impl core::fmt::Display for Offer {
480481
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
481-
self.to_tlv_stream().fmt(f)
482-
}
483-
}
484-
485-
impl core::fmt::Display for OfferTlvStream {
486-
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
487-
use util::ser::Writeable;
488482
let mut buffer = Vec::new();
489483
self.write(&mut buffer).unwrap();
490484

491485
use bitcoin::bech32::ToBase32;
492486
let data = buffer.to_base32();
493487
bech32::encode_without_checksum_to_fmt(f, OFFER_BECH32_HRP, data).expect("HRP is valid").unwrap();
494-
495488
Ok(())
496489
}
497490
}

lightning/src/util/ser_macros.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ macro_rules! check_missing_tlv {
135135
#[allow(unused_comparisons)] // Note that $type may be 0 making the second comparison always true
136136
let missing_req_type = $last_seen_type.is_none() || $last_seen_type.unwrap() < $type;
137137
if missing_req_type {
138-
return Err(DecodeError::InvalidValue);
138+
return Err(DecodeError::InvalidValue.into());
139139
}
140140
}};
141141
($last_seen_type: expr, $type: expr, $field: ident, vec_type) => {{
@@ -194,18 +194,18 @@ macro_rules! decode_tlv_stream {
194194
if !tracking_reader.have_read {
195195
break 'tlv_read;
196196
} else {
197-
return Err(DecodeError::ShortRead);
197+
return Err(DecodeError::ShortRead.into());
198198
}
199199
},
200-
Err(e) => return Err(e),
200+
Err(e) => return Err(e.into()),
201201
Ok(t) => t,
202202
}
203203
};
204204

205205
// Types must be unique and monotonically increasing:
206206
match last_seen_type {
207207
Some(t) if typ.0 <= t => {
208-
return Err(DecodeError::InvalidValue);
208+
return Err(DecodeError::InvalidValue.into());
209209
},
210210
_ => {},
211211
}
@@ -223,11 +223,11 @@ macro_rules! decode_tlv_stream {
223223
decode_tlv!(s, $field, $fieldty);
224224
if s.bytes_remain() {
225225
s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes
226-
return Err(DecodeError::InvalidValue);
226+
return Err(DecodeError::InvalidValue.into());
227227
}
228228
},)*
229229
x if x % 2 == 0 => {
230-
return Err(DecodeError::UnknownRequiredFeature);
230+
return Err(DecodeError::UnknownRequiredFeature.into());
231231
},
232232
_ => {},
233233
}

0 commit comments

Comments
 (0)