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 //! Utilities to send payments and manage outbound payment information.
12 use crate::ln::{PaymentHash, PaymentSecret};
13 use crate::ln::msgs::DecodeError;
14 use crate::routing::router::{RouteHop, RoutePath};
15 use crate::prelude::*;
17 /// Stores the session_priv for each part of a payment that is still pending. For versions 0.0.102
18 /// and later, also stores information for retrying the payment.
19 pub(crate) enum PendingOutboundPayment {
21 session_privs: HashSet<[u8; 32]>,
24 session_privs: HashSet<[u8; 32]>,
25 payment_hash: PaymentHash,
26 payment_secret: Option<PaymentSecret>,
27 pending_amt_msat: u64,
28 /// Used to track the fee paid. Only present if the payment was serialized on 0.0.103+.
29 pending_fee_msat: Option<u64>,
30 /// The total payment amount across all paths, used to verify that a retry is not overpaying.
32 /// Our best known block height at the time this payment was initiated.
33 starting_block_height: u32,
35 /// When a pending payment is fulfilled, we continue tracking it until all pending HTLCs have
36 /// been resolved. This ensures we don't look up pending payments in ChannelMonitors on restart
37 /// and add a pending payment that was already fulfilled.
39 session_privs: HashSet<[u8; 32]>,
40 payment_hash: Option<PaymentHash>,
41 timer_ticks_without_htlcs: u8,
43 /// When a payer gives up trying to retry a payment, they inform us, letting us generate a
44 /// `PaymentFailed` event when all HTLCs have irrevocably failed. This avoids a number of race
45 /// conditions in MPP-aware payment retriers (1), where the possibility of multiple
46 /// `PaymentPathFailed` events with `all_paths_failed` can be pending at once, confusing a
47 /// downstream event handler as to when a payment has actually failed.
49 /// (1) https://github.com/lightningdevkit/rust-lightning/issues/1164
51 session_privs: HashSet<[u8; 32]>,
52 payment_hash: PaymentHash,
56 impl PendingOutboundPayment {
57 pub(super) fn is_fulfilled(&self) -> bool {
59 PendingOutboundPayment::Fulfilled { .. } => true,
63 pub(super) fn abandoned(&self) -> bool {
65 PendingOutboundPayment::Abandoned { .. } => true,
69 pub(super) fn get_pending_fee_msat(&self) -> Option<u64> {
71 PendingOutboundPayment::Retryable { pending_fee_msat, .. } => pending_fee_msat.clone(),
76 pub(super) fn payment_hash(&self) -> Option<PaymentHash> {
78 PendingOutboundPayment::Legacy { .. } => None,
79 PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash),
80 PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash,
81 PendingOutboundPayment::Abandoned { payment_hash, .. } => Some(*payment_hash),
85 pub(super) fn mark_fulfilled(&mut self) {
86 let mut session_privs = HashSet::new();
87 core::mem::swap(&mut session_privs, match self {
88 PendingOutboundPayment::Legacy { session_privs } |
89 PendingOutboundPayment::Retryable { session_privs, .. } |
90 PendingOutboundPayment::Fulfilled { session_privs, .. } |
91 PendingOutboundPayment::Abandoned { session_privs, .. }
94 let payment_hash = self.payment_hash();
95 *self = PendingOutboundPayment::Fulfilled { session_privs, payment_hash, timer_ticks_without_htlcs: 0 };
98 pub(super) fn mark_abandoned(&mut self) -> Result<(), ()> {
99 let mut session_privs = HashSet::new();
100 let our_payment_hash;
101 core::mem::swap(&mut session_privs, match self {
102 PendingOutboundPayment::Legacy { .. } |
103 PendingOutboundPayment::Fulfilled { .. } =>
105 PendingOutboundPayment::Retryable { session_privs, payment_hash, .. } |
106 PendingOutboundPayment::Abandoned { session_privs, payment_hash, .. } => {
107 our_payment_hash = *payment_hash;
111 *self = PendingOutboundPayment::Abandoned { session_privs, payment_hash: our_payment_hash };
115 /// panics if path is None and !self.is_fulfilled
116 pub(super) fn remove(&mut self, session_priv: &[u8; 32], path: Option<&Vec<RouteHop>>) -> bool {
117 let remove_res = match self {
118 PendingOutboundPayment::Legacy { session_privs } |
119 PendingOutboundPayment::Retryable { session_privs, .. } |
120 PendingOutboundPayment::Fulfilled { session_privs, .. } |
121 PendingOutboundPayment::Abandoned { session_privs, .. } => {
122 session_privs.remove(session_priv)
126 if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
127 let path = path.expect("Fulfilling a payment should always come with a path");
128 let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
129 *pending_amt_msat -= path_last_hop.fee_msat;
130 if let Some(fee_msat) = pending_fee_msat.as_mut() {
131 *fee_msat -= path.get_path_fees();
138 pub(super) fn insert(&mut self, session_priv: [u8; 32], path: &Vec<RouteHop>) -> bool {
139 let insert_res = match self {
140 PendingOutboundPayment::Legacy { session_privs } |
141 PendingOutboundPayment::Retryable { session_privs, .. } => {
142 session_privs.insert(session_priv)
144 PendingOutboundPayment::Fulfilled { .. } => false,
145 PendingOutboundPayment::Abandoned { .. } => false,
148 if let PendingOutboundPayment::Retryable { ref mut pending_amt_msat, ref mut pending_fee_msat, .. } = self {
149 let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
150 *pending_amt_msat += path_last_hop.fee_msat;
151 if let Some(fee_msat) = pending_fee_msat.as_mut() {
152 *fee_msat += path.get_path_fees();
159 pub(super) fn remaining_parts(&self) -> usize {
161 PendingOutboundPayment::Legacy { session_privs } |
162 PendingOutboundPayment::Retryable { session_privs, .. } |
163 PendingOutboundPayment::Fulfilled { session_privs, .. } |
164 PendingOutboundPayment::Abandoned { session_privs, .. } => {
171 impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
173 (0, session_privs, required),
176 (0, session_privs, required),
177 (1, payment_hash, option),
178 (3, timer_ticks_without_htlcs, (default_value, 0)),
181 (0, session_privs, required),
182 (1, pending_fee_msat, option),
183 (2, payment_hash, required),
184 (4, payment_secret, option),
185 (6, total_msat, required),
186 (8, pending_amt_msat, required),
187 (10, starting_block_height, required),
190 (0, session_privs, required),
191 (2, payment_hash, required),