diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 73b3f22d4d6..94632212f17 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -56,7 +56,6 @@ use lightning::ln::channelmanager::{ TrustedChannelFeatures, }; use lightning::ln::functional_test_utils::*; -use lightning::ln::funding::{FundingContribution, FundingContributionError, FundingTemplate}; use lightning::ln::inbound_payment::ExpandedKey; use lightning::ln::msgs::{ self, BaseMessageHandler, ChannelMessageHandler, CommitmentUpdate, Init, MessageSendEvent, @@ -570,7 +569,7 @@ type ChanMan<'a> = ChannelManager< #[inline] fn get_payment_secret_hash( dest: &ChanMan, payment_ctr: &mut u64, - payment_preimages: &RefCell>, + payment_preimages: &mut HashMap, ) -> (PaymentSecret, PaymentHash) { *payment_ctr += 1; let mut payment_preimage = PaymentPreimage([0; 32]); @@ -579,7 +578,7 @@ fn get_payment_secret_hash( let payment_secret = dest .create_inbound_payment_for_hash(payment_hash, None, 3600, None) .expect("create_inbound_payment_for_hash failed"); - assert!(payment_preimages.borrow_mut().insert(payment_hash, payment_preimage).is_none()); + assert!(payment_preimages.insert(payment_hash, payment_preimage).is_none()); (payment_secret, payment_hash) } @@ -869,190 +868,348 @@ fn assert_action_timeout_awaiting_response(action: &msgs::ErrorAction) { )); } +#[derive(Copy, Clone)] enum ChanType { Legacy, KeyedAnchors, ZeroFeeCommitments, } -#[inline] -pub fn do_test(data: &[u8], out: Out) { - let broadcast_a = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); - let broadcast_b = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); - let broadcast_c = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); - let router = FuzzRouter {}; +#[derive(Copy, Clone, PartialEq, Eq)] +enum ProcessMessages { + /// Deliver all available messages, including fetching any new messages from + /// `get_and_clear_pending_msg_events()` which may have side effects. + AllMessages, + /// Call `get_and_clear_pending_msg_events()` first, then deliver up to one + /// message, which may already be queued. + OneMessage, + /// Deliver up to one already-queued message. This avoids the side effects of + /// `get_and_clear_pending_msg_events()`, such as freeing the HTLC holding cell. + OnePendingMessage, +} - // Read initial monitor styles and channel type from fuzz input byte 0: - // bits 0-2: monitor styles (1 bit per node) - // bits 3-4: channel type (0=Legacy, 1=KeyedAnchors, 2=ZeroFeeCommitments) - let config_byte = if !data.is_empty() { data[0] } else { 0 }; - let chan_type = match (config_byte >> 3) & 0b11 { - 0 => ChanType::Legacy, - 1 => ChanType::KeyedAnchors, - _ => ChanType::ZeroFeeCommitments, - }; - let mon_style = [ - RefCell::new(if config_byte & 0b01 != 0 { - ChannelMonitorUpdateStatus::InProgress - } else { - ChannelMonitorUpdateStatus::Completed - }), - RefCell::new(if config_byte & 0b10 != 0 { - ChannelMonitorUpdateStatus::InProgress - } else { - ChannelMonitorUpdateStatus::Completed - }), - RefCell::new(if config_byte & 0b100 != 0 { - ChannelMonitorUpdateStatus::InProgress - } else { - ChannelMonitorUpdateStatus::Completed - }), - ]; - - let mut chain_state = ChainState::new(); - let mut node_height_a: u32 = 0; - let mut node_height_b: u32 = 0; - let mut node_height_c: u32 = 0; - - macro_rules! make_node { - ($node_id: expr, $fee_estimator: expr, $broadcaster: expr) => {{ - let logger: Arc = - Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone())); - let node_secret = SecretKey::from_slice(&[ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, $node_id, - ]) - .unwrap(); - let keys_manager = Arc::new(KeyProvider { - node_secret, - rand_bytes_id: atomic::AtomicU32::new(0), - enforcement_states: Mutex::new(new_hash_map()), - }); - let monitor = Arc::new(TestChainMonitor::new( - $broadcaster.clone(), - logger.clone(), - $fee_estimator.clone(), - Arc::new(TestPersister { - update_ret: Mutex::new(mon_style[$node_id as usize].borrow().clone()), - }), - Arc::clone(&keys_manager), - )); - - let mut config = UserConfig::default(); - config.channel_config.forwarding_fee_proportional_millionths = 0; - config.channel_handshake_config.announce_for_forwarding = true; - config.reject_inbound_splices = false; - match chan_type { - ChanType::Legacy => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; - }, - ChanType::KeyedAnchors => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; +struct HarnessNode<'a> { + node_id: u8, + node: ChanMan<'a>, + monitor: Arc, + keys_manager: Arc, + logger: Arc, + broadcaster: Arc, + fee_estimator: Arc, + wallet: TestWalletSource, + persistence_style: ChannelMonitorUpdateStatus, + serialized_manager: Vec, + height: u32, + last_htlc_clear_fee: u32, +} + +impl<'a> HarnessNode<'a> { + fn build_loggers( + node_id: u8, out: &Out, + ) -> (Arc, Arc) { + let raw_logger = Arc::new(test_logger::TestLogger::new(node_id.to_string(), out.clone())); + let logger_for_monitor: Arc = raw_logger.clone(); + let logger: Arc = raw_logger; + (logger_for_monitor, logger) + } + + fn build_chain_monitor( + broadcaster: &Arc, fee_estimator: &Arc, + keys_manager: &Arc, logger_for_monitor: Arc, + persistence_style: ChannelMonitorUpdateStatus, + ) -> Arc { + Arc::new(TestChainMonitor::new( + Arc::clone(broadcaster), + logger_for_monitor, + Arc::clone(fee_estimator), + Arc::new(TestPersister { update_ret: Mutex::new(persistence_style) }), + Arc::clone(keys_manager), + )) + } + + fn new( + node_id: u8, wallet: TestWalletSource, fee_estimator: Arc, + broadcaster: Arc, persistence_style: ChannelMonitorUpdateStatus, + out: &Out, router: &'a FuzzRouter, chan_type: ChanType, + ) -> Self { + let (logger_for_monitor, logger) = Self::build_loggers(node_id, out); + let node_secret = SecretKey::from_slice(&[ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, node_id, + ]) + .unwrap(); + let keys_manager = Arc::new(KeyProvider { + node_secret, + rand_bytes_id: atomic::AtomicU32::new(0), + enforcement_states: Mutex::new(new_hash_map()), + }); + let monitor = Self::build_chain_monitor( + &broadcaster, + &fee_estimator, + &keys_manager, + logger_for_monitor, + persistence_style, + ); + let network = Network::Bitcoin; + let best_block_timestamp = genesis_block(network).header.time; + let params = ChainParameters { network, best_block: BestBlock::from_network(network) }; + let node = ChannelManager::new( + Arc::clone(&fee_estimator), + Arc::clone(&monitor), + Arc::clone(&broadcaster), + router, + router, + Arc::clone(&logger), + Arc::clone(&keys_manager), + Arc::clone(&keys_manager), + Arc::clone(&keys_manager), + build_node_config(chan_type), + params, + best_block_timestamp, + ); + Self { + node_id, + node, + monitor, + keys_manager, + logger, + broadcaster, + fee_estimator, + wallet, + persistence_style, + serialized_manager: Vec::new(), + height: 0, + last_htlc_clear_fee: 253, + } + } + + fn our_node_id(&self) -> PublicKey { + self.node.get_our_node_id() + } + + fn set_persistence_style(&mut self, style: ChannelMonitorUpdateStatus) { + self.persistence_style = style; + *self.monitor.persister.update_ret.lock().unwrap() = style; + } + + fn complete_all_monitor_updates(&self, chan_id: &ChannelId) { + if let Some(state) = self.monitor.latest_monitors.lock().unwrap().get_mut(chan_id) { + assert!( + state.pending_monitors.windows(2).all(|pair| pair[0].0 < pair[1].0), + "updates should be sorted by id" + ); + for (id, data) in state.pending_monitors.drain(..) { + self.monitor.chain_monitor.channel_monitor_updated(*chan_id, id).unwrap(); + if id > state.persisted_monitor_id { + state.persisted_monitor_id = id; + state.persisted_monitor = data; + } + } + } + } + + fn complete_all_pending_monitor_updates(&self) { + for (channel_id, state) in self.monitor.latest_monitors.lock().unwrap().iter_mut() { + for (id, data) in state.pending_monitors.drain(..) { + self.monitor.chain_monitor.channel_monitor_updated(*channel_id, id).unwrap(); + if id >= state.persisted_monitor_id { + state.persisted_monitor_id = id; + state.persisted_monitor = data; + } + } + } + } + + fn complete_monitor_update(&self, chan_id: &ChannelId, selector: MonitorUpdateSelector) { + if let Some(state) = self.monitor.latest_monitors.lock().unwrap().get_mut(chan_id) { + assert!( + state.pending_monitors.windows(2).all(|pair| pair[0].0 < pair[1].0), + "updates should be sorted by id" + ); + let update = match selector { + MonitorUpdateSelector::First => { + if state.pending_monitors.is_empty() { + None + } else { + Some(state.pending_monitors.remove(0)) + } }, - ChanType::ZeroFeeCommitments => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true; + MonitorUpdateSelector::Second => { + if state.pending_monitors.len() > 1 { + Some(state.pending_monitors.remove(1)) + } else { + None + } }, + MonitorUpdateSelector::Last => state.pending_monitors.pop(), + }; + if let Some((id, data)) = update { + self.monitor.chain_monitor.channel_monitor_updated(*chan_id, id).unwrap(); + if id > state.persisted_monitor_id { + state.persisted_monitor_id = id; + state.persisted_monitor = data; + } } - let network = Network::Bitcoin; - let best_block_timestamp = genesis_block(network).header.time; - let params = ChainParameters { network, best_block: BestBlock::from_network(network) }; - ( - ChannelManager::new( - $fee_estimator.clone(), - monitor.clone(), - $broadcaster.clone(), - &router, - &router, - Arc::clone(&logger), - keys_manager.clone(), - keys_manager.clone(), - keys_manager.clone(), - config, - params, - best_block_timestamp, - ), - monitor, - keys_manager, - logger, - ) - }}; - } - - let reload_node = |ser: &Vec, - node_id: u8, - old_monitors: &TestChainMonitor, - mut use_old_mons, - keys, - fee_estimator, - broadcaster: Arc| { - let keys_manager = Arc::clone(keys); - let logger: Arc = - Arc::new(test_logger::TestLogger::new(node_id.to_string(), out.clone())); - let chain_monitor = Arc::new(TestChainMonitor::new( - broadcaster.clone(), - logger.clone(), - Arc::clone(fee_estimator), - Arc::new(TestPersister { - update_ret: Mutex::new(ChannelMonitorUpdateStatus::Completed), - }), - Arc::clone(keys), - )); + } + } + + fn sync_with_chain_state(&mut self, chain_state: &ChainState, num_blocks: Option) { + let target_height = if let Some(num_blocks) = num_blocks { + std::cmp::min(self.height + num_blocks, chain_state.tip_height()) + } else { + chain_state.tip_height() + }; + + while self.height < target_height { + self.height += 1; + let (header, txn) = chain_state.block_at(self.height); + let txdata: Vec<_> = txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect(); + if !txdata.is_empty() { + self.node.transactions_confirmed(header, &txdata, self.height); + } + self.node.best_block_updated(header, self.height); + } + } + + fn refresh_serialized_manager(&mut self) { + if self.node.get_and_clear_needs_persistence() { + self.serialized_manager = self.node.encode(); + } + } + + fn bump_fee_estimate(&mut self, chan_type: ChanType) { + let mut max_feerate = self.last_htlc_clear_fee; + if matches!(chan_type, ChanType::Legacy) { + max_feerate *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32; + } + if self.fee_estimator.ret_val.fetch_add(250, atomic::Ordering::AcqRel) + 250 > max_feerate { + self.fee_estimator.ret_val.store(max_feerate, atomic::Ordering::Release); + } + self.node.timer_tick_occurred(); + } + + fn reset_fee_estimate(&self) { + self.fee_estimator.ret_val.store(253, atomic::Ordering::Release); + self.node.timer_tick_occurred(); + } + + fn current_feerate_sat_per_kw(&self) -> FeeRate { + self.fee_estimator.feerate_sat_per_kw() + } + + fn record_last_htlc_clear_fee(&mut self) { + self.last_htlc_clear_fee = self.fee_estimator.ret_val.load(atomic::Ordering::Acquire); + } - let mut config = UserConfig::default(); - config.channel_config.forwarding_fee_proportional_millionths = 0; - config.channel_handshake_config.announce_for_forwarding = true; - config.reject_inbound_splices = false; - match chan_type { - ChanType::Legacy => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; + fn splice_in(&self, counterparty_node_id: &PublicKey, channel_id: &ChannelId) { + let wallet = WalletSync::new(&self.wallet, Arc::clone(&self.logger)); + match self.node.splice_channel(channel_id, counterparty_node_id) { + Ok(funding_template) => { + let feerate = + funding_template.min_rbf_feerate().unwrap_or(self.current_feerate_sat_per_kw()); + if let Ok(contribution) = funding_template.splice_in_sync( + Amount::from_sat(10_000), + feerate, + FeeRate::MAX, + &wallet, + ) { + let _ = self.node.funding_contributed( + channel_id, + counterparty_node_id, + contribution, + None, + ); + } + }, + Err(e) => { + assert!( + matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice")), + "{:?}", + e + ); }, - ChanType::KeyedAnchors => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; + } + } + + fn splice_out(&self, counterparty_node_id: &PublicKey, channel_id: &ChannelId) { + let outbound_capacity_msat = self + .node + .list_channels() + .iter() + .find(|chan| chan.channel_id == *channel_id) + .map(|chan| chan.outbound_capacity_msat) + .unwrap(); + if outbound_capacity_msat < 20_000_000 { + return; + } + match self.node.splice_channel(channel_id, counterparty_node_id) { + Ok(funding_template) => { + let feerate = + funding_template.min_rbf_feerate().unwrap_or(self.current_feerate_sat_per_kw()); + let outputs = vec![TxOut { + value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS), + script_pubkey: self.wallet.get_change_script().unwrap(), + }]; + let wallet_sync = WalletSync::new(&self.wallet, Arc::clone(&self.logger)); + if let Ok(contribution) = + funding_template.splice_out_sync(outputs, feerate, FeeRate::MAX, &wallet_sync) + { + let _ = self.node.funding_contributed( + channel_id, + counterparty_node_id, + contribution, + None, + ); + } }, - ChanType::ZeroFeeCommitments => { - config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; - config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true; + Err(e) => { + assert!( + matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice")), + "{:?}", + e + ); }, } + } + + fn reload( + &mut self, use_old_mons: u8, out: &Out, router: &'a FuzzRouter, chan_type: ChanType, + ) { + let (logger_for_monitor, logger) = Self::build_loggers(self.node_id, out); + let chain_monitor = Self::build_chain_monitor( + &self.broadcaster, + &self.fee_estimator, + &self.keys_manager, + logger_for_monitor, + ChannelMonitorUpdateStatus::Completed, + ); let mut monitors = new_hash_map(); - let mut old_monitors = old_monitors.latest_monitors.lock().unwrap(); - for (channel_id, mut prev_state) in old_monitors.drain() { - let (mon_id, serialized_mon) = if use_old_mons % 3 == 0 { - // Reload with the oldest `ChannelMonitor` (the one that we already told - // `ChannelManager` we finished persisting). - (prev_state.persisted_monitor_id, prev_state.persisted_monitor) - } else if use_old_mons % 3 == 1 { - // Reload with the second-oldest `ChannelMonitor` - let old_mon = (prev_state.persisted_monitor_id, prev_state.persisted_monitor); - prev_state.pending_monitors.drain(..).next().unwrap_or(old_mon) - } else { - // Reload with the newest `ChannelMonitor` - let old_mon = (prev_state.persisted_monitor_id, prev_state.persisted_monitor); - prev_state.pending_monitors.pop().unwrap_or(old_mon) - }; - // Use a different value of `use_old_mons` if we have another monitor (only for node B) - // by shifting `use_old_mons` one in base-3. - use_old_mons /= 3; - let mon = <(BestBlock, ChannelMonitor)>::read( - &mut &serialized_mon[..], - (&**keys, &**keys), - ) - .expect("Failed to read monitor"); - monitors.insert(channel_id, mon.1); - // Update the latest `ChannelMonitor` state to match what we just told LDK. - prev_state.persisted_monitor = serialized_mon; - prev_state.persisted_monitor_id = mon_id; - // Wipe any `ChannelMonitor`s which we never told LDK we finished persisting, - // considering them discarded. LDK should replay these for us as they're stored in - // the `ChannelManager`. - prev_state.pending_monitors.clear(); - chain_monitor.latest_monitors.lock().unwrap().insert(channel_id, prev_state); + let mut use_old_mons = use_old_mons; + { + let mut old_monitors = self.monitor.latest_monitors.lock().unwrap(); + for (channel_id, mut prev_state) in old_monitors.drain() { + let (mon_id, serialized_mon) = if use_old_mons % 3 == 0 { + (prev_state.persisted_monitor_id, prev_state.persisted_monitor) + } else if use_old_mons % 3 == 1 { + let old_mon = (prev_state.persisted_monitor_id, prev_state.persisted_monitor); + prev_state.pending_monitors.drain(..).next().unwrap_or(old_mon) + } else { + let old_mon = (prev_state.persisted_monitor_id, prev_state.persisted_monitor); + prev_state.pending_monitors.pop().unwrap_or(old_mon) + }; + use_old_mons /= 3; + let mon = <(BestBlock, ChannelMonitor)>::read( + &mut &serialized_mon[..], + (&*self.keys_manager, &*self.keys_manager), + ) + .expect("Failed to read monitor"); + monitors.insert(channel_id, mon.1); + prev_state.persisted_monitor = serialized_mon; + prev_state.persisted_monitor_id = mon_id; + prev_state.pending_monitors.clear(); + chain_monitor.latest_monitors.lock().unwrap().insert(channel_id, prev_state); + } } let mut monitor_refs = new_hash_map(); for (channel_id, monitor) in monitors.iter() { @@ -1060,1837 +1217,1985 @@ pub fn do_test(data: &[u8], out: Out) { } let read_args = ChannelManagerReadArgs { - entropy_source: Arc::clone(&keys_manager), - node_signer: Arc::clone(&keys_manager), - signer_provider: keys_manager, - fee_estimator: Arc::clone(fee_estimator), - chain_monitor: chain_monitor.clone(), - tx_broadcaster: broadcaster, - router: &router, - message_router: &router, - logger, - config, + entropy_source: Arc::clone(&self.keys_manager), + node_signer: Arc::clone(&self.keys_manager), + signer_provider: Arc::clone(&self.keys_manager), + fee_estimator: Arc::clone(&self.fee_estimator), + chain_monitor: Arc::clone(&chain_monitor), + tx_broadcaster: Arc::clone(&self.broadcaster), + router, + message_router: router, + logger: Arc::clone(&logger), + config: build_node_config(chan_type), channel_monitors: monitor_refs, }; - let manager = - <(BestBlock, ChanMan)>::read(&mut &ser[..], read_args).expect("Failed to read manager"); - let res = (manager.1, chain_monitor.clone()); + let manager = <(BestBlock, ChanMan)>::read(&mut &self.serialized_manager[..], read_args) + .expect("Failed to read manager"); for (channel_id, mon) in monitors.drain() { assert_eq!( chain_monitor.chain_monitor.watch_channel(channel_id, mon), Ok(ChannelMonitorUpdateStatus::Completed) ); } - *chain_monitor.persister.update_ret.lock().unwrap() = *mon_style[node_id as usize].borrow(); - res - }; + *chain_monitor.persister.update_ret.lock().unwrap() = self.persistence_style; + self.node = manager.1; + self.monitor = chain_monitor; + self.logger = logger; + } +} - macro_rules! complete_all_pending_monitor_updates { - ($monitor: expr) => {{ - for (channel_id, state) in $monitor.latest_monitors.lock().unwrap().iter_mut() { - for (id, data) in state.pending_monitors.drain(..) { - $monitor.chain_monitor.channel_monitor_updated(*channel_id, id).unwrap(); - if id >= state.persisted_monitor_id { - state.persisted_monitor_id = id; - state.persisted_monitor = data; - } - } - } - }}; - } - macro_rules! connect_peers { - ($source: expr, $dest: expr) => {{ - let init_dest = Init { - features: $dest.init_features(), - networks: None, - remote_network_address: None, - }; - $source.peer_connected($dest.get_our_node_id(), &init_dest, true).unwrap(); - let init_src = Init { - features: $source.init_features(), - networks: None, - remote_network_address: None, - }; - $dest.peer_connected($source.get_our_node_id(), &init_src, false).unwrap(); - }}; - } - macro_rules! make_channel { - ($source: expr, $dest: expr, $source_monitor: expr, $dest_monitor: expr, $dest_keys_manager: expr, $chan_id: expr, $trusted_open: expr, $trusted_accept: expr) => {{ - if $trusted_open { - $source - .create_channel_to_trusted_peer_0reserve( - $dest.get_our_node_id(), - 100_000, - 42, - 0, - None, - None, - ) - .unwrap(); - } else { - $source - .create_channel($dest.get_our_node_id(), 100_000, 42, 0, None, None) - .unwrap(); - } - let open_channel = { - let events = $source.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - if let MessageSendEvent::SendOpenChannel { ref msg, .. } = events[0] { - msg.clone() - } else { - panic!("Wrong event type"); - } - }; +struct EventQueues { + ab: Vec, + ba: Vec, + bc: Vec, + cb: Vec, +} - $dest.handle_open_channel($source.get_our_node_id(), &open_channel); - let accept_channel = { - let events = $dest.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - if let events::Event::OpenChannelRequest { - ref temporary_channel_id, - ref counterparty_node_id, - .. - } = events[0] - { - let mut random_bytes = [0u8; 16]; - random_bytes - .copy_from_slice(&$dest_keys_manager.get_secure_random_bytes()[..16]); - let user_channel_id = u128::from_be_bytes(random_bytes); - if $trusted_accept { - $dest - .accept_inbound_channel_from_trusted_peer( - temporary_channel_id, - counterparty_node_id, - user_channel_id, - TrustedChannelFeatures::ZeroReserve, - None, - ) - .unwrap(); - } else { - $dest - .accept_inbound_channel( - temporary_channel_id, - counterparty_node_id, - user_channel_id, - None, - ) - .unwrap(); - } - } else { - panic!("Wrong event type"); - } - let events = $dest.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - if let MessageSendEvent::SendAcceptChannel { ref msg, .. } = events[0] { - msg.clone() - } else { - panic!("Wrong event type"); - } - }; +impl EventQueues { + fn new() -> Self { + Self { ab: Vec::new(), ba: Vec::new(), bc: Vec::new(), cb: Vec::new() } + } - $source.handle_accept_channel($dest.get_our_node_id(), &accept_channel); - { - let mut events = $source.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - if let events::Event::FundingGenerationReady { - temporary_channel_id, - channel_value_satoshis, - output_script, - .. - } = events.pop().unwrap() - { - let tx = Transaction { - version: Version($chan_id), - lock_time: LockTime::ZERO, - input: Vec::new(), - output: vec![TxOut { - value: Amount::from_sat(channel_value_satoshis), - script_pubkey: output_script, - }], - }; - $source - .funding_transaction_generated( - temporary_channel_id, - $dest.get_our_node_id(), - tx.clone(), - ) - .unwrap(); - chain_state.confirm_tx(tx); - } else { - panic!("Wrong event type"); - } - } + fn take_for_node(&mut self, node_idx: usize) -> Vec { + match node_idx { + 0 => { + let mut events = Vec::new(); + mem::swap(&mut events, &mut self.ab); + events + }, + 1 => { + let mut events = Vec::new(); + mem::swap(&mut events, &mut self.ba); + events.extend_from_slice(&self.bc[..]); + self.bc.clear(); + events + }, + 2 => { + let mut events = Vec::new(); + mem::swap(&mut events, &mut self.cb); + events + }, + _ => panic!("invalid node index"), + } + } - let funding_created = { - let events = $source.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - if let MessageSendEvent::SendFundingCreated { ref msg, .. } = events[0] { - msg.clone() - } else { - panic!("Wrong event type"); - } - }; - $dest.handle_funding_created($source.get_our_node_id(), &funding_created); - // Complete any pending monitor updates for dest after watch_channel - complete_all_pending_monitor_updates!($dest_monitor); - - let (funding_signed, channel_id) = { - let events = $dest.get_and_clear_pending_msg_events(); - assert_eq!(events.len(), 1); - if let MessageSendEvent::SendFundingSigned { ref msg, .. } = events[0] { - (msg.clone(), msg.channel_id.clone()) - } else { - panic!("Wrong event type"); - } - }; - let events = $dest.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - if let events::Event::ChannelPending { ref counterparty_node_id, .. } = events[0] { - assert_eq!(counterparty_node_id, &$source.get_our_node_id()); - } else { - panic!("Wrong event type"); - } + fn push_for_node(&mut self, node_idx: usize, event: MessageSendEvent) { + match node_idx { + 0 => self.ab.push(event), + 2 => self.cb.push(event), + _ => panic!("cannot directly queue messages for node {}", node_idx), + } + } - $source.handle_funding_signed($dest.get_our_node_id(), &funding_signed); - // Complete any pending monitor updates for source after watch_channel - complete_all_pending_monitor_updates!($source_monitor); + fn extend_for_node>( + &mut self, node_idx: usize, events: I, + ) { + match node_idx { + 0 => self.ab.extend(events), + 2 => self.cb.extend(events), + _ => panic!("cannot directly queue messages for node {}", node_idx), + } + } - let events = $source.get_and_clear_pending_events(); - assert_eq!(events.len(), 1); - if let events::Event::ChannelPending { - ref counterparty_node_id, - channel_id: ref event_channel_id, - .. - } = events[0] - { - assert_eq!(counterparty_node_id, &$dest.get_our_node_id()); - assert_eq!(*event_channel_id, channel_id); + fn route_from_middle<'a, I: IntoIterator>( + &mut self, excess_events: I, expect_drop_node: Option, nodes: &[HarnessNode<'a>; 3], + ) { + let a_id = nodes[0].our_node_id(); + let expect_drop_id = expect_drop_node.map(|id| nodes[id].our_node_id()); + for event in excess_events { + let push_a = match event { + MessageSendEvent::UpdateHTLCs { ref node_id, .. } + | MessageSendEvent::SendRevokeAndACK { ref node_id, .. } + | MessageSendEvent::SendChannelReestablish { ref node_id, .. } + | MessageSendEvent::SendStfu { ref node_id, .. } + | MessageSendEvent::SendSpliceInit { ref node_id, .. } + | MessageSendEvent::SendSpliceAck { ref node_id, .. } + | MessageSendEvent::SendSpliceLocked { ref node_id, .. } + | MessageSendEvent::SendTxAddInput { ref node_id, .. } + | MessageSendEvent::SendTxAddOutput { ref node_id, .. } + | MessageSendEvent::SendTxRemoveInput { ref node_id, .. } + | MessageSendEvent::SendTxRemoveOutput { ref node_id, .. } + | MessageSendEvent::SendTxComplete { ref node_id, .. } + | MessageSendEvent::SendTxAbort { ref node_id, .. } + | MessageSendEvent::SendTxInitRbf { ref node_id, .. } + | MessageSendEvent::SendTxAckRbf { ref node_id, .. } + | MessageSendEvent::SendTxSignatures { ref node_id, .. } + | MessageSendEvent::SendChannelUpdate { ref node_id, .. } => { + if Some(*node_id) == expect_drop_id { + panic!( + "peer_disconnected should drop msgs bound for the disconnected peer" + ); + } + *node_id == a_id + }, + MessageSendEvent::HandleError { ref action, ref node_id } => { + assert_action_timeout_awaiting_response(action); + if Some(*node_id) == expect_drop_id { + panic!( + "peer_disconnected should drop msgs bound for the disconnected peer" + ); + } + *node_id == a_id + }, + MessageSendEvent::SendChannelReady { .. } + | MessageSendEvent::SendAnnouncementSignatures { .. } + | MessageSendEvent::BroadcastChannelUpdate { .. } => continue, + _ => panic!("Unhandled message event {:?}", event), + }; + if push_a { + self.ba.push(event); } else { - panic!("Wrong event type"); + self.bc.push(event); } - }}; + } } - macro_rules! lock_fundings { - ($nodes: expr) => {{ - let mut node_events = Vec::new(); - for node in $nodes.iter() { - node_events.push(node.get_and_clear_pending_msg_events()); - } - for (idx, node_event) in node_events.iter().enumerate() { - for event in node_event { - if let MessageSendEvent::SendChannelReady { ref node_id, ref msg } = event { - for node in $nodes.iter() { - if node.get_our_node_id() == *node_id { - node.handle_channel_ready($nodes[idx].get_our_node_id(), msg); - } - } - } else { - panic!("Wrong event type"); + fn clear_link(&mut self, link: &PeerLink) { + match (link.node_a, link.node_b) { + (0, 1) | (1, 0) => { + self.ab.clear(); + self.ba.clear(); + }, + (1, 2) | (2, 1) => { + self.bc.clear(); + self.cb.clear(); + }, + _ => panic!("unsupported link"), + } + } + + fn drain_on_disconnect(&mut self, edge_node: usize, nodes: &[HarnessNode<'_>; 3]) { + match edge_node { + 0 => { + for event in nodes[0].node.get_and_clear_pending_msg_events() { + match event { + MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::SendRevokeAndACK { .. } => {}, + MessageSendEvent::SendChannelReestablish { .. } => {}, + MessageSendEvent::SendStfu { .. } => {}, + MessageSendEvent::SendChannelReady { .. } => {}, + MessageSendEvent::SendAnnouncementSignatures { .. } => {}, + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + MessageSendEvent::SendChannelUpdate { .. } => {}, + MessageSendEvent::HandleError { ref action, .. } => { + assert_action_timeout_awaiting_response(action); + }, + _ => panic!("Unhandled message event"), } } - } - - for node in $nodes.iter() { - let events = node.get_and_clear_pending_msg_events(); - for event in events { - if let MessageSendEvent::SendAnnouncementSignatures { .. } = event { - } else { - panic!("Wrong event type"); + self.route_from_middle( + nodes[1].node.get_and_clear_pending_msg_events(), + Some(0), + nodes, + ); + }, + 2 => { + for event in nodes[2].node.get_and_clear_pending_msg_events() { + match event { + MessageSendEvent::UpdateHTLCs { .. } => {}, + MessageSendEvent::SendRevokeAndACK { .. } => {}, + MessageSendEvent::SendChannelReestablish { .. } => {}, + MessageSendEvent::SendStfu { .. } => {}, + MessageSendEvent::SendChannelReady { .. } => {}, + MessageSendEvent::SendAnnouncementSignatures { .. } => {}, + MessageSendEvent::BroadcastChannelUpdate { .. } => {}, + MessageSendEvent::SendChannelUpdate { .. } => {}, + MessageSendEvent::HandleError { ref action, .. } => { + assert_action_timeout_awaiting_response(action); + }, + _ => panic!("Unhandled message event"), } } - } - }}; + self.route_from_middle( + nodes[1].node.get_and_clear_pending_msg_events(), + Some(2), + nodes, + ); + }, + _ => panic!("unsupported disconnected edge"), + } } +} - let wallet_a = TestWalletSource::new(SecretKey::from_slice(&[1; 32]).unwrap()); - let wallet_b = TestWalletSource::new(SecretKey::from_slice(&[2; 32]).unwrap()); - let wallet_c = TestWalletSource::new(SecretKey::from_slice(&[3; 32]).unwrap()); - - let wallets = vec![wallet_a, wallet_b, wallet_c]; - let coinbase_tx = bitcoin::Transaction { - version: bitcoin::transaction::Version::TWO, - lock_time: bitcoin::absolute::LockTime::ZERO, - input: vec![bitcoin::TxIn { ..Default::default() }], - output: wallets - .iter() - .map(|w| TxOut { - value: Amount::from_sat(100_000), - script_pubkey: w.get_change_script().unwrap(), - }) - .collect(), - }; - wallets.iter().enumerate().for_each(|(i, w)| { - w.add_utxo(coinbase_tx.clone(), i as u32); - }); +struct PeerLink { + node_a: usize, + node_b: usize, + channel_ids: [ChannelId; 3], + disconnected: bool, +} - let fee_est_a = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); - let mut last_htlc_clear_fee_a = 253; - let fee_est_b = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); - let mut last_htlc_clear_fee_b = 253; - let fee_est_c = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); - let mut last_htlc_clear_fee_c = 253; - - // 3 nodes is enough to hit all the possible cases, notably unknown-source-unknown-dest - // forwarding. - let (node_a, mut monitor_a, keys_manager_a, logger_a) = make_node!(0, fee_est_a, broadcast_a); - let (node_b, mut monitor_b, keys_manager_b, logger_b) = make_node!(1, fee_est_b, broadcast_b); - let (node_c, mut monitor_c, keys_manager_c, logger_c) = make_node!(2, fee_est_c, broadcast_c); - - let mut nodes = [node_a, node_b, node_c]; - #[allow(unused_variables)] - let loggers = [logger_a, logger_b, logger_c]; - #[allow(unused_variables)] - let fee_estimators = [Arc::clone(&fee_est_a), Arc::clone(&fee_est_b), Arc::clone(&fee_est_c)]; - - // Connect peers first, then create channels - connect_peers!(nodes[0], nodes[1]); - connect_peers!(nodes[1], nodes[2]); - - // Create 3 channels between A-B and 3 channels between B-C (6 total). - // - // Use distinct version numbers for each funding transaction so each test channel gets its own - // txid and funding outpoint. - // A-B: channel 2 A and B have 0-reserve (trusted open + trusted accept), - // channel 3 A has 0-reserve (trusted accept) - make_channel!(nodes[0], nodes[1], monitor_a, monitor_b, keys_manager_b, 1, false, false); - make_channel!(nodes[0], nodes[1], monitor_a, monitor_b, keys_manager_b, 2, true, true); - make_channel!(nodes[0], nodes[1], monitor_a, monitor_b, keys_manager_b, 3, false, true); - // B-C: channel 4 B has 0-reserve (via trusted accept), - // channel 5 C has 0-reserve (via trusted open) - make_channel!(nodes[1], nodes[2], monitor_b, monitor_c, keys_manager_c, 4, false, true); - make_channel!(nodes[1], nodes[2], monitor_b, monitor_c, keys_manager_c, 5, true, false); - make_channel!(nodes[1], nodes[2], monitor_b, monitor_c, keys_manager_c, 6, false, false); - - // Wipe the transactions-broadcasted set to make sure we don't broadcast any transactions - // during normal operation in `test_return`. - broadcast_a.txn_broadcasted.borrow_mut().clear(); - broadcast_b.txn_broadcasted.borrow_mut().clear(); - broadcast_c.txn_broadcasted.borrow_mut().clear(); - - let sync_with_chain_state = |chain_state: &ChainState, - node: &ChannelManager<_, _, _, _, _, _, _, _, _>, - node_height: &mut u32, - num_blocks: Option| { - let target_height = if let Some(num_blocks) = num_blocks { - std::cmp::min(*node_height + num_blocks, chain_state.tip_height()) - } else { - chain_state.tip_height() - }; +impl PeerLink { + fn new(node_a: usize, node_b: usize, channel_ids: [ChannelId; 3]) -> Self { + Self { node_a, node_b, channel_ids, disconnected: false } + } - while *node_height < target_height { - *node_height += 1; - let (header, txn) = chain_state.block_at(*node_height); - let txdata: Vec<_> = txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect(); - if !txdata.is_empty() { - node.transactions_confirmed(header, &txdata, *node_height); - } - node.best_block_updated(header, *node_height); - } - }; + fn first_channel_id(&self) -> ChannelId { + self.channel_ids[0] + } - // Sync all nodes to tip to lock the funding. - sync_with_chain_state(&mut chain_state, &nodes[0], &mut node_height_a, None); - sync_with_chain_state(&mut chain_state, &nodes[1], &mut node_height_b, None); - sync_with_chain_state(&mut chain_state, &nodes[2], &mut node_height_c, None); + fn channel_ids(&self) -> &[ChannelId; 3] { + &self.channel_ids + } - lock_fundings!(nodes); + fn complete_all_monitor_updates(&self, nodes: &[HarnessNode<'_>; 3]) { + for id in &self.channel_ids { + nodes[self.node_a].complete_all_monitor_updates(id); + nodes[self.node_b].complete_all_monitor_updates(id); + } + } - // Get channel IDs for all A-B channels (from node A's perspective) - let chan_ab_ids = { - let node_a_chans = nodes[0].list_usable_channels(); - [node_a_chans[0].channel_id, node_a_chans[1].channel_id, node_a_chans[2].channel_id] - }; - // Get channel IDs for all B-C channels (from node C's perspective) - let chan_bc_ids = { - let node_c_chans = nodes[2].list_usable_channels(); - [node_c_chans[0].channel_id, node_c_chans[1].channel_id, node_c_chans[2].channel_id] - }; - // Keep old names for backward compatibility in existing code - let chan_a_id = chan_ab_ids[0]; - let chan_b_id = chan_bc_ids[0]; - - let mut p_ctr: u64 = 0; - - let mut peers_ab_disconnected = false; - let mut peers_bc_disconnected = false; - let mut ab_events = Vec::new(); - let mut ba_events = Vec::new(); - let mut bc_events = Vec::new(); - let mut cb_events = Vec::new(); - - let mut node_a_ser = nodes[0].encode(); - let mut node_b_ser = nodes[1].encode(); - let mut node_c_ser = nodes[2].encode(); - - let pending_payments = RefCell::new([Vec::new(), Vec::new(), Vec::new()]); - let resolved_payments: RefCell<[HashMap>; 3]> = - RefCell::new([new_hash_map(), new_hash_map(), new_hash_map()]); - let claimed_payment_hashes: RefCell> = RefCell::new(HashSet::new()); - let payment_preimages: RefCell> = - RefCell::new(new_hash_map()); - - macro_rules! test_return { - () => {{ - assert_eq!(nodes[0].list_channels().len(), 3); - assert_eq!(nodes[1].list_channels().len(), 6); - assert_eq!(nodes[2].list_channels().len(), 3); - - // All broadcasters should be empty (all broadcast transactions should be handled - // explicitly). - assert!(broadcast_a.txn_broadcasted.borrow().is_empty()); - assert!(broadcast_b.txn_broadcasted.borrow().is_empty()); - assert!(broadcast_c.txn_broadcasted.borrow().is_empty()); + fn complete_monitor_updates_for_node( + &self, node_idx: usize, nodes: &[HarnessNode<'_>; 3], selector: MonitorUpdateSelector, + ) { + assert!(node_idx == self.node_a || node_idx == self.node_b); + for id in &self.channel_ids { + nodes[node_idx].complete_monitor_update(id, selector); + } + } + fn disconnect(&mut self, nodes: &mut [HarnessNode<'_>; 3], queues: &mut EventQueues) { + if self.disconnected { return; - }}; + } + let node_a_id = nodes[self.node_a].our_node_id(); + let node_b_id = nodes[self.node_b].our_node_id(); + nodes[self.node_a].node.peer_disconnected(node_b_id); + nodes[self.node_b].node.peer_disconnected(node_a_id); + self.disconnected = true; + let edge_node = if self.node_a == 1 { + self.node_b + } else if self.node_b == 1 { + self.node_a + } else { + panic!("unsupported link topology") + }; + queues.drain_on_disconnect(edge_node, nodes); + queues.clear_link(self); } - let mut read_pos = 1; // First byte was consumed for initial config (mon_style + chan_type) - macro_rules! get_slice { - ($len: expr) => {{ - let slice_len = $len as usize; - if data.len() < read_pos + slice_len { - test_return!(); - } - read_pos += slice_len; - &data[read_pos - slice_len..read_pos] - }}; - } - - let splice_channel = - |node: &ChanMan, - counterparty_node_id: &PublicKey, - channel_id: &ChannelId, - f: &dyn Fn(FundingTemplate) -> Result| { - match node.splice_channel(channel_id, counterparty_node_id) { - Ok(funding_template) => { - if let Ok(contribution) = f(funding_template) { - let _ = node.funding_contributed( - channel_id, - counterparty_node_id, - contribution, - None, - ); - } - }, - Err(e) => { - assert!( - matches!(e, APIError::APIMisuseError { ref err } if err.contains("splice")), - "{:?}", - e - ); - }, - } + fn reconnect(&mut self, nodes: &mut [HarnessNode<'_>; 3]) { + if !self.disconnected { + return; + } + let node_a_id = nodes[self.node_a].our_node_id(); + let node_b_id = nodes[self.node_b].our_node_id(); + let init_b = Init { + features: nodes[self.node_b].node.init_features(), + networks: None, + remote_network_address: None, }; - - let splice_in = - |node: &ChanMan, - counterparty_node_id: &PublicKey, - channel_id: &ChannelId, - wallet: &WalletSync<&TestWalletSource, Arc>, - funding_feerate_sat_per_kw: FeeRate| { - splice_channel( - node, - counterparty_node_id, - channel_id, - &move |funding_template: FundingTemplate| { - let feerate = - funding_template.min_rbf_feerate().unwrap_or(funding_feerate_sat_per_kw); - funding_template.splice_in_sync( - Amount::from_sat(10_000), - feerate, - FeeRate::MAX, - wallet, - ) - }, - ); + nodes[self.node_a].node.peer_connected(node_b_id, &init_b, true).unwrap(); + let init_a = Init { + features: nodes[self.node_a].node.init_features(), + networks: None, + remote_network_address: None, }; + nodes[self.node_b].node.peer_connected(node_a_id, &init_a, false).unwrap(); + self.disconnected = false; + } - let splice_out = |node: &ChanMan, - counterparty_node_id: &PublicKey, - channel_id: &ChannelId, - wallet: &TestWalletSource, - logger: Arc, - funding_feerate_sat_per_kw: FeeRate| { - // We conditionally splice out `MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS` only when the node - // has double the balance required to send a payment upon a `0xff` byte. We do this to - // ensure there's always liquidity available for a payment to succeed then. - let outbound_capacity_msat = node - .list_channels() - .iter() - .find(|chan| chan.channel_id == *channel_id) - .map(|chan| chan.outbound_capacity_msat) - .unwrap(); - if outbound_capacity_msat < 20_000_000 { + fn disconnect_for_reload( + &mut self, restarted_node: usize, nodes: &mut [HarnessNode<'_>; 3], + queues: &mut EventQueues, + ) { + if self.disconnected { return; } - splice_channel(node, counterparty_node_id, channel_id, &move |funding_template| { - let feerate = funding_template.min_rbf_feerate().unwrap_or(funding_feerate_sat_per_kw); - let outputs = vec![TxOut { - value: Amount::from_sat(MAX_STD_OUTPUT_DUST_LIMIT_SATOSHIS), - script_pubkey: wallet.get_change_script().unwrap(), - }]; - funding_template.splice_out_sync( - outputs, - feerate, - FeeRate::MAX, - &WalletSync::new(wallet, logger.clone()), - ) - }); - }; + assert!(restarted_node == self.node_a || restarted_node == self.node_b); + + let remaining_node = if restarted_node == self.node_a { self.node_b } else { self.node_a }; + let restarted_node_id = nodes[restarted_node].our_node_id(); + nodes[remaining_node].node.peer_disconnected(restarted_node_id); + self.disconnected = true; + + if remaining_node == 1 { + queues.route_from_middle( + nodes[1].node.get_and_clear_pending_msg_events(), + Some(restarted_node), + nodes, + ); + } else { + nodes[remaining_node].node.get_and_clear_pending_msg_events(); + } + queues.clear_link(self); + } +} - loop { - // Push any events from Node B onto ba_events and bc_events - macro_rules! push_excess_b_events { - ($excess_events: expr, $expect_drop_node: expr) => { { - let a_id = nodes[0].get_our_node_id(); - let expect_drop_node: Option = $expect_drop_node; - let expect_drop_id = if let Some(id) = expect_drop_node { Some(nodes[id].get_our_node_id()) } else { None }; - for event in $excess_events { - let push_a = match event { - MessageSendEvent::UpdateHTLCs { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendRevokeAndACK { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendChannelReestablish { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendStfu { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendSpliceInit { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendSpliceAck { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendSpliceLocked { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxAddInput { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxAddOutput { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxRemoveInput { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxRemoveOutput { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxComplete { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxAbort { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxInitRbf { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxAckRbf { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendTxSignatures { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::SendChannelReady { .. } => continue, - MessageSendEvent::SendAnnouncementSignatures { .. } => continue, - MessageSendEvent::BroadcastChannelUpdate { .. } => continue, - MessageSendEvent::SendChannelUpdate { ref node_id, .. } => { - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - MessageSendEvent::HandleError { ref action, ref node_id } => { - assert_action_timeout_awaiting_response(action); - if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } - *node_id == a_id - }, - _ => panic!("Unhandled message event {:?}", event), - }; - if push_a { ba_events.push(event); } else { bc_events.push(event); } - } - } } - } - - // While delivering messages, we select across three possible message selection processes - // to ensure we get as much coverage as possible. See the individual enum variants for more - // details. - #[derive(PartialEq)] - enum ProcessMessages { - /// Deliver all available messages, including fetching any new messages from - /// `get_and_clear_pending_msg_events()` (which may have side effects). - AllMessages, - /// Call `get_and_clear_pending_msg_events()` first, and then deliver up to one - /// message (which may already be queued). - OneMessage, - /// Deliver up to one already-queued message. This avoids any potential side-effects - /// of `get_and_clear_pending_msg_events()` (eg freeing the HTLC holding cell), which - /// provides potentially more coverage. - OnePendingMessage, - } - - macro_rules! process_msg_events { - ($node: expr, $corrupt_forward: expr, $limit_events: expr) => { { - let mut events = if $node == 1 { - let mut new_events = Vec::new(); - mem::swap(&mut new_events, &mut ba_events); - new_events.extend_from_slice(&bc_events[..]); - bc_events.clear(); - new_events - } else if $node == 0 { - let mut new_events = Vec::new(); - mem::swap(&mut new_events, &mut ab_events); - new_events +#[derive(Copy, Clone)] +enum MonitorUpdateSelector { + First, + Second, + Last, +} + +struct PaymentTracker { + payment_ctr: u64, + pending_payments: [Vec; 3], + resolved_payments: [HashMap>; 3], + claimed_payment_hashes: HashSet, + payment_preimages: HashMap, +} + +impl PaymentTracker { + fn new() -> Self { + Self { + payment_ctr: 0, + pending_payments: [Vec::new(), Vec::new(), Vec::new()], + resolved_payments: [new_hash_map(), new_hash_map(), new_hash_map()], + claimed_payment_hashes: HashSet::new(), + payment_preimages: new_hash_map(), + } + } + + fn next_payment(&mut self, dest: &ChanMan) -> (PaymentSecret, PaymentHash, PaymentId) { + let (secret, hash) = + get_payment_secret_hash(dest, &mut self.payment_ctr, &mut self.payment_preimages); + let mut id = PaymentId([0; 32]); + id.0[0..8].copy_from_slice(&self.payment_ctr.to_ne_bytes()); + (secret, hash, id) + } + + fn send_direct( + &mut self, nodes: &[HarnessNode<'_>; 3], source_idx: usize, dest_idx: usize, + dest_chan_id: ChannelId, amt: u64, + ) -> bool { + let source = &nodes[source_idx].node; + let dest = &nodes[dest_idx].node; + let (secret, hash, id) = self.next_payment(dest); + let succeeded = send_payment(source, dest, dest_chan_id, amt, secret, hash, id); + if succeeded { + self.pending_payments[source_idx].push(id); + } + succeeded + } + + fn send_hop( + &mut self, nodes: &[HarnessNode<'_>; 3], source_idx: usize, middle_idx: usize, + middle_chan_id: ChannelId, dest_idx: usize, dest_chan_id: ChannelId, amt: u64, + ) { + let source = &nodes[source_idx].node; + let middle = &nodes[middle_idx].node; + let dest = &nodes[dest_idx].node; + let (secret, hash, id) = self.next_payment(dest); + let succeeded = send_hop_payment( + source, + middle, + middle_chan_id, + dest, + dest_chan_id, + amt, + secret, + hash, + id, + ); + if succeeded { + self.pending_payments[source_idx].push(id); + } + } + + fn send_mpp_direct( + &mut self, nodes: &[HarnessNode<'_>; 3], source_idx: usize, dest_idx: usize, + dest_chan_ids: &[ChannelId], amt: u64, + ) { + let source = &nodes[source_idx].node; + let dest = &nodes[dest_idx].node; + let (secret, hash, id) = self.next_payment(dest); + let succeeded = send_mpp_payment(source, dest, dest_chan_ids, amt, secret, hash, id); + if succeeded { + self.pending_payments[source_idx].push(id); + } + } + + fn send_mpp_hop( + &mut self, nodes: &[HarnessNode<'_>; 3], source_idx: usize, middle_idx: usize, + middle_chan_ids: &[ChannelId], dest_idx: usize, dest_chan_ids: &[ChannelId], amt: u64, + ) { + let source = &nodes[source_idx].node; + let middle = &nodes[middle_idx].node; + let dest = &nodes[dest_idx].node; + let (secret, hash, id) = self.next_payment(dest); + let succeeded = send_mpp_hop_payment( + source, + middle, + middle_chan_ids, + dest, + dest_chan_ids, + amt, + secret, + hash, + id, + ); + if succeeded { + self.pending_payments[source_idx].push(id); + } + } + + fn claim_payment(&mut self, node: &HarnessNode<'_>, payment_hash: PaymentHash, fail: bool) { + if fail { + node.node.fail_htlc_backwards(&payment_hash); + } else { + let payment_preimage = *self + .payment_preimages + .get(&payment_hash) + .expect("PaymentClaimable for unknown payment hash"); + node.node.claim_funds(payment_preimage); + self.claimed_payment_hashes.insert(payment_hash); + } + } + + fn mark_sent(&mut self, node_idx: usize, sent_id: PaymentId, payment_hash: PaymentHash) { + let idx_opt = self.pending_payments[node_idx].iter().position(|id| *id == sent_id); + if let Some(idx) = idx_opt { + self.pending_payments[node_idx].remove(idx); + self.resolved_payments[node_idx].insert(sent_id, Some(payment_hash)); + } else { + assert!(self.resolved_payments[node_idx].contains_key(&sent_id)); + } + } + + fn mark_resolved_without_hash(&mut self, node_idx: usize, payment_id: PaymentId) { + let idx_opt = self.pending_payments[node_idx].iter().position(|id| *id == payment_id); + if let Some(idx) = idx_opt { + self.pending_payments[node_idx].remove(idx); + self.resolved_payments[node_idx].insert(payment_id, None); + } else if !self.resolved_payments[node_idx].contains_key(&payment_id) { + self.resolved_payments[node_idx].insert(payment_id, None); + } + } + + fn assert_all_resolved(&self) { + for (idx, pending) in self.pending_payments.iter().enumerate() { + assert!( + pending.is_empty(), + "Node {} has {} stuck pending payments after settling all state", + idx, + pending.len() + ); + } + } + + fn assert_claims_reported(&self) { + for hash in self.claimed_payment_hashes.iter() { + let found = self + .resolved_payments + .iter() + .any(|node_resolved| node_resolved.values().any(|h| h.as_ref() == Some(hash))); + assert!( + found, + "Payment {:?} was claimed by receiver but sender never got PaymentSent", + hash + ); + } + } +} + +struct Harness<'a, 'd, Out: Output + MaybeSend + MaybeSync> { + data: &'d [u8], + out: Out, + chan_type: ChanType, + chain_state: ChainState, + nodes: [HarnessNode<'a>; 3], + ab_link: PeerLink, + bc_link: PeerLink, + queues: EventQueues, + payments: PaymentTracker, + read_pos: usize, +} + +fn build_node_config(chan_type: ChanType) -> UserConfig { + let mut config = UserConfig::default(); + config.channel_config.forwarding_fee_proportional_millionths = 0; + config.channel_handshake_config.announce_for_forwarding = true; + config.reject_inbound_splices = false; + match chan_type { + ChanType::Legacy => { + config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; + config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; + }, + ChanType::KeyedAnchors => { + config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true; + config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = false; + }, + ChanType::ZeroFeeCommitments => { + config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = false; + config.channel_handshake_config.negotiate_anchor_zero_fee_commitments = true; + }, + } + config +} + +fn assert_test_invariants(nodes: &[HarnessNode<'_>; 3]) { + assert_eq!(nodes[0].node.list_channels().len(), 3); + assert_eq!(nodes[1].node.list_channels().len(), 6); + assert_eq!(nodes[2].node.list_channels().len(), 3); + + assert!(nodes[0].broadcaster.txn_broadcasted.borrow().is_empty()); + assert!(nodes[1].broadcaster.txn_broadcasted.borrow().is_empty()); + assert!(nodes[2].broadcaster.txn_broadcasted.borrow().is_empty()); +} + +impl<'a, 'd, Out: Output + MaybeSend + MaybeSync> Harness<'a, 'd, Out> { + fn connect_peers(source: &ChanMan<'_>, dest: &ChanMan<'_>) { + let init_dest = + Init { features: dest.init_features(), networks: None, remote_network_address: None }; + source.peer_connected(dest.get_our_node_id(), &init_dest, true).unwrap(); + let init_src = + Init { features: source.init_features(), networks: None, remote_network_address: None }; + dest.peer_connected(source.get_our_node_id(), &init_src, false).unwrap(); + } + + fn make_channel( + source: &HarnessNode<'_>, dest: &HarnessNode<'_>, chan_id: i32, trusted_open: bool, + trusted_accept: bool, chain_state: &mut ChainState, + ) { + if trusted_open { + source + .node + .create_channel_to_trusted_peer_0reserve( + dest.our_node_id(), + 100_000, + 42, + 0, + None, + None, + ) + .unwrap(); + } else { + source.node.create_channel(dest.our_node_id(), 100_000, 42, 0, None, None).unwrap(); + } + let open_channel = { + let events = source.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + if let MessageSendEvent::SendOpenChannel { ref msg, .. } = events[0] { + msg.clone() + } else { + panic!("Wrong event type"); + } + }; + + dest.node.handle_open_channel(source.our_node_id(), &open_channel); + let accept_channel = { + let events = dest.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::OpenChannelRequest { + ref temporary_channel_id, + ref counterparty_node_id, + .. + } = events[0] + { + let mut random_bytes = [0u8; 16]; + random_bytes.copy_from_slice(&dest.keys_manager.get_secure_random_bytes()[..16]); + let user_channel_id = u128::from_be_bytes(random_bytes); + if trusted_accept { + dest.node + .accept_inbound_channel_from_trusted_peer( + temporary_channel_id, + counterparty_node_id, + user_channel_id, + TrustedChannelFeatures::ZeroReserve, + None, + ) + .unwrap(); } else { - let mut new_events = Vec::new(); - mem::swap(&mut new_events, &mut cb_events); - new_events - }; - let mut new_events = Vec::new(); - if $limit_events != ProcessMessages::OnePendingMessage { - new_events = nodes[$node].get_and_clear_pending_msg_events(); + dest.node + .accept_inbound_channel( + temporary_channel_id, + counterparty_node_id, + user_channel_id, + None, + ) + .unwrap(); } - let mut had_events = false; - let mut events_iter = events.drain(..).chain(new_events.drain(..)); - let mut extra_ev = None; - for event in &mut events_iter { - had_events = true; - match event { - MessageSendEvent::UpdateHTLCs { node_id, channel_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == node_id { - for update_add in update_add_htlcs.iter() { - out.locked_write(format!("Delivering update_add_htlc from node {} to node {}.\n", $node, idx).as_bytes()); - if !$corrupt_forward { - dest.handle_update_add_htlc(nodes[$node].get_our_node_id(), update_add); - } else { - // Corrupt the update_add_htlc message so that its HMAC - // check will fail and we generate a - // update_fail_malformed_htlc instead of an - // update_fail_htlc as we do when we reject a payment. - let mut msg_ser = update_add.encode(); - msg_ser[1000] ^= 0xff; - let new_msg = UpdateAddHTLC::read_from_fixed_length_buffer(&mut &msg_ser[..]).unwrap(); - dest.handle_update_add_htlc(nodes[$node].get_our_node_id(), &new_msg); - } - } - let processed_change = !update_add_htlcs.is_empty() || !update_fulfill_htlcs.is_empty() || - !update_fail_htlcs.is_empty() || !update_fail_malformed_htlcs.is_empty(); - for update_fulfill in update_fulfill_htlcs { - out.locked_write(format!("Delivering update_fulfill_htlc from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_update_fulfill_htlc(nodes[$node].get_our_node_id(), update_fulfill); - } - for update_fail in update_fail_htlcs.iter() { - out.locked_write(format!("Delivering update_fail_htlc from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_update_fail_htlc(nodes[$node].get_our_node_id(), update_fail); - } - for update_fail_malformed in update_fail_malformed_htlcs.iter() { - out.locked_write(format!("Delivering update_fail_malformed_htlc from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_update_fail_malformed_htlc(nodes[$node].get_our_node_id(), update_fail_malformed); - } - if let Some(msg) = update_fee { - out.locked_write(format!("Delivering update_fee from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_update_fee(nodes[$node].get_our_node_id(), &msg); - } - if $limit_events != ProcessMessages::AllMessages && processed_change { - // If we only want to process some messages, don't deliver the CS until later. - extra_ev = Some(MessageSendEvent::UpdateHTLCs { node_id, channel_id, updates: CommitmentUpdate { - update_add_htlcs: Vec::new(), - update_fail_htlcs: Vec::new(), - update_fulfill_htlcs: Vec::new(), - update_fail_malformed_htlcs: Vec::new(), - update_fee: None, - commitment_signed - } }); - break; - } - out.locked_write(format!("Delivering commitment_signed from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_commitment_signed_batch_test(nodes[$node].get_our_node_id(), &commitment_signed); - break; - } - } - }, - MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering revoke_and_ack from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_revoke_and_ack(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering channel_reestablish from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_channel_reestablish(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendStfu { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering stfu from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_stfu(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxAddInput { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_add_input from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_add_input(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxAddOutput { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_add_output from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_add_output(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxRemoveInput { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_remove_input from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_remove_input(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxRemoveOutput { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_remove_output from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_remove_output(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxComplete { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_complete from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_complete(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxAbort { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_abort from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_abort(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxInitRbf { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_init_rbf from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_init_rbf(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxAckRbf { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_ack_rbf from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_ack_rbf(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendTxSignatures { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering tx_signatures from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_tx_signatures(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendSpliceInit { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering splice_init from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_splice_init(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendSpliceAck { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering splice_ack from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_splice_ack(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::SendSpliceLocked { ref node_id, ref msg } => { - for (idx, dest) in nodes.iter().enumerate() { - if dest.get_our_node_id() == *node_id { - out.locked_write(format!("Delivering splice_locked from node {} to node {}.\n", $node, idx).as_bytes()); - dest.handle_splice_locked(nodes[$node].get_our_node_id(), msg); - } - } - }, - MessageSendEvent::HandleError { ref action, .. } => { - assert_action_timeout_awaiting_response(action); - }, - MessageSendEvent::SendChannelReady { .. } => { - // Can be generated as a reestablish response - }, - MessageSendEvent::SendAnnouncementSignatures { .. } => { - // Can be generated as a reestablish response - }, - MessageSendEvent::SendChannelUpdate { .. } => { - // Can be generated as a reestablish response - }, - MessageSendEvent::BroadcastChannelUpdate { .. } => { - // Can be generated as a result of calling `timer_tick_occurred` enough - // times while peers are disconnected - }, - _ => panic!("Unhandled message event {:?}", event), - } - if $limit_events != ProcessMessages::AllMessages { - break; + } else { + panic!("Wrong event type"); + } + let events = dest.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + if let MessageSendEvent::SendAcceptChannel { ref msg, .. } = events[0] { + msg.clone() + } else { + panic!("Wrong event type"); + } + }; + + source.node.handle_accept_channel(dest.our_node_id(), &accept_channel); + { + let mut events = source.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::FundingGenerationReady { + temporary_channel_id, + channel_value_satoshis, + output_script, + .. + } = events.pop().unwrap() + { + let tx = Transaction { + version: Version(chan_id), + lock_time: LockTime::ZERO, + input: Vec::new(), + output: vec![TxOut { + value: Amount::from_sat(channel_value_satoshis), + script_pubkey: output_script, + }], + }; + source + .node + .funding_transaction_generated( + temporary_channel_id, + dest.our_node_id(), + tx.clone(), + ) + .unwrap(); + chain_state.confirm_tx(tx); + } else { + panic!("Wrong event type"); + } + } + + let funding_created = { + let events = source.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + if let MessageSendEvent::SendFundingCreated { ref msg, .. } = events[0] { + msg.clone() + } else { + panic!("Wrong event type"); + } + }; + dest.node.handle_funding_created(source.our_node_id(), &funding_created); + dest.complete_all_pending_monitor_updates(); + + let (funding_signed, channel_id) = { + let events = dest.node.get_and_clear_pending_msg_events(); + assert_eq!(events.len(), 1); + if let MessageSendEvent::SendFundingSigned { ref msg, .. } = events[0] { + (msg.clone(), msg.channel_id) + } else { + panic!("Wrong event type"); + } + }; + let events = dest.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::ChannelPending { ref counterparty_node_id, .. } = events[0] { + assert_eq!(counterparty_node_id, &source.our_node_id()); + } else { + panic!("Wrong event type"); + } + + source.node.handle_funding_signed(dest.our_node_id(), &funding_signed); + source.complete_all_pending_monitor_updates(); + + let events = source.node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + if let events::Event::ChannelPending { + ref counterparty_node_id, + channel_id: ref event_channel_id, + .. + } = events[0] + { + assert_eq!(counterparty_node_id, &dest.our_node_id()); + assert_eq!(*event_channel_id, channel_id); + } else { + panic!("Wrong event type"); + } + } + + fn lock_fundings(nodes: &[HarnessNode<'_>; 3]) { + let mut node_events = Vec::new(); + for node in nodes.iter() { + node_events.push(node.node.get_and_clear_pending_msg_events()); + } + for (idx, node_event) in node_events.iter().enumerate() { + for event in node_event { + if let MessageSendEvent::SendChannelReady { ref node_id, ref msg } = event { + for node in nodes.iter() { + if node.our_node_id() == *node_id { + node.node.handle_channel_ready(nodes[idx].our_node_id(), msg); + } } - } - if $node == 1 { - push_excess_b_events!(extra_ev.into_iter().chain(events_iter), None); - } else if $node == 0 { - if let Some(ev) = extra_ev { ab_events.push(ev); } - for event in events_iter { ab_events.push(event); } } else { - if let Some(ev) = extra_ev { cb_events.push(ev); } - for event in events_iter { cb_events.push(event); } + panic!("Wrong event type"); } - had_events - } } - } - - macro_rules! process_msg_noret { - ($node: expr, $corrupt_forward: expr, $limit_events: expr) => {{ - process_msg_events!($node, $corrupt_forward, $limit_events); - }}; - } - - macro_rules! drain_msg_events_on_disconnect { - ($counterparty_id: expr) => {{ - if $counterparty_id == 0 { - for event in nodes[0].get_and_clear_pending_msg_events() { - match event { - MessageSendEvent::UpdateHTLCs { .. } => {}, - MessageSendEvent::SendRevokeAndACK { .. } => {}, - MessageSendEvent::SendChannelReestablish { .. } => {}, - MessageSendEvent::SendStfu { .. } => {}, - MessageSendEvent::SendChannelReady { .. } => {}, - MessageSendEvent::SendAnnouncementSignatures { .. } => {}, - MessageSendEvent::BroadcastChannelUpdate { .. } => {}, - MessageSendEvent::SendChannelUpdate { .. } => {}, - MessageSendEvent::HandleError { ref action, .. } => { - assert_action_timeout_awaiting_response(action); - }, - _ => panic!("Unhandled message event"), - } - } - push_excess_b_events!( - nodes[1].get_and_clear_pending_msg_events().drain(..), - Some(0) - ); - ab_events.clear(); - ba_events.clear(); + } + } + + for node in nodes.iter() { + let events = node.node.get_and_clear_pending_msg_events(); + for event in events { + if let MessageSendEvent::SendAnnouncementSignatures { .. } = event { } else { - for event in nodes[2].get_and_clear_pending_msg_events() { - match event { - MessageSendEvent::UpdateHTLCs { .. } => {}, - MessageSendEvent::SendRevokeAndACK { .. } => {}, - MessageSendEvent::SendChannelReestablish { .. } => {}, - MessageSendEvent::SendStfu { .. } => {}, - MessageSendEvent::SendChannelReady { .. } => {}, - MessageSendEvent::SendAnnouncementSignatures { .. } => {}, - MessageSendEvent::BroadcastChannelUpdate { .. } => {}, - MessageSendEvent::SendChannelUpdate { .. } => {}, - MessageSendEvent::HandleError { ref action, .. } => { - assert_action_timeout_awaiting_response(action); - }, - _ => panic!("Unhandled message event"), - } - } - push_excess_b_events!( - nodes[1].get_and_clear_pending_msg_events().drain(..), - Some(2) - ); - bc_events.clear(); - cb_events.clear(); + panic!("Wrong event type"); } - }}; - } - - macro_rules! process_events { - ($node: expr, $fail: expr) => {{ - // Multiple HTLCs can resolve for the same payment hash, so deduplicate - // claim/fail handling per event batch. - let mut claim_set = new_hash_map(); - let mut events = nodes[$node].get_and_clear_pending_events(); - let had_events = !events.is_empty(); - let mut pending_payments = pending_payments.borrow_mut(); - let mut resolved_payments = resolved_payments.borrow_mut(); - for event in events.drain(..) { - match event { - events::Event::PaymentClaimable { payment_hash, .. } => { - if claim_set.insert(payment_hash.0, ()).is_none() { - if $fail { - nodes[$node].fail_htlc_backwards(&payment_hash); - } else { - let payment_preimage = *payment_preimages - .borrow() - .get(&payment_hash) - .expect("PaymentClaimable for unknown payment hash"); - nodes[$node].claim_funds(payment_preimage); - claimed_payment_hashes.borrow_mut().insert(payment_hash); - } - } - }, - events::Event::PaymentSent { payment_id, payment_hash, .. } => { - let sent_id = payment_id.unwrap(); - let idx_opt = - pending_payments[$node].iter().position(|id| *id == sent_id); - if let Some(idx) = idx_opt { - pending_payments[$node].remove(idx); - resolved_payments[$node].insert(sent_id, Some(payment_hash)); - } else { - assert!(resolved_payments[$node].contains_key(&sent_id)); - } - }, - // Even though we don't explicitly send probes, because probes are - // detected based on hashing the payment hash+preimage, its rather - // trivial for the fuzzer to build payments that accidentally end up - // looking like probes. - events::Event::ProbeSuccessful { payment_id, .. } => { - let idx_opt = - pending_payments[$node].iter().position(|id| *id == payment_id); - if let Some(idx) = idx_opt { - pending_payments[$node].remove(idx); - resolved_payments[$node].insert(payment_id, None); - } else { - assert!(resolved_payments[$node].contains_key(&payment_id)); - } - }, - events::Event::PaymentFailed { payment_id, .. } - | events::Event::ProbeFailed { payment_id, .. } => { - let idx_opt = - pending_payments[$node].iter().position(|id| *id == payment_id); - if let Some(idx) = idx_opt { - pending_payments[$node].remove(idx); - resolved_payments[$node].insert(payment_id, None); - } else if !resolved_payments[$node].contains_key(&payment_id) { - // Payment failed immediately on send, so it was never added to - // pending_payments. Add it to resolved_payments to track it. - resolved_payments[$node].insert(payment_id, None); - } - }, - events::Event::PaymentClaimed { .. } => {}, - events::Event::PaymentPathSuccessful { .. } => {}, - events::Event::PaymentPathFailed { .. } => {}, - events::Event::PaymentForwarded { .. } if $node == 1 => {}, - events::Event::ChannelReady { .. } => {}, - events::Event::HTLCHandlingFailed { .. } => {}, - - events::Event::FundingTransactionReadyForSigning { - channel_id, - counterparty_node_id, - unsigned_transaction, - .. - } => { - let signed_tx = wallets[$node].sign_tx(unsigned_transaction).unwrap(); - nodes[$node] - .funding_transaction_signed( - &channel_id, - &counterparty_node_id, - signed_tx, - ) - .unwrap(); - }, - events::Event::SplicePending { new_funding_txo, .. } => { - let broadcaster = match $node { - 0 => &broadcast_a, - 1 => &broadcast_b, - _ => &broadcast_c, - }; - let mut txs = broadcaster.txn_broadcasted.borrow_mut(); - assert!(txs.len() >= 1); - let splice_tx = txs.remove(0); - assert_eq!(new_funding_txo.txid, splice_tx.compute_txid()); - chain_state.confirm_tx(splice_tx); - }, - events::Event::SpliceFailed { .. } => {}, - events::Event::DiscardFunding { - funding_info: events::FundingInfo::Contribution { .. }, - .. - } => {}, + } + } + } + + fn new(data: &'d [u8], out: Out, router: &'a FuzzRouter) -> Self { + let config_byte = if !data.is_empty() { data[0] } else { 0 }; + let chan_type = match (config_byte >> 3) & 0b11 { + 0 => ChanType::Legacy, + 1 => ChanType::KeyedAnchors, + _ => ChanType::ZeroFeeCommitments, + }; + let persistence_styles = [ + if config_byte & 0b01 != 0 { + ChannelMonitorUpdateStatus::InProgress + } else { + ChannelMonitorUpdateStatus::Completed + }, + if config_byte & 0b10 != 0 { + ChannelMonitorUpdateStatus::InProgress + } else { + ChannelMonitorUpdateStatus::Completed + }, + if config_byte & 0b100 != 0 { + ChannelMonitorUpdateStatus::InProgress + } else { + ChannelMonitorUpdateStatus::Completed + }, + ]; + + let wallet_a = TestWalletSource::new(SecretKey::from_slice(&[1; 32]).unwrap()); + let wallet_b = TestWalletSource::new(SecretKey::from_slice(&[2; 32]).unwrap()); + let wallet_c = TestWalletSource::new(SecretKey::from_slice(&[3; 32]).unwrap()); + let wallets = [&wallet_a, &wallet_b, &wallet_c]; + let coinbase_tx = bitcoin::Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::ZERO, + input: vec![bitcoin::TxIn { ..Default::default() }], + output: wallets + .iter() + .map(|wallet| TxOut { + value: Amount::from_sat(100_000), + script_pubkey: wallet.get_change_script().unwrap(), + }) + .collect(), + }; + for (idx, wallet) in wallets.iter().enumerate() { + wallet.add_utxo(coinbase_tx.clone(), idx as u32); + } + + let fee_est_a = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); + let fee_est_b = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); + let fee_est_c = Arc::new(FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }); + let broadcast_a = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); + let broadcast_b = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); + let broadcast_c = Arc::new(TestBroadcaster { txn_broadcasted: RefCell::new(Vec::new()) }); + + let mut nodes = [ + HarnessNode::new( + 0, + wallet_a, + Arc::clone(&fee_est_a), + Arc::clone(&broadcast_a), + persistence_styles[0], + &out, + router, + chan_type, + ), + HarnessNode::new( + 1, + wallet_b, + Arc::clone(&fee_est_b), + Arc::clone(&broadcast_b), + persistence_styles[1], + &out, + router, + chan_type, + ), + HarnessNode::new( + 2, + wallet_c, + Arc::clone(&fee_est_c), + Arc::clone(&broadcast_c), + persistence_styles[2], + &out, + router, + chan_type, + ), + ]; + let mut chain_state = ChainState::new(); + + Self::connect_peers(&nodes[0].node, &nodes[1].node); + Self::connect_peers(&nodes[1].node, &nodes[2].node); + + Self::make_channel(&nodes[0], &nodes[1], 1, false, false, &mut chain_state); + Self::make_channel(&nodes[0], &nodes[1], 2, true, true, &mut chain_state); + Self::make_channel(&nodes[0], &nodes[1], 3, false, true, &mut chain_state); + Self::make_channel(&nodes[1], &nodes[2], 4, false, true, &mut chain_state); + Self::make_channel(&nodes[1], &nodes[2], 5, true, false, &mut chain_state); + Self::make_channel(&nodes[1], &nodes[2], 6, false, false, &mut chain_state); + + nodes[0].broadcaster.txn_broadcasted.borrow_mut().clear(); + nodes[1].broadcaster.txn_broadcasted.borrow_mut().clear(); + nodes[2].broadcaster.txn_broadcasted.borrow_mut().clear(); + + nodes[0].sync_with_chain_state(&chain_state, None); + nodes[1].sync_with_chain_state(&chain_state, None); + nodes[2].sync_with_chain_state(&chain_state, None); + + Self::lock_fundings(&nodes); + + let chan_ab_ids = { + let node_a_chans = nodes[0].node.list_usable_channels(); + [node_a_chans[0].channel_id, node_a_chans[1].channel_id, node_a_chans[2].channel_id] + }; + let chan_bc_ids = { + let node_c_chans = nodes[2].node.list_usable_channels(); + [node_c_chans[0].channel_id, node_c_chans[1].channel_id, node_c_chans[2].channel_id] + }; + + for node in &mut nodes { + node.serialized_manager = node.node.encode(); + } + + Self { + data, + out, + chan_type, + chain_state, + nodes, + ab_link: PeerLink::new(0, 1, chan_ab_ids), + bc_link: PeerLink::new(1, 2, chan_bc_ids), + queues: EventQueues::new(), + payments: PaymentTracker::new(), + read_pos: 1, + } + } + + fn chan_a_id(&self) -> ChannelId { + self.ab_link.first_channel_id() + } + + fn chan_b_id(&self) -> ChannelId { + self.bc_link.first_channel_id() + } + + fn next_input_byte(&mut self) -> Option { + if self.data.len() < self.read_pos + 1 { + None + } else { + let value = self.data[self.read_pos]; + self.read_pos += 1; + Some(value) + } + } + + fn finish(&self) { + assert_test_invariants(&self.nodes); + } + + fn send_direct( + &mut self, source_idx: usize, dest_idx: usize, dest_chan_id: ChannelId, amt: u64, + ) -> bool { + self.payments.send_direct(&self.nodes, source_idx, dest_idx, dest_chan_id, amt) + } + + fn send_hop( + &mut self, source_idx: usize, middle_idx: usize, middle_chan_id: ChannelId, + dest_idx: usize, dest_chan_id: ChannelId, amt: u64, + ) { + self.payments.send_hop( + &self.nodes, + source_idx, + middle_idx, + middle_chan_id, + dest_idx, + dest_chan_id, + amt, + ); + } + + fn send_mpp_direct( + &mut self, source_idx: usize, dest_idx: usize, dest_chan_ids: &[ChannelId], amt: u64, + ) { + self.payments.send_mpp_direct(&self.nodes, source_idx, dest_idx, dest_chan_ids, amt); + } + + fn send_mpp_hop( + &mut self, source_idx: usize, middle_idx: usize, middle_chan_ids: &[ChannelId], + dest_idx: usize, dest_chan_ids: &[ChannelId], amt: u64, + ) { + self.payments.send_mpp_hop( + &self.nodes, + source_idx, + middle_idx, + middle_chan_ids, + dest_idx, + dest_chan_ids, + amt, + ); + } + + fn process_msg_events( + &mut self, node_idx: usize, corrupt_forward: bool, limit_events: ProcessMessages, + ) -> bool { + process_msg_events_impl( + node_idx, + corrupt_forward, + limit_events, + &self.nodes, + &self.out, + &mut self.queues, + ) + } + + fn process_events(&mut self, node_idx: usize, fail: bool) -> bool { + process_events_impl(node_idx, fail, &self.nodes, &mut self.chain_state, &mut self.payments) + } + + fn process_all_events(&mut self) { + process_all_events_impl( + &self.nodes, + &self.out, + &self.ab_link, + &self.bc_link, + &mut self.chain_state, + &mut self.payments, + &mut self.queues, + ); + } + + fn disconnect_ab(&mut self) { + self.ab_link.disconnect(&mut self.nodes, &mut self.queues); + } + + fn disconnect_bc(&mut self) { + self.bc_link.disconnect(&mut self.nodes, &mut self.queues); + } + + fn reconnect_ab(&mut self) { + self.ab_link.reconnect(&mut self.nodes); + } + + fn reconnect_bc(&mut self) { + self.bc_link.reconnect(&mut self.nodes); + } + + fn restart_node(&mut self, node_idx: usize, v: u8, router: &'a FuzzRouter) { + match node_idx { + 0 => { + self.ab_link.disconnect_for_reload(0, &mut self.nodes, &mut self.queues); + }, + 1 => { + self.ab_link.disconnect_for_reload(1, &mut self.nodes, &mut self.queues); + self.bc_link.disconnect_for_reload(1, &mut self.nodes, &mut self.queues); + }, + 2 => { + self.bc_link.disconnect_for_reload(2, &mut self.nodes, &mut self.queues); + }, + _ => panic!("invalid node index"), + } + self.nodes[node_idx].reload(v, &self.out, router, self.chan_type); + } + + fn settle_all(&mut self) { + self.reconnect_ab(); + self.reconnect_bc(); + + for op in SUPPORTED_SIGNER_OPS { + self.nodes[0].keys_manager.enable_op_for_all_signers(op); + self.nodes[1].keys_manager.enable_op_for_all_signers(op); + self.nodes[2].keys_manager.enable_op_for_all_signers(op); + } + self.nodes[0].node.signer_unblocked(None); + self.nodes[1].node.signer_unblocked(None); + self.nodes[2].node.signer_unblocked(None); + + self.process_all_events(); + + for node in self.nodes.iter() { + node.node.timer_tick_occurred(); + } + self.process_all_events(); + + self.payments.assert_all_resolved(); + self.payments.assert_claims_reported(); + + let chan_ab_ids = self.ab_link.channel_ids().clone(); + let chan_bc_ids = self.bc_link.channel_ids().clone(); + for chan_id in chan_ab_ids { + assert!( + self.send_direct(0, 1, chan_id, 10_000_000) + || self.send_direct(1, 0, chan_id, 10_000_000) + ); + } + for chan_id in chan_bc_ids { + assert!( + self.send_direct(1, 2, chan_id, 10_000_000) + || self.send_direct(2, 1, chan_id, 10_000_000) + ); + } + + self.nodes[0].record_last_htlc_clear_fee(); + self.nodes[1].record_last_htlc_clear_fee(); + self.nodes[2].record_last_htlc_clear_fee(); + } + + fn refresh_serialized_managers(&mut self) { + for node in &mut self.nodes { + node.refresh_serialized_manager(); + } + } +} + +fn process_msg_events_impl( + node_idx: usize, corrupt_forward: bool, limit_events: ProcessMessages, + nodes: &[HarnessNode<'_>; 3], out: &Out, queues: &mut EventQueues, +) -> bool { + fn find_destination_node(nodes: &[HarnessNode<'_>; 3], node_id: &PublicKey) -> usize { + nodes + .iter() + .position(|node| node.our_node_id() == *node_id) + .expect("message destination should be a known harness node") + } + + fn log_msg_delivery( + node_idx: usize, dest_idx: usize, msg_name: &str, out: &Out, + ) { + out.locked_write( + format!("Delivering {} from node {} to node {}.\n", msg_name, node_idx, dest_idx) + .as_bytes(), + ); + } + + fn log_peer_message( + node_idx: usize, node_id: &PublicKey, nodes: &[HarnessNode<'_>; 3], out: &Out, + msg_name: &str, + ) -> usize { + let dest_idx = find_destination_node(nodes, node_id); + log_msg_delivery(node_idx, dest_idx, msg_name, out); + dest_idx + } - _ => panic!("Unhandled event"), - } - } - while nodes[$node].needs_pending_htlc_processing() { - nodes[$node].process_pending_htlc_forwards(); - } - had_events - }}; - } - - macro_rules! process_ev_noret { - ($node: expr, $fail: expr) => {{ - process_events!($node, $fail); - }}; - } - - let complete_first = |v: &mut Vec<_>| if !v.is_empty() { Some(v.remove(0)) } else { None }; - let complete_second = |v: &mut Vec<_>| if v.len() > 1 { Some(v.remove(1)) } else { None }; - let complete_monitor_update = - |monitor: &Arc, - chan_funding, - compl_selector: &dyn Fn(&mut Vec<(u64, Vec)>) -> Option<(u64, Vec)>| { - if let Some(state) = monitor.latest_monitors.lock().unwrap().get_mut(chan_funding) { - assert!( - state.pending_monitors.windows(2).all(|pair| pair[0].0 < pair[1].0), - "updates should be sorted by id" - ); - if let Some((id, data)) = compl_selector(&mut state.pending_monitors) { - monitor.chain_monitor.channel_monitor_updated(*chan_funding, id).unwrap(); - if id > state.persisted_monitor_id { - state.persisted_monitor_id = id; - state.persisted_monitor = data; - } - } - } - }; + fn handle_update_add_htlc( + source_node_id: PublicKey, dest: &HarnessNode<'_>, update_add: &UpdateAddHTLC, + corrupt_forward: bool, + ) { + if !corrupt_forward { + dest.node.handle_update_add_htlc(source_node_id, update_add); + } else { + let mut msg_ser = update_add.encode(); + msg_ser[1000] ^= 0xff; + let new_msg = UpdateAddHTLC::read_from_fixed_length_buffer(&mut &msg_ser[..]).unwrap(); + dest.node.handle_update_add_htlc(source_node_id, &new_msg); + } + } - let complete_all_monitor_updates = |monitor: &Arc, chan_id| { - if let Some(state) = monitor.latest_monitors.lock().unwrap().get_mut(chan_id) { - assert!( - state.pending_monitors.windows(2).all(|pair| pair[0].0 < pair[1].0), - "updates should be sorted by id" - ); - for (id, data) in state.pending_monitors.drain(..) { - monitor.chain_monitor.channel_monitor_updated(*chan_id, id).unwrap(); - if id > state.persisted_monitor_id { - state.persisted_monitor_id = id; - state.persisted_monitor = data; - } - } - } - }; + fn handle_update_htlcs_event( + node_idx: usize, source_node_id: PublicKey, node_id: PublicKey, channel_id: ChannelId, + updates: CommitmentUpdate, corrupt_forward: bool, limit_events: ProcessMessages, + nodes: &[HarnessNode<'_>; 3], out: &Out, + ) -> Option { + let dest_idx = find_destination_node(nodes, &node_id); + let dest = &nodes[dest_idx]; + let CommitmentUpdate { + update_add_htlcs, + update_fail_htlcs, + update_fulfill_htlcs, + update_fail_malformed_htlcs, + update_fee, + commitment_signed, + } = updates; + + for update_add in update_add_htlcs.iter() { + log_msg_delivery(node_idx, dest_idx, "update_add_htlc", out); + handle_update_add_htlc(source_node_id, dest, update_add, corrupt_forward); + } + let processed_change = !update_add_htlcs.is_empty() + || !update_fulfill_htlcs.is_empty() + || !update_fail_htlcs.is_empty() + || !update_fail_malformed_htlcs.is_empty(); + for update_fulfill in update_fulfill_htlcs { + log_msg_delivery(node_idx, dest_idx, "update_fulfill_htlc", out); + dest.node.handle_update_fulfill_htlc(source_node_id, update_fulfill); + } + for update_fail in update_fail_htlcs.iter() { + log_msg_delivery(node_idx, dest_idx, "update_fail_htlc", out); + dest.node.handle_update_fail_htlc(source_node_id, update_fail); + } + for update_fail_malformed in update_fail_malformed_htlcs.iter() { + log_msg_delivery(node_idx, dest_idx, "update_fail_malformed_htlc", out); + dest.node.handle_update_fail_malformed_htlc(source_node_id, update_fail_malformed); + } + if let Some(msg) = update_fee { + log_msg_delivery(node_idx, dest_idx, "update_fee", out); + dest.node.handle_update_fee(source_node_id, &msg); + } + if limit_events != ProcessMessages::AllMessages && processed_change { + return Some(MessageSendEvent::UpdateHTLCs { + node_id, + channel_id, + updates: CommitmentUpdate { + update_add_htlcs: Vec::new(), + update_fail_htlcs: Vec::new(), + update_fulfill_htlcs: Vec::new(), + update_fail_malformed_htlcs: Vec::new(), + update_fee: None, + commitment_signed, + }, + }); + } + log_msg_delivery(node_idx, dest_idx, "commitment_signed", out); + dest.node.handle_commitment_signed_batch_test(source_node_id, &commitment_signed); + None + } - let send = - |source_idx: usize, dest_idx: usize, dest_chan_id, amt, payment_ctr: &mut u64| { - let source = &nodes[source_idx]; - let dest = &nodes[dest_idx]; - let (secret, hash) = get_payment_secret_hash(dest, payment_ctr, &payment_preimages); - let mut id = PaymentId([0; 32]); - id.0[0..8].copy_from_slice(&payment_ctr.to_ne_bytes()); - let succeeded = send_payment(source, dest, dest_chan_id, amt, secret, hash, id); - if succeeded { - pending_payments.borrow_mut()[source_idx].push(id); - } - succeeded - }; - let send_noret = |source_idx, dest_idx, dest_chan_id, amt, payment_ctr: &mut u64| { - send(source_idx, dest_idx, dest_chan_id, amt, payment_ctr); - }; + fn process_msg_event( + node_idx: usize, source_node_id: PublicKey, event: MessageSendEvent, corrupt_forward: bool, + limit_events: ProcessMessages, nodes: &[HarnessNode<'_>; 3], out: &Out, + ) -> Option { + match event { + MessageSendEvent::UpdateHTLCs { node_id, channel_id, updates } => { + handle_update_htlcs_event( + node_idx, + source_node_id, + node_id, + channel_id, + updates, + corrupt_forward, + limit_events, + nodes, + out, + ) + }, + MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "revoke_and_ack"); + nodes[dest_idx].node.handle_revoke_and_ack(source_node_id, msg); + None + }, + MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => { + let dest_idx = + log_peer_message(node_idx, node_id, nodes, out, "channel_reestablish"); + nodes[dest_idx].node.handle_channel_reestablish(source_node_id, msg); + None + }, + MessageSendEvent::SendStfu { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "stfu"); + nodes[dest_idx].node.handle_stfu(source_node_id, msg); + None + }, + MessageSendEvent::SendTxAddInput { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_add_input"); + nodes[dest_idx].node.handle_tx_add_input(source_node_id, msg); + None + }, + MessageSendEvent::SendTxAddOutput { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_add_output"); + nodes[dest_idx].node.handle_tx_add_output(source_node_id, msg); + None + }, + MessageSendEvent::SendTxRemoveInput { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_remove_input"); + nodes[dest_idx].node.handle_tx_remove_input(source_node_id, msg); + None + }, + MessageSendEvent::SendTxRemoveOutput { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_remove_output"); + nodes[dest_idx].node.handle_tx_remove_output(source_node_id, msg); + None + }, + MessageSendEvent::SendTxComplete { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_complete"); + nodes[dest_idx].node.handle_tx_complete(source_node_id, msg); + None + }, + MessageSendEvent::SendTxAbort { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_abort"); + nodes[dest_idx].node.handle_tx_abort(source_node_id, msg); + None + }, + MessageSendEvent::SendTxInitRbf { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_init_rbf"); + nodes[dest_idx].node.handle_tx_init_rbf(source_node_id, msg); + None + }, + MessageSendEvent::SendTxAckRbf { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_ack_rbf"); + nodes[dest_idx].node.handle_tx_ack_rbf(source_node_id, msg); + None + }, + MessageSendEvent::SendTxSignatures { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "tx_signatures"); + nodes[dest_idx].node.handle_tx_signatures(source_node_id, msg); + None + }, + MessageSendEvent::SendSpliceInit { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "splice_init"); + nodes[dest_idx].node.handle_splice_init(source_node_id, msg); + None + }, + MessageSendEvent::SendSpliceAck { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "splice_ack"); + nodes[dest_idx].node.handle_splice_ack(source_node_id, msg); + None + }, + MessageSendEvent::SendSpliceLocked { ref node_id, ref msg } => { + let dest_idx = log_peer_message(node_idx, node_id, nodes, out, "splice_locked"); + nodes[dest_idx].node.handle_splice_locked(source_node_id, msg); + None + }, + MessageSendEvent::HandleError { ref action, .. } => { + assert_action_timeout_awaiting_response(action); + None + }, + MessageSendEvent::SendChannelReady { .. } + | MessageSendEvent::SendAnnouncementSignatures { .. } + | MessageSendEvent::SendChannelUpdate { .. } + | MessageSendEvent::BroadcastChannelUpdate { .. } => None, + _ => panic!("Unhandled message event {:?}", event), + } + } - let send_hop_noret = |source_idx: usize, - middle_idx: usize, - middle_chan_id: ChannelId, - dest_idx: usize, - dest_chan_id: ChannelId, - amt: u64, - payment_ctr: &mut u64| { - let source = &nodes[source_idx]; - let middle = &nodes[middle_idx]; - let dest = &nodes[dest_idx]; - let (secret, hash) = get_payment_secret_hash(dest, payment_ctr, &payment_preimages); - let mut id = PaymentId([0; 32]); - id.0[0..8].copy_from_slice(&payment_ctr.to_ne_bytes()); - let succeeded = send_hop_payment( - source, - middle, - middle_chan_id, - dest, - dest_chan_id, - amt, - secret, - hash, - id, - ); - if succeeded { - pending_payments.borrow_mut()[source_idx].push(id); - } - }; + let mut events = queues.take_for_node(node_idx); + let mut new_events = Vec::new(); + if limit_events != ProcessMessages::OnePendingMessage { + new_events = nodes[node_idx].node.get_and_clear_pending_msg_events(); + } + let mut had_events = false; + let source_node_id = nodes[node_idx].our_node_id(); + let mut events_iter = events.drain(..).chain(new_events.drain(..)); + let mut extra_ev = None; + for event in &mut events_iter { + had_events = true; + extra_ev = process_msg_event( + node_idx, + source_node_id, + event, + corrupt_forward, + limit_events, + nodes, + out, + ); + if limit_events != ProcessMessages::AllMessages { + break; + } + } + if node_idx == 1 { + let remaining = extra_ev.into_iter().chain(events_iter).collect::>(); + queues.route_from_middle(remaining, None, nodes); + } else if node_idx == 0 { + if let Some(ev) = extra_ev { + queues.push_for_node(0, ev); + } + queues.extend_for_node(0, events_iter); + } else { + if let Some(ev) = extra_ev { + queues.push_for_node(2, ev); + } + queues.extend_for_node(2, events_iter); + } + had_events +} - // Direct MPP payment (no hop) - let send_mpp_direct = |source_idx: usize, - dest_idx: usize, - dest_chan_ids: &[ChannelId], - amt: u64, - payment_ctr: &mut u64| { - let source = &nodes[source_idx]; - let dest = &nodes[dest_idx]; - let (secret, hash) = get_payment_secret_hash(dest, payment_ctr, &payment_preimages); - let mut id = PaymentId([0; 32]); - id.0[0..8].copy_from_slice(&payment_ctr.to_ne_bytes()); - let succeeded = send_mpp_payment(source, dest, dest_chan_ids, amt, secret, hash, id); - if succeeded { - pending_payments.borrow_mut()[source_idx].push(id); - } - }; +fn process_events_impl( + node_idx: usize, fail: bool, nodes: &[HarnessNode<'_>; 3], chain_state: &mut ChainState, + payments: &mut PaymentTracker, +) -> bool { + let mut claim_set = new_hash_map(); + let mut events = nodes[node_idx].node.get_and_clear_pending_events(); + let had_events = !events.is_empty(); + for event in events.drain(..) { + match event { + events::Event::PaymentClaimable { payment_hash, .. } => { + if claim_set.insert(payment_hash.0, ()).is_none() { + payments.claim_payment(&nodes[node_idx], payment_hash, fail); + } + }, + events::Event::PaymentSent { payment_id, payment_hash, .. } => { + payments.mark_sent(node_idx, payment_id.unwrap(), payment_hash); + }, + events::Event::ProbeSuccessful { payment_id, .. } => { + payments.mark_resolved_without_hash(node_idx, payment_id); + }, + events::Event::PaymentFailed { payment_id, .. } + | events::Event::ProbeFailed { payment_id, .. } => { + payments.mark_resolved_without_hash(node_idx, payment_id); + }, + events::Event::PaymentClaimed { .. } => {}, + events::Event::PaymentPathSuccessful { .. } => {}, + events::Event::PaymentPathFailed { .. } => {}, + events::Event::PaymentForwarded { .. } if node_idx == 1 => {}, + events::Event::ChannelReady { .. } => {}, + events::Event::HTLCHandlingFailed { .. } => {}, + events::Event::FundingTransactionReadyForSigning { + channel_id, + counterparty_node_id, + unsigned_transaction, + .. + } => { + let signed_tx = nodes[node_idx].wallet.sign_tx(unsigned_transaction).unwrap(); + nodes[node_idx] + .node + .funding_transaction_signed(&channel_id, &counterparty_node_id, signed_tx) + .unwrap(); + }, + events::Event::SplicePending { new_funding_txo, .. } => { + let mut txs = nodes[node_idx].broadcaster.txn_broadcasted.borrow_mut(); + assert!(txs.len() >= 1); + let splice_tx = txs.remove(0); + assert_eq!(new_funding_txo.txid, splice_tx.compute_txid()); + chain_state.confirm_tx(splice_tx); + }, + events::Event::SpliceFailed { .. } => {}, + events::Event::DiscardFunding { + funding_info: events::FundingInfo::Contribution { .. }, + .. + } => {}, + _ => panic!("Unhandled event"), + } + } + while nodes[node_idx].node.needs_pending_htlc_processing() { + nodes[node_idx].node.process_pending_htlc_forwards(); + } + had_events +} - // MPP payment via hop - splits payment across multiple channels on either or both hops - let send_mpp_hop = |source_idx: usize, - middle_idx: usize, - middle_chan_ids: &[ChannelId], - dest_idx: usize, - dest_chan_ids: &[ChannelId], - amt: u64, - payment_ctr: &mut u64| { - let source = &nodes[source_idx]; - let middle = &nodes[middle_idx]; - let dest = &nodes[dest_idx]; - let (secret, hash) = get_payment_secret_hash(dest, payment_ctr, &payment_preimages); - let mut id = PaymentId([0; 32]); - id.0[0..8].copy_from_slice(&payment_ctr.to_ne_bytes()); - let succeeded = send_mpp_hop_payment( - source, - middle, - middle_chan_ids, - dest, - dest_chan_ids, - amt, - secret, - hash, - id, +fn process_all_events_impl( + nodes: &[HarnessNode<'_>; 3], out: &Out, ab_link: &PeerLink, bc_link: &PeerLink, + chain_state: &mut ChainState, payments: &mut PaymentTracker, queues: &mut EventQueues, +) { + let mut last_pass_no_updates = false; + for i in 0..std::usize::MAX { + if i == 100 { + panic!( + "It may take may iterations to settle the state, but it should not take forever" ); - if succeeded { - pending_payments.borrow_mut()[source_idx].push(id); - } - }; + } + ab_link.complete_all_monitor_updates(nodes); + bc_link.complete_all_monitor_updates(nodes); + if process_msg_events_impl(0, false, ProcessMessages::AllMessages, nodes, out, queues) { + last_pass_no_updates = false; + continue; + } + if process_msg_events_impl(1, false, ProcessMessages::AllMessages, nodes, out, queues) { + last_pass_no_updates = false; + continue; + } + if process_msg_events_impl(2, false, ProcessMessages::AllMessages, nodes, out, queues) { + last_pass_no_updates = false; + continue; + } + if process_events_impl(0, false, nodes, chain_state, payments) { + last_pass_no_updates = false; + continue; + } + if process_events_impl(1, false, nodes, chain_state, payments) { + last_pass_no_updates = false; + continue; + } + if process_events_impl(2, false, nodes, chain_state, payments) { + last_pass_no_updates = false; + continue; + } + if last_pass_no_updates { + break; + } + last_pass_no_updates = true; + } +} + +#[inline] +pub fn do_test(data: &[u8], out: Out) { + let router = FuzzRouter {}; + let mut harness = Harness::new(data, out, &router); - let v = get_slice!(1)[0]; - out.locked_write(format!("READ A BYTE! HANDLING INPUT {:x}...........\n", v).as_bytes()); + loop { + let v = if let Some(value) = harness.next_input_byte() { + value + } else { + harness.finish(); + return; + }; + harness + .out + .locked_write(format!("READ A BYTE! HANDLING INPUT {:x}...........\n", v).as_bytes()); match v { // In general, we keep related message groups close together in binary form, allowing // bit-twiddling mutations to have similar effects. This is probably overkill, but no // harm in doing so. - 0x00 => { - *mon_style[0].borrow_mut() = ChannelMonitorUpdateStatus::InProgress; - }, - 0x01 => { - *mon_style[1].borrow_mut() = ChannelMonitorUpdateStatus::InProgress; - }, - 0x02 => { - *mon_style[2].borrow_mut() = ChannelMonitorUpdateStatus::InProgress; - }, - 0x04 => { - *mon_style[0].borrow_mut() = ChannelMonitorUpdateStatus::Completed; - }, - 0x05 => { - *mon_style[1].borrow_mut() = ChannelMonitorUpdateStatus::Completed; - }, - 0x06 => { - *mon_style[2].borrow_mut() = ChannelMonitorUpdateStatus::Completed; - }, + 0x00 => harness.nodes[0].set_persistence_style(ChannelMonitorUpdateStatus::InProgress), + 0x01 => harness.nodes[1].set_persistence_style(ChannelMonitorUpdateStatus::InProgress), + 0x02 => harness.nodes[2].set_persistence_style(ChannelMonitorUpdateStatus::InProgress), + 0x04 => harness.nodes[0].set_persistence_style(ChannelMonitorUpdateStatus::Completed), + 0x05 => harness.nodes[1].set_persistence_style(ChannelMonitorUpdateStatus::Completed), + 0x06 => harness.nodes[2].set_persistence_style(ChannelMonitorUpdateStatus::Completed), 0x08 => { - for id in &chan_ab_ids { - complete_all_monitor_updates(&monitor_a, id); + for id in harness.ab_link.channel_ids() { + harness.nodes[0].complete_all_monitor_updates(id); } }, 0x09 => { - for id in &chan_ab_ids { - complete_all_monitor_updates(&monitor_b, id); + for id in harness.ab_link.channel_ids() { + harness.nodes[1].complete_all_monitor_updates(id); } }, 0x0a => { - for id in &chan_bc_ids { - complete_all_monitor_updates(&monitor_b, id); + for id in harness.bc_link.channel_ids() { + harness.nodes[1].complete_all_monitor_updates(id); } }, 0x0b => { - for id in &chan_bc_ids { - complete_all_monitor_updates(&monitor_c, id); + for id in harness.bc_link.channel_ids() { + harness.nodes[2].complete_all_monitor_updates(id); } }, 0x0c => { - if !peers_ab_disconnected { - nodes[0].peer_disconnected(nodes[1].get_our_node_id()); - nodes[1].peer_disconnected(nodes[0].get_our_node_id()); - peers_ab_disconnected = true; - drain_msg_events_on_disconnect!(0); - } + harness.disconnect_ab(); }, 0x0d => { - if !peers_bc_disconnected { - nodes[1].peer_disconnected(nodes[2].get_our_node_id()); - nodes[2].peer_disconnected(nodes[1].get_our_node_id()); - peers_bc_disconnected = true; - drain_msg_events_on_disconnect!(2); - } + harness.disconnect_bc(); }, 0x0e => { - if peers_ab_disconnected { - let init_1 = Init { - features: nodes[1].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[0].peer_connected(nodes[1].get_our_node_id(), &init_1, true).unwrap(); - let init_0 = Init { - features: nodes[0].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[1].peer_connected(nodes[0].get_our_node_id(), &init_0, false).unwrap(); - peers_ab_disconnected = false; - } + harness.reconnect_ab(); }, 0x0f => { - if peers_bc_disconnected { - let init_2 = Init { - features: nodes[2].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[1].peer_connected(nodes[2].get_our_node_id(), &init_2, true).unwrap(); - let init_1 = Init { - features: nodes[1].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[2].peer_connected(nodes[1].get_our_node_id(), &init_1, false).unwrap(); - peers_bc_disconnected = false; - } + harness.reconnect_bc(); }, - 0x10 => process_msg_noret!(0, true, ProcessMessages::AllMessages), - 0x11 => process_msg_noret!(0, false, ProcessMessages::AllMessages), - 0x12 => process_msg_noret!(0, true, ProcessMessages::OneMessage), - 0x13 => process_msg_noret!(0, false, ProcessMessages::OneMessage), - 0x14 => process_msg_noret!(0, true, ProcessMessages::OnePendingMessage), - 0x15 => process_msg_noret!(0, false, ProcessMessages::OnePendingMessage), + 0x10 => { + harness.process_msg_events(0, true, ProcessMessages::AllMessages); + }, + 0x11 => { + harness.process_msg_events(0, false, ProcessMessages::AllMessages); + }, + 0x12 => { + harness.process_msg_events(0, true, ProcessMessages::OneMessage); + }, + 0x13 => { + harness.process_msg_events(0, false, ProcessMessages::OneMessage); + }, + 0x14 => { + harness.process_msg_events(0, true, ProcessMessages::OnePendingMessage); + }, + 0x15 => { + harness.process_msg_events(0, false, ProcessMessages::OnePendingMessage); + }, - 0x16 => process_ev_noret!(0, true), - 0x17 => process_ev_noret!(0, false), + 0x16 => { + harness.process_events(0, true); + }, + 0x17 => { + harness.process_events(0, false); + }, - 0x18 => process_msg_noret!(1, true, ProcessMessages::AllMessages), - 0x19 => process_msg_noret!(1, false, ProcessMessages::AllMessages), - 0x1a => process_msg_noret!(1, true, ProcessMessages::OneMessage), - 0x1b => process_msg_noret!(1, false, ProcessMessages::OneMessage), - 0x1c => process_msg_noret!(1, true, ProcessMessages::OnePendingMessage), - 0x1d => process_msg_noret!(1, false, ProcessMessages::OnePendingMessage), + 0x18 => { + harness.process_msg_events(1, true, ProcessMessages::AllMessages); + }, + 0x19 => { + harness.process_msg_events(1, false, ProcessMessages::AllMessages); + }, + 0x1a => { + harness.process_msg_events(1, true, ProcessMessages::OneMessage); + }, + 0x1b => { + harness.process_msg_events(1, false, ProcessMessages::OneMessage); + }, + 0x1c => { + harness.process_msg_events(1, true, ProcessMessages::OnePendingMessage); + }, + 0x1d => { + harness.process_msg_events(1, false, ProcessMessages::OnePendingMessage); + }, - 0x1e => process_ev_noret!(1, true), - 0x1f => process_ev_noret!(1, false), + 0x1e => { + harness.process_events(1, true); + }, + 0x1f => { + harness.process_events(1, false); + }, - 0x20 => process_msg_noret!(2, true, ProcessMessages::AllMessages), - 0x21 => process_msg_noret!(2, false, ProcessMessages::AllMessages), - 0x22 => process_msg_noret!(2, true, ProcessMessages::OneMessage), - 0x23 => process_msg_noret!(2, false, ProcessMessages::OneMessage), - 0x24 => process_msg_noret!(2, true, ProcessMessages::OnePendingMessage), - 0x25 => process_msg_noret!(2, false, ProcessMessages::OnePendingMessage), + 0x20 => { + harness.process_msg_events(2, true, ProcessMessages::AllMessages); + }, + 0x21 => { + harness.process_msg_events(2, false, ProcessMessages::AllMessages); + }, + 0x22 => { + harness.process_msg_events(2, true, ProcessMessages::OneMessage); + }, + 0x23 => { + harness.process_msg_events(2, false, ProcessMessages::OneMessage); + }, + 0x24 => { + harness.process_msg_events(2, true, ProcessMessages::OnePendingMessage); + }, + 0x25 => { + harness.process_msg_events(2, false, ProcessMessages::OnePendingMessage); + }, - 0x26 => process_ev_noret!(2, true), - 0x27 => process_ev_noret!(2, false), + 0x26 => { + harness.process_events(2, true); + }, + 0x27 => { + harness.process_events(2, false); + }, // 1/10th the channel size: - 0x30 => send_noret(0, 1, chan_a_id, 10_000_000, &mut p_ctr), - 0x31 => send_noret(1, 0, chan_a_id, 10_000_000, &mut p_ctr), - 0x32 => send_noret(1, 2, chan_b_id, 10_000_000, &mut p_ctr), - 0x33 => send_noret(2, 1, chan_b_id, 10_000_000, &mut p_ctr), - 0x34 => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 10_000_000, &mut p_ctr), - 0x35 => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 10_000_000, &mut p_ctr), - - 0x38 => send_noret(0, 1, chan_a_id, 1_000_000, &mut p_ctr), - 0x39 => send_noret(1, 0, chan_a_id, 1_000_000, &mut p_ctr), - 0x3a => send_noret(1, 2, chan_b_id, 1_000_000, &mut p_ctr), - 0x3b => send_noret(2, 1, chan_b_id, 1_000_000, &mut p_ctr), - 0x3c => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 1_000_000, &mut p_ctr), - 0x3d => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 1_000_000, &mut p_ctr), - - 0x40 => send_noret(0, 1, chan_a_id, 100_000, &mut p_ctr), - 0x41 => send_noret(1, 0, chan_a_id, 100_000, &mut p_ctr), - 0x42 => send_noret(1, 2, chan_b_id, 100_000, &mut p_ctr), - 0x43 => send_noret(2, 1, chan_b_id, 100_000, &mut p_ctr), - 0x44 => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 100_000, &mut p_ctr), - 0x45 => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 100_000, &mut p_ctr), - - 0x48 => send_noret(0, 1, chan_a_id, 10_000, &mut p_ctr), - 0x49 => send_noret(1, 0, chan_a_id, 10_000, &mut p_ctr), - 0x4a => send_noret(1, 2, chan_b_id, 10_000, &mut p_ctr), - 0x4b => send_noret(2, 1, chan_b_id, 10_000, &mut p_ctr), - 0x4c => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 10_000, &mut p_ctr), - 0x4d => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 10_000, &mut p_ctr), - - 0x50 => send_noret(0, 1, chan_a_id, 1_000, &mut p_ctr), - 0x51 => send_noret(1, 0, chan_a_id, 1_000, &mut p_ctr), - 0x52 => send_noret(1, 2, chan_b_id, 1_000, &mut p_ctr), - 0x53 => send_noret(2, 1, chan_b_id, 1_000, &mut p_ctr), - 0x54 => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 1_000, &mut p_ctr), - 0x55 => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 1_000, &mut p_ctr), - - 0x58 => send_noret(0, 1, chan_a_id, 100, &mut p_ctr), - 0x59 => send_noret(1, 0, chan_a_id, 100, &mut p_ctr), - 0x5a => send_noret(1, 2, chan_b_id, 100, &mut p_ctr), - 0x5b => send_noret(2, 1, chan_b_id, 100, &mut p_ctr), - 0x5c => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 100, &mut p_ctr), - 0x5d => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 100, &mut p_ctr), - - 0x60 => send_noret(0, 1, chan_a_id, 10, &mut p_ctr), - 0x61 => send_noret(1, 0, chan_a_id, 10, &mut p_ctr), - 0x62 => send_noret(1, 2, chan_b_id, 10, &mut p_ctr), - 0x63 => send_noret(2, 1, chan_b_id, 10, &mut p_ctr), - 0x64 => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 10, &mut p_ctr), - 0x65 => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 10, &mut p_ctr), - - 0x68 => send_noret(0, 1, chan_a_id, 1, &mut p_ctr), - 0x69 => send_noret(1, 0, chan_a_id, 1, &mut p_ctr), - 0x6a => send_noret(1, 2, chan_b_id, 1, &mut p_ctr), - 0x6b => send_noret(2, 1, chan_b_id, 1, &mut p_ctr), - 0x6c => send_hop_noret(0, 1, chan_a_id, 2, chan_b_id, 1, &mut p_ctr), - 0x6d => send_hop_noret(2, 1, chan_b_id, 0, chan_a_id, 1, &mut p_ctr), + 0x30 => { + harness.send_direct(0, 1, harness.chan_a_id(), 10_000_000); + }, + 0x31 => { + harness.send_direct(1, 0, harness.chan_a_id(), 10_000_000); + }, + 0x32 => { + harness.send_direct(1, 2, harness.chan_b_id(), 10_000_000); + }, + 0x33 => { + harness.send_direct(2, 1, harness.chan_b_id(), 10_000_000); + }, + 0x34 => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 10_000_000); + }, + 0x35 => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 10_000_000); + }, - // MPP payments - // 0x70: direct MPP from 0 to 1 (multi A-B channels) - 0x70 => send_mpp_direct(0, 1, &chan_ab_ids, 1_000_000, &mut p_ctr), - // 0x71: MPP 0->1->2, multi channels on first hop (A-B) - 0x71 => send_mpp_hop(0, 1, &chan_ab_ids, 2, &[chan_b_id], 1_000_000, &mut p_ctr), - // 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C) - 0x72 => send_mpp_hop(0, 1, &chan_ab_ids, 2, &chan_bc_ids, 1_000_000, &mut p_ctr), - // 0x73: MPP 0->1->2, multi channels on second hop (B-C) - 0x73 => send_mpp_hop(0, 1, &[chan_a_id], 2, &chan_bc_ids, 1_000_000, &mut p_ctr), - // 0x74: direct MPP from 0 to 1, multi parts over single channel - 0x74 => { - send_mpp_direct(0, 1, &[chan_a_id, chan_a_id, chan_a_id], 1_000_000, &mut p_ctr) + 0x38 => { + harness.send_direct(0, 1, harness.chan_a_id(), 1_000_000); + }, + 0x39 => { + harness.send_direct(1, 0, harness.chan_a_id(), 1_000_000); + }, + 0x3a => { + harness.send_direct(1, 2, harness.chan_b_id(), 1_000_000); + }, + 0x3b => { + harness.send_direct(2, 1, harness.chan_b_id(), 1_000_000); + }, + 0x3c => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 1_000_000); + }, + 0x3d => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 1_000_000); }, - 0x80 => { - let mut max_feerate = last_htlc_clear_fee_a; - if matches!(chan_type, ChanType::Legacy) { - max_feerate *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32; - } - if fee_est_a.ret_val.fetch_add(250, atomic::Ordering::AcqRel) + 250 > max_feerate { - fee_est_a.ret_val.store(max_feerate, atomic::Ordering::Release); - } - nodes[0].timer_tick_occurred(); + 0x40 => { + harness.send_direct(0, 1, harness.chan_a_id(), 100_000); + }, + 0x41 => { + harness.send_direct(1, 0, harness.chan_a_id(), 100_000); + }, + 0x42 => { + harness.send_direct(1, 2, harness.chan_b_id(), 100_000); + }, + 0x43 => { + harness.send_direct(2, 1, harness.chan_b_id(), 100_000); + }, + 0x44 => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 100_000); }, - 0x81 => { - fee_est_a.ret_val.store(253, atomic::Ordering::Release); - nodes[0].timer_tick_occurred(); + 0x45 => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 100_000); }, - 0x84 => { - let mut max_feerate = last_htlc_clear_fee_b; - if matches!(chan_type, ChanType::Legacy) { - max_feerate *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32; - } - if fee_est_b.ret_val.fetch_add(250, atomic::Ordering::AcqRel) + 250 > max_feerate { - fee_est_b.ret_val.store(max_feerate, atomic::Ordering::Release); - } - nodes[1].timer_tick_occurred(); + 0x48 => { + harness.send_direct(0, 1, harness.chan_a_id(), 10_000); + }, + 0x49 => { + harness.send_direct(1, 0, harness.chan_a_id(), 10_000); + }, + 0x4a => { + harness.send_direct(1, 2, harness.chan_b_id(), 10_000); }, - 0x85 => { - fee_est_b.ret_val.store(253, atomic::Ordering::Release); - nodes[1].timer_tick_occurred(); + 0x4b => { + harness.send_direct(2, 1, harness.chan_b_id(), 10_000); + }, + 0x4c => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 10_000); + }, + 0x4d => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 10_000); }, - 0x88 => { - let mut max_feerate = last_htlc_clear_fee_c; - if matches!(chan_type, ChanType::Legacy) { - max_feerate *= FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE as u32; - } - if fee_est_c.ret_val.fetch_add(250, atomic::Ordering::AcqRel) + 250 > max_feerate { - fee_est_c.ret_val.store(max_feerate, atomic::Ordering::Release); - } - nodes[2].timer_tick_occurred(); + 0x50 => { + harness.send_direct(0, 1, harness.chan_a_id(), 1_000); + }, + 0x51 => { + harness.send_direct(1, 0, harness.chan_a_id(), 1_000); + }, + 0x52 => { + harness.send_direct(1, 2, harness.chan_b_id(), 1_000); + }, + 0x53 => { + harness.send_direct(2, 1, harness.chan_b_id(), 1_000); + }, + 0x54 => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 1_000); + }, + 0x55 => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 1_000); + }, + + 0x58 => { + harness.send_direct(0, 1, harness.chan_a_id(), 100); + }, + 0x59 => { + harness.send_direct(1, 0, harness.chan_a_id(), 100); + }, + 0x5a => { + harness.send_direct(1, 2, harness.chan_b_id(), 100); + }, + 0x5b => { + harness.send_direct(2, 1, harness.chan_b_id(), 100); + }, + 0x5c => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 100); + }, + 0x5d => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 100); + }, + + 0x60 => { + harness.send_direct(0, 1, harness.chan_a_id(), 10); + }, + 0x61 => { + harness.send_direct(1, 0, harness.chan_a_id(), 10); + }, + 0x62 => { + harness.send_direct(1, 2, harness.chan_b_id(), 10); }, - 0x89 => { - fee_est_c.ret_val.store(253, atomic::Ordering::Release); - nodes[2].timer_tick_occurred(); + 0x63 => { + harness.send_direct(2, 1, harness.chan_b_id(), 10); + }, + 0x64 => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 10); + }, + 0x65 => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 10); + }, + + 0x68 => { + harness.send_direct(0, 1, harness.chan_a_id(), 1); + }, + 0x69 => { + harness.send_direct(1, 0, harness.chan_a_id(), 1); + }, + 0x6a => { + harness.send_direct(1, 2, harness.chan_b_id(), 1); + }, + 0x6b => { + harness.send_direct(2, 1, harness.chan_b_id(), 1); + }, + 0x6c => { + harness.send_hop(0, 1, harness.chan_a_id(), 2, harness.chan_b_id(), 1); + }, + 0x6d => { + harness.send_hop(2, 1, harness.chan_b_id(), 0, harness.chan_a_id(), 1); + }, + + // MPP payments + // 0x70: direct MPP from 0 to 1 (multi A-B channels) + 0x70 => { + let chan_ab_ids = harness.ab_link.channel_ids().clone(); + harness.send_mpp_direct(0, 1, &chan_ab_ids, 1_000_000); + }, + // 0x71: MPP 0->1->2, multi channels on first hop (A-B) + 0x71 => { + let chan_ab_ids = harness.ab_link.channel_ids().clone(); + let chan_b_id = harness.chan_b_id(); + harness.send_mpp_hop(0, 1, &chan_ab_ids, 2, &[chan_b_id], 1_000_000); + }, + // 0x72: MPP 0->1->2, multi channels on both hops (A-B and B-C) + 0x72 => { + let chan_ab_ids = harness.ab_link.channel_ids().clone(); + let chan_bc_ids = harness.bc_link.channel_ids().clone(); + harness.send_mpp_hop(0, 1, &chan_ab_ids, 2, &chan_bc_ids, 1_000_000); + }, + // 0x73: MPP 0->1->2, multi channels on second hop (B-C) + 0x73 => { + let chan_a_id = harness.chan_a_id(); + let chan_bc_ids = harness.bc_link.channel_ids().clone(); + harness.send_mpp_hop(0, 1, &[chan_a_id], 2, &chan_bc_ids, 1_000_000); + }, + // 0x74: direct MPP from 0 to 1, multi parts over single channel + 0x74 => { + let chan_a_id = harness.chan_a_id(); + harness.send_mpp_direct(0, 1, &[chan_a_id, chan_a_id, chan_a_id], 1_000_000); }, + 0x80 => harness.nodes[0].bump_fee_estimate(harness.chan_type), + 0x81 => harness.nodes[0].reset_fee_estimate(), + 0x84 => harness.nodes[1].bump_fee_estimate(harness.chan_type), + 0x85 => harness.nodes[1].reset_fee_estimate(), + 0x88 => harness.nodes[2].bump_fee_estimate(harness.chan_type), + 0x89 => harness.nodes[2].reset_fee_estimate(), + 0xa0 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[1].get_our_node_id(); - let wallet = WalletSync::new(&wallets[0], Arc::clone(&loggers[0])); - let feerate_sat_per_kw = fee_estimators[0].feerate_sat_per_kw(); - splice_in(&nodes[0], &cp_node_id, &chan_a_id, &wallet, feerate_sat_per_kw); + let cp_node_id = harness.nodes[1].our_node_id(); + harness.nodes[0].splice_in(&cp_node_id, &harness.chan_a_id()); }, 0xa1 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[0].get_our_node_id(); - let wallet = WalletSync::new(&wallets[1], Arc::clone(&loggers[1])); - let feerate_sat_per_kw = fee_estimators[1].feerate_sat_per_kw(); - splice_in(&nodes[1], &cp_node_id, &chan_a_id, &wallet, feerate_sat_per_kw); + let cp_node_id = harness.nodes[0].our_node_id(); + harness.nodes[1].splice_in(&cp_node_id, &harness.chan_a_id()); }, 0xa2 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[2].get_our_node_id(); - let wallet = WalletSync::new(&wallets[1], Arc::clone(&loggers[1])); - let feerate_sat_per_kw = fee_estimators[1].feerate_sat_per_kw(); - splice_in(&nodes[1], &cp_node_id, &chan_b_id, &wallet, feerate_sat_per_kw); + let cp_node_id = harness.nodes[2].our_node_id(); + harness.nodes[1].splice_in(&cp_node_id, &harness.chan_b_id()); }, 0xa3 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[1].get_our_node_id(); - let wallet = WalletSync::new(&wallets[2], Arc::clone(&loggers[2])); - let feerate_sat_per_kw = fee_estimators[2].feerate_sat_per_kw(); - splice_in(&nodes[2], &cp_node_id, &chan_b_id, &wallet, feerate_sat_per_kw); + let cp_node_id = harness.nodes[1].our_node_id(); + harness.nodes[2].splice_in(&cp_node_id, &harness.chan_b_id()); }, 0xa4 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[1].get_our_node_id(); - let wallet = &wallets[0]; - let logger = Arc::clone(&loggers[0]); - let feerate_sat_per_kw = fee_estimators[0].feerate_sat_per_kw(); - splice_out(&nodes[0], &cp_node_id, &chan_a_id, wallet, logger, feerate_sat_per_kw); + let cp_node_id = harness.nodes[1].our_node_id(); + harness.nodes[0].splice_out(&cp_node_id, &harness.chan_a_id()); }, 0xa5 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[0].get_our_node_id(); - let wallet = &wallets[1]; - let logger = Arc::clone(&loggers[1]); - let feerate_sat_per_kw = fee_estimators[1].feerate_sat_per_kw(); - splice_out(&nodes[1], &cp_node_id, &chan_a_id, wallet, logger, feerate_sat_per_kw); + let cp_node_id = harness.nodes[0].our_node_id(); + harness.nodes[1].splice_out(&cp_node_id, &harness.chan_a_id()); }, 0xa6 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[2].get_our_node_id(); - let wallet = &wallets[1]; - let logger = Arc::clone(&loggers[1]); - let feerate_sat_per_kw = fee_estimators[1].feerate_sat_per_kw(); - splice_out(&nodes[1], &cp_node_id, &chan_b_id, wallet, logger, feerate_sat_per_kw); + let cp_node_id = harness.nodes[2].our_node_id(); + harness.nodes[1].splice_out(&cp_node_id, &harness.chan_b_id()); }, 0xa7 => { if !cfg!(splicing) { - test_return!(); + assert_test_invariants(&harness.nodes); + return; } - let cp_node_id = nodes[1].get_our_node_id(); - let wallet = &wallets[2]; - let logger = Arc::clone(&loggers[2]); - let feerate_sat_per_kw = fee_estimators[2].feerate_sat_per_kw(); - splice_out(&nodes[2], &cp_node_id, &chan_b_id, wallet, logger, feerate_sat_per_kw); + let cp_node_id = harness.nodes[1].our_node_id(); + harness.nodes[2].splice_out(&cp_node_id, &harness.chan_b_id()); }, // Sync node by 1 block to cover confirmation of a transaction. - 0xa8 => sync_with_chain_state(&mut chain_state, &nodes[0], &mut node_height_a, Some(1)), - 0xa9 => sync_with_chain_state(&mut chain_state, &nodes[1], &mut node_height_b, Some(1)), - 0xaa => sync_with_chain_state(&mut chain_state, &nodes[2], &mut node_height_c, Some(1)), + 0xa8 => harness.nodes[0].sync_with_chain_state(&harness.chain_state, Some(1)), + 0xa9 => harness.nodes[1].sync_with_chain_state(&harness.chain_state, Some(1)), + 0xaa => harness.nodes[2].sync_with_chain_state(&harness.chain_state, Some(1)), // Sync node to chain tip to cover confirmation of a transaction post-reorg-risk. - 0xab => sync_with_chain_state(&mut chain_state, &nodes[0], &mut node_height_a, None), - 0xac => sync_with_chain_state(&mut chain_state, &nodes[1], &mut node_height_b, None), - 0xad => sync_with_chain_state(&mut chain_state, &nodes[2], &mut node_height_c, None), + 0xab => harness.nodes[0].sync_with_chain_state(&harness.chain_state, None), + 0xac => harness.nodes[1].sync_with_chain_state(&harness.chain_state, None), + 0xad => harness.nodes[2].sync_with_chain_state(&harness.chain_state, None), 0xb0 | 0xb1 | 0xb2 => { // Restart node A, picking among the in-flight `ChannelMonitor`s to use based on // the value of `v` we're matching. - if !peers_ab_disconnected { - nodes[1].peer_disconnected(nodes[0].get_our_node_id()); - peers_ab_disconnected = true; - push_excess_b_events!( - nodes[1].get_and_clear_pending_msg_events().drain(..), - Some(0) - ); - ab_events.clear(); - ba_events.clear(); - } - let (new_node_a, new_monitor_a) = reload_node( - &node_a_ser, - 0, - &monitor_a, - v, - &keys_manager_a, - &fee_est_a, - broadcast_a.clone(), - ); - nodes[0] = new_node_a; - monitor_a = new_monitor_a; + harness.restart_node(0, v, &router); }, 0xb3..=0xbb => { // Restart node B, picking among the in-flight `ChannelMonitor`s to use based on // the value of `v` we're matching. - if !peers_ab_disconnected { - nodes[0].peer_disconnected(nodes[1].get_our_node_id()); - peers_ab_disconnected = true; - nodes[0].get_and_clear_pending_msg_events(); - ab_events.clear(); - ba_events.clear(); - } - if !peers_bc_disconnected { - nodes[2].peer_disconnected(nodes[1].get_our_node_id()); - peers_bc_disconnected = true; - nodes[2].get_and_clear_pending_msg_events(); - bc_events.clear(); - cb_events.clear(); - } - let (new_node_b, new_monitor_b) = reload_node( - &node_b_ser, - 1, - &monitor_b, - v, - &keys_manager_b, - &fee_est_b, - broadcast_b.clone(), - ); - nodes[1] = new_node_b; - monitor_b = new_monitor_b; + harness.restart_node(1, v, &router); }, 0xbc | 0xbd | 0xbe => { // Restart node C, picking among the in-flight `ChannelMonitor`s to use based on // the value of `v` we're matching. - if !peers_bc_disconnected { - nodes[1].peer_disconnected(nodes[2].get_our_node_id()); - peers_bc_disconnected = true; - push_excess_b_events!( - nodes[1].get_and_clear_pending_msg_events().drain(..), - Some(2) - ); - bc_events.clear(); - cb_events.clear(); - } - let (new_node_c, new_monitor_c) = reload_node( - &node_c_ser, - 2, - &monitor_c, - v, - &keys_manager_c, - &fee_est_c, - broadcast_c.clone(), - ); - nodes[2] = new_node_c; - monitor_c = new_monitor_c; + harness.restart_node(2, v, &router); }, - 0xc0 => keys_manager_a.disable_supported_ops_for_all_signers(), - 0xc1 => keys_manager_b.disable_supported_ops_for_all_signers(), - 0xc2 => keys_manager_c.disable_supported_ops_for_all_signers(), + 0xc0 => harness.nodes[0].keys_manager.disable_supported_ops_for_all_signers(), + 0xc1 => harness.nodes[1].keys_manager.disable_supported_ops_for_all_signers(), + 0xc2 => harness.nodes[2].keys_manager.disable_supported_ops_for_all_signers(), 0xc3 => { - keys_manager_a.enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); - nodes[0].signer_unblocked(None); + harness.nodes[0] + .keys_manager + .enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); + harness.nodes[0].node.signer_unblocked(None); }, 0xc4 => { - keys_manager_b.enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); - let filter = Some((nodes[0].get_our_node_id(), chan_a_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); + let filter = Some((harness.nodes[0].our_node_id(), harness.chan_a_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xc5 => { - keys_manager_b.enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); - let filter = Some((nodes[2].get_our_node_id(), chan_b_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); + let filter = Some((harness.nodes[2].our_node_id(), harness.chan_b_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xc6 => { - keys_manager_c.enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); - nodes[2].signer_unblocked(None); + harness.nodes[2] + .keys_manager + .enable_op_for_all_signers(SignerOp::SignCounterpartyCommitment); + harness.nodes[2].node.signer_unblocked(None); }, 0xc7 => { - keys_manager_a.enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); - nodes[0].signer_unblocked(None); + harness.nodes[0] + .keys_manager + .enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); + harness.nodes[0].node.signer_unblocked(None); }, 0xc8 => { - keys_manager_b.enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); - let filter = Some((nodes[0].get_our_node_id(), chan_a_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); + let filter = Some((harness.nodes[0].our_node_id(), harness.chan_a_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xc9 => { - keys_manager_b.enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); - let filter = Some((nodes[2].get_our_node_id(), chan_b_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); + let filter = Some((harness.nodes[2].our_node_id(), harness.chan_b_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xca => { - keys_manager_c.enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); - nodes[2].signer_unblocked(None); + harness.nodes[2] + .keys_manager + .enable_op_for_all_signers(SignerOp::GetPerCommitmentPoint); + harness.nodes[2].node.signer_unblocked(None); }, 0xcb => { - keys_manager_a.enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); - nodes[0].signer_unblocked(None); + harness.nodes[0] + .keys_manager + .enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); + harness.nodes[0].node.signer_unblocked(None); }, 0xcc => { - keys_manager_b.enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); - let filter = Some((nodes[0].get_our_node_id(), chan_a_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); + let filter = Some((harness.nodes[0].our_node_id(), harness.chan_a_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xcd => { - keys_manager_b.enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); - let filter = Some((nodes[2].get_our_node_id(), chan_b_id)); - nodes[1].signer_unblocked(filter); + harness.nodes[1] + .keys_manager + .enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); + let filter = Some((harness.nodes[2].our_node_id(), harness.chan_b_id())); + harness.nodes[1].node.signer_unblocked(filter); }, 0xce => { - keys_manager_c.enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); - nodes[2].signer_unblocked(None); + harness.nodes[2] + .keys_manager + .enable_op_for_all_signers(SignerOp::ReleaseCommitmentSecret); + harness.nodes[2].node.signer_unblocked(None); }, 0xf0 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_a, id, &complete_first); - } + harness.ab_link.complete_monitor_updates_for_node( + 0, + &harness.nodes, + MonitorUpdateSelector::First, + ); }, 0xf1 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_a, id, &complete_second); - } + harness.ab_link.complete_monitor_updates_for_node( + 0, + &harness.nodes, + MonitorUpdateSelector::Second, + ); }, 0xf2 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_a, id, &Vec::pop); - } + harness.ab_link.complete_monitor_updates_for_node( + 0, + &harness.nodes, + MonitorUpdateSelector::Last, + ); }, 0xf4 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_b, id, &complete_first); - } + harness.ab_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::First, + ); }, 0xf5 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_b, id, &complete_second); - } + harness.ab_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::Second, + ); }, 0xf6 => { - for id in &chan_ab_ids { - complete_monitor_update(&monitor_b, id, &Vec::pop); - } + harness.ab_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::Last, + ); }, 0xf8 => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_b, id, &complete_first); - } + harness.bc_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::First, + ); }, 0xf9 => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_b, id, &complete_second); - } + harness.bc_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::Second, + ); }, 0xfa => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_b, id, &Vec::pop); - } + harness.bc_link.complete_monitor_updates_for_node( + 1, + &harness.nodes, + MonitorUpdateSelector::Last, + ); }, 0xfc => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_c, id, &complete_first); - } + harness.bc_link.complete_monitor_updates_for_node( + 2, + &harness.nodes, + MonitorUpdateSelector::First, + ); }, 0xfd => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_c, id, &complete_second); - } + harness.bc_link.complete_monitor_updates_for_node( + 2, + &harness.nodes, + MonitorUpdateSelector::Second, + ); }, 0xfe => { - for id in &chan_bc_ids { - complete_monitor_update(&monitor_c, id, &Vec::pop); - } + harness.bc_link.complete_monitor_updates_for_node( + 2, + &harness.nodes, + MonitorUpdateSelector::Last, + ); }, 0xff => { // Test that no channel is in a stuck state where neither party can send funds even // after we resolve all pending events. - - // First, make sure peers are all connected to each other - if peers_ab_disconnected { - let init_1 = Init { - features: nodes[1].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[0].peer_connected(nodes[1].get_our_node_id(), &init_1, true).unwrap(); - let init_0 = Init { - features: nodes[0].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[1].peer_connected(nodes[0].get_our_node_id(), &init_0, false).unwrap(); - peers_ab_disconnected = false; - } - if peers_bc_disconnected { - let init_2 = Init { - features: nodes[2].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[1].peer_connected(nodes[2].get_our_node_id(), &init_2, true).unwrap(); - let init_1 = Init { - features: nodes[1].init_features(), - networks: None, - remote_network_address: None, - }; - nodes[2].peer_connected(nodes[1].get_our_node_id(), &init_1, false).unwrap(); - peers_bc_disconnected = false; - } - - for op in SUPPORTED_SIGNER_OPS { - keys_manager_a.enable_op_for_all_signers(op); - keys_manager_b.enable_op_for_all_signers(op); - keys_manager_c.enable_op_for_all_signers(op); - } - nodes[0].signer_unblocked(None); - nodes[1].signer_unblocked(None); - nodes[2].signer_unblocked(None); - - macro_rules! process_all_events { - () => { { - let mut last_pass_no_updates = false; - for i in 0..std::usize::MAX { - if i == 100 { - panic!("It may take may iterations to settle the state, but it should not take forever"); - } - // Next, make sure no monitor updates are pending - for id in &chan_ab_ids { - complete_all_monitor_updates(&monitor_a, id); - complete_all_monitor_updates(&monitor_b, id); - } - for id in &chan_bc_ids { - complete_all_monitor_updates(&monitor_b, id); - complete_all_monitor_updates(&monitor_c, id); - } - // Then, make sure any current forwards make their way to their destination - if process_msg_events!(0, false, ProcessMessages::AllMessages) { - last_pass_no_updates = false; - continue; - } - if process_msg_events!(1, false, ProcessMessages::AllMessages) { - last_pass_no_updates = false; - continue; - } - if process_msg_events!(2, false, ProcessMessages::AllMessages) { - last_pass_no_updates = false; - continue; - } - // ...making sure any payments are claimed. - if process_events!(0, false) { - last_pass_no_updates = false; - continue; - } - if process_events!(1, false) { - last_pass_no_updates = false; - continue; - } - if process_events!(2, false) { - last_pass_no_updates = false; - continue; - } - if last_pass_no_updates { - // In some cases, we may generate a message to send in - // `process_msg_events`, but block sending until - // `complete_all_monitor_updates` gets called on the next - // iteration. - // - // Thus, we only exit if we manage two iterations with no messages - // or events to process. - break; - } - last_pass_no_updates = true; - } - } }; - } - - process_all_events!(); - - // Since MPP payments are supported, we wait until we fully settle the state of all - // channels to see if we have any committed HTLC parts of an MPP payment that need - // to be failed back. - for node in &nodes { - node.timer_tick_occurred(); - } - process_all_events!(); - - // Verify no payments are stuck - all should have resolved - for (idx, pending) in pending_payments.borrow().iter().enumerate() { - assert!( - pending.is_empty(), - "Node {} has {} stuck pending payments after settling all state", - idx, - pending.len() - ); - } - - // Verify that every payment claimed by a receiver resulted in a - // PaymentSent event at the sender. - let resolved = resolved_payments.borrow(); - for hash in claimed_payment_hashes.borrow().iter() { - let found = resolved.iter().any(|node_resolved| { - node_resolved.values().any(|h| h.as_ref() == Some(hash)) - }); - assert!( - found, - "Payment {:?} was claimed by receiver but sender never got PaymentSent", - hash - ); - } - - // Finally, make sure that at least one end of each channel can make a substantial payment - for &chan_id in &chan_ab_ids { - assert!( - send(0, 1, chan_id, 10_000_000, &mut p_ctr) - || send(1, 0, chan_id, 10_000_000, &mut p_ctr) - ); - } - for &chan_id in &chan_bc_ids { - assert!( - send(1, 2, chan_id, 10_000_000, &mut p_ctr) - || send(2, 1, chan_id, 10_000_000, &mut p_ctr) - ); - } - - last_htlc_clear_fee_a = fee_est_a.ret_val.load(atomic::Ordering::Acquire); - last_htlc_clear_fee_b = fee_est_b.ret_val.load(atomic::Ordering::Acquire); - last_htlc_clear_fee_c = fee_est_c.ret_val.load(atomic::Ordering::Acquire); + harness.settle_all(); + }, + _ => { + assert_test_invariants(&harness.nodes); + return; }, - _ => test_return!(), } - if nodes[0].get_and_clear_needs_persistence() == true { - node_a_ser = nodes[0].encode(); - } - if nodes[1].get_and_clear_needs_persistence() == true { - node_b_ser = nodes[1].encode(); - } - if nodes[2].get_and_clear_needs_persistence() == true { - node_c_ser = nodes[2].encode(); - } + harness.refresh_serialized_managers(); } }