Skip to content

Commit ca8a64f

Browse files
committed
Offer raw byte encoding and decoding
Offers are typically encoded as bech32 strings for use in QR codes. However, a more compact encoding is useful when storing offers long-term. Implement Writeable for Offer and have a corresponding TryFrom implementation for decoding the raw bytes.
1 parent 136f088 commit ca8a64f

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

lightning/src/offers/offer.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
//! extern crate core;
1919
//! extern crate lightning;
2020
//!
21+
//! use core::convert::TryFrom;
2122
//! use core::num::NonZeroU64;
2223
//! use core::time::Duration;
2324
//!
2425
//! use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
2526
//! use lightning::offers::offer::{Amount, Offer, OfferBuilder};
2627
//! use lightning::offers::parse::ParseError;
28+
//! use lightning::util::ser::{Readable, Writeable};
2729
//!
2830
//! # use lightning::onion_message::BlindedPath;
2931
//! # #[cfg(feature = "std")]
@@ -54,6 +56,13 @@
5456
//!
5557
//! // Parse from a bech32 string after scanning from a QR code.
5658
//! let offer = encoded_offer.parse::<Offer>()?;
59+
//!
60+
//! // Encode offer as raw bytes.
61+
//! let mut bytes = Vec::new();
62+
//! offer.write(&mut bytes).unwrap();
63+
//!
64+
//! // Decode raw bytes into an offer.
65+
//! let offer = Offer::try_from(bytes)?;
5766
//! # Ok(())
5867
//! # }
5968
//! ```
@@ -70,7 +79,7 @@ use io;
7079
use ln::features::OfferFeatures;
7180
use offers::parse::{Bech32Encode, ParseError, SemanticError};
7281
use onion_message::BlindedPath;
73-
use util::ser::{Writeable, Writer};
82+
use util::ser::{Readable, Writeable, Writer};
7483

7584
use prelude::*;
7685

@@ -383,12 +392,27 @@ impl OfferContents {
383392
}
384393
}
385394

395+
impl Writeable for Offer {
396+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
397+
self.bytes.write(writer)
398+
}
399+
}
400+
386401
impl Writeable for OfferContents {
387402
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
388403
self.as_tlv_stream().write(writer)
389404
}
390405
}
391406

407+
impl TryFrom<Vec<u8>> for Offer {
408+
type Error = ParseError;
409+
410+
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
411+
let tlv_stream: OfferTlvStream = Readable::read(&mut &bytes[..])?;
412+
Offer::try_from((bytes, tlv_stream))
413+
}
414+
}
415+
392416
/// The amount required for an item in an [`Offer`] denominated in either bitcoin or another
393417
/// currency.
394418
#[derive(Clone, Debug, PartialEq)]
@@ -431,6 +455,8 @@ impl Bech32Encode for Offer {
431455
const BECH32_HRP: &'static str = "lno";
432456
}
433457

458+
type ParsedOffer = (Vec<u8>, OfferTlvStream);
459+
434460
impl FromStr for Offer {
435461
type Err = ParseError;
436462

@@ -441,6 +467,16 @@ impl FromStr for Offer {
441467
}
442468
}
443469

470+
impl TryFrom<ParsedOffer> for Offer {
471+
type Error = ParseError;
472+
473+
fn try_from(offer: ParsedOffer) -> Result<Self, Self::Error> {
474+
let (bytes, tlv_stream) = offer;
475+
let contents = OfferContents::try_from(tlv_stream)?;
476+
Ok(Offer { bytes, contents })
477+
}
478+
}
479+
444480
impl TryFrom<OfferTlvStream> for OfferContents {
445481
type Error = SemanticError;
446482

0 commit comments

Comments
 (0)