X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Fchanmon_consistency.rs;h=393f1b25d265cd165256f1bc61676a1692d10efa;hb=acf68eddefef0ffabdadc0d9d61655c6e63685e1;hp=f12c2aa374b423e774283b4876271b682fc34af2;hpb=1599a13643d893277eb3921c1bb15297547eb030;p=rust-lightning diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index f12c2aa3..393f1b25 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -29,15 +29,17 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{BlockHash, WPubkeyHash}; use lightning::chain; +use lightning::chain::chainmonitor; +use lightning::chain::channelmonitor; +use lightning::chain::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, MonitorEvent}; use lightning::chain::transaction::OutPoint; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::keysinterface::{KeysInterface, InMemoryChannelKeys}; -use lightning::ln::channelmonitor; -use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, MonitorEvent}; -use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, ChannelManagerReadArgs}; +use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret, PaymentSendFailure, ChannelManagerReadArgs}; use lightning::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, ErrorAction, UpdateAddHTLC, Init}; use lightning::util::enforcing_trait_impls::EnforcingChannelKeys; +use lightning::util::errors::APIError; use lightning::util::events; use lightning::util::logger::Logger; use lightning::util::config::UserConfig; @@ -47,6 +49,7 @@ use lightning::routing::router::{Route, RouteHop}; use utils::test_logger; +use utils::test_persister::TestPersister; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; use bitcoin::secp256k1::Secp256k1; @@ -83,7 +86,7 @@ impl Writer for VecWriter { struct TestChainMonitor { pub logger: Arc, - pub chain_monitor: Arc, Arc, 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 @@ -94,9 +97,9 @@ struct TestChainMonitor { pub should_update_manager: atomic::AtomicBool, } impl TestChainMonitor { - pub fn new(broadcaster: Arc, logger: Arc, feeest: Arc) -> Self { + pub fn new(broadcaster: Arc, logger: Arc, feeest: Arc, persister: Arc) -> Self { Self { - chain_monitor: Arc::new(channelmonitor::ChainMonitor::new(broadcaster, logger.clone(), feeest)), + chain_monitor: Arc::new(chainmonitor::ChainMonitor::new(None, broadcaster, logger.clone(), feeest, persister)), logger, update_ret: Mutex::new(Ok(())), latest_monitors: Mutex::new(HashMap::new()), @@ -109,7 +112,7 @@ impl chain::Watch for TestChainMonitor { fn watch_channel(&self, funding_txo: OutPoint, monitor: channelmonitor::ChannelMonitor) -> Result<(), channelmonitor::ChannelMonitorUpdateErr> { let mut ser = VecWriter(Vec::new()); - monitor.write_for_disk(&mut ser).unwrap(); + monitor.serialize_for_disk(&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"); } @@ -126,9 +129,9 @@ impl chain::Watch for TestChainMonitor { }; let mut deserialized_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>:: read(&mut Cursor::new(&map_entry.get().1)).unwrap().1; - deserialized_monitor.update_monitor(update.clone(), &&TestBroadcaster {}, &self.logger).unwrap(); + deserialized_monitor.update_monitor(&update, &&TestBroadcaster{}, &&FuzzEstimator{}, &self.logger).unwrap(); let mut ser = VecWriter(Vec::new()); - deserialized_monitor.write_for_disk(&mut ser).unwrap(); + deserialized_monitor.serialize_for_disk(&mut ser).unwrap(); map_entry.insert((update.update_id, ser.0)); self.should_update_manager.store(true, atomic::Ordering::Relaxed); self.update_ret.lock().unwrap().clone() @@ -183,6 +186,47 @@ impl KeysInterface for KeyProvider { } } +#[inline] +fn check_api_err(api_err: APIError) { + match api_err { + APIError::APIMisuseError { .. } => panic!("We can't misuse the API"), + APIError::FeeRateTooHigh { .. } => panic!("We can't send too much fee?"), + APIError::RouteError { .. } => panic!("Our routes should work"), + APIError::ChannelUnavailable { err } => { + // Test the error against a list of errors we can hit, and reject + // all others. If you hit this panic, the list of acceptable errors + // is probably just stale and you should add new messages here. + match err.as_str() { + "Peer for first hop currently disconnected/pending monitor update!" => {}, + _ if err.starts_with("Cannot push more than their max accepted HTLCs ") => {}, + _ if err.starts_with("Cannot send value that would put us over the max HTLC value in flight our peer will accept ") => {}, + _ if err.starts_with("Cannot send value that would put our balance under counterparty-announced channel reserve value") => {}, + _ if err.starts_with("Cannot send value that would overdraw remaining funds.") => {}, + _ if err.starts_with("Cannot send value that would not leave enough to pay for fees.") => {}, + _ => panic!(err), + } + }, + APIError::MonitorUpdateFailed => { + // We can (obviously) temp-fail a monitor update + }, + } +} +#[inline] +fn check_payment_err(send_err: PaymentSendFailure) { + match send_err { + PaymentSendFailure::ParameterError(api_err) => check_api_err(api_err), + PaymentSendFailure::PathParameterError(per_path_results) => { + for res in per_path_results { if let Err(api_err) = res { check_api_err(api_err); } } + }, + 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); } } + }, + } +} + #[inline] pub fn do_test(data: &[u8], out: Out) { let fee_est = Arc::new(FuzzEstimator{}); @@ -191,7 +235,7 @@ pub fn do_test(data: &[u8], out: Out) { macro_rules! make_node { ($node_id: expr) => { { let logger: Arc = Arc::new(test_logger::TestLogger::new($node_id.to_string(), out.clone())); - let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone())); + let monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone(), Arc::new(TestPersister{}))); let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) }); let mut config = UserConfig::default(); @@ -206,7 +250,7 @@ pub fn do_test(data: &[u8], out: Out) { macro_rules! reload_node { ($ser: expr, $node_id: expr, $old_monitors: expr) => { { 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_est.clone())); + let chain_monitor = Arc::new(TestChainMonitor::new(broadcast.clone(), logger.clone(), fee_est.clone(), Arc::new(TestPersister{}))); let keys_manager = Arc::new(KeyProvider { node_id: $node_id, rand_bytes_id: atomic::AtomicU8::new(0) }); let mut config = UserConfig::default(); @@ -405,7 +449,7 @@ pub fn do_test(data: &[u8], out: Out) { ($source: expr, $dest: expr, $amt: expr) => { { let payment_hash = Sha256::hash(&[payment_id; 1]); payment_id = payment_id.wrapping_add(1); - if let Err(_) = $source.send_payment(&Route { + if let Err(err) = $source.send_payment(&Route { paths: vec![vec![RouteHop { pubkey: $dest.0.get_our_node_id(), node_features: NodeFeatures::empty(), @@ -415,14 +459,13 @@ pub fn do_test(data: &[u8], out: Out) { cltv_expiry_delta: 200, }]], }, PaymentHash(payment_hash.into_inner()), &None) { - // Probably ran out of funds - test_return!(); + check_payment_err(err); } } }; ($source: expr, $middle: expr, $dest: expr, $amt: expr) => { { let payment_hash = Sha256::hash(&[payment_id; 1]); payment_id = payment_id.wrapping_add(1); - if let Err(_) = $source.send_payment(&Route { + if let Err(err) = $source.send_payment(&Route { paths: vec![vec![RouteHop { pubkey: $middle.0.get_our_node_id(), node_features: NodeFeatures::empty(), @@ -439,8 +482,7 @@ pub fn do_test(data: &[u8], out: Out) { cltv_expiry_delta: 200, }]], }, PaymentHash(payment_hash.into_inner()), &None) { - // Probably ran out of funds - test_return!(); + check_payment_err(err); } } } } @@ -450,7 +492,7 @@ pub fn do_test(data: &[u8], out: Out) { payment_id = payment_id.wrapping_add(1); let payment_secret = Sha256::hash(&[payment_id; 1]); payment_id = payment_id.wrapping_add(1); - if let Err(_) = $source.send_payment(&Route { + if let Err(err) = $source.send_payment(&Route { paths: vec![vec![RouteHop { pubkey: $middle.0.get_our_node_id(), node_features: NodeFeatures::empty(), @@ -481,8 +523,7 @@ pub fn do_test(data: &[u8], out: Out) { cltv_expiry_delta: 200, }]], }, PaymentHash(payment_hash.into_inner()), &Some(PaymentSecret(payment_secret.into_inner()))) { - // Probably ran out of funds - test_return!(); + check_payment_err(err); } } } }