Skip to content

Commit

Permalink
Correctly handle any UPDATE errors to phandom invoices
Browse files Browse the repository at this point in the history
If we try to send any onion error with the `UPDATE` flag in
response to a phantom receipt, we should always swap it for
something generic that doesn't require a `channel_update` in it.
Here we use `temporary_node_failure`.

Test provided by Valentine Wallace <[email protected]>
  • Loading branch information
TheBlueMatt committed Dec 2, 2022
1 parent af89d18 commit a663ab2
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
7 changes: 6 additions & 1 deletion lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2222,7 +2222,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
// with a short_channel_id of 0. This is important as various things later assume
// short_channel_id is non-0 in any ::Forward.
if let &PendingHTLCRouting::Forward { ref short_channel_id, .. } = routing {
if let Some((err, code, chan_update)) = loop {
if let Some((err, mut code, chan_update)) = loop {
let id_option = self.short_to_chan_info.read().unwrap().get(&short_channel_id).cloned();
let mut channel_state = self.channel_state.lock().unwrap();
let forwarding_id_opt = match id_option {
Expand Down Expand Up @@ -2331,6 +2331,11 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
(chan_update.serialized_length() as u16 + 2).write(&mut res).expect("Writes cannot fail");
msgs::ChannelUpdate::TYPE.write(&mut res).expect("Writes cannot fail");
chan_update.write(&mut res).expect("Writes cannot fail");
} else if code & 0x1000 == 0x1000 {
// If we're trying to return an error that requires a `channel_update` but
// we're forwarding to a phantom "channel" (i.e. cannot generate an
// update), just use the generic "temporary_node_failure" instead.
code = 0x2000 | 2;
}
return_err!(err, code, &res.0[..]);
}
Expand Down
39 changes: 39 additions & 0 deletions lightning/src/ln/onion_route_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,45 @@ fn test_phantom_failure_modified_cltv() {
expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
}

#[test]
fn test_phantom_failure_expires_too_soon() {
// Test that we fail back phantoms if the HTLC got delayed and we got blocks in between with
// the correct error code.
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);

let channel = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());

// Get the route.
let recv_value_msat = 10_000;
let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(nodes[1], Some(recv_value_msat));
let (mut route, phantom_scid) = get_phantom_route!(nodes, recv_value_msat, channel);

// Route the HTLC through to the destination.
nodes[0].node.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)).unwrap();
check_added_monitors!(nodes[0], 1);
let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
let mut update_add = update_0.update_add_htlcs[0].clone();

connect_blocks(&nodes[1], CLTV_FAR_FAR_AWAY);
nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add);
commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true);

let update_1 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
assert!(update_1.update_fail_htlcs.len() == 1);
let fail_msg = update_1.update_fail_htlcs[0].clone();
nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg);
commitment_signed_dance!(nodes[0], nodes[1], update_1.commitment_signed, false);

// Ensure the payment fails with the expected error.
let mut fail_conditions = PaymentFailedConditions::new()
.blamed_scid(phantom_scid)
.expected_htlc_error_data(0x2000 | 2, &[]);
expect_payment_failed_conditions(&nodes[0], payment_hash, false, fail_conditions);
}

#[test]
fn test_phantom_failure_too_low_recv_amt() {
let chanmon_cfgs = create_chanmon_cfgs(2);
Expand Down

0 comments on commit a663ab2

Please sign in to comment.