X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Fchanmon_consistency.rs;h=8472f8fa6278a4e158e810a600895545cbbd27ae;hb=28d33ff9e03b7e3a0cd7ba3bc59f1303b3903f88;hp=21a8b37f1cd8314ff5af8a797daca22434bd105e;hpb=f8caa325e51d8afb0cb65effd9cdb351ffda3fc7;p=rust-lightning diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 21a8b37f..8472f8fa 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -30,18 +30,18 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{BlockHash, WPubkeyHash}; use lightning::chain; -use lightning::chain::{BestBlock, chainmonitor, channelmonitor, Confirm, Watch}; -use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, MonitorEvent}; +use lightning::chain::{BestBlock, ChannelMonitorUpdateErr, chainmonitor, channelmonitor, Confirm, Watch}; +use lightning::chain::channelmonitor::{ChannelMonitor, MonitorEvent}; use lightning::chain::transaction::OutPoint; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; -use lightning::chain::keysinterface::{KeysInterface, InMemorySigner}; +use lightning::chain::keysinterface::{KeyMaterial, KeysInterface, InMemorySigner, Recipient}; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentSendFailure, ChannelManagerReadArgs}; use lightning::ln::channel::FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE; use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, DecodeError, UpdateAddHTLC, Init}; use lightning::ln::script::ShutdownScript; -use lightning::util::enforcing_trait_impls::{EnforcingSigner, INITIAL_REVOKED_COMMITMENT_NUMBER}; +use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use lightning::util::errors::APIError; use lightning::util::events; use lightning::util::logger::Logger; @@ -50,12 +50,11 @@ use lightning::util::events::MessageSendEventsProvider; use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; use lightning::routing::router::{Route, RouteHop}; - -use utils::test_logger; +use utils::test_logger::{self, Output}; use utils::test_persister::TestPersister; -use bitcoin::secp256k1::key::{PublicKey,SecretKey}; -use bitcoin::secp256k1::recovery::RecoverableSignature; +use bitcoin::secp256k1::{PublicKey,SecretKey}; +use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::secp256k1::Secp256k1; use std::mem; @@ -64,6 +63,7 @@ use std::collections::{HashSet, hash_map, HashMap}; use std::sync::{Arc,Mutex}; use std::sync::atomic; use std::io::Cursor; +use bitcoin::bech32::u5; const MAX_FEE: u32 = 10_000; struct FuzzEstimator { @@ -94,16 +94,13 @@ impl Writer for VecWriter { self.0.extend_from_slice(buf); Ok(()) } - fn size_hint(&mut self, size: usize) { - self.0.reserve_exact(size); - } } struct TestChainMonitor { pub logger: Arc, pub keys: Arc, + pub persister: Arc, pub chain_monitor: Arc, Arc, Arc, Arc, Arc>>, - pub update_ret: Mutex>, // If we reload a node with an old copy of ChannelMonitors, the ChannelManager deserialization // logic will automatically force-close our channels for us (as we don't have an up-to-date // monitor implying we are not able to punish misbehaving counterparties). Because this test @@ -115,28 +112,27 @@ struct TestChainMonitor { impl TestChainMonitor { pub fn new(broadcaster: Arc, logger: Arc, feeest: Arc, persister: Arc, keys: Arc) -> Self { Self { - chain_monitor: Arc::new(chainmonitor::ChainMonitor::new(None, broadcaster, logger.clone(), feeest, persister)), + chain_monitor: Arc::new(chainmonitor::ChainMonitor::new(None, broadcaster, logger.clone(), feeest, Arc::clone(&persister))), logger, keys, - update_ret: Mutex::new(Ok(())), + persister, latest_monitors: Mutex::new(HashMap::new()), should_update_manager: atomic::AtomicBool::new(false), } } } impl chain::Watch for TestChainMonitor { - fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { + fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor) -> Result<(), chain::ChannelMonitorUpdateErr> { let mut ser = VecWriter(Vec::new()); monitor.write(&mut ser).unwrap(); if let Some(_) = self.latest_monitors.lock().unwrap().insert(funding_txo, (monitor.get_latest_update_id(), ser.0)) { panic!("Already had monitor pre-watch_channel"); } self.should_update_manager.store(true, atomic::Ordering::Relaxed); - assert!(self.chain_monitor.watch_channel(funding_txo, monitor).is_ok()); - self.update_ret.lock().unwrap().clone() + self.chain_monitor.watch_channel(funding_txo, monitor) } - fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { + fn update_channel(&self, funding_txo: OutPoint, update: channelmonitor::ChannelMonitorUpdate) -> Result<(), chain::ChannelMonitorUpdateErr> { let mut map_lock = self.latest_monitors.lock().unwrap(); let mut map_entry = match map_lock.entry(funding_txo) { hash_map::Entry::Occupied(entry) => entry, @@ -149,8 +145,7 @@ impl chain::Watch for TestChainMonitor { deserialized_monitor.write(&mut ser).unwrap(); map_entry.insert((update.update_id, ser.0)); self.should_update_manager.store(true, atomic::Ordering::Relaxed); - assert!(self.chain_monitor.update_channel(funding_txo, update).is_ok()); - self.update_ret.lock().unwrap().clone() + self.chain_monitor.update_channel(funding_txo, update) } fn release_pending_monitor_events(&self) -> Vec { @@ -161,13 +156,17 @@ impl chain::Watch for TestChainMonitor { struct KeyProvider { node_id: u8, rand_bytes_id: atomic::AtomicU32, - revoked_commitments: Mutex>>>, + enforcement_states: Mutex>>>, } impl KeysInterface for KeyProvider { type Signer = EnforcingSigner; - fn get_node_secret(&self) -> SecretKey { - 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, self.node_id]).unwrap() + fn get_node_secret(&self, _recipient: Recipient) -> Result { + Ok(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, self.node_id]).unwrap()) + } + + fn get_inbound_payment_key_material(&self) -> KeyMaterial { + KeyMaterial([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, self.node_id]) } fn get_destination_script(&self) -> Script { @@ -189,6 +188,7 @@ impl KeysInterface for KeyProvider { let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed); let keys = InMemorySigner::new( &secp_ctx, + self.get_node_secret(Recipient::Node).unwrap(), 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, 4, self.node_id]).unwrap(), 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, 5, self.node_id]).unwrap(), 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, 6, self.node_id]).unwrap(), @@ -198,7 +198,7 @@ impl KeysInterface for KeyProvider { channel_value_satoshis, [0; 32], ); - let revoked_commitment = self.make_revoked_commitment_cell(keys.commitment_seed); + let revoked_commitment = self.make_enforcement_state_cell(keys.commitment_seed); EnforcingSigner::new_with_revoked(keys, revoked_commitment, false) } @@ -212,29 +212,26 @@ impl KeysInterface for KeyProvider { fn read_chan_signer(&self, buffer: &[u8]) -> Result { let mut reader = std::io::Cursor::new(buffer); - let inner: InMemorySigner = Readable::read(&mut reader)?; - let revoked_commitment = self.make_revoked_commitment_cell(inner.commitment_seed); - - let last_commitment_number = Readable::read(&mut reader)?; + let inner: InMemorySigner = ReadableArgs::read(&mut reader, self.get_node_secret(Recipient::Node).unwrap())?; + let state = self.make_enforcement_state_cell(inner.commitment_seed); Ok(EnforcingSigner { inner, - last_commitment_number: Arc::new(Mutex::new(last_commitment_number)), - revoked_commitment, + state, disable_revocation_policy_check: false, }) } - fn sign_invoice(&self, _invoice_preimage: Vec) -> Result { + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { unreachable!() } } impl KeyProvider { - fn make_revoked_commitment_cell(&self, commitment_seed: [u8; 32]) -> Arc> { - let mut revoked_commitments = self.revoked_commitments.lock().unwrap(); + fn make_enforcement_state_cell(&self, commitment_seed: [u8; 32]) -> Arc> { + let mut revoked_commitments = self.enforcement_states.lock().unwrap(); if !revoked_commitments.contains_key(&commitment_seed) { - revoked_commitments.insert(commitment_seed, Arc::new(Mutex::new(INITIAL_REVOKED_COMMITMENT_NUMBER))); + revoked_commitments.insert(commitment_seed, Arc::new(Mutex::new(EnforcementState::new()))); } let cell = revoked_commitments.get(&commitment_seed).unwrap(); Arc::clone(cell) @@ -279,8 +276,8 @@ fn check_payment_err(send_err: PaymentSendFailure) { PaymentSendFailure::AllFailedRetrySafe(per_path_results) => { for api_err in per_path_results { check_api_err(api_err); } }, - PaymentSendFailure::PartialFailure(per_path_results) => { - for res in per_path_results { if let Err(api_err) = res { check_api_err(api_err); } } + PaymentSendFailure::PartialFailure { results, .. } => { + for res in results { if let Err(api_err) = res { check_api_err(api_err); } } }, } } @@ -292,7 +289,7 @@ fn get_payment_secret_hash(dest: &ChanMan, payment_id: &mut u8) -> Option<(Payme let mut payment_hash; for _ in 0..256 { payment_hash = PaymentHash(Sha256::hash(&[*payment_id; 1]).into_inner()); - if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600, 0) { + if let Ok(payment_secret) = dest.create_inbound_payment_for_hash(payment_hash, None, 3600) { return Some((payment_secret, payment_hash)); } *payment_id = payment_id.wrapping_add(1); @@ -313,6 +310,7 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p fee_msat: amt, cltv_expiry_delta: 200, }]], + payment_params: None, }, payment_hash, &Some(payment_secret)) { check_payment_err(err); false @@ -338,6 +336,7 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des fee_msat: amt, cltv_expiry_delta: 200, }]], + payment_params: None, }, payment_hash, &Some(payment_secret)) { check_payment_err(err); false @@ -345,14 +344,16 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des } #[inline] -pub fn do_test(data: &[u8], out: Out) { +pub fn do_test(data: &[u8], underlying_out: Out) { + let out = SearchingOutput::new(underlying_out); let broadcast = Arc::new(TestBroadcaster{}); macro_rules! make_node { ($node_id: expr, $fee_estimator: expr) => { { let logger: Arc = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone())); - let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), revoked_commitments: Mutex::new(HashMap::new()) }); - let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(), Arc::new(TestPersister{}), Arc::clone(&keys_manager))); + let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU32::new(0), enforcement_states: Mutex::new(HashMap::new()) }); + let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(), + Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(&keys_manager))); let mut config = UserConfig::default(); config.channel_options.forwarding_fee_proportional_millionths = 0; @@ -371,7 +372,8 @@ pub fn do_test(data: &[u8], out: Out) { ($ser: expr, $node_id: expr, $old_monitors: expr, $keys_manager: expr, $fee_estimator: expr) => { { let keys_manager = Arc::clone(& $keys_manager); let logger: Arc = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone())); - let chain_monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(), Arc::new(TestPersister{}), Arc::clone(& $keys_manager))); + let chain_monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), $fee_estimator.clone(), + Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(& $keys_manager))); let mut config = UserConfig::default(); config.channel_options.forwarding_fee_proportional_millionths = 0; @@ -409,8 +411,8 @@ pub fn do_test(data: &[u8], out: Out) { let mut channel_txn = Vec::new(); macro_rules! make_channel { ($source: expr, $dest: expr, $chan_id: expr) => { { - $source.peer_connected(&$dest.get_our_node_id(), &Init { features: InitFeatures::known() }); - $dest.peer_connected(&$source.get_our_node_id(), &Init { features: InitFeatures::known() }); + $source.peer_connected(&$dest.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + $dest.peer_connected(&$source.get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); $source.create_channel($dest.get_our_node_id(), 100_000, 42, 0, None).unwrap(); let open_channel = { @@ -597,7 +599,6 @@ pub fn do_test(data: &[u8], out: Out) { }, events::MessageSendEvent::SendFundingLocked { .. } => continue, events::MessageSendEvent::SendAnnouncementSignatures { .. } => continue, - events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => continue, events::MessageSendEvent::SendChannelUpdate { ref node_id, ref msg } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } @@ -655,9 +656,10 @@ pub fn do_test(data: &[u8], out: Out) { had_events = true; match event { events::MessageSendEvent::UpdateHTLCs { node_id, updates: CommitmentUpdate { update_add_htlcs, update_fail_htlcs, update_fulfill_htlcs, update_fail_malformed_htlcs, update_fee, commitment_signed } } => { - for dest in nodes.iter() { + 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 to node {}.\n", idx).as_bytes()); if !$corrupt_forward { dest.handle_update_add_htlc(&nodes[$node].get_our_node_id(), update_add); } else { @@ -672,15 +674,19 @@ pub fn do_test(data: &[u8], out: Out) { } } for update_fulfill in update_fulfill_htlcs.iter() { + out.locked_write(format!("Delivering update_fulfill_htlc to node {}.\n", 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 to node {}.\n", 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 to node {}.\n", 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 to node {}.\n", idx).as_bytes()); dest.handle_update_fee(&nodes[$node].get_our_node_id(), &msg); } let processed_change = !update_add_htlcs.is_empty() || !update_fulfill_htlcs.is_empty() || @@ -697,21 +703,24 @@ pub fn do_test(data: &[u8], out: Out) { } }); break; } + out.locked_write(format!("Delivering commitment_signed to node {}.\n", idx).as_bytes()); dest.handle_commitment_signed(&nodes[$node].get_our_node_id(), &commitment_signed); break; } } }, events::MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { - for dest in nodes.iter() { + for (idx, dest) in nodes.iter().enumerate() { if dest.get_our_node_id() == *node_id { + out.locked_write(format!("Delivering revoke_and_ack to node {}.\n", idx).as_bytes()); dest.handle_revoke_and_ack(&nodes[$node].get_our_node_id(), msg); } } }, events::MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => { - for dest in nodes.iter() { + for (idx, dest) in nodes.iter().enumerate() { if dest.get_our_node_id() == *node_id { + out.locked_write(format!("Delivering channel_reestablish to node {}.\n", idx).as_bytes()); dest.handle_channel_reestablish(&nodes[$node].get_our_node_id(), msg); } } @@ -722,10 +731,6 @@ pub fn do_test(data: &[u8], out: Out) { events::MessageSendEvent::SendAnnouncementSignatures { .. } => { // Can be generated as a reestablish response }, - events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => { - // Can be generated due to a payment forward being rejected due to a - // channel having previously failed a monitor update - }, events::MessageSendEvent::SendChannelUpdate { ref msg, .. } => { // When we reconnect we will resend a channel_update to make sure our // counterparty has the latest parameters for receiving payments @@ -735,7 +740,11 @@ pub fn do_test(data: &[u8], out: Out) { // force-close which we should detect as an error). assert_eq!(msg.contents.flags & 2, 0); }, - _ => panic!("Unhandled message event {:?}", event), + _ => if out.may_fail.load(atomic::Ordering::Acquire) { + return; + } else { + panic!("Unhandled message event {:?}", event) + }, } if $limit_events != ProcessMessages::AllMessages { break; @@ -764,11 +773,14 @@ pub fn do_test(data: &[u8], out: Out) { events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendFundingLocked { .. } => {}, events::MessageSendEvent::SendAnnouncementSignatures { .. } => {}, - events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => {}, events::MessageSendEvent::SendChannelUpdate { ref msg, .. } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! }, - _ => panic!("Unhandled message event"), + _ => if out.may_fail.load(atomic::Ordering::Acquire) { + return; + } else { + panic!("Unhandled message event") + }, } } push_excess_b_events!(nodes[1].get_and_clear_pending_msg_events().drain(..), Some(0)); @@ -782,11 +794,14 @@ pub fn do_test(data: &[u8], out: Out) { events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendFundingLocked { .. } => {}, events::MessageSendEvent::SendAnnouncementSignatures { .. } => {}, - events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => {}, events::MessageSendEvent::SendChannelUpdate { ref msg, .. } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! }, - _ => panic!("Unhandled message event"), + _ => if out.may_fail.load(atomic::Ordering::Acquire) { + return; + } else { + panic!("Unhandled message event") + }, } } push_excess_b_events!(nodes[1].get_and_clear_pending_msg_events().drain(..), Some(2)); @@ -832,48 +847,59 @@ pub fn do_test(data: &[u8], out: Out) { } }, events::Event::PaymentSent { .. } => {}, - events::Event::PaymentFailed { .. } => {}, + events::Event::PaymentPathSuccessful { .. } => {}, + events::Event::PaymentPathFailed { .. } => {}, events::Event::PaymentForwarded { .. } if $node == 1 => {}, events::Event::PendingHTLCsForwardable { .. } => { nodes[$node].process_pending_htlc_forwards(); }, - _ => panic!("Unhandled event"), + _ => if out.may_fail.load(atomic::Ordering::Acquire) { + return; + } else { + panic!("Unhandled event") + }, } } had_events } } } - match get_slice!(1)[0] { + let v = get_slice!(1)[0]; + 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 => *monitor_a.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), - 0x01 => *monitor_b.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), - 0x02 => *monitor_c.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), - 0x04 => *monitor_a.update_ret.lock().unwrap() = Ok(()), - 0x05 => *monitor_b.update_ret.lock().unwrap() = Ok(()), - 0x06 => *monitor_c.update_ret.lock().unwrap() = Ok(()), + 0x00 => *monitor_a.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), + 0x01 => *monitor_b.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), + 0x02 => *monitor_c.persister.update_ret.lock().unwrap() = Err(ChannelMonitorUpdateErr::TemporaryFailure), + 0x04 => *monitor_a.persister.update_ret.lock().unwrap() = Ok(()), + 0x05 => *monitor_b.persister.update_ret.lock().unwrap() = Ok(()), + 0x06 => *monitor_c.persister.update_ret.lock().unwrap() = Ok(()), 0x08 => { if let Some((id, _)) = monitor_a.latest_monitors.lock().unwrap().get(&chan_1_funding) { - nodes[0].channel_monitor_updated(&chan_1_funding, *id); + monitor_a.chain_monitor.force_channel_monitor_updated(chan_1_funding, *id); + nodes[0].process_monitor_events(); } }, 0x09 => { if let Some((id, _)) = monitor_b.latest_monitors.lock().unwrap().get(&chan_1_funding) { - nodes[1].channel_monitor_updated(&chan_1_funding, *id); + monitor_b.chain_monitor.force_channel_monitor_updated(chan_1_funding, *id); + nodes[1].process_monitor_events(); } }, 0x0a => { if let Some((id, _)) = monitor_b.latest_monitors.lock().unwrap().get(&chan_2_funding) { - nodes[1].channel_monitor_updated(&chan_2_funding, *id); + monitor_b.chain_monitor.force_channel_monitor_updated(chan_2_funding, *id); + nodes[1].process_monitor_events(); } }, 0x0b => { if let Some((id, _)) = monitor_c.latest_monitors.lock().unwrap().get(&chan_2_funding) { - nodes[2].channel_monitor_updated(&chan_2_funding, *id); + monitor_c.chain_monitor.force_channel_monitor_updated(chan_2_funding, *id); + nodes[2].process_monitor_events(); } }, @@ -895,15 +921,15 @@ pub fn do_test(data: &[u8], out: Out) { }, 0x0e => { if chan_a_disconnected { - nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); chan_a_disconnected = false; } }, 0x0f => { if chan_b_disconnected { - nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); chan_b_disconnected = false; } }, @@ -1074,33 +1100,37 @@ pub fn do_test(data: &[u8], out: Out) { // 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 there are no pending monitor updates, resetting the error state - // and calling channel_monitor_updated for each monitor. - *monitor_a.update_ret.lock().unwrap() = Ok(()); - *monitor_b.update_ret.lock().unwrap() = Ok(()); - *monitor_c.update_ret.lock().unwrap() = Ok(()); + // and calling force_channel_monitor_updated for each monitor. + *monitor_a.persister.update_ret.lock().unwrap() = Ok(()); + *monitor_b.persister.update_ret.lock().unwrap() = Ok(()); + *monitor_c.persister.update_ret.lock().unwrap() = Ok(()); if let Some((id, _)) = monitor_a.latest_monitors.lock().unwrap().get(&chan_1_funding) { - nodes[0].channel_monitor_updated(&chan_1_funding, *id); + monitor_a.chain_monitor.force_channel_monitor_updated(chan_1_funding, *id); + nodes[0].process_monitor_events(); } if let Some((id, _)) = monitor_b.latest_monitors.lock().unwrap().get(&chan_1_funding) { - nodes[1].channel_monitor_updated(&chan_1_funding, *id); + monitor_b.chain_monitor.force_channel_monitor_updated(chan_1_funding, *id); + nodes[1].process_monitor_events(); } if let Some((id, _)) = monitor_b.latest_monitors.lock().unwrap().get(&chan_2_funding) { - nodes[1].channel_monitor_updated(&chan_2_funding, *id); + monitor_b.chain_monitor.force_channel_monitor_updated(chan_2_funding, *id); + nodes[1].process_monitor_events(); } if let Some((id, _)) = monitor_c.latest_monitors.lock().unwrap().get(&chan_2_funding) { - nodes[2].channel_monitor_updated(&chan_2_funding, *id); + monitor_c.chain_monitor.force_channel_monitor_updated(chan_2_funding, *id); + nodes[2].process_monitor_events(); } // Next, make sure peers are all connected to each other if chan_a_disconnected { - nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); chan_a_disconnected = false; } if chan_b_disconnected { - nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known() }); - nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known() }); + nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); + nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::known(), remote_network_address: None }); chan_b_disconnected = false; } @@ -1118,7 +1148,7 @@ pub fn do_test(data: &[u8], out: Out) { break; } - // Finally, make sure that at least one end of each channel can make a substantial payment. + // Finally, make sure that at least one end of each channel can make a substantial payment assert!( send_payment(&nodes[0], &nodes[1], chan_a, 10_000_000, &mut payment_id) || send_payment(&nodes[1], &nodes[0], chan_a, 10_000_000, &mut payment_id)); @@ -1145,7 +1175,29 @@ pub fn do_test(data: &[u8], out: Out) { } } -pub fn chanmon_consistency_test(data: &[u8], out: Out) { +/// We actually have different behavior based on if a certain log string has been seen, so we have +/// to do a bit more tracking. +#[derive(Clone)] +struct SearchingOutput { + output: O, + may_fail: Arc, +} +impl Output for SearchingOutput { + fn locked_write(&self, data: &[u8]) { + // We hit a design limitation of LN state machine (see CONCURRENT_INBOUND_HTLC_FEE_BUFFER) + if std::str::from_utf8(data).unwrap().contains("Outbound update_fee HTLC buffer overflow - counterparty should force-close this channel") { + self.may_fail.store(true, atomic::Ordering::Release); + } + self.output.locked_write(data) + } +} +impl SearchingOutput { + pub fn new(output: O) -> Self { + Self { output, may_fail: Arc::new(atomic::AtomicBool::new(false)) } + } +} + +pub fn chanmon_consistency_test(data: &[u8], out: Out) { do_test(data, out); }