X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_tests.rs;h=a414204379f15abf02f8f0792fb230282ee0a98a;hb=7728d3b6a86db7a12d591c8947fbe88a94fdffdd;hp=3279b275897be8fede7c85c66f7d32d2ab274d62;hpb=da7d53fdf2a0fb7393eea01fe5bff6efbb05dabc;p=rust-lightning diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index 3279b275..a4142043 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -3,13 +3,13 @@ //! claim outputs on-chain. use chain::transaction::OutPoint; -use chain::keysinterface::{KeysInterface, SpendableOutputDescriptor}; +use chain::keysinterface::{ChannelKeys, KeysInterface, SpendableOutputDescriptor}; use chain::chaininterface::{ChainListener, ChainWatchInterfaceUtil, BlockNotifier}; use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC}; use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSendFailure, BREAKDOWN_TIMEOUT}; use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY}; use ln::channel::{Channel, ChannelError}; -use ln::onion_utils; +use ln::{chan_utils, onion_utils}; use ln::router::{Route, RouteHop}; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use ln::msgs; @@ -2152,6 +2152,15 @@ fn claim_htlc_outputs_single_tx() { let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200); nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 200); + + // Expect pending failures, but we don't bother trying to update the channel state with them. + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PendingHTLCsForwardable { .. } => { }, + _ => panic!("Unexpected event"), + }; + connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 200, true, header.bitcoin_hash()); let events = nodes[1].node.get_and_clear_pending_events(); @@ -3406,6 +3415,48 @@ fn test_drop_messages_peer_disconnect_dual_htlc() { claim_payment(&nodes[0], &[&nodes[1]], payment_preimage_2, 1_000_000); } +#[test] +fn test_htlc_timeout() { + // If the user fails to claim/fail an HTLC within the HTLC CLTV timeout we fail it for them + // to avoid our counterparty failing the channel. + let node_cfgs = create_node_cfgs(2); + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::supported(), InitFeatures::supported()); + let (_, our_payment_hash) = route_payment(&nodes[0], &[&nodes[1]], 100000); + + let mut header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected_checked(&header, 101, &[], &[]); + nodes[1].block_notifier.block_connected_checked(&header, 101, &[], &[]); + for i in 102..TEST_FINAL_CLTV + 100 + 1 - CLTV_CLAIM_BUFFER - LATENCY_GRACE_PERIOD_BLOCKS { + header.prev_blockhash = header.bitcoin_hash(); + nodes[0].block_notifier.block_connected_checked(&header, i, &[], &[]); + nodes[1].block_notifier.block_connected_checked(&header, i, &[], &[]); + } + + expect_pending_htlcs_forwardable!(nodes[1]); + + check_added_monitors!(nodes[1], 1); + let htlc_timeout_updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + assert!(htlc_timeout_updates.update_add_htlcs.is_empty()); + assert_eq!(htlc_timeout_updates.update_fail_htlcs.len(), 1); + assert!(htlc_timeout_updates.update_fail_malformed_htlcs.is_empty()); + assert!(htlc_timeout_updates.update_fee.is_none()); + + nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &htlc_timeout_updates.update_fail_htlcs[0]); + commitment_signed_dance!(nodes[0], nodes[1], htlc_timeout_updates.commitment_signed, false); + let events = nodes[0].node.get_and_clear_pending_events(); + match events[0] { + Event::PaymentFailed { payment_hash, rejected_by_dest, error_code } => { + assert_eq!(payment_hash, our_payment_hash); + assert!(rejected_by_dest); + assert_eq!(error_code.unwrap(), 0x4000 | 15); + }, + _ => panic!("Unexpected event"), + } +} + #[test] fn test_invalid_channel_announcement() { //Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs @@ -6663,6 +6714,15 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { // Broadcast set of revoked txn on A let header_128 = connect_blocks(&nodes[0].block_notifier, 128, 0, true, header.bitcoin_hash()); + + // Expect pending failures, but we don't bother trying to update the channel state with them. + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PendingHTLCsForwardable { .. } => { }, + _ => panic!("Unexpected event"), + }; + let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_128, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[0].block_notifier.block_connected(&Block { header: header_129, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] }, 129); let first; @@ -6971,6 +7031,31 @@ fn test_set_outpoints_partial_claiming() { } } +#[test] +fn test_counterparty_raa_skip_no_crash() { + // Previously, if our counterparty sent two RAAs in a row without us having provided a + // commitment transaction, we would have happily carried on and provided them the next + // commitment transaction based on one RAA forward. This would probably eventually have led to + // channel closure, but it would not have resulted in funds loss. Still, our + // EnforcingChannelKeys would have paniced as it doesn't like jumps into the future. Here, we + // check simply that the channel is closed in response to such an RAA, but don't check whether + // we decide to punish our counterparty for revoking their funds (as we don't currently + // implement that). + let node_cfgs = create_node_cfgs(2); + 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(&nodes, 0, 1, InitFeatures::supported(), InitFeatures::supported()); + + let commitment_seed = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan.2).unwrap().local_keys.commitment_seed().clone(); + let next_per_commitment_point = PublicKey::from_secret_key(&Secp256k1::new(), + &SecretKey::from_slice(&chan_utils::build_commitment_secret(&commitment_seed, (1 << 48) - 3)).unwrap()); + let per_commitment_secret = chan_utils::build_commitment_secret(&commitment_seed, (1 << 48) - 1); + + nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(), + &msgs::RevokeAndACK { channel_id: chan.2, per_commitment_secret, next_per_commitment_point }); + assert_eq!(check_closed_broadcast!(nodes[1], true).unwrap().data, "Got a revoke when we weren't expecting one"); +} + #[test] fn test_bump_txn_sanitize_tracking_maps() { // Sanitizing pendning_claim_request and claimable_outpoints used to be buggy, @@ -6994,6 +7079,15 @@ fn test_bump_txn_sanitize_tracking_maps() { // Broadcast set of revoked txn on A let header_128 = connect_blocks(&nodes[0].block_notifier, 128, 0, false, Default::default()); + + // Expect pending failures, but we don't bother trying to update the channel state with them. + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::PendingHTLCsForwardable { .. } => { }, + _ => panic!("Unexpected event"), + }; + let header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_128, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[0].block_notifier.block_connected(&Block { header: header_129, txdata: vec![revoked_local_txn[0].clone()] }, 129); check_closed_broadcast!(nodes[0], false); @@ -7033,10 +7127,41 @@ fn test_simple_payment_secret() { let (payment_preimage, payment_hash) = get_payment_preimage_hash!(&nodes[0]); let (_, payment_secret) = get_payment_preimage_hash!(&nodes[0]); let route = nodes[0].router.get_route(&nodes[2].node.get_our_node_id(), None, &[], 100000, TEST_FINAL_CLTV).unwrap(); - send_along_route_with_secret(&nodes[0], route, &[&nodes[1], &nodes[2]], 100000, payment_hash, Some(payment_secret.0)); + send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[2]]], 100000, payment_hash, Some(payment_secret.0)); // Claiming with all the correct values but the wrong secret should result in nothing... assert_eq!(nodes[2].node.claim_funds(payment_preimage, &None, 100_000), false); assert_eq!(nodes[2].node.claim_funds(payment_preimage, &Some([42; 32]), 100_000), false); // ...but with the right secret we should be able to claim all the way back - claim_payment_along_route_with_secret(&nodes[0], &[&nodes[1], &nodes[2]], false, payment_preimage, Some(payment_secret.0), 100_000); + claim_payment_along_route_with_secret(&nodes[0], &[&[&nodes[1], &nodes[2]]], false, payment_preimage, Some(payment_secret.0), 100_000); +} + +#[test] +fn test_simple_mpp() { + // Simple test of sending a multi-path payment. + let node_cfgs = create_node_cfgs(4); + let node_chanmgrs = create_node_chanmgrs(4, &node_cfgs, &[None, None, None, None]); + let nodes = create_network(4, &node_cfgs, &node_chanmgrs); + + let chan_1_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::supported(), InitFeatures::supported()).0.contents.short_channel_id; + let chan_2_id = create_announced_chan_between_nodes(&nodes, 0, 2, InitFeatures::supported(), InitFeatures::supported()).0.contents.short_channel_id; + let chan_3_id = create_announced_chan_between_nodes(&nodes, 1, 3, InitFeatures::supported(), InitFeatures::supported()).0.contents.short_channel_id; + let chan_4_id = create_announced_chan_between_nodes(&nodes, 2, 3, InitFeatures::supported(), InitFeatures::supported()).0.contents.short_channel_id; + + let (payment_preimage, payment_hash) = get_payment_preimage_hash!(&nodes[0]); + let (_, payment_secret) = get_payment_preimage_hash!(&nodes[0]); + let mut route = nodes[0].router.get_route(&nodes[3].node.get_our_node_id(), None, &[], 100000, TEST_FINAL_CLTV).unwrap(); + let path = route.paths[0].clone(); + route.paths.push(path); + route.paths[0][0].pubkey = nodes[1].node.get_our_node_id(); + route.paths[0][0].short_channel_id = chan_1_id; + route.paths[0][1].short_channel_id = chan_3_id; + route.paths[1][0].pubkey = nodes[2].node.get_our_node_id(); + route.paths[1][0].short_channel_id = chan_2_id; + route.paths[1][1].short_channel_id = chan_4_id; + send_along_route_with_secret(&nodes[0], route, &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], 200_000, payment_hash, Some(payment_secret.0)); + // Claiming with all the correct values but the wrong secret should result in nothing... + assert_eq!(nodes[3].node.claim_funds(payment_preimage, &None, 200_000), false); + assert_eq!(nodes[3].node.claim_funds(payment_preimage, &Some([42; 32]), 200_000), false); + // ...but with the right secret we should be able to claim all the way back + claim_payment_along_route_with_secret(&nodes[0], &[&[&nodes[1], &nodes[3]], &[&nodes[2], &nodes[3]]], false, payment_preimage, Some(payment_secret.0), 200_000); }