X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Ffunctional_tests.rs;h=9a3c4b793612ed6215f420599ccf657d7895f97f;hb=38dacf1b93c9e1ce0bfc2b9df573fa3db145cdd9;hp=eda476699cf1849fcc2a32145d27889fce21cd24;hpb=00d063df5c46ef313901f2a69cff8ffe2cf8cb55;p=rust-lightning diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index eda47669..9a3c4b79 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -16,7 +16,7 @@ use chain::keysinterface::{ChannelKeys, KeysInterface, SpendableOutputDescriptor use chain::chaininterface; 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, PaymentSecret, PaymentSendFailure, BREAKDOWN_TIMEOUT}; +use ln::channelmanager::{ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure, BREAKDOWN_TIMEOUT}; use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY}; use ln::channelmonitor; use ln::channel::{Channel, ChannelError}; @@ -24,12 +24,12 @@ use ln::{chan_utils, onion_utils}; use routing::router::{Route, RouteHop, get_route}; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use ln::msgs; -use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction, OptionalField}; +use ln::msgs::{ChannelMessageHandler,RoutingMessageHandler,HTLCFailChannelUpdate, ErrorAction}; use util::enforcing_trait_impls::EnforcingChannelKeys; use util::{byte_utils, test_utils}; use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider}; use util::errors::APIError; -use util::ser::{Writeable, Writer, ReadableArgs, Readable}; +use util::ser::{Writeable, ReadableArgs, Readable}; use util::config::UserConfig; use bitcoin::hashes::sha256d::Hash as Sha256dHash; @@ -57,7 +57,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::default::Default; use std::sync::{Arc, Mutex}; use std::sync::atomic::Ordering; -use std::{mem, io}; +use std::mem; use ln::functional_test_utils::*; use ln::chan_utils::PreCalculatedTxCreationKeys; @@ -4697,7 +4697,7 @@ macro_rules! check_spendable_outputs { spend_tx.input[0].witness.push(remotepubkey.serialize().to_vec()); txn.push(spend_tx); }, - SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref key_derivation_params, ref counterparty_revocation_pubkey } => { + SpendableOutputDescriptor::DynamicOutputP2WSH { ref outpoint, ref per_commitment_point, ref to_self_delay, ref output, ref key_derivation_params, ref revocation_pubkey } => { let input = TxIn { previous_output: outpoint.into_bitcoin_outpoint(), script_sig: Script::new(), @@ -4719,7 +4719,7 @@ macro_rules! check_spendable_outputs { if let Ok(delayed_payment_key) = chan_utils::derive_private_key(&secp_ctx, &per_commitment_point, &keys.inner.delayed_payment_base_key) { let delayed_payment_pubkey = PublicKey::from_secret_key(&secp_ctx, &delayed_payment_key); - let witness_script = chan_utils::get_revokeable_redeemscript(counterparty_revocation_pubkey, *to_self_delay, &delayed_payment_pubkey); + let witness_script = chan_utils::get_revokeable_redeemscript(revocation_pubkey, *to_self_delay, &delayed_payment_pubkey); let sighash = Message::from_slice(&bip143::SigHashCache::new(&spend_tx).signature_hash(0, &witness_script, output.value, SigHashType::All)[..]).unwrap(); let local_delayedsig = secp_ctx.sign(&sighash, &delayed_payment_key); spend_tx.input[0].witness.push(local_delayedsig.serialize_der().to_vec()); @@ -5037,24 +5037,34 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() { check_added_monitors!(nodes[1], 1); let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); - assert_eq!(node_txn.len(), 4); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-timeout, adjusted justice tx, ChannelManager: local commitment tx - assert_eq!(node_txn[0].input.len(), 2); - check_spends!(node_txn[0], revoked_local_txn[0]); - check_spends!(node_txn[1], chan_1.3); + assert_eq!(node_txn.len(), 3); // ChannelMonitor: bogus justice tx, justice tx on revoked outputs, ChannelManager: local commitment tx + // The first transaction generated is bogus - it spends both outputs of revoked_local_txn[0] + // including the one already spent by revoked_htlc_txn[0]. That's OK, we'll spend with valid + // transactions next... + assert_eq!(node_txn[0].input.len(), 3); + check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[0]); + + assert_eq!(node_txn[1].input.len(), 2); + check_spends!(node_txn[1], revoked_local_txn[0], revoked_htlc_txn[0]); + if node_txn[1].input[1].previous_output.txid == revoked_htlc_txn[0].txid() { + assert_ne!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output); + } else { + assert_eq!(node_txn[1].input[0].previous_output.txid, revoked_htlc_txn[0].txid()); + assert_ne!(node_txn[1].input[1].previous_output, revoked_htlc_txn[0].input[0].previous_output); + } + assert_eq!(node_txn[2].input.len(), 1); - check_spends!(node_txn[2], revoked_htlc_txn[0]); - assert_eq!(node_txn[3].input.len(), 1); - check_spends!(node_txn[3], revoked_local_txn[0]); + check_spends!(node_txn[2], chan_1.3); let header_1 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone(), node_txn[2].clone()] }, 1); + nodes[1].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[1].clone()] }, 1); connect_blocks(&nodes[1].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.block_hash()); // Check B's ChannelMonitor was able to generate the right spendable output descriptor let spend_txn = check_spendable_outputs!(nodes[1], 1, node_cfgs[1].keys_manager, 100000); - assert_eq!(spend_txn.len(), 2); - check_spends!(spend_txn[0], node_txn[0]); - check_spends!(spend_txn[1], node_txn[2]); + assert_eq!(spend_txn.len(), 1); + assert_eq!(spend_txn[0].input.len(), 1); + check_spends!(spend_txn[0], node_txn[1]); } #[test] @@ -5072,6 +5082,9 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { assert_eq!(revoked_local_txn[0].input.len(), 1); assert_eq!(revoked_local_txn[0].input[0].previous_output.txid, chan_1.3.txid()); + // The to-be-revoked commitment tx should have one HTLC and one to_remote output + assert_eq!(revoked_local_txn[0].output.len(), 2); + claim_payment(&nodes[0], &vec!(&nodes[1])[..], payment_preimage, 3_000_000); let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; @@ -5086,6 +5099,10 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]); + // Check that the unspent (of two) outputs on revoked_local_txn[0] is a P2WPKH: + let unspent_local_txn_output = revoked_htlc_txn[0].input[0].previous_output.vout as usize ^ 1; + assert_eq!(revoked_local_txn[0].output[unspent_local_txn_output].script_pubkey.len(), 2 + 20); // P2WPKH + // A will generate justice tx from B's revoked commitment/HTLC tx nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone(), revoked_htlc_txn[0].clone()] }, 1); check_closed_broadcast!(nodes[0], false); @@ -5093,21 +5110,39 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() { let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 3); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-success, ChannelManager: local commitment tx - assert_eq!(node_txn[2].input.len(), 1); - check_spends!(node_txn[2], revoked_htlc_txn[0]); + + // The first transaction generated is bogus - it spends both outputs of revoked_local_txn[0] + // including the one already spent by revoked_htlc_txn[0]. That's OK, we'll spend with valid + // transactions next... + assert_eq!(node_txn[0].input.len(), 2); + check_spends!(node_txn[0], revoked_local_txn[0], revoked_htlc_txn[0]); + if node_txn[0].input[1].previous_output.txid == revoked_htlc_txn[0].txid() { + assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output); + } else { + assert_eq!(node_txn[0].input[0].previous_output.txid, revoked_htlc_txn[0].txid()); + assert_eq!(node_txn[0].input[1].previous_output, revoked_htlc_txn[0].input[0].previous_output); + } + + assert_eq!(node_txn[1].input.len(), 1); + check_spends!(node_txn[1], revoked_htlc_txn[0]); + + check_spends!(node_txn[2], chan_1.3); let header_1 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - nodes[0].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[0].clone(), node_txn[2].clone()] }, 1); + nodes[0].block_notifier.block_connected(&Block { header: header_1, txdata: vec![node_txn[1].clone()] }, 1); connect_blocks(&nodes[0].block_notifier, ANTI_REORG_DELAY - 1, 1, true, header.block_hash()); + // Note that nodes[0]'s tx_broadcaster is still locked, so if we get here the channelmonitor + // didn't try to generate any new transactions. + // Check A's ChannelMonitor was able to generate the right spendable output descriptor let spend_txn = check_spendable_outputs!(nodes[0], 1, node_cfgs[0].keys_manager, 100000); - assert_eq!(spend_txn.len(), 5); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking + assert_eq!(spend_txn.len(), 3); // Duplicated SpendableOutput due to block rescan after revoked htlc output tracking assert_eq!(spend_txn[0], spend_txn[1]); - assert_eq!(spend_txn[0], spend_txn[2]); + assert_eq!(spend_txn[0].input.len(), 1); check_spends!(spend_txn[0], revoked_local_txn[0]); // spending to_remote output from revoked local tx - check_spends!(spend_txn[3], node_txn[0]); // spending justice tx output from revoked local tx htlc received output - check_spends!(spend_txn[4], node_txn[2]); // spending justice tx output on htlc success tx + assert_ne!(spend_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output); + check_spends!(spend_txn[2], node_txn[1]); // spending justice tx output on the htlc success tx } #[test] @@ -5921,454 +5956,6 @@ fn htlc_claim_single_commitment_only_b() { do_htlc_claim_previous_remote_commitment_only(false, true); } -fn run_onion_failure_test(_name: &str, test_case: u8, nodes: &Vec, route: &Route, payment_hash: &PaymentHash, callback_msg: F1, callback_node: F2, expected_retryable: bool, expected_error_code: Option, expected_channel_update: Option) - where F1: for <'a> FnMut(&'a mut msgs::UpdateAddHTLC), - F2: FnMut(), -{ - run_onion_failure_test_with_fail_intercept(_name, test_case, nodes, route, payment_hash, callback_msg, |_|{}, callback_node, expected_retryable, expected_error_code, expected_channel_update); -} - -// test_case -// 0: node1 fails backward -// 1: final node fails backward -// 2: payment completed but the user rejects the payment -// 3: final node fails backward (but tamper onion payloads from node0) -// 100: trigger error in the intermediate node and tamper returning fail_htlc -// 200: trigger error in the final node and tamper returning fail_htlc -fn run_onion_failure_test_with_fail_intercept(_name: &str, test_case: u8, nodes: &Vec, route: &Route, payment_hash: &PaymentHash, mut callback_msg: F1, mut callback_fail: F2, mut callback_node: F3, expected_retryable: bool, expected_error_code: Option, expected_channel_update: Option) - where F1: for <'a> FnMut(&'a mut msgs::UpdateAddHTLC), - F2: for <'a> FnMut(&'a mut msgs::UpdateFailHTLC), - F3: FnMut(), -{ - - // reset block height - let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - for ix in 0..nodes.len() { - nodes[ix].block_notifier.block_connected_checked(&header, 1, &[], &[]); - } - - macro_rules! expect_event { - ($node: expr, $event_type: path) => {{ - let events = $node.node.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - match events[0] { - $event_type { .. } => {}, - _ => panic!("Unexpected event"), - } - }} - } - - macro_rules! expect_htlc_forward { - ($node: expr) => {{ - expect_event!($node, Event::PendingHTLCsForwardable); - $node.node.process_pending_htlc_forwards(); - }} - } - - // 0 ~~> 2 send payment - nodes[0].node.send_payment(&route, payment_hash.clone(), &None).unwrap(); - check_added_monitors!(nodes[0], 1); - let update_0 = get_htlc_update_msgs!(nodes[0], nodes[1].node.get_our_node_id()); - // temper update_add (0 => 1) - let mut update_add_0 = update_0.update_add_htlcs[0].clone(); - if test_case == 0 || test_case == 3 || test_case == 100 { - callback_msg(&mut update_add_0); - callback_node(); - } - // 0 => 1 update_add & CS - nodes[1].node.handle_update_add_htlc(&nodes[0].node.get_our_node_id(), &update_add_0); - commitment_signed_dance!(nodes[1], nodes[0], &update_0.commitment_signed, false, true); - - let update_1_0 = match test_case { - 0|100 => { // intermediate node failure; fail backward to 0 - let update_1_0 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); - assert!(update_1_0.update_fail_htlcs.len()+update_1_0.update_fail_malformed_htlcs.len()==1 && (update_1_0.update_fail_htlcs.len()==1 || update_1_0.update_fail_malformed_htlcs.len()==1)); - update_1_0 - }, - 1|2|3|200 => { // final node failure; forwarding to 2 - assert!(nodes[1].node.get_and_clear_pending_msg_events().is_empty()); - // forwarding on 1 - if test_case != 200 { - callback_node(); - } - expect_htlc_forward!(&nodes[1]); - - let update_1 = get_htlc_update_msgs!(nodes[1], nodes[2].node.get_our_node_id()); - check_added_monitors!(&nodes[1], 1); - assert_eq!(update_1.update_add_htlcs.len(), 1); - // tamper update_add (1 => 2) - let mut update_add_1 = update_1.update_add_htlcs[0].clone(); - if test_case != 3 && test_case != 200 { - callback_msg(&mut update_add_1); - } - - // 1 => 2 - nodes[2].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &update_add_1); - commitment_signed_dance!(nodes[2], nodes[1], update_1.commitment_signed, false, true); - - if test_case == 2 || test_case == 200 { - expect_htlc_forward!(&nodes[2]); - expect_event!(&nodes[2], Event::PaymentReceived); - callback_node(); - expect_pending_htlcs_forwardable!(nodes[2]); - } - - let update_2_1 = get_htlc_update_msgs!(nodes[2], nodes[1].node.get_our_node_id()); - if test_case == 2 || test_case == 200 { - check_added_monitors!(&nodes[2], 1); - } - assert!(update_2_1.update_fail_htlcs.len() == 1); - - let mut fail_msg = update_2_1.update_fail_htlcs[0].clone(); - if test_case == 200 { - callback_fail(&mut fail_msg); - } - - // 2 => 1 - nodes[1].node.handle_update_fail_htlc(&nodes[2].node.get_our_node_id(), &fail_msg); - commitment_signed_dance!(nodes[1], nodes[2], update_2_1.commitment_signed, true); - - // backward fail on 1 - let update_1_0 = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); - assert!(update_1_0.update_fail_htlcs.len() == 1); - update_1_0 - }, - _ => unreachable!(), - }; - - // 1 => 0 commitment_signed_dance - if update_1_0.update_fail_htlcs.len() > 0 { - let mut fail_msg = update_1_0.update_fail_htlcs[0].clone(); - if test_case == 100 { - callback_fail(&mut fail_msg); - } - nodes[0].node.handle_update_fail_htlc(&nodes[1].node.get_our_node_id(), &fail_msg); - } else { - nodes[0].node.handle_update_fail_malformed_htlc(&nodes[1].node.get_our_node_id(), &update_1_0.update_fail_malformed_htlcs[0]); - }; - - commitment_signed_dance!(nodes[0], nodes[1], update_1_0.commitment_signed, false, true); - - let events = nodes[0].node.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - if let &Event::PaymentFailed { payment_hash:_, ref rejected_by_dest, ref error_code, error_data: _ } = &events[0] { - assert_eq!(*rejected_by_dest, !expected_retryable); - assert_eq!(*error_code, expected_error_code); - } else { - panic!("Uexpected event"); - } - - let events = nodes[0].node.get_and_clear_pending_msg_events(); - if expected_channel_update.is_some() { - assert_eq!(events.len(), 1); - match events[0] { - MessageSendEvent::PaymentFailureNetworkUpdate { ref update } => { - match update { - &HTLCFailChannelUpdate::ChannelUpdateMessage { .. } => { - if let HTLCFailChannelUpdate::ChannelUpdateMessage { .. } = expected_channel_update.unwrap() {} else { - panic!("channel_update not found!"); - } - }, - &HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => { - if let HTLCFailChannelUpdate::ChannelClosed { short_channel_id: ref expected_short_channel_id, is_permanent: ref expected_is_permanent } = expected_channel_update.unwrap() { - assert!(*short_channel_id == *expected_short_channel_id); - assert!(*is_permanent == *expected_is_permanent); - } else { - panic!("Unexpected message event"); - } - }, - &HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => { - if let HTLCFailChannelUpdate::NodeFailure { node_id: ref expected_node_id, is_permanent: ref expected_is_permanent } = expected_channel_update.unwrap() { - assert!(*node_id == *expected_node_id); - assert!(*is_permanent == *expected_is_permanent); - } else { - panic!("Unexpected message event"); - } - }, - } - }, - _ => panic!("Unexpected message event"), - } - } else { - assert_eq!(events.len(), 0); - } -} - -impl msgs::ChannelUpdate { - fn dummy() -> msgs::ChannelUpdate { - use bitcoin::secp256k1::ffi::Signature as FFISignature; - use bitcoin::secp256k1::Signature; - msgs::ChannelUpdate { - signature: Signature::from(FFISignature::new()), - contents: msgs::UnsignedChannelUpdate { - chain_hash: BlockHash::hash(&vec![0u8][..]), - short_channel_id: 0, - timestamp: 0, - flags: 0, - cltv_expiry_delta: 0, - htlc_minimum_msat: 0, - htlc_maximum_msat: OptionalField::Absent, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: vec![], - } - } - } -} - -struct BogusOnionHopData { - data: Vec -} -impl BogusOnionHopData { - fn new(orig: msgs::OnionHopData) -> Self { - Self { data: orig.encode() } - } -} -impl Writeable for BogusOnionHopData { - fn write(&self, writer: &mut W) -> Result<(), io::Error> { - writer.write_all(&self.data[..]) - } -} - -#[test] -fn test_onion_failure() { - use ln::msgs::ChannelUpdate; - use ln::channelmanager::CLTV_FAR_FAR_AWAY; - use bitcoin::secp256k1; - - const BADONION: u16 = 0x8000; - const PERM: u16 = 0x4000; - const NODE: u16 = 0x2000; - const UPDATE: u16 = 0x1000; - - 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 mut nodes = create_network(3, &node_cfgs, &node_chanmgrs); - for node in nodes.iter() { - *node.keys_manager.override_session_priv.lock().unwrap() = Some([3; 32]); - } - let channels = [create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()), create_announced_chan_between_nodes(&nodes, 1, 2, InitFeatures::known(), InitFeatures::known())]; - let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]); - let net_graph_msg_handler = &nodes[0].net_graph_msg_handler; - let logger = test_utils::TestLogger::new(); - let route = get_route(&nodes[0].node.get_our_node_id(), &net_graph_msg_handler.network_graph.read().unwrap(), &nodes[2].node.get_our_node_id(), None, &Vec::new(), 40000, TEST_FINAL_CLTV, &logger).unwrap(); - // positve case - send_payment(&nodes[0], &vec!(&nodes[1], &nodes[2])[..], 40000, 40_000); - - // intermediate node failure - run_onion_failure_test("invalid_realm", 0, &nodes, &route, &payment_hash, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1; - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height).unwrap(); - let mut new_payloads = Vec::new(); - for payload in onion_payloads.drain(..) { - new_payloads.push(BogusOnionHopData::new(payload)); - } - // break the first (non-final) hop payload by swapping the realm (0) byte for a byte - // describing a length-1 TLV payload, which is obviously bogus. - new_payloads[0].data[0] = 1; - msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash); - }, ||{}, true, Some(PERM|22), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));//XXX incremented channels idx here - - // final node failure - run_onion_failure_test("invalid_realm", 3, &nodes, &route, &payment_hash, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1; - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, cur_height).unwrap(); - let mut new_payloads = Vec::new(); - for payload in onion_payloads.drain(..) { - new_payloads.push(BogusOnionHopData::new(payload)); - } - // break the last-hop payload by swapping the realm (0) byte for a byte describing a - // length-1 TLV payload, which is obviously bogus. - new_payloads[1].data[0] = 1; - msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash); - }, ||{}, false, Some(PERM|22), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true})); - - // the following three with run_onion_failure_test_with_fail_intercept() test only the origin node - // receiving simulated fail messages - // intermediate node failure - run_onion_failure_test_with_fail_intercept("temporary_node_failure", 100, &nodes, &route, &payment_hash, |msg| { - // trigger error - msg.amount_msat -= 1; - }, |msg| { - // and tamper returning error message - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], NODE|2, &[0;0]); - }, ||{}, true, Some(NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][0].pubkey, is_permanent: false})); - - // final node failure - run_onion_failure_test_with_fail_intercept("temporary_node_failure", 200, &nodes, &route, &payment_hash, |_msg| {}, |msg| { - // and tamper returning error message - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], NODE|2, &[0;0]); - }, ||{ - nodes[2].node.fail_htlc_backwards(&payment_hash, &None); - }, true, Some(NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][1].pubkey, is_permanent: false})); - - // intermediate node failure - run_onion_failure_test_with_fail_intercept("permanent_node_failure", 100, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], PERM|NODE|2, &[0;0]); - }, ||{}, true, Some(PERM|NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][0].pubkey, is_permanent: true})); - - // final node failure - run_onion_failure_test_with_fail_intercept("permanent_node_failure", 200, &nodes, &route, &payment_hash, |_msg| {}, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], PERM|NODE|2, &[0;0]); - }, ||{ - nodes[2].node.fail_htlc_backwards(&payment_hash, &None); - }, false, Some(PERM|NODE|2), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][1].pubkey, is_permanent: true})); - - // intermediate node failure - run_onion_failure_test_with_fail_intercept("required_node_feature_missing", 100, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], PERM|NODE|3, &[0;0]); - }, ||{ - nodes[2].node.fail_htlc_backwards(&payment_hash, &None); - }, true, Some(PERM|NODE|3), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][0].pubkey, is_permanent: true})); - - // final node failure - run_onion_failure_test_with_fail_intercept("required_node_feature_missing", 200, &nodes, &route, &payment_hash, |_msg| {}, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[1].shared_secret[..], PERM|NODE|3, &[0;0]); - }, ||{ - nodes[2].node.fail_htlc_backwards(&payment_hash, &None); - }, false, Some(PERM|NODE|3), Some(msgs::HTLCFailChannelUpdate::NodeFailure{node_id: route.paths[0][1].pubkey, is_permanent: true})); - - run_onion_failure_test("invalid_onion_version", 0, &nodes, &route, &payment_hash, |msg| { msg.onion_routing_packet.version = 1; }, ||{}, true, - Some(BADONION|PERM|4), None); - - run_onion_failure_test("invalid_onion_hmac", 0, &nodes, &route, &payment_hash, |msg| { msg.onion_routing_packet.hmac = [3; 32]; }, ||{}, true, - Some(BADONION|PERM|5), None); - - run_onion_failure_test("invalid_onion_key", 0, &nodes, &route, &payment_hash, |msg| { msg.onion_routing_packet.public_key = Err(secp256k1::Error::InvalidPublicKey);}, ||{}, true, - Some(BADONION|PERM|6), None); - - run_onion_failure_test_with_fail_intercept("temporary_channel_failure", 100, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], UPDATE|7, &ChannelUpdate::dummy().encode_with_len()[..]); - }, ||{}, true, Some(UPDATE|7), Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy()})); - - run_onion_failure_test_with_fail_intercept("permanent_channel_failure", 100, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], PERM|8, &[0;0]); - // short_channel_id from the processing node - }, ||{}, true, Some(PERM|8), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true})); - - run_onion_failure_test_with_fail_intercept("required_channel_feature_missing", 100, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - msg.reason = onion_utils::build_first_hop_failure_packet(&onion_keys[0].shared_secret[..], PERM|9, &[0;0]); - // short_channel_id from the processing node - }, ||{}, true, Some(PERM|9), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true})); - - let mut bogus_route = route.clone(); - bogus_route.paths[0][1].short_channel_id -= 1; - run_onion_failure_test("unknown_next_peer", 0, &nodes, &bogus_route, &payment_hash, |_| {}, ||{}, true, Some(PERM|10), - Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: bogus_route.paths[0][1].short_channel_id, is_permanent:true})); - - let amt_to_forward = nodes[1].node.channel_state.lock().unwrap().by_id.get(&channels[1].2).unwrap().get_counterparty_htlc_minimum_msat() - 1; - let mut bogus_route = route.clone(); - let route_len = bogus_route.paths[0].len(); - bogus_route.paths[0][route_len-1].fee_msat = amt_to_forward; - run_onion_failure_test("amount_below_minimum", 0, &nodes, &bogus_route, &payment_hash, |_| {}, ||{}, true, Some(UPDATE|11), Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy()})); - - //TODO: with new config API, we will be able to generate both valid and - //invalid channel_update cases. - run_onion_failure_test("fee_insufficient", 0, &nodes, &route, &payment_hash, |msg| { - msg.amount_msat -= 1; - }, || {}, true, Some(UPDATE|12), Some(msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id: channels[0].0.contents.short_channel_id, is_permanent: true})); - - run_onion_failure_test("incorrect_cltv_expiry", 0, &nodes, &route, &payment_hash, |msg| { - // need to violate: cltv_expiry - cltv_expiry_delta >= outgoing_cltv_value - msg.cltv_expiry -= 1; - }, || {}, true, Some(UPDATE|13), Some(msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id: channels[0].0.contents.short_channel_id, is_permanent: true})); - - run_onion_failure_test("expiry_too_soon", 0, &nodes, &route, &payment_hash, |msg| { - let height = msg.cltv_expiry - CLTV_CLAIM_BUFFER - LATENCY_GRACE_PERIOD_BLOCKS + 1; - let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - - nodes[1].block_notifier.block_connected_checked(&header, height, &[], &[]); - }, ||{}, true, Some(UPDATE|14), Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy()})); - - run_onion_failure_test("unknown_payment_hash", 2, &nodes, &route, &payment_hash, |_| {}, || { - nodes[2].node.fail_htlc_backwards(&payment_hash, &None); - }, false, Some(PERM|15), None); - - run_onion_failure_test("final_expiry_too_soon", 1, &nodes, &route, &payment_hash, |msg| { - let height = msg.cltv_expiry - CLTV_CLAIM_BUFFER - LATENCY_GRACE_PERIOD_BLOCKS + 1; - let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - - nodes[2].block_notifier.block_connected_checked(&header, height, &[], &[]); - }, || {}, true, Some(17), None); - - run_onion_failure_test("final_incorrect_cltv_expiry", 1, &nodes, &route, &payment_hash, |_| {}, || { - for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() { - for f in pending_forwards.iter_mut() { - match f { - &mut HTLCForwardInfo::AddHTLC { ref mut forward_info, .. } => - forward_info.outgoing_cltv_value += 1, - _ => {}, - } - } - } - }, true, Some(18), None); - - run_onion_failure_test("final_incorrect_htlc_amount", 1, &nodes, &route, &payment_hash, |_| {}, || { - // violate amt_to_forward > msg.amount_msat - for (_, pending_forwards) in nodes[1].node.channel_state.lock().unwrap().forward_htlcs.iter_mut() { - for f in pending_forwards.iter_mut() { - match f { - &mut HTLCForwardInfo::AddHTLC { ref mut forward_info, .. } => - forward_info.amt_to_forward -= 1, - _ => {}, - } - } - } - }, true, Some(19), None); - - run_onion_failure_test("channel_disabled", 0, &nodes, &route, &payment_hash, |_| {}, || { - // disconnect event to the channel between nodes[1] ~ nodes[2] - nodes[1].node.peer_disconnected(&nodes[2].node.get_our_node_id(), false); - nodes[2].node.peer_disconnected(&nodes[1].node.get_our_node_id(), false); - }, true, Some(UPDATE|20), Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage{msg: ChannelUpdate::dummy()})); - reconnect_nodes(&nodes[1], &nodes[2], (false, false), (0, 0), (0, 0), (0, 0), (0, 0), (false, false)); - - run_onion_failure_test("expiry_too_far", 0, &nodes, &route, &payment_hash, |msg| { - let session_priv = SecretKey::from_slice(&[3; 32]).unwrap(); - let mut route = route.clone(); - let height = 1; - route.paths[0][1].cltv_expiry_delta += CLTV_FAR_FAR_AWAY + route.paths[0][0].cltv_expiry_delta + 1; - let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route.paths[0], &session_priv).unwrap(); - let (onion_payloads, _, htlc_cltv) = onion_utils::build_onion_payloads(&route.paths[0], 40000, &None, height).unwrap(); - let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); - msg.cltv_expiry = htlc_cltv; - msg.onion_routing_packet = onion_packet; - }, ||{}, true, Some(21), None); -} - #[test] #[should_panic] fn bolt2_open_channel_sending_node_checks_part1() { //This test needs to be on its own as we are catching a panic @@ -8205,21 +7792,23 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]); assert_eq!(revoked_htlc_txn[1].input.len(), 1); assert_eq!(revoked_htlc_txn[1].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + assert_eq!(revoked_htlc_txn[1].output.len(), 1); check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]); } else if revoked_htlc_txn[1].input[0].witness.last().unwrap().len() == ACCEPTED_HTLC_SCRIPT_WEIGHT { assert_eq!(revoked_htlc_txn[1].input.len(), 1); check_spends!(revoked_htlc_txn[1], revoked_local_txn[0]); assert_eq!(revoked_htlc_txn[0].input.len(), 1); assert_eq!(revoked_htlc_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); + assert_eq!(revoked_htlc_txn[0].output.len(), 1); check_spends!(revoked_htlc_txn[0], revoked_local_txn[0]); } // Broadcast set of revoked txn on A - let header_128 = connect_blocks(&nodes[0].block_notifier, 128, 0, true, header.block_hash()); + let header_128 = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected(&Block { header: header_128, txdata: vec![revoked_local_txn[0].clone()] }, 128); expect_pending_htlcs_forwardable_ignore!(nodes[0]); - - 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 header_129 = BlockHeader { version: 0x20000000, prev_blockhash: header_128.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected(&Block { header: header_129, txdata: vec![revoked_htlc_txn[0].clone(), revoked_htlc_txn[1].clone()] }, 129); let first; let feerate_1; let penalty_txn; @@ -8227,32 +7816,71 @@ fn test_bump_penalty_txn_on_revoked_htlcs() { let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 5); // 3 penalty txn on revoked commitment tx + A commitment tx + 1 penalty tnx on revoked HTLC txn // Verify claim tx are spending revoked HTLC txn + + // node_txn 0-2 each spend a separate revoked output from revoked_local_txn[0] + // Note that node_txn[0] and node_txn[1] are bogus - they double spend the revoked_htlc_txn + // which are included in the same block (they are broadcasted because we scan the + // transactions linearly and generate claims as we go, they likely should be removed in the + // future). + assert_eq!(node_txn[0].input.len(), 1); + check_spends!(node_txn[0], revoked_local_txn[0]); + assert_eq!(node_txn[1].input.len(), 1); + check_spends!(node_txn[1], revoked_local_txn[0]); + assert_eq!(node_txn[2].input.len(), 1); + check_spends!(node_txn[2], revoked_local_txn[0]); + + // Each of the three justice transactions claim a separate (single) output of the three + // available, which we check here: + assert_ne!(node_txn[0].input[0].previous_output, node_txn[1].input[0].previous_output); + assert_ne!(node_txn[0].input[0].previous_output, node_txn[2].input[0].previous_output); + assert_ne!(node_txn[1].input[0].previous_output, node_txn[2].input[0].previous_output); + + assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output); + assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output); + + // node_txn[3] is the local commitment tx broadcast just because (and somewhat in case of + // reorgs, though its not clear its ever worth broadcasting conflicting txn like this when + // a remote commitment tx has already been confirmed). + check_spends!(node_txn[3], chan.3); + + // node_txn[4] spends the revoked outputs from the revoked_htlc_txn (which only have one + // output, checked above). assert_eq!(node_txn[4].input.len(), 2); assert_eq!(node_txn[4].output.len(), 1); check_spends!(node_txn[4], revoked_htlc_txn[0], revoked_htlc_txn[1]); + first = node_txn[4].txid(); // Store both feerates for later comparison let fee_1 = revoked_htlc_txn[0].output[0].value + revoked_htlc_txn[1].output[0].value - node_txn[4].output[0].value; feerate_1 = fee_1 * 1000 / node_txn[4].get_weight() as u64; - penalty_txn = vec![node_txn[0].clone(), node_txn[1].clone(), node_txn[2].clone()]; + penalty_txn = vec![node_txn[2].clone()]; node_txn.clear(); } - // Connect three more block to see if bumped penalty are issued for HTLC txn + // Connect one more block to see if bumped penalty are issued for HTLC txn let header_130 = BlockHeader { version: 0x20000000, prev_blockhash: header_129.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; nodes[0].block_notifier.block_connected(&Block { header: header_130, txdata: penalty_txn }, 130); + let header_131 = BlockHeader { version: 0x20000000, prev_blockhash: header_130.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + nodes[0].block_notifier.block_connected(&Block { header: header_131, txdata: Vec::new() }, 131); { let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); assert_eq!(node_txn.len(), 2); // 2 bumped penalty txn on revoked commitment tx check_spends!(node_txn[0], revoked_local_txn[0]); check_spends!(node_txn[1], revoked_local_txn[0]); + // Note that these are both bogus - they spend outputs already claimed in block 129: + if node_txn[0].input[0].previous_output == revoked_htlc_txn[0].input[0].previous_output { + assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output); + } else { + assert_eq!(node_txn[0].input[0].previous_output, revoked_htlc_txn[1].input[0].previous_output); + assert_eq!(node_txn[1].input[0].previous_output, revoked_htlc_txn[0].input[0].previous_output); + } node_txn.clear(); }; // Few more blocks to confirm penalty txn - let header_135 = connect_blocks(&nodes[0].block_notifier, 5, 130, true, header_130.block_hash()); + let header_135 = connect_blocks(&nodes[0].block_notifier, 4, 131, true, header_131.block_hash()); assert!(nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty()); let header_144 = connect_blocks(&nodes[0].block_notifier, 9, 135, true, header_135); let node_txn = { @@ -8735,3 +8363,115 @@ fn test_update_err_monitor_lockdown() { let events = nodes[0].node.get_and_clear_pending_events(); assert_eq!(events.len(), 1); } + +#[test] +fn test_concurrent_monitor_claim() { + // Watchtower A receives block, broadcasts state N, then channel receives new state N+1, + // sending it to both watchtowers, Bob accepts N+1, then receives block and broadcasts + // the latest state N+1, Alice rejects state N+1, but Bob has already broadcast it, + // state N+1 confirms. Alice claims output from state N+1. + + 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 mut nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + // Create some initial channel + let chan_1 = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::known(), InitFeatures::known()); + let outpoint = OutPoint { txid: chan_1.3.txid(), index: 0 }; + + // Rebalance the network to generate htlc in the two directions + send_payment(&nodes[0], &vec!(&nodes[1])[..], 10_000_000, 10_000_000); + + // Route a HTLC from node 0 to node 1 (but don't settle) + route_payment(&nodes[0], &vec!(&nodes[1])[..], 9_000_000).0; + + // Copy SimpleManyChannelMonitor to simulate watchtower Alice and update block height her ChannelMonitor timeout HTLC onchain + let logger = test_utils::TestLogger::with_id(format!("node {}", "Alice")); + let chain_monitor = chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet); + let watchtower_alice = { + let monitors = nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap(); + let monitor = monitors.get(&outpoint).unwrap(); + let mut w = test_utils::TestVecWriter(Vec::new()); + monitor.write_for_disk(&mut w).unwrap(); + let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>::read( + &mut ::std::io::Cursor::new(&w.0)).unwrap().1; + assert!(new_monitor == *monitor); + let watchtower = test_utils::TestChannelMonitor::new(&chain_monitor, &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator); + assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok()); + watchtower + }; + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + watchtower_alice.simple_monitor.block_connected(&header, 135, &vec![], &vec![]); + + // Watchtower Alice should have broadcast a commitment/HTLC-timeout + { + let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(txn.len(), 2); + txn.clear(); + } + + // Copy SimpleManyChannelMonitor to simulate watchtower Bob and make it receive a commitment update first. + let logger = test_utils::TestLogger::with_id(format!("node {}", "Bob")); + let chain_monitor = chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet); + let watchtower_bob = { + let monitors = nodes[0].chan_monitor.simple_monitor.monitors.lock().unwrap(); + let monitor = monitors.get(&outpoint).unwrap(); + let mut w = test_utils::TestVecWriter(Vec::new()); + monitor.write_for_disk(&mut w).unwrap(); + let new_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>::read( + &mut ::std::io::Cursor::new(&w.0)).unwrap().1; + assert!(new_monitor == *monitor); + let watchtower = test_utils::TestChannelMonitor::new(&chain_monitor, &chanmon_cfgs[0].tx_broadcaster, &logger, &chanmon_cfgs[0].fee_estimator); + assert!(watchtower.add_monitor(outpoint, new_monitor).is_ok()); + watchtower + }; + let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + watchtower_bob.simple_monitor.block_connected(&header, 134, &vec![], &vec![]); + + // Route another payment to generate another update with still previous HTLC pending + let (_, payment_hash) = get_payment_preimage_hash!(nodes[0]); + { + 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, &Vec::new(), 3000000 , TEST_FINAL_CLTV, &logger).unwrap(); + nodes[1].node.send_payment(&route, payment_hash, &None).unwrap(); + } + check_added_monitors!(nodes[1], 1); + + let updates = get_htlc_update_msgs!(nodes[1], nodes[0].node.get_our_node_id()); + assert_eq!(updates.update_add_htlcs.len(), 1); + nodes[0].node.handle_update_add_htlc(&nodes[1].node.get_our_node_id(), &updates.update_add_htlcs[0]); + if let Some(ref mut channel) = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2) { + if let Ok((_, _, _, update)) = channel.commitment_signed(&updates.commitment_signed, &node_cfgs[0].fee_estimator, &node_cfgs[0].logger) { + // Watchtower Alice should already have seen the block and reject the update + if let Err(_) = watchtower_alice.simple_monitor.update_monitor(outpoint, update.clone()) {} else { assert!(false); } + if let Ok(_) = watchtower_bob.simple_monitor.update_monitor(outpoint, update.clone()) {} else { assert!(false); } + if let Ok(_) = nodes[0].chan_monitor.update_monitor(outpoint, update) {} else { assert!(false); } + } else { assert!(false); } + } else { assert!(false); }; + // Our local monitor is in-sync and hasn't processed yet timeout + check_added_monitors!(nodes[0], 1); + + //// Provide one more block to watchtower Bob, expect broadcast of commitment and HTLC-Timeout + watchtower_bob.simple_monitor.block_connected(&header, 135, &vec![], &vec![]); + + // Watchtower Bob should have broadcast a commitment/HTLC-timeout + let bob_state_y; + { + let mut txn = chanmon_cfgs[0].tx_broadcaster.txn_broadcasted.lock().unwrap(); + assert_eq!(txn.len(), 2); + bob_state_y = txn[0].clone(); + txn.clear(); + }; + + // We confirm Bob's state Y on Alice, she should broadcast a HTLC-timeout + watchtower_alice.simple_monitor.block_connected(&header, 136, &vec![&bob_state_y][..], &vec![]); + { + 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 + // the onchain detection of the HTLC output + assert_eq!(htlc_txn.len(), 2); + check_spends!(htlc_txn[0], bob_state_y); + check_spends!(htlc_txn[1], bob_state_y); + } +}