X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Frouter.rs;h=baa32312ee9b769aef249810f80894c300507ac8;hb=2b08a47e887913c8b056192d5b9df4569cf32548;hp=434e1b657d135de9d49dffdf1a7d83c4be2d2cc5;hpb=c906f2843234ba9164e562a19bccaabde0243d95;p=rust-lightning diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs index 434e1b65..baa32312 100644 --- a/fuzz/src/router.rs +++ b/fuzz/src/router.rs @@ -1,21 +1,34 @@ -use bitcoin_hashes::sha256d::Hash as Sha256dHash; -use bitcoin::blockdata::script::{Script, Builder}; -use bitcoin::blockdata::block::Block; -use bitcoin::blockdata::transaction::Transaction; +// 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. -use lightning::chain::chaininterface::{ChainError,ChainWatchInterface}; -use lightning::ln::channelmanager::ChannelDetails; +use bitcoin::blockdata::script::Builder; +use bitcoin::blockdata::transaction::TxOut; +use bitcoin::hash_types::BlockHash; + +use lightning::chain; +use lightning::chain::transaction::OutPoint; +use lightning::ln::channelmanager::{ChannelDetails, ChannelCounterparty}; use lightning::ln::features::InitFeatures; use lightning::ln::msgs; -use lightning::ln::msgs::RoutingMessageHandler; -use lightning::ln::router::{Router, RouteHint}; +use lightning::routing::router::{get_route, RouteHint, RouteHintHop}; use lightning::util::logger::Logger; use lightning::util::ser::Readable; +use lightning::routing::network_graph::{NetworkGraph, RoutingFees}; -use secp256k1::key::PublicKey; +use bitcoin::hashes::Hash; +use bitcoin::secp256k1::key::PublicKey; +use bitcoin::network::constants::Network; +use bitcoin::blockdata::constants::genesis_block; use utils::test_logger; +use std::collections::HashSet; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -67,33 +80,23 @@ impl InputData { } } -struct DummyChainWatcher { +struct FuzzChainSource { input: Arc, } - -impl ChainWatchInterface for DummyChainWatcher { - fn install_watch_tx(&self, _txid: &Sha256dHash, _script_pub_key: &Script) { } - fn install_watch_outpoint(&self, _outpoint: (Sha256dHash, u32), _out_script: &Script) { } - fn watch_all_txn(&self) { } - fn filter_block<'a>(&self, _block: &'a Block) -> (Vec<&'a Transaction>, Vec) { - (Vec::new(), Vec::new()) - } - fn reentered(&self) -> usize { 0 } - - fn get_chain_utxo(&self, _genesis_hash: Sha256dHash, _unspent_tx_output_identifier: u64) -> Result<(Script, u64), ChainError> { +impl chain::Access for FuzzChainSource { + fn get_utxo(&self, _genesis_hash: &BlockHash, _short_channel_id: u64) -> Result { match self.input.get_slice(2) { - Some(&[0, _]) => Err(ChainError::NotSupported), - Some(&[1, _]) => Err(ChainError::NotWatched), - Some(&[2, _]) => Err(ChainError::UnknownTx), - Some(&[_, x]) => Ok((Builder::new().push_int(x as i64).into_script().to_v0_p2wsh(), 0)), - None => Err(ChainError::UnknownTx), + Some(&[0, _]) => Err(chain::AccessError::UnknownChain), + Some(&[1, _]) => Err(chain::AccessError::UnknownTx), + Some(&[_, x]) => Ok(TxOut { value: 0, script_pubkey: Builder::new().push_int(x as i64).into_script().to_v0_p2wsh() }), + None => Err(chain::AccessError::UnknownTx), _ => unreachable!(), } } } #[inline] -pub fn do_test(data: &[u8]) { +pub fn do_test(data: &[u8], out: Out) { let input = Arc::new(InputData { data: data.to_vec(), read_pos: AtomicUsize::new(0), @@ -118,26 +121,29 @@ pub fn do_test(data: &[u8]) { macro_rules! decode_msg { ($MsgType: path, $len: expr) => {{ let mut reader = ::std::io::Cursor::new(get_slice!($len)); - match <($MsgType)>::read(&mut reader) { - Ok(msg) => msg, + match <$MsgType>::read(&mut reader) { + Ok(msg) => { + assert_eq!(reader.position(), $len as u64); + msg + }, Err(e) => match e { msgs::DecodeError::UnknownVersion => return, msgs::DecodeError::UnknownRequiredFeature => return, msgs::DecodeError::InvalidValue => return, - msgs::DecodeError::ExtraAddressesPerType => return, msgs::DecodeError::BadLengthDescriptor => return, msgs::DecodeError::ShortRead => panic!("We picked the length..."), - msgs::DecodeError::Io(e) => panic!(format!("{}", e)), + msgs::DecodeError::Io(e) => panic!("{:?}", e), + msgs::DecodeError::UnsupportedCompression => return, } } }} } macro_rules! decode_msg_with_len16 { - ($MsgType: path, $begin_len: expr, $excess: expr) => { + ($MsgType: path, $excess: expr) => { { - let extra_len = slice_to_be16(&get_slice_nonadvancing!($begin_len as usize + 2)[$begin_len..$begin_len + 2]); - decode_msg!($MsgType, $begin_len as usize + 2 + (extra_len as usize) + $excess) + let extra_len = slice_to_be16(get_slice_nonadvancing!(2)); + decode_msg!($MsgType, 2 + (extra_len as usize) + $excess) } } } @@ -151,89 +157,112 @@ pub fn do_test(data: &[u8]) { } } - let logger: Arc = Arc::new(test_logger::TestLogger::new("".to_owned())); - let chain_monitor = Arc::new(DummyChainWatcher { - input: Arc::clone(&input), - }); + let logger: Arc = Arc::new(test_logger::TestLogger::new("".to_owned(), out)); let our_pubkey = get_pubkey!(); - let router = Router::new(our_pubkey.clone(), chain_monitor, Arc::clone(&logger)); + let mut net_graph = NetworkGraph::new(genesis_block(Network::Bitcoin).header.block_hash()); + + let mut node_pks = HashSet::new(); + let mut scid = 42; loop { match get_slice!(1)[0] { 0 => { - let start_len = slice_to_be16(&get_slice_nonadvancing!(64 + 2)[64..64 + 2]) as usize; - let addr_len = slice_to_be16(&get_slice_nonadvancing!(64+start_len+2 + 74)[64+start_len+2 + 72..64+start_len+2 + 74]); + let start_len = slice_to_be16(&get_slice_nonadvancing!(2)[0..2]) as usize; + let addr_len = slice_to_be16(&get_slice_nonadvancing!(start_len+2 + 74)[start_len+2 + 72..start_len+2 + 74]); if addr_len > (37+1)*4 { return; } - let _ = router.handle_node_announcement(&decode_msg_with_len16!(msgs::NodeAnnouncement, 64, 288)); + let msg = decode_msg_with_len16!(msgs::UnsignedNodeAnnouncement, 288); + node_pks.insert(msg.node_id); + let _ = net_graph.update_node_from_unsigned_announcement(&msg); }, 1 => { - let _ = router.handle_channel_announcement(&decode_msg_with_len16!(msgs::ChannelAnnouncement, 64*4, 32+8+33*4)); + let msg = decode_msg_with_len16!(msgs::UnsignedChannelAnnouncement, 32+8+33*4); + node_pks.insert(msg.node_id_1); + node_pks.insert(msg.node_id_2); + let _ = net_graph.update_channel_from_unsigned_announcement::<&FuzzChainSource>(&msg, &None); }, 2 => { - let _ = router.handle_channel_update(&decode_msg!(msgs::ChannelUpdate, 128)); + let msg = decode_msg_with_len16!(msgs::UnsignedChannelAnnouncement, 32+8+33*4); + node_pks.insert(msg.node_id_1); + node_pks.insert(msg.node_id_2); + let _ = net_graph.update_channel_from_unsigned_announcement(&msg, &Some(&FuzzChainSource { input: Arc::clone(&input) })); }, 3 => { - match get_slice!(1)[0] { - 0 => { - router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {msg: decode_msg!(msgs::ChannelUpdate, 128)}); - }, - 1 => { - let short_channel_id = slice_to_be64(get_slice!(8)); - router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed {short_channel_id, is_permanent: false}); - }, - _ => return, - } + let _ = net_graph.update_channel_unsigned(&decode_msg!(msgs::UnsignedChannelUpdate, 72)); }, 4 => { - let target = get_pubkey!(); + let short_channel_id = slice_to_be64(get_slice!(8)); + net_graph.close_channel_from_update(short_channel_id, false); + }, + _ if node_pks.is_empty() => {}, + _ => { let mut first_hops_vec = Vec::new(); let first_hops = match get_slice!(1)[0] { 0 => None, - 1 => { - let count = slice_to_be16(get_slice!(2)); + count => { for _ in 0..count { + scid += 1; + let rnid = node_pks.iter().skip(slice_to_be16(get_slice!(2))as usize % node_pks.len()).next().unwrap(); first_hops_vec.push(ChannelDetails { channel_id: [0; 32], - short_channel_id: Some(slice_to_be64(get_slice!(8))), - remote_network_id: get_pubkey!(), - counterparty_features: InitFeatures::empty(), + counterparty: ChannelCounterparty { + node_id: *rnid, + features: InitFeatures::known(), + unspendable_punishment_reserve: 0, + forwarding_info: None, + }, + funding_txo: Some(OutPoint { txid: bitcoin::Txid::from_slice(&[0; 32]).unwrap(), index: 0 }), + short_channel_id: Some(scid), channel_value_satoshis: slice_to_be64(get_slice!(8)), - user_id: 0, - inbound_capacity_msat: 0, - is_live: true, + user_id: 0, inbound_capacity_msat: 0, + unspendable_punishment_reserve: None, + confirmations_required: None, + force_close_spend_delay: None, + is_outbound: true, is_funding_locked: true, + is_usable: true, is_public: true, outbound_capacity_msat: 0, }); } Some(&first_hops_vec[..]) }, - _ => return, }; - let mut last_hops_vec = Vec::new(); - let last_hops = { - let count = slice_to_be16(get_slice!(2)); + let mut last_hops = Vec::new(); + { + let count = get_slice!(1)[0]; for _ in 0..count { - last_hops_vec.push(RouteHint { - src_node_id: get_pubkey!(), - short_channel_id: slice_to_be64(get_slice!(8)), - fee_base_msat: slice_to_be32(get_slice!(4)), - fee_proportional_millionths: slice_to_be32(get_slice!(4)), + scid += 1; + let rnid = node_pks.iter().skip(slice_to_be16(get_slice!(2))as usize % node_pks.len()).next().unwrap(); + last_hops.push(RouteHint(vec![RouteHintHop { + src_node_id: *rnid, + short_channel_id: scid, + fees: RoutingFees { + base_msat: slice_to_be32(get_slice!(4)), + proportional_millionths: slice_to_be32(get_slice!(4)), + }, cltv_expiry_delta: slice_to_be16(get_slice!(2)), - htlc_minimum_msat: slice_to_be64(get_slice!(8)), - }); + htlc_minimum_msat: Some(slice_to_be64(get_slice!(8))), + htlc_maximum_msat: None, + }])); } - &last_hops_vec[..] - }; - let _ = router.get_route(&target, first_hops, last_hops, slice_to_be64(get_slice!(8)), slice_to_be32(get_slice!(4))); + } + for target in node_pks.iter() { + let _ = get_route(&our_pubkey, &net_graph, target, None, + first_hops.map(|c| c.iter().collect::>()).as_ref().map(|a| a.as_slice()), + &last_hops.iter().collect::>(), + slice_to_be64(get_slice!(8)), slice_to_be32(get_slice!(4)), Arc::clone(&logger)); + } }, - _ => return, } } } +pub fn router_test(data: &[u8], out: Out) { + do_test(data, out); +} + #[no_mangle] pub extern "C" fn router_run(data: *const u8, datalen: usize) { - do_test(unsafe { std::slice::from_raw_parts(data, datalen) }); + do_test(unsafe { std::slice::from_raw_parts(data, datalen) }, test_logger::DevNull {}); }