use bitcoin::blockdata::script::Builder;
use bitcoin::blockdata::opcodes;
use bitcoin::secp256k1::Secp256k1;
+use bitcoin::Transaction;
use prelude::*;
expect_payment_failed_with_update!(nodes[0], payment_hash, false, update_a.contents.short_channel_id, true);
}
+fn test_spendable_output<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, spendable_tx: &Transaction) {
+ let mut spendable = node.chain_monitor.chain_monitor.get_and_clear_pending_events();
+ assert_eq!(spendable.len(), 1);
+ if let Event::SpendableOutputs { outputs } = spendable.pop().unwrap() {
+ assert_eq!(outputs.len(), 1);
+ let spend_tx = node.keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
+ Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
+ check_spends!(spend_tx, spendable_tx);
+ } else { panic!(); }
+}
+
+#[test]
+fn revoked_output_htlc_resolution_timing() {
+ // Tests that HTLCs which were present in a broadcasted remote revoked commitment transaction
+ // are resolved only after a spend of the HTLC output reaches six confirmations. Preivously
+ // they would resolve after the revoked commitment transaction itself reaches six
+ // confirmations.
+ 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 chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1_000_000, 500_000_000, InitFeatures::known(), InitFeatures::known());
+
+ let payment_hash_1 = route_payment(&nodes[1], &[&nodes[0]], 1_000_000).1;
+
+ // Get a commitment transaction which contains the HTLC we care about, but which we'll revoke
+ // before forwarding.
+ let revoked_local_txn = get_local_commitment_txn!(nodes[0], chan.2);
+ assert_eq!(revoked_local_txn.len(), 1);
+
+ // Route a dust payment to revoke the above commitment transaction
+ route_payment(&nodes[0], &[&nodes[1]], 1_000);
+
+ // Confirm the revoked commitment transaction, closing the channel.
+ mine_transaction(&nodes[1], &revoked_local_txn[0]);
+ check_added_monitors!(nodes[1], 1);
+ check_closed_event!(nodes[1], 1, ClosureReason::CommitmentTxConfirmed);
+ check_closed_broadcast!(nodes[1], true);
+
+ let bs_spend_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0);
+ assert_eq!(bs_spend_txn.len(), 2);
+ check_spends!(bs_spend_txn[0], revoked_local_txn[0]);
+ check_spends!(bs_spend_txn[1], chan.3);
+
+ // After the commitment transaction confirms, we should still wait on the HTLC spend
+ // transaction to confirm before resolving the HTLC.
+ connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+ assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+ assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+ // Spend the HTLC output, generating a HTLC failure event after ANTI_REORG_DELAY confirmations.
+ mine_transaction(&nodes[1], &bs_spend_txn[0]);
+ assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty());
+ assert!(nodes[1].node.get_and_clear_pending_events().is_empty());
+
+ connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1);
+ expect_payment_failed!(nodes[1], payment_hash_1, true);
+}
+
#[test]
fn chanmon_claim_value_coop_close() {
// Tests `get_claimable_balances` returns the correct values across a simple cooperative claim.
assert_eq!(vec![Balance::ClaimableOnChannelClose { claimable_amount_satoshis: 1_000, }],
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
- nodes[0].node.close_channel(&chan_id).unwrap();
+ nodes[0].node.close_channel(&chan_id, &nodes[1].node.get_our_node_id()).unwrap();
let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id());
nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &InitFeatures::known(), &node_0_shutdown);
let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
assert_eq!(Vec::<Balance>::new(),
nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
- let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_a_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, shutdown_tx[0]);
- }
+ test_spendable_output(&nodes[0], &shutdown_tx[0]);
+ test_spendable_output(&nodes[1], &shutdown_tx[0]);
- let mut node_b_spendable = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_b_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_b_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[1].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, shutdown_tx[0]);
- }
check_closed_event!(nodes[0], 1, ClosureReason::CooperativeClosure);
check_closed_event!(nodes[1], 1, ClosureReason::CooperativeClosure);
}
assert_eq!(funding_outpoint.to_channel_id(), chan_id);
// This HTLC is immediately claimed, giving node B the preimage
- let payment_preimage = route_payment(&nodes[0], &[&nodes[1]], 3_000_000).0;
+ let (payment_preimage, payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 3_000_000);
// This HTLC is allowed to time out, letting A claim it. However, in order to test claimable
// balances more fully we also give B the preimage for this HTLC.
let (timeout_payment_preimage, timeout_payment_hash, _) = route_payment(&nodes[0], &[&nodes[1]], 4_000_000);
nodes[1].node.claim_funds(payment_preimage);
check_added_monitors!(nodes[1], 1);
+ expect_payment_claimed!(nodes[1], payment_hash, 3_000_000);
+
let b_htlc_msgs = get_htlc_update_msgs!(&nodes[1], nodes[0].node.get_our_node_id());
// We claim the dust payment here as well, but it won't impact our claimable balances as its
// dust and thus doesn't appear on chain at all.
nodes[1].node.claim_funds(dust_payment_preimage);
check_added_monitors!(nodes[1], 1);
+ expect_payment_claimed!(nodes[1], dust_payment_hash, 3_000);
+
nodes[1].node.claim_funds(timeout_payment_preimage);
check_added_monitors!(nodes[1], 1);
+ expect_payment_claimed!(nodes[1], timeout_payment_hash, 4_000_000);
if prev_commitment_tx {
// To build a previous commitment transaction, deliver one round of commitment messages.
}]),
sorted_vec(nodes[1].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances()));
- let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_a_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, remote_txn[0]);
- }
-
+ test_spendable_output(&nodes[0], &remote_txn[0]);
assert!(nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
// After broadcasting the HTLC claim transaction, node A will still consider the HTLC
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
expect_payment_failed!(nodes[0], timeout_payment_hash, true);
- let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_a_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, a_broadcast_txn[2]);
- } else { panic!(); }
+ test_spendable_output(&nodes[0], &a_broadcast_txn[2]);
// Node B will no longer consider the HTLC "contentious" after the HTLC claim transaction
// confirms, and consider it simply "awaiting confirmations". Note that it has to wait for the
// After reaching the commitment output CSV, we'll get a SpendableOutputs event for it and have
// only the HTLCs claimable on node B.
connect_blocks(&nodes[1], node_b_commitment_claimable - nodes[1].best_block_info().1);
-
- let mut node_b_spendable = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_b_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_b_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[1].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, remote_txn[0]);
- }
+ test_spendable_output(&nodes[1], &remote_txn[0]);
assert_eq!(sorted_vec(vec![Balance::ClaimableAwaitingConfirmations {
claimable_amount_satoshis: 3_000,
// After reaching the claimed HTLC output CSV, we'll get a SpendableOutptus event for it and
// have only one HTLC output left spendable.
connect_blocks(&nodes[1], node_b_htlc_claimable - nodes[1].best_block_info().1);
-
- let mut node_b_spendable = nodes[1].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_b_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_b_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[1].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, b_broadcast_txn[0]);
- } else { panic!(); }
+ test_spendable_output(&nodes[1], &b_broadcast_txn[0]);
assert_eq!(vec![Balance::ContentiousClaimable {
claimable_amount_satoshis: 4_000,
expect_pending_htlcs_forwardable!(nodes[1]);
expect_payment_received!(nodes[1], payment_hash_2, payment_secret_2, 20_000_000);
- assert!(nodes[1].node.claim_funds(payment_preimage_2));
+ nodes[1].node.claim_funds(payment_preimage_2);
get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id());
check_added_monitors!(nodes[1], 1);
+ expect_payment_claimed!(nodes[1], payment_hash_2, 20_000_000);
let chan_feerate = get_feerate!(nodes[0], chan_id) as u64;
let opt_anchors = get_opt_anchors!(nodes[0], chan_id);
confirmation_height: node_a_htlc_claimable,
}],
nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances());
- let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_a_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, as_txn[0]);
- }
+ test_spendable_output(&nodes[0], &as_txn[0]);
// Connect blocks until the HTLC-Timeout's CSV expires, providing us the relevant
// `SpendableOutputs` event and removing the claimable balance entry.
connect_blocks(&nodes[0], node_a_htlc_claimable - nodes[0].best_block_info().1);
assert!(nodes[0].chain_monitor.chain_monitor.get_monitor(funding_outpoint).unwrap().get_claimable_balances().is_empty());
- let mut node_a_spendable = nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events();
- assert_eq!(node_a_spendable.len(), 1);
- if let Event::SpendableOutputs { outputs } = node_a_spendable.pop().unwrap() {
- assert_eq!(outputs.len(), 1);
- let spend_tx = nodes[0].keys_manager.backing.spend_spendable_outputs(&[&outputs[0]], Vec::new(),
- Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(), 253, &Secp256k1::new()).unwrap();
- check_spends!(spend_tx, as_txn[1]);
- }
+ test_spendable_output(&nodes[0], &as_txn[1]);
}