Skip to content

Commit 15b1c9b

Browse files
authored
Merge pull request #2319 from valentinewallace/2023-05-forward-less-than-onion
Allow forwarding less than the amount in the onion
2 parents ba342de + 2127eb8 commit 15b1c9b

File tree

9 files changed

+606
-201
lines changed

9 files changed

+606
-201
lines changed

lightning/src/events/mod.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -385,8 +385,25 @@ pub enum Event {
385385
///
386386
/// Payments received on LDK versions prior to 0.0.115 will have this field unset.
387387
onion_fields: Option<RecipientOnionFields>,
388-
/// The value, in thousandths of a satoshi, that this payment is for.
388+
/// The value, in thousandths of a satoshi, that this payment is claimable for. May be greater
389+
/// than the invoice amount.
390+
///
391+
/// May be less than the invoice amount if [`ChannelConfig::accept_underpaying_htlcs`] is set
392+
/// and the previous hop took an extra fee.
393+
///
394+
/// # Note
395+
/// If [`ChannelConfig::accept_underpaying_htlcs`] is set and you claim without verifying this
396+
/// field, you may lose money!
397+
///
398+
/// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
389399
amount_msat: u64,
400+
/// The value, in thousands of a satoshi, that was skimmed off of this payment as an extra fee
401+
/// taken by our channel counterparty.
402+
///
403+
/// Will always be 0 unless [`ChannelConfig::accept_underpaying_htlcs`] is set.
404+
///
405+
/// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
406+
counterparty_skimmed_fee_msat: u64,
390407
/// Information for claiming this received payment, based on whether the purpose of the
391408
/// payment is to pay an invoice or to send a spontaneous payment.
392409
purpose: PaymentPurpose,
@@ -428,7 +445,8 @@ pub enum Event {
428445
/// The payment hash of the claimed payment. Note that LDK will not stop you from
429446
/// registering duplicate payment hashes for inbound payments.
430447
payment_hash: PaymentHash,
431-
/// The value, in thousandths of a satoshi, that this payment is for.
448+
/// The value, in thousandths of a satoshi, that this payment is for. May be greater than the
449+
/// invoice amount.
432450
amount_msat: u64,
433451
/// The purpose of the claimed payment, i.e. whether the payment was for an invoice or a
434452
/// spontaneous payment.
@@ -621,6 +639,7 @@ pub enum Event {
621639
inbound_amount_msat: u64,
622640
/// How many msats the payer intended to route to the next node. Depending on the reason you are
623641
/// intercepting this payment, you might take a fee by forwarding less than this amount.
642+
/// Forwarding less than this amount may break compatibility with LDK versions prior to 0.0.116.
624643
///
625644
/// Note that LDK will NOT check that expected fees were factored into this value. You MUST
626645
/// check that whatever fee you want has been included here or subtract it as required. Further,
@@ -830,8 +849,8 @@ impl Writeable for Event {
830849
// We never write out FundingGenerationReady events as, upon disconnection, peers
831850
// drop any channels which have not yet exchanged funding_signed.
832851
},
833-
&Event::PaymentClaimable { ref payment_hash, ref amount_msat, ref purpose,
834-
ref receiver_node_id, ref via_channel_id, ref via_user_channel_id,
852+
&Event::PaymentClaimable { ref payment_hash, ref amount_msat, counterparty_skimmed_fee_msat,
853+
ref purpose, ref receiver_node_id, ref via_channel_id, ref via_user_channel_id,
835854
ref claim_deadline, ref onion_fields
836855
} => {
837856
1u8.write(writer)?;
@@ -846,6 +865,8 @@ impl Writeable for Event {
846865
payment_preimage = Some(*preimage);
847866
}
848867
}
868+
let skimmed_fee_opt = if counterparty_skimmed_fee_msat == 0 { None }
869+
else { Some(counterparty_skimmed_fee_msat) };
849870
write_tlv_fields!(writer, {
850871
(0, payment_hash, required),
851872
(1, receiver_node_id, option),
@@ -857,6 +878,7 @@ impl Writeable for Event {
857878
(7, claim_deadline, option),
858879
(8, payment_preimage, option),
859880
(9, onion_fields, option),
881+
(10, skimmed_fee_opt, option),
860882
});
861883
},
862884
&Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
@@ -1056,6 +1078,7 @@ impl MaybeReadable for Event {
10561078
let mut payment_preimage = None;
10571079
let mut payment_secret = None;
10581080
let mut amount_msat = 0;
1081+
let mut counterparty_skimmed_fee_msat_opt = None;
10591082
let mut receiver_node_id = None;
10601083
let mut _user_payment_id = None::<u64>; // Used in 0.0.103 and earlier, no longer written in 0.0.116+.
10611084
let mut via_channel_id = None;
@@ -1073,6 +1096,7 @@ impl MaybeReadable for Event {
10731096
(7, claim_deadline, option),
10741097
(8, payment_preimage, option),
10751098
(9, onion_fields, option),
1099+
(10, counterparty_skimmed_fee_msat_opt, option),
10761100
});
10771101
let purpose = match payment_secret {
10781102
Some(secret) => PaymentPurpose::InvoicePayment {
@@ -1086,6 +1110,7 @@ impl MaybeReadable for Event {
10861110
receiver_node_id,
10871111
payment_hash,
10881112
amount_msat,
1113+
counterparty_skimmed_fee_msat: counterparty_skimmed_fee_msat_opt.unwrap_or(0),
10891114
purpose,
10901115
via_channel_id,
10911116
via_user_channel_id,

lightning/src/ln/channel.rs

+88-15
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ struct OutboundHTLCOutput {
224224
payment_hash: PaymentHash,
225225
state: OutboundHTLCState,
226226
source: HTLCSource,
227+
skimmed_fee_msat: Option<u64>,
227228
}
228229

229230
/// See AwaitingRemoteRevoke ChannelState for more info
@@ -235,6 +236,8 @@ enum HTLCUpdateAwaitingACK {
235236
payment_hash: PaymentHash,
236237
source: HTLCSource,
237238
onion_routing_packet: msgs::OnionPacket,
239+
// The extra fee we're skimming off the top of this HTLC.
240+
skimmed_fee_msat: Option<u64>,
238241
},
239242
ClaimHTLC {
240243
payment_preimage: PaymentPreimage,
@@ -3052,8 +3055,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
30523055
// handling this case better and maybe fulfilling some of the HTLCs while attempting
30533056
// to rebalance channels.
30543057
match &htlc_update {
3055-
&HTLCUpdateAwaitingACK::AddHTLC {amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet, ..} => {
3056-
match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(), onion_routing_packet.clone(), false, logger) {
3058+
&HTLCUpdateAwaitingACK::AddHTLC {
3059+
amount_msat, cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet,
3060+
skimmed_fee_msat, ..
3061+
} => {
3062+
match self.send_htlc(amount_msat, *payment_hash, cltv_expiry, source.clone(),
3063+
onion_routing_packet.clone(), false, skimmed_fee_msat, logger)
3064+
{
30573065
Ok(update_add_msg_option) => update_add_htlcs.push(update_add_msg_option.unwrap()),
30583066
Err(e) => {
30593067
match e {
@@ -3695,6 +3703,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
36953703
payment_hash: htlc.payment_hash,
36963704
cltv_expiry: htlc.cltv_expiry,
36973705
onion_routing_packet: (**onion_packet).clone(),
3706+
skimmed_fee_msat: htlc.skimmed_fee_msat,
36983707
});
36993708
}
37003709
}
@@ -5042,11 +5051,13 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
50425051
/// commitment update.
50435052
///
50445053
/// `Err`s will only be [`ChannelError::Ignore`].
5045-
pub fn queue_add_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5046-
onion_routing_packet: msgs::OnionPacket, logger: &L)
5047-
-> Result<(), ChannelError> where L::Target: Logger {
5054+
pub fn queue_add_htlc<L: Deref>(
5055+
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5056+
onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>, logger: &L
5057+
) -> Result<(), ChannelError> where L::Target: Logger {
50485058
self
5049-
.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true, logger)
5059+
.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, true,
5060+
skimmed_fee_msat, logger)
50505061
.map(|msg_opt| assert!(msg_opt.is_none(), "We forced holding cell?"))
50515062
.map_err(|err| {
50525063
if let ChannelError::Ignore(_) = err { /* fine */ }
@@ -5071,9 +5082,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
50715082
/// on this [`Channel`] if `force_holding_cell` is false.
50725083
///
50735084
/// `Err`s will only be [`ChannelError::Ignore`].
5074-
fn send_htlc<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5075-
onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool, logger: &L)
5076-
-> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
5085+
fn send_htlc<L: Deref>(
5086+
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5087+
onion_routing_packet: msgs::OnionPacket, mut force_holding_cell: bool,
5088+
skimmed_fee_msat: Option<u64>, logger: &L
5089+
) -> Result<Option<msgs::UpdateAddHTLC>, ChannelError> where L::Target: Logger {
50775090
if (self.context.channel_state & (ChannelState::ChannelReady as u32 | BOTH_SIDES_SHUTDOWN_MASK)) != (ChannelState::ChannelReady as u32) {
50785091
return Err(ChannelError::Ignore("Cannot send HTLC until channel is fully established and we haven't started shutting down".to_owned()));
50795092
}
@@ -5125,6 +5138,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
51255138
cltv_expiry,
51265139
source,
51275140
onion_routing_packet,
5141+
skimmed_fee_msat,
51285142
});
51295143
return Ok(None);
51305144
}
@@ -5136,6 +5150,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
51365150
cltv_expiry,
51375151
state: OutboundHTLCState::LocalAnnounced(Box::new(onion_routing_packet.clone())),
51385152
source,
5153+
skimmed_fee_msat,
51395154
});
51405155

51415156
let res = msgs::UpdateAddHTLC {
@@ -5145,6 +5160,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
51455160
payment_hash,
51465161
cltv_expiry,
51475162
onion_routing_packet,
5163+
skimmed_fee_msat,
51485164
};
51495165
self.context.next_holder_htlc_id += 1;
51505166

@@ -5283,8 +5299,12 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
52835299
///
52845300
/// Shorthand for calling [`Self::send_htlc`] followed by a commitment update, see docs on
52855301
/// [`Self::send_htlc`] and [`Self::build_commitment_no_state_update`] for more info.
5286-
pub fn send_htlc_and_commit<L: Deref>(&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource, onion_routing_packet: msgs::OnionPacket, logger: &L) -> Result<Option<&ChannelMonitorUpdate>, ChannelError> where L::Target: Logger {
5287-
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source, onion_routing_packet, false, logger);
5302+
pub fn send_htlc_and_commit<L: Deref>(
5303+
&mut self, amount_msat: u64, payment_hash: PaymentHash, cltv_expiry: u32, source: HTLCSource,
5304+
onion_routing_packet: msgs::OnionPacket, skimmed_fee_msat: Option<u64>, logger: &L
5305+
) -> Result<Option<&ChannelMonitorUpdate>, ChannelError> where L::Target: Logger {
5306+
let send_res = self.send_htlc(amount_msat, payment_hash, cltv_expiry, source,
5307+
onion_routing_packet, false, skimmed_fee_msat, logger);
52885308
if let Err(e) = &send_res { if let ChannelError::Ignore(_) = e {} else { debug_assert!(false, "Sending cannot trigger channel failure"); } }
52895309
match send_res? {
52905310
Some(_) => {
@@ -6609,9 +6629,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
66096629
}
66106630

66116631
let mut preimages: Vec<&Option<PaymentPreimage>> = vec![];
6632+
let mut pending_outbound_skimmed_fees: Vec<Option<u64>> = Vec::new();
66126633

66136634
(self.context.pending_outbound_htlcs.len() as u64).write(writer)?;
6614-
for htlc in self.context.pending_outbound_htlcs.iter() {
6635+
for (idx, htlc) in self.context.pending_outbound_htlcs.iter().enumerate() {
66156636
htlc.htlc_id.write(writer)?;
66166637
htlc.amount_msat.write(writer)?;
66176638
htlc.cltv_expiry.write(writer)?;
@@ -6647,18 +6668,37 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
66476668
reason.write(writer)?;
66486669
}
66496670
}
6671+
if let Some(skimmed_fee) = htlc.skimmed_fee_msat {
6672+
if pending_outbound_skimmed_fees.is_empty() {
6673+
for _ in 0..idx { pending_outbound_skimmed_fees.push(None); }
6674+
}
6675+
pending_outbound_skimmed_fees.push(Some(skimmed_fee));
6676+
} else if !pending_outbound_skimmed_fees.is_empty() {
6677+
pending_outbound_skimmed_fees.push(None);
6678+
}
66506679
}
66516680

6681+
let mut holding_cell_skimmed_fees: Vec<Option<u64>> = Vec::new();
66526682
(self.context.holding_cell_htlc_updates.len() as u64).write(writer)?;
6653-
for update in self.context.holding_cell_htlc_updates.iter() {
6683+
for (idx, update) in self.context.holding_cell_htlc_updates.iter().enumerate() {
66546684
match update {
6655-
&HTLCUpdateAwaitingACK::AddHTLC { ref amount_msat, ref cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet } => {
6685+
&HTLCUpdateAwaitingACK::AddHTLC {
6686+
ref amount_msat, ref cltv_expiry, ref payment_hash, ref source, ref onion_routing_packet,
6687+
skimmed_fee_msat,
6688+
} => {
66566689
0u8.write(writer)?;
66576690
amount_msat.write(writer)?;
66586691
cltv_expiry.write(writer)?;
66596692
payment_hash.write(writer)?;
66606693
source.write(writer)?;
66616694
onion_routing_packet.write(writer)?;
6695+
6696+
if let Some(skimmed_fee) = skimmed_fee_msat {
6697+
if holding_cell_skimmed_fees.is_empty() {
6698+
for _ in 0..idx { holding_cell_skimmed_fees.push(None); }
6699+
}
6700+
holding_cell_skimmed_fees.push(Some(skimmed_fee));
6701+
} else if !holding_cell_skimmed_fees.is_empty() { holding_cell_skimmed_fees.push(None); }
66626702
},
66636703
&HTLCUpdateAwaitingACK::ClaimHTLC { ref payment_preimage, ref htlc_id } => {
66646704
1u8.write(writer)?;
@@ -6825,6 +6865,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Writeable for Channel<Signer> {
68256865
(29, self.context.temporary_channel_id, option),
68266866
(31, channel_pending_event_emitted, option),
68276867
(33, self.context.pending_monitor_updates, vec_type),
6868+
(35, pending_outbound_skimmed_fees, optional_vec),
6869+
(37, holding_cell_skimmed_fees, optional_vec),
68286870
});
68296871

68306872
Ok(())
@@ -6935,6 +6977,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
69356977
},
69366978
_ => return Err(DecodeError::InvalidValue),
69376979
},
6980+
skimmed_fee_msat: None,
69386981
});
69396982
}
69406983

@@ -6948,6 +6991,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
69486991
payment_hash: Readable::read(reader)?,
69496992
source: Readable::read(reader)?,
69506993
onion_routing_packet: Readable::read(reader)?,
6994+
skimmed_fee_msat: None,
69516995
},
69526996
1 => HTLCUpdateAwaitingACK::ClaimHTLC {
69536997
payment_preimage: Readable::read(reader)?,
@@ -7103,6 +7147,9 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
71037147

71047148
let mut pending_monitor_updates = Some(Vec::new());
71057149

7150+
let mut pending_outbound_skimmed_fees_opt: Option<Vec<Option<u64>>> = None;
7151+
let mut holding_cell_skimmed_fees_opt: Option<Vec<Option<u64>>> = None;
7152+
71067153
read_tlv_fields!(reader, {
71077154
(0, announcement_sigs, option),
71087155
(1, minimum_depth, option),
@@ -7126,6 +7173,8 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
71267173
(29, temporary_channel_id, option),
71277174
(31, channel_pending_event_emitted, option),
71287175
(33, pending_monitor_updates, vec_type),
7176+
(35, pending_outbound_skimmed_fees_opt, optional_vec),
7177+
(37, holding_cell_skimmed_fees_opt, optional_vec),
71297178
});
71307179

71317180
let (channel_keys_id, holder_signer) = if let Some(channel_keys_id) = channel_keys_id {
@@ -7180,6 +7229,25 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
71807229

71817230
let holder_max_accepted_htlcs = holder_max_accepted_htlcs.unwrap_or(DEFAULT_MAX_HTLCS);
71827231

7232+
if let Some(skimmed_fees) = pending_outbound_skimmed_fees_opt {
7233+
let mut iter = skimmed_fees.into_iter();
7234+
for htlc in pending_outbound_htlcs.iter_mut() {
7235+
htlc.skimmed_fee_msat = iter.next().ok_or(DecodeError::InvalidValue)?;
7236+
}
7237+
// We expect all skimmed fees to be consumed above
7238+
if iter.next().is_some() { return Err(DecodeError::InvalidValue) }
7239+
}
7240+
if let Some(skimmed_fees) = holding_cell_skimmed_fees_opt {
7241+
let mut iter = skimmed_fees.into_iter();
7242+
for htlc in holding_cell_htlc_updates.iter_mut() {
7243+
if let HTLCUpdateAwaitingACK::AddHTLC { ref mut skimmed_fee_msat, .. } = htlc {
7244+
*skimmed_fee_msat = iter.next().ok_or(DecodeError::InvalidValue)?;
7245+
}
7246+
}
7247+
// We expect all skimmed fees to be consumed above
7248+
if iter.next().is_some() { return Err(DecodeError::InvalidValue) }
7249+
}
7250+
71837251
Ok(Channel {
71847252
context: ChannelContext {
71857253
user_id,
@@ -7522,7 +7590,8 @@ mod tests {
75227590
session_priv: SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
75237591
first_hop_htlc_msat: 548,
75247592
payment_id: PaymentId([42; 32]),
7525-
}
7593+
},
7594+
skimmed_fee_msat: None,
75267595
});
75277596

75287597
// Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
@@ -8079,6 +8148,7 @@ mod tests {
80798148
payment_hash: PaymentHash([0; 32]),
80808149
state: OutboundHTLCState::Committed,
80818150
source: HTLCSource::dummy(),
8151+
skimmed_fee_msat: None,
80828152
};
80838153
out.payment_hash.0 = Sha256::hash(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).into_inner();
80848154
out
@@ -8091,6 +8161,7 @@ mod tests {
80918161
payment_hash: PaymentHash([0; 32]),
80928162
state: OutboundHTLCState::Committed,
80938163
source: HTLCSource::dummy(),
8164+
skimmed_fee_msat: None,
80948165
};
80958166
out.payment_hash.0 = Sha256::hash(&hex::decode("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).into_inner();
80968167
out
@@ -8492,6 +8563,7 @@ mod tests {
84928563
payment_hash: PaymentHash([0; 32]),
84938564
state: OutboundHTLCState::Committed,
84948565
source: HTLCSource::dummy(),
8566+
skimmed_fee_msat: None,
84958567
};
84968568
out.payment_hash.0 = Sha256::hash(&hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).into_inner();
84978569
out
@@ -8504,6 +8576,7 @@ mod tests {
85048576
payment_hash: PaymentHash([0; 32]),
85058577
state: OutboundHTLCState::Committed,
85068578
source: HTLCSource::dummy(),
8579+
skimmed_fee_msat: None,
85078580
};
85088581
out.payment_hash.0 = Sha256::hash(&hex::decode("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).into_inner();
85098582
out

0 commit comments

Comments
 (0)