Skip to content

Commit 8c7346d

Browse files
committed
Refactor outgoing channel lookup out from decode_update_add_htlc_onion
In the future, we plan to complete remove `decode_update_add_htlc_onion` and replace it with a batched variant. This refactor, while improving readability in its current form, does not feature any functional changes and allows us to reuse most of the logic in the batched variant.
1 parent bcd5a96 commit 8c7346d

File tree

1 file changed

+67
-64
lines changed

1 file changed

+67
-64
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,6 +3133,66 @@ where
31333133
Ok(chan_update_opt)
31343134
}
31353135

3136+
fn can_forward_htlc(
3137+
&self, msg: &msgs::UpdateAddHTLC, next_packet_details: &NextPacketDetails
3138+
) -> Result<Option<msgs::ChannelUpdate>, (&'static str, u16, Option<msgs::ChannelUpdate>)> {
3139+
let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details.outgoing_scid).cloned();
3140+
let forwarding_chan_info_opt = match id_option {
3141+
None => { // unknown_next_peer
3142+
// Note that this is likely a timing oracle for detecting whether an scid is a
3143+
// phantom or an intercept.
3144+
if (self.default_configuration.accept_intercept_htlcs &&
3145+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)) ||
3146+
fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)
3147+
{
3148+
None
3149+
} else {
3150+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3151+
}
3152+
},
3153+
Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
3154+
};
3155+
3156+
let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
3157+
let per_peer_state = self.per_peer_state.read().unwrap();
3158+
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
3159+
if peer_state_mutex_opt.is_none() {
3160+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3161+
}
3162+
let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
3163+
let peer_state = &mut *peer_state_lock;
3164+
let chan = match peer_state.channel_by_id.get_mut(&forwarding_id).map(
3165+
|chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
3166+
).flatten() {
3167+
None => {
3168+
// Channel was removed. The short_to_chan_info and channel_by_id maps
3169+
// have no consistency guarantees.
3170+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3171+
},
3172+
Some(chan) => chan,
3173+
};
3174+
self.can_forward_htlc_to_outgoing_channel(chan, msg, next_packet_details)?
3175+
} else {
3176+
None
3177+
};
3178+
3179+
let cur_height = self.best_block.read().unwrap().height + 1;
3180+
if let Err((err_msg, err_code)) = check_incoming_htlc_cltv(
3181+
cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
3182+
) {
3183+
if err_code & 0x1000 != 0 && chan_update_opt.is_none() {
3184+
// We really should set `incorrect_cltv_expiry` here but as we're not
3185+
// forwarding over a real channel we can't generate a channel_update
3186+
// for it. Instead we just return a generic temporary_node_failure.
3187+
return Err((err_msg, 0x2000 | 2, None));
3188+
}
3189+
let chan_update_opt = if err_code & 0x1000 != 0 { chan_update_opt } else { None };
3190+
return Err((err_msg, err_code, chan_update_opt));
3191+
}
3192+
3193+
Ok(chan_update_opt)
3194+
}
3195+
31363196
fn htlc_failure_from_update_add_err(
31373197
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
31383198
mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_forward: bool,
@@ -3205,71 +3265,14 @@ where
32053265

32063266
// Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
32073267
// can't hold the outbound peer state lock at the same time as the inbound peer state lock.
3208-
if let Some((err, code, chan_update)) = loop {
3209-
let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details.outgoing_scid).cloned();
3210-
let forwarding_chan_info_opt = match id_option {
3211-
None => { // unknown_next_peer
3212-
// Note that this is likely a timing oracle for detecting whether an scid is a
3213-
// phantom or an intercept.
3214-
if (self.default_configuration.accept_intercept_htlcs &&
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)
3217-
{
3218-
None
3219-
} else {
3220-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3221-
}
3222-
},
3223-
Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
3224-
};
3225-
let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
3226-
let per_peer_state = self.per_peer_state.read().unwrap();
3227-
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
3228-
if peer_state_mutex_opt.is_none() {
3229-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3230-
}
3231-
let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
3232-
let peer_state = &mut *peer_state_lock;
3233-
let chan = match peer_state.channel_by_id.get_mut(&forwarding_id).map(
3234-
|chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
3235-
).flatten() {
3236-
None => {
3237-
// Channel was removed. The short_to_chan_info and channel_by_id maps
3238-
// have no consistency guarantees.
3239-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3240-
},
3241-
Some(chan) => chan
3242-
};
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),
3246-
}
3247-
} else {
3248-
None
3249-
};
3250-
3251-
let cur_height = self.best_block.read().unwrap().height + 1;
3252-
3253-
if let Err((err_msg, code)) = check_incoming_htlc_cltv(
3254-
cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
3255-
) {
3256-
if code & 0x1000 != 0 && chan_update_opt.is_none() {
3257-
// We really should set `incorrect_cltv_expiry` here but as we're not
3258-
// forwarding over a real channel we can't generate a channel_update
3259-
// for it. Instead we just return a generic temporary_node_failure.
3260-
break Some((err_msg, 0x2000 | 2, None))
3261-
}
3262-
let chan_update_opt = if code & 0x1000 != 0 { chan_update_opt } else { None };
3263-
break Some((err_msg, code, chan_update_opt));
3264-
}
3268+
let _ = self.can_forward_htlc(&msg, &next_packet_details).map_err(|e| {
3269+
let (err_msg, err_code, chan_update_opt) = e;
3270+
self.htlc_failure_from_update_add_err(
3271+
msg, counterparty_node_id, err_msg, err_code, chan_update_opt,
3272+
next_hop.is_intro_node_forward(), &shared_secret
3273+
)
3274+
})?;
32653275

3266-
break None;
3267-
}
3268-
{
3269-
return Err(self.htlc_failure_from_update_add_err(
3270-
msg, counterparty_node_id, err, code, chan_update, next_hop.is_intro_node_forward(), &shared_secret
3271-
));
3272-
}
32733276
Ok((next_hop, shared_secret, Some(next_packet_details.next_packet_pubkey)))
32743277
}
32753278

0 commit comments

Comments
 (0)