use crate::offers::invoice_request::{EXPERIMENTAL_INVOICE_REQUEST_TYPES, INVOICE_REQUEST_PAYER_ID_TYPE, INVOICE_REQUEST_TYPES, IV_BYTES as INVOICE_REQUEST_IV_BYTES, InvoiceRequest, InvoiceRequestContents, InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self, SIGNATURE_TLV_RECORD_SIZE};
use crate::offers::nonce::Nonce;
-use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
+use crate::offers::offer::{Amount, EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, OfferTlvStream, OfferTlvStreamRef, Quantity};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::payer::{PAYER_METADATA_TYPE, PayerTlvStream, PayerTlvStreamRef};
use crate::offers::refund::{IV_BYTES_WITH_METADATA as REFUND_IV_BYTES_WITH_METADATA, IV_BYTES_WITHOUT_METADATA as REFUND_IV_BYTES_WITHOUT_METADATA, Refund, RefundContents};
const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
- let (_, _, _, invoice_tlv_stream) = contents.as_tlv_stream();
+ let (_, _, _, invoice_tlv_stream, _) = contents.as_tlv_stream();
// Allocate enough space for the invoice, which will include:
// - all TLV records from `invreq_bytes` except signatures,
}
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
- let (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream) =
- self.contents.as_tlv_stream();
+ let (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
+ experimental_offer_tlv_stream,
+ ) = self.contents.as_tlv_stream();
let signature_tlv_stream = SignatureTlvStreamRef {
signature: Some(&self.signature),
};
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
- signature_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
+ signature_tlv_stream, experimental_offer_tlv_stream,
+ )
}
pub(crate) fn is_for_refund_without_paths(&self) -> bool {
fn verify<T: secp256k1::Signing>(
&self, bytes: &[u8], metadata: &Metadata, key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
- secp_ctx: &Secp256k1<T>
+ secp_ctx: &Secp256k1<T>,
) -> Result<PaymentId, ()> {
const EXPERIMENTAL_TYPES: core::ops::Range<u64> =
EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_REQUEST_TYPES.end;
}
fn as_tlv_stream(&self) -> PartialInvoiceTlvStreamRef {
- let (payer, offer, invoice_request) = match self {
+ let (payer, offer, invoice_request, experimental_offer) = match self {
InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.as_tlv_stream(),
InvoiceContents::ForRefund { refund, .. } => refund.as_tlv_stream(),
};
let invoice = self.fields().as_tlv_stream();
- (payer, offer, invoice_request, invoice)
+ (payer, offer, invoice_request, invoice, experimental_offer)
}
}
impl_writeable!(FallbackAddress, { version, program });
-type FullInvoiceTlvStream =
- (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream);
+type FullInvoiceTlvStream =(
+ PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream,
+ ExperimentalOfferTlvStream,
+);
type FullInvoiceTlvStreamRef<'a> = (
PayerTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>,
InvoiceTlvStreamRef<'a>,
SignatureTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
);
impl CursorReadable for FullInvoiceTlvStream {
let invoice_request = CursorReadable::read(r)?;
let invoice = CursorReadable::read(r)?;
let signature = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
- Ok((payer, offer, invoice_request, invoice, signature))
+ Ok((payer, offer, invoice_request, invoice, signature, experimental_offer))
}
}
-type PartialInvoiceTlvStream =
- (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream);
+type PartialInvoiceTlvStream = (
+ PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream,
+ ExperimentalOfferTlvStream,
+);
type PartialInvoiceTlvStreamRef<'a> = (
PayerTlvStreamRef<'a>,
OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>,
InvoiceTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
);
impl CursorReadable for PartialInvoiceTlvStream {
let offer = CursorReadable::read(r)?;
let invoice_request = CursorReadable::read(r)?;
let invoice = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
- Ok((payer, offer, invoice_request, invoice))
+ Ok((payer, offer, invoice_request, invoice, experimental_offer))
}
}
let (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
SignatureTlvStream { signature },
+ experimental_offer_tlv_stream,
) = tlv_stream;
let contents = InvoiceContents::try_from(
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
+ experimental_offer_tlv_stream,
+ )
)?;
let signature = signature.ok_or(
paths, blindedpay, created_at, relative_expiry, payment_hash, amount, fallbacks,
features, node_id, message_paths,
},
+ experimental_offer_tlv_stream,
) = tlv_stream;
if message_paths.is_some() { return Err(Bolt12SemanticError::UnexpectedPaths) }
if offer_tlv_stream.issuer_id.is_none() && offer_tlv_stream.paths.is_none() {
let refund = RefundContents::try_from(
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
+ experimental_offer_tlv_stream,
+ )
)?;
Ok(InvoiceContents::ForRefund { refund, fields })
} else {
let invoice_request = InvoiceRequestContents::try_from(
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
+ experimental_offer_tlv_stream,
+ )
)?;
Ok(InvoiceContents::ForOffer { invoice_request, fields })
}
use crate::offers::invoice_request::InvoiceRequestTlvStreamRef;
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
use crate::offers::nonce::Nonce;
- use crate::offers::offer::{Amount, OfferTlvStreamRef, Quantity};
+ use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
use crate::prelude::*;
#[cfg(not(c_bindings))]
use {
message_paths: None,
},
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
+ ExperimentalOfferTlvStreamRef {},
),
);
message_paths: None,
},
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
+ ExperimentalOfferTlvStreamRef {},
),
);
.relative_expiry(one_hour.as_secs() as u32)
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
#[cfg(feature = "std")]
assert!(!invoice.is_expired());
assert_eq!(invoice.relative_expiry(), one_hour);
.relative_expiry(one_hour.as_secs() as u32 - 1)
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
#[cfg(feature = "std")]
assert!(invoice.is_expired());
assert_eq!(invoice.relative_expiry(), one_hour - Duration::from_secs(1));
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.amount_msats(), 1001);
assert_eq!(tlv_stream.amount, Some(1001));
}
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.amount_msats(), 2000);
assert_eq!(tlv_stream.amount, Some(2000));
.fallback_v1_p2tr_tweaked(&tweaked_pubkey)
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
assert_eq!(
invoice.fallbacks(),
vec![
.allow_mpp()
.build().unwrap()
.sign(recipient_sign).unwrap();
- let (_, _, _, tlv_stream, _) = invoice.as_tlv_stream();
+ let (_, _, _, tlv_stream, _, _) = invoice.as_tlv_stream();
assert_eq!(invoice.invoice_features(), &features);
assert_eq!(tlv_stream.features, Some(&features));
}
use crate::ln::msgs::DecodeError;
use crate::offers::merkle::{SignError, SignFn, SignatureTlvStream, SignatureTlvStreamRef, TaggedHash, TlvStream, self, SIGNATURE_TLV_RECORD_SIZE};
use crate::offers::nonce::Nonce;
-use crate::offers::offer::{EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES, Offer, OfferContents, OfferId, OfferTlvStream, OfferTlvStreamRef};
+use crate::offers::offer::{EXPERIMENTAL_OFFER_TYPES, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OFFER_TYPES, Offer, OfferContents, OfferId, OfferTlvStream, OfferTlvStreamRef};
use crate::offers::parse::{Bolt12ParseError, ParsedMessage, Bolt12SemanticError};
use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
use crate::offers::signer::{Metadata, MetadataMaterial};
// unknown TLV records, which are not stored in `OfferContents`.
let (
payer_tlv_stream, _offer_tlv_stream, invoice_request_tlv_stream,
+ _experimental_offer_tlv_stream,
) = contents.as_tlv_stream();
// Allocate enough space for the invoice_request, which will include:
}
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef {
- let (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) =
- self.contents.as_tlv_stream();
+ let (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
+ experimental_offer_tlv_stream,
+ ) = self.contents.as_tlv_stream();
let signature_tlv_stream = SignatureTlvStreamRef {
signature: Some(&self.signature),
};
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, signature_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
+ signature_tlv_stream, experimental_offer_tlv_stream,
+ )
}
}
}
pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef {
- let (payer, offer, mut invoice_request) = self.inner.as_tlv_stream();
+ let (payer, offer, mut invoice_request, experimental_offer) = self.inner.as_tlv_stream();
invoice_request.payer_id = Some(&self.payer_signing_pubkey);
- (payer, offer, invoice_request)
+ (payer, offer, invoice_request, experimental_offer)
}
}
metadata: self.payer.0.as_bytes(),
};
- let offer = self.offer.as_tlv_stream();
+ let (offer, experimental_offer) = self.offer.as_tlv_stream();
let features = {
if self.features == InvoiceRequestFeatures::empty() { None }
paths: None,
};
- (payer, offer, invoice_request)
+ (payer, offer, invoice_request, experimental_offer)
}
}
pub(super) const EXPERIMENTAL_INVOICE_REQUEST_TYPES: core::ops::Range<u64> =
2_000_000_000..3_000_000_000;
-type FullInvoiceRequestTlvStream =
- (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, SignatureTlvStream);
+type FullInvoiceRequestTlvStream = (
+ PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, SignatureTlvStream,
+ ExperimentalOfferTlvStream,
+);
type FullInvoiceRequestTlvStreamRef<'a> = (
PayerTlvStreamRef<'a>,
OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>,
SignatureTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
);
impl CursorReadable for FullInvoiceRequestTlvStream {
let offer = CursorReadable::read(r)?;
let invoice_request = CursorReadable::read(r)?;
let signature = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
- Ok((payer, offer, invoice_request, signature))
+ Ok((payer, offer, invoice_request, signature, experimental_offer))
}
}
-type PartialInvoiceRequestTlvStream = (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream);
+type PartialInvoiceRequestTlvStream = (
+ PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream,
+);
type PartialInvoiceRequestTlvStreamRef<'a> = (
PayerTlvStreamRef<'a>,
OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
);
impl TryFrom<Vec<u8>> for UnsignedInvoiceRequest {
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
let invoice_request = ParsedMessage::<PartialInvoiceRequestTlvStream>::try_from(bytes)?;
let ParsedMessage { mut bytes, tlv_stream } = invoice_request;
- let (
- payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
- ) = tlv_stream;
- let contents = InvoiceRequestContents::try_from(
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
- )?;
+ let contents = InvoiceRequestContents::try_from(tlv_stream)?;
let tagged_hash = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &bytes);
let offset = TlvStream::new(&bytes)
let (
payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
SignatureTlvStream { signature },
+ experimental_offer_tlv_stream,
) = tlv_stream;
let contents = InvoiceRequestContents::try_from(
- (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
+ (
+ payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream,
+ experimental_offer_tlv_stream,
+ )
)?;
let signature = match signature {
InvoiceRequestTlvStream {
chain, amount, features, quantity, payer_id, payer_note, paths,
},
+ experimental_offer_tlv_stream,
) = tlv_stream;
let payer = match metadata {
None => return Err(Bolt12SemanticError::MissingPayerMetadata),
Some(metadata) => PayerContents(Metadata::Bytes(metadata)),
};
- let offer = OfferContents::try_from(offer_tlv_stream)?;
+ let offer = OfferContents::try_from((offer_tlv_stream, experimental_offer_tlv_stream))?;
if !offer.supports_chain(chain.unwrap_or_else(|| offer.implied_chain())) {
return Err(Bolt12SemanticError::UnsupportedChain);
use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
use crate::offers::merkle::{SignError, SignatureTlvStreamRef, TaggedHash, self};
use crate::offers::nonce::Nonce;
- use crate::offers::offer::{Amount, OfferTlvStreamRef, Quantity};
+ use crate::offers::offer::{Amount, ExperimentalOfferTlvStreamRef, OfferTlvStreamRef, Quantity};
#[cfg(not(c_bindings))]
use {
crate::offers::offer::OfferBuilder,
paths: None,
},
SignatureTlvStreamRef { signature: Some(&invoice_request.signature()) },
+ ExperimentalOfferTlvStreamRef {},
),
);
// Fails verification with altered fields
let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream,
- mut invoice_tlv_stream, mut signature_tlv_stream
+ mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
) = invoice.as_tlv_stream();
invoice_request_tlv_stream.amount = Some(2000);
invoice_tlv_stream.amount = Some(2000);
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap();
+ experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature);
- let mut encoded_invoice = bytes;
+ let mut encoded_invoice = Vec::new();
+ tlv_stream.write(&mut encoded_invoice).unwrap();
signature_tlv_stream.write(&mut encoded_invoice).unwrap();
+ experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
// Fails verification with altered metadata
let (
mut payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
- mut signature_tlv_stream
+ mut signature_tlv_stream, experimental_offer_tlv_stream,
) = invoice.as_tlv_stream();
let metadata = payer_tlv_stream.metadata.unwrap().iter().copied().rev().collect();
payer_tlv_stream.metadata = Some(&metadata);
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap();
+ experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature);
- let mut encoded_invoice = bytes;
+ let mut encoded_invoice = Vec::new();
+ tlv_stream.write(&mut encoded_invoice).unwrap();
signature_tlv_stream.write(&mut encoded_invoice).unwrap();
+ experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(invoice.verify_using_metadata(&expanded_key, &secp_ctx).is_err());
// Fails verification with altered fields
let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream,
- mut invoice_tlv_stream, mut signature_tlv_stream
+ mut invoice_tlv_stream, mut signature_tlv_stream, experimental_offer_tlv_stream,
) = invoice.as_tlv_stream();
invoice_request_tlv_stream.amount = Some(2000);
invoice_tlv_stream.amount = Some(2000);
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap();
+ experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature);
- let mut encoded_invoice = bytes;
+ let mut encoded_invoice = Vec::new();
+ tlv_stream.write(&mut encoded_invoice).unwrap();
signature_tlv_stream.write(&mut encoded_invoice).unwrap();
+ experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(
// Fails verification with altered payer id
let (
payer_tlv_stream, offer_tlv_stream, mut invoice_request_tlv_stream, invoice_tlv_stream,
- mut signature_tlv_stream
+ mut signature_tlv_stream, experimental_offer_tlv_stream,
) = invoice.as_tlv_stream();
let payer_id = pubkey(1);
invoice_request_tlv_stream.payer_id = Some(&payer_id);
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream);
let mut bytes = Vec::new();
tlv_stream.write(&mut bytes).unwrap();
+ experimental_offer_tlv_stream.write(&mut bytes).unwrap();
let message = TaggedHash::from_valid_tlv_stream_bytes(INVOICE_SIGNATURE_TAG, &bytes);
let signature = merkle::sign_message(recipient_sign, &message, recipient_pubkey()).unwrap();
signature_tlv_stream.signature = Some(&signature);
- let mut encoded_invoice = bytes;
+ let mut encoded_invoice = Vec::new();
+ tlv_stream.write(&mut encoded_invoice).unwrap();
signature_tlv_stream.write(&mut encoded_invoice).unwrap();
+ experimental_offer_tlv_stream.write(&mut encoded_invoice).unwrap();
let invoice = Bolt12Invoice::try_from(encoded_invoice).unwrap();
assert!(
.chain(Network::Bitcoin).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), mainnet);
assert_eq!(tlv_stream.chain, None);
.chain(Network::Testnet).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet));
.chain(Network::Bitcoin).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), mainnet);
assert_eq!(tlv_stream.chain, None);
.chain(Network::Testnet).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet));
.amount_msats(1000).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1000));
assert_eq!(tlv_stream.amount, Some(1000));
.amount_msats(1000).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1000));
assert_eq!(tlv_stream.amount, Some(1000));
.amount_msats(1001).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(1001));
assert_eq!(tlv_stream.amount, Some(1001));
.features_unchecked(InvoiceRequestFeatures::unknown())
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::unknown());
assert_eq!(tlv_stream.features, Some(&InvoiceRequestFeatures::unknown()));
.features_unchecked(InvoiceRequestFeatures::empty())
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
assert_eq!(tlv_stream.features, None);
}
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.quantity(), None);
assert_eq!(tlv_stream.quantity, None);
.quantity(10).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(10_000));
assert_eq!(tlv_stream.amount, Some(10_000));
.quantity(2).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.amount_msats(), Some(2_000));
assert_eq!(tlv_stream.amount, Some(2_000));
.payer_note("bar".into())
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.payer_note(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("bar")));
.payer_note("baz".into())
.build().unwrap()
.sign(payer_sign).unwrap();
- let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
+ let (_, _, tlv_stream, _, _) = invoice_request.as_tlv_stream();
assert_eq!(invoice_request.payer_note(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
}
use crate::offers::nonce::Nonce;
use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::signer::{Metadata, MetadataMaterial, self};
-use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
+use crate::util::ser::{CursorReadable, HighZeroBytesDroppedBigSize, Readable, WithoutLength, Writeable, Writer};
use crate::util::string::PrintableString;
#[cfg(not(c_bindings))]
};
let mut tlv_stream = $self.offer.as_tlv_stream();
- debug_assert_eq!(tlv_stream.metadata, None);
- tlv_stream.metadata = None;
+ debug_assert_eq!(tlv_stream.0.metadata, None);
+ tlv_stream.0.metadata = None;
if metadata.derives_recipient_keys() {
- tlv_stream.issuer_id = None;
+ tlv_stream.0.issuer_id = None;
}
// Either replace the signing pubkey with the derived pubkey or include the metadata
bytes: &'a [u8]
) -> impl core::iter::Iterator<Item = TlvRecord<'a>> {
TlvStream::new(bytes).range(OFFER_TYPES)
+ .chain(TlvStream::new(bytes).range(EXPERIMENTAL_OFFER_TYPES))
}
#[cfg(async_payments)]
#[cfg(test)]
impl Offer {
- pub(super) fn as_tlv_stream(&self) -> OfferTlvStreamRef {
+ pub(super) fn as_tlv_stream(&self) -> FullOfferTlvStreamRef {
self.contents.as_tlv_stream()
}
}
}
}
- pub(super) fn as_tlv_stream(&self) -> OfferTlvStreamRef {
+ pub(super) fn as_tlv_stream(&self) -> FullOfferTlvStreamRef {
let (currency, amount) = match &self.amount {
None => (None, None),
Some(Amount::Bitcoin { amount_msats }) => (None, Some(*amount_msats)),
if self.features == OfferFeatures::empty() { None } else { Some(&self.features) }
};
- OfferTlvStreamRef {
+ let offer = OfferTlvStreamRef {
chains: self.chains.as_ref(),
metadata: self.metadata(),
currency,
issuer: self.issuer.as_ref(),
quantity_max: self.supported_quantity.to_tlv_record(),
issuer_id: self.issuer_signing_pubkey.as_ref(),
- }
+ };
+
+ let experimental_offer = ExperimentalOfferTlvStreamRef {};
+
+ (offer, experimental_offer)
}
}
/// Valid type range for experimental offer TLV records.
pub(super) const EXPERIMENTAL_OFFER_TYPES: core::ops::Range<u64> = 1_000_000_000..2_000_000_000;
+tlv_stream!(ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, EXPERIMENTAL_OFFER_TYPES, {
+});
+
+type FullOfferTlvStream = (OfferTlvStream, ExperimentalOfferTlvStream);
+
+type FullOfferTlvStreamRef<'a> = (OfferTlvStreamRef<'a>, ExperimentalOfferTlvStreamRef);
+
+impl CursorReadable for FullOfferTlvStream {
+ fn read<R: AsRef<[u8]>>(r: &mut io::Cursor<R>) -> Result<Self, DecodeError> {
+ let offer = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
+
+ Ok((offer, experimental_offer))
+ }
+}
+
impl Bech32Encode for Offer {
const BECH32_HRP: &'static str = "lno";
}
type Error = Bolt12ParseError;
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
- let offer = ParsedMessage::<OfferTlvStream>::try_from(bytes)?;
+ let offer = ParsedMessage::<FullOfferTlvStream>::try_from(bytes)?;
let ParsedMessage { bytes, tlv_stream } = offer;
let contents = OfferContents::try_from(tlv_stream)?;
let id = OfferId::from_valid_offer_tlv_stream(&bytes);
}
}
-impl TryFrom<OfferTlvStream> for OfferContents {
+impl TryFrom<FullOfferTlvStream> for OfferContents {
type Error = Bolt12SemanticError;
- fn try_from(tlv_stream: OfferTlvStream) -> Result<Self, Self::Error> {
- let OfferTlvStream {
- chains, metadata, currency, amount, description, features, absolute_expiry, paths,
- issuer, quantity_max, issuer_id,
- } = tlv_stream;
+ fn try_from(tlv_stream: FullOfferTlvStream) -> Result<Self, Self::Error> {
+ let (
+ OfferTlvStream {
+ chains, metadata, currency, amount, description, features, absolute_expiry, paths,
+ issuer, quantity_max, issuer_id,
+ },
+ ExperimentalOfferTlvStream {},
+ ) = tlv_stream;
let metadata = metadata.map(|metadata| Metadata::Bytes(metadata));
#[cfg(test)]
mod tests {
- use super::{Amount, OFFER_TYPES, Offer, OfferTlvStreamRef, Quantity};
+ use super::{Amount, ExperimentalOfferTlvStreamRef, OFFER_TYPES, Offer, OfferTlvStreamRef, Quantity};
#[cfg(not(c_bindings))]
use {
super::OfferBuilder,
assert_eq!(
offer.as_tlv_stream(),
- OfferTlvStreamRef {
- chains: None,
- metadata: None,
- currency: None,
- amount: None,
- description: None,
- features: None,
- absolute_expiry: None,
- paths: None,
- issuer: None,
- quantity_max: None,
- issuer_id: Some(&pubkey(42)),
- },
+ (
+ OfferTlvStreamRef {
+ chains: None,
+ metadata: None,
+ currency: None,
+ amount: None,
+ description: None,
+ features: None,
+ absolute_expiry: None,
+ paths: None,
+ issuer: None,
+ quantity_max: None,
+ issuer_id: Some(&pubkey(42)),
+ },
+ ExperimentalOfferTlvStreamRef {},
+ ),
);
if let Err(e) = Offer::try_from(buffer) {
.unwrap();
assert!(offer.supports_chain(mainnet));
assert_eq!(offer.chains(), vec![mainnet]);
- assert_eq!(offer.as_tlv_stream().chains, None);
+ assert_eq!(offer.as_tlv_stream().0.chains, None);
let offer = OfferBuilder::new(pubkey(42))
.chain(Network::Testnet)
.unwrap();
assert!(offer.supports_chain(testnet));
assert_eq!(offer.chains(), vec![testnet]);
- assert_eq!(offer.as_tlv_stream().chains, Some(&vec![testnet]));
+ assert_eq!(offer.as_tlv_stream().0.chains, Some(&vec![testnet]));
let offer = OfferBuilder::new(pubkey(42))
.chain(Network::Testnet)
.unwrap();
assert!(offer.supports_chain(testnet));
assert_eq!(offer.chains(), vec![testnet]);
- assert_eq!(offer.as_tlv_stream().chains, Some(&vec![testnet]));
+ assert_eq!(offer.as_tlv_stream().0.chains, Some(&vec![testnet]));
let offer = OfferBuilder::new(pubkey(42))
.chain(Network::Bitcoin)
assert!(offer.supports_chain(mainnet));
assert!(offer.supports_chain(testnet));
assert_eq!(offer.chains(), vec![mainnet, testnet]);
- assert_eq!(offer.as_tlv_stream().chains, Some(&vec![mainnet, testnet]));
+ assert_eq!(offer.as_tlv_stream().0.chains, Some(&vec![mainnet, testnet]));
}
#[test]
.build()
.unwrap();
assert_eq!(offer.metadata(), Some(&vec![42; 32]));
- assert_eq!(offer.as_tlv_stream().metadata, Some(&vec![42; 32]));
+ assert_eq!(offer.as_tlv_stream().0.metadata, Some(&vec![42; 32]));
let offer = OfferBuilder::new(pubkey(42))
.metadata(vec![42; 32]).unwrap()
.build()
.unwrap();
assert_eq!(offer.metadata(), Some(&vec![43; 32]));
- assert_eq!(offer.as_tlv_stream().metadata, Some(&vec![43; 32]));
+ assert_eq!(offer.as_tlv_stream().0.metadata, Some(&vec![43; 32]));
}
#[test]
// Fails verification with altered offer field
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.amount = Some(100);
+ tlv_stream.0.amount = Some(100);
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
// Fails verification with altered metadata
let mut tlv_stream = offer.as_tlv_stream();
- let metadata = tlv_stream.metadata.unwrap().iter().copied().rev().collect();
- tlv_stream.metadata = Some(&metadata);
+ let metadata = tlv_stream.0.metadata.unwrap().iter().copied().rev().collect();
+ tlv_stream.0.metadata = Some(&metadata);
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
// Fails verification with altered offer field
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.amount = Some(100);
+ tlv_stream.0.amount = Some(100);
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
// Fails verification with altered signing pubkey
let mut tlv_stream = offer.as_tlv_stream();
let issuer_id = pubkey(1);
- tlv_stream.issuer_id = Some(&issuer_id);
+ tlv_stream.0.issuer_id = Some(&issuer_id);
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
.unwrap();
let tlv_stream = offer.as_tlv_stream();
assert_eq!(offer.amount(), Some(bitcoin_amount));
- assert_eq!(tlv_stream.amount, Some(1000));
- assert_eq!(tlv_stream.currency, None);
+ assert_eq!(tlv_stream.0.amount, Some(1000));
+ assert_eq!(tlv_stream.0.currency, None);
#[cfg(not(c_bindings))]
let builder = OfferBuilder::new(pubkey(42))
builder.amount(currency_amount.clone());
let tlv_stream = builder.offer.as_tlv_stream();
assert_eq!(builder.offer.amount, Some(currency_amount.clone()));
- assert_eq!(tlv_stream.amount, Some(10));
- assert_eq!(tlv_stream.currency, Some(b"USD"));
+ assert_eq!(tlv_stream.0.amount, Some(10));
+ assert_eq!(tlv_stream.0.currency, Some(b"USD"));
match builder.build() {
Ok(_) => panic!("expected error"),
Err(e) => assert_eq!(e, Bolt12SemanticError::UnsupportedCurrency),
.build()
.unwrap();
let tlv_stream = offer.as_tlv_stream();
- assert_eq!(tlv_stream.amount, Some(1000));
- assert_eq!(tlv_stream.currency, None);
+ assert_eq!(tlv_stream.0.amount, Some(1000));
+ assert_eq!(tlv_stream.0.currency, None);
let invalid_amount = Amount::Bitcoin { amount_msats: MAX_VALUE_MSAT + 1 };
match OfferBuilder::new(pubkey(42)).amount(invalid_amount).build() {
.build()
.unwrap();
assert_eq!(offer.description(), Some(PrintableString("foo")));
- assert_eq!(offer.as_tlv_stream().description, Some(&String::from("foo")));
+ assert_eq!(offer.as_tlv_stream().0.description, Some(&String::from("foo")));
let offer = OfferBuilder::new(pubkey(42))
.description("foo".into())
.build()
.unwrap();
assert_eq!(offer.description(), Some(PrintableString("bar")));
- assert_eq!(offer.as_tlv_stream().description, Some(&String::from("bar")));
+ assert_eq!(offer.as_tlv_stream().0.description, Some(&String::from("bar")));
let offer = OfferBuilder::new(pubkey(42))
.amount_msats(1000)
.build()
.unwrap();
assert_eq!(offer.description(), Some(PrintableString("")));
- assert_eq!(offer.as_tlv_stream().description, Some(&String::from("")));
+ assert_eq!(offer.as_tlv_stream().0.description, Some(&String::from("")));
}
#[test]
.build()
.unwrap();
assert_eq!(offer.offer_features(), &OfferFeatures::unknown());
- assert_eq!(offer.as_tlv_stream().features, Some(&OfferFeatures::unknown()));
+ assert_eq!(offer.as_tlv_stream().0.features, Some(&OfferFeatures::unknown()));
let offer = OfferBuilder::new(pubkey(42))
.features_unchecked(OfferFeatures::unknown())
.build()
.unwrap();
assert_eq!(offer.offer_features(), &OfferFeatures::empty());
- assert_eq!(offer.as_tlv_stream().features, None);
+ assert_eq!(offer.as_tlv_stream().0.features, None);
}
#[test]
assert!(!offer.is_expired());
assert!(!offer.is_expired_no_std(now));
assert_eq!(offer.absolute_expiry(), Some(future_expiry));
- assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(future_expiry.as_secs()));
+ assert_eq!(offer.as_tlv_stream().0.absolute_expiry, Some(future_expiry.as_secs()));
let offer = OfferBuilder::new(pubkey(42))
.absolute_expiry(future_expiry)
assert!(offer.is_expired());
assert!(offer.is_expired_no_std(now));
assert_eq!(offer.absolute_expiry(), Some(past_expiry));
- assert_eq!(offer.as_tlv_stream().absolute_expiry, Some(past_expiry.as_secs()));
+ assert_eq!(offer.as_tlv_stream().0.absolute_expiry, Some(past_expiry.as_secs()));
}
#[test]
assert_eq!(offer.paths(), paths.as_slice());
assert_eq!(offer.issuer_signing_pubkey(), Some(pubkey(42)));
assert_ne!(pubkey(42), pubkey(44));
- assert_eq!(tlv_stream.paths, Some(&paths));
- assert_eq!(tlv_stream.issuer_id, Some(&pubkey(42)));
+ assert_eq!(tlv_stream.0.paths, Some(&paths));
+ assert_eq!(tlv_stream.0.issuer_id, Some(&pubkey(42)));
}
#[test]
.build()
.unwrap();
assert_eq!(offer.issuer(), Some(PrintableString("foo")));
- assert_eq!(offer.as_tlv_stream().issuer, Some(&String::from("foo")));
+ assert_eq!(offer.as_tlv_stream().0.issuer, Some(&String::from("foo")));
let offer = OfferBuilder::new(pubkey(42))
.issuer("foo".into())
.build()
.unwrap();
assert_eq!(offer.issuer(), Some(PrintableString("bar")));
- assert_eq!(offer.as_tlv_stream().issuer, Some(&String::from("bar")));
+ assert_eq!(offer.as_tlv_stream().0.issuer, Some(&String::from("bar")));
}
#[test]
let tlv_stream = offer.as_tlv_stream();
assert!(!offer.expects_quantity());
assert_eq!(offer.supported_quantity(), Quantity::One);
- assert_eq!(tlv_stream.quantity_max, None);
+ assert_eq!(tlv_stream.0.quantity_max, None);
let offer = OfferBuilder::new(pubkey(42))
.supported_quantity(Quantity::Unbounded)
let tlv_stream = offer.as_tlv_stream();
assert!(offer.expects_quantity());
assert_eq!(offer.supported_quantity(), Quantity::Unbounded);
- assert_eq!(tlv_stream.quantity_max, Some(0));
+ assert_eq!(tlv_stream.0.quantity_max, Some(0));
let offer = OfferBuilder::new(pubkey(42))
.supported_quantity(Quantity::Bounded(ten))
let tlv_stream = offer.as_tlv_stream();
assert!(offer.expects_quantity());
assert_eq!(offer.supported_quantity(), Quantity::Bounded(ten));
- assert_eq!(tlv_stream.quantity_max, Some(10));
+ assert_eq!(tlv_stream.0.quantity_max, Some(10));
let offer = OfferBuilder::new(pubkey(42))
.supported_quantity(Quantity::Bounded(one))
let tlv_stream = offer.as_tlv_stream();
assert!(offer.expects_quantity());
assert_eq!(offer.supported_quantity(), Quantity::Bounded(one));
- assert_eq!(tlv_stream.quantity_max, Some(1));
+ assert_eq!(tlv_stream.0.quantity_max, Some(1));
let offer = OfferBuilder::new(pubkey(42))
.supported_quantity(Quantity::Bounded(ten))
let tlv_stream = offer.as_tlv_stream();
assert!(!offer.expects_quantity());
assert_eq!(offer.supported_quantity(), Quantity::One);
- assert_eq!(tlv_stream.quantity_max, None);
+ assert_eq!(tlv_stream.0.quantity_max, None);
}
#[test]
}
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.amount = Some(1000);
- tlv_stream.currency = Some(b"USD");
+ tlv_stream.0.amount = Some(1000);
+ tlv_stream.0.currency = Some(b"USD");
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
}
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.amount = None;
- tlv_stream.currency = Some(b"USD");
+ tlv_stream.0.amount = None;
+ tlv_stream.0.currency = Some(b"USD");
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
}
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.amount = Some(MAX_VALUE_MSAT + 1);
- tlv_stream.currency = None;
+ tlv_stream.0.amount = Some(MAX_VALUE_MSAT + 1);
+ tlv_stream.0.currency = None;
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
}
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.description = None;
+ tlv_stream.0.description = None;
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
}
let mut tlv_stream = offer.as_tlv_stream();
- tlv_stream.issuer_id = None;
+ tlv_stream.0.issuer_id = None;
let mut encoded_offer = Vec::new();
tlv_stream.write(&mut encoded_offer).unwrap();
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
use crate::offers::invoice_request::{InvoiceRequestTlvStream, InvoiceRequestTlvStreamRef};
use crate::offers::nonce::Nonce;
-use crate::offers::offer::{OfferTlvStream, OfferTlvStreamRef};
+use crate::offers::offer::{ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, OfferTlvStream, OfferTlvStreamRef};
use crate::offers::parse::{Bech32Encode, Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::offers::payer::{PayerContents, PayerTlvStream, PayerTlvStreamRef};
use crate::offers::signer::{Metadata, MetadataMaterial, self};
paths: self.paths.as_ref(),
};
- (payer, offer, invoice_request)
+ let experimental_offer = ExperimentalOfferTlvStreamRef {};
+
+ (payer, offer, invoice_request, experimental_offer)
}
}
}
}
-type RefundTlvStream = (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream);
+type RefundTlvStream = (
+ PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, ExperimentalOfferTlvStream,
+);
type RefundTlvStreamRef<'a> = (
PayerTlvStreamRef<'a>,
OfferTlvStreamRef<'a>,
InvoiceRequestTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
);
impl CursorReadable for RefundTlvStream {
let payer = CursorReadable::read(r)?;
let offer = CursorReadable::read(r)?;
let invoice_request = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
- Ok((payer, offer, invoice_request))
+ Ok((payer, offer, invoice_request, experimental_offer))
}
}
InvoiceRequestTlvStream {
chain, amount, features, quantity, payer_id, payer_note, paths
},
+ _experimental_offer_tlv_stream,
) = tlv_stream;
let payer = match payer_metadata {
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
use crate::offers::invoice_request::{INVOICE_REQUEST_TYPES, InvoiceRequestTlvStreamRef};
use crate::offers::nonce::Nonce;
- use crate::offers::offer::OfferTlvStreamRef;
+ use crate::offers::offer::{ExperimentalOfferTlvStreamRef, OfferTlvStreamRef};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
use crate::offers::payer::PayerTlvStreamRef;
use crate::offers::test_utils::*;
payer_note: None,
paths: None,
},
+ ExperimentalOfferTlvStreamRef {},
),
);
.absolute_expiry(future_expiry)
.build()
.unwrap();
- let (_, tlv_stream, _) = refund.as_tlv_stream();
+ let (_, tlv_stream, _, _) = refund.as_tlv_stream();
#[cfg(feature = "std")]
assert!(!refund.is_expired());
assert!(!refund.is_expired_no_std(now));
.absolute_expiry(past_expiry)
.build()
.unwrap();
- let (_, tlv_stream, _) = refund.as_tlv_stream();
+ let (_, tlv_stream, _, _) = refund.as_tlv_stream();
#[cfg(feature = "std")]
assert!(refund.is_expired());
assert!(refund.is_expired_no_std(now));
.path(paths[1].clone())
.build()
.unwrap();
- let (_, _, invoice_request_tlv_stream) = refund.as_tlv_stream();
+ let (_, _, invoice_request_tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_signing_pubkey(), pubkey(42));
assert_eq!(refund.paths(), paths.as_slice());
assert_ne!(pubkey(42), pubkey(44));
.issuer("bar".into())
.build()
.unwrap();
- let (_, tlv_stream, _) = refund.as_tlv_stream();
+ let (_, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.issuer(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.issuer, Some(&String::from("bar")));
.issuer("baz".into())
.build()
.unwrap();
- let (_, tlv_stream, _) = refund.as_tlv_stream();
+ let (_, tlv_stream, _, _) = refund.as_tlv_stream();
assert_eq!(refund.issuer(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.issuer, Some(&String::from("baz")));
}
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.chain(Network::Bitcoin)
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), mainnet);
assert_eq!(tlv_stream.chain, None);
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.chain(Network::Testnet)
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet));
.chain(Network::Regtest)
.chain(Network::Testnet)
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.chain(), testnet);
assert_eq!(tlv_stream.chain, Some(&testnet));
}
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.quantity(10)
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.quantity(), Some(10));
assert_eq!(tlv_stream.quantity, Some(10));
.quantity(10)
.quantity(1)
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.quantity(), Some(1));
assert_eq!(tlv_stream.quantity, Some(1));
}
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
.payer_note("bar".into())
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_note(), Some(PrintableString("bar")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("bar")));
.payer_note("bar".into())
.payer_note("baz".into())
.build().unwrap();
- let (_, _, tlv_stream) = refund.as_tlv_stream();
+ let (_, _, tlv_stream, _) = refund.as_tlv_stream();
assert_eq!(refund.payer_note(), Some(PrintableString("baz")));
assert_eq!(tlv_stream.payer_note, Some(&String::from("baz")));
}
};
use crate::offers::nonce::Nonce;
use crate::offers::offer::{
- Amount, Offer, OfferContents, OfferTlvStream, OfferTlvStreamRef, Quantity,
- EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES,
+ Amount, ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, Offer, OfferContents,
+ OfferTlvStream, OfferTlvStreamRef, Quantity, EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES,
};
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError, ParsedMessage};
use crate::util::ser::{CursorReadable, Iterable, WithoutLength, Writeable, Writer};
impl UnsignedStaticInvoice {
fn new(offer_bytes: &Vec<u8>, contents: InvoiceContents) -> Self {
- let (_, invoice_tlv_stream) = contents.as_tlv_stream();
+ let (_, invoice_tlv_stream, _) = contents.as_tlv_stream();
// Allocate enough space for the invoice, which will include:
// - all TLV records from `offer_bytes`,
payment_hash: None,
};
- (self.offer.as_tlv_stream(), invoice)
+ let (offer, experimental_offer) = self.offer.as_tlv_stream();
+
+ (offer, invoice, experimental_offer)
}
fn chain(&self) -> ChainHash {
}
}
-type FullInvoiceTlvStream = (OfferTlvStream, InvoiceTlvStream, SignatureTlvStream);
+type FullInvoiceTlvStream =
+ (OfferTlvStream, InvoiceTlvStream, SignatureTlvStream, ExperimentalOfferTlvStream);
impl CursorReadable for FullInvoiceTlvStream {
fn read<R: AsRef<[u8]>>(r: &mut io::Cursor<R>) -> Result<Self, DecodeError> {
let offer = CursorReadable::read(r)?;
let invoice = CursorReadable::read(r)?;
let signature = CursorReadable::read(r)?;
+ let experimental_offer = CursorReadable::read(r)?;
- Ok((offer, invoice, signature))
+ Ok((offer, invoice, signature, experimental_offer))
}
}
-type PartialInvoiceTlvStream = (OfferTlvStream, InvoiceTlvStream);
+type PartialInvoiceTlvStream = (OfferTlvStream, InvoiceTlvStream, ExperimentalOfferTlvStream);
-type PartialInvoiceTlvStreamRef<'a> = (OfferTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>);
+type PartialInvoiceTlvStreamRef<'a> =
+ (OfferTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>, ExperimentalOfferTlvStreamRef);
impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for StaticInvoice {
type Error = Bolt12ParseError;
fn try_from(invoice: ParsedMessage<FullInvoiceTlvStream>) -> Result<Self, Self::Error> {
let ParsedMessage { bytes, tlv_stream } = invoice;
- let (offer_tlv_stream, invoice_tlv_stream, SignatureTlvStream { signature }) = tlv_stream;
- let contents = InvoiceContents::try_from((offer_tlv_stream, invoice_tlv_stream))?;
+ let (
+ offer_tlv_stream,
+ invoice_tlv_stream,
+ SignatureTlvStream { signature },
+ experimental_offer_tlv_stream,
+ ) = tlv_stream;
+ let contents = InvoiceContents::try_from((
+ offer_tlv_stream,
+ invoice_tlv_stream,
+ experimental_offer_tlv_stream,
+ ))?;
let signature = match signature {
None => {
payment_hash,
amount,
},
+ experimental_offer_tlv_stream,
) = tlv_stream;
if payment_hash.is_some() {
}
Ok(InvoiceContents {
- offer: OfferContents::try_from(offer_tlv_stream)?,
+ offer: OfferContents::try_from((offer_tlv_stream, experimental_offer_tlv_stream))?,
payment_paths,
message_paths,
created_at,
use crate::offers::merkle;
use crate::offers::merkle::{SignatureTlvStreamRef, TaggedHash};
use crate::offers::nonce::Nonce;
- use crate::offers::offer::{Offer, OfferBuilder, OfferTlvStreamRef, Quantity};
+ use crate::offers::offer::{
+ ExperimentalOfferTlvStreamRef, Offer, OfferBuilder, OfferTlvStreamRef, Quantity,
+ };
use crate::offers::parse::{Bolt12ParseError, Bolt12SemanticError};
use crate::offers::static_invoice::{
StaticInvoice, StaticInvoiceBuilder, UnsignedStaticInvoice, DEFAULT_RELATIVE_EXPIRY,
use bitcoin::Network;
use core::time::Duration;
- type FullInvoiceTlvStreamRef<'a> =
- (OfferTlvStreamRef<'a>, InvoiceTlvStreamRef<'a>, SignatureTlvStreamRef<'a>);
+ type FullInvoiceTlvStreamRef<'a> = (
+ OfferTlvStreamRef<'a>,
+ InvoiceTlvStreamRef<'a>,
+ SignatureTlvStreamRef<'a>,
+ ExperimentalOfferTlvStreamRef,
+ );
impl StaticInvoice {
fn as_tlv_stream(&self) -> FullInvoiceTlvStreamRef {
- let (offer_tlv_stream, invoice_tlv_stream) = self.contents.as_tlv_stream();
+ let (offer_tlv_stream, invoice_tlv_stream, experimental_offer_tlv_stream) =
+ self.contents.as_tlv_stream();
(
offer_tlv_stream,
invoice_tlv_stream,
SignatureTlvStreamRef { signature: Some(&self.signature) },
+ experimental_offer_tlv_stream,
)
}
}
fn tlv_stream_to_bytes(
- tlv_stream: &(OfferTlvStreamRef, InvoiceTlvStreamRef, SignatureTlvStreamRef),
+ tlv_stream: &(
+ OfferTlvStreamRef,
+ InvoiceTlvStreamRef,
+ SignatureTlvStreamRef,
+ ExperimentalOfferTlvStreamRef,
+ ),
) -> Vec<u8> {
let mut buffer = Vec::new();
tlv_stream.0.write(&mut buffer).unwrap();
tlv_stream.1.write(&mut buffer).unwrap();
tlv_stream.2.write(&mut buffer).unwrap();
+ tlv_stream.3.write(&mut buffer).unwrap();
buffer
}
message_paths: Some(&paths),
},
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
+ ExperimentalOfferTlvStreamRef {},
)
);
// Error if offer paths are missing.
let mut offer_without_paths = valid_offer.clone();
- let mut offer_tlv_stream = offer_without_paths.as_tlv_stream();
+ let (mut offer_tlv_stream, _) = offer_without_paths.as_tlv_stream();
offer_tlv_stream.paths.take();
let mut buffer = Vec::new();
offer_tlv_stream.write(&mut buffer).unwrap();
.unwrap();
let mut offer_missing_issuer_id = valid_offer.clone();
- let mut offer_tlv_stream = offer_missing_issuer_id.as_tlv_stream();
+ let (mut offer_tlv_stream, _) = offer_missing_issuer_id.as_tlv_stream();
offer_tlv_stream.issuer_id.take();
let mut buffer = Vec::new();
offer_tlv_stream.write(&mut buffer).unwrap();
}
}
+impl<A: Readable, B: Readable, C: Readable, D: Readable, E: Readable> Readable for (A, B, C, D, E) {
+ fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+ let a: A = Readable::read(r)?;
+ let b: B = Readable::read(r)?;
+ let c: C = Readable::read(r)?;
+ let d: D = Readable::read(r)?;
+ let e: E = Readable::read(r)?;
+ Ok((a, b, c, d, e))
+ }
+}
+impl<A: Writeable, B: Writeable, C: Writeable, D: Writeable, E: Writeable> Writeable for (A, B, C, D, E) {
+ fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+ self.0.write(w)?;
+ self.1.write(w)?;
+ self.2.write(w)?;
+ self.3.write(w)?;
+ self.4.write(w)
+ }
+}
+
impl Writeable for () {
fn write<W: Writer>(&self, _: &mut W) -> Result<(), io::Error> {
Ok(())