@@ -2502,12 +2502,14 @@ where
2502
2502
} )
2503
2503
}
2504
2504
2505
- fn decode_update_add_htlc_onion ( & self , msg : & msgs:: UpdateAddHTLC ) -> PendingHTLCStatus {
2505
+ fn decode_update_add_htlc_onion (
2506
+ & self , msg : & msgs:: UpdateAddHTLC
2507
+ ) -> Result < ( onion_utils:: Hop , [ u8 ; 32 ] ) , HTLCFailureMsg > {
2506
2508
macro_rules! return_malformed_err {
2507
2509
( $msg: expr, $err_code: expr) => {
2508
2510
{
2509
2511
log_info!( self . logger, "Failed to accept/forward incoming HTLC: {}" , $msg) ;
2510
- return PendingHTLCStatus :: Fail ( HTLCFailureMsg :: Malformed ( msgs:: UpdateFailMalformedHTLC {
2512
+ return Err ( HTLCFailureMsg :: Malformed ( msgs:: UpdateFailMalformedHTLC {
2511
2513
channel_id: msg. channel_id,
2512
2514
htlc_id: msg. htlc_id,
2513
2515
sha256_of_onion: Sha256 :: hash( & msg. onion_routing_packet. hop_data) . into_inner( ) ,
@@ -2538,7 +2540,7 @@ where
2538
2540
( $msg: expr, $err_code: expr, $data: expr) => {
2539
2541
{
2540
2542
log_info!( self . logger, "Failed to accept/forward incoming HTLC: {}" , $msg) ;
2541
- return PendingHTLCStatus :: Fail ( HTLCFailureMsg :: Relay ( msgs:: UpdateFailHTLC {
2543
+ return Err ( HTLCFailureMsg :: Relay ( msgs:: UpdateFailHTLC {
2542
2544
channel_id: msg. channel_id,
2543
2545
htlc_id: msg. htlc_id,
2544
2546
reason: HTLCFailReason :: reason( $err_code, $data. to_vec( ) )
@@ -2557,8 +2559,174 @@ where
2557
2559
return_err ! ( err_msg, err_code, & [ 0 ; 0 ] ) ;
2558
2560
} ,
2559
2561
} ;
2562
+ let ( outgoing_scid, outgoing_amt_msat, outgoing_cltv_value) = match next_hop {
2563
+ onion_utils:: Hop :: Forward {
2564
+ next_hop_data : msgs:: OnionHopData {
2565
+ format : msgs:: OnionHopDataFormat :: NonFinalNode { short_channel_id } , amt_to_forward,
2566
+ outgoing_cltv_value,
2567
+ } , ..
2568
+ } => ( short_channel_id, amt_to_forward, outgoing_cltv_value) ,
2569
+ // We'll do receive checks in [`Self::construct_pending_htlc_info`] so we have access to the
2570
+ // inbound channel's state.
2571
+ onion_utils:: Hop :: Receive { .. } => return Ok ( ( next_hop, shared_secret) ) ,
2572
+ _ => {
2573
+ return_err ! ( "Final Node OnionHopData provided for us as an intermediary node" , 0x4000 | 22 , & [ 0 ; 0 ] ) ;
2574
+ }
2575
+ } ;
2560
2576
2561
- let pending_forward_info = match next_hop {
2577
+ // Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
2578
+ // can't hold the outbound peer state lock at the same time as the inbound peer state lock.
2579
+ if let Some ( ( err, mut code, chan_update) ) = loop {
2580
+ let id_option = self . short_to_chan_info . read ( ) . unwrap ( ) . get ( & outgoing_scid) . cloned ( ) ;
2581
+ let forwarding_chan_info_opt = match id_option {
2582
+ None => { // unknown_next_peer
2583
+ // Note that this is likely a timing oracle for detecting whether an scid is a
2584
+ // phantom or an intercept.
2585
+ if ( self . default_configuration . accept_intercept_htlcs &&
2586
+ fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , outgoing_scid, & self . genesis_hash ) ) ||
2587
+ fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , outgoing_scid, & self . genesis_hash )
2588
+ {
2589
+ None
2590
+ } else {
2591
+ break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2592
+ }
2593
+ } ,
2594
+ Some ( ( cp_id, id) ) => Some ( ( cp_id. clone ( ) , id. clone ( ) ) ) ,
2595
+ } ;
2596
+ let chan_update_opt = if let Some ( ( counterparty_node_id, forwarding_id) ) = forwarding_chan_info_opt {
2597
+ let per_peer_state = self . per_peer_state . read ( ) . unwrap ( ) ;
2598
+ let peer_state_mutex_opt = per_peer_state. get ( & counterparty_node_id) ;
2599
+ if peer_state_mutex_opt. is_none ( ) {
2600
+ break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2601
+ }
2602
+ let mut peer_state_lock = peer_state_mutex_opt. unwrap ( ) . lock ( ) . unwrap ( ) ;
2603
+ let peer_state = & mut * peer_state_lock;
2604
+ let chan = match peer_state. channel_by_id . get_mut ( & forwarding_id) {
2605
+ None => {
2606
+ // Channel was removed. The short_to_chan_info and channel_by_id maps
2607
+ // have no consistency guarantees.
2608
+ break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2609
+ } ,
2610
+ Some ( chan) => chan
2611
+ } ;
2612
+ if !chan. should_announce ( ) && !self . default_configuration . accept_forwards_to_priv_channels {
2613
+ // Note that the behavior here should be identical to the above block - we
2614
+ // should NOT reveal the existence or non-existence of a private channel if
2615
+ // we don't allow forwards outbound over them.
2616
+ break Some ( ( "Refusing to forward to a private channel based on our config." , 0x4000 | 10 , None ) ) ;
2617
+ }
2618
+ if chan. get_channel_type ( ) . supports_scid_privacy ( ) && outgoing_scid != chan. outbound_scid_alias ( ) {
2619
+ // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
2620
+ // "refuse to forward unless the SCID alias was used", so we pretend
2621
+ // we don't have the channel here.
2622
+ break Some ( ( "Refusing to forward over real channel SCID as our counterparty requested." , 0x4000 | 10 , None ) ) ;
2623
+ }
2624
+ let chan_update_opt = self . get_channel_update_for_onion ( outgoing_scid, chan) . ok ( ) ;
2625
+
2626
+ // Note that we could technically not return an error yet here and just hope
2627
+ // that the connection is reestablished or monitor updated by the time we get
2628
+ // around to doing the actual forward, but better to fail early if we can and
2629
+ // hopefully an attacker trying to path-trace payments cannot make this occur
2630
+ // on a small/per-node/per-channel scale.
2631
+ if !chan. is_live ( ) { // channel_disabled
2632
+ // If the channel_update we're going to return is disabled (i.e. the
2633
+ // peer has been disabled for some time), return `channel_disabled`,
2634
+ // otherwise return `temporary_channel_failure`.
2635
+ if chan_update_opt. as_ref ( ) . map ( |u| u. contents . flags & 2 == 2 ) . unwrap_or ( false ) {
2636
+ break Some ( ( "Forwarding channel has been disconnected for some time." , 0x1000 | 20 , chan_update_opt) ) ;
2637
+ } else {
2638
+ break Some ( ( "Forwarding channel is not in a ready state." , 0x1000 | 7 , chan_update_opt) ) ;
2639
+ }
2640
+ }
2641
+ if outgoing_amt_msat < chan. get_counterparty_htlc_minimum_msat ( ) { // amount_below_minimum
2642
+ break Some ( ( "HTLC amount was below the htlc_minimum_msat" , 0x1000 | 11 , chan_update_opt) ) ;
2643
+ }
2644
+ if let Err ( ( err, code) ) = chan. htlc_satisfies_config ( & msg, outgoing_amt_msat, outgoing_cltv_value) {
2645
+ break Some ( ( err, code, chan_update_opt) ) ;
2646
+ }
2647
+ chan_update_opt
2648
+ } else {
2649
+ if ( msg. cltv_expiry as u64 ) < ( outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
2650
+ // We really should set `incorrect_cltv_expiry` here but as we're not
2651
+ // forwarding over a real channel we can't generate a channel_update
2652
+ // for it. Instead we just return a generic temporary_node_failure.
2653
+ break Some ( (
2654
+ "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta" ,
2655
+ 0x2000 | 2 , None ,
2656
+ ) ) ;
2657
+ }
2658
+ None
2659
+ } ;
2660
+
2661
+ let cur_height = self . best_block . read ( ) . unwrap ( ) . height ( ) + 1 ;
2662
+ // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
2663
+ // but we want to be robust wrt to counterparty packet sanitization (see
2664
+ // HTLC_FAIL_BACK_BUFFER rationale).
2665
+ if msg. cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
2666
+ break Some ( ( "CLTV expiry is too close" , 0x1000 | 14 , chan_update_opt) ) ;
2667
+ }
2668
+ if msg. cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
2669
+ break Some ( ( "CLTV expiry is too far in the future" , 21 , None ) ) ;
2670
+ }
2671
+ // If the HTLC expires ~now, don't bother trying to forward it to our
2672
+ // counterparty. They should fail it anyway, but we don't want to bother with
2673
+ // the round-trips or risk them deciding they definitely want the HTLC and
2674
+ // force-closing to ensure they get it if we're offline.
2675
+ // We previously had a much more aggressive check here which tried to ensure
2676
+ // our counterparty receives an HTLC which has *our* risk threshold met on it,
2677
+ // but there is no need to do that, and since we're a bit conservative with our
2678
+ // risk threshold it just results in failing to forward payments.
2679
+ if ( outgoing_cltv_value) as u64 <= ( cur_height + LATENCY_GRACE_PERIOD_BLOCKS ) as u64 {
2680
+ break Some ( ( "Outgoing CLTV value is too soon" , 0x1000 | 14 , chan_update_opt) ) ;
2681
+ }
2682
+
2683
+ break None ;
2684
+ }
2685
+ {
2686
+ let mut res = VecWriter ( Vec :: with_capacity ( chan_update. serialized_length ( ) + 2 + 8 + 2 ) ) ;
2687
+ if let Some ( chan_update) = chan_update {
2688
+ if code == 0x1000 | 11 || code == 0x1000 | 12 {
2689
+ msg. amount_msat . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2690
+ }
2691
+ else if code == 0x1000 | 13 {
2692
+ msg. cltv_expiry . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2693
+ }
2694
+ else if code == 0x1000 | 20 {
2695
+ // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
2696
+ 0u16 . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2697
+ }
2698
+ ( chan_update. serialized_length ( ) as u16 + 2 ) . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2699
+ msgs:: ChannelUpdate :: TYPE . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2700
+ chan_update. write ( & mut res) . expect ( "Writes cannot fail" ) ;
2701
+ } else if code & 0x1000 == 0x1000 {
2702
+ // If we're trying to return an error that requires a `channel_update` but
2703
+ // we're forwarding to a phantom or intercept "channel" (i.e. cannot
2704
+ // generate an update), just use the generic "temporary_node_failure"
2705
+ // instead.
2706
+ code = 0x2000 | 2 ;
2707
+ }
2708
+ return_err ! ( err, code, & res. 0 [ ..] ) ;
2709
+ }
2710
+ Ok ( ( next_hop, shared_secret) )
2711
+ }
2712
+
2713
+ fn construct_pending_htlc_info < ' a > (
2714
+ & self , msg : & msgs:: UpdateAddHTLC , shared_secret : [ u8 ; 32 ] , decoded_hop : onion_utils:: Hop ,
2715
+ ) -> PendingHTLCStatus {
2716
+ macro_rules! return_err {
2717
+ ( $msg: expr, $err_code: expr, $data: expr) => {
2718
+ {
2719
+ log_info!( self . logger, "Failed to accept/forward incoming HTLC: {}" , $msg) ;
2720
+ return PendingHTLCStatus :: Fail ( HTLCFailureMsg :: Relay ( msgs:: UpdateFailHTLC {
2721
+ channel_id: msg. channel_id,
2722
+ htlc_id: msg. htlc_id,
2723
+ reason: HTLCFailReason :: reason( $err_code, $data. to_vec( ) )
2724
+ . get_encrypted_failure_packet( & shared_secret, & None ) ,
2725
+ } ) ) ;
2726
+ }
2727
+ }
2728
+ }
2729
+ match decoded_hop {
2562
2730
onion_utils:: Hop :: Receive ( next_hop_data) => {
2563
2731
// OUR PAYMENT!
2564
2732
match self . construct_recv_pending_htlc_info ( next_hop_data, shared_secret, msg. payment_hash , msg. amount_msat , msg. cltv_expiry , None ) {
@@ -2600,148 +2768,7 @@ where
2600
2768
outgoing_cltv_value : next_hop_data. outgoing_cltv_value ,
2601
2769
} )
2602
2770
}
2603
- } ;
2604
-
2605
- if let & PendingHTLCStatus :: Forward ( PendingHTLCInfo { ref routing, ref outgoing_amt_msat, ref outgoing_cltv_value, .. } ) = & pending_forward_info {
2606
- // If short_channel_id is 0 here, we'll reject the HTLC as there cannot be a channel
2607
- // with a short_channel_id of 0. This is important as various things later assume
2608
- // short_channel_id is non-0 in any ::Forward.
2609
- if let & PendingHTLCRouting :: Forward { ref short_channel_id, .. } = routing {
2610
- if let Some ( ( err, mut code, chan_update) ) = loop {
2611
- let id_option = self . short_to_chan_info . read ( ) . unwrap ( ) . get ( short_channel_id) . cloned ( ) ;
2612
- let forwarding_chan_info_opt = match id_option {
2613
- None => { // unknown_next_peer
2614
- // Note that this is likely a timing oracle for detecting whether an scid is a
2615
- // phantom or an intercept.
2616
- if ( self . default_configuration . accept_intercept_htlcs &&
2617
- fake_scid:: is_valid_intercept ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash ) ) ||
2618
- fake_scid:: is_valid_phantom ( & self . fake_scid_rand_bytes , * short_channel_id, & self . genesis_hash )
2619
- {
2620
- None
2621
- } else {
2622
- break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2623
- }
2624
- } ,
2625
- Some ( ( cp_id, id) ) => Some ( ( cp_id. clone ( ) , id. clone ( ) ) ) ,
2626
- } ;
2627
- let chan_update_opt = if let Some ( ( counterparty_node_id, forwarding_id) ) = forwarding_chan_info_opt {
2628
- let per_peer_state = self . per_peer_state . read ( ) . unwrap ( ) ;
2629
- let peer_state_mutex_opt = per_peer_state. get ( & counterparty_node_id) ;
2630
- if peer_state_mutex_opt. is_none ( ) {
2631
- break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2632
- }
2633
- let mut peer_state_lock = peer_state_mutex_opt. unwrap ( ) . lock ( ) . unwrap ( ) ;
2634
- let peer_state = & mut * peer_state_lock;
2635
- let chan = match peer_state. channel_by_id . get_mut ( & forwarding_id) {
2636
- None => {
2637
- // Channel was removed. The short_to_chan_info and channel_by_id maps
2638
- // have no consistency guarantees.
2639
- break Some ( ( "Don't have available channel for forwarding as requested." , 0x4000 | 10 , None ) ) ;
2640
- } ,
2641
- Some ( chan) => chan
2642
- } ;
2643
- if !chan. should_announce ( ) && !self . default_configuration . accept_forwards_to_priv_channels {
2644
- // Note that the behavior here should be identical to the above block - we
2645
- // should NOT reveal the existence or non-existence of a private channel if
2646
- // we don't allow forwards outbound over them.
2647
- break Some ( ( "Refusing to forward to a private channel based on our config." , 0x4000 | 10 , None ) ) ;
2648
- }
2649
- if chan. get_channel_type ( ) . supports_scid_privacy ( ) && * short_channel_id != chan. outbound_scid_alias ( ) {
2650
- // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
2651
- // "refuse to forward unless the SCID alias was used", so we pretend
2652
- // we don't have the channel here.
2653
- break Some ( ( "Refusing to forward over real channel SCID as our counterparty requested." , 0x4000 | 10 , None ) ) ;
2654
- }
2655
- let chan_update_opt = self . get_channel_update_for_onion ( * short_channel_id, chan) . ok ( ) ;
2656
-
2657
- // Note that we could technically not return an error yet here and just hope
2658
- // that the connection is reestablished or monitor updated by the time we get
2659
- // around to doing the actual forward, but better to fail early if we can and
2660
- // hopefully an attacker trying to path-trace payments cannot make this occur
2661
- // on a small/per-node/per-channel scale.
2662
- if !chan. is_live ( ) { // channel_disabled
2663
- // If the channel_update we're going to return is disabled (i.e. the
2664
- // peer has been disabled for some time), return `channel_disabled`,
2665
- // otherwise return `temporary_channel_failure`.
2666
- if chan_update_opt. as_ref ( ) . map ( |u| u. contents . flags & 2 == 2 ) . unwrap_or ( false ) {
2667
- break Some ( ( "Forwarding channel has been disconnected for some time." , 0x1000 | 20 , chan_update_opt) ) ;
2668
- } else {
2669
- break Some ( ( "Forwarding channel is not in a ready state." , 0x1000 | 7 , chan_update_opt) ) ;
2670
- }
2671
- }
2672
- if * outgoing_amt_msat < chan. get_counterparty_htlc_minimum_msat ( ) { // amount_below_minimum
2673
- break Some ( ( "HTLC amount was below the htlc_minimum_msat" , 0x1000 | 11 , chan_update_opt) ) ;
2674
- }
2675
- if let Err ( ( err, code) ) = chan. htlc_satisfies_config ( & msg, * outgoing_amt_msat, * outgoing_cltv_value) {
2676
- break Some ( ( err, code, chan_update_opt) ) ;
2677
- }
2678
- chan_update_opt
2679
- } else {
2680
- if ( msg. cltv_expiry as u64 ) < ( * outgoing_cltv_value) as u64 + MIN_CLTV_EXPIRY_DELTA as u64 {
2681
- // We really should set `incorrect_cltv_expiry` here but as we're not
2682
- // forwarding over a real channel we can't generate a channel_update
2683
- // for it. Instead we just return a generic temporary_node_failure.
2684
- break Some ( (
2685
- "Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta" ,
2686
- 0x2000 | 2 , None ,
2687
- ) ) ;
2688
- }
2689
- None
2690
- } ;
2691
-
2692
- let cur_height = self . best_block . read ( ) . unwrap ( ) . height ( ) + 1 ;
2693
- // Theoretically, channel counterparty shouldn't send us a HTLC expiring now,
2694
- // but we want to be robust wrt to counterparty packet sanitization (see
2695
- // HTLC_FAIL_BACK_BUFFER rationale).
2696
- if msg. cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon
2697
- break Some ( ( "CLTV expiry is too close" , 0x1000 | 14 , chan_update_opt) ) ;
2698
- }
2699
- if msg. cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far
2700
- break Some ( ( "CLTV expiry is too far in the future" , 21 , None ) ) ;
2701
- }
2702
- // If the HTLC expires ~now, don't bother trying to forward it to our
2703
- // counterparty. They should fail it anyway, but we don't want to bother with
2704
- // the round-trips or risk them deciding they definitely want the HTLC and
2705
- // force-closing to ensure they get it if we're offline.
2706
- // We previously had a much more aggressive check here which tried to ensure
2707
- // our counterparty receives an HTLC which has *our* risk threshold met on it,
2708
- // but there is no need to do that, and since we're a bit conservative with our
2709
- // risk threshold it just results in failing to forward payments.
2710
- if ( * outgoing_cltv_value) as u64 <= ( cur_height + LATENCY_GRACE_PERIOD_BLOCKS ) as u64 {
2711
- break Some ( ( "Outgoing CLTV value is too soon" , 0x1000 | 14 , chan_update_opt) ) ;
2712
- }
2713
-
2714
- break None ;
2715
- }
2716
- {
2717
- let mut res = VecWriter ( Vec :: with_capacity ( chan_update. serialized_length ( ) + 2 + 8 + 2 ) ) ;
2718
- if let Some ( chan_update) = chan_update {
2719
- if code == 0x1000 | 11 || code == 0x1000 | 12 {
2720
- msg. amount_msat . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2721
- }
2722
- else if code == 0x1000 | 13 {
2723
- msg. cltv_expiry . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2724
- }
2725
- else if code == 0x1000 | 20 {
2726
- // TODO: underspecified, follow https://github.com/lightning/bolts/issues/791
2727
- 0u16 . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2728
- }
2729
- ( chan_update. serialized_length ( ) as u16 + 2 ) . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2730
- msgs:: ChannelUpdate :: TYPE . write ( & mut res) . expect ( "Writes cannot fail" ) ;
2731
- chan_update. write ( & mut res) . expect ( "Writes cannot fail" ) ;
2732
- } else if code & 0x1000 == 0x1000 {
2733
- // If we're trying to return an error that requires a `channel_update` but
2734
- // we're forwarding to a phantom or intercept "channel" (i.e. cannot
2735
- // generate an update), just use the generic "temporary_node_failure"
2736
- // instead.
2737
- code = 0x2000 | 2 ;
2738
- }
2739
- return_err ! ( err, code, & res. 0 [ ..] ) ;
2740
- }
2741
- }
2742
2771
}
2743
-
2744
- pending_forward_info
2745
2772
}
2746
2773
2747
2774
/// Gets the current [`channel_update`] for the given channel. This first checks if the channel is
@@ -5258,7 +5285,7 @@ where
5258
5285
//encrypted with the same key. It's not immediately obvious how to usefully exploit that,
5259
5286
//but we should prevent it anyway.
5260
5287
5261
- let pending_forward_info = self . decode_update_add_htlc_onion ( msg) ;
5288
+ let decoded_hop_res = self . decode_update_add_htlc_onion ( msg) ;
5262
5289
let per_peer_state = self . per_peer_state . read ( ) . unwrap ( ) ;
5263
5290
let peer_state_mutex = per_peer_state. get ( counterparty_node_id)
5264
5291
. ok_or_else ( || {
@@ -5270,6 +5297,11 @@ where
5270
5297
match peer_state. channel_by_id . entry ( msg. channel_id ) {
5271
5298
hash_map:: Entry :: Occupied ( mut chan) => {
5272
5299
5300
+ let pending_forward_info = match decoded_hop_res {
5301
+ Ok ( ( next_hop, shared_secret) ) =>
5302
+ self . construct_pending_htlc_info ( msg, shared_secret, next_hop) ,
5303
+ Err ( e) => PendingHTLCStatus :: Fail ( e)
5304
+ } ;
5273
5305
let create_pending_htlc_status = |chan : & Channel < <SP :: Target as SignerProvider >:: Signer > , pending_forward_info : PendingHTLCStatus , error_code : u16 | {
5274
5306
// If the update_add is completely bogus, the call will Err and we will close,
5275
5307
// but if we've sent a shutdown and they haven't acknowledged it yet, we just
0 commit comments