X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Ffull_stack.rs;h=a5c7bd9b2bedaa9e1351f81a12252d8f03c0247d;hb=0b8bdbf968fb4888b30e7e0f0471d66855abc1e3;hp=fbe854e01c04e6a1d0ce36019773b130a02696ec;hpb=b04d1b868fe28bea2e4c711e6e6d2470d2b98d77;p=rust-lightning diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index fbe854e0..a5c7bd9b 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -26,6 +26,7 @@ use bitcoin::network::constants::Network; use bitcoin::hashes::Hash as TraitImport; use bitcoin::hashes::HashEngine as TraitImportEngine; use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash}; use lightning::chain; @@ -33,32 +34,31 @@ use lightning::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen}; use lightning::chain::chaininterface::{BroadcasterInterface, ConfirmationTarget, FeeEstimator}; use lightning::chain::chainmonitor; use lightning::chain::transaction::OutPoint; -use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, KeysInterface}; +use lightning::chain::keysinterface::{InMemorySigner, Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider}; +use lightning::events::Event; use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::ln::channelmanager::{ChainParameters, ChannelManager, PaymentId}; +use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelManager, PaymentId, RecipientOnionFields, Retry}; use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler}; -use lightning::ln::msgs::DecodeError; +use lightning::ln::msgs::{self, DecodeError}; use lightning::ln::script::ShutdownScript; use lightning::routing::gossip::{P2PGossipSync, NetworkGraph}; -use lightning::routing::router::{find_route, PaymentParameters, RouteParameters}; -use lightning::routing::scoring::FixedPenaltyScorer; +use lightning::routing::utxo::UtxoLookup; +use lightning::routing::router::{InFlightHtlcs, PaymentParameters, Route, RouteParameters, Router}; use lightning::util::config::UserConfig; use lightning::util::errors::APIError; -use lightning::util::events::Event; use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState}; use lightning::util::logger::Logger; -use lightning::util::ser::ReadableArgs; +use lightning::util::ser::{Readable, ReadableArgs, Writeable}; use crate::utils::test_logger; use crate::utils::test_persister::TestPersister; -use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar}; +use bitcoin::secp256k1::{Message, PublicKey, SecretKey, Scalar, Secp256k1}; use bitcoin::secp256k1::ecdh::SharedSecret; -use bitcoin::secp256k1::ecdsa::RecoverableSignature; -use bitcoin::secp256k1::Secp256k1; +use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature}; use std::cell::RefCell; -use std::collections::{HashMap, hash_map}; +use hashbrown::{HashMap, hash_map}; use std::convert::TryInto; use std::cmp; use std::sync::{Arc, Mutex}; @@ -127,6 +127,20 @@ impl FeeEstimator for FuzzEstimator { } } +struct FuzzRouter {} + +impl Router for FuzzRouter { + fn find_route( + &self, _payer: &PublicKey, _params: &RouteParameters, _first_hops: Option<&[&ChannelDetails]>, + _inflight_htlcs: &InFlightHtlcs + ) -> Result { + Err(msgs::LightningError { + err: String::from("Not implemented"), + action: msgs::ErrorAction::IgnoreError + }) + } +} + struct TestBroadcaster { txn_broadcasted: Mutex>, } @@ -162,13 +176,13 @@ impl<'a> std::hash::Hash for Peer<'a> { } } -type ChannelMan = ChannelManager< +type ChannelMan<'a> = ChannelManager< Arc, Arc, Arc, Arc, Arc>>, - Arc, Arc, Arc, Arc>; -type PeerMan<'a> = PeerManager, Arc, Arc>>, Arc, Arc>>, IgnoringMessageHandler, Arc, IgnoringMessageHandler>; + Arc, Arc, Arc, Arc, Arc, &'a FuzzRouter, Arc>; +type PeerMan<'a> = PeerManager, Arc>, Arc>>, Arc, Arc>>, IgnoringMessageHandler, Arc, IgnoringMessageHandler, Arc>; struct MoneyLossDetector<'a> { - manager: Arc, + manager: Arc>, monitor: Arc, Arc, Arc, Arc, Arc>>, handler: PeerMan<'a>, @@ -182,7 +196,7 @@ struct MoneyLossDetector<'a> { } impl<'a> MoneyLossDetector<'a> { pub fn new(peers: &'a RefCell<[bool; 256]>, - manager: Arc, + manager: Arc>, monitor: Arc, Arc, Arc, Arc, Arc>>, handler: PeerMan<'a>) -> Self { MoneyLossDetector { @@ -265,17 +279,31 @@ struct KeyProvider { counter: AtomicU64, signer_state: RefCell>)>> } -impl KeysInterface for KeyProvider { - type Signer = EnforcingSigner; - fn get_node_secret(&self, _recipient: Recipient) -> Result { - Ok(self.node_secret.clone()) +impl EntropySource for KeyProvider { + 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] + } +} + +impl NodeSigner for KeyProvider { + fn get_node_id(&self, recipient: Recipient) -> Result { + let node_secret = match recipient { + Recipient::Node => Ok(&self.node_secret), + Recipient::PhantomNode => Err(()) + }?; + Ok(PublicKey::from_secret_key(&Secp256k1::signing_only(), node_secret)) } fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { - let mut node_secret = self.get_node_secret(recipient)?; + let mut node_secret = match recipient { + Recipient::Node => Ok(self.node_secret.clone()), + Recipient::PhantomNode => Err(()) + }?; if let Some(tweak) = tweak { - node_secret = node_secret.mul_tweak(tweak).unwrap(); + node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?; } Ok(SharedSecret::new(other_key, &node_secret)) } @@ -284,19 +312,19 @@ impl KeysInterface for KeyProvider { self.inbound_payment_key.clone() } - fn get_destination_script(&self) -> Script { - let secp_ctx = Secp256k1::signing_only(); - let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); - let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); - Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script() + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { + unreachable!() } - fn get_shutdown_scriptpubkey(&self) -> ShutdownScript { + fn sign_gossip_message(&self, msg: lightning::ln::msgs::UnsignedGossipMessage) -> Result { + let msg_hash = Message::from_slice(&Sha256dHash::hash(&msg.encode()[..])[..]).map_err(|_| ())?; let secp_ctx = Secp256k1::signing_only(); - let secret_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, 0, 1]).unwrap(); - let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); - ShutdownScript::new_p2wpkh(&pubkey_hash) + Ok(secp_ctx.sign_ecdsa(&msg_hash, &self.node_secret)) } +} + +impl SignerProvider for KeyProvider { + type Signer = EnforcingSigner; fn generate_channel_keys_id(&self, inbound: bool, _channel_value_satoshis: u64, _user_channel_id: u128) -> [u8; 32] { let ctr = self.counter.fetch_add(1, Ordering::Relaxed) as u8; @@ -311,7 +339,6 @@ impl KeysInterface for KeyProvider { EnforcingSigner::new_with_revoked(if inbound { InMemorySigner::new( &secp_ctx, - self.node_secret.clone(), 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, ctr]).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, 2, ctr]).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, 3, ctr]).unwrap(), @@ -320,11 +347,11 @@ impl KeysInterface for KeyProvider { [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, ctr], channel_value_satoshis, channel_keys_id, + channel_keys_id, ) } else { InMemorySigner::new( &secp_ctx, - self.node_secret.clone(), 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, ctr]).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, 8, ctr]).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, 9, ctr]).unwrap(), @@ -333,18 +360,13 @@ impl KeysInterface for KeyProvider { [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, 12, ctr], channel_value_satoshis, channel_keys_id, + channel_keys_id, ) }, state, false) } - 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, mut data: &[u8]) -> Result { - let inner: InMemorySigner = ReadableArgs::read(&mut data, self.node_secret.clone())?; + let inner: InMemorySigner = ReadableArgs::read(&mut data, self)?; let state = Arc::new(Mutex::new(EnforcementState::new())); Ok(EnforcingSigner::new_with_revoked( @@ -354,8 +376,18 @@ impl KeysInterface for KeyProvider { )) } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { - unreachable!() + fn get_destination_script(&self) -> Result { + let secp_ctx = Secp256k1::signing_only(); + let channel_monitor_claim_key = SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(); + let our_channel_monitor_claim_key_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &channel_monitor_claim_key).serialize()); + Ok(Builder::new().push_opcode(opcodes::all::OP_PUSHBYTES_0).push_slice(&our_channel_monitor_claim_key_hash[..]).into_script()) + } + + fn get_shutdown_scriptpubkey(&self) -> Result { + let secp_ctx = Secp256k1::signing_only(); + let secret_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, 0, 1]).unwrap(); + let pubkey_hash = WPubkeyHash::hash(&PublicKey::from_secret_key(&secp_ctx, &secret_key).serialize()); + Ok(ShutdownScript::new_p2wpkh(&pubkey_hash)) } } @@ -368,6 +400,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { let fee_est = Arc::new(FuzzEstimator { input: input.clone(), }); + let router = FuzzRouter {}; macro_rules! get_slice { ($len: expr) => { @@ -410,24 +443,22 @@ pub fn do_test(data: &[u8], logger: &Arc) { let network = Network::Bitcoin; let params = ChainParameters { network, - best_block: BestBlock::from_genesis(network), + best_block: BestBlock::from_network(network), }; - let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, params)); - // Adding new calls to `KeysInterface::get_secure_random_bytes` during startup can change all the + let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), &router, Arc::clone(&logger), keys_manager.clone(), keys_manager.clone(), keys_manager.clone(), config, params)); + // Adding new calls to `EntropySource::get_secure_random_bytes` during startup can change all the // keys subsequently generated in this test. Rather than regenerating all the messages manually, // it's easier to just increment the counter here so the keys don't change. keys_manager.counter.fetch_sub(3, Ordering::AcqRel); - let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret(Recipient::Node).unwrap()); - let network_graph = Arc::new(NetworkGraph::new(genesis_block(network).block_hash(), Arc::clone(&logger))); + let network_graph = Arc::new(NetworkGraph::new(network, Arc::clone(&logger))); let gossip_sync = Arc::new(P2PGossipSync::new(Arc::clone(&network_graph), None, Arc::clone(&logger))); - let scorer = FixedPenaltyScorer::with_penalty(0); let peers = RefCell::new([false; 256]); let mut loss_detector = MoneyLossDetector::new(&peers, channelmanager.clone(), monitor.clone(), PeerManager::new(MessageHandler { chan_handler: channelmanager.clone(), route_handler: gossip_sync.clone(), onion_message_handler: IgnoringMessageHandler {}, - }, our_network_key, 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, 0, 15, 0], Arc::clone(&logger), IgnoringMessageHandler{})); + }, 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, 0, 15, 0], Arc::clone(&logger), IgnoringMessageHandler{}, keys_manager.clone())); let mut should_forward = false; let mut payments_received: Vec = Vec::new(); @@ -477,16 +508,10 @@ pub fn do_test(data: &[u8], logger: &Arc) { }, 4 => { let final_value_msat = slice_to_be24(get_slice!(3)) as u64; - let payment_params = PaymentParameters::from_node_id(get_pubkey!()); + let payment_params = PaymentParameters::from_node_id(get_pubkey!(), 42); let params = RouteParameters { payment_params, final_value_msat, - final_cltv_expiry_delta: 42, - }; - let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes(); - let route = match find_route(&our_id, ¶ms, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) { - Ok(route) => route, - Err(_) => return, }; let mut payment_hash = PaymentHash([0; 32]); payment_hash.0[0..8].copy_from_slice(&be64_to_array(payments_sent)); @@ -494,25 +519,21 @@ pub fn do_test(data: &[u8], logger: &Arc) { sha.input(&payment_hash.0[..]); payment_hash.0 = Sha256::from_engine(sha).into_inner(); payments_sent += 1; - match channelmanager.send_payment(&route, payment_hash, &None, PaymentId(payment_hash.0)) { + match channelmanager.send_payment(payment_hash, + RecipientOnionFields::spontaneous_empty(), PaymentId(payment_hash.0), params, + Retry::Attempts(0)) + { Ok(_) => {}, Err(_) => return, } }, 15 => { let final_value_msat = slice_to_be24(get_slice!(3)) as u64; - let payment_params = PaymentParameters::from_node_id(get_pubkey!()); + let payment_params = PaymentParameters::from_node_id(get_pubkey!(), 42); let params = RouteParameters { payment_params, final_value_msat, - final_cltv_expiry_delta: 42, - }; - let random_seed_bytes: [u8; 32] = keys_manager.get_secure_random_bytes(); - let mut route = match find_route(&our_id, ¶ms, &network_graph, None, Arc::clone(&logger), &scorer, &random_seed_bytes) { - Ok(route) => route, - Err(_) => return, }; - route.paths.push(route.paths[0].clone()); let mut payment_hash = PaymentHash([0; 32]); payment_hash.0[0..8].copy_from_slice(&be64_to_array(payments_sent)); let mut sha = Sha256::engine(); @@ -522,7 +543,10 @@ pub fn do_test(data: &[u8], logger: &Arc) { let mut payment_secret = PaymentSecret([0; 32]); payment_secret.0[0..8].copy_from_slice(&be64_to_array(payments_sent)); payments_sent += 1; - match channelmanager.send_payment(&route, payment_hash, &Some(payment_secret), PaymentId(payment_hash.0)) { + match channelmanager.send_payment(payment_hash, + RecipientOnionFields::secret_only(payment_secret), PaymentId(payment_hash.0), + params, Retry::Attempts(0)) + { Ok(_) => {}, Err(_) => return, } @@ -570,7 +594,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { let payment_hash = PaymentHash(Sha256::from_engine(sha).into_inner()); // Note that this may fail - our hashes may collide and we'll end up trying to // double-register the same payment_hash. - let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1); + let _ = channelmanager.create_inbound_payment_for_hash(payment_hash, None, 1, None); }, 9 => { for payment in payments_received.drain(..) { @@ -602,9 +626,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { if let Err(e) = channelmanager.funding_transaction_generated(&funding_generation.0, &funding_generation.1, tx.clone()) { // It's possible the channel has been closed in the mean time, but any other // failure may be a bug. - if let APIError::ChannelUnavailable { err } = e { - assert_eq!(err, "No such channel"); - } else { panic!(); } + if let APIError::ChannelUnavailable { .. } = e { } else { panic!(); } } pending_funding_signatures.insert(funding_output, tx); } @@ -659,7 +681,7 @@ pub fn do_test(data: &[u8], logger: &Arc) { Event::FundingGenerationReady { temporary_channel_id, counterparty_node_id, channel_value_satoshis, output_script, .. } => { pending_funding_generation.push((temporary_channel_id, counterparty_node_id, channel_value_satoshis, output_script)); }, - Event::PaymentReceived { payment_hash, .. } => { + Event::PaymentClaimable { payment_hash, .. } => { //TODO: enhance by fetching random amounts from fuzz input? payments_received.push(payment_hash); }, @@ -833,7 +855,7 @@ mod tests { // 0085 3d00000000000000000000000000000000000000000000000000000000000000 0900000000000000000000000000000000000000000000000000000000000000 020b00000000000000000000000000000000000000000000000000000000000000 03000000000000000000000000000000 - revoke_and_ack and mac // // 07 - process the now-pending HTLC forward - // - client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: SendHTLCs event for node 03020000 with 1 HTLCs for channel 3f000000) + // - client now sends id 1 update_add_htlc and commitment_signed (CHECK 7: UpdateHTLCs event for node 03020000 with 1 HTLCs for channel 3f000000) // // - we respond with commitment_signed then revoke_and_ack (a weird, but valid, order) // 030112 - inbound read from peer id 1 of len 18