//! claim outputs on-chain.
use chain;
+use chain::Listen;
use chain::Watch;
use chain::channelmonitor;
use chain::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ANTI_REORG_DELAY};
use chain::transaction::OutPoint;
-use chain::keysinterface::{Sign, KeysInterface};
+use chain::keysinterface::{KeysInterface, BaseSign};
use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure, BREAKDOWN_TIMEOUT};
use ln::channel::{Channel, ChannelError};
use std::collections::{BTreeSet, HashMap, HashSet};
use std::default::Default;
use std::sync::Mutex;
-use std::sync::atomic::Ordering;
use ln::functional_test_utils::*;
use ln::chan_utils::CommitmentTransaction;
let (temporary_channel_id, tx, funding_output) = create_funding_transaction(&nodes[0], 100000, 42);
if steps & 0x0f == 3 { return; }
- nodes[0].node.funding_transaction_generated(&temporary_channel_id, funding_output);
+ nodes[0].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
check_added_monitors!(nodes[0], 0);
let funding_created = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
}
let events_4 = nodes[0].node.get_and_clear_pending_events();
- assert_eq!(events_4.len(), 1);
- match events_4[0] {
- Event::FundingBroadcastSafe { ref funding_txo, user_channel_id } => {
- assert_eq!(user_channel_id, 42);
- assert_eq!(*funding_txo, funding_output);
- },
- _ => panic!("Unexpected event"),
- };
+ assert_eq!(events_4.len(), 0);
if steps & 0x0f == 6 { return; }
create_chan_between_nodes_with_value_confirm_first(&nodes[0], &nodes[1], &tx, 2);
let secp_ctx = Secp256k1::new();
let session_priv = SecretKey::from_slice(&[42; 32]).expect("RNG is bad!");
- let cur_height = nodes[1].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
+ let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3460001, &None, cur_height).unwrap();
// Need to manually create the update_add_htlc message to go around the channel reserve check in send_htlc()
let secp_ctx = Secp256k1::new();
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
- let cur_height = nodes[1].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
+ let cur_height = nodes[1].node.best_block.read().unwrap().height() + 1;
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route.paths[0], &session_priv).unwrap();
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 1000, &None, cur_height).unwrap();
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
// transaction fee with 0 HTLCs (183 sats)).
create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 98817000, InitFeatures::known(), InitFeatures::known());
- let dust_amt = 546000; // Dust amount
+ let dust_amt = 329000; // Dust amount
// In the previous code, routing this dust payment would cause nodes[0] to perceive a channel
// reserve violation even though it's a dust HTLC and therefore shouldn't count towards the
// commitment transaction fee.
// Need to manually create the update_add_htlc message to go around the channel reserve check in send_htlc()
let secp_ctx = Secp256k1::new();
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
- let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
+ let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
let onion_keys = onion_utils::construct_onion_keys(&secp_ctx, &route_2.paths[0], &session_priv).unwrap();
let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route_2.paths[0], recv_value_2, &None, cur_height).unwrap();
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash_1);
check_tx_local_broadcast!(nodes[0], true, commitment_tx[0], chan_1.3);
}
-#[test]
-fn test_htlc_on_chain_timeout() {
+fn do_test_htlc_on_chain_timeout(connect_style: ConnectStyle) {
// Test that in case of a unilateral close onchain, we detect the state of output and
// timeout the HTLC backward accordingly. So here we test that ChannelManager is
// broadcasting the right event to other nodes in payment path.
let chanmon_cfgs = create_chanmon_cfgs(3);
let node_cfgs = create_node_cfgs(3, &chanmon_cfgs);
let node_chanmgrs = create_node_chanmgrs(3, &node_cfgs, &[None, None, None]);
- let nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+ let mut nodes = create_network(3, &node_cfgs, &node_chanmgrs);
+ *nodes[0].connect_style.borrow_mut() = connect_style;
+ *nodes[1].connect_style.borrow_mut() = connect_style;
+ *nodes[2].connect_style.borrow_mut() = connect_style;
// Create some intial channels
let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known());
assert_eq!(node_txn[2].clone().input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
}
+#[test]
+fn test_htlc_on_chain_timeout() {
+ do_test_htlc_on_chain_timeout(ConnectStyle::BestBlockFirstSkippingBlocks);
+ do_test_htlc_on_chain_timeout(ConnectStyle::TransactionsFirstSkippingBlocks);
+ do_test_htlc_on_chain_timeout(ConnectStyle::FullBlockViaListen);
+}
+
#[test]
fn test_simple_commitment_revoked_fail_backward() {
// Test that in case of a revoked commitment tx, we detect the resolution of output by justice tx
let secp_ctx = Secp256k1::new();
let session_priv = SecretKey::from_slice(&[42; 32]).unwrap();
- let current_height = nodes[1].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
+ let current_height = nodes[1].node.best_block.read().unwrap().height() + 1;
let net_graph_msg_handler = &nodes[1].net_graph_msg_handler;
let route = get_route(&nodes[1].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[0].node.get_our_node_id(), None, None, &Vec::new(), 50_000, TEST_FINAL_CLTV, &logger).unwrap();
let (onion_payloads, _amount_msat, cltv_expiry) = onion_utils::build_onion_payloads(&route.paths[0], 50_000, &None, current_height).unwrap();
let nodes_0_deserialized: ChannelManager<EnforcingSigner, &test_utils::TestChainMonitor, &test_utils::TestBroadcaster, &test_utils::TestKeysInterface, &test_utils::TestFeeEstimator, &test_utils::TestLogger>;
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
- // Start creating a channel, but stop right before broadcasting the event message FundingBroadcastSafe
+ // Start creating a channel, but stop right before broadcasting the funding transaction
let channel_value = 100000;
let push_msat = 10001;
let a_flags = InitFeatures::known();
let (temporary_channel_id, tx, funding_output) = create_funding_transaction(&node_a, channel_value, 42);
- node_a.node.funding_transaction_generated(&temporary_channel_id, funding_output);
+ node_a.node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
check_added_monitors!(node_a, 0);
node_b.node.handle_funding_created(&node_a.node.get_our_node_id(), &get_event_msg!(node_a, MessageSendEvent::SendFundingCreated, node_b.node.get_our_node_id()));
assert_eq!(added_monitors[0].0, funding_output);
added_monitors.clear();
}
- // Normally, this is where node_a would check for a FundingBroadcastSafe event, but the test de/serializes first instead
+ // Normally, this is where node_a would broadcast the funding transaction, but the test de/serializes first instead
nodes.push(node_a);
nodes.push(node_b);
assert!(nodes[0].chain_monitor.watch_channel(chan_0_monitor.get_funding_txo().0, chan_0_monitor).is_ok());
nodes[0].node = &nodes_0_deserialized;
- // After deserializing, make sure the FundingBroadcastSafe event is still held by the channel manager
+ // After deserializing, make sure the funding_transaction is still held by the channel manager
let events_4 = nodes[0].node.get_and_clear_pending_events();
- assert_eq!(events_4.len(), 1);
- match events_4[0] {
- Event::FundingBroadcastSafe { ref funding_txo, user_channel_id } => {
- assert_eq!(user_channel_id, 42);
- assert_eq!(*funding_txo, funding_output);
- },
- _ => panic!("Unexpected event"),
- };
+ assert_eq!(events_4.len(), 0);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].txid(), funding_output.txid);
// Make sure the channel is functioning as though the de/serialization never happened
assert_eq!(nodes[0].node.list_channels().len(), 1);
assert!(PublicKey::from_slice(&node0_to_1_send_open_channel.delayed_payment_basepoint.serialize()).is_ok());
}
+#[test]
+fn bolt2_open_channel_sane_dust_limit() {
+ 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 channel_value_satoshis=1000000;
+ let push_msat=10001;
+ nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), channel_value_satoshis, push_msat, 42, None).unwrap();
+ let mut node0_to_1_send_open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
+ node0_to_1_send_open_channel.dust_limit_satoshis = 661;
+ node0_to_1_send_open_channel.channel_reserve_satoshis = 100001;
+
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &node0_to_1_send_open_channel);
+ let events = nodes[1].node.get_and_clear_pending_msg_events();
+ let err_msg = match events[0] {
+ MessageSendEvent::HandleError { action: ErrorAction::SendErrorMessage { ref msg }, node_id: _ } => {
+ msg.clone()
+ },
+ _ => panic!("Unexpected event"),
+ };
+ assert_eq!(err_msg.data, "dust_limit_satoshis (661) is greater than the implementation limit (660)");
+}
+
// Test that if we fail to send an HTLC that is being freed from the holding cell, and the HTLC
// originated from our node, its failure is surfaced to the user. We trigger this failure to
// free the HTLC by increasing our fee while the HTLC is in the holding cell such that the HTLC
let net_graph_msg_handler = &nodes[0].net_graph_msg_handler;
let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[1].node.get_our_node_id(), None, None, &[], 3999999, TEST_FINAL_CLTV, &logger).unwrap();
- let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
+ let cur_height = nodes[0].node.best_block.read().unwrap().height() + 1;
let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::signing_only(), &route.paths[0], &session_priv).unwrap();
let (onion_payloads, _htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 3999999, &None, cur_height).unwrap();
let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &our_payment_hash);
#[test]
fn test_announce_disable_channels() {
- // Create 2 channels between A and B. Disconnect B. Call timer_chan_freshness_every_min and check for generated
+ // Create 2 channels between A and B. Disconnect B. Call timer_tick_occurred and check for generated
// ChannelUpdate. Reconnect B, reestablish and check there is non-generated ChannelUpdate.
let chanmon_cfgs = create_chanmon_cfgs(2);
nodes[0].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false);
nodes[1].node.peer_disconnected(&nodes[0].node.get_our_node_id(), false);
- nodes[0].node.timer_chan_freshness_every_min(); // dirty -> stagged
- nodes[0].node.timer_chan_freshness_every_min(); // staged -> fresh
+ nodes[0].node.timer_tick_occurred(); // dirty -> stagged
+ nodes[0].node.timer_tick_occurred(); // staged -> fresh
let msg_events = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(msg_events.len(), 3);
for e in msg_events {
nodes[1].node.handle_channel_reestablish(&nodes[0].node.get_our_node_id(), &reestablish_1[2]);
handle_chan_reestablish_msgs!(nodes[1], nodes[0]);
- nodes[0].node.timer_chan_freshness_every_min();
+ nodes[0].node.timer_tick_occurred();
assert!(nodes[0].node.get_and_clear_pending_msg_events().is_empty());
}
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- watchtower.chain_monitor.block_connected(&header, &[], 200);
+ watchtower.chain_monitor.block_connected(&Block { header, txdata: vec![] }, 200);
// Try to update ChannelMonitor
assert!(nodes[1].node.claim_funds(preimage, &None, 9_000_000));
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- watchtower_alice.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
+ watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
// Watchtower Alice should have broadcast a commitment/HTLC-timeout
{
watchtower
};
let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
- watchtower_bob.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
+ watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
// Route another payment to generate another update with still previous HTLC pending
let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]);
check_added_monitors!(nodes[0], 1);
//// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout
- watchtower_bob.chain_monitor.block_connected(&header, &vec![], CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ watchtower_bob.chain_monitor.block_connected(&Block { header, txdata: vec![] }, CHAN_CONFIRM_DEPTH + 1 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
// Watchtower Bob should have broadcast a commitment/HTLC-timeout
let bob_state_y;
};
// We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout
- watchtower_alice.chain_monitor.block_connected(&header, &vec![(0, &bob_state_y)], CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
+ let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+ watchtower_alice.chain_monitor.block_connected(&Block { header, txdata: vec![bob_state_y.clone()] }, CHAN_CONFIRM_DEPTH + 2 + TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS);
{
let htlc_txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
// We broadcast twice the transaction, once due to the HTLC-timeout, once due
nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_chan_msg);
// Move the first channel through the funding flow...
- let (temporary_channel_id, _tx, funding_output) = create_funding_transaction(&nodes[0], 100000, 42);
+ let (temporary_channel_id, tx, _) = create_funding_transaction(&nodes[0], 100000, 42);
- nodes[0].node.funding_transaction_generated(&temporary_channel_id, funding_output);
+ nodes[0].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
check_added_monitors!(nodes[0], 0);
let funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
// Move the first channel through the funding flow...
let (temporary_channel_id, tx, funding_output) = create_funding_transaction(&nodes[0], 100000, 42);
- nodes[0].node.funding_transaction_generated(&temporary_channel_id, funding_output);
+ nodes[0].node.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap();
check_added_monitors!(nodes[0], 0);
let mut funding_created_msg = get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id());
let mut a_channel_lock = nodes[0].node.channel_state.lock().unwrap();
let mut as_chan = a_channel_lock.by_id.get_mut(&open_chan_2_msg.temporary_channel_id).unwrap();
let logger = test_utils::TestLogger::new();
- as_chan.get_outbound_funding_created(funding_outpoint, &&logger).unwrap()
+ as_chan.get_outbound_funding_created(tx.clone(), funding_outpoint, &&logger).unwrap()
};
check_added_monitors!(nodes[0], 0);
nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &funding_created);
}
let events_4 = nodes[0].node.get_and_clear_pending_events();
- assert_eq!(events_4.len(), 1);
- match events_4[0] {
- Event::FundingBroadcastSafe { ref funding_txo, user_channel_id } => {
- assert_eq!(user_channel_id, 42);
- assert_eq!(*funding_txo, funding_output);
- },
- _ => panic!("Unexpected event"),
- };
+ assert_eq!(events_4.len(), 0);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0].txid(), funding_output.txid);
let (funding_locked, _) = create_chan_between_nodes_with_value_confirm(&nodes[0], &nodes[1], &tx);
let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &funding_locked);
nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: chan_2.2, data: "ERR".to_owned() });
check_added_monitors!(nodes[0], 1);
check_closed_broadcast!(nodes[0], false);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().split_off(0).len(), 1);
assert_eq!(nodes[0].node.list_usable_channels().len(), 2);
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_1.2 || nodes[0].node.list_usable_channels()[1].channel_id == chan_1.2);
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2 || nodes[0].node.list_usable_channels()[1].channel_id == chan_3.2);
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
assert!(nodes[0].node.list_usable_channels()[0].channel_id == chan_3.2);
}
+
+#[test]
+fn test_invalid_funding_tx() {
+ // Test that we properly handle invalid funding transactions sent to us from a peer.
+ //
+ // Previously, all other major lightning implementations had failed to properly sanitize
+ // funding transactions from their counterparties, leading to a multi-implementation critical
+ // security vulnerability (though we always sanitized properly, we've previously had
+ // un-released crashes in the sanitization process).
+ 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);
+
+ nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_000, 42, None).unwrap();
+ nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()));
+ nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()));
+
+ let (temporary_channel_id, mut tx, _) = create_funding_transaction(&nodes[0], 100_000, 42);
+ for output in tx.output.iter_mut() {
+ // Make the confirmed funding transaction have a bogus script_pubkey
+ output.script_pubkey = bitcoin::Script::new();
+ }
+
+ nodes[0].node.funding_transaction_generated_unchecked(&temporary_channel_id, tx.clone(), 0).unwrap();
+ nodes[1].node.handle_funding_created(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendFundingCreated, nodes[1].node.get_our_node_id()));
+ check_added_monitors!(nodes[1], 1);
+
+ nodes[0].node.handle_funding_signed(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id()));
+ check_added_monitors!(nodes[0], 1);
+
+ let events_1 = nodes[0].node.get_and_clear_pending_events();
+ assert_eq!(events_1.len(), 0);
+
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().len(), 1);
+ assert_eq!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap()[0], tx);
+ nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clear();
+
+ confirm_transaction_at(&nodes[1], &tx, 1);
+ check_added_monitors!(nodes[1], 1);
+ let events_2 = nodes[1].node.get_and_clear_pending_msg_events();
+ assert_eq!(events_2.len(), 1);
+ if let MessageSendEvent::HandleError { node_id, action } = &events_2[0] {
+ assert_eq!(*node_id, nodes[0].node.get_our_node_id());
+ if let msgs::ErrorAction::SendErrorMessage { msg } = action {
+ assert_eq!(msg.data, "funding tx had wrong script/value or output index");
+ } else { panic!(); }
+ } else { panic!(); }
+ assert_eq!(nodes[1].node.list_channels().len(), 0);
+}