check_closed_broadcast!(nodes[1]);
}
+fn do_htlc_claim_current_remote_commitment_only(use_dust: bool) {
+ let mut nodes = create_network(2);
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+ let route = nodes[0].router.get_route(&nodes[1].node.get_our_node_id(), None, &Vec::new(), if use_dust { 50000 } else { 3000000 }, TEST_FINAL_CLTV).unwrap();
+ let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]);
+ nodes[0].node.send_payment(route, payment_hash).unwrap();
+ check_added_monitors!(nodes[0], 1);
+
+ let _as_update = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+
+ // As far as A is concerened, the HTLC is now present only in the latest remote commitment
+ // transaction, however it is not in A's latest local commitment, so we can just broadcast that
+ // to "time out" the HTLC.
+
+ let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ for i in 1..TEST_FINAL_CLTV + HTLC_FAIL_TIMEOUT_BLOCKS + CHAN_CONFIRM_DEPTH + 1 {
+ nodes[0].chain_monitor.block_connected_checked(&header, i, &Vec::new(), &Vec::new());
+ header.prev_blockhash = header.bitcoin_hash();
+ }
+ test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
+ check_closed_broadcast!(nodes[0]);
+}
+
+fn do_htlc_claim_previous_remote_commitment_only(use_dust: bool, check_revoke_no_close: bool) {
+ let nodes = create_network(3);
+ let chan = create_announced_chan_between_nodes(&nodes, 0, 1);
+
+ // Fail the payment, but don't deliver A's final RAA, resulting in the HTLC only being present
+ // in B's previous (unrevoked) commitment transaction, but none of A's commitment transactions.
+ // Also optionally test that we *don't* fail the channel in case the commitment transaction was
+ // actually revoked.
+ let htlc_value = if use_dust { 50000 } else { 3000000 };
+ let (_, our_payment_hash) = route_payment(&nodes[0], &[&nodes[1]], htlc_value);
+ assert!(nodes[1].node.fail_htlc_backwards(&our_payment_hash, htlc_value));
+ expect_pending_htlcs_forwardable!(nodes[1]);
+ check_added_monitors!(nodes[1], 1);
+
+ let bs_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
+ nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &bs_updates.update_fail_htlcs[0]).unwrap();
+ nodes[0].node.handle_commitment_signed(&nodes[1].node.get_our_node_id(), &bs_updates.commitment_signed).unwrap();
+ check_added_monitors!(nodes[0], 1);
+ let as_updates = get_revoke_commit_msgs!(nodes[0], nodes[1].node.get_our_node_id());
+ nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), &as_updates.0).unwrap();
+ check_added_monitors!(nodes[1], 1);
+ nodes[1].node.handle_commitment_signed(&nodes[0].node.get_our_node_id(), &as_updates.1).unwrap();
+ check_added_monitors!(nodes[1], 1);
+ let bs_revoke_and_ack = get_event_msg!(nodes[1], MessageSendEvent::SendRevokeAndACK, nodes[0].node.get_our_node_id());
+
+ if check_revoke_no_close {
+ nodes[0].node.handle_revoke_and_ack(&nodes[1].node.get_our_node_id(), &bs_revoke_and_ack).unwrap();
+ check_added_monitors!(nodes[0], 1);
+ }
+
+ let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ for i in 1..TEST_FINAL_CLTV + HTLC_FAIL_TIMEOUT_BLOCKS + CHAN_CONFIRM_DEPTH + 1 {
+ nodes[0].chain_monitor.block_connected_checked(&header, i, &Vec::new(), &Vec::new());
+ header.prev_blockhash = header.bitcoin_hash();
+ }
+ if !check_revoke_no_close {
+ test_txn_broadcast(&nodes[0], &chan, None, HTLCType::NONE);
+ check_closed_broadcast!(nodes[0]);
+ } else {
+ let events = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events.len(), 1);
+ match events[0] {
+ Event::PaymentFailed { payment_hash, rejected_by_dest, .. } => {
+ assert_eq!(payment_hash, our_payment_hash);
+ assert!(rejected_by_dest);
+ },
+ _ => panic!("Unexpected event"),
+ }
+ }
+}
+
+// Test that we close channels on-chain when broadcastable HTLCs reach their timeout window.
+// There are only a few cases to test here:
+// * its not really normative behavior, but we test that below-dust HTLCs "included" in
+// broadcastable commitment transactions result in channel closure,
+// * its included in an unrevoked-but-previous remote commitment transaction,
+// * its included in the latest remote or local commitment transactions.
+// We test each of the three possible commitment transactions individually and use both dust and
+// non-dust HTLCs.
+// Note that we don't bother testing both outbound and inbound HTLC failures for each case, and we
+// assume they are handled the same across all six cases, as both outbound and inbound failures are
+// tested for at least one of the cases in other tests.
#[test]
-fn htlc_claim_local_commitment_only() {
+fn htlc_claim_single_commitment_only_a() {
do_htlc_claim_local_commitment_only(true);
do_htlc_claim_local_commitment_only(false);
+
+ do_htlc_claim_current_remote_commitment_only(true);
+ do_htlc_claim_current_remote_commitment_only(false);
+}
+
+#[test]
+fn htlc_claim_single_commitment_only_b() {
+ do_htlc_claim_previous_remote_commitment_only(true, false);
+ do_htlc_claim_previous_remote_commitment_only(false, false);
+ do_htlc_claim_previous_remote_commitment_only(true, true);
+ do_htlc_claim_previous_remote_commitment_only(false, true);
}
fn run_onion_failure_test<F1,F2>(_name: &str, test_case: u8, nodes: &Vec<Node>, route: &Route, payment_hash: &PaymentHash, callback_msg: F1, callback_node: F2, expected_retryable: bool, expected_error_code: Option<u16>, expected_channel_update: Option<HTLCFailChannelUpdate>)