X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Ffull_stack.rs;h=901c9ef1e25e43850e1fa2dd090fd591d69b116c;hb=75d71cead386cac3c42a6c4d4f204869ec8dacc5;hp=8cef7fb5458f0f0105cd655e78f2b6e0f4621d4f;hpb=4c655b2281383069e6ca27ba0faf640250d251c3;p=rust-lightning diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 8cef7fb5..901c9ef1 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -1,3 +1,12 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + //! Test that no series of bytes received over the wire/connections created/payments sent can //! result in a crash. We do this by standing up a node and then reading bytes from input to denote //! actions such as creating new inbound/outbound connections, bytes to be read from a connection, @@ -10,27 +19,31 @@ use bitcoin::blockdata::script::{Builder, Script}; use bitcoin::blockdata::opcodes; use bitcoin::consensus::encode::deserialize; use bitcoin::network::constants::Network; -use bitcoin::util::hash::BitcoinHash; +use bitcoin::blockdata::constants::genesis_block; use bitcoin::hashes::Hash as TraitImport; use bitcoin::hashes::HashEngine as TraitImportEngine; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; -use lightning::chain::chaininterface::{BroadcasterInterface,ConfirmationTarget,ChainListener,FeeEstimator,ChainWatchInterfaceUtil}; +use lightning::chain; +use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; +use lightning::chain::chainmonitor; use lightning::chain::transaction::OutPoint; use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface}; -use lightning::ln::channelmonitor; use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret}; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; +use lightning::ln::msgs::DecodeError; use lightning::routing::router::get_route; use lightning::routing::network_graph::NetGraphMsgHandler; +use lightning::util::config::UserConfig; use lightning::util::events::{EventsProvider,Event}; use lightning::util::enforcing_trait_impls::EnforcingChannelKeys; use lightning::util::logger::Logger; -use lightning::util::config::UserConfig; +use lightning::util::ser::Readable; use utils::test_logger; +use utils::test_persister::TestPersister; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; use bitcoin::secp256k1::Secp256k1; @@ -94,10 +107,10 @@ struct FuzzEstimator { input: Arc, } impl FeeEstimator for FuzzEstimator { - fn get_est_sat_per_1000_weight(&self, _: ConfirmationTarget) -> u64 { + fn get_est_sat_per_1000_weight(&self, _: ConfirmationTarget) -> u32 { //TODO: We should actually be testing at least much more than 64k... match self.input.get_slice(2) { - Some(slice) => cmp::max(slice_to_be16(slice) as u64, 253), + Some(slice) => cmp::max(slice_to_be16(slice) as u32, 253), None => 253 } } @@ -136,14 +149,13 @@ impl<'a> std::hash::Hash for Peer<'a> { type ChannelMan = ChannelManager< EnforcingChannelKeys, - Arc, Arc, Arc, Arc>>, + Arc, Arc, Arc, Arc, Arc>>, Arc, Arc, Arc, Arc>; -type PeerMan<'a> = PeerManager, Arc, Arc, Arc>>, Arc>; +type PeerMan<'a> = PeerManager, Arc, Arc, Arc>>, Arc>; struct MoneyLossDetector<'a> { manager: Arc, - monitor: Arc, Arc, Arc, Arc>>, + monitor: Arc, Arc, Arc, Arc, Arc>>, handler: PeerMan<'a>, peers: &'a RefCell<[bool; 256]>, @@ -157,7 +169,7 @@ struct MoneyLossDetector<'a> { impl<'a> MoneyLossDetector<'a> { pub fn new(peers: &'a RefCell<[bool; 256]>, manager: Arc, - monitor: Arc, Arc, Arc, Arc>>, + monitor: Arc, Arc, Arc, Arc, Arc>>, handler: PeerMan<'a>) -> Self { MoneyLossDetector { manager, @@ -175,15 +187,13 @@ impl<'a> MoneyLossDetector<'a> { } fn connect_block(&mut self, all_txn: &[Transaction]) { - let mut txn = Vec::with_capacity(all_txn.len()); - let mut txn_idxs = Vec::with_capacity(all_txn.len()); + let mut txdata = Vec::with_capacity(all_txn.len()); for (idx, tx) in all_txn.iter().enumerate() { let txid = tx.txid(); match self.txids_confirmed.entry(txid) { hash_map::Entry::Vacant(e) => { e.insert(self.height); - txn.push(tx); - txn_idxs.push(idx as u32 + 1); + txdata.push((idx + 1, tx)); }, _ => {}, } @@ -192,13 +202,13 @@ impl<'a> MoneyLossDetector<'a> { let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 }; self.height += 1; self.blocks_connected += 1; - self.manager.block_connected(&header, self.height as u32, &txn[..], &txn_idxs[..]); - (*self.monitor).block_connected(&header, self.height as u32, &txn[..], &txn_idxs[..]); + self.manager.block_connected(&header, &txdata, self.height as u32); + (*self.monitor).block_connected(&header, &txdata, self.height as u32); if self.header_hashes.len() > self.height { - self.header_hashes[self.height] = header.bitcoin_hash(); + self.header_hashes[self.height] = header.block_hash(); } else { assert_eq!(self.header_hashes.len(), self.height); - self.header_hashes.push(header.bitcoin_hash()); + self.header_hashes.push(header.block_hash()); } self.max_height = cmp::max(self.height, self.max_height); } @@ -206,7 +216,7 @@ impl<'a> MoneyLossDetector<'a> { fn disconnect_block(&mut self) { if self.height > 0 && (self.max_height < 6 || self.height >= self.max_height - 6) { let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height], merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; - self.manager.block_disconnected(&header, self.height as u32); + self.manager.block_disconnected(&header); self.monitor.block_disconnected(&header, self.height as u32); self.height -= 1; let removal_height = self.height; @@ -286,17 +296,15 @@ impl KeysInterface for KeyProvider { }) } - fn get_onion_rand(&self) -> (SecretKey, [u8; 32]) { - let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8; - (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, 13, ctr]).unwrap(), - [0; 32]) - } - - fn get_channel_id(&self) -> [u8; 32] { + fn get_secure_random_bytes(&self) -> [u8; 32] { let ctr = self.counter.fetch_add(1, Ordering::Relaxed); [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (ctr >> 8*7) as u8, (ctr >> 8*6) as u8, (ctr >> 8*5) as u8, (ctr >> 8*4) as u8, (ctr >> 8*3) as u8, (ctr >> 8*2) as u8, (ctr >> 8*1) as u8, 14, (ctr >> 8*0) as u8] } + + fn read_chan_signer(&self, data: &[u8]) -> Result { + EnforcingChannelKeys::read(&mut std::io::Cursor::new(data)) + } } #[inline] @@ -332,9 +340,8 @@ pub fn do_test(data: &[u8], logger: &Arc) { Err(_) => return, }; - let watch = Arc::new(ChainWatchInterfaceUtil::new(Network::Bitcoin)); let broadcast = Arc::new(TestBroadcaster{}); - let monitor = Arc::new(channelmonitor::SimpleManyChannelMonitor::new(watch.clone(), broadcast.clone(), Arc::clone(&logger), fee_est.clone())); + let monitor = Arc::new(chainmonitor::ChainMonitor::new(None, broadcast.clone(), Arc::clone(&logger), fee_est.clone(), Arc::new(TestPersister{}))); let keys_manager = Arc::new(KeyProvider { node_secret: our_network_key.clone(), counter: AtomicU64::new(0) }); let mut config = UserConfig::default(); @@ -343,7 +350,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { config.peer_channel_config_limits.min_dust_limit_satoshis = 0; let channelmanager = Arc::new(ChannelManager::new(Network::Bitcoin, fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, 0)); let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret()); - let net_graph_msg_handler = Arc::new(NetGraphMsgHandler::new(watch.clone(), Arc::clone(&logger))); + let net_graph_msg_handler = Arc::new(NetGraphMsgHandler::new(genesis_block(Network::Bitcoin).header.block_hash(), None, Arc::clone(&logger))); let peers = RefCell::new([false; 256]); let mut loss_detector = MoneyLossDetector::new(&peers, channelmanager.clone(), monitor.clone(), PeerManager::new(MessageHandler { @@ -400,7 +407,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { }, 4 => { let value = slice_to_be24(get_slice!(3)) as u64; - let route = match get_route(&our_id, &net_graph_msg_handler, &get_pubkey!(), None, &Vec::new(), value, 42, Arc::clone(&logger)) { + let route = match get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &get_pubkey!(), None, &Vec::new(), value, 42, Arc::clone(&logger)) { Ok(route) => route, Err(_) => return, }; @@ -417,7 +424,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { }, 15 => { let value = slice_to_be24(get_slice!(3)) as u64; - let mut route = match get_route(&our_id, &net_graph_msg_handler, &get_pubkey!(), None, &Vec::new(), value, 42, Arc::clone(&logger)) { + let mut route = match get_route(&our_id, &net_graph_msg_handler.network_graph.read().unwrap(), &get_pubkey!(), None, &Vec::new(), value, 42, Arc::clone(&logger)) { Ok(route) => route, Err(_) => return, }; @@ -541,7 +548,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { let channel_id = get_slice!(1)[0] as usize; if channel_id >= channels.len() { return; } channels.sort_by(|a, b| { a.channel_id.cmp(&b.channel_id) }); - channelmanager.force_close_channel(&channels[channel_id].channel_id); + channelmanager.force_close_channel(&channels[channel_id].channel_id).unwrap(); }, // 15 is above _ => return, @@ -609,7 +616,7 @@ mod tests { // What each byte represents is broken down below, and then everything is concatenated into // one large test at the end (you want %s/ -.*//g %s/\n\| \|\t\|\///g). - // Following BOLT 8, lightning message on the wire are: 2-byte encrypted message length + + // Following BOLT 8, lightning message on the wire are: 2-byte encrypted message length + // 16-byte MAC of the encrypted message length + encrypted Lightning message + 16-byte MAC // of the Lightning message // I.e 2nd inbound read, len 18 : 0006 (encrypted message length) + 03000000000000000000000000000000 (MAC of the encrypted message length) @@ -901,6 +908,6 @@ mod tests { assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 - assert_eq!(log_entries.get(&("lightning::ln::channelmonitor".to_string(), "Input spending remote commitment tx (00000000000000000000000000000000000000000000000000000000000000a1:0) in 0000000000000000000000000000000000000000000000000000000000000018 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); // 10 + assert_eq!(log_entries.get(&("lightning::chain::channelmonitor".to_string(), "Input spending counterparty commitment tx (00000000000000000000000000000000000000000000000000000000000000a1:0) in 0000000000000000000000000000000000000000000000000000000000000018 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); // 10 } }