X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fshutdown_tests.rs;h=0eb56434169bec971cdf9853cb3245a1916190d5;hb=dedc8306f68e397dd51d0e9055eab2c04e373cdf;hp=bdd32e90d0ace1cca8b1fd46c4eac99ecb486b61;hpb=e1897de60643f2d31113ae98d2fe9bd36f8192ef;p=rust-lightning diff --git a/lightning/src/ln/shutdown_tests.rs b/lightning/src/ln/shutdown_tests.rs index bdd32e90..0eb56434 100644 --- a/lightning/src/ln/shutdown_tests.rs +++ b/lightning/src/ln/shutdown_tests.rs @@ -7,15 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Tests of our shutdown and closing_signed negotiation logic. +//! Tests of our shutdown and closing_signed negotiation logic as well as some assorted force-close +//! handling tests. use crate::sign::{EntropySource, SignerProvider}; use crate::chain::ChannelMonitorUpdateStatus; use crate::chain::transaction::OutPoint; -use crate::events::{MessageSendEvent, HTLCDestination, MessageSendEventsProvider, ClosureReason}; +use crate::events::{Event, MessageSendEvent, HTLCDestination, MessageSendEventsProvider, ClosureReason}; use crate::ln::channelmanager::{self, PaymentSendFailure, PaymentId, RecipientOnionFields, Retry, ChannelShutdownState, ChannelDetails}; use crate::routing::router::{PaymentParameters, get_route, RouteParameters}; -use crate::ln::msgs; +use crate::ln::{ChannelId, msgs}; use crate::ln::msgs::{ChannelMessageHandler, ErrorAction}; use crate::ln::onion_utils::INVALID_ONION_BLINDING; use crate::ln::script::ShutdownScript; @@ -25,6 +26,8 @@ use crate::util::errors::APIError; use crate::util::config::UserConfig; use crate::util::string::UntrustedString; +use bitcoin::{Transaction, TxOut}; +use bitcoin::blockdata::locktime::absolute::LockTime; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; use bitcoin::network::constants::Network; @@ -48,7 +51,7 @@ fn pre_funding_lock_shutdown_test() { mine_transaction(&nodes[0], &tx); mine_transaction(&nodes[1], &tx); - nodes[0].node.close_channel(&OutPoint { txid: tx.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap(); + nodes[0].node.close_channel(&ChannelId::v1_from_funding_outpoint(OutPoint { txid: tx.txid(), index: 0 }), &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(), &node_0_shutdown); let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); @@ -718,7 +721,7 @@ fn test_upfront_shutdown_script() { // We test that in case of peer committing upfront to a script, if it changes at closing, we refuse to sign let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1000000, 1000000); - nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[2].node.get_our_node_id()).unwrap(); + nodes[0].node.close_channel(&chan.2, &nodes[2].node.get_our_node_id()).unwrap(); let node_0_orig_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id()); let mut node_0_shutdown = node_0_orig_shutdown.clone(); node_0_shutdown.scriptpubkey = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script().to_p2sh(); @@ -733,7 +736,7 @@ fn test_upfront_shutdown_script() { // We test that in case of peer committing upfront to a script, if it doesn't change at closing, we sign let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 2, 1000000, 1000000); - nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[2].node.get_our_node_id()).unwrap(); + nodes[0].node.close_channel(&chan.2, &nodes[2].node.get_our_node_id()).unwrap(); let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[2].node.get_our_node_id()); // We test that in case of peer committing upfront to a script, if it oesn't change at closing, we sign nodes[2].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &node_0_shutdown); @@ -747,7 +750,7 @@ fn test_upfront_shutdown_script() { // We test that if case of peer non-signaling we don't enforce committed script at channel opening *nodes[0].override_init_features.borrow_mut() = Some(nodes[0].node.init_features().clear_upfront_shutdown_script()); let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000); - nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap(); + nodes[0].node.close_channel(&chan.2, &nodes[1].node.get_our_node_id()).unwrap(); let node_1_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(), &node_1_shutdown); check_added_monitors!(nodes[1], 1); @@ -762,7 +765,7 @@ fn test_upfront_shutdown_script() { // channel smoothly, opt-out is from channel initiator here *nodes[0].override_init_features.borrow_mut() = None; let chan = create_announced_chan_between_nodes_with_value(&nodes, 1, 0, 1000000, 1000000); - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); let node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown); @@ -776,7 +779,7 @@ fn test_upfront_shutdown_script() { //// We test that if user opt-out, we provide a zero-length script at channel opening and we are able to close //// channel smoothly let chan = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 1000000, 1000000); - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); let node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &node_0_shutdown); @@ -891,7 +894,7 @@ fn test_segwit_v0_shutdown_script() { let nodes = create_network(3, &node_cfgs, &node_chanmgrs); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); // Use a segwit v0 script supported even without option_shutdown_anysegwit @@ -926,7 +929,7 @@ fn test_anysegwit_shutdown_script() { let nodes = create_network(3, &node_cfgs, &node_chanmgrs); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); // Use a non-v0 segwit script supported by option_shutdown_anysegwit @@ -972,14 +975,14 @@ fn test_unsupported_anysegwit_shutdown_script() { .expect(OnGetShutdownScriptpubkey { returns: supported_shutdown_script }); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - match nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()) { + match nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()) { Err(APIError::IncompatibleShutdownScript { script }) => { assert_eq!(script.into_inner(), unsupported_shutdown_script.clone().into_inner()); }, Err(e) => panic!("Unexpected error: {:?}", e), Ok(_) => panic!("Expected error"), } - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); // Use a non-v0 segwit script unsupported without option_shutdown_anysegwit @@ -1004,7 +1007,7 @@ fn test_invalid_shutdown_script() { let nodes = create_network(3, &node_cfgs, &node_chanmgrs); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - nodes[1].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id()).unwrap(); + nodes[1].node.close_channel(&chan.2, &nodes[0].node.get_our_node_id()).unwrap(); check_added_monitors!(nodes[1], 1); // Use a segwit v0 script with an unsupported witness program @@ -1038,7 +1041,7 @@ fn test_user_shutdown_script() { let shutdown_script = ShutdownScript::try_from(script.clone()).unwrap(); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - nodes[1].node.close_channel_with_feerate_and_script(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id(), None, Some(shutdown_script)).unwrap(); + nodes[1].node.close_channel_with_feerate_and_script(&chan.2, &nodes[0].node.get_our_node_id(), None, Some(shutdown_script)).unwrap(); check_added_monitors!(nodes[1], 1); let mut node_0_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); @@ -1065,7 +1068,7 @@ fn test_already_set_user_shutdown_script() { let shutdown_script = ShutdownScript::try_from(script).unwrap(); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - let result = nodes[1].node.close_channel_with_feerate_and_script(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[0].node.get_our_node_id(), None, Some(shutdown_script)); + let result = nodes[1].node.close_channel_with_feerate_and_script(&chan.2, &nodes[0].node.get_our_node_id(), None, Some(shutdown_script)); assert_eq!(result, Err(APIError::APIMisuseError { err: "Cannot override shutdown script for a channel with one already set".to_string() })); } @@ -1197,7 +1200,7 @@ fn do_simple_legacy_shutdown_test(high_initiator_fee: bool) { *feerate_lock *= 10; } - nodes[0].node.close_channel(&OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(), &nodes[1].node.get_our_node_id()).unwrap(); + nodes[0].node.close_channel(&chan.2, &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(), &node_0_shutdown); let node_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id()); @@ -1237,7 +1240,7 @@ fn simple_target_feerate_shutdown() { let nodes = create_network(2, &node_cfgs, &node_chanmgrs); let chan = create_announced_chan_between_nodes(&nodes, 0, 1); - let chan_id = OutPoint { txid: chan.3.txid(), index: 0 }.to_channel_id(); + let chan_id = chan.2; nodes[0].node.close_channel_with_feerate_and_script(&chan_id, &nodes[1].node.get_our_node_id(), Some(253 * 10), None).unwrap(); let node_0_shutdown = get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()); @@ -1375,3 +1378,41 @@ fn outbound_update_no_early_closing_signed() { do_outbound_update_no_early_closing_signed(true); do_outbound_update_no_early_closing_signed(false); } + +#[test] +fn batch_funding_failure() { + // Provides test coverage of batch funding failure, which previously deadlocked + 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); + + exchange_open_accept_chan(&nodes[0], &nodes[1], 1_000_000, 0); + exchange_open_accept_chan(&nodes[0], &nodes[2], 1_000_000, 0); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 2); + // Build a transaction which only has the output for one of the two channels we're trying to + // confirm. Previously this led to a deadlock in channel closure handling. + let mut tx = Transaction { version: 2, lock_time: LockTime::ZERO, input: Vec::new(), output: Vec::new() }; + let mut chans = Vec::new(); + for (idx, ev) in events.iter().enumerate() { + if let Event::FundingGenerationReady { temporary_channel_id, counterparty_node_id, output_script, .. } = ev { + if idx == 0 { + tx.output.push(TxOut { value: 1_000_000, script_pubkey: output_script.clone() }); + } + chans.push((temporary_channel_id, counterparty_node_id)); + } else { panic!(); } + } + + // We should probably end up with an error for both channels, but currently we don't generate + // an error for the failing channel itself. + let err = "Error in transaction funding: Misuse error: No output matched the script_pubkey and value in the FundingGenerationReady event".to_string(); + let close = [ExpectedCloseEvent::from_id_reason(ChannelId::v1_from_funding_txid(tx.txid().as_ref(), 0), true, ClosureReason::ProcessingError { err })]; + + nodes[0].node.batch_funding_transaction_generated(&chans, tx).unwrap_err(); + + get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id()); + check_closed_events(&nodes[0], &close); + assert_eq!(nodes[0].node.list_channels().len(), 0); +}