1 // This file is Copyright its original authors, visible in version control
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
10 //! Data structures and encoding for `invoice` messages.
12 use bitcoin::blockdata::constants::ChainHash;
13 use bitcoin::network::constants::Network;
14 use bitcoin::secp256k1::PublicKey;
15 use bitcoin::secp256k1::schnorr::Signature;
16 use bitcoin::util::address::{Address, Payload, WitnessVersion};
17 use core::convert::TryFrom;
18 use core::time::Duration;
20 use crate::ln::PaymentHash;
21 use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures};
22 use crate::ln::msgs::DecodeError;
23 use crate::offers::invoice_request::{InvoiceRequestContents, InvoiceRequestTlvStream};
24 use crate::offers::merkle::{SignatureTlvStream, self};
25 use crate::offers::offer::OfferTlvStream;
26 use crate::offers::parse::{ParseError, ParsedMessage, SemanticError};
27 use crate::offers::payer::PayerTlvStream;
28 use crate::offers::refund::RefundContents;
29 use crate::onion_message::BlindedPath;
30 use crate::util::ser::{HighZeroBytesDroppedBigSize, SeekReadable, WithoutLength, Writeable, Writer};
32 use crate::prelude::*;
34 #[cfg(feature = "std")]
35 use std::time::SystemTime;
37 const DEFAULT_RELATIVE_EXPIRY: Duration = Duration::from_secs(7200);
39 const SIGNATURE_TAG: &'static str = concat!("lightning", "invoice", "signature");
41 /// An `Invoice` is a payment request, typically corresponding to an [`Offer`] or a [`Refund`].
43 /// An invoice may be sent in response to an [`InvoiceRequest`] in the case of an offer or sent
44 /// directly after scanning a refund. It includes all the information needed to pay a recipient.
46 /// [`Offer`]: crate::offers::offer::Offer
47 /// [`Refund`]: crate::offers::refund::Refund
48 /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
51 contents: InvoiceContents,
55 /// The contents of an [`Invoice`] for responding to either an [`Offer`] or a [`Refund`].
57 /// [`Offer`]: crate::offers::offer::Offer
58 /// [`Refund`]: crate::offers::refund::Refund
59 enum InvoiceContents {
60 /// Contents for an [`Invoice`] corresponding to an [`Offer`].
62 /// [`Offer`]: crate::offers::offer::Offer
64 invoice_request: InvoiceRequestContents,
65 fields: InvoiceFields,
67 /// Contents for an [`Invoice`] corresponding to a [`Refund`].
69 /// [`Refund`]: crate::offers::refund::Refund
71 refund: RefundContents,
72 fields: InvoiceFields,
76 /// Invoice-specific fields for an `invoice` message.
77 struct InvoiceFields {
78 payment_paths: Vec<(BlindedPath, BlindedPayInfo)>,
80 relative_expiry: Option<Duration>,
81 payment_hash: PaymentHash,
83 fallbacks: Option<Vec<FallbackAddress>>,
84 features: Bolt12InvoiceFeatures,
85 signing_pubkey: PublicKey,
89 /// Paths to the recipient originating from publicly reachable nodes, including information
90 /// needed for routing payments across them. Blinded paths provide recipient privacy by
91 /// obfuscating its node id.
92 pub fn payment_paths(&self) -> &[(BlindedPath, BlindedPayInfo)] {
93 &self.contents.fields().payment_paths[..]
96 /// Duration since the Unix epoch when the invoice was created.
97 pub fn created_at(&self) -> Duration {
98 self.contents.fields().created_at
101 /// Duration since [`Invoice::created_at`] when the invoice has expired and therefore should no
103 pub fn relative_expiry(&self) -> Duration {
104 self.contents.fields().relative_expiry.unwrap_or(DEFAULT_RELATIVE_EXPIRY)
107 /// Whether the invoice has expired.
108 #[cfg(feature = "std")]
109 pub fn is_expired(&self) -> bool {
110 let absolute_expiry = self.created_at().checked_add(self.relative_expiry());
111 match absolute_expiry {
112 Some(seconds_from_epoch) => match SystemTime::UNIX_EPOCH.elapsed() {
113 Ok(elapsed) => elapsed > seconds_from_epoch,
120 /// SHA256 hash of the payment preimage that will be given in return for paying the invoice.
121 pub fn payment_hash(&self) -> PaymentHash {
122 self.contents.fields().payment_hash
125 /// The minimum amount required for a successful payment of the invoice.
126 pub fn amount_msats(&self) -> u64 {
127 self.contents.fields().amount_msats
130 /// Fallback addresses for paying the invoice on-chain, in order of most-preferred to
132 pub fn fallbacks(&self) -> Vec<Address> {
133 let network = match self.network() {
134 None => return Vec::new(),
135 Some(network) => network,
138 let to_valid_address = |address: &FallbackAddress| {
139 let version = match WitnessVersion::try_from(address.version) {
140 Ok(version) => version,
141 Err(_) => return None,
144 let program = &address.program;
145 if program.len() < 2 || program.len() > 40 {
149 let address = Address {
150 payload: Payload::WitnessProgram {
152 program: address.program.clone(),
157 if !address.is_standard() && version == WitnessVersion::V0 {
164 self.contents.fields().fallbacks
166 .map(|fallbacks| fallbacks.iter().filter_map(to_valid_address).collect())
167 .unwrap_or_else(Vec::new)
170 fn network(&self) -> Option<Network> {
171 let chain = self.contents.chain();
172 if chain == ChainHash::using_genesis_block(Network::Bitcoin) {
173 Some(Network::Bitcoin)
174 } else if chain == ChainHash::using_genesis_block(Network::Testnet) {
175 Some(Network::Testnet)
176 } else if chain == ChainHash::using_genesis_block(Network::Signet) {
177 Some(Network::Signet)
178 } else if chain == ChainHash::using_genesis_block(Network::Regtest) {
179 Some(Network::Regtest)
185 /// Features pertaining to paying an invoice.
186 pub fn features(&self) -> &Bolt12InvoiceFeatures {
187 &self.contents.fields().features
190 /// The public key used to sign invoices.
191 pub fn signing_pubkey(&self) -> PublicKey {
192 self.contents.fields().signing_pubkey
195 /// Signature of the invoice using [`Invoice::signing_pubkey`].
196 pub fn signature(&self) -> Signature {
201 impl InvoiceContents {
202 fn chain(&self) -> ChainHash {
204 InvoiceContents::ForOffer { invoice_request, .. } => invoice_request.chain(),
205 InvoiceContents::ForRefund { refund, .. } => refund.chain(),
209 fn fields(&self) -> &InvoiceFields {
211 InvoiceContents::ForOffer { fields, .. } => fields,
212 InvoiceContents::ForRefund { fields, .. } => fields,
217 impl Writeable for Invoice {
218 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
219 WithoutLength(&self.bytes).write(writer)
223 impl TryFrom<Vec<u8>> for Invoice {
224 type Error = ParseError;
226 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
227 let parsed_invoice = ParsedMessage::<FullInvoiceTlvStream>::try_from(bytes)?;
228 Invoice::try_from(parsed_invoice)
232 tlv_stream!(InvoiceTlvStream, InvoiceTlvStreamRef, 160..240, {
233 (160, paths: (Vec<BlindedPath>, WithoutLength)),
234 (162, blindedpay: (Vec<BlindedPayInfo>, WithoutLength)),
235 (164, created_at: (u64, HighZeroBytesDroppedBigSize)),
236 (166, relative_expiry: (u32, HighZeroBytesDroppedBigSize)),
237 (168, payment_hash: PaymentHash),
238 (170, amount: (u64, HighZeroBytesDroppedBigSize)),
239 (172, fallbacks: (Vec<FallbackAddress>, WithoutLength)),
240 (174, features: (Bolt12InvoiceFeatures, WithoutLength)),
241 (176, node_id: PublicKey),
244 /// Information needed to route a payment across a [`BlindedPath`] hop.
245 #[derive(Debug, PartialEq)]
246 pub struct BlindedPayInfo {
248 fee_proportional_millionths: u32,
249 cltv_expiry_delta: u16,
250 htlc_minimum_msat: u64,
251 htlc_maximum_msat: u64,
252 features: BlindedHopFeatures,
255 impl_writeable!(BlindedPayInfo, {
257 fee_proportional_millionths,
264 /// Wire representation for an on-chain fallback address.
265 #[derive(Debug, PartialEq)]
266 pub(super) struct FallbackAddress {
271 impl_writeable!(FallbackAddress, { version, program });
273 type FullInvoiceTlvStream =
274 (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream, SignatureTlvStream);
276 impl SeekReadable for FullInvoiceTlvStream {
277 fn read<R: io::Read + io::Seek>(r: &mut R) -> Result<Self, DecodeError> {
278 let payer = SeekReadable::read(r)?;
279 let offer = SeekReadable::read(r)?;
280 let invoice_request = SeekReadable::read(r)?;
281 let invoice = SeekReadable::read(r)?;
282 let signature = SeekReadable::read(r)?;
284 Ok((payer, offer, invoice_request, invoice, signature))
288 type PartialInvoiceTlvStream =
289 (PayerTlvStream, OfferTlvStream, InvoiceRequestTlvStream, InvoiceTlvStream);
291 impl TryFrom<ParsedMessage<FullInvoiceTlvStream>> for Invoice {
292 type Error = ParseError;
294 fn try_from(invoice: ParsedMessage<FullInvoiceTlvStream>) -> Result<Self, Self::Error> {
295 let ParsedMessage { bytes, tlv_stream } = invoice;
297 payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream,
298 SignatureTlvStream { signature },
300 let contents = InvoiceContents::try_from(
301 (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream, invoice_tlv_stream)
304 let signature = match signature {
305 None => return Err(ParseError::InvalidSemantics(SemanticError::MissingSignature)),
306 Some(signature) => signature,
308 let pubkey = contents.fields().signing_pubkey;
309 merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, pubkey)?;
311 Ok(Invoice { bytes, contents, signature })
315 impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
316 type Error = SemanticError;
318 fn try_from(tlv_stream: PartialInvoiceTlvStream) -> Result<Self, Self::Error> {
322 invoice_request_tlv_stream,
324 paths, blindedpay, created_at, relative_expiry, payment_hash, amount, fallbacks,
329 let payment_paths = match (paths, blindedpay) {
330 (None, _) => return Err(SemanticError::MissingPaths),
331 (_, None) => return Err(SemanticError::InvalidPayInfo),
332 (Some(paths), _) if paths.is_empty() => return Err(SemanticError::MissingPaths),
333 (Some(paths), Some(blindedpay)) if paths.len() != blindedpay.len() => {
334 return Err(SemanticError::InvalidPayInfo);
336 (Some(paths), Some(blindedpay)) => {
337 paths.into_iter().zip(blindedpay.into_iter()).collect::<Vec<_>>()
341 let created_at = match created_at {
342 None => return Err(SemanticError::MissingCreationTime),
343 Some(timestamp) => Duration::from_secs(timestamp),
346 let relative_expiry = relative_expiry
347 .map(Into::<u64>::into)
348 .map(Duration::from_secs);
350 let payment_hash = match payment_hash {
351 None => return Err(SemanticError::MissingPaymentHash),
352 Some(payment_hash) => payment_hash,
355 let amount_msats = match amount {
356 None => return Err(SemanticError::MissingAmount),
357 Some(amount) => amount,
360 let features = features.unwrap_or_else(Bolt12InvoiceFeatures::empty);
362 let signing_pubkey = match node_id {
363 None => return Err(SemanticError::MissingSigningPubkey),
364 Some(node_id) => node_id,
367 let fields = InvoiceFields {
368 payment_paths, created_at, relative_expiry, payment_hash, amount_msats, fallbacks,
369 features, signing_pubkey,
372 match offer_tlv_stream.node_id {
373 Some(expected_signing_pubkey) => {
374 if fields.signing_pubkey != expected_signing_pubkey {
375 return Err(SemanticError::InvalidSigningPubkey);
378 let invoice_request = InvoiceRequestContents::try_from(
379 (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
381 Ok(InvoiceContents::ForOffer { invoice_request, fields })
384 let refund = RefundContents::try_from(
385 (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
387 Ok(InvoiceContents::ForRefund { refund, fields })