Skip to content

Commit db76201

Browse files
committed
Add FailureCode enum
This enum is used to specify which error code and data to send to peers when failing back an HTLC.
1 parent e0a0add commit db76201

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

lightning/src/ln/channelmanager.rs

+57-4
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,30 @@ struct ReceiveError {
289289
msg: &'static str,
290290
}
291291

292+
/// This enum is used to specify which error data to send to peers when failing back an HTLC
293+
/// using [`ChannelManager::fail_htlc_backwards_with_reason`].
294+
///
295+
/// For more info on failure codes, see <https://github.com/lightning/bolts/blob/master/04-onion-routing.md#failure-messages>.
296+
#[derive(Clone, Copy)]
297+
pub enum FailureCode {
298+
/// We had a temporary error processing the payment. Useful if no other error codes fit
299+
/// and you want to indicate that the payer may want to retry.
300+
TemporaryNodeFailure = 0x2000 | 2,
301+
/// We have a required feature which was not in this onion. For example, you may require
302+
/// some additional metadata that was not provided with this payment.
303+
RequiredNodeFeatureMissing = 0x4000 | 0x2000 | 3,
304+
/// The CLTV expiry is too close to the current block height for safe handling by us. This
305+
/// should only be used when failing back as a forwarding node.
306+
ExpiryTooSoon = 0x1000 | 14,
307+
/// You may wish to use this when a `payment_hash` is unknown, the `payment_secret` is
308+
/// required and not present, the `payment_secret` doesn't match the `payment_hash`, the
309+
/// received amount is incorrect, the CLTV expiry of the HTLC is too close to the current
310+
/// block height for safe handling, or `payment_metadata` isn't present when it should be.
311+
/// Using this failure code in [`ChannelManager::fail_htlc_backwards_with_reason`] is
312+
/// equivalent to calling [`ChannelManager::fail_htlc_backwards`].
313+
IncorrectOrUnknownPaymentDetails = 0x4000 | 15,
314+
}
315+
292316
type ShutdownResult = (Option<(OutPoint, ChannelMonitorUpdate)>, Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>);
293317

294318
/// Error type returned across the peer_state mutex boundary. When an Err is generated for a
@@ -3472,16 +3496,45 @@ where
34723496
/// [`events::Event::PaymentClaimed`] events even for payments you intend to fail, especially on
34733497
/// startup during which time claims that were in-progress at shutdown may be replayed.
34743498
pub fn fail_htlc_backwards(&self, payment_hash: &PaymentHash) {
3499+
self.fail_htlc_backwards_with_reason(payment_hash, &FailureCode::IncorrectOrUnknownPaymentDetails);
3500+
}
3501+
3502+
/// This is a variant of [`ChannelManager::fail_htlc_backwards`] that allows you to specify the
3503+
/// reason for the failure.
3504+
///
3505+
/// See [`FailureCode`] for valid failure codes.
3506+
pub fn fail_htlc_backwards_with_reason(&self, payment_hash: &PaymentHash, failure_code: &FailureCode) {
34753507
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
34763508

34773509
let removed_source = self.claimable_payments.lock().unwrap().claimable_htlcs.remove(payment_hash);
34783510
if let Some((_, mut sources)) = removed_source {
34793511
for htlc in sources.drain(..) {
3480-
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
3481-
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
3482-
let source = HTLCSource::PreviousHopData(htlc.prev_hop);
3483-
let reason = HTLCFailReason::reason(0x4000 | 15, htlc_msat_height_data);
3512+
let source = HTLCSource::PreviousHopData(htlc.prev_hop.clone());
34843513
let receiver = HTLCDestination::FailedPayment { payment_hash: *payment_hash };
3514+
3515+
let reason = match failure_code {
3516+
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(*failure_code as u16),
3517+
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(*failure_code as u16),
3518+
FailureCode::ExpiryTooSoon => {
3519+
let short_channel_id = htlc.prev_hop.short_channel_id;
3520+
let (counterparty_node_id, chan_id) = self.short_to_chan_info.read().unwrap().get(&short_channel_id).cloned().unwrap();
3521+
let per_peer_state = self.per_peer_state.read().unwrap();
3522+
let peer_state = per_peer_state.get(&counterparty_node_id).unwrap().lock().unwrap();
3523+
let chan = peer_state.channel_by_id.get(&chan_id).unwrap();
3524+
let channel_update = self.get_channel_update_for_onion(short_channel_id, chan).unwrap();
3525+
let mut channel_update_data = Vec::new();
3526+
(channel_update.serialized_length() as u16 + 2).write(&mut channel_update_data).expect("Writes cannot fail");
3527+
msgs::ChannelUpdate::TYPE.write(&mut channel_update_data).expect("Writes cannot fail");
3528+
channel_update.write(&mut channel_update_data).expect("Writes cannot fail");
3529+
HTLCFailReason::reason(*failure_code as u16, channel_update_data)
3530+
},
3531+
FailureCode::IncorrectOrUnknownPaymentDetails => {
3532+
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
3533+
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
3534+
HTLCFailReason::reason(*failure_code as u16, htlc_msat_height_data)
3535+
}
3536+
};
3537+
34853538
self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
34863539
}
34873540
}

0 commit comments

Comments
 (0)