ldk_node/payment/
store.rs

1// This file is Copyright its original authors, visible in version control history.
2//
3// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
6// accordance with one or both of these licenses.
7
8use std::time::{Duration, SystemTime, UNIX_EPOCH};
9
10use bitcoin::{BlockHash, Txid};
11use lightning::ln::channelmanager::PaymentId;
12use lightning::ln::msgs::DecodeError;
13use lightning::offers::offer::OfferId;
14use lightning::util::ser::{Readable, Writeable};
15use lightning::{
16	_init_and_read_len_prefixed_tlv_fields, impl_writeable_tlv_based,
17	impl_writeable_tlv_based_enum, write_tlv_fields,
18};
19use lightning_types::payment::{PaymentHash, PaymentPreimage, PaymentSecret};
20use lightning_types::string::UntrustedString;
21
22use crate::data_store::{StorableObject, StorableObjectId, StorableObjectUpdate};
23use crate::hex_utils;
24
25/// Represents a payment.
26#[derive(Clone, Debug, PartialEq, Eq)]
27pub struct PaymentDetails {
28	/// The identifier of this payment.
29	pub id: PaymentId,
30	/// The kind of the payment.
31	pub kind: PaymentKind,
32	/// The amount transferred.
33	///
34	/// Will be `None` for variable-amount payments until we receive them.
35	pub amount_msat: Option<u64>,
36	/// The fees that were paid for this payment.
37	///
38	/// For Lightning payments, this will only be updated for outbound payments once they
39	/// succeeded.
40	///
41	/// Will be `None` for Lightning payments made with LDK Node v0.4.x and earlier.
42	pub fee_paid_msat: Option<u64>,
43	/// The direction of the payment.
44	pub direction: PaymentDirection,
45	/// The status of the payment.
46	pub status: PaymentStatus,
47	/// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated.
48	pub latest_update_timestamp: u64,
49}
50
51impl PaymentDetails {
52	pub(crate) fn new(
53		id: PaymentId, kind: PaymentKind, amount_msat: Option<u64>, fee_paid_msat: Option<u64>,
54		direction: PaymentDirection, status: PaymentStatus,
55	) -> Self {
56		let latest_update_timestamp = SystemTime::now()
57			.duration_since(UNIX_EPOCH)
58			.unwrap_or(Duration::from_secs(0))
59			.as_secs();
60		Self { id, kind, amount_msat, fee_paid_msat, direction, status, latest_update_timestamp }
61	}
62}
63
64impl Writeable for PaymentDetails {
65	fn write<W: lightning::util::ser::Writer>(
66		&self, writer: &mut W,
67	) -> Result<(), lightning::io::Error> {
68		write_tlv_fields!(writer, {
69			(0, self.id, required), // Used to be `hash` for v0.2.1 and prior
70			// 1 briefly used to be lsp_fee_limits, could probably be reused at some point in the future.
71			// 2 used to be `preimage` before it was moved to `kind` in v0.3.0
72			(2, None::<Option<PaymentPreimage>>, required),
73			(3, self.kind, required),
74			// 4 used to be `secret` before it was moved to `kind` in v0.3.0
75			(4, None::<Option<PaymentSecret>>, required),
76			(5, self.latest_update_timestamp, required),
77			(6, self.amount_msat, required),
78			(7, self.fee_paid_msat, option),
79			(8, self.direction, required),
80			(10, self.status, required)
81		});
82		Ok(())
83	}
84}
85
86impl Readable for PaymentDetails {
87	fn read<R: lightning::io::Read>(reader: &mut R) -> Result<PaymentDetails, DecodeError> {
88		let unix_time_secs = SystemTime::now()
89			.duration_since(UNIX_EPOCH)
90			.unwrap_or(Duration::from_secs(0))
91			.as_secs();
92		_init_and_read_len_prefixed_tlv_fields!(reader, {
93			(0, id, required), // Used to be `hash`
94			(1, lsp_fee_limits, option),
95			(2, preimage, required),
96			(3, kind_opt, option),
97			(4, secret, required),
98			(5, latest_update_timestamp, (default_value, unix_time_secs)),
99			(6, amount_msat, required),
100			(7, fee_paid_msat, option),
101			(8, direction, required),
102			(10, status, required)
103		});
104
105		let id: PaymentId = id.0.ok_or(DecodeError::InvalidValue)?;
106		let preimage: Option<PaymentPreimage> = preimage.0.ok_or(DecodeError::InvalidValue)?;
107		let secret: Option<PaymentSecret> = secret.0.ok_or(DecodeError::InvalidValue)?;
108		let latest_update_timestamp: u64 =
109			latest_update_timestamp.0.ok_or(DecodeError::InvalidValue)?;
110		let amount_msat: Option<u64> = amount_msat.0.ok_or(DecodeError::InvalidValue)?;
111		let direction: PaymentDirection = direction.0.ok_or(DecodeError::InvalidValue)?;
112		let status: PaymentStatus = status.0.ok_or(DecodeError::InvalidValue)?;
113
114		let kind = if let Some(kind) = kind_opt {
115			// If we serialized the payment kind, use it.
116			// This will always be the case for any version after v0.2.1.
117			kind
118		} else {
119			// Otherwise we persisted with v0.2.1 or before, and puzzle together the kind from the
120			// provided fields.
121
122			// We used to track everything by hash, but switched to track everything by id
123			// post-v0.2.1. As both are serialized identically, we just switched the `0`-type field above
124			// from `PaymentHash` to `PaymentId` and serialize a separate `PaymentHash` in
125			// `PaymentKind` when needed. Here, for backwards compat, we can just re-create the
126			// `PaymentHash` from the id, as 'back then' `payment_hash == payment_id` was always
127			// true.
128			let hash = PaymentHash(id.0);
129
130			if secret.is_some() {
131				if let Some(lsp_fee_limits) = lsp_fee_limits {
132					let counterparty_skimmed_fee_msat = None;
133					PaymentKind::Bolt11Jit {
134						hash,
135						preimage,
136						secret,
137						counterparty_skimmed_fee_msat,
138						lsp_fee_limits,
139					}
140				} else {
141					PaymentKind::Bolt11 { hash, preimage, secret }
142				}
143			} else {
144				PaymentKind::Spontaneous { hash, preimage }
145			}
146		};
147
148		Ok(PaymentDetails {
149			id,
150			kind,
151			amount_msat,
152			fee_paid_msat,
153			direction,
154			status,
155			latest_update_timestamp,
156		})
157	}
158}
159
160impl StorableObjectId for PaymentId {
161	fn encode_to_hex_str(&self) -> String {
162		hex_utils::to_string(&self.0)
163	}
164}
165impl StorableObject for PaymentDetails {
166	type Id = PaymentId;
167	type Update = PaymentDetailsUpdate;
168
169	fn id(&self) -> Self::Id {
170		self.id
171	}
172
173	fn update(&mut self, update: &Self::Update) -> bool {
174		debug_assert_eq!(
175			self.id, update.id,
176			"We should only ever override payment data for the same payment id"
177		);
178
179		let mut updated = false;
180
181		macro_rules! update_if_necessary {
182			($val:expr, $update:expr) => {
183				if $val != $update {
184					$val = $update;
185					updated = true;
186				}
187			};
188		}
189
190		if let Some(hash_opt) = update.hash {
191			match self.kind {
192				PaymentKind::Bolt12Offer { ref mut hash, .. } => {
193					debug_assert_eq!(
194						self.direction,
195						PaymentDirection::Outbound,
196						"We should only ever override payment hash for outbound BOLT 12 payments"
197					);
198					debug_assert!(
199						hash.is_none() || *hash == hash_opt,
200						"We should never change a payment hash after being initially set"
201					);
202					update_if_necessary!(*hash, hash_opt);
203				},
204				PaymentKind::Bolt12Refund { ref mut hash, .. } => {
205					debug_assert_eq!(
206						self.direction,
207						PaymentDirection::Outbound,
208						"We should only ever override payment hash for outbound BOLT 12 payments"
209					);
210					debug_assert!(
211						hash.is_none() || *hash == hash_opt,
212						"We should never change a payment hash after being initially set"
213					);
214					update_if_necessary!(*hash, hash_opt);
215				},
216				_ => {
217					// We can omit updating the hash for BOLT11 payments as the payment hash
218					// will always be known from the beginning.
219				},
220			}
221		}
222		if let Some(preimage_opt) = update.preimage {
223			match self.kind {
224				PaymentKind::Bolt11 { ref mut preimage, .. } => {
225					update_if_necessary!(*preimage, preimage_opt)
226				},
227				PaymentKind::Bolt11Jit { ref mut preimage, .. } => {
228					update_if_necessary!(*preimage, preimage_opt)
229				},
230				PaymentKind::Bolt12Offer { ref mut preimage, .. } => {
231					update_if_necessary!(*preimage, preimage_opt)
232				},
233				PaymentKind::Bolt12Refund { ref mut preimage, .. } => {
234					update_if_necessary!(*preimage, preimage_opt)
235				},
236				PaymentKind::Spontaneous { ref mut preimage, .. } => {
237					update_if_necessary!(*preimage, preimage_opt)
238				},
239				_ => {},
240			}
241		}
242
243		if let Some(secret_opt) = update.secret {
244			match self.kind {
245				PaymentKind::Bolt11 { ref mut secret, .. } => {
246					update_if_necessary!(*secret, secret_opt)
247				},
248				PaymentKind::Bolt11Jit { ref mut secret, .. } => {
249					update_if_necessary!(*secret, secret_opt)
250				},
251				PaymentKind::Bolt12Offer { ref mut secret, .. } => {
252					update_if_necessary!(*secret, secret_opt)
253				},
254				PaymentKind::Bolt12Refund { ref mut secret, .. } => {
255					update_if_necessary!(*secret, secret_opt)
256				},
257				_ => {},
258			}
259		}
260
261		if let Some(amount_opt) = update.amount_msat {
262			update_if_necessary!(self.amount_msat, amount_opt);
263		}
264
265		if let Some(fee_paid_msat_opt) = update.fee_paid_msat {
266			update_if_necessary!(self.fee_paid_msat, fee_paid_msat_opt);
267		}
268
269		if let Some(skimmed_fee_msat) = update.counterparty_skimmed_fee_msat {
270			match self.kind {
271				PaymentKind::Bolt11Jit { ref mut counterparty_skimmed_fee_msat, .. } => {
272					update_if_necessary!(*counterparty_skimmed_fee_msat, skimmed_fee_msat);
273				},
274				_ => debug_assert!(
275					false,
276					"We should only ever override counterparty_skimmed_fee_msat for JIT payments"
277				),
278			}
279		}
280
281		if let Some(status) = update.status {
282			update_if_necessary!(self.status, status);
283		}
284
285		if let Some(confirmation_status) = update.confirmation_status {
286			match self.kind {
287				PaymentKind::Onchain { ref mut status, .. } => {
288					update_if_necessary!(*status, confirmation_status);
289				},
290				_ => {},
291			}
292		}
293
294		if updated {
295			self.latest_update_timestamp = SystemTime::now()
296				.duration_since(UNIX_EPOCH)
297				.unwrap_or(Duration::from_secs(0))
298				.as_secs();
299		}
300
301		updated
302	}
303
304	fn to_update(&self) -> Self::Update {
305		self.into()
306	}
307}
308
309/// Represents the direction of a payment.
310#[derive(Copy, Clone, Debug, PartialEq, Eq)]
311pub enum PaymentDirection {
312	/// The payment is inbound.
313	Inbound,
314	/// The payment is outbound.
315	Outbound,
316}
317
318impl_writeable_tlv_based_enum!(PaymentDirection,
319	(0, Inbound) => {},
320	(1, Outbound) => {}
321);
322
323/// Represents the current status of a payment.
324#[derive(Copy, Clone, Debug, PartialEq, Eq)]
325pub enum PaymentStatus {
326	/// The payment is still pending.
327	Pending,
328	/// The payment succeeded.
329	Succeeded,
330	/// The payment failed.
331	Failed,
332}
333
334impl_writeable_tlv_based_enum!(PaymentStatus,
335	(0, Pending) => {},
336	(2, Succeeded) => {},
337	(4, Failed) => {}
338);
339
340/// Represents the kind of a payment.
341#[derive(Clone, Debug, PartialEq, Eq)]
342pub enum PaymentKind {
343	/// An on-chain payment.
344	///
345	/// Payments of this kind will be considered pending until the respective transaction has
346	/// reached [`ANTI_REORG_DELAY`] confirmations on-chain.
347	///
348	/// [`ANTI_REORG_DELAY`]: lightning::chain::channelmonitor::ANTI_REORG_DELAY
349	Onchain {
350		/// The transaction identifier of this payment.
351		txid: Txid,
352		/// The confirmation status of this payment.
353		status: ConfirmationStatus,
354	},
355	/// A [BOLT 11] payment.
356	///
357	/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
358	Bolt11 {
359		/// The payment hash, i.e., the hash of the `preimage`.
360		hash: PaymentHash,
361		/// The pre-image used by the payment.
362		preimage: Option<PaymentPreimage>,
363		/// The secret used by the payment.
364		secret: Option<PaymentSecret>,
365	},
366	/// A [BOLT 11] payment intended to open an [bLIP-52 / LSPS 2] just-in-time channel.
367	///
368	/// [BOLT 11]: https://github.com/lightning/bolts/blob/master/11-payment-encoding.md
369	/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
370	Bolt11Jit {
371		/// The payment hash, i.e., the hash of the `preimage`.
372		hash: PaymentHash,
373		/// The pre-image used by the payment.
374		preimage: Option<PaymentPreimage>,
375		/// The secret used by the payment.
376		secret: Option<PaymentSecret>,
377		/// The value, in thousands of a satoshi, that was deducted from this payment as an extra
378		/// fee taken by our channel counterparty.
379		///
380		/// Will only be `Some` once we received the payment. Will always be `None` for LDK Node
381		/// v0.4 and prior.
382		counterparty_skimmed_fee_msat: Option<u64>,
383		/// Limits applying to how much fee we allow an LSP to deduct from the payment amount.
384		///
385		/// Allowing them to deduct this fee from the first inbound payment will pay for the LSP's
386		/// channel opening fees.
387		///
388		/// See [`LdkChannelConfig::accept_underpaying_htlcs`] for more information.
389		///
390		/// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs
391		lsp_fee_limits: LSPFeeLimits,
392	},
393	/// A [BOLT 12] 'offer' payment, i.e., a payment for an [`Offer`].
394	///
395	/// [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
396	/// [`Offer`]: crate::lightning::offers::offer::Offer
397	Bolt12Offer {
398		/// The payment hash, i.e., the hash of the `preimage`.
399		hash: Option<PaymentHash>,
400		/// The pre-image used by the payment.
401		preimage: Option<PaymentPreimage>,
402		/// The secret used by the payment.
403		secret: Option<PaymentSecret>,
404		/// The ID of the offer this payment is for.
405		offer_id: OfferId,
406		/// The payer note for the payment.
407		///
408		/// Truncated to [`PAYER_NOTE_LIMIT`] characters.
409		///
410		/// This will always be `None` for payments serialized with version `v0.3.0`.
411		///
412		/// [`PAYER_NOTE_LIMIT`]: lightning::offers::invoice_request::PAYER_NOTE_LIMIT
413		payer_note: Option<UntrustedString>,
414		/// The quantity of an item requested in the offer.
415		///
416		/// This will always be `None` for payments serialized with version `v0.3.0`.
417		quantity: Option<u64>,
418	},
419	/// A [BOLT 12] 'refund' payment, i.e., a payment for a [`Refund`].
420	///
421	/// [BOLT 12]: https://github.com/lightning/bolts/blob/master/12-offer-encoding.md
422	/// [`Refund`]: lightning::offers::refund::Refund
423	Bolt12Refund {
424		/// The payment hash, i.e., the hash of the `preimage`.
425		hash: Option<PaymentHash>,
426		/// The pre-image used by the payment.
427		preimage: Option<PaymentPreimage>,
428		/// The secret used by the payment.
429		secret: Option<PaymentSecret>,
430		/// The payer note for the refund payment.
431		///
432		/// This will always be `None` for payments serialized with version `v0.3.0`.
433		payer_note: Option<UntrustedString>,
434		/// The quantity of an item that the refund is for.
435		///
436		/// This will always be `None` for payments serialized with version `v0.3.0`.
437		quantity: Option<u64>,
438	},
439	/// A spontaneous ("keysend") payment.
440	Spontaneous {
441		/// The payment hash, i.e., the hash of the `preimage`.
442		hash: PaymentHash,
443		/// The pre-image used by the payment.
444		preimage: Option<PaymentPreimage>,
445	},
446}
447
448impl_writeable_tlv_based_enum!(PaymentKind,
449	(0, Onchain) => {
450		(0, txid, required),
451		(2, status, required),
452	},
453	(2, Bolt11) => {
454		(0, hash, required),
455		(2, preimage, option),
456		(4, secret, option),
457	},
458	(4, Bolt11Jit) => {
459		(0, hash, required),
460		(1, counterparty_skimmed_fee_msat, option),
461		(2, preimage, option),
462		(4, secret, option),
463		(6, lsp_fee_limits, required),
464	},
465	(6, Bolt12Offer) => {
466		(0, hash, option),
467		(1, payer_note, option),
468		(2, preimage, option),
469		(3, quantity, option),
470		(4, secret, option),
471		(6, offer_id, required),
472	},
473	(8, Spontaneous) => {
474		(0, hash, required),
475		(2, preimage, option),
476	},
477	(10, Bolt12Refund) => {
478		(0, hash, option),
479		(1, payer_note, option),
480		(2, preimage, option),
481		(3, quantity, option),
482		(4, secret, option),
483	}
484);
485
486/// Represents the confirmation status of a transaction.
487#[derive(Copy, Clone, Debug, PartialEq, Eq)]
488pub enum ConfirmationStatus {
489	/// The transaction is confirmed in the best chain.
490	Confirmed {
491		/// The hash of the block in which the transaction was confirmed.
492		block_hash: BlockHash,
493		/// The height under which the block was confirmed.
494		height: u32,
495		/// The timestamp, in seconds since start of the UNIX epoch, when this entry was last updated.
496		timestamp: u64,
497	},
498	/// The transaction is unconfirmed.
499	Unconfirmed,
500}
501
502impl_writeable_tlv_based_enum!(ConfirmationStatus,
503	(0, Confirmed) => {
504		(0, block_hash, required),
505		(2, height, required),
506		(4, timestamp, required),
507	},
508	(2, Unconfirmed) => {},
509);
510
511/// Limits applying to how much fee we allow an LSP to deduct from the payment amount.
512///
513/// See [`LdkChannelConfig::accept_underpaying_htlcs`] for more information.
514///
515/// [`LdkChannelConfig::accept_underpaying_htlcs`]: lightning::util::config::ChannelConfig::accept_underpaying_htlcs
516#[derive(Copy, Clone, Debug, PartialEq, Eq)]
517pub struct LSPFeeLimits {
518	/// The maximal total amount we allow any configured LSP withhold from us when forwarding the
519	/// payment.
520	pub max_total_opening_fee_msat: Option<u64>,
521	/// The maximal proportional fee, in parts-per-million millisatoshi, we allow any configured
522	/// LSP withhold from us when forwarding the payment.
523	pub max_proportional_opening_fee_ppm_msat: Option<u64>,
524}
525
526impl_writeable_tlv_based!(LSPFeeLimits, {
527	(0, max_total_opening_fee_msat, option),
528	(2, max_proportional_opening_fee_ppm_msat, option),
529});
530
531#[derive(Clone, Debug, PartialEq, Eq)]
532pub(crate) struct PaymentDetailsUpdate {
533	pub id: PaymentId,
534	pub hash: Option<Option<PaymentHash>>,
535	pub preimage: Option<Option<PaymentPreimage>>,
536	pub secret: Option<Option<PaymentSecret>>,
537	pub amount_msat: Option<Option<u64>>,
538	pub fee_paid_msat: Option<Option<u64>>,
539	pub counterparty_skimmed_fee_msat: Option<Option<u64>>,
540	pub direction: Option<PaymentDirection>,
541	pub status: Option<PaymentStatus>,
542	pub confirmation_status: Option<ConfirmationStatus>,
543}
544
545impl PaymentDetailsUpdate {
546	pub fn new(id: PaymentId) -> Self {
547		Self {
548			id,
549			hash: None,
550			preimage: None,
551			secret: None,
552			amount_msat: None,
553			fee_paid_msat: None,
554			counterparty_skimmed_fee_msat: None,
555			direction: None,
556			status: None,
557			confirmation_status: None,
558		}
559	}
560}
561
562impl From<&PaymentDetails> for PaymentDetailsUpdate {
563	fn from(value: &PaymentDetails) -> Self {
564		let (hash, preimage, secret) = match value.kind {
565			PaymentKind::Bolt11 { hash, preimage, secret, .. } => (Some(hash), preimage, secret),
566			PaymentKind::Bolt11Jit { hash, preimage, secret, .. } => (Some(hash), preimage, secret),
567			PaymentKind::Bolt12Offer { hash, preimage, secret, .. } => (hash, preimage, secret),
568			PaymentKind::Bolt12Refund { hash, preimage, secret, .. } => (hash, preimage, secret),
569			PaymentKind::Spontaneous { hash, preimage, .. } => (Some(hash), preimage, None),
570			_ => (None, None, None),
571		};
572
573		let confirmation_status = match value.kind {
574			PaymentKind::Onchain { status, .. } => Some(status),
575			_ => None,
576		};
577
578		let counterparty_skimmed_fee_msat = match value.kind {
579			PaymentKind::Bolt11Jit { counterparty_skimmed_fee_msat, .. } => {
580				Some(counterparty_skimmed_fee_msat)
581			},
582			_ => None,
583		};
584
585		Self {
586			id: value.id,
587			hash: Some(hash),
588			preimage: Some(preimage),
589			secret: Some(secret),
590			amount_msat: Some(value.amount_msat),
591			fee_paid_msat: Some(value.fee_paid_msat),
592			counterparty_skimmed_fee_msat,
593			direction: Some(value.direction),
594			status: Some(value.status),
595			confirmation_status,
596		}
597	}
598}
599
600impl StorableObjectUpdate<PaymentDetails> for PaymentDetailsUpdate {
601	fn id(&self) -> <PaymentDetails as StorableObject>::Id {
602		self.id
603	}
604}
605
606#[cfg(test)]
607mod tests {
608	use bitcoin::io::Cursor;
609	use lightning::util::ser::Readable;
610
611	use super::*;
612
613	/// We refactored `PaymentDetails` to hold a payment id and moved some required fields into
614	/// `PaymentKind`. Here, we keep the old layout available in order test de/ser compatibility.
615	#[derive(Clone, Debug, PartialEq, Eq)]
616	struct OldPaymentDetails {
617		pub hash: PaymentHash,
618		pub preimage: Option<PaymentPreimage>,
619		pub secret: Option<PaymentSecret>,
620		pub amount_msat: Option<u64>,
621		pub direction: PaymentDirection,
622		pub status: PaymentStatus,
623		pub lsp_fee_limits: Option<LSPFeeLimits>,
624	}
625
626	impl_writeable_tlv_based!(OldPaymentDetails, {
627		(0, hash, required),
628		(1, lsp_fee_limits, option),
629		(2, preimage, required),
630		(4, secret, required),
631		(6, amount_msat, required),
632		(8, direction, required),
633		(10, status, required)
634	});
635
636	#[test]
637	fn old_payment_details_deser_compat() {
638		// We refactored `PaymentDetails` to hold a payment id and moved some required fields into
639		// `PaymentKind`. Here, we test compatibility with the old layout.
640		let hash = PaymentHash([42u8; 32]);
641		let preimage = Some(PaymentPreimage([43u8; 32]));
642		let secret = Some(PaymentSecret([44u8; 32]));
643		let amount_msat = Some(45_000_000);
644
645		// Test `Bolt11` de/ser
646		{
647			let old_bolt11_payment = OldPaymentDetails {
648				hash,
649				preimage,
650				secret,
651				amount_msat,
652				direction: PaymentDirection::Inbound,
653				status: PaymentStatus::Pending,
654				lsp_fee_limits: None,
655			};
656
657			let old_bolt11_encoded = old_bolt11_payment.encode();
658			assert_eq!(
659				old_bolt11_payment,
660				OldPaymentDetails::read(&mut Cursor::new(old_bolt11_encoded.clone())).unwrap()
661			);
662
663			let bolt11_decoded =
664				PaymentDetails::read(&mut Cursor::new(old_bolt11_encoded)).unwrap();
665			let bolt11_reencoded = bolt11_decoded.encode();
666			assert_eq!(
667				bolt11_decoded,
668				PaymentDetails::read(&mut Cursor::new(bolt11_reencoded)).unwrap()
669			);
670
671			match bolt11_decoded.kind {
672				PaymentKind::Bolt11 { hash: h, preimage: p, secret: s } => {
673					assert_eq!(hash, h);
674					assert_eq!(preimage, p);
675					assert_eq!(secret, s);
676				},
677				_ => {
678					panic!("Unexpected kind!");
679				},
680			}
681		}
682
683		// Test `Bolt11Jit` de/ser
684		{
685			let lsp_fee_limits = Some(LSPFeeLimits {
686				max_total_opening_fee_msat: Some(46_000),
687				max_proportional_opening_fee_ppm_msat: Some(47_000),
688			});
689
690			let old_bolt11_jit_payment = OldPaymentDetails {
691				hash,
692				preimage,
693				secret,
694				amount_msat,
695				direction: PaymentDirection::Inbound,
696				status: PaymentStatus::Pending,
697				lsp_fee_limits,
698			};
699
700			let old_bolt11_jit_encoded = old_bolt11_jit_payment.encode();
701			assert_eq!(
702				old_bolt11_jit_payment,
703				OldPaymentDetails::read(&mut Cursor::new(old_bolt11_jit_encoded.clone())).unwrap()
704			);
705
706			let bolt11_jit_decoded =
707				PaymentDetails::read(&mut Cursor::new(old_bolt11_jit_encoded)).unwrap();
708			let bolt11_jit_reencoded = bolt11_jit_decoded.encode();
709			assert_eq!(
710				bolt11_jit_decoded,
711				PaymentDetails::read(&mut Cursor::new(bolt11_jit_reencoded)).unwrap()
712			);
713
714			match bolt11_jit_decoded.kind {
715				PaymentKind::Bolt11Jit {
716					hash: h,
717					preimage: p,
718					secret: s,
719					counterparty_skimmed_fee_msat: c,
720					lsp_fee_limits: l,
721				} => {
722					assert_eq!(hash, h);
723					assert_eq!(preimage, p);
724					assert_eq!(secret, s);
725					assert_eq!(None, c);
726					assert_eq!(lsp_fee_limits, Some(l));
727				},
728				_ => {
729					panic!("Unexpected kind!");
730				},
731			}
732		}
733
734		// Test `Spontaneous` de/ser
735		{
736			let old_spontaneous_payment = OldPaymentDetails {
737				hash,
738				preimage,
739				secret: None,
740				amount_msat,
741				direction: PaymentDirection::Inbound,
742				status: PaymentStatus::Pending,
743				lsp_fee_limits: None,
744			};
745
746			let old_spontaneous_encoded = old_spontaneous_payment.encode();
747			assert_eq!(
748				old_spontaneous_payment,
749				OldPaymentDetails::read(&mut Cursor::new(old_spontaneous_encoded.clone())).unwrap()
750			);
751
752			let spontaneous_decoded =
753				PaymentDetails::read(&mut Cursor::new(old_spontaneous_encoded)).unwrap();
754			let spontaneous_reencoded = spontaneous_decoded.encode();
755			assert_eq!(
756				spontaneous_decoded,
757				PaymentDetails::read(&mut Cursor::new(spontaneous_reencoded)).unwrap()
758			);
759
760			match spontaneous_decoded.kind {
761				PaymentKind::Spontaneous { hash: h, preimage: p } => {
762					assert_eq!(hash, h);
763					assert_eq!(preimage, p);
764				},
765				_ => {
766					panic!("Unexpected kind!");
767				},
768			}
769		}
770	}
771}