Skip to content

Commit

Permalink
Test serialization for malformed holding cell HTLCs
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinewallace committed Aug 29, 2023
1 parent 93e718f commit 838c32c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 26 deletions.
68 changes: 51 additions & 17 deletions lightning/src/ln/blinded_payment_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ use crate::ln::outbound_payment::Retry;
use crate::prelude::*;
use crate::routing::router::{PaymentParameters, RouteParameters};
use crate::util::config::UserConfig;
use crate::util::ser::Writeable;
use crate::util::test_utils;

#[test]
fn simple_blinded_payment() {
Expand Down Expand Up @@ -364,13 +366,21 @@ fn min_htlc() {

#[test]
fn fail_blinded_payment() {
do_fail_blinded_payment(true);
do_fail_blinded_payment(false);
}

fn do_fail_blinded_payment(reload: bool) {
let (new_persister, new_chain_monitor, node_3_deserialized);
let chanmon_cfgs = create_chanmon_cfgs(4);
let node_cfgs = create_node_cfgs(4, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]);
let nodes = create_network(4, &node_cfgs, &node_chanmgrs);
let mut nodes = create_network(4, &node_cfgs, &node_chanmgrs);
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 0);
create_announced_chan_between_nodes_with_value(&nodes, 1, 2, 1_000_000, 0);
let chan_upd = create_announced_chan_between_nodes_with_value(&nodes, 2, 3, 1_000_000, 0).0.contents;
let (signed_chan_upd, _, chan_id_2_3, _) = create_announced_chan_between_nodes_with_value(
&nodes, 2, 3, 1_000_000, 500_000_000);
let chan_upd = signed_chan_upd.contents;

let amt_msat = 5000;
let (_, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
Expand Down Expand Up @@ -410,30 +420,54 @@ fn fail_blinded_payment() {
pass_along_route(&nodes[0], &[&[&nodes[1], &nodes[2], &nodes[3]]], amt_msat, payment_hash,
payment_secret);

if reload {
nodes[3].node.peer_disconnected(&nodes[2].node.get_our_node_id());
nodes[2].node.peer_disconnected(&nodes[3].node.get_our_node_id());
}

nodes[3].node.fail_htlc_backwards(&payment_hash);
expect_pending_htlcs_forwardable_conditions(nodes[3].node.get_and_clear_pending_events(),
&[HTLCDestination::FailedPayment { payment_hash }]);
nodes[3].node.process_pending_htlc_forwards();

// The last node should fail back with malformed since it's not the intro node.
check_added_monitors!(nodes[3], 1);
let (update_fail_malformed, commitment_signed) = {
let msg_events = nodes[3].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 1);
match msg_events[0] {
MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate {
ref update_fail_malformed_htlcs, ref commitment_signed, ..
}, .. } => {
if reload {
// We've just placed our malformed HTLC in the holding cell. Make sure we'll reload this holding
// cell htlc on restart.
let mon = get_monitor!(nodes[3], chan_id_2_3).encode();
reload_node!(nodes[3], UserConfig::default(), &nodes[3].node.encode(), &[&mon],
new_persister, new_chain_monitor, node_3_deserialized);

let mut reconnect_args = ReconnectArgs::new(&nodes[2], &nodes[3]);
reconnect_args.pending_cell_htlc_malforms.0 = 1;
reconnect_nodes(reconnect_args);
expect_pending_htlcs_forwardable_conditions(nodes[2].node.get_and_clear_pending_events(),
&[HTLCDestination::NextHopChannel {
node_id: Some(nodes[3].node.get_our_node_id()),
channel_id: chan_id_2_3,
}]);
nodes[2].node.process_pending_htlc_forwards();
check_added_monitors(&nodes[2], 1);
} else {
// The last node should fail back with malformed since it's not the intro node.
check_added_monitors!(nodes[3], 1);
let (update_fail_malformed, commitment_signed) = {
let msg_events = nodes[3].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 1);
match &msg_events[0] {
MessageSendEvent::UpdateHTLCs { updates: msgs::CommitmentUpdate {
ref update_fail_malformed_htlcs, ref commitment_signed, ..
}, .. } => {
assert_eq!(update_fail_malformed_htlcs.len(), 1);
(update_fail_malformed_htlcs[0].clone(), commitment_signed.clone())
},
_ => panic!("Unexpected event"),
}
};
assert_eq!(update_fail_malformed.sha256_of_onion, [0; 32]);
assert_eq!(update_fail_malformed.failure_code, INVALID_ONION_BLINDING);
nodes[2].node.handle_update_fail_malformed_htlc(&nodes[3].node.get_our_node_id(), &update_fail_malformed);
do_commitment_signed_dance(&nodes[2], &nodes[3], &commitment_signed, true, false);
}
};
assert_eq!(update_fail_malformed.sha256_of_onion, [0; 32]);
assert_eq!(update_fail_malformed.failure_code, INVALID_ONION_BLINDING);
nodes[2].node.handle_update_fail_malformed_htlc(&nodes[3].node.get_our_node_id(), &update_fail_malformed);
do_commitment_signed_dance(&nodes[2], &nodes[3], &commitment_signed, true, false);
}

// The intro node fails back with the invalid_onion_blinding error.
let (update_fail, commitment_signed) = {
Expand Down
38 changes: 29 additions & 9 deletions lightning/src/ln/functional_test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3026,6 +3026,7 @@ pub struct ReconnectArgs<'a, 'b, 'c, 'd> {
pub pending_htlc_fails: (usize, usize),
pub pending_cell_htlc_claims: (usize, usize),
pub pending_cell_htlc_fails: (usize, usize),
pub pending_cell_htlc_malforms: (usize, usize),
pub pending_raa: (bool, bool),
}

Expand All @@ -3040,6 +3041,7 @@ impl<'a, 'b, 'c, 'd> ReconnectArgs<'a, 'b, 'c, 'd> {
pending_htlc_fails: (0, 0),
pending_cell_htlc_claims: (0, 0),
pending_cell_htlc_fails: (0, 0),
pending_cell_htlc_malforms: (0, 0),
pending_raa: (false, false),
}
}
Expand All @@ -3050,7 +3052,7 @@ impl<'a, 'b, 'c, 'd> ReconnectArgs<'a, 'b, 'c, 'd> {
pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
let ReconnectArgs {
node_a, node_b, send_channel_ready, pending_htlc_adds, pending_htlc_claims, pending_htlc_fails,
pending_cell_htlc_claims, pending_cell_htlc_fails, pending_raa
pending_cell_htlc_claims, pending_cell_htlc_fails, pending_cell_htlc_malforms, pending_raa
} = args;
node_a.node.peer_connected(&node_b.node.get_our_node_id(), &msgs::Init {
features: node_b.node.init_features(), networks: None, remote_network_address: None
Expand Down Expand Up @@ -3091,7 +3093,9 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
node_b.node.handle_channel_reestablish(&node_a.node.get_our_node_id(), &msg);
resp_1.push(handle_chan_reestablish_msgs!(node_b, node_a));
}
if pending_cell_htlc_claims.0 != 0 || pending_cell_htlc_fails.0 != 0 {
if pending_cell_htlc_claims.0 != 0 || pending_cell_htlc_fails.0 != 0 ||
pending_cell_htlc_malforms.0 != 0
{
check_added_monitors!(node_b, 1);
} else {
check_added_monitors!(node_b, 0);
Expand All @@ -3102,17 +3106,21 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
node_a.node.handle_channel_reestablish(&node_b.node.get_our_node_id(), &msg);
resp_2.push(handle_chan_reestablish_msgs!(node_a, node_b));
}
if pending_cell_htlc_claims.1 != 0 || pending_cell_htlc_fails.1 != 0 {
if pending_cell_htlc_claims.1 != 0 || pending_cell_htlc_fails.1 != 0 ||
pending_cell_htlc_malforms.1 != 0
{
check_added_monitors!(node_a, 1);
} else {
check_added_monitors!(node_a, 0);
}

// We don't yet support both needing updates, as that would require a different commitment dance:
assert!((pending_htlc_adds.0 == 0 && pending_htlc_claims.0 == 0 && pending_htlc_fails.0 == 0 &&
pending_cell_htlc_claims.0 == 0 && pending_cell_htlc_fails.0 == 0) ||
pending_cell_htlc_claims.0 == 0 && pending_cell_htlc_fails.0 == 0 &&
pending_cell_htlc_malforms.0 == 0) ||
(pending_htlc_adds.1 == 0 && pending_htlc_claims.1 == 0 && pending_htlc_fails.1 == 0 &&
pending_cell_htlc_claims.1 == 0 && pending_cell_htlc_fails.1 == 0));
pending_cell_htlc_claims.1 == 0 && pending_cell_htlc_fails.1 == 0 &&
pending_cell_htlc_malforms.1 == 0));

for chan_msgs in resp_1.drain(..) {
if send_channel_ready.0 {
Expand All @@ -3135,7 +3143,10 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
} else {
assert!(chan_msgs.1.is_none());
}
if pending_htlc_adds.0 != 0 || pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 || pending_cell_htlc_claims.0 != 0 || pending_cell_htlc_fails.0 != 0 {
if pending_htlc_adds.0 != 0 || pending_htlc_claims.0 != 0 || pending_htlc_fails.0 != 0 ||
pending_cell_htlc_claims.0 != 0 || pending_cell_htlc_fails.0 != 0 ||
pending_cell_htlc_malforms.0 != 0
{
let commitment_update = chan_msgs.2.unwrap();
if pending_htlc_adds.0 != -1 { // We use -1 to denote a response commitment_signed
assert_eq!(commitment_update.update_add_htlcs.len(), pending_htlc_adds.0 as usize);
Expand All @@ -3144,7 +3155,7 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
}
assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.0 + pending_cell_htlc_claims.0);
assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.0 + pending_cell_htlc_fails.0);
assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
assert_eq!(commitment_update.update_fail_malformed_htlcs.len(), pending_cell_htlc_malforms.0);
for update_add in commitment_update.update_add_htlcs {
node_a.node.handle_update_add_htlc(&node_b.node.get_our_node_id(), &update_add);
}
Expand All @@ -3154,6 +3165,9 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
for update_fail in commitment_update.update_fail_htlcs {
node_a.node.handle_update_fail_htlc(&node_b.node.get_our_node_id(), &update_fail);
}
for update_malformed in commitment_update.update_fail_malformed_htlcs {
node_a.node.handle_update_fail_malformed_htlc(&node_b.node.get_our_node_id(), &update_malformed);
}

if pending_htlc_adds.0 != -1 { // We use -1 to denote a response commitment_signed
commitment_signed_dance!(node_a, node_b, commitment_update.commitment_signed, false);
Expand Down Expand Up @@ -3194,14 +3208,17 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
} else {
assert!(chan_msgs.1.is_none());
}
if pending_htlc_adds.1 != 0 || pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 || pending_cell_htlc_claims.1 != 0 || pending_cell_htlc_fails.1 != 0 {
if pending_htlc_adds.1 != 0 || pending_htlc_claims.1 != 0 || pending_htlc_fails.1 != 0 ||
pending_cell_htlc_claims.1 != 0 || pending_cell_htlc_fails.1 != 0 ||
pending_cell_htlc_malforms.1 != 0
{
let commitment_update = chan_msgs.2.unwrap();
if pending_htlc_adds.1 != -1 { // We use -1 to denote a response commitment_signed
assert_eq!(commitment_update.update_add_htlcs.len(), pending_htlc_adds.1 as usize);
}
assert_eq!(commitment_update.update_fulfill_htlcs.len(), pending_htlc_claims.1 + pending_cell_htlc_claims.1);
assert_eq!(commitment_update.update_fail_htlcs.len(), pending_htlc_fails.1 + pending_cell_htlc_fails.1);
assert!(commitment_update.update_fail_malformed_htlcs.is_empty());
assert_eq!(commitment_update.update_fail_malformed_htlcs.len(), pending_cell_htlc_malforms.1);
for update_add in commitment_update.update_add_htlcs {
node_b.node.handle_update_add_htlc(&node_a.node.get_our_node_id(), &update_add);
}
Expand All @@ -3211,6 +3228,9 @@ pub fn reconnect_nodes<'a, 'b, 'c, 'd>(args: ReconnectArgs<'a, 'b, 'c, 'd>) {
for update_fail in commitment_update.update_fail_htlcs {
node_b.node.handle_update_fail_htlc(&node_a.node.get_our_node_id(), &update_fail);
}
for update_malformed in commitment_update.update_fail_malformed_htlcs {
node_b.node.handle_update_fail_malformed_htlc(&node_a.node.get_our_node_id(), &update_malformed);
}

if pending_htlc_adds.1 != -1 { // We use -1 to denote a response commitment_signed
commitment_signed_dance!(node_b, node_a, commitment_update.commitment_signed, false);
Expand Down

0 comments on commit 838c32c

Please sign in to comment.