X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_tests.rs;h=7a39db2f312b1bf97b7a340906d55018b6d13e53;hb=7af9976261436fe2357a187c2aaa6792fb0506c6;hp=2ab48831b2cb8256bdcf3247ccc9edab03573fc3;hpb=eee1c30ea6592463d41eefad8306223ec5548014;p=rust-lightning diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 2ab48831..7a39db2f 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -12,6 +12,7 @@ //! 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}; @@ -51,7 +52,6 @@ use regex; 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; @@ -1585,7 +1585,7 @@ fn test_fee_spike_violation_fails_htlc() { 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(); @@ -1756,7 +1756,7 @@ fn test_chan_reserve_violation_inbound_htlc_outbound_channel() { // 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); @@ -1879,7 +1879,7 @@ fn test_chan_reserve_violation_inbound_htlc_inbound_chan() { // 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); @@ -2941,8 +2941,7 @@ fn test_htlc_on_chain_success() { 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. @@ -2954,7 +2953,10 @@ fn test_htlc_on_chain_timeout() { 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()); @@ -3068,6 +3070,13 @@ fn test_htlc_on_chain_timeout() { 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 @@ -3400,7 +3409,7 @@ fn fail_backward_pending_htlc_upon_channel_failure() { 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(); @@ -6504,7 +6513,7 @@ fn test_update_add_htlc_bolt2_receiver_check_max_htlc_limit() { 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); @@ -8217,7 +8226,7 @@ fn test_update_err_monitor_lockdown() { 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)); @@ -8276,7 +8285,7 @@ fn test_concurrent_monitor_claim() { 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 { @@ -8302,7 +8311,7 @@ fn test_concurrent_monitor_claim() { 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]); @@ -8328,7 +8337,8 @@ fn test_concurrent_monitor_claim() { 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; @@ -8340,7 +8350,8 @@ fn test_concurrent_monitor_claim() { }; // 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 @@ -8817,3 +8828,53 @@ fn test_error_chans_closed() { 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); +}