@@ -3091,6 +3091,48 @@ where
30913091 }
30923092 }
30933093
3094+ fn can_forward_htlc_to_outgoing_channel(
3095+ &self, chan: &mut Channel<SP>, msg: &msgs::UpdateAddHTLC, next_packet: &NextPacketDetails
3096+ ) -> Result<Option<msgs::ChannelUpdate>, (&'static str, u16, Option<msgs::ChannelUpdate>)> {
3097+ if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
3098+ // Note that the behavior here should be identical to the above block - we
3099+ // should NOT reveal the existence or non-existence of a private channel if
3100+ // we don't allow forwards outbound over them.
3101+ return Err(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
3102+ }
3103+ if chan.context.get_channel_type().supports_scid_privacy() && next_packet.outgoing_scid != chan.context.outbound_scid_alias() {
3104+ // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
3105+ // "refuse to forward unless the SCID alias was used", so we pretend
3106+ // we don't have the channel here.
3107+ return Err(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
3108+ }
3109+ let chan_update_opt = self.get_channel_update_for_onion(next_packet.outgoing_scid, chan).ok();
3110+
3111+ // Note that we could technically not return an error yet here and just hope
3112+ // that the connection is reestablished or monitor updated by the time we get
3113+ // around to doing the actual forward, but better to fail early if we can and
3114+ // hopefully an attacker trying to path-trace payments cannot make this occur
3115+ // on a small/per-node/per-channel scale.
3116+ if !chan.context.is_live() { // channel_disabled
3117+ // If the channel_update we're going to return is disabled (i.e. the
3118+ // peer has been disabled for some time), return `channel_disabled`,
3119+ // otherwise return `temporary_channel_failure`.
3120+ if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
3121+ return Err(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
3122+ } else {
3123+ return Err(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
3124+ }
3125+ }
3126+ if next_packet.outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
3127+ return Err(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
3128+ }
3129+ if let Err((err, code)) = chan.htlc_satisfies_config(msg, next_packet.outgoing_amt_msat, next_packet.outgoing_cltv_value) {
3130+ return Err((err, code, chan_update_opt));
3131+ }
3132+
3133+ Ok(chan_update_opt)
3134+ }
3135+
30943136 fn htlc_failure_from_update_add_err(
30953137 &self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
30963138 mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_blinded_forward: bool,
@@ -3155,9 +3197,7 @@ where
31553197 msg, &self.node_signer, &self.logger, &self.secp_ctx
31563198 )?;
31573199
3158- let NextPacketDetails {
3159- next_packet_pubkey, outgoing_amt_msat, outgoing_scid, outgoing_cltv_value
3160- } = match next_packet_details_opt {
3200+ let next_packet_details = match next_packet_details_opt {
31613201 Some(next_packet_details) => next_packet_details,
31623202 // it is a receive, so no need for outbound checks
31633203 None => return Ok((next_hop, shared_secret, None)),
@@ -3166,14 +3206,14 @@ where
31663206 // Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
31673207 // can't hold the outbound peer state lock at the same time as the inbound peer state lock.
31683208 if let Some((err, code, chan_update)) = loop {
3169- let id_option = self.short_to_chan_info.read().unwrap().get(&outgoing_scid).cloned();
3209+ let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details. outgoing_scid).cloned();
31703210 let forwarding_chan_info_opt = match id_option {
31713211 None => { // unknown_next_peer
31723212 // Note that this is likely a timing oracle for detecting whether an scid is a
31733213 // phantom or an intercept.
31743214 if (self.default_configuration.accept_intercept_htlcs &&
3175- fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)) ||
3176- fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, outgoing_scid, &self.chain_hash)
3215+ fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details. outgoing_scid, &self.chain_hash)) ||
3216+ fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details. outgoing_scid, &self.chain_hash)
31773217 {
31783218 None
31793219 } else {
@@ -3200,50 +3240,18 @@ where
32003240 },
32013241 Some(chan) => chan
32023242 };
3203- if !chan.context.should_announce() && !self.default_configuration.accept_forwards_to_priv_channels {
3204- // Note that the behavior here should be identical to the above block - we
3205- // should NOT reveal the existence or non-existence of a private channel if
3206- // we don't allow forwards outbound over them.
3207- break Some(("Refusing to forward to a private channel based on our config.", 0x4000 | 10, None));
3208- }
3209- if chan.context.get_channel_type().supports_scid_privacy() && outgoing_scid != chan.context.outbound_scid_alias() {
3210- // `option_scid_alias` (referred to in LDK as `scid_privacy`) means
3211- // "refuse to forward unless the SCID alias was used", so we pretend
3212- // we don't have the channel here.
3213- break Some(("Refusing to forward over real channel SCID as our counterparty requested.", 0x4000 | 10, None));
3214- }
3215- let chan_update_opt = self.get_channel_update_for_onion(outgoing_scid, chan).ok();
3216-
3217- // Note that we could technically not return an error yet here and just hope
3218- // that the connection is reestablished or monitor updated by the time we get
3219- // around to doing the actual forward, but better to fail early if we can and
3220- // hopefully an attacker trying to path-trace payments cannot make this occur
3221- // on a small/per-node/per-channel scale.
3222- if !chan.context.is_live() { // channel_disabled
3223- // If the channel_update we're going to return is disabled (i.e. the
3224- // peer has been disabled for some time), return `channel_disabled`,
3225- // otherwise return `temporary_channel_failure`.
3226- if chan_update_opt.as_ref().map(|u| u.contents.flags & 2 == 2).unwrap_or(false) {
3227- break Some(("Forwarding channel has been disconnected for some time.", 0x1000 | 20, chan_update_opt));
3228- } else {
3229- break Some(("Forwarding channel is not in a ready state.", 0x1000 | 7, chan_update_opt));
3230- }
3231- }
3232- if outgoing_amt_msat < chan.context.get_counterparty_htlc_minimum_msat() { // amount_below_minimum
3233- break Some(("HTLC amount was below the htlc_minimum_msat", 0x1000 | 11, chan_update_opt));
3234- }
3235- if let Err((err, code)) = chan.htlc_satisfies_config(&msg, outgoing_amt_msat, outgoing_cltv_value) {
3236- break Some((err, code, chan_update_opt));
3243+ match self.can_forward_htlc_to_outgoing_channel(chan, msg, &next_packet_details) {
3244+ Ok(chan_update_opt) => chan_update_opt,
3245+ Err(e) => break Some(e),
32373246 }
3238- chan_update_opt
32393247 } else {
32403248 None
32413249 };
32423250
32433251 let cur_height = self.best_block.read().unwrap().height + 1;
32443252
32453253 if let Err((err_msg, code)) = check_incoming_htlc_cltv(
3246- cur_height, outgoing_cltv_value, msg.cltv_expiry
3254+ cur_height, next_packet_details. outgoing_cltv_value, msg.cltv_expiry
32473255 ) {
32483256 if code & 0x1000 != 0 && chan_update_opt.is_none() {
32493257 // We really should set `incorrect_cltv_expiry` here but as we're not
@@ -3262,7 +3270,7 @@ where
32623270 msg, counterparty_node_id, err, code, chan_update, next_hop.is_intro_node_blinded_forward(), &shared_secret
32633271 ));
32643272 }
3265- Ok((next_hop, shared_secret, Some(next_packet_pubkey)))
3273+ Ok((next_hop, shared_secret, Some(next_packet_details. next_packet_pubkey)))
32663274 }
32673275
32683276 fn construct_pending_htlc_status<'a>(
0 commit comments