X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmonitor_tests.rs;h=4f36b9a88810aa5122c3347953028c6b31943a87;hb=28c9b56113ff1ebb1b505a2c979c55c1626aa06b;hp=6fa0aab9d311fb2ed5f9dff09ac3b487b2298051;hpb=f9983de4856f5be0ea672119bfaf1d28e3916201;p=rust-lightning diff --git a/lightning/src/ln/monitor_tests.rs b/lightning/src/ln/monitor_tests.rs index 6fa0aab9..4f36b9a8 100644 --- a/lightning/src/ln/monitor_tests.rs +++ b/lightning/src/ln/monitor_tests.rs @@ -15,11 +15,12 @@ use ln::channel; use ln::channelmanager::BREAKDOWN_TIMEOUT; use ln::features::InitFeatures; use ln::msgs::ChannelMessageHandler; -use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; +use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason, HTLCDestination}; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; use bitcoin::secp256k1::Secp256k1; +use bitcoin::Transaction; use prelude::*; @@ -73,7 +74,7 @@ fn chanmon_fail_from_stale_commitment() { assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); connect_blocks(&nodes[1], ANTI_REORG_DELAY - 1); - expect_pending_htlcs_forwardable!(nodes[1]); + expect_pending_htlcs_forwardable_and_htlc_handling_failed!(nodes[1], vec![HTLCDestination::NextHopChannel { node_id: Some(nodes[2].node.get_our_node_id()), channel_id: chan_id_2 }]); check_added_monitors!(nodes[1], 1); let fail_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); @@ -82,6 +83,66 @@ fn chanmon_fail_from_stale_commitment() { 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. @@ -108,7 +169,7 @@ fn chanmon_claim_value_coop_close() { 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()); @@ -155,23 +216,9 @@ fn chanmon_claim_value_coop_close() { assert_eq!(Vec::::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); } @@ -203,7 +250,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { 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); @@ -236,13 +283,18 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { 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. @@ -384,15 +436,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { }]), 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 @@ -449,14 +493,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { 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 @@ -479,15 +516,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { // 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, @@ -501,15 +530,7 @@ fn do_test_claim_value_force_close(prev_commitment_tx: bool) { // 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, @@ -580,9 +601,10 @@ fn test_balances_on_local_commitment_htlcs() { 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); @@ -704,25 +726,11 @@ fn test_balances_on_local_commitment_htlcs() { 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]); }