Add a few more simple tests of the PeerHandler
[rust-lightning] / fuzz / src / chanmon_consistency.rs
index acdf3cb3ca2dc3b2f902aa1a323e645b837d2368..8c4f5adcb64ae64abbbc03b0956c556f3abbf44c 100644 (file)
@@ -34,7 +34,7 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateErr, chainmonitor, channel
 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;
@@ -50,8 +50,7 @@ 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};
@@ -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 {
@@ -161,8 +161,12 @@ struct KeyProvider {
 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<SecretKey, ()> {
+               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 {
@@ -184,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(),
@@ -207,7 +212,7 @@ impl KeysInterface for KeyProvider {
        fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::Signer, DecodeError> {
                let mut reader = std::io::Cursor::new(buffer);
 
-               let inner: InMemorySigner = 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 {
@@ -217,7 +222,7 @@ impl KeysInterface for KeyProvider {
                })
        }
 
-       fn sign_invoice(&self, _invoice_preimage: Vec<u8>) -> Result<RecoverableSignature, ()> {
+       fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result<RecoverableSignature, ()> {
                unreachable!()
        }
 }
@@ -284,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);
@@ -305,7 +310,7 @@ fn send_payment(source: &ChanMan, dest: &ChanMan, dest_chan_id: u64, amt: u64, p
                        fee_msat: amt,
                        cltv_expiry_delta: 200,
                }]],
-               payee: None,
+               payment_params: None,
        }, payment_hash, &Some(payment_secret)) {
                check_payment_err(err);
                false
@@ -331,7 +336,7 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
                        fee_msat: amt,
                        cltv_expiry_delta: 200,
                }]],
-               payee: None,
+               payment_params: None,
        }, payment_hash, &Some(payment_secret)) {
                check_payment_err(err);
                false
@@ -339,7 +344,8 @@ fn send_hop_payment(source: &ChanMan, middle: &ChanMan, middle_chan_id: u64, des
 }
 
 #[inline]
-pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
+pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
+       let out = SearchingOutput::new(underlying_out);
        let broadcast = Arc::new(TestBroadcaster{});
 
        macro_rules! make_node {
@@ -405,8 +411,8 @@ pub fn do_test<Out: test_logger::Output>(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 = {
@@ -734,7 +740,11 @@ pub fn do_test<Out: test_logger::Output>(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;
@@ -766,7 +776,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                        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));
@@ -783,7 +797,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                        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));
@@ -829,12 +847,17 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
                                                        }
                                                },
                                                events::Event::PaymentSent { .. } => {},
+                                               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
@@ -898,15 +921,15 @@ pub fn do_test<Out: test_logger::Output>(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;
                                }
                        },
@@ -1101,13 +1124,13 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
 
                                // 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;
                                }
 
@@ -1125,7 +1148,7 @@ pub fn do_test<Out: test_logger::Output>(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));
@@ -1152,7 +1175,29 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
        }
 }
 
-pub fn chanmon_consistency_test<Out: test_logger::Output>(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<O: Output> {
+       output: O,
+       may_fail: Arc<atomic::AtomicBool>,
+}
+impl<O: Output> Output for SearchingOutput<O> {
+       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<O: Output> SearchingOutput<O> {
+       pub fn new(output: O) -> Self {
+               Self { output, may_fail: Arc::new(atomic::AtomicBool::new(false)) }
+       }
+}
+
+pub fn chanmon_consistency_test<Out: Output>(data: &[u8], out: Out) {
        do_test(data, out);
 }