X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Fchanmon_consistency.rs;h=c0b897e21a3ab65d97e0df0d01a3587f8fcb3f67;hb=08cf93e403af6dcac54b4341ab119fccf902831e;hp=9cdeace668a7b60b7428224eb8f7c3d95a16d2f4;hpb=f2a2fd0d48be78972ed81481c2dfbfb68ecda44e;p=rust-lightning diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 9cdeace6..c0b897e2 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -24,12 +24,14 @@ use bitcoin_hashes::sha256d::Hash as Sha256d; use lightning::chain::chaininterface; use lightning::chain::transaction::OutPoint; use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil}; -use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface}; +use lightning::chain::keysinterface::{KeysInterface, InMemoryChannelKeys}; use lightning::ln::channelmonitor; use lightning::ln::channelmonitor::{ChannelMonitor, ChannelMonitorUpdateErr, HTLCUpdate}; use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, ChannelManagerReadArgs}; use lightning::ln::router::{Route, RouteHop}; -use lightning::ln::msgs::{CommitmentUpdate, ChannelMessageHandler, ErrorAction, LightningError, UpdateAddHTLC, LocalFeatures}; +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::events; use lightning::util::logger::Logger; use lightning::util::config::UserConfig; @@ -83,7 +85,7 @@ pub struct TestChannelMonitor { impl TestChannelMonitor { pub fn new(chain_monitor: Arc, broadcaster: Arc, logger: Arc, feeest: Arc) -> Self { Self { - simple_monitor: channelmonitor::SimpleManyChannelMonitor::new(chain_monitor, broadcaster, logger, feeest), + simple_monitor: Arc::new(channelmonitor::SimpleManyChannelMonitor::new(chain_monitor, broadcaster, logger, feeest)), update_ret: Mutex::new(Ok(())), latest_good_update: Mutex::new(HashMap::new()), latest_update_good: Mutex::new(HashMap::new()), @@ -130,7 +132,7 @@ struct KeyProvider { channel_id: atomic::AtomicU8, } impl KeysInterface for KeyProvider { - type ChanKeySigner = InMemoryChannelKeys; + type ChanKeySigner = EnforcingChannelKeys; 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() @@ -148,15 +150,17 @@ impl KeysInterface for KeyProvider { PublicKey::from_secret_key(&secp_ctx, &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, 3, self.node_id]).unwrap()) } - fn get_channel_keys(&self, _inbound: bool) -> InMemoryChannelKeys { - InMemoryChannelKeys { + fn get_channel_keys(&self, _inbound: bool, channel_value_satoshis: u64) -> EnforcingChannelKeys { + EnforcingChannelKeys::new(InMemoryChannelKeys { funding_key: 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(), revocation_base_key: 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(), payment_base_key: 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(), delayed_payment_base_key: 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, 7, self.node_id]).unwrap(), htlc_base_key: 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, 8, self.node_id]).unwrap(), commitment_seed: [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, 9, self.node_id], - } + remote_channel_pubkeys: None, + channel_value_satoshis, + }) } fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) { @@ -187,7 +191,7 @@ pub fn do_test(data: &[u8]) { config.channel_options.fee_proportional_millionths = 0; config.channel_options.announced_channel = true; config.peer_channel_config_limits.min_dust_limit_satoshis = 0; - (ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0).unwrap(), + (Arc::new(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0).unwrap()), monitor) } } } @@ -211,7 +215,7 @@ pub fn do_test(data: &[u8]) { monitor.latest_good_update.lock().unwrap().insert(outpoint, monitor_ser); } let mut monitor_refs = HashMap::new(); - for (outpoint, monitor) in monitors.iter() { + for (outpoint, monitor) in monitors.iter_mut() { monitor_refs.insert(*outpoint, monitor); } @@ -222,10 +226,10 @@ pub fn do_test(data: &[u8]) { tx_broadcaster: broadcast.clone(), logger, default_config: config, - channel_monitors: &monitor_refs, + channel_monitors: &mut monitor_refs, }; - let res = (<(Sha256d, ChannelManager)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor); + let res = (<(Sha256d, ChannelManager>)>::read(&mut Cursor::new(&$ser.0), read_args).expect("Failed to read manager").1, monitor); for (_, was_good) in $old_monitors.latest_updates_good_at_last_ser.lock().unwrap().iter() { if !was_good { // If the last time we updated a monitor we didn't successfully update (and we @@ -251,7 +255,7 @@ pub fn do_test(data: &[u8]) { } else { panic!("Wrong event type"); } }; - $dest.handle_open_channel(&$source.get_our_node_id(), LocalFeatures::new(), &open_channel).unwrap(); + $dest.handle_open_channel(&$source.get_our_node_id(), InitFeatures::supported(), &open_channel); let accept_channel = { let events = $dest.get_and_clear_pending_msg_events(); assert_eq!(events.len(), 1); @@ -260,7 +264,7 @@ pub fn do_test(data: &[u8]) { } else { panic!("Wrong event type"); } }; - $source.handle_accept_channel(&$dest.get_our_node_id(), LocalFeatures::new(), &accept_channel).unwrap(); + $source.handle_accept_channel(&$dest.get_our_node_id(), InitFeatures::supported(), &accept_channel); { let events = $source.get_and_clear_pending_events(); assert_eq!(events.len(), 1); @@ -281,7 +285,7 @@ pub fn do_test(data: &[u8]) { msg.clone() } else { panic!("Wrong event type"); } }; - $dest.handle_funding_created(&$source.get_our_node_id(), &funding_created).unwrap(); + $dest.handle_funding_created(&$source.get_our_node_id(), &funding_created); let funding_signed = { let events = $dest.get_and_clear_pending_msg_events(); @@ -290,7 +294,7 @@ pub fn do_test(data: &[u8]) { msg.clone() } else { panic!("Wrong event type"); } }; - $source.handle_funding_signed(&$dest.get_our_node_id(), &funding_signed).unwrap(); + $source.handle_funding_signed(&$dest.get_our_node_id(), &funding_signed); { let events = $source.get_and_clear_pending_events(); @@ -329,7 +333,7 @@ pub fn do_test(data: &[u8]) { if let events::MessageSendEvent::SendFundingLocked { ref node_id, ref msg } = event { for node in $nodes.iter() { if node.get_our_node_id() == *node_id { - node.handle_funding_locked(&$nodes[idx].get_our_node_id(), msg).unwrap(); + node.handle_funding_locked(&$nodes[idx].get_our_node_id(), msg); } } } else { panic!("Wrong event type"); } @@ -380,16 +384,6 @@ pub fn do_test(data: &[u8]) { let mut node_c_ser = VecWriter(Vec::new()); nodes[2].write(&mut node_c_ser).unwrap(); - macro_rules! test_err { - ($res: expr) => { - match $res { - Ok(()) => {}, - Err(LightningError { action: ErrorAction::IgnoreError, .. }) => { }, - _ => { $res.unwrap() }, - } - } - } - macro_rules! test_return { () => { { assert_eq!(nodes[0].list_channels().len(), 1); @@ -419,33 +413,79 @@ pub fn do_test(data: &[u8]) { let payment_hash = Sha256::hash(&[payment_id; 1]); payment_id = payment_id.wrapping_add(1); if let Err(_) = $source.send_payment(Route { - hops: vec![RouteHop { + paths: vec![vec![RouteHop { pubkey: $dest.0.get_our_node_id(), + node_features: NodeFeatures::empty(), short_channel_id: $dest.1, + channel_features: ChannelFeatures::empty(), fee_msat: 5000000, cltv_expiry_delta: 200, - }], - }, PaymentHash(payment_hash.into_inner())) { + }]], + }, PaymentHash(payment_hash.into_inner()), None) { // Probably ran out of funds test_return!(); } } }; - ($source: expr, $middle: expr, $dest: expr) => { { + ($source: expr, $middle: expr, $dest: expr, false) => { { let payment_hash = Sha256::hash(&[payment_id; 1]); payment_id = payment_id.wrapping_add(1); if let Err(_) = $source.send_payment(Route { - hops: vec![RouteHop { + paths: vec![vec![RouteHop { + pubkey: $middle.0.get_our_node_id(), + node_features: NodeFeatures::empty(), + short_channel_id: $middle.1, + channel_features: ChannelFeatures::empty(), + fee_msat: 50000, + cltv_expiry_delta: 100, + },RouteHop { + pubkey: $dest.0.get_our_node_id(), + node_features: NodeFeatures::empty(), + short_channel_id: $dest.1, + channel_features: ChannelFeatures::empty(), + fee_msat: 5000000, + cltv_expiry_delta: 200, + }]], + }, PaymentHash(payment_hash.into_inner()), None) { + // Probably ran out of funds + test_return!(); + } + } }; + ($source: expr, $middle: expr, $dest: expr, true) => { { + let payment_hash = Sha256::hash(&[payment_id; 1]); + 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 { + paths: vec![vec![RouteHop { + pubkey: $middle.0.get_our_node_id(), + node_features: NodeFeatures::empty(), + short_channel_id: $middle.1, + channel_features: ChannelFeatures::empty(), + fee_msat: 50000, + cltv_expiry_delta: 100, + },RouteHop { + pubkey: $dest.0.get_our_node_id(), + node_features: NodeFeatures::empty(), + short_channel_id: $dest.1, + channel_features: ChannelFeatures::empty(), + fee_msat: 5000000, + cltv_expiry_delta: 200, + }],vec![RouteHop { pubkey: $middle.0.get_our_node_id(), + node_features: NodeFeatures::empty(), short_channel_id: $middle.1, + channel_features: ChannelFeatures::empty(), fee_msat: 50000, cltv_expiry_delta: 100, },RouteHop { pubkey: $dest.0.get_our_node_id(), + node_features: NodeFeatures::empty(), short_channel_id: $dest.1, + channel_features: ChannelFeatures::empty(), fee_msat: 5000000, cltv_expiry_delta: 200, - }], - }, PaymentHash(payment_hash.into_inner())) { + }]], + }, PaymentHash(payment_hash.into_inner()), Some(&payment_secret.into_inner())) { // Probably ran out of funds test_return!(); } @@ -461,7 +501,28 @@ pub fn do_test(data: &[u8]) { bc_events.clear(); new_events } else { Vec::new() }; - for event in events.iter().chain(nodes[$node].get_and_clear_pending_msg_events().iter()) { + let ev = nodes[$node].get_and_clear_pending_msg_events(); + for event in events.iter().chain(ev.iter()) { + match event { + events::MessageSendEvent::UpdateHTLCs { updates: CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, .. }, .. } => { + println!("UPDATEHTLCs {} {} {} {}", update_add_htlcs.len(), update_fail_htlcs.len(), update_fulfill_htlcs.len(), update_fail_malformed_htlcs.len()); + }, + events::MessageSendEvent::SendRevokeAndACK { .. } => { + println!("RAA"); + }, + events::MessageSendEvent::SendChannelReestablish { .. } => { + println!("Chan REE"); + }, + events::MessageSendEvent::SendFundingLocked { .. } => { + println!("FL"); + }, + events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => { + println!("Fail net update"); + }, + _ => panic!("Unhandled message event"), + } + } + for event in events.iter().chain(ev.iter()) { match event { events::MessageSendEvent::UpdateHTLCs { ref node_id, updates: CommitmentUpdate { ref update_add_htlcs, ref update_fail_htlcs, ref update_fulfill_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { for dest in nodes.iter() { @@ -469,7 +530,7 @@ pub fn do_test(data: &[u8]) { assert!(update_fee.is_none()); for update_add in update_add_htlcs { if !$corrupt_forward { - test_err!(dest.handle_update_add_htlc(&nodes[$node].get_our_node_id(), &update_add)); + 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 @@ -478,33 +539,33 @@ pub fn do_test(data: &[u8]) { let mut msg_ser = update_add.encode(); msg_ser[1000] ^= 0xff; let new_msg = UpdateAddHTLC::read(&mut Cursor::new(&msg_ser)).unwrap(); - test_err!(dest.handle_update_add_htlc(&nodes[$node].get_our_node_id(), &new_msg)); + dest.handle_update_add_htlc(&nodes[$node].get_our_node_id(), &new_msg); } } for update_fulfill in update_fulfill_htlcs { - test_err!(dest.handle_update_fulfill_htlc(&nodes[$node].get_our_node_id(), &update_fulfill)); + dest.handle_update_fulfill_htlc(&nodes[$node].get_our_node_id(), &update_fulfill); } for update_fail in update_fail_htlcs { - test_err!(dest.handle_update_fail_htlc(&nodes[$node].get_our_node_id(), &update_fail)); + dest.handle_update_fail_htlc(&nodes[$node].get_our_node_id(), &update_fail); } for update_fail_malformed in update_fail_malformed_htlcs { - test_err!(dest.handle_update_fail_malformed_htlc(&nodes[$node].get_our_node_id(), &update_fail_malformed)); + dest.handle_update_fail_malformed_htlc(&nodes[$node].get_our_node_id(), &update_fail_malformed); } - test_err!(dest.handle_commitment_signed(&nodes[$node].get_our_node_id(), &commitment_signed)); + dest.handle_commitment_signed(&nodes[$node].get_our_node_id(), &commitment_signed); } } }, events::MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { for dest in nodes.iter() { if dest.get_our_node_id() == *node_id { - test_err!(dest.handle_revoke_and_ack(&nodes[$node].get_our_node_id(), msg)); + 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() { if dest.get_our_node_id() == *node_id { - test_err!(dest.handle_channel_reestablish(&nodes[$node].get_our_node_id(), msg)); + dest.handle_channel_reestablish(&nodes[$node].get_our_node_id(), msg); } } }, @@ -515,6 +576,10 @@ pub fn do_test(data: &[u8]) { // Can be generated due to a payment forward being rejected due to a // channel having previously failed a monitor update }, + events::MessageSendEvent::HandleError { action: ErrorAction::IgnoreError, .. } => { + // Can be generated at any processing step to send back an error, disconnect + // peer or just ignore + }, _ => panic!("Unhandled message event"), } } @@ -531,6 +596,7 @@ pub fn do_test(data: &[u8]) { events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendFundingLocked { .. } => {}, events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => {}, + events::MessageSendEvent::HandleError { action: ErrorAction::IgnoreError, .. } => {}, _ => panic!("Unhandled message event"), } } @@ -543,6 +609,7 @@ pub fn do_test(data: &[u8]) { events::MessageSendEvent::SendChannelReestablish { .. } => {}, events::MessageSendEvent::SendFundingLocked { .. } => {}, events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => {}, + events::MessageSendEvent::HandleError { action: ErrorAction::IgnoreError, .. } => {}, _ => panic!("Unhandled message event"), } } @@ -564,6 +631,7 @@ pub fn do_test(data: &[u8]) { }, events::MessageSendEvent::SendFundingLocked { .. } => false, events::MessageSendEvent::PaymentFailureNetworkUpdate { .. } => false, + events::MessageSendEvent::HandleError { action: ErrorAction::IgnoreError, .. } => false, _ => panic!("Unhandled message event"), }; if push { msg_sink.push(event); } @@ -596,12 +664,12 @@ pub fn do_test(data: &[u8]) { }); for event in events.drain(..) { match event { - events::Event::PaymentReceived { payment_hash, .. } => { + events::Event::PaymentReceived { payment_hash, payment_secret, .. } => { if claim_set.insert(payment_hash.0) { if $fail { - assert!(nodes[$node].fail_htlc_backwards(&payment_hash)); + assert!(nodes[$node].fail_htlc_backwards(&payment_hash, &payment_secret)); } else { - assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0), 5_000_000)); + assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0), &payment_secret, 5_000_000)); } } }, @@ -616,7 +684,9 @@ pub fn do_test(data: &[u8]) { } } } - match get_slice!(1)[0] { + let a = get_slice!(1)[0]; + println!("PROCESSING {:x}", a); + match a { 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), @@ -630,8 +700,8 @@ pub fn do_test(data: &[u8]) { 0x0a => send_payment!(nodes[1], (&nodes[0], chan_a)), 0x0b => send_payment!(nodes[1], (&nodes[2], chan_b)), 0x0c => send_payment!(nodes[2], (&nodes[1], chan_b)), - 0x0d => send_payment!(nodes[0], (&nodes[1], chan_a), (&nodes[2], chan_b)), - 0x0e => send_payment!(nodes[2], (&nodes[1], chan_b), (&nodes[0], chan_a)), + 0x0d => send_payment!(nodes[0], (&nodes[1], chan_a), (&nodes[2], chan_b), false), + 0x0e => send_payment!(nodes[2], (&nodes[1], chan_b), (&nodes[0], chan_a), false), 0x0f => { if !chan_a_disconnected { nodes[0].peer_disconnected(&nodes[1].get_our_node_id(), false); @@ -650,15 +720,15 @@ pub fn do_test(data: &[u8]) { }, 0x11 => { if chan_a_disconnected { - nodes[0].peer_connected(&nodes[1].get_our_node_id()); - nodes[1].peer_connected(&nodes[0].get_our_node_id()); + nodes[0].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::empty() }); + nodes[1].peer_connected(&nodes[0].get_our_node_id(), &Init { features: InitFeatures::empty() }); chan_a_disconnected = false; } }, 0x12 => { if chan_b_disconnected { - nodes[1].peer_connected(&nodes[2].get_our_node_id()); - nodes[2].peer_connected(&nodes[1].get_our_node_id()); + nodes[1].peer_connected(&nodes[2].get_our_node_id(), &Init { features: InitFeatures::empty() }); + nodes[2].peer_connected(&nodes[1].get_our_node_id(), &Init { features: InitFeatures::empty() }); chan_b_disconnected = false; } }, @@ -714,6 +784,8 @@ pub fn do_test(data: &[u8]) { nodes[2] = node_c.clone(); monitor_c = new_monitor_c; }, + 0x22 => send_payment!(nodes[0], (&nodes[1], chan_a), (&nodes[2], chan_b), true), + 0x23 => send_payment!(nodes[2], (&nodes[1], chan_b), (&nodes[0], chan_a), true), _ => test_return!(), } @@ -742,11 +814,3 @@ pub fn do_test(data: &[u8]) { pub extern "C" fn chanmon_consistency_run(data: *const u8, datalen: usize) { do_test(unsafe { std::slice::from_raw_parts(data, datalen) }); } - -#[cfg(test)] -mod tests { - #[test] - fn duplicate_crash() { - super::do_test(&::hex::decode("00").unwrap()); - } -}