@@ -3020,6 +3020,48 @@ where
3020
3020
}
3021
3021
}
3022
3022
3023
+ fn can_accept_htlc(
3024
+ &self, chan: &mut Channel<SP>, msg: &msgs::UpdateAddHTLC, next_packet: &NextPacketDetails
3025
+ ) -> Result<Option<msgs::ChannelUpdate>, (&'static str, u16, Option<msgs::ChannelUpdate>)> {
3026
+ if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
3027
+ // Note that the behavior here should be identical to the above block - we
3028
+ // should NOT reveal the existence or non-existence of a private channel if
3029
+ // we don't allow forwards outbound over them.
3030
+ return Err(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
3031
+ }
3032
+ if chan.context.get_channel_type().supports_scid_privacy() && next_packet.outgoing_scid != chan.context.outbound_scid_alias() {
3033
+ // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
3034
+ // "refuse to forward unless the SCID alias was used", so we pretend
3035
+ // we don't have the channel here.
3036
+ return Err(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
3037
+ }
3038
+ let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
3039
+
3040
+ // Note that we could technically not return an error yet here and just hope
3041
+ // that the connection is reestablished or monitor updated by the time we get
3042
+ // around to doing the actual forward, but better to fail early if we can and
3043
+ // hopefully an attacker trying to path-trace payments cannot make this occur
3044
+ // on a small/per-node/per-channel scale.
3045
+ if !chan.context.is_live() { // channel_disabled
3046
+ // If the channel_update we're going to return is disabled (i.e. the
3047
+ // peer has been disabled for some time), return `channel_disabled`,
3048
+ // otherwise return `temporary_channel_failure`.
3049
+ if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
3050
+ return Err(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
3051
+ } else {
3052
+ return Err(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
3053
+ }
3054
+ }
3055
+ if next_packet.outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
3056
+ return Err(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
3057
+ }
3058
+ if let Err((err, code)) = chan.htlc_satisfies_config(msg, next_packet.outgoing_amt_msat, next_packet.outgoing_cltv_value) {
3059
+ return Err((err, code, chan_update_opt));
3060
+ }
3061
+
3062
+ Ok(chan_update_opt)
3063
+ }
3064
+
3023
3065
fn process_failed_accept_err(
3024
3066
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
3025
3067
mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_forward: bool,
@@ -3093,9 +3135,7 @@ where
3093
3135
_ => false,
3094
3136
};
3095
3137
3096
- let NextPacketDetails {
3097
- next_packet_pubkey, outgoing_amt_msat, outgoing_scid, outgoing_cltv_value
3098
- } = match next_packet_details_opt {
3138
+ let next_packet_details = match next_packet_details_opt {
3099
3139
Some(next_packet_details) => next_packet_details,
3100
3140
// it is a receive, so no need for outbound checks
3101
3141
None => return Ok((next_hop, shared_secret, None)),
@@ -3104,14 +3144,14 @@ where
3104
3144
// Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
3105
3145
// can't hold the outbound peer state lock at the same time as the inbound peer state lock.
3106
3146
if let Some((err, code, chan_update)) = loop {
3107
- let id_option = self.short_to_chan_info.read().unwrap().get(&outgoing_scid).cloned();
3147
+ let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details. outgoing_scid).cloned();
3108
3148
let forwarding_chan_info_opt = match id_option {
3109
3149
None => { // unknown_next_peer
3110
3150
// Note that this is likely a timing oracle for detecting whether an scid is a
3111
3151
// phantom or an intercept.
3112
3152
if (self.default_configuration.accept_intercept_htlcs &&
3113
- fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)) ||
3114
- fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)
3153
+ fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details. outgoing_scid, &self.chain_hash)) ||
3154
+ fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details. outgoing_scid, &self.chain_hash)
3115
3155
{
3116
3156
None
3117
3157
} else {
@@ -3138,50 +3178,18 @@ where
3138
3178
},
3139
3179
Some(chan) => chan
3140
3180
};
3141
- if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
3142
- // Note that the behavior here should be identical to the above block - we
3143
- // should NOT reveal the existence or non-existence of a private channel if
3144
- // we don't allow forwards outbound over them.
3145
- break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
3146
- }
3147
- if chan.context.get_channel_type().supports_scid_privacy() && outgoing_scid != chan.context.outbound_scid_alias() {
3148
- // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
3149
- // "refuse to forward unless the SCID alias was used", so we pretend
3150
- // we don't have the channel here.
3151
- break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
3152
- }
3153
- let chan_update_opt = self.get_channel_update_for_onion(outgoing_scid, chan).ok();
3154
-
3155
- // Note that we could technically not return an error yet here and just hope
3156
- // that the connection is reestablished or monitor updated by the time we get
3157
- // around to doing the actual forward, but better to fail early if we can and
3158
- // hopefully an attacker trying to path-trace payments cannot make this occur
3159
- // on a small/per-node/per-channel scale.
3160
- if !chan.context.is_live() { // channel_disabled
3161
- // If the channel_update we're going to return is disabled (i.e. the
3162
- // peer has been disabled for some time), return `channel_disabled`,
3163
- // otherwise return `temporary_channel_failure`.
3164
- if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
3165
- break Some(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
3166
- } else {
3167
- break Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
3168
- }
3169
- }
3170
- if outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
3171
- break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
3172
- }
3173
- if let Err((err, code)) = chan.htlc_satisfies_config(&msg, outgoing_amt_msat, outgoing_cltv_value) {
3174
- break Some((err, code, chan_update_opt));
3181
+ match self.can_accept_htlc(chan, msg, &next_packet_details) {
3182
+ Ok(chan_update_opt) => chan_update_opt,
3183
+ Err(e) => break Some(e),
3175
3184
}
3176
- chan_update_opt
3177
3185
} else {
3178
3186
None
3179
3187
};
3180
3188
3181
3189
let cur_height = self.best_block.read().unwrap().height() + 1;
3182
3190
3183
3191
if let Err((err_msg, code)) = check_incoming_htlc_cltv(
3184
- cur_height, outgoing_cltv_value, msg.cltv_expiry
3192
+ cur_height, next_packet_details. outgoing_cltv_value, msg.cltv_expiry
3185
3193
) {
3186
3194
if code & 0x1000 != 0 && chan_update_opt.is_none() {
3187
3195
// We really should set `incorrect_cltv_expiry` here but as we're not
@@ -3200,7 +3208,7 @@ where
3200
3208
msg, counterparty_node_id, err, code, chan_update, is_intro_node_forward, &shared_secret
3201
3209
));
3202
3210
}
3203
- Ok((next_hop, shared_secret, Some(next_packet_pubkey)))
3211
+ Ok((next_hop, shared_secret, Some(next_packet_details. next_packet_pubkey)))
3204
3212
}
3205
3213
3206
3214
fn construct_pending_htlc_status<'a>(
0 commit comments