X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=fuzz%2Fsrc%2Fchanmon_consistency.rs;h=372bed6049370c065c0d7a660f61a466ec715bd4;hb=ee2f1a929ed427c5b2f963a3d13da2fec1a1cc24;hp=7ac628d4ff009b59d3c6efc2d5f4c6b4ea66c470;hpb=803d6b6e2fb8664a671c92156e6b1fb11aba0ab1;p=rust-lightning diff --git a/fuzz/src/chanmon_consistency.rs b/fuzz/src/chanmon_consistency.rs index 7ac628d4..372bed60 100644 --- a/fuzz/src/chanmon_consistency.rs +++ b/fuzz/src/chanmon_consistency.rs @@ -18,11 +18,13 @@ //! send-side handling is correct, other peers. We consider it a failure if any action results in a //! channel being force-closed. +use bitcoin::TxMerkleNode; use bitcoin::blockdata::block::BlockHeader; use bitcoin::blockdata::constants::genesis_block; use bitcoin::blockdata::transaction::{Transaction, TxOut}; use bitcoin::blockdata::script::{Builder, Script}; use bitcoin::blockdata::opcodes; +use bitcoin::blockdata::locktime::PackedLockTime; use bitcoin::network::constants::Network; use bitcoin::hashes::Hash as TraitImport; @@ -34,7 +36,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::{KeyMaterial, 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; @@ -53,8 +55,9 @@ use lightning::routing::router::{Route, RouteHop}; use utils::test_logger::{self, Output}; use utils::test_persister::TestPersister; -use bitcoin::secp256k1::key::{PublicKey,SecretKey}; -use bitcoin::secp256k1::recovery::RecoverableSignature; +use bitcoin::secp256k1::{PublicKey, SecretKey, Scalar}; +use bitcoin::secp256k1::ecdh::SharedSecret; +use bitcoin::secp256k1::ecdsa::RecoverableSignature; use bitcoin::secp256k1::Secp256k1; use std::mem; @@ -140,7 +143,7 @@ impl chain::Watch for TestChainMonitor { }; let deserialized_monitor = <(BlockHash, channelmonitor::ChannelMonitor)>:: read(&mut Cursor::new(&map_entry.get().1), &*self.keys).unwrap().1; - deserialized_monitor.update_monitor(&update, &&TestBroadcaster{}, &&FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }, &self.logger).unwrap(); + deserialized_monitor.update_monitor(&update, &&TestBroadcaster{}, &FuzzEstimator { ret_val: atomic::AtomicU32::new(253) }, &self.logger).unwrap(); let mut ser = VecWriter(Vec::new()); deserialized_monitor.write(&mut ser).unwrap(); map_entry.insert((update.update_id, ser.0)); @@ -148,7 +151,7 @@ impl chain::Watch for TestChainMonitor { self.chain_monitor.update_channel(funding_txo, update) } - fn release_pending_monitor_events(&self) -> Vec { + fn release_pending_monitor_events(&self) -> Vec<(OutPoint, Vec, Option)> { return self.chain_monitor.release_pending_monitor_events(); } } @@ -161,8 +164,16 @@ 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 { + 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 ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result { + let mut node_secret = self.get_node_secret(recipient)?; + if let Some(tweak) = tweak { + node_secret = node_secret.mul_tweak(tweak).unwrap(); + } + Ok(SharedSecret::new(other_key, &node_secret)) } fn get_inbound_payment_key_material(&self) -> KeyMaterial { @@ -188,6 +199,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(), @@ -211,7 +223,7 @@ impl KeysInterface for KeyProvider { fn read_chan_signer(&self, buffer: &[u8]) -> Result { 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 { @@ -221,7 +233,7 @@ impl KeysInterface for KeyProvider { }) } - fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5]) -> Result { + fn sign_invoice(&self, _hrp_bytes: &[u8], _invoice_data: &[u5], _recipient: Recipient) -> Result { unreachable!() } } @@ -309,7 +321,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 @@ -335,7 +347,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 @@ -355,8 +367,8 @@ pub fn do_test(data: &[u8], underlying_out: Out) { Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(&keys_manager))); let mut config = UserConfig::default(); - config.channel_options.forwarding_fee_proportional_millionths = 0; - config.channel_options.announced_channel = true; + config.channel_config.forwarding_fee_proportional_millionths = 0; + config.channel_handshake_config.announced_channel = true; let network = Network::Bitcoin; let params = ChainParameters { network, @@ -375,8 +387,8 @@ pub fn do_test(data: &[u8], underlying_out: Out) { Arc::new(TestPersister { update_ret: Mutex::new(Ok(())) }), Arc::clone(& $keys_manager))); let mut config = UserConfig::default(); - config.channel_options.forwarding_fee_proportional_millionths = 0; - config.channel_options.announced_channel = true; + config.channel_config.forwarding_fee_proportional_millionths = 0; + config.channel_handshake_config.announced_channel = true; let mut monitors = HashMap::new(); let mut old_monitors = $old_monitors.latest_monitors.lock().unwrap(); @@ -410,8 +422,8 @@ pub fn do_test(data: &[u8], underlying_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 = { @@ -437,11 +449,11 @@ pub fn do_test(data: &[u8], underlying_out: Out) { let events = $source.get_and_clear_pending_events(); assert_eq!(events.len(), 1); if let events::Event::FundingGenerationReady { ref temporary_channel_id, ref channel_value_satoshis, ref output_script, .. } = events[0] { - let tx = Transaction { version: $chan_id, lock_time: 0, input: Vec::new(), output: vec![TxOut { + let tx = Transaction { version: $chan_id, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: vec![TxOut { value: *channel_value_satoshis, script_pubkey: output_script.clone(), }]}; funding_output = OutPoint { txid: tx.txid(), index: 0 }; - $source.funding_transaction_generated(&temporary_channel_id, tx.clone()).unwrap(); + $source.funding_transaction_generated(&temporary_channel_id, &$dest.get_our_node_id(), tx.clone()).unwrap(); channel_txn.push(tx); } else { panic!("Wrong event type"); } } @@ -471,11 +483,11 @@ pub fn do_test(data: &[u8], underlying_out: Out) { macro_rules! confirm_txn { ($node: expr) => { { let chain_hash = genesis_block(Network::Bitcoin).block_hash(); - let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect(); $node.transactions_confirmed(&header, &txdata, 1); for _ in 2..100 { - header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 }; + header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: TxMerkleNode::all_zeros(), time: 42, bits: 42, nonce: 42 }; } $node.best_block_updated(&header, 99); } } @@ -489,10 +501,10 @@ pub fn do_test(data: &[u8], underlying_out: Out) { } for (idx, node_event) in node_events.iter().enumerate() { for event in node_event { - if let events::MessageSendEvent::SendFundingLocked { ref node_id, ref msg } = event { + if let events::MessageSendEvent::SendChannelReady { 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); + node.handle_channel_ready(&$nodes[idx].get_our_node_id(), msg); } } } else { panic!("Wrong event type"); } @@ -596,7 +608,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { if Some(*node_id) == expect_drop_id { panic!("peer_disconnected should drop msgs bound for the disconnected peer"); } *node_id == a_id }, - events::MessageSendEvent::SendFundingLocked { .. } => continue, + events::MessageSendEvent::SendChannelReady { .. } => continue, events::MessageSendEvent::SendAnnouncementSignatures { .. } => continue, events::MessageSendEvent::SendChannelUpdate { ref node_id, ref msg } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! @@ -724,7 +736,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { } } }, - events::MessageSendEvent::SendFundingLocked { .. } => { + events::MessageSendEvent::SendChannelReady { .. } => { // Can be generated as a reestablish response }, events::MessageSendEvent::SendAnnouncementSignatures { .. } => { @@ -770,7 +782,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { events::MessageSendEvent::UpdateHTLCs { .. } => {}, events::MessageSendEvent::SendRevokeAndACK { .. } => {}, events::MessageSendEvent::SendChannelReestablish { .. } => {}, - events::MessageSendEvent::SendFundingLocked { .. } => {}, + events::MessageSendEvent::SendChannelReady { .. } => {}, events::MessageSendEvent::SendAnnouncementSignatures { .. } => {}, events::MessageSendEvent::SendChannelUpdate { ref msg, .. } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! @@ -791,7 +803,7 @@ pub fn do_test(data: &[u8], underlying_out: Out) { events::MessageSendEvent::UpdateHTLCs { .. } => {}, events::MessageSendEvent::SendRevokeAndACK { .. } => {}, events::MessageSendEvent::SendChannelReestablish { .. } => {}, - events::MessageSendEvent::SendFundingLocked { .. } => {}, + events::MessageSendEvent::SendChannelReady { .. } => {}, events::MessageSendEvent::SendAnnouncementSignatures { .. } => {}, events::MessageSendEvent::SendChannelUpdate { ref msg, .. } => { assert_eq!(msg.contents.flags & 2, 0); // The disable bit must never be set! @@ -839,19 +851,27 @@ pub fn do_test(data: &[u8], underlying_out: Out) { events::Event::PaymentReceived { payment_hash, .. } => { if claim_set.insert(payment_hash.0) { if $fail { - assert!(nodes[$node].fail_htlc_backwards(&payment_hash)); + nodes[$node].fail_htlc_backwards(&payment_hash); } else { - assert!(nodes[$node].claim_funds(PaymentPreimage(payment_hash.0))); + nodes[$node].claim_funds(PaymentPreimage(payment_hash.0)); } } }, events::Event::PaymentSent { .. } => {}, + events::Event::PaymentClaimed { .. } => {}, events::Event::PaymentPathSuccessful { .. } => {}, events::Event::PaymentPathFailed { .. } => {}, + events::Event::ProbeSuccessful { .. } | events::Event::ProbeFailed { .. } => { + // Even though we don't explicitly send probes, because probes are + // detected based on hashing the payment hash+preimage, its rather + // trivial for the fuzzer to build payments that accidentally end up + // looking like probes. + }, events::Event::PaymentForwarded { .. } if $node == 1 => {}, events::Event::PendingHTLCsForwardable { .. } => { nodes[$node].process_pending_htlc_forwards(); }, + events::Event::HTLCHandlingFailed { .. } => {}, _ => if out.may_fail.load(atomic::Ordering::Acquire) { return; } else { @@ -920,15 +940,15 @@ pub fn do_test(data: &[u8], underlying_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; } }, @@ -1123,13 +1143,13 @@ pub fn do_test(data: &[u8], underlying_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; }