Skip to content

Commit 0b355fc

Browse files
committed
Refactor decode_update_add_htlc_onion to avoid doing channel lookups
This allows callers to use the method on a specific channel when the `per_peer_state` locks have already been acquired. This will become helpful later on when we move to decoding incoming HTLC onions once the HTLC has been fully committed to by both sides.
1 parent d718096 commit 0b355fc

File tree

1 file changed

+76
-70
lines changed

1 file changed

+76
-70
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 76 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3062,6 +3062,49 @@ where
30623062
Ok(chan_update_opt)
30633063
}
30643064

3065+
fn find_channel_and_process_accept(
3066+
&self, msg: &msgs::UpdateAddHTLC, next_packet_details: &NextPacketDetails
3067+
) -> Result<Option<msgs::ChannelUpdate>, (&'static str, u16, Option<msgs::ChannelUpdate>)> {
3068+
let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details.outgoing_scid).cloned();
3069+
let forwarding_chan_info_opt = match id_option {
3070+
None => { // unknown_next_peer
3071+
// Note that this is likely a timing oracle for detecting whether an scid is a
3072+
// phantom or an intercept.
3073+
if (self.default_configuration.accept_intercept_htlcs &&
3074+
fake_scid::is_valid_intercept(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)) ||
3075+
fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, next_packet_details.outgoing_scid, &self.chain_hash)
3076+
{
3077+
None
3078+
} else {
3079+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3080+
}
3081+
},
3082+
Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
3083+
};
3084+
if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
3085+
let per_peer_state = self.per_peer_state.read().unwrap();
3086+
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
3087+
if peer_state_mutex_opt.is_none() {
3088+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3089+
}
3090+
let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
3091+
let peer_state = &mut *peer_state_lock;
3092+
let chan = match peer_state.channel_by_id.get_mut(&forwarding_id).map(
3093+
|chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
3094+
).flatten() {
3095+
None => {
3096+
// Channel was removed. The short_to_chan_info and channel_by_id maps
3097+
// have no consistency guarantees.
3098+
return Err(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3099+
},
3100+
Some(chan) => chan,
3101+
};
3102+
self.can_accept_htlc(chan, msg, next_packet_details)
3103+
} else {
3104+
Ok(None)
3105+
}
3106+
}
3107+
30653108
fn process_failed_accept_err(
30663109
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, err_msg: &'static str,
30673110
mut err_code: u16, chan_update: Option<msgs::ChannelUpdate>, is_intro_node_forward: bool,
@@ -3118,14 +3161,20 @@ where
31183161
}
31193162

