Skip to content

Commit 803cf3f

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 01fe9ba commit 803cf3f

File tree

1 file changed

+59
-4
lines changed

1 file changed

+59
-4
lines changed

lightning/src/ln/channelmanager.rs

+59-4
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,32 @@ struct ReceiveError {
291291
msg: &'static str,
292292
}
293293

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

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

34773511
let removed_source = self.claimable_payments.lock().unwrap().claimable_htlcs.remove(payment_hash);
34783512
if let Some((_, mut sources)) = removed_source {
34793513
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);
3514+
let source = HTLCSource::PreviousHopData(htlc.prev_hop.clone());
34843515
let receiver = HTLCDestination::FailedPayment { payment_hash: *payment_hash };
3516+
3517+
let reason = match failure_code {
3518+
FailureCode::TemporaryNodeFailure => HTLCFailReason::from_failure_code(*failure_code as u16),
3519+
FailureCode::RequiredNodeFeatureMissing => HTLCFailReason::from_failure_code(*failure_code as u16),
3520+
FailureCode::ExpiryTooSoon => {
3521+
let short_channel_id = htlc.prev_hop.short_channel_id;
3522+
let (counterparty_node_id, chan_id) = self.short_to_chan_info.read().unwrap().get(&short_channel_id).cloned().unwrap();
3523+
let per_peer_state = self.per_peer_state.read().unwrap();
3524+
let peer_state = per_peer_state.get(&counterparty_node_id).unwrap().lock().unwrap();
3525+
let chan = peer_state.channel_by_id.get(&chan_id).unwrap();
3526+
let channel_update = self.get_channel_update_for_onion(short_channel_id, chan).unwrap();
3527+
let mut channel_update_data = Vec::new();
3528+
(channel_update.serialized_length() as u16 + 2).write(&mut channel_update_data).expect("Writes cannot fail");
3529+
msgs::ChannelUpdate::TYPE.write(&mut channel_update_data).expect("Writes cannot fail");
3530+
channel_update.write(&mut channel_update_data).expect("Writes cannot fail");
3531+
HTLCFailReason::reason(*failure_code as u16, channel_update_data)
3532+
},
3533+
FailureCode::IncorrectOrUnknownPaymentDetails => {
3534+
let mut htlc_msat_height_data = htlc.value.to_be_bytes().to_vec();
3535+
htlc_msat_height_data.extend_from_slice(&self.best_block.read().unwrap().height().to_be_bytes());
3536+
HTLCFailReason::reason(*failure_code as u16, htlc_msat_height_data)
3537+
}
3538+
};
3539+
34853540
self.fail_htlc_backwards_internal(&source, &payment_hash, &reason, receiver);
34863541
}
34873542
}

0 commit comments

Comments
 (0)