31203163
fn decode_update_add_htlc_onion(
3121-
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey,
3164+
&self, msg: &msgs::UpdateAddHTLC, counterparty_node_id: &PublicKey, channel: Option<&mut Channel<SP>>,
31223165
) -> Result<
31233166
(onion_utils::Hop, [u8; 32], Option<Result<PublicKey, secp256k1::Error>>), HTLCFailureMsg
31243167
> {
31253168
let (next_hop, shared_secret, next_packet_details_opt) = decode_incoming_update_add_htlc_onion(
31263169
msg, &self.node_signer, &self.logger, &self.secp_ctx
31273170
)?;
31283171

3172+
let next_packet_details = match next_packet_details_opt {
3173+
Some(next_packet_details) => next_packet_details,
3174+
// it is a receive, so no need for outbound checks
3175+
None => return Ok((next_hop, shared_secret, None)),
3176+
};
3177+
31293178
let is_intro_node_forward = match next_hop {
31303179
onion_utils::Hop::Forward {
31313180
next_hop_data: msgs::InboundOnionPayload::BlindedForward {
@@ -3135,79 +3184,36 @@ where
31353184
_ => false,
31363185
};
31373186

3138-
let next_packet_details = match next_packet_details_opt {
3139-
Some(next_packet_details) => next_packet_details,
3140-
// it is a receive, so no need for outbound checks
3141-
None => return Ok((next_hop, shared_secret, None)),
3187+
let fail_msg_from_err = |err_msg: &'static str, err_code: u16, chan_update: Option<msgs::ChannelUpdate>| {
3188+
self.process_failed_accept_err(msg, counterparty_node_id, err_msg, err_code, chan_update, is_intro_node_forward, &shared_secret)
31423189
};
31433190

3144-
// Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
3145-
// can't hold the outbound peer state lock at the same time as the inbound peer state lock.
3146-
if let Some((err, code, chan_update)) = loop {
3147-
let id_option = self.short_to_chan_info.read().unwrap().get(&next_packet_details.outgoing_scid).cloned();
3148-
let forwarding_chan_info_opt = match id_option {
3149-
None => { // unknown_next_peer
3150-
// Note that this is likely a timing oracle for detecting whether an scid is a
3151-
// phantom or an intercept.
3152-
if (self.default_configuration.accept_intercept_htlcs &&
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)
3155-
{
3156-
None
3157-
} else {
3158-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3159-
}
3160-
},
3161-
Some((cp_id, id)) => Some((cp_id.clone(), id.clone())),
3162-
};
3163-
let chan_update_opt = if let Some((counterparty_node_id, forwarding_id)) = forwarding_chan_info_opt {
3164-
let per_peer_state = self.per_peer_state.read().unwrap();
3165-
let peer_state_mutex_opt = per_peer_state.get(&counterparty_node_id);
3166-
if peer_state_mutex_opt.is_none() {
3167-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3168-
}
3169-
let mut peer_state_lock = peer_state_mutex_opt.unwrap().lock().unwrap();
3170-
let peer_state = &mut *peer_state_lock;
3171-
let chan = match peer_state.channel_by_id.get_mut(&forwarding_id).map(
3172-
|chan_phase| if let ChannelPhase::Funded(chan) = chan_phase { Some(chan) } else { None }
3173-
).flatten() {
3174-
None => {
3175-
// Channel was removed. The short_to_chan_info and channel_by_id maps
3176-
// have no consistency guarantees.
3177-
break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
3178-
},
3179-
Some(chan) => chan
3180-
};
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),
3184-
}
3185-
} else {
3186-
None
3187-
};
3188-
3189-
let cur_height = self.best_block.read().unwrap().height() + 1;
3191+
let res = if let Some(channel) = channel {
3192+
self.can_accept_htlc(channel, msg, &next_packet_details)
3193+
} else {
3194+
// Perform outbound checks here instead of in [`Self::construct_pending_htlc_info`] because we
3195+
// can't hold the outbound peer state lock at the same time as the inbound peer state lock.
3196+
self.find_channel_and_process_accept(msg, &next_packet_details)
3197+
};
3198+
let chan_update_opt = match res {
3199+
Ok(chan_update_opt) => chan_update_opt,
3200+
Err((err_msg, err_code, chan_update)) => return Err(fail_msg_from_err(err_msg, err_code, chan_update)),
3201+
};
31903202

3191-
if let Err((err_msg, code)) = check_incoming_htlc_cltv(
3192-
cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
3193-
) {
3194-
if code & 0x1000 != 0 && chan_update_opt.is_none() {
3195-
// We really should set `incorrect_cltv_expiry` here but as we're not
3196-
// forwarding over a real channel we can't generate a channel_update
3197-
// for it. Instead we just return a generic temporary_node_failure.
3198-
break Some((err_msg, 0x2000 | 2, None))
3199-
}
3200-
let chan_update_opt = if code & 0x1000 != 0 { chan_update_opt } else { None };
3201-
break Some((err_msg, code, chan_update_opt));
3203+
let cur_height = self.best_block.read().unwrap().height() + 1;
3204+
if let Err((err_msg, err_code)) = check_incoming_htlc_cltv(
3205+
cur_height, next_packet_details.outgoing_cltv_value, msg.cltv_expiry
3206+
) {
3207+
if err_code & 0x1000 != 0 && chan_update_opt.is_none() {
3208+
// We really should set `incorrect_cltv_expiry` here but as we're not
3209+
// forwarding over a real channel we can't generate a channel_update
3210+
// for it. Instead we just return a generic temporary_node_failure.
3211+
return Err(fail_msg_from_err(err_msg, 0x2000 | 2, None));
32023212
}
3203-
3204-
break None;
3205-
}
3206-
{
3207-
return Err(self.process_failed_accept_err(
3208-
msg, counterparty_node_id, err, code, chan_update, is_intro_node_forward, &shared_secret
3209-
));
3213+
let chan_update_opt = if err_code & 0x1000 != 0 { chan_update_opt } else { None };
3214+
return Err(fail_msg_from_err(err_msg, err_code, chan_update_opt));
32103215
}
3216+
32113217
Ok((next_hop, shared_secret, Some(next_packet_details.next_packet_pubkey)))
32123218
}
32133219

@@ -6655,7 +6661,7 @@ where
66556661
// Note that the ChannelManager is NOT re-persisted on disk after this (unless we error
66566662
// closing a channel), so any changes are likely to be lost on restart!
66576663

6658-
let decoded_hop_res = self.decode_update_add_htlc_onion(msg, counterparty_node_id);
6664+
let decoded_hop_res = self.decode_update_add_htlc_onion(msg, counterparty_node_id, None);
66596665
let per_peer_state = self.per_peer_state.read().unwrap();
66606666
let peer_state_mutex = per_peer_state.get(counterparty_node_id)
66616667
.ok_or_else(|| {

0 commit comments

Comments
 (0)