]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Merge pull request #470 from ariard/2020-01-contributing-draft
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Wed, 12 Feb 2020 19:31:26 +0000 (19:31 +0000)
committerGitHub <noreply@github.com>
Wed, 12 Feb 2020 19:31:26 +0000 (19:31 +0000)
First draft, don't-cover-everything-but-yet-a-good-start-CONTRIBUTING.md

19 files changed:
README.md
fuzz/src/msg_targets/gen_target.sh
fuzz/src/msg_targets/mod.rs
fuzz/src/msg_targets/msg_onion_hop_data.rs
fuzz/src/msg_targets/utils.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/channelmonitor.rs
lightning/src/ln/features.rs
lightning/src/ln/functional_test_utils.rs
lightning/src/ln/functional_tests.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_utils.rs
lightning/src/ln/peer_handler.rs
lightning/src/ln/router.rs
lightning/src/util/chacha20.rs
lightning/src/util/ser.rs
lightning/src/util/ser_macros.rs
lightning/src/util/test_utils.rs

index 943766940b3d7a328a14b0d0bd913ab1e8f43c40..f6fba666c337d39d0c0e768e93e1d0fbd7a8453b 100644 (file)
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ implementation has pretty good test coverage that is expected to continue to
 improve. There are a number of internal refactorings being done now that will
 make the code base more welcoming to new contributors. It is also anticipated
 that as developers begin using the API, the lessons from that will result in
-changes to the API, so any developer using LDK at this stage should be prepared
+changes to the API, so any developer using this API at this stage should be prepared
 to embrace that. The current state is sufficient for a developer or project to
 experiment with it. Recent increased contribution rate to the project is expected
 to lead to a high quality, stable, production-worthy implementation in 2020.
index 2f6826ac5381767416a1e47c0dcdb6426e2d92af..0121e4eb821990ef5c104d95f15fe1f13ae212a8 100755 (executable)
@@ -34,8 +34,8 @@ GEN_TEST NodeAnnouncement test_msg_exact ""
 
 GEN_TEST UpdateAddHTLC test_msg_hole ", 85, 33"
 GEN_TEST ErrorMessage test_msg_hole ", 32, 2"
-GEN_TEST OnionHopData test_msg_hole ", 1+8+8+4, 12"
 
 GEN_TEST Init test_msg_simple ""
+GEN_TEST OnionHopData test_msg_simple ""
 GEN_TEST Ping test_msg_simple ""
 GEN_TEST Pong test_msg_simple ""
index ef3c489f041768721328499c1f120ddc7db07f2d..69fc4e74219b8cf20e81e5cb49937918c596ccf5 100644 (file)
@@ -20,7 +20,7 @@ pub mod msg_channel_update;
 pub mod msg_node_announcement;
 pub mod msg_update_add_htlc;
 pub mod msg_error_message;
-pub mod msg_onion_hop_data;
 pub mod msg_init;
+pub mod msg_onion_hop_data;
 pub mod msg_ping;
 pub mod msg_pong;
index e446a063bd9df18bc52c268b57e15c138a6ac6f9..9d7ad602582fafa2a36d5cee16adefabd6d28195 100644 (file)
@@ -7,7 +7,7 @@ use msg_targets::utils::VecWriter;
 
 #[inline]
 pub fn do_test(data: &[u8]) {
-       test_msg_hole!(msgs::OnionHopData, data, 1+8+8+4, 12);
+       test_msg_simple!(msgs::OnionHopData, data);
 }
 
 #[no_mangle]
index a5257ba0f80c1fea24f399018103da37f572c763..2a7731ccd136d2185414b4b73f7510a7bebe8397 100644 (file)
@@ -13,6 +13,15 @@ impl Writer for VecWriter {
        }
 }
 
+// We attempt to test the strictest behavior we can for a given message, however, some messages
+// have different expected behavior. You can see which messages have which behavior in
+// gen_target.sh, but, in general, the *_announcement messages have to round-trip exactly (as
+// otherwise we'd invalidate the signatures), most messages just need to round-trip up to the
+// amount of data we know how to interpret, and some messages we may throw out invalid stuff (eg
+// if an error message isn't valid UTF-8 we cant String-ize it), so they wont roundtrip correctly.
+
+// Tests a message that must survive roundtrip exactly, though may not empty the read buffer
+// entirely
 #[macro_export]
 macro_rules! test_msg {
        ($MsgType: path, $data: ident) => {
@@ -31,6 +40,8 @@ macro_rules! test_msg {
        }
 }
 
+// Tests a message that may lose data on roundtrip, but shoulnd't lose data compared to our
+// re-serialization.
 #[macro_export]
 macro_rules! test_msg_simple {
        ($MsgType: path, $data: ident) => {
@@ -40,11 +51,18 @@ macro_rules! test_msg_simple {
                        if let Ok(msg) = <$MsgType as Readable<::std::io::Cursor<&[u8]>>>::read(&mut r) {
                                let mut w = VecWriter(Vec::new());
                                msg.write(&mut w).unwrap();
+
+                               let msg = <$MsgType as Readable<::std::io::Cursor<&[u8]>>>::read(&mut ::std::io::Cursor::new(&w.0)).unwrap();
+                               let mut w_two = VecWriter(Vec::new());
+                               msg.write(&mut w_two).unwrap();
+                               assert_eq!(&w.0[..], &w_two.0[..]);
                        }
                }
        }
 }
 
+// Tests a message that must survive roundtrip exactly, and must exactly empty the read buffer and
+// split it back out on re-serialization.
 #[macro_export]
 macro_rules! test_msg_exact {
        ($MsgType: path, $data: ident) => {
@@ -54,13 +72,14 @@ macro_rules! test_msg_exact {
                        if let Ok(msg) = <$MsgType as Readable<::std::io::Cursor<&[u8]>>>::read(&mut r) {
                                let mut w = VecWriter(Vec::new());
                                msg.write(&mut w).unwrap();
-
                                assert_eq!(&r.into_inner()[..], &w.0[..]);
                        }
                }
        }
 }
 
+// Tests a message that must survive roundtrip exactly, modulo one "hole" which may be set to 0s on
+// re-serialization.
 #[macro_export]
 macro_rules! test_msg_hole {
        ($MsgType: path, $data: ident, $hole: expr, $hole_len: expr) => {
index c86136d6070a8f2c7909f8f3b39c743689ecd1f9..58ade789fbb16c16039b7c1cd200d224093aa180 100644 (file)
@@ -240,7 +240,10 @@ pub(super) struct Channel<ChanSigner: ChannelKeys> {
        secp_ctx: Secp256k1<secp256k1::All>,
        channel_value_satoshis: u64,
 
+       #[cfg(not(test))]
        local_keys: ChanSigner,
+       #[cfg(test)]
+       pub(super) local_keys: ChanSigner,
        shutdown_pubkey: PublicKey,
 
        // Our commitment numbers start at 2^48-1 and count down, whereas the ones used in transaction
@@ -1995,6 +1998,17 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                self.channel_monitor.provide_secret(self.cur_remote_commitment_transaction_number + 1, msg.per_commitment_secret)
                        .map_err(|e| ChannelError::Close(e.0))?;
 
+               if self.channel_state & ChannelState::AwaitingRemoteRevoke as u32 == 0 {
+                       // Our counterparty seems to have burned their coins to us (by revoking a state when we
+                       // haven't given them a new commitment transaction to broadcast). We should probably
+                       // take advantage of this by updating our channel monitor, sending them an error, and
+                       // waiting for them to broadcast their latest (now-revoked claim). But, that would be a
+                       // lot of work, and there's some chance this is all a misunderstanding anyway.
+                       // We have to do *something*, though, since our signer may get mad at us for otherwise
+                       // jumping a remote commitment number, so best to just force-close and move on.
+                       return Err(ChannelError::Close("Received an unexpected revoke_and_ack"));
+               }
+
                // Update state now that we've passed all the can-fail calls...
                // (note that we may still fail to generate the new commitment_signed message, but that's
                // OK, we step the channel here and *then* if the new generation fails we can fail the
@@ -2973,49 +2987,8 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
        pub fn block_connected(&mut self, header: &BlockHeader, height: u32, txn_matched: &[&Transaction], indexes_of_txn_matched: &[u32]) -> Result<Option<msgs::FundingLocked>, msgs::ErrorMessage> {
                let non_shutdown_state = self.channel_state & (!MULTI_STATE_FLAGS);
                if header.bitcoin_hash() != self.last_block_connected {
-                       self.last_block_connected = header.bitcoin_hash();
-                       self.channel_monitor.last_block_hash = self.last_block_connected;
                        if self.funding_tx_confirmations > 0 {
                                self.funding_tx_confirmations += 1;
-                               if self.funding_tx_confirmations == self.minimum_depth as u64 {
-                                       let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
-                                               self.channel_state |= ChannelState::OurFundingLocked as u32;
-                                               true
-                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
-                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
-                                               self.channel_update_count += 1;
-                                               true
-                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
-                                               // We got a reorg but not enough to trigger a force close, just update
-                                               // funding_tx_confirmed_in and return.
-                                               false
-                                       } else if self.channel_state < ChannelState::ChannelFunded as u32 {
-                                               panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
-                                       } else {
-                                               // We got a reorg but not enough to trigger a force close, just update
-                                               // funding_tx_confirmed_in and return.
-                                               false
-                                       };
-                                       self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
-
-                                       //TODO: Note that this must be a duplicate of the previous commitment point they sent us,
-                                       //as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
-                                       //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be
-                                       //a protocol oversight, but I assume I'm just missing something.
-                                       if need_commitment_update {
-                                               if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
-                                                       let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
-                                                       let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
-                                                       return Ok(Some(msgs::FundingLocked {
-                                                               channel_id: self.channel_id,
-                                                               next_per_commitment_point: next_per_commitment_point,
-                                                       }));
-                                               } else {
-                                                       self.monitor_pending_funding_locked = true;
-                                                       return Ok(None);
-                                               }
-                                       }
-                               }
                        }
                }
                if non_shutdown_state & !(ChannelState::TheirFundingLocked as u32) == ChannelState::FundingSent as u32 {
@@ -3058,6 +3031,51 @@ impl<ChanSigner: ChannelKeys> Channel<ChanSigner> {
                                }
                        }
                }
+               if header.bitcoin_hash() != self.last_block_connected {
+                       self.last_block_connected = header.bitcoin_hash();
+                       self.channel_monitor.last_block_hash = self.last_block_connected;
+                       if self.funding_tx_confirmations > 0 {
+                               if self.funding_tx_confirmations == self.minimum_depth as u64 {
+                                       let need_commitment_update = if non_shutdown_state == ChannelState::FundingSent as u32 {
+                                               self.channel_state |= ChannelState::OurFundingLocked as u32;
+                                               true
+                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::TheirFundingLocked as u32) {
+                                               self.channel_state = ChannelState::ChannelFunded as u32 | (self.channel_state & MULTI_STATE_FLAGS);
+                                               self.channel_update_count += 1;
+                                               true
+                                       } else if non_shutdown_state == (ChannelState::FundingSent as u32 | ChannelState::OurFundingLocked as u32) {
+                                               // We got a reorg but not enough to trigger a force close, just update
+                                               // funding_tx_confirmed_in and return.
+                                               false
+                                       } else if self.channel_state < ChannelState::ChannelFunded as u32 {
+                                               panic!("Started confirming a channel in a state pre-FundingSent?: {}", self.channel_state);
+                                       } else {
+                                               // We got a reorg but not enough to trigger a force close, just update
+                                               // funding_tx_confirmed_in and return.
+                                               false
+                                       };
+                                       self.funding_tx_confirmed_in = Some(header.bitcoin_hash());
+
+                                       //TODO: Note that this must be a duplicate of the previous commitment point they sent us,
+                                       //as otherwise we will have a commitment transaction that they can't revoke (well, kinda,
+                                       //they can by sending two revoke_and_acks back-to-back, but not really). This appears to be
+                                       //a protocol oversight, but I assume I'm just missing something.
+                                       if need_commitment_update {
+                                               if self.channel_state & (ChannelState::MonitorUpdateFailed as u32) == 0 {
+                                                       let next_per_commitment_secret = self.build_local_commitment_secret(self.cur_local_commitment_transaction_number);
+                                                       let next_per_commitment_point = PublicKey::from_secret_key(&self.secp_ctx, &next_per_commitment_secret);
+                                                       return Ok(Some(msgs::FundingLocked {
+                                                               channel_id: self.channel_id,
+                                                               next_per_commitment_point: next_per_commitment_point,
+                                                       }));
+                                               } else {
+                                                       self.monitor_pending_funding_locked = true;
+                                                       return Ok(None);
+                                               }
+                                       }
+                               }
+                       }
+               }
                Ok(None)
        }
 
index 3c1c0b240ae6d666bae64b4c1ebc82cba1f4396e..e5f8acc2a8d6f48a6fe2bcca3cc95d525f4271c1 100644 (file)
@@ -38,21 +38,19 @@ use chain::keysinterface::{ChannelKeys, KeysInterface, InMemoryChannelKeys};
 use util::config::UserConfig;
 use util::{byte_utils, events};
 use util::ser::{Readable, ReadableArgs, Writeable, Writer};
-use util::chacha20::ChaCha20;
+use util::chacha20::{ChaCha20, ChaChaReader};
 use util::logger::Logger;
 use util::errors::APIError;
 
 use std::{cmp, mem};
 use std::collections::{HashMap, hash_map, HashSet};
-use std::io::Cursor;
+use std::io::{Cursor, Read};
 use std::sync::{Arc, Mutex, MutexGuard, RwLock};
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::time::Duration;
 use std::marker::{Sync, Send};
 use std::ops::Deref;
 
-const SIXTY_FIVE_ZEROS: [u8; 65] = [0; 65];
-
 // We hold various information about HTLC relay in the HTLC objects in Channel itself:
 //
 // Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
@@ -906,22 +904,30 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                }
 
                let mut chacha = ChaCha20::new(&rho, &[0u8; 8]);
-               let next_hop_data = {
-                       let mut decoded = [0; 65];
-                       chacha.process(&msg.onion_routing_packet.hop_data[0..65], &mut decoded);
-                       match msgs::OnionHopData::read(&mut Cursor::new(&decoded[..])) {
+               let mut chacha_stream = ChaChaReader { chacha: &mut chacha, read: Cursor::new(&msg.onion_routing_packet.hop_data[..]) };
+               let (next_hop_data, next_hop_hmac) = {
+                       match msgs::OnionHopData::read(&mut chacha_stream) {
                                Err(err) => {
                                        let error_code = match err {
                                                msgs::DecodeError::UnknownVersion => 0x4000 | 1, // unknown realm byte
+                                               msgs::DecodeError::UnknownRequiredFeature|
+                                               msgs::DecodeError::InvalidValue|
+                                               msgs::DecodeError::ShortRead => 0x4000 | 22, // invalid_onion_payload
                                                _ => 0x2000 | 2, // Should never happen
                                        };
                                        return_err!("Unable to decode our hop data", error_code, &[0;0]);
                                },
-                               Ok(msg) => msg
+                               Ok(msg) => {
+                                       let mut hmac = [0; 32];
+                                       if let Err(_) = chacha_stream.read_exact(&mut hmac[..]) {
+                                               return_err!("Unable to decode hop data", 0x4000 | 22, &[0;0]);
+                                       }
+                                       (msg, hmac)
+                               },
                        }
                };
 
-               let pending_forward_info = if next_hop_data.hmac == [0; 32] {
+               let pending_forward_info = if next_hop_hmac == [0; 32] {
                                #[cfg(test)]
                                {
                                        // In tests, make sure that the initial onion pcket data is, at least, non-0.
@@ -931,10 +937,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                        // as-is (and were originally 0s).
                                        // Of course reverse path calculation is still pretty easy given naive routing
                                        // algorithms, but this fixes the most-obvious case.
-                                       let mut new_packet_data = [0; 19*65];
-                                       chacha.process(&msg.onion_routing_packet.hop_data[65..], &mut new_packet_data[0..19*65]);
-                                       assert_ne!(new_packet_data[0..65], [0; 65][..]);
-                                       assert_ne!(new_packet_data[..], [0; 19*65][..]);
+                                       let mut next_bytes = [0; 32];
+                                       chacha_stream.read_exact(&mut next_bytes).unwrap();
+                                       assert_ne!(next_bytes[..], [0; 32][..]);
+                                       chacha_stream.read_exact(&mut next_bytes).unwrap();
+                                       assert_ne!(next_bytes[..], [0; 32][..]);
                                }
 
                                // OUR PAYMENT!
@@ -943,11 +950,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                        return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]);
                                }
                                // final_incorrect_htlc_amount
-                               if next_hop_data.data.amt_to_forward > msg.amount_msat {
+                               if next_hop_data.amt_to_forward > msg.amount_msat {
                                        return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat));
                                }
                                // final_incorrect_cltv_expiry
-                               if next_hop_data.data.outgoing_cltv_value != msg.cltv_expiry {
+                               if next_hop_data.outgoing_cltv_value != msg.cltv_expiry {
                                        return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry));
                                }
 
@@ -961,13 +968,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                        payment_hash: msg.payment_hash.clone(),
                                        short_channel_id: 0,
                                        incoming_shared_secret: shared_secret,
-                                       amt_to_forward: next_hop_data.data.amt_to_forward,
-                                       outgoing_cltv_value: next_hop_data.data.outgoing_cltv_value,
+                                       amt_to_forward: next_hop_data.amt_to_forward,
+                                       outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
                                })
                        } else {
                                let mut new_packet_data = [0; 20*65];
-                               chacha.process(&msg.onion_routing_packet.hop_data[65..], &mut new_packet_data[0..19*65]);
-                               chacha.process(&SIXTY_FIVE_ZEROS[..], &mut new_packet_data[19*65..]);
+                               let read_pos = chacha_stream.read(&mut new_packet_data).unwrap();
+                               #[cfg(debug_assertions)]
+                               {
+                                       // Check two things:
+                                       // a) that the behavior of our stream here will return Ok(0) even if the TLV
+                                       //    read above emptied out our buffer and the unwrap() wont needlessly panic
+                                       // b) that we didn't somehow magically end up with extra data.
+                                       let mut t = [0; 1];
+                                       debug_assert!(chacha_stream.read(&mut t).unwrap() == 0);
+                               }
+                               // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we
+                               // fill the onion hop data we'll forward to our next-hop peer.
+                               chacha_stream.chacha.process_in_place(&mut new_packet_data[read_pos..]);
 
                                let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap();
 
@@ -986,16 +1004,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                        version: 0,
                                        public_key,
                                        hop_data: new_packet_data,
-                                       hmac: next_hop_data.hmac.clone(),
+                                       hmac: next_hop_hmac.clone(),
+                               };
+
+                               let short_channel_id = match next_hop_data.format {
+                                       msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id,
+                                       msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id,
+                                       msgs::OnionHopDataFormat::FinalNode => {
+                                               return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]);
+                                       },
                                };
 
                                PendingHTLCStatus::Forward(PendingForwardHTLCInfo {
                                        onion_packet: Some(outgoing_packet),
                                        payment_hash: msg.payment_hash.clone(),
-                                       short_channel_id: next_hop_data.data.short_channel_id,
+                                       short_channel_id: short_channel_id,
                                        incoming_shared_secret: shared_secret,
-                                       amt_to_forward: next_hop_data.data.amt_to_forward,
-                                       outgoing_cltv_value: next_hop_data.data.outgoing_cltv_value,
+                                       amt_to_forward: next_hop_data.amt_to_forward,
+                                       outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
                                })
                        };
 
@@ -1137,6 +1163,9 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route, &session_priv),
                                APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
                let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height)?;
+               if onion_utils::route_size_insane(&onion_payloads) {
+                       return Err(APIError::RouteError{err: "Route size too large considering onion data"});
+               }
                let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
 
                let _ = self.total_consistency_lock.read().unwrap();
@@ -1268,7 +1297,10 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
        }
 
        fn get_announcement_sigs(&self, chan: &Channel<ChanSigner>) -> Option<msgs::AnnouncementSignatures> {
-               if !chan.should_announce() { return None }
+               if !chan.should_announce() {
+                       log_trace!(self, "Can't send announcement_signatures for private channel {}", log_bytes!(chan.channel_id()));
+                       return None
+               }
 
                let (announcement, our_bitcoin_sig) = match chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) {
                        Ok(res) => res,
@@ -1984,6 +2016,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                }
                                try_chan_entry!(self, chan.get_mut().funding_locked(&msg), channel_state, chan);
                                if let Some(announcement_sigs) = self.get_announcement_sigs(chan.get()) {
+                                       log_trace!(self, "Sending announcement_signatures for {} in response to funding_locked", log_bytes!(chan.get().channel_id()));
                                        // If we see locking block before receiving remote funding_locked, we broadcast our
                                        // announcement_sigs at remote funding_locked reception. If we receive remote
                                        // funding_locked before seeing locking block, we broadcast our announcement_sigs at locking
@@ -2578,10 +2611,13 @@ impl<ChanSigner: ChannelKeys, M: Deref + Sync + Send> ChainListener for ChannelM
                                                msg: funding_locked,
                                        });
                                        if let Some(announcement_sigs) = self.get_announcement_sigs(channel) {
+                                               log_trace!(self, "Sending funding_locked and announcement_signatures for {}", log_bytes!(channel.channel_id()));
                                                pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
                                                        node_id: channel.get_their_node_id(),
                                                        msg: announcement_sigs,
                                                });
+                                       } else {
+                                               log_trace!(self, "Sending funding_locked WITHOUT announcement_signatures for {}", log_bytes!(channel.channel_id()));
                                        }
                                        short_to_id.insert(channel.get_short_channel_id().unwrap(), channel.channel_id());
                                } else if let Err(e) = chan_res {
index 51446ccc57162d80fb1a1f56472959ddaa97d803..a1577712fdd8e2196529535fa912c3432c46aebd 100644 (file)
@@ -1799,11 +1799,11 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                        let mut inputs_info = Vec::new();
 
                                        macro_rules! sign_input {
-                                               ($sighash_parts: expr, $input: expr, $amount: expr, $preimage: expr) => {
+                                               ($sighash_parts: expr, $input: expr, $amount: expr, $preimage: expr, $idx: expr) => {
                                                        {
                                                                let (sig, redeemscript, htlc_key) = match self.key_storage {
                                                                        Storage::Local { ref htlc_base_key, .. } => {
-                                                                               let htlc = &per_commitment_option.unwrap()[$input.sequence as usize].0;
+                                                                               let htlc = &per_commitment_option.unwrap()[$idx as usize].0;
                                                                                let redeemscript = chan_utils::get_htlc_redeemscript_with_explicit_keys(htlc, &a_htlc_key, &b_htlc_key, &revocation_pubkey);
                                                                                let sighash = hash_to_message!(&$sighash_parts.sighash_all(&$input, &redeemscript, $amount)[..]);
                                                                                let htlc_key = ignore_error!(chan_utils::derive_private_key(&self.secp_ctx, revocation_point, &htlc_base_key));
@@ -1838,13 +1838,13 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                                        vout: transaction_output_index,
                                                                                },
                                                                                script_sig: Script::new(),
-                                                                               sequence: idx as u32, // reset to 0xfffffffd in sign_input
+                                                                               sequence: 0xff_ff_ff_fd,
                                                                                witness: Vec::new(),
                                                                        };
                                                                        if htlc.cltv_expiry > height + CLTV_SHARED_CLAIM_BUFFER {
                                                                                inputs.push(input);
                                                                                inputs_desc.push(if htlc.offered { InputDescriptors::OfferedHTLC } else { InputDescriptors::ReceivedHTLC });
-                                                                               inputs_info.push((payment_preimage, tx.output[transaction_output_index as usize].value, htlc.cltv_expiry));
+                                                                               inputs_info.push((payment_preimage, tx.output[transaction_output_index as usize].value, htlc.cltv_expiry, idx));
                                                                                total_value += tx.output[transaction_output_index as usize].value;
                                                                        } else {
                                                                                let mut single_htlc_tx = Transaction {
@@ -1861,7 +1861,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                                let mut used_feerate;
                                                                                if subtract_high_prio_fee!(self, fee_estimator, single_htlc_tx.output[0].value, predicted_weight, used_feerate) {
                                                                                        let sighash_parts = bip143::SighashComponents::new(&single_htlc_tx);
-                                                                                       let (redeemscript, htlc_key) = sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec());
+                                                                                       let (redeemscript, htlc_key) = sign_input!(sighash_parts, single_htlc_tx.input[0], htlc.amount_msat / 1000, payment_preimage.0.to_vec(), idx);
                                                                                        assert!(predicted_weight >= single_htlc_tx.get_weight());
                                                                                        spendable_outputs.push(SpendableOutputDescriptor::StaticOutput {
                                                                                                outpoint: BitcoinOutPoint { txid: single_htlc_tx.txid(), vout: 0 },
@@ -1892,7 +1892,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                                vout: transaction_output_index,
                                                                        },
                                                                        script_sig: Script::new(),
-                                                                       sequence: idx as u32,
+                                                                       sequence: 0xff_ff_ff_fd,
                                                                        witness: Vec::new(),
                                                                };
                                                                let mut timeout_tx = Transaction {
@@ -1909,7 +1909,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                                                let mut used_feerate;
                                                                if subtract_high_prio_fee!(self, fee_estimator, timeout_tx.output[0].value, predicted_weight, used_feerate) {
                                                                        let sighash_parts = bip143::SighashComponents::new(&timeout_tx);
-                                                                       let (redeemscript, htlc_key) = sign_input!(sighash_parts, timeout_tx.input[0], htlc.amount_msat / 1000, vec![0]);
+                                                                       let (redeemscript, htlc_key) = sign_input!(sighash_parts, timeout_tx.input[0], htlc.amount_msat / 1000, vec![0], idx);
                                                                        assert!(predicted_weight >= timeout_tx.get_weight());
                                                                        //TODO: track SpendableOutputDescriptor
                                                                        log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", timeout_tx.input[0].previous_output.txid, timeout_tx.input[0].previous_output.vout, height_timer);
@@ -1961,7 +1961,7 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                                        let height_timer = Self::get_height_timer(height, soonest_timelock);
                                        let spend_txid = spend_tx.txid();
                                        for (input, info) in spend_tx.input.iter_mut().zip(inputs_info.iter()) {
-                                               let (redeemscript, htlc_key) = sign_input!(sighash_parts, input, info.1, (info.0).0.to_vec());
+                                               let (redeemscript, htlc_key) = sign_input!(sighash_parts, input, info.1, (info.0).0.to_vec(), info.3);
                                                log_trace!(self, "Outpoint {}:{} is being being claimed, if it doesn't succeed, a bumped claiming txn is going to be broadcast at height {}", input.previous_output.txid, input.previous_output.vout, height_timer);
                                                per_input_material.insert(input.previous_output, InputMaterial::RemoteHTLC { script: redeemscript, key: htlc_key, preimage: Some(*(info.0)), amount: info.1, locktime: 0});
                                                match self.claimable_outpoints.entry(input.previous_output) {
@@ -2908,7 +2908,6 @@ impl<ChanSigner: ChannelKeys> ChannelMonitor<ChanSigner> {
                for per_outp_material in cached_claim_datas.per_input_material.values() {
                        match per_outp_material {
                                &InputMaterial::Revoked { ref script, ref is_htlc, ref amount, .. } => {
-                                       log_trace!(self, "Is HLTC ? {}", is_htlc);
                                        inputs_witnesses_weight += Self::get_witnesses_weight(if !is_htlc { &[InputDescriptors::RevokedOutput] } else if HTLCType::scriptlen_to_htlctype(script.len()) == Some(HTLCType::OfferedHTLC) { &[InputDescriptors::RevokedOfferedHTLC] } else if HTLCType::scriptlen_to_htlctype(script.len()) == Some(HTLCType::AcceptedHTLC) { &[InputDescriptors::RevokedReceivedHTLC] } else { unreachable!() });
                                        amt += *amount;
                                },
index eee534f71087215ff1f00e71be32e314ab44d623..dd0b7fa1a82aba540a259bd18ede2b5156c9eef1 100644 (file)
@@ -29,6 +29,10 @@ mod sealed { // You should just use the type aliases instead.
        pub trait UpfrontShutdownScript: Context {}
        impl UpfrontShutdownScript for InitContext {}
        impl UpfrontShutdownScript for NodeContext {}
+
+       pub trait VariableLengthOnion: Context {}
+       impl VariableLengthOnion for InitContext {}
+       impl VariableLengthOnion for NodeContext {}
 }
 
 /// Tracks the set of features which a node implements, templated by the context in which it
@@ -69,7 +73,7 @@ impl InitFeatures {
        /// Create a Features with the features we support
        pub fn supported() -> InitFeatures {
                InitFeatures {
-                       flags: vec![2 | 1 << 5],
+                       flags: vec![2 | 1 << 5, 1 << (9-8)],
                        mark: PhantomData,
                }
        }
@@ -132,14 +136,14 @@ impl NodeFeatures {
        #[cfg(not(feature = "fuzztarget"))]
        pub(crate) fn supported() -> NodeFeatures {
                NodeFeatures {
-                       flags: vec![2 | 1 << 5],
+                       flags: vec![2 | 1 << 5, 1 << (9-8)],
                        mark: PhantomData,
                }
        }
        #[cfg(feature = "fuzztarget")]
        pub fn supported() -> NodeFeatures {
                NodeFeatures {
-                       flags: vec![2 | 1 << 5],
+                       flags: vec![2 | 1 << 5, 1 << (9-8)],
                        mark: PhantomData,
                }
        }
@@ -182,13 +186,21 @@ impl<T: sealed::Context> Features<T> {
 
        pub(crate) fn requires_unknown_bits(&self) -> bool {
                self.flags.iter().enumerate().any(|(idx, &byte)| {
-                       ( idx != 0 && (byte & 0x55) != 0 ) || ( idx == 0 && (byte & 0x14) != 0 )
+                       (match idx {
+                               0 => (byte & 0b00010100),
+                               1 => (byte & 0b01010100),
+                               _ => (byte & 0b01010101),
+                       }) != 0
                })
        }
 
        pub(crate) fn supports_unknown_bits(&self) -> bool {
                self.flags.iter().enumerate().any(|(idx, &byte)| {
-                       ( idx != 0 && byte != 0 ) || ( idx == 0 && (byte & 0xc4) != 0 )
+                       (match idx {
+                               0 => (byte & 0b11000100),
+                               1 => (byte & 0b11111100),
+                               _ => byte,
+                       }) != 0
                })
        }
 
@@ -232,6 +244,12 @@ impl<T: sealed::UpfrontShutdownScript> Features<T> {
        }
 }
 
+impl<T: sealed::VariableLengthOnion> Features<T> {
+       pub(crate) fn supports_variable_length_onion(&self) -> bool {
+               self.flags.len() > 1 && (self.flags[1] & 3) != 0
+       }
+}
+
 impl<T: sealed::InitialRoutingSync> Features<T> {
        pub(crate) fn initial_routing_sync(&self) -> bool {
                self.flags.len() > 0 && (self.flags[0] & (1 << 3)) != 0
index 472e50aae27b1cedfeccccd880b1cd2958099d4a..1ae8ca1e0058cbb59a006017fc30f9aa4bb75849 100644 (file)
@@ -35,6 +35,7 @@ use std::cell::RefCell;
 use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 use std::mem;
+use std::collections::HashSet;
 
 pub const CHAN_CONFIRM_DEPTH: u32 = 100;
 pub fn confirm_transaction<'a, 'b: 'a>(notifier: &'a chaininterface::BlockNotifierRef<'b>, chain: &chaininterface::ChainWatchInterfaceUtil, tx: &Transaction, chan_id: u32) {
@@ -857,7 +858,7 @@ pub fn create_node_cfgs(node_count: usize) -> Vec<NodeCfg> {
                let logger = Arc::new(test_utils::TestLogger::with_id(format!("node {}", i)));
                let fee_estimator = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
                let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, logger.clone() as Arc<Logger>));
-               let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+               let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), broadcasted_txn: Mutex::new(HashSet::new())});
                let mut seed = [0; 32];
                rng.fill_bytes(&mut seed);
                let keys_manager = Arc::new(test_utils::TestKeysInterface::new(&seed, Network::Testnet, logger.clone() as Arc<Logger>));
index ddd5f56b19959e1f5b9025f62c9354ea6aeacd00..9b1907cbb776e4b048482ba21328947b4f68b497 100644 (file)
@@ -9,7 +9,7 @@ use ln::channel::{COMMITMENT_TX_BASE_WEIGHT, COMMITMENT_TX_WEIGHT_PER_HTLC};
 use ln::channelmanager::{ChannelManager,ChannelManagerReadArgs,HTLCForwardInfo,RAACommitmentOrder, PaymentPreimage, PaymentHash, BREAKDOWN_TIMEOUT};
 use ln::channelmonitor::{ChannelMonitor, CLTV_CLAIM_BUFFER, LATENCY_GRACE_PERIOD_BLOCKS, ManyChannelMonitor, ANTI_REORG_DELAY};
 use ln::channel::{Channel, ChannelError};
-use ln::onion_utils;
+use ln::{chan_utils, onion_utils};
 use ln::router::{Route, RouteHop};
 use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
 use ln::msgs;
@@ -18,7 +18,7 @@ use util::enforcing_trait_impls::EnforcingChannelKeys;
 use util::test_utils;
 use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider};
 use util::errors::APIError;
-use util::ser::{Writeable, ReadableArgs};
+use util::ser::{Writeable, Writer, ReadableArgs};
 use util::config::UserConfig;
 use util::logger::Logger;
 
@@ -44,7 +44,7 @@ use std::collections::{BTreeSet, HashMap, HashSet};
 use std::default::Default;
 use std::sync::{Arc, Mutex};
 use std::sync::atomic::Ordering;
-use std::mem;
+use std::{mem, io};
 
 use rand::{thread_rng, Rng};
 
@@ -378,6 +378,41 @@ fn test_multi_flight_update_fee() {
        check_added_monitors!(nodes[1], 1);
 }
 
+#[test]
+fn test_1_conf_open() {
+       // Previously, if the minium_depth config was set to 1, we'd never send a funding_locked. This
+       // tests that we properly send one in that case.
+       let mut alice_config = UserConfig::default();
+       alice_config.own_channel_config.minimum_depth = 1;
+       alice_config.channel_options.announced_channel = true;
+       alice_config.peer_channel_config_limits.force_announced_channel_preference = false;
+       let mut bob_config = UserConfig::default();
+       bob_config.own_channel_config.minimum_depth = 1;
+       bob_config.channel_options.announced_channel = true;
+       bob_config.peer_channel_config_limits.force_announced_channel_preference = false;
+       let node_cfgs = create_node_cfgs(2);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(alice_config), Some(bob_config)]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+
+       let tx = create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 100000, 10001, InitFeatures::supported(), InitFeatures::supported());
+       assert!(nodes[0].chain_monitor.does_match_tx(&tx));
+       assert!(nodes[1].chain_monitor.does_match_tx(&tx));
+
+       let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
+       nodes[1].block_notifier.block_connected_checked(&header, 1, &[&tx; 1], &[tx.version; 1]);
+       nodes[0].node.handle_funding_locked(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendFundingLocked, nodes[0].node.get_our_node_id()));
+
+       nodes[0].block_notifier.block_connected_checked(&header, 1, &[&tx; 1], &[tx.version; 1]);
+       let (funding_locked, _) = create_chan_between_nodes_with_value_confirm_second(&nodes[1], &nodes[0]);
+       let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &funding_locked);
+
+       for node in nodes {
+               assert!(node.router.handle_channel_announcement(&announcement).unwrap());
+               node.router.handle_channel_update(&as_update).unwrap();
+               node.router.handle_channel_update(&bs_update).unwrap();
+       }
+}
+
 #[test]
 fn test_update_fee_vanilla() {
        let node_cfgs = create_node_cfgs(2);
@@ -1343,11 +1378,9 @@ fn test_duplicate_htlc_different_direction_onchain() {
        // Check we only broadcast 1 timeout tx
        let claim_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone();
        let htlc_pair = if claim_txn[0].output[0].value == 800_000 / 1000 { (claim_txn[0].clone(), claim_txn[1].clone()) } else { (claim_txn[1].clone(), claim_txn[0].clone()) };
-       assert_eq!(claim_txn.len(), 7);
+       assert_eq!(claim_txn.len(), 5);
        check_spends!(claim_txn[2], chan_1.3);
        check_spends!(claim_txn[3], claim_txn[2]);
-       assert_eq!(claim_txn[0], claim_txn[5]);
-       assert_eq!(claim_txn[1], claim_txn[6]);
        assert_eq!(htlc_pair.0.input.len(), 1);
        assert_eq!(htlc_pair.0.input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT); // HTLC 1 <--> 0, preimage tx
        check_spends!(htlc_pair.0, remote_txn[0].clone());
@@ -1964,8 +1997,7 @@ fn test_justice_tx() {
                nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
                {
                        let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-                       assert_eq!(node_txn.len(), 3);
-                       assert_eq!(node_txn.pop().unwrap(), node_txn[0]); // An outpoint registration will result in a 2nd block_connected
+                       assert_eq!(node_txn.len(), 2); // ChannelMonitor: penalty tx, ChannelManager: local commitment tx
                        assert_eq!(node_txn[0].input.len(), 2); // We should claim the revoked output and the HTLC output
 
                        check_spends!(node_txn[0], revoked_local_txn[0].clone());
@@ -2008,8 +2040,7 @@ fn test_justice_tx() {
                nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
                {
                        let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
-                       assert_eq!(node_txn.len(), 3);
-                       assert_eq!(node_txn.pop().unwrap(), node_txn[0]); // An outpoint registration will result in a 2nd block_connected
+                       assert_eq!(node_txn.len(), 2); //ChannelMonitor: penalty tx, ChannelManager: local commitment tx
                        assert_eq!(node_txn[0].input.len(), 1); // We claim the received HTLC output
 
                        check_spends!(node_txn[0], revoked_local_txn[0].clone());
@@ -2048,9 +2079,7 @@ fn revoked_output_claim() {
        let header = BlockHeader { version: 0x20000000, prev_blockhash: Default::default(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
        nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
        let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-       assert_eq!(node_txn.len(), 3); // nodes[1] will broadcast justice tx twice, and its own local state once
-
-       assert_eq!(node_txn[0], node_txn[2]);
+       assert_eq!(node_txn.len(), 2); // ChannelMonitor: justice tx against revoked to_local output, ChannelManager: local commitment tx
 
        check_spends!(node_txn[0], revoked_local_txn[0].clone());
        check_spends!(node_txn[1], chan_1.3.clone());
@@ -2105,13 +2134,11 @@ fn claim_htlc_outputs_shared_tx() {
                }
 
                let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 4);
+               assert_eq!(node_txn.len(), 3); // ChannelMonitor: penalty tx, ChannelManager: local commitment + HTLC-timeout
 
                assert_eq!(node_txn[0].input.len(), 3); // Claim the revoked output + both revoked HTLC outputs
                check_spends!(node_txn[0], revoked_local_txn[0].clone());
 
-               assert_eq!(node_txn[0], node_txn[3]); // justice tx is duplicated due to block re-scanning
-
                let mut witness_lens = BTreeSet::new();
                witness_lens.insert(node_txn[0].input[0].witness.last().unwrap().len());
                witness_lens.insert(node_txn[0].input[1].witness.last().unwrap().len());
@@ -2175,15 +2202,28 @@ fn claim_htlc_outputs_single_tx() {
                }
 
                let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 29); // ChannelManager : 2, ChannelMontitor: 8 (1 standard revoked output, 2 revocation htlc tx, 1 local commitment tx + 1 htlc timeout tx) * 2 (block-rescan) + 5 * (1 local commitment tx + 1 htlc timeout tx)
-
-               assert_eq!(node_txn[0], node_txn[7]);
-               assert_eq!(node_txn[1], node_txn[8]);
-               assert_eq!(node_txn[2], node_txn[9]);
-               assert_eq!(node_txn[3], node_txn[10]);
-               assert_eq!(node_txn[4], node_txn[11]);
-               assert_eq!(node_txn[3], node_txn[5]); //local commitment tx + htlc timeout tx broadcasted by ChannelManger
+               assert_eq!(node_txn.len(), 26);
+               // ChannelMonitor: justice tx revoked offered htlc, justice tx revoked received htlc, justice tx revoked to_local (3)
+               // ChannelManager: local commmitment + local HTLC-timeout (2)
+               // ChannelMonitor: bumped justice tx * 7 (7), after one increase, bumps on HTLC aren't generated not being substantial anymore
+               // ChannelMonitor: local commitment + local HTLC-timeout (14)
+
+
+               assert_eq!(node_txn[3], node_txn[5]);
+               assert_eq!(node_txn[3], node_txn[7]);
+               assert_eq!(node_txn[3], node_txn[9]);
+               assert_eq!(node_txn[3], node_txn[14]);
+               assert_eq!(node_txn[3], node_txn[17]);
+               assert_eq!(node_txn[3], node_txn[20]);
+               assert_eq!(node_txn[3], node_txn[23]);
+
                assert_eq!(node_txn[4], node_txn[6]);
+               assert_eq!(node_txn[4], node_txn[8]);
+               assert_eq!(node_txn[4], node_txn[10]);
+               assert_eq!(node_txn[4], node_txn[15]);
+               assert_eq!(node_txn[4], node_txn[18]);
+               assert_eq!(node_txn[4], node_txn[21]);
+               assert_eq!(node_txn[4], node_txn[24]);
 
                assert_eq!(node_txn[0].input.len(), 1);
                assert_eq!(node_txn[1].input.len(), 1);
@@ -2315,13 +2355,16 @@ fn test_htlc_on_chain_success() {
        };
        macro_rules! check_tx_local_broadcast {
                ($node: expr, $htlc_offered: expr, $commitment_tx: expr, $chan_tx: expr) => { {
-                       // ChannelManager : 3 (commitment tx, 2*HTLC-Timeout tx), ChannelMonitor : 2 (timeout tx) * 2 (block-rescan)
                        let mut node_txn = $node.tx_broadcaster.txn_broadcasted.lock().unwrap();
-                       assert_eq!(node_txn.len(), 7);
-                       assert_eq!(node_txn[0], node_txn[5]);
-                       assert_eq!(node_txn[1], node_txn[6]);
+                       assert_eq!(node_txn.len(), if $htlc_offered { 7 } else { 5 });
+                       // Node[1]: ChannelManager: 3 (commitment tx, 2*HTLC-Timeout tx), ChannelMonitor: 2 (timeout tx)
+                       // Node[0]: ChannelManager: 3 (commtiemtn tx, 2*HTLC-Timeout tx), ChannelMonitor: 2 HTLC-timeout * 2 (block-rescan)
                        check_spends!(node_txn[0], $commitment_tx.clone());
                        check_spends!(node_txn[1], $commitment_tx.clone());
+                       if $htlc_offered {
+                               assert_eq!(node_txn[0], node_txn[5]);
+                               assert_eq!(node_txn[1], node_txn[6]);
+                       }
                        assert_ne!(node_txn[0].lock_time, 0);
                        assert_ne!(node_txn[1].lock_time, 0);
                        if $htlc_offered {
@@ -2359,9 +2402,8 @@ fn test_htlc_on_chain_success() {
        check_spends!(commitment_tx[0], chan_1.3.clone());
        nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
        check_closed_broadcast!(nodes[1], false);
-       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 3 (commitment tx + 2*HTLC-Success), ChannelMonitor : 1 (HTLC-Success) * 2 (block-rescan)
-       assert_eq!(node_txn.len(), 5);
-       assert_eq!(node_txn[0], node_txn[4]);
+       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 3 (commitment tx + HTLC-Sucess * 2), ChannelMonitor : 1 (HTLC-Success)
+       assert_eq!(node_txn.len(), 4);
        check_spends!(node_txn[0], commitment_tx[0].clone());
        assert_eq!(node_txn[0].input.len(), 2);
        assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
@@ -2455,10 +2497,11 @@ fn test_htlc_on_chain_timeout() {
        let timeout_tx;
        {
                let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 8); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 6 (HTLC-Timeout tx, commitment tx, timeout tx) * 2 (block-rescan)
-               assert_eq!(node_txn[0], node_txn[5]);
-               assert_eq!(node_txn[1], node_txn[6]);
-               assert_eq!(node_txn[2], node_txn[7]);
+               assert_eq!(node_txn.len(), 7); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : (local commitment tx + HTLC-timeout) * 2 (block-rescan), timeout tx
+               assert_eq!(node_txn[1], node_txn[3]);
+               assert_eq!(node_txn[1], node_txn[5]);
+               assert_eq!(node_txn[2], node_txn[4]);
+               assert_eq!(node_txn[2], node_txn[6]);
                check_spends!(node_txn[0], commitment_tx[0].clone());
                assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
                check_spends!(node_txn[1], chan_2.3.clone());
@@ -2501,9 +2544,8 @@ fn test_htlc_on_chain_timeout() {
 
        nodes[0].block_notifier.block_connected(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 200);
        check_closed_broadcast!(nodes[0], false);
-       let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 2 (timeout tx) * 2 block-rescan
-       assert_eq!(node_txn.len(), 4);
-       assert_eq!(node_txn[0], node_txn[3]);
+       let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap().clone(); // ChannelManager : 2 (commitment tx, HTLC-Timeout tx), ChannelMonitor : 1 timeout tx
+       assert_eq!(node_txn.len(), 3);
        check_spends!(node_txn[0], commitment_tx[0].clone());
        assert_eq!(node_txn[0].clone().input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
        check_spends!(node_txn[1], chan_1.3.clone());
@@ -3921,10 +3963,9 @@ fn test_static_spendable_outputs_preimage_tx() {
        }
 
        // Check B's monitor was able to send back output descriptor event for preimage tx on A's commitment tx
-       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 2 (local commitment tx + HTLC-Success), ChannelMonitor: 2 (1 preimage tx)
-       assert_eq!(node_txn.len(), 4);
+       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap(); // ChannelManager : 2 (local commitment tx + HTLC-Success), ChannelMonitor: preimage tx
+       assert_eq!(node_txn.len(), 3);
        check_spends!(node_txn[0], commitment_tx[0].clone());
-       assert_eq!(node_txn[0], node_txn[3]);
        assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
 eprintln!("{:?}", node_txn[1]);
        check_spends!(node_txn[1], chan_1.3.clone());
@@ -3956,9 +3997,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_commitment_tx() {
        nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![revoked_local_txn[0].clone()] }, 1);
        check_closed_broadcast!(nodes[1], false);
 
-       let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-       assert_eq!(node_txn.len(), 3);
-       assert_eq!(node_txn.pop().unwrap(), node_txn[0]);
+       let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
+       assert_eq!(node_txn.len(), 2);
        assert_eq!(node_txn[0].input.len(), 2);
        check_spends!(node_txn[0], revoked_local_txn[0].clone());
 
@@ -4002,16 +4042,16 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_timeout_tx() {
        check_closed_broadcast!(nodes[1], false);
 
        let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-       assert_eq!(node_txn.len(), 5);
-       assert_eq!(node_txn[3].input.len(), 1);
-       check_spends!(node_txn[3], revoked_htlc_txn[0].clone());
+       assert_eq!(node_txn.len(), 4 ); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-timeout, adjusted justice tx, ChannelManager: local commitment tx
+       assert_eq!(node_txn[2].input.len(), 1);
+       check_spends!(node_txn[2], revoked_htlc_txn[0].clone());
 
        // Check B's ChannelMonitor was able to generate the right spendable output descriptor
        let spend_txn = check_spendable_outputs!(nodes[1], 1);
        assert_eq!(spend_txn.len(), 3);
        assert_eq!(spend_txn[0], spend_txn[1]);
        check_spends!(spend_txn[0], node_txn[0].clone());
-       check_spends!(spend_txn[2], node_txn[3].clone());
+       check_spends!(spend_txn[2], node_txn[2].clone());
 }
 
 #[test]
@@ -4047,9 +4087,9 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
        check_closed_broadcast!(nodes[0], false);
 
        let node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
-       assert_eq!(node_txn.len(), 4);
-       assert_eq!(node_txn[3].input.len(), 1);
-       check_spends!(node_txn[3], revoked_htlc_txn[0].clone());
+       assert_eq!(node_txn.len(), 3); // ChannelMonitor: justice tx on revoked commitment, justice tx on revoked HTLC-success, ChannelManager: local commitment tx
+       assert_eq!(node_txn[2].input.len(), 1);
+       check_spends!(node_txn[2], revoked_htlc_txn[0].clone());
 
        // Check A's ChannelMonitor was able to generate the right spendable output descriptor
        let spend_txn = check_spendable_outputs!(nodes[0], 1);
@@ -4057,8 +4097,8 @@ fn test_static_spendable_outputs_justice_tx_revoked_htlc_success_tx() {
        assert_eq!(spend_txn[0], spend_txn[2]);
        assert_eq!(spend_txn[1], spend_txn[3]);
        check_spends!(spend_txn[0], revoked_local_txn[0].clone()); // spending to_remote output from revoked local tx
-       check_spends!(spend_txn[1], node_txn[2].clone()); // spending justice tx output from revoked local tx htlc received output
-       check_spends!(spend_txn[4], node_txn[3].clone()); // spending justice tx output on htlc success tx
+       check_spends!(spend_txn[1], node_txn[0].clone()); // spending justice tx output from revoked local tx htlc received output
+       check_spends!(spend_txn[4], node_txn[2].clone()); // spending justice tx output on htlc success tx
 }
 
 #[test]
@@ -4114,8 +4154,8 @@ fn test_onchain_to_onchain_claim() {
        nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![c_txn[1].clone(), c_txn[2].clone()]}, 1);
        {
                let mut b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(b_txn.len(), 4);
-               assert_eq!(b_txn[0], b_txn[3]);
+               // ChannelMonitor: claim tx, ChannelManager: local commitment tx + HTLC-timeout tx
+               assert_eq!(b_txn.len(), 3);
                check_spends!(b_txn[1], chan_2.3); // B local commitment tx, issued by ChannelManager
                check_spends!(b_txn[2], b_txn[1].clone()); // HTLC-Timeout on B local commitment tx, issued by ChannelManager
                assert_eq!(b_txn[2].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
@@ -4147,14 +4187,14 @@ fn test_onchain_to_onchain_claim() {
        let commitment_tx = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&chan_1.2).unwrap().channel_monitor().get_latest_local_commitment_txn();
        nodes[1].block_notifier.block_connected(&Block { header, txdata: vec![commitment_tx[0].clone()]}, 1);
        let b_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-       assert_eq!(b_txn.len(), 4);
-       check_spends!(b_txn[1], chan_1.3); // Local commitment tx, issued by ChannelManager
-       check_spends!(b_txn[2], b_txn[1]); // HTLC-Success tx, as a part of the local txn rebroadcast by ChannelManager in the force close
-       assert_eq!(b_txn[0], b_txn[3]); // HTLC-Success tx, issued by ChannelMonitor, * 2 due to block rescan
+       // ChannelMonitor: HTLC-Success tx, ChannelManager: local commitment tx + HTLC-Success tx
+       assert_eq!(b_txn.len(), 3);
+       check_spends!(b_txn[1], chan_1.3);
+       check_spends!(b_txn[2], b_txn[1].clone());
        check_spends!(b_txn[0], commitment_tx[0].clone());
        assert_eq!(b_txn[0].input[0].witness.clone().last().unwrap().len(), OFFERED_HTLC_SCRIPT_WEIGHT);
        assert!(b_txn[0].output[0].script_pubkey.is_v0_p2wpkh()); // direct payment
-       assert_eq!(b_txn[2].lock_time, 0); // Success tx
+       assert_eq!(b_txn[0].lock_time, 0); // Success tx
 
        check_closed_broadcast!(nodes[1], false);
 }
@@ -4185,14 +4225,15 @@ fn test_duplicate_payment_hash_one_failure_one_success() {
        let htlc_timeout_tx;
        { // Extract one of the two HTLC-Timeout transaction
                let node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 7);
-               assert_eq!(node_txn[0], node_txn[5]);
-               assert_eq!(node_txn[1], node_txn[6]);
+               // ChannelMonitor: timeout tx * 2, ChannelManager: local commitment tx + HTLC-timeout * 2
+               assert_eq!(node_txn.len(), 5);
                check_spends!(node_txn[0], commitment_txn[0].clone());
                assert_eq!(node_txn[0].input.len(), 1);
                check_spends!(node_txn[1], commitment_txn[0].clone());
                assert_eq!(node_txn[1].input.len(), 1);
                assert_ne!(node_txn[0].input[0], node_txn[1].input[0]);
+               assert_eq!(node_txn[0].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
+               assert_eq!(node_txn[1].input[0].witness.last().unwrap().len(), ACCEPTED_HTLC_SCRIPT_WEIGHT);
                check_spends!(node_txn[2], chan_2.3.clone());
                check_spends!(node_txn[3], node_txn[2].clone());
                check_spends!(node_txn[4], node_txn[2].clone());
@@ -4972,6 +5013,20 @@ impl msgs::ChannelUpdate {
        }
 }
 
+struct BogusOnionHopData {
+       data: Vec<u8>
+}
+impl BogusOnionHopData {
+       fn new(orig: msgs::OnionHopData) -> Self {
+               Self { data: orig.encode() }
+       }
+}
+impl Writeable for BogusOnionHopData {
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
+               writer.write_all(&self.data[..])
+       }
+}
+
 #[test]
 fn test_onion_failure() {
        use ln::msgs::ChannelUpdate;
@@ -5001,9 +5056,15 @@ fn test_onion_failure() {
                let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
                let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
                let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height).unwrap();
-               onion_payloads[0].realm = 3;
-               msg.onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
-       }, ||{}, true, Some(PERM|1), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));//XXX incremented channels idx here
+               let mut new_payloads = Vec::new();
+               for payload in onion_payloads.drain(..) {
+                       new_payloads.push(BogusOnionHopData::new(payload));
+               }
+               // break the first (non-final) hop payload by swapping the realm (0) byte for a byte
+               // describing a length-1 TLV payload, which is obviously bogus.
+               new_payloads[0].data[0] = 1;
+               msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash);
+       }, ||{}, true, Some(PERM|22), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));//XXX incremented channels idx here
 
        // final node failure
        run_onion_failure_test("invalid_realm", 3, &nodes, &route, &payment_hash, |msg| {
@@ -5011,9 +5072,15 @@ fn test_onion_failure() {
                let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1;
                let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap();
                let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height).unwrap();
-               onion_payloads[1].realm = 3;
-               msg.onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash);
-       }, ||{}, false, Some(PERM|1), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));
+               let mut new_payloads = Vec::new();
+               for payload in onion_payloads.drain(..) {
+                       new_payloads.push(BogusOnionHopData::new(payload));
+               }
+               // break the last-hop payload by swapping the realm (0) byte for a byte describing a
+               // length-1 TLV payload, which is obviously bogus.
+               new_payloads[1].data[0] = 1;
+               msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash);
+       }, ||{}, false, Some(PERM|22), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));
 
        // the following three with run_onion_failure_test_with_fail_intercept() test only the origin node
        // receiving simulated fail messages
@@ -6312,7 +6379,7 @@ fn test_data_loss_protect() {
        let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::with_id(format!("node {}", 0)));
        let mut chan_monitor = <(Sha256dHash, ChannelMonitor<EnforcingChannelKeys>)>::read(&mut ::std::io::Cursor::new(previous_chan_monitor_state.0), Arc::clone(&logger)).unwrap().1;
        let chain_monitor = Arc::new(ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
-       let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
+       let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new()), broadcasted_txn: Mutex::new(HashSet::new())});
        let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
        monitor = test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone(), logger.clone(), feeest.clone());
        node_state_0 = {
@@ -6553,8 +6620,7 @@ fn test_bump_penalty_txn_on_revoked_commitment() {
        let feerate_1;
        {
                let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 4); // justice tx (broadcasted from ChannelMonitor) * 2 (block-reparsing) + local commitment tx + local HTLC-timeout (broadcasted from ChannelManager)
-               assert_eq!(node_txn[0], node_txn[3]);
+               assert_eq!(node_txn.len(), 3); // justice tx (broadcasted from ChannelMonitor) + local commitment tx + local HTLC-timeout (broadcasted from ChannelManager)
                assert_eq!(node_txn[0].input.len(), 3); // Penalty txn claims to_local, offered_htlc and received_htlc outputs
                assert_eq!(node_txn[0].output.len(), 1);
                check_spends!(node_txn[0], revoked_txn[0].clone());
@@ -6672,21 +6738,21 @@ fn test_bump_penalty_txn_on_revoked_htlcs() {
        let feerate_2;
        {
                let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 9); // 3 penalty txn on revoked commitment tx * 2 (block-rescan) + A commitment tx + 2 penalty tnx on revoked HTLC txn
+               assert_eq!(node_txn.len(), 6); // 3 penalty txn on revoked commitment tx + A commitment tx + 2 penalty tnx on revoked HTLC txn
                // Verify claim tx are spending revoked HTLC txn
-               assert_eq!(node_txn[7].input.len(), 1);
-               assert_eq!(node_txn[7].output.len(), 1);
-               check_spends!(node_txn[7], revoked_htlc_txn[0].clone());
-               first = node_txn[7].txid();
-               assert_eq!(node_txn[8].input.len(), 1);
-               assert_eq!(node_txn[8].output.len(), 1);
-               check_spends!(node_txn[8], revoked_htlc_txn[1].clone());
-               second = node_txn[8].txid();
+               assert_eq!(node_txn[4].input.len(), 1);
+               assert_eq!(node_txn[4].output.len(), 1);
+               check_spends!(node_txn[4], revoked_htlc_txn[0].clone());
+               first = node_txn[4].txid();
+               assert_eq!(node_txn[5].input.len(), 1);
+               assert_eq!(node_txn[5].output.len(), 1);
+               check_spends!(node_txn[5], revoked_htlc_txn[1].clone());
+               second = node_txn[5].txid();
                // Store both feerates for later comparison
-               let fee_1 = revoked_htlc_txn[0].output[0].value - node_txn[7].output[0].value;
-               feerate_1 = fee_1 * 1000 / node_txn[7].get_weight() as u64;
-               let fee_2 = revoked_htlc_txn[1].output[0].value - node_txn[8].output[0].value;
-               feerate_2 = fee_2 * 1000 / node_txn[8].get_weight() as u64;
+               let fee_1 = revoked_htlc_txn[0].output[0].value - node_txn[4].output[0].value;
+               feerate_1 = fee_1 * 1000 / node_txn[4].get_weight() as u64;
+               let fee_2 = revoked_htlc_txn[1].output[0].value - node_txn[5].output[0].value;
+               feerate_2 = fee_2 * 1000 / node_txn[5].get_weight() as u64;
                node_txn.clear();
        }
 
@@ -6801,9 +6867,7 @@ fn test_bump_penalty_txn_on_remote_commitment() {
        let feerate_preimage;
        {
                let mut node_txn = nodes[1].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 7); // 2 * claim tx (broadcasted from ChannelMonitor) * 2 (block-reparsing) + local commitment tx + local HTLC-timeout + HTLC-success (broadcasted from ChannelManager)
-               assert_eq!(node_txn[0], node_txn[5]);
-               assert_eq!(node_txn[1], node_txn[6]);
+               assert_eq!(node_txn.len(), 5); // 2 * claim tx (broadcasted from ChannelMonitor) + local commitment tx + local HTLC-timeout + local HTLC-success (broadcasted from ChannelManager)
                assert_eq!(node_txn[0].input.len(), 1);
                assert_eq!(node_txn[1].input.len(), 1);
                check_spends!(node_txn[0], remote_txn[0].clone());
@@ -6915,8 +6979,8 @@ fn test_set_outpoints_partial_claiming() {
        // Verify node A broadcast tx claiming both HTLCs
        {
                let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 5);
-               assert_eq!(node_txn[0], node_txn[4]);
+               // ChannelMonitor: claim tx, ChannelManager: local commitment tx + HTLC-Success*2
+               assert_eq!(node_txn.len(), 4);
                check_spends!(node_txn[0], remote_txn[0].clone());
                check_spends!(node_txn[1], chan.3.clone());
                check_spends!(node_txn[2], node_txn[1]);
@@ -6972,6 +7036,32 @@ fn test_set_outpoints_partial_claiming() {
        }
 }
 
+#[test]
+fn test_counterparty_raa_skip_no_crash() {
+       // Previously, if our counterparty sent two RAAs in a row without us having provided a
+       // commitment transaction, we would have happily carried on and provided them the next
+       // commitment transaction based on one RAA forward. This would probably eventually have led to
+       // channel closure, but it would not have resulted in funds loss. Still, our
+       // EnforcingChannelKeys would have paniced as it doesn't like jumps into the future. Here, we
+       // check simply that the channel is closed in response to such an RAA, but don't check whether
+       // we decide to punish our counterparty for revoking their funds (as we don't currently
+       // implement that).
+       let node_cfgs = create_node_cfgs(2);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       let channel_id = create_announced_chan_between_nodes(&nodes, 0, 1, InitFeatures::supported(), InitFeatures::supported()).2;
+
+       let commitment_seed = nodes[0].node.channel_state.lock().unwrap().by_id.get_mut(&channel_id).unwrap().local_keys.commitment_seed().clone();
+       const INITIAL_COMMITMENT_NUMBER: u64 = (1 << 48) - 1;
+       let next_per_commitment_point = PublicKey::from_secret_key(&Secp256k1::new(),
+               &SecretKey::from_slice(&chan_utils::build_commitment_secret(&commitment_seed, INITIAL_COMMITMENT_NUMBER - 2)).unwrap());
+       let per_commitment_secret = chan_utils::build_commitment_secret(&commitment_seed, INITIAL_COMMITMENT_NUMBER);
+
+       nodes[1].node.handle_revoke_and_ack(&nodes[0].node.get_our_node_id(),
+               &msgs::RevokeAndACK { channel_id, per_commitment_secret, next_per_commitment_point });
+       assert_eq!(check_closed_broadcast!(nodes[1], true).unwrap().data, "Received an unexpected revoke_and_ack");
+}
+
 #[test]
 fn test_bump_txn_sanitize_tracking_maps() {
        // Sanitizing pendning_claim_request and claimable_outpoints used to be buggy,
@@ -7000,7 +7090,7 @@ fn test_bump_txn_sanitize_tracking_maps() {
        check_closed_broadcast!(nodes[0], false);
        let penalty_txn = {
                let mut node_txn = nodes[0].tx_broadcaster.txn_broadcasted.lock().unwrap();
-               assert_eq!(node_txn.len(), 7);
+               assert_eq!(node_txn.len(), 4); //ChannelMonitor: justice txn * 3, ChannelManager: local commitment tx
                check_spends!(node_txn[0], revoked_local_txn[0].clone());
                check_spends!(node_txn[1], revoked_local_txn[0].clone());
                check_spends!(node_txn[2], revoked_local_txn[0].clone());
index 483d69e7a39ee9b3b0a0aac35a9dad46882f150f..b50e35b96dc14c62966aab1e8a3c85ca19097bd7 100644 (file)
@@ -29,7 +29,7 @@ use std::io::Read;
 use std::result::Result;
 
 use util::events;
-use util::ser::{Readable, Writeable, Writer};
+use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt};
 
 use ln::channelmanager::{PaymentPreimage, PaymentHash};
 
@@ -39,10 +39,11 @@ pub enum DecodeError {
        /// A version byte specified something we don't know how to handle.
        /// Includes unknown realm byte in an OnionHopData packet
        UnknownVersion,
-       /// Unknown feature mandating we fail to parse message
+       /// Unknown feature mandating we fail to parse message (eg TLV with an even, unknown type)
        UnknownRequiredFeature,
        /// Value was invalid, eg a byte which was supposed to be a bool was something other than a 0
-       /// or 1, a public key/private key/signature was invalid, text wasn't UTF-8, etc
+       /// or 1, a public key/private key/signature was invalid, text wasn't UTF-8, TLV was
+       /// syntactically incorrect, etc
        InvalidValue,
        /// Buffer too short
        ShortRead,
@@ -604,24 +605,29 @@ pub trait RoutingMessageHandler : Send + Sync {
        /// starting at the node *after* the provided publickey and including batch_amount entries.
        /// If None is provided for starting_point, we start at the first node.
        fn get_next_node_announcements(&self, starting_point: Option<&PublicKey>, batch_amount: u8) -> Vec<NodeAnnouncement>;
-}
-
-pub(crate) struct OnionRealm0HopData {
-       pub(crate) short_channel_id: u64,
-       pub(crate) amt_to_forward: u64,
-       pub(crate) outgoing_cltv_value: u32,
-       // 12 bytes of 0-padding
+       /// Returns whether a full sync should be requested from a peer.
+       fn should_request_full_sync(&self, node_id: &PublicKey) -> bool;
 }
 
 mod fuzzy_internal_msgs {
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
 
-       use super::OnionRealm0HopData;
+       pub(crate) enum OnionHopDataFormat {
+               Legacy { // aka Realm-0
+                       short_channel_id: u64,
+               },
+               NonFinalNode {
+                       short_channel_id: u64,
+               },
+               FinalNode,
+       }
+
        pub struct OnionHopData {
-               pub(crate) realm: u8,
-               pub(crate) data: OnionRealm0HopData,
-               pub(crate) hmac: [u8; 32],
+               pub(crate) format: OnionHopDataFormat,
+               pub(crate) amt_to_forward: u64,
+               pub(crate) outgoing_cltv_value: u32,
+               // 12 bytes of 0-padding for Legacy format
        }
 
        pub struct DecodedOnionErrorPacket {
@@ -958,53 +964,78 @@ impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, {
        onion_routing_packet
 });
 
-impl Writeable for OnionRealm0HopData {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
-               w.size_hint(32);
-               self.short_channel_id.write(w)?;
-               self.amt_to_forward.write(w)?;
-               self.outgoing_cltv_value.write(w)?;
-               w.write_all(&[0;12])?;
-               Ok(())
-       }
-}
-
-impl<R: Read> Readable<R> for OnionRealm0HopData {
-       fn read(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(OnionRealm0HopData {
-                       short_channel_id: Readable::read(r)?,
-                       amt_to_forward: Readable::read(r)?,
-                       outgoing_cltv_value: {
-                               let v: u32 = Readable::read(r)?;
-                               r.read_exact(&mut [0; 12])?;
-                               v
-                       }
-               })
-       }
-}
-
 impl Writeable for OnionHopData {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
-               w.size_hint(65);
-               self.realm.write(w)?;
-               self.data.write(w)?;
-               self.hmac.write(w)?;
+               w.size_hint(33);
+               match self.format {
+                       OnionHopDataFormat::Legacy { short_channel_id } => {
+                               0u8.write(w)?;
+                               short_channel_id.write(w)?;
+                               self.amt_to_forward.write(w)?;
+                               self.outgoing_cltv_value.write(w)?;
+                               w.write_all(&[0;12])?;
+                       },
+                       OnionHopDataFormat::NonFinalNode { short_channel_id } => {
+                               encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
+                                       (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
+                                       (6, short_channel_id)
+                               });
+                       },
+                       OnionHopDataFormat::FinalNode => {
+                               encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
+                                       (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value))
+                               });
+                       },
+               }
                Ok(())
        }
 }
 
 impl<R: Read> Readable<R> for OnionHopData {
-       fn read(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(OnionHopData {
-                       realm: {
-                               let r: u8 = Readable::read(r)?;
-                               if r != 0 {
-                                       return Err(DecodeError::UnknownVersion);
+       fn read(mut r: &mut R) -> Result<Self, DecodeError> {
+               use bitcoin::consensus::encode::{Decodable, Error, VarInt};
+               let v: VarInt = Decodable::consensus_decode(&mut r)
+                       .map_err(|e| match e {
+                               Error::Io(ioe) => DecodeError::from(ioe),
+                               _ => DecodeError::InvalidValue
+                       })?;
+               const LEGACY_ONION_HOP_FLAG: u64 = 0;
+               let (format, amt, cltv_value) = if v.0 != LEGACY_ONION_HOP_FLAG {
+                       let mut rd = FixedLengthReader::new(r, v.0);
+                       let mut amt = HighZeroBytesDroppedVarInt(0u64);
+                       let mut cltv_value = HighZeroBytesDroppedVarInt(0u32);
+                       let mut short_id: Option<u64> = None;
+                       decode_tlv!(&mut rd, {
+                               (2, amt),
+                               (4, cltv_value)
+                       }, {
+                               (6, short_id)
+                       });
+                       rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
+                       let format = if let Some(short_channel_id) = short_id {
+                               OnionHopDataFormat::NonFinalNode {
+                                       short_channel_id,
                                }
-                               r
-                       },
-                       data: Readable::read(r)?,
-                       hmac: Readable::read(r)?,
+                       } else {
+                               OnionHopDataFormat::FinalNode
+                       };
+                       (format, amt.0, cltv_value.0)
+               } else {
+                       let format = OnionHopDataFormat::Legacy {
+                               short_channel_id: Readable::read(r)?,
+                       };
+                       let amt: u64 = Readable::read(r)?;
+                       let cltv_value: u32 = Readable::read(r)?;
+                       r.read_exact(&mut [0; 12])?;
+                       (format, amt, cltv_value)
+               };
+
+               Ok(OnionHopData {
+                       format,
+                       amt_to_forward: amt,
+                       outgoing_cltv_value: cltv_value,
                })
        }
 }
@@ -1290,9 +1321,9 @@ impl_writeable_len_match!(NodeAnnouncement, {
 mod tests {
        use hex;
        use ln::msgs;
-       use ln::msgs::{ChannelFeatures, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket};
+       use ln::msgs::{ChannelFeatures, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat};
        use ln::channelmanager::{PaymentPreimage, PaymentHash};
-       use util::ser::Writeable;
+       use util::ser::{Writeable, Readable};
 
        use bitcoin_hashes::sha256d::Hash as Sha256dHash;
        use bitcoin_hashes::hex::FromHex;
@@ -1304,6 +1335,8 @@ mod tests {
        use secp256k1::key::{PublicKey,SecretKey};
        use secp256k1::{Secp256k1, Message};
 
+       use std::io::Cursor;
+
        #[test]
        fn encoding_channel_reestablish_no_secret() {
                let cr = msgs::ChannelReestablish {
@@ -1943,4 +1976,54 @@ mod tests {
                let target_value = hex::decode("004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
                assert_eq!(encoded_value, target_value);
        }
+
+       #[test]
+       fn encoding_legacy_onion_hop_data() {
+               let msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::Legacy {
+                               short_channel_id: 0xdeadbeef1bad1dea,
+                       },
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("00deadbeef1bad1dea0badf00d01020304ffffffff000000000000000000000000").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_nonfinal_onion_hop_data() {
+               let mut msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::NonFinalNode {
+                               short_channel_id: 0xdeadbeef1bad1dea,
+                       },
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("1a02080badf00d010203040404ffffffff0608deadbeef1bad1dea").unwrap();
+               assert_eq!(encoded_value, target_value);
+               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let OnionHopDataFormat::NonFinalNode { short_channel_id } = msg.format {
+                       assert_eq!(short_channel_id, 0xdeadbeef1bad1dea);
+               } else { panic!(); }
+               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
+               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
+       }
+
+       #[test]
+       fn encoding_final_onion_hop_data() {
+               let mut msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::FinalNode,
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap();
+               assert_eq!(encoded_value, target_value);
+               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let OnionHopDataFormat::FinalNode = msg.format { } else { panic!(); }
+               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
+               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
+       }
 }
index 98f4b64496eadbdbab31efb2e6cfa5f9ad734f52..c2835460e22b9646f9a659686280283c99f577bf 100644 (file)
@@ -4,7 +4,7 @@ use ln::router::{Route,RouteHop};
 use util::byte_utils;
 use util::chacha20::ChaCha20;
 use util::errors::{self, APIError};
-use util::ser::{Readable, Writeable};
+use util::ser::{Readable, Writeable, LengthCalculatingWriter};
 use util::logger::{Logger, LogHolder};
 
 use bitcoin_hashes::{Hash, HashEngine};
@@ -114,20 +114,28 @@ pub(super) fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) ->
        let mut last_short_channel_id = 0;
        let mut res: Vec<msgs::OnionHopData> = Vec::with_capacity(route.hops.len());
 
-       for hop in route.hops.iter().rev() {
+       for (idx, hop) in route.hops.iter().rev().enumerate() {
                // First hop gets special values so that it can check, on receipt, that everything is
                // exactly as it should be (and the next hop isn't trying to probe to find out if we're
                // the intended recipient).
                let value_msat = if cur_value_msat == 0 { hop.fee_msat } else { cur_value_msat };
                let cltv = if cur_cltv == starting_htlc_offset { hop.cltv_expiry_delta + starting_htlc_offset } else { cur_cltv };
                res.insert(0, msgs::OnionHopData {
-                       realm: 0,
-                       data: msgs::OnionRealm0HopData {
-                               short_channel_id: last_short_channel_id,
-                               amt_to_forward: value_msat,
-                               outgoing_cltv_value: cltv,
+                       format: if hop.node_features.supports_variable_length_onion() {
+                               if idx == 0 {
+                                       msgs::OnionHopDataFormat::FinalNode
+                               } else {
+                                       msgs::OnionHopDataFormat::NonFinalNode {
+                                               short_channel_id: last_short_channel_id,
+                                       }
+                               }
+                       } else {
+                               msgs::OnionHopDataFormat::Legacy {
+                                       short_channel_id: last_short_channel_id,
+                               }
                        },
-                       hmac: [0; 32],
+                       amt_to_forward: value_msat,
+                       outgoing_cltv_value: cltv,
                });
                cur_value_msat += hop.fee_msat;
                if cur_value_msat >= 21000000 * 100000000 * 1000 {
@@ -142,68 +150,96 @@ pub(super) fn build_onion_payloads(route: &Route, starting_htlc_offset: u32) ->
        Ok((res, cur_value_msat, cur_cltv))
 }
 
+/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now
+/// the hops can be of variable length.
+pub(crate) const ONION_DATA_LEN: usize = 20*65;
+
 #[inline]
-fn shift_arr_right(arr: &mut [u8; 20*65]) {
-       for i in (65..20*65).rev() {
-               arr[i] = arr[i-65];
+fn shift_arr_right(arr: &mut [u8; ONION_DATA_LEN], amt: usize) {
+       for i in (amt..ONION_DATA_LEN).rev() {
+               arr[i] = arr[i-amt];
        }
-       for i in 0..65 {
+       for i in 0..amt {
                arr[i] = 0;
        }
 }
 
-#[inline]
-fn xor_bufs(dst: &mut[u8], src: &[u8]) {
-       assert_eq!(dst.len(), src.len());
-
-       for i in 0..dst.len() {
-               dst[i] ^= src[i];
+pub(super) fn route_size_insane(payloads: &Vec<msgs::OnionHopData>) -> bool {
+       let mut len = 0;
+       for payload in payloads.iter() {
+               let mut payload_len = LengthCalculatingWriter(0);
+               payload.write(&mut payload_len).expect("Failed to calculate length");
+               assert!(payload_len.0 + 32 < ONION_DATA_LEN);
+               len += payload_len.0 + 32;
+               if len > ONION_DATA_LEN {
+                       return true;
+               }
        }
+       false
 }
 
-
-const ZERO:[u8; 21*65] = [0; 21*65];
+/// panics if route_size_insane(paylods)
 pub(super) fn construct_onion_packet(payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket {
-       let mut packet_data = [0; 20*65];
+       let mut packet_data = [0; ONION_DATA_LEN];
 
        let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
-       chacha.process(&[0; 20*65], &mut packet_data);
+       chacha.process(&[0; ONION_DATA_LEN], &mut packet_data);
 
        construct_onion_packet_with_init_noise(payloads, onion_keys, packet_data, associated_data)
 }
 
-fn construct_onion_packet_with_init_noise(mut payloads: Vec<msgs::OnionHopData>, onion_keys: Vec<OnionKeys>, mut packet_data: [u8; 20*65], associated_data: &PaymentHash) -> msgs::OnionPacket {
-       let mut buf = Vec::with_capacity(21*65);
-       buf.resize(21*65, 0);
+#[cfg(test)]
+// Used in testing to write bogus OnionHopDatas, which is otherwise not representable in
+// msgs::OnionHopData.
+pub(super) fn construct_onion_packet_bogus_hopdata<HD: Writeable>(payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket {
+       let mut packet_data = [0; ONION_DATA_LEN];
+
+       let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
+       chacha.process(&[0; ONION_DATA_LEN], &mut packet_data);
 
+       construct_onion_packet_with_init_noise(payloads, onion_keys, packet_data, associated_data)
+}
+
+/// panics if route_size_insane(paylods)
+fn construct_onion_packet_with_init_noise<HD: Writeable>(mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: [u8; ONION_DATA_LEN], associated_data: &PaymentHash) -> msgs::OnionPacket {
        let filler = {
-               let iters = payloads.len() - 1;
-               let end_len = iters * 65;
-               let mut res = Vec::with_capacity(end_len);
-               res.resize(end_len, 0);
+               const ONION_HOP_DATA_LEN: usize = 65; // We may decrease this eventually after TLV is common
+               let mut res = Vec::with_capacity(ONION_HOP_DATA_LEN * (payloads.len() - 1));
+
+               let mut pos = 0;
+               for (i, (payload, keys)) in payloads.iter().zip(onion_keys.iter()).enumerate() {
+                       if i == payloads.len() - 1 { break; }
 
-               for (i, keys) in onion_keys.iter().enumerate() {
-                       if i == payloads.len() - 1 { continue; }
                        let mut chacha = ChaCha20::new(&keys.rho, &[0u8; 8]);
-                       chacha.process(&ZERO, &mut buf); // We don't have a seek function :(
-                       xor_bufs(&mut res[0..(i + 1)*65], &buf[(20 - i)*65..21*65]);
+                       for _ in 0..(ONION_DATA_LEN - pos) { // TODO: Batch this.
+                               let mut dummy = [0; 1];
+                               chacha.process_in_place(&mut dummy); // We don't have a seek function :(
+                       }
+
+                       let mut payload_len = LengthCalculatingWriter(0);
+                       payload.write(&mut payload_len).expect("Failed to calculate length");
+                       pos += payload_len.0 + 32;
+                       assert!(pos <= ONION_DATA_LEN);
+
+                       res.resize(pos, 0u8);
+                       chacha.process_in_place(&mut res);
                }
                res
        };
 
        let mut hmac_res = [0; 32];
-
        for (i, (payload, keys)) in payloads.iter_mut().zip(onion_keys.iter()).rev().enumerate() {
-               shift_arr_right(&mut packet_data);
-               payload.hmac = hmac_res;
-               packet_data[0..65].copy_from_slice(&payload.encode()[..]);
+               let mut payload_len = LengthCalculatingWriter(0);
+               payload.write(&mut payload_len).expect("Failed to calculate length");
+               shift_arr_right(&mut packet_data, payload_len.0 + 32);
+               packet_data[0..payload_len.0].copy_from_slice(&payload.encode()[..]);
+               packet_data[payload_len.0..(payload_len.0 + 32)].copy_from_slice(&hmac_res);
 
                let mut chacha = ChaCha20::new(&keys.rho, &[0u8; 8]);
-               chacha.process(&packet_data, &mut buf[0..20*65]);
-               packet_data[..].copy_from_slice(&buf[0..20*65]);
+               chacha.process_in_place(&mut packet_data);
 
                if i == 0 {
-                       packet_data[20*65 - filler.len()..20*65].copy_from_slice(&filler[..]);
+                       packet_data[ONION_DATA_LEN - filler.len()..ONION_DATA_LEN].copy_from_slice(&filler[..]);
                }
 
                let mut hmac = HmacEngine::<Sha256>::new(&keys.mu);
@@ -212,7 +248,7 @@ fn construct_onion_packet_with_init_noise(mut payloads: Vec<msgs::OnionHopData>,
                hmac_res = Hmac::from_engine(hmac).into_inner();
        }
 
-       msgs::OnionPacket{
+       msgs::OnionPacket {
                version: 0,
                public_key: Ok(onion_keys.first().unwrap().ephemeral_pubkey),
                hop_data: packet_data,
@@ -428,7 +464,7 @@ mod tests {
        use ln::features::{ChannelFeatures, NodeFeatures};
        use ln::router::{Route, RouteHop};
        use ln::msgs;
-       use util::ser::Writeable;
+       use util::ser::{Writeable, Writer};
 
        use hex;
 
@@ -480,7 +516,7 @@ mod tests {
 
        #[test]
        fn onion_vectors() {
-               // Packet creation test vectors from BOLT 4
+               // Legacy packet creation test vectors from BOLT 4
                let onion_keys = build_test_onion_keys();
 
                assert_eq!(onion_keys[0].shared_secret[..], hex::decode("53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66").unwrap()[..]);
@@ -516,54 +552,43 @@ mod tests {
                // Test vectors below are flat-out wrong: they claim to set outgoing_cltv_value to non-0 :/
                let payloads = vec!(
                        msgs::OnionHopData {
-                               realm: 0,
-                               data: msgs::OnionRealm0HopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
                                        short_channel_id: 0,
-                                       amt_to_forward: 0,
-                                       outgoing_cltv_value: 0,
                                },
-                               hmac: [0; 32],
+                               amt_to_forward: 0,
+                               outgoing_cltv_value: 0,
                        },
                        msgs::OnionHopData {
-                               realm: 0,
-                               data: msgs::OnionRealm0HopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
                                        short_channel_id: 0x0101010101010101,
-                                       amt_to_forward: 0x0100000001,
-                                       outgoing_cltv_value: 0,
                                },
-                               hmac: [0; 32],
+                               amt_to_forward: 0x0100000001,
+                               outgoing_cltv_value: 0,
                        },
                        msgs::OnionHopData {
-                               realm: 0,
-                               data: msgs::OnionRealm0HopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
                                        short_channel_id: 0x0202020202020202,
-                                       amt_to_forward: 0x0200000002,
-                                       outgoing_cltv_value: 0,
                                },
-                               hmac: [0; 32],
+                               amt_to_forward: 0x0200000002,
+                               outgoing_cltv_value: 0,
                        },
                        msgs::OnionHopData {
-                               realm: 0,
-                               data: msgs::OnionRealm0HopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
                                        short_channel_id: 0x0303030303030303,
-                                       amt_to_forward: 0x0300000003,
-                                       outgoing_cltv_value: 0,
                                },
-                               hmac: [0; 32],
+                               amt_to_forward: 0x0300000003,
+                               outgoing_cltv_value: 0,
                        },
                        msgs::OnionHopData {
-                               realm: 0,
-                               data: msgs::OnionRealm0HopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
                                        short_channel_id: 0x0404040404040404,
-                                       amt_to_forward: 0x0400000004,
-                                       outgoing_cltv_value: 0,
                                },
-                               hmac: [0; 32],
+                               amt_to_forward: 0x0400000004,
+                               outgoing_cltv_value: 0,
                        },
                );
 
-               let packet = [0; 20*65];
-               let packet = super::construct_onion_packet_with_init_noise(payloads, onion_keys, packet, &PaymentHash([0x42; 32]));
+               let packet = super::construct_onion_packet_with_init_noise(payloads, onion_keys, [0; super::ONION_DATA_LEN], &PaymentHash([0x42; 32]));
                // Just check the final packet encoding, as it includes all the per-hop vectors in it
                // anyway...
                assert_eq!(packet.encode(), hex::decode("0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a716a996c7845c93d90e4ecbb9bde4ece2f69425c99e4bc820e44485455f135edc0d10f7d61ab590531cf08000179a333a347f8b4072f216400406bdf3bf038659793d4a1fd7b246979e3150a0a4cb052c9ec69acf0f48c3d39cd55675fe717cb7d80ce721caad69320c3a469a202f1e468c67eaf7a7cd8226d0fd32f7b48084dca885d56047694762b67021713ca673929c163ec36e04e40ca8e1c6d17569419d3039d9a1ec866abe044a9ad635778b961fc0776dc832b3a451bd5d35072d2269cf9b040f6b7a7dad84fb114ed413b1426cb96ceaf83825665ed5a1d002c1687f92465b49ed4c7f0218ff8c6c7dd7221d589c65b3b9aaa71a41484b122846c7c7b57e02e679ea8469b70e14fe4f70fee4d87b910cf144be6fe48eef24da475c0b0bcc6565ae82cd3f4e3b24c76eaa5616c6111343306ab35c1fe5ca4a77c0e314ed7dba39d6f1e0de791719c241a939cc493bea2bae1c1e932679ea94d29084278513c77b899cc98059d06a27d171b0dbdf6bee13ddc4fc17a0c4d2827d488436b57baa167544138ca2e64a11b43ac8a06cd0c2fba2d4d900ed2d9205305e2d7383cc98dacb078133de5f6fb6bed2ef26ba92cea28aafc3b9948dd9ae5559e8bd6920b8cea462aa445ca6a95e0e7ba52961b181c79e73bd581821df2b10173727a810c92b83b5ba4a0403eb710d2ca10689a35bec6c3a708e9e92f7d78ff3c5d9989574b00c6736f84c199256e76e19e78f0c98a9d580b4a658c84fc8f2096c2fbea8f5f8c59d0fdacb3be2802ef802abbecb3aba4acaac69a0e965abd8981e9896b1f6ef9d60f7a164b371af869fd0e48073742825e9434fc54da837e120266d53302954843538ea7c6c3dbfb4ff3b2fdbe244437f2a153ccf7bdb4c92aa08102d4f3cff2ae5ef86fab4653595e6a5837fa2f3e29f27a9cde5966843fb847a4a61f1e76c281fe8bb2b0a181d096100db5a1a5ce7a910238251a43ca556712eaadea167fb4d7d75825e440f3ecd782036d7574df8bceacb397abefc5f5254d2722215c53ff54af8299aaaad642c6d72a14d27882d9bbd539e1cc7a527526ba89b8c037ad09120e98ab042d3e8652b31ae0e478516bfaf88efca9f3676ffe99d2819dcaeb7610a626695f53117665d267d3f7abebd6bbd6733f645c72c389f03855bdf1e4b8075b516569b118233a0f0971d24b83113c0b096f5216a207ca99a7cddc81c130923fe3d91e7508c9ac5f2e914ff5dccab9e558566fa14efb34ac98d878580814b94b73acbfde9072f30b881f7f0fff42d4045d1ace6322d86a97d164aa84d93a60498065cc7c20e636f5862dc81531a88c60305a2e59a985be327a6902e4bed986dbf4a0b50c217af0ea7fdf9ab37f9ea1a1aaa72f54cf40154ea9b269f1a7c09f9f43245109431a175d50e2db0132337baa0ef97eed0fcf20489da36b79a1172faccc2f7ded7c60e00694282d93359c4682135642bc81f433574aa8ef0c97b4ade7ca372c5ffc23c7eddd839bab4e0f14d6df15c9dbeab176bec8b5701cf054eb3072f6dadc98f88819042bf10c407516ee58bce33fbe3b3d86a54255e577db4598e30a135361528c101683a5fcde7e8ba53f3456254be8f45fe3a56120ae96ea3773631fcb3873aa3abd91bcff00bd38bd43697a2e789e00da6077482e7b1b1a677b5afae4c54e6cbdf7377b694eb7d7a5b913476a5be923322d3de06060fd5e819635232a2cf4f0731da13b8546d1d6d4f8d75b9fce6c2341a71b0ea6f780df54bfdb0dd5cd9855179f602f9172307c7268724c3618e6817abd793adc214a0dc0bc616816632f27ea336fb56dfd").unwrap());
@@ -592,4 +617,59 @@ mod tests {
                let onion_packet_5 = super::encrypt_failure_packet(&onion_keys[0].shared_secret[..], &onion_packet_4.data[..]);
                assert_eq!(onion_packet_5.data, hex::decode("9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d").unwrap());
        }
+
+       struct RawOnionHopData {
+               data: Vec<u8>
+       }
+       impl RawOnionHopData {
+               fn new(orig: msgs::OnionHopData) -> Self {
+                       Self { data: orig.encode() }
+               }
+       }
+       impl Writeable for RawOnionHopData {
+               fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+                       writer.write_all(&self.data[..])
+               }
+       }
+
+       #[test]
+       fn variable_length_onion_vectors() {
+               // Packet creation test vectors from BOLT 4 (as of this writing at
+               // bolt04/onion-test-multi-frame.json in the spec repo).
+               // Note that we use he RawOnionHopData for everything except Legacy hops, as even the hops
+               // with "type": "tlv" are not valid TLV (they were for a previous version of TLV that
+               // didn't move forward), and, thus, cannot be directly represented in our in-memory enums.
+               let onion_keys = build_test_onion_keys();
+
+               let payloads = vec!(
+                       RawOnionHopData::new(msgs::OnionHopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
+                                       short_channel_id: 0,
+                               },
+                               amt_to_forward: 0,
+                               outgoing_cltv_value: 0,
+                       }),
+                       RawOnionHopData {
+                               data: hex::decode("140101010101010101000000000000000100000001").unwrap(),
+                       },
+                       RawOnionHopData {
+                               data: hex::decode("fd0100000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff").unwrap(),
+                       },
+                       RawOnionHopData {
+                               data: hex::decode("140303030303030303000000000000000300000003").unwrap(),
+                       },
+                       RawOnionHopData::new(msgs::OnionHopData {
+                               format: msgs::OnionHopDataFormat::Legacy {
+                                       short_channel_id: 0x0404040404040404,
+                               },
+                               amt_to_forward: 4,
+                               outgoing_cltv_value: 4,
+                       }),
+               );
+
+               let packet = super::construct_onion_packet_with_init_noise(payloads, onion_keys, [0; super::ONION_DATA_LEN], &PaymentHash([0x42; 32]));
+               // Just check the final packet encoding, as it includes all the per-hop vectors in it
+               // anyway...
+               assert_eq!(packet.encode(), hex::decode("0002eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619e5f14350c2a76fc232b5e46d421e9615471ab9e0bc887beff8c95fdb878f7b3a71a060daf367132b378b3a3883c0e2c0e026b8900b2b5cdbc784e1a3bb913f88a9c50f7d61ab590531cf08000178a333a347f8b4072ed056f820f77774345e183a342ec4729f3d84accf515e88adddb85ecc08daba68404bae9a8e8d7178977d7094a1ae549f89338c0777551f874159eb42d3a59fb9285ad4e24883f27de23942ec966611e99bee1cee503455be9e8e642cef6cef7b9864130f692283f8a973d47a8f1c1726b6e59969385975c766e35737c8d76388b64f748ee7943ffb0e2ee45c57a1abc40762ae598723d21bd184e2b338f68ebff47219357bd19cd7e01e2337b806ef4d717888e129e59cd3dc31e6201ccb2fd6d7499836f37a993262468bcb3a4dcd03a22818aca49c6b7b9b8e9e870045631d8e039b066ff86e0d1b7291f71cefa7264c70404a8e538b566c17ccc5feab231401e6c08a01bd5edfc1aa8e3e533b96e82d1f91118d508924b923531929aea889fcdf050597c681185f336b1da63b0939aa2b7c50b21b5eb7b6ad66c81fab98a3cdf73f658149e7e9ced4edde5d38c9b8f92e16f6b4ab13d7fca6a0e4ecc9f9de611a90da6e99c39551094c56e3196f282c5dffd9fc4b2fc12f3bca8e6fe47eb45fbdd3be21a8a8d200797eae3c9a0497132f92410d804977408494dff49dd3d8bce248e0b74fd9e6f0f7102c25ddfa02bd9ad9f746abbfa337ef811d5345a9e16b60de1767b209645ba40bd1f9a5f75bc04feca9b27c5554be4fe83fac2cb83aa447a817bb85ae966c68b420063833fada375e2f515965e687a45699632902672c654d1d18d7bcbf55e8fa57f63f2da449f8e1e606e8722df081e5f193fc4179feb99ad22819afdeef211f7c54afdba92aeef0c00b7bc2b65a4813c01f907a8377585708f2d4c940a25328e585714c8ded0a9a4d7a6de1027c1cb7a0198cd3db68b58c0704dfd0cfbe624e9cd18cc0ae5d96697bb476708b9ee0403d211e64e0d5a7683a7a9a140c02f0ff1c6e67a302941b4052bdea8a63e70a3ad62c5b89c698f1fd3c7685cb49705096cad702d02d93bcb1c27a409f4c9bddec001205ca4a2740f19b50900be81c7e847f1a863deea8d35701f1355cad8db57b1d4eb2ab4e29587734785abfb46ddede71928213d7d089dfdeda052827f459f1688cc0935bd47e7bcec27427c8376dcce7e22699567c0d145f8a7db33f6758815f1f15f9f7a9760dec4f34ae095edda4c64e9735bdd029c4e32c2ee31ba47ec5e6bdb97813d52dbd15b4e0b7a2c7f790ae64104d99f38c127f0a093288fa34144adb16b8968d4fa7656fcec99de8503dd46d3b03620a71c7cd085364abd30dccf7fbda25a1cdc102600149c9af1c97aa0372cd2e1909f28ac5c686f432b310e79528c9b8b9e8f314c1e74621ce6308ad2278b81d460892e0d9dd38b7c76d58be6dfd10ae7583ee1e7ef5b3f6f78dc60af0950df1b00cc55b6d178ba2e476bea0eaeef49323b83f05804159e7aef4eed4cc60dd07be76f067dfd0bcfb0b806b69ba921336a20c43c832d0cab8fa3ddeb29e3bf07b0d98a112eb07802756235a49d44a8b82a950d84e95e01971f0e106ccb337f07384e21620e0ad39e16ed9edca123226cf55ac44f449eeb53e38a7f27d101806e4823e4efcc887414240ee6826c4a5cb1c6443ad36ebf905a435c1d9054e54173911b17b5b40f60b3d9fd5f12eac54ca1e20191f5f18544d5fd3d665e9bcef96fb44b76110aa64d9db4c86c9513cbdad546538e8aec521fbe83ceac5e74a15629f1ed0b870a1d0d1e5680b6d6100d1bd3f3b9043bd35b8919c4088f1949b8be89e4701eb870f8ed64fafa446c78df3ea").unwrap());
+       }
 }
index 327664c7fc2420128b0d9d8be3d99b9cf8d8ee7b..44d08030062fb47b337b879901b6967a73776d58 100644 (file)
@@ -12,13 +12,13 @@ use ln::features::InitFeatures;
 use ln::msgs;
 use ln::msgs::ChannelMessageHandler;
 use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager};
+use util::ser::VecWriter;
 use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep};
 use ln::wire;
 use ln::wire::Encode;
 use util::byte_utils;
 use util::events::{MessageSendEvent, MessageSendEventsProvider};
 use util::logger::Logger;
-use util::ser::Writer;
 
 use std::collections::{HashMap,hash_map,HashSet,LinkedList};
 use std::sync::{Arc, Mutex};
@@ -189,21 +189,9 @@ pub struct PeerManager<Descriptor: SocketDescriptor, CM: Deref> where CM::Target
        peer_counter_low: AtomicUsize,
        peer_counter_high: AtomicUsize,
 
-       initial_syncs_sent: AtomicUsize,
        logger: Arc<Logger>,
 }
 
-struct VecWriter(Vec<u8>);
-impl Writer for VecWriter {
-       fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
-               self.0.extend_from_slice(buf);
-               Ok(())
-       }
-       fn size_hint(&mut self, size: usize) {
-               self.0.reserve_exact(size);
-       }
-}
-
 macro_rules! encode_msg {
        ($msg: expr) => {{
                let mut buffer = VecWriter(Vec::new());
@@ -212,9 +200,6 @@ macro_rules! encode_msg {
        }}
 }
 
-//TODO: Really should do something smarter for this
-const INITIAL_SYNCS_TO_SEND: usize = 5;
-
 /// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds.
 /// PeerIds may repeat, but only after disconnect_event() has been called.
 impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where CM::Target: msgs::ChannelMessageHandler {
@@ -236,7 +221,6 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
                        ephemeral_key_midstate,
                        peer_counter_low: AtomicUsize::new(0),
                        peer_counter_high: AtomicUsize::new(0),
-                       initial_syncs_sent: AtomicUsize::new(0),
                        logger,
                }
        }
@@ -549,8 +533,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
                                                                        peer.their_node_id = Some(their_node_id);
                                                                        insert_node_id!();
                                                                        let mut features = InitFeatures::supported();
-                                                                       if self.initial_syncs_sent.load(Ordering::Acquire) < INITIAL_SYNCS_TO_SEND {
-                                                                               self.initial_syncs_sent.fetch_add(1, Ordering::AcqRel);
+                                                                       if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) {
                                                                                features.set_initial_routing_sync();
                                                                        }
 
@@ -648,8 +631,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref> PeerManager<Descriptor, CM> where
 
                                                                                                if !peer.outbound {
                                                                                                        let mut features = InitFeatures::supported();
-                                                                                                       if self.initial_syncs_sent.load(Ordering::Acquire) < INITIAL_SYNCS_TO_SEND {
-                                                                                                               self.initial_syncs_sent.fetch_add(1, Ordering::AcqRel);
+                                                                                                       if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) {
                                                                                                                features.set_initial_routing_sync();
                                                                                                        }
 
index 0025656087bce2228a7376f2af906a5e0c131e7d..36e68462c392d9d8983535ef0faa0e77c7040b2f 100644 (file)
@@ -22,6 +22,7 @@ use util::logger::Logger;
 
 use std::cmp;
 use std::sync::{RwLock,Arc};
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::collections::{HashMap,BinaryHeap,BTreeMap};
 use std::collections::btree_map::Entry as BtreeEntry;
 use std;
@@ -347,6 +348,7 @@ pub struct RouteHint {
 pub struct Router {
        secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
        network_map: RwLock<NetworkMap>,
+       full_syncs_requested: AtomicUsize,
        chain_monitor: Arc<ChainWatchInterface>,
        logger: Arc<Logger>,
 }
@@ -390,6 +392,7 @@ impl<R: ::std::io::Read> ReadableArgs<R, RouterReadArgs> for Router {
                Ok(Router {
                        secp_ctx: Secp256k1::verification_only(),
                        network_map: RwLock::new(network_map),
+                       full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor: args.chain_monitor,
                        logger: args.logger,
                })
@@ -406,6 +409,7 @@ macro_rules! secp_verify_sig {
 }
 
 impl RoutingMessageHandler for Router {
+
        fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, LightningError> {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
                secp_verify_sig!(self.secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id);
@@ -698,6 +702,17 @@ impl RoutingMessageHandler for Router {
                }
                result
        }
+
+       fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool {
+               //TODO: Determine whether to request a full sync based on the network map.
+               const FULL_SYNCS_TO_REQUEST: usize = 5;
+               if self.full_syncs_requested.load(Ordering::Acquire) < FULL_SYNCS_TO_REQUEST {
+                       self.full_syncs_requested.fetch_add(1, Ordering::AcqRel);
+                       true
+               } else {
+                       false
+               }
+       }
 }
 
 #[derive(Eq, PartialEq)]
@@ -750,6 +765,7 @@ impl Router {
                                our_node_id: our_pubkey,
                                nodes: nodes,
                        }),
+                       full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor,
                        logger,
                }
@@ -1035,7 +1051,7 @@ mod tests {
        use ln::channelmanager;
        use ln::router::{Router,NodeInfo,NetworkMap,ChannelInfo,DirectionalChannelInfo,RouteHint};
        use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
-       use ln::msgs::{LightningError, ErrorAction};
+       use ln::msgs::{ErrorAction, LightningError, RoutingMessageHandler};
        use util::test_utils;
        use util::test_utils::TestVecWriter;
        use util::logger::Logger;
@@ -1048,17 +1064,23 @@ mod tests {
        use hex;
 
        use secp256k1::key::{PublicKey,SecretKey};
+       use secp256k1::All;
        use secp256k1::Secp256k1;
 
        use std::sync::Arc;
 
-       #[test]
-       fn route_test() {
+       fn create_router() -> (Secp256k1<All>, PublicKey, Router) {
                let secp_ctx = Secp256k1::new();
                let our_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap());
                let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
                let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
                let router = Router::new(our_id, chain_monitor, Arc::clone(&logger));
+               (secp_ctx, our_id, router)
+       }
+
+       #[test]
+       fn route_test() {
+               let (secp_ctx, our_id, router) = create_router();
 
                // Build network from our_id to node8:
                //
@@ -1823,4 +1845,17 @@ mod tests {
                        assert!(<NetworkMap>::read(&mut ::std::io::Cursor::new(&w.0)).unwrap() == *network);
                }
        }
+
+       #[test]
+       fn request_full_sync_finite_times() {
+               let (secp_ctx, _, router) = create_router();
+               let node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()[..]).unwrap());
+
+               assert!(router.should_request_full_sync(&node_id));
+               assert!(router.should_request_full_sync(&node_id));
+               assert!(router.should_request_full_sync(&node_id));
+               assert!(router.should_request_full_sync(&node_id));
+               assert!(router.should_request_full_sync(&node_id));
+               assert!(!router.should_request_full_sync(&node_id));
+       }
 }
index c96577da02c4a31ec1a3827b0ac38d9003e1a831..8a8205f8dac593b6b41bd71369f2e749c85261f2 100644 (file)
@@ -9,6 +9,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::io;
+
 #[cfg(not(feature = "fuzztarget"))]
 mod real_chacha {
        use std::cmp;
@@ -54,6 +56,8 @@ mod real_chacha {
                }
        }
 
+       const BLOCK_SIZE: usize = 64;
+
        #[derive(Clone,Copy)]
        struct ChaChaState {
                a: u32x4,
@@ -65,7 +69,7 @@ mod real_chacha {
        #[derive(Copy)]
        pub struct ChaCha20 {
                state  : ChaChaState,
-               output : [u8; 64],
+               output : [u8; BLOCK_SIZE],
                offset : usize,
        }
 
@@ -133,7 +137,7 @@ mod real_chacha {
                        assert!(key.len() == 16 || key.len() == 32);
                        assert!(nonce.len() == 8 || nonce.len() == 12);
 
-                       ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; 64], offset: 64 }
+                       ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
                }
 
                fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
@@ -195,7 +199,7 @@ mod real_chacha {
                        }
                }
 
-               // put the the next 64 keystream bytes into self.output
+               // put the the next BLOCK_SIZE keystream bytes into self.output
                fn update(&mut self) {
                        let mut state = self.state;
 
@@ -232,12 +236,12 @@ mod real_chacha {
                        while i < len {
                                // If there is no keystream available in the output buffer,
                                // generate the next block.
-                               if self.offset == 64 {
+                               if self.offset == BLOCK_SIZE {
                                        self.update();
                                }
 
                                // Process the min(available keystream, remaining input length).
-                               let count = cmp::min(64 - self.offset, len - i);
+                               let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
                                // explicitly assert lengths to avoid bounds checks:
                                assert!(output.len() >= i + count);
                                assert!(input.len() >= i + count);
@@ -249,6 +253,29 @@ mod real_chacha {
                                self.offset += count;
                        }
                }
+
+               pub fn process_in_place(&mut self, input_output: &mut [u8]) {
+                       let len = input_output.len();
+                       let mut i = 0;
+                       while i < len {
+                               // If there is no keystream available in the output buffer,
+                               // generate the next block.
+                               if self.offset == BLOCK_SIZE {
+                                       self.update();
+                               }
+
+                               // Process the min(available keystream, remaining input length).
+                               let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
+                               // explicitly assert lengths to avoid bounds checks:
+                               assert!(input_output.len() >= i + count);
+                               assert!(self.output.len() >= self.offset + count);
+                               for j in 0..count {
+                                       input_output[i + j] ^= self.output[self.offset + j];
+                               }
+                               i += count;
+                               self.offset += count;
+                       }
+               }
        }
 }
 #[cfg(not(feature = "fuzztarget"))]
@@ -268,11 +295,27 @@ mod fuzzy_chacha {
                pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
                        output.copy_from_slice(input);
                }
+
+               pub fn process_in_place(&mut self, _input_output: &mut [u8]) {}
        }
 }
 #[cfg(feature = "fuzztarget")]
 pub use self::fuzzy_chacha::ChaCha20;
 
+pub(crate) struct ChaChaReader<'a, R: io::Read> {
+       pub chacha: &'a mut ChaCha20,
+       pub read: R,
+}
+impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> {
+       fn read(&mut self, dest: &mut [u8]) -> Result<usize, io::Error> {
+               let res = self.read.read(dest)?;
+               if res > 0 {
+                       self.chacha.process_in_place(&mut dest[0..res]);
+               }
+               Ok(res)
+       }
+}
+
 #[cfg(test)]
 mod test {
        use std::iter::repeat;
index 7e4f789097940824a8ebfb3f1bb9f054cf3e145d..1b98e341fad6f35e94e555528865ed1cee508b5a 100644 (file)
@@ -6,6 +6,7 @@ use std::io::{Read, Write};
 use std::collections::HashMap;
 use std::hash::Hash;
 use std::sync::Mutex;
+use std::cmp;
 
 use secp256k1::Signature;
 use secp256k1::key::{PublicKey, SecretKey};
@@ -56,7 +57,7 @@ impl<'a, W: Writer + 'a> Write for WriterWriteAdaptor<'a, W> {
        }
 }
 
-struct VecWriter(Vec<u8>);
+pub(crate) struct VecWriter(pub Vec<u8>);
 impl Writer for VecWriter {
        fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
                self.0.extend_from_slice(buf);
@@ -67,6 +68,85 @@ impl Writer for VecWriter {
        }
 }
 
+/// Writer that only tracks the amount of data written - useful if you need to calculate the length
+/// of some data when serialized but don't yet need the full data.
+pub(crate) struct LengthCalculatingWriter(pub usize);
+impl Writer for LengthCalculatingWriter {
+       #[inline]
+       fn write_all(&mut self, buf: &[u8]) -> Result<(), ::std::io::Error> {
+               self.0 += buf.len();
+               Ok(())
+       }
+       #[inline]
+       fn size_hint(&mut self, _size: usize) {}
+}
+
+/// Essentially std::io::Take but a bit simpler and with a method to walk the underlying stream
+/// forward to ensure we always consume exactly the fixed length specified.
+pub(crate) struct FixedLengthReader<R: Read> {
+       read: R,
+       bytes_read: u64,
+       total_bytes: u64,
+}
+impl<R: Read> FixedLengthReader<R> {
+       pub fn new(read: R, total_bytes: u64) -> Self {
+               Self { read, bytes_read: 0, total_bytes }
+       }
+
+       pub fn bytes_remain(&mut self) -> bool {
+               self.bytes_read != self.total_bytes
+       }
+
+       pub fn eat_remaining(&mut self) -> Result<(), DecodeError> {
+               ::std::io::copy(self, &mut ::std::io::sink()).unwrap();
+               if self.bytes_read != self.total_bytes {
+                       Err(DecodeError::ShortRead)
+               } else {
+                       Ok(())
+               }
+       }
+}
+impl<R: Read> Read for FixedLengthReader<R> {
+       fn read(&mut self, dest: &mut [u8]) -> Result<usize, ::std::io::Error> {
+               if self.total_bytes == self.bytes_read {
+                       Ok(0)
+               } else {
+                       let read_len = cmp::min(dest.len() as u64, self.total_bytes - self.bytes_read);
+                       match self.read.read(&mut dest[0..(read_len as usize)]) {
+                               Ok(v) => {
+                                       self.bytes_read += v as u64;
+                                       Ok(v)
+                               },
+                               Err(e) => Err(e),
+                       }
+               }
+       }
+}
+
+/// A Read which tracks whether any bytes have been read at all. This allows us to distinguish
+/// between "EOF reached before we started" and "EOF reached mid-read".
+pub(crate) struct ReadTrackingReader<R: Read> {
+       read: R,
+       pub have_read: bool,
+}
+impl<R: Read> ReadTrackingReader<R> {
+       pub fn new(read: R) -> Self {
+               Self { read, have_read: false }
+       }
+}
+impl<R: Read> Read for ReadTrackingReader<R> {
+       fn read(&mut self, dest: &mut [u8]) -> Result<usize, ::std::io::Error> {
+               match self.read.read(dest) {
+                       Ok(0) => Ok(0),
+                       Ok(len) => {
+                               self.have_read = true;
+                               Ok(len)
+                       },
+                       Err(e) => Err(e),
+               }
+       }
+}
+
 /// A trait that various rust-lightning types implement allowing them to be written out to a Writer
 pub trait Writeable {
        /// Writes self out to the given Writer
@@ -125,6 +205,76 @@ impl<R: Read> Readable<R> for U48 {
        }
 }
 
+/// Lightning TLV uses a custom variable-length integer called BigSize. It is similar to Bitcoin's
+/// variable-length integers except that it is serialized in big-endian instead of little-endian.
+///
+/// Like Bitcoin's variable-length integer, it exhibits ambiguity in that certain values can be
+/// encoded in several different ways, which we must check for at deserialization-time. Thus, if
+/// you're looking for an example of a variable-length integer to use for your own project, move
+/// along, this is a rather poor design.
+pub(crate) struct BigSize(pub u64);
+impl Writeable for BigSize {
+       #[inline]
+       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+               match self.0 {
+                       0...0xFC => {
+                               (self.0 as u8).write(writer)
+                       },
+                       0xFD...0xFFFF => {
+                               0xFDu8.write(writer)?;
+                               (self.0 as u16).write(writer)
+                       },
+                       0x10000...0xFFFFFFFF => {
+                               0xFEu8.write(writer)?;
+                               (self.0 as u32).write(writer)
+                       },
+                       _ => {
+                               0xFFu8.write(writer)?;
+                               (self.0 as u64).write(writer)
+                       },
+               }
+       }
+}
+impl<R: Read> Readable<R> for BigSize {
+       #[inline]
+       fn read(reader: &mut R) -> Result<BigSize, DecodeError> {
+               let n: u8 = Readable::read(reader)?;
+               match n {
+                       0xFF => {
+                               let x: u64 = Readable::read(reader)?;
+                               if x < 0x100000000 {
+                                       Err(DecodeError::InvalidValue)
+                               } else {
+                                       Ok(BigSize(x))
+                               }
+                       }
+                       0xFE => {
+                               let x: u32 = Readable::read(reader)?;
+                               if x < 0x10000 {
+                                       Err(DecodeError::InvalidValue)
+                               } else {
+                                       Ok(BigSize(x as u64))
+                               }
+                       }
+                       0xFD => {
+                               let x: u16 = Readable::read(reader)?;
+                               if x < 0xFD {
+                                       Err(DecodeError::InvalidValue)
+                               } else {
+                                       Ok(BigSize(x as u64))
+                               }
+                       }
+                       n => Ok(BigSize(n as u64))
+               }
+       }
+}
+
+/// In TLV we occasionally send fields which only consist of, or potentially end with, a
+/// variable-length integer which is simply truncated by skipping high zero bytes. This type
+/// encapsulates such integers implementing Readable/Writeable for them.
+#[cfg_attr(test, derive(PartialEq, Debug))]
+pub(crate) struct HighZeroBytesDroppedVarInt<T>(pub T);
+
 macro_rules! impl_writeable_primitive {
        ($val_type:ty, $meth_write:ident, $len: expr, $meth_read:ident) => {
                impl Writeable for $val_type {
@@ -133,6 +283,13 @@ macro_rules! impl_writeable_primitive {
                                writer.write_all(&$meth_write(*self))
                        }
                }
+               impl Writeable for HighZeroBytesDroppedVarInt<$val_type> {
+                       #[inline]
+                       fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
+                               // Skip any full leading 0 bytes when writing (in BE):
+                               writer.write_all(&$meth_write(self.0)[(self.0.leading_zeros()/8) as usize..$len])
+                       }
+               }
                impl<R: Read> Readable<R> for $val_type {
                        #[inline]
                        fn read(reader: &mut R) -> Result<$val_type, DecodeError> {
@@ -141,6 +298,30 @@ macro_rules! impl_writeable_primitive {
                                Ok($meth_read(&buf))
                        }
                }
+               impl<R: Read> Readable<R> for HighZeroBytesDroppedVarInt<$val_type> {
+                       #[inline]
+                       fn read(reader: &mut R) -> Result<HighZeroBytesDroppedVarInt<$val_type>, DecodeError> {
+                               // We need to accept short reads (read_len == 0) as "EOF" and handle them as simply
+                               // the high bytes being dropped. To do so, we start reading into the middle of buf
+                               // and then convert the appropriate number of bytes with extra high bytes out of
+                               // buf.
+                               let mut buf = [0; $len*2];
+                               let mut read_len = reader.read(&mut buf[$len..])?;
+                               let mut total_read_len = read_len;
+                               while read_len != 0 && total_read_len != $len {
+                                       read_len = reader.read(&mut buf[($len + total_read_len)..])?;
+                                       total_read_len += read_len;
+                               }
+                               if total_read_len == 0 || buf[$len] != 0 {
+                                       let first_byte = $len - ($len - total_read_len);
+                                       Ok(HighZeroBytesDroppedVarInt($meth_read(&buf[first_byte..first_byte + $len])))
+                               } else {
+                                       // If the encoding had extra zero bytes, return a failure even though we know
+                                       // what they meant (as the TLV test vectors require this)
+                                       Err(DecodeError::InvalidValue)
+                               }
+                       }
+               }
        }
 }
 
index 48e87b3bc2108a35b97282981b8738b5b87a93fb..766d4ee2d78ff90a774049e8cc13d9731b490d18 100644 (file)
@@ -1,3 +1,109 @@
+macro_rules! encode_tlv {
+       ($stream: expr, {$(($type: expr, $field: expr)),*}) => { {
+               use util::ser::{BigSize, LengthCalculatingWriter};
+               $(
+                       BigSize($type).write($stream)?;
+                       let mut len_calc = LengthCalculatingWriter(0);
+                       $field.write(&mut len_calc)?;
+                       BigSize(len_calc.0 as u64).write($stream)?;
+                       $field.write($stream)?;
+               )*
+       } }
+}
+
+macro_rules! encode_varint_length_prefixed_tlv {
+       ($stream: expr, {$(($type: expr, $field: expr)),*}) => { {
+               use util::ser::{BigSize, LengthCalculatingWriter};
+               let mut len = LengthCalculatingWriter(0);
+               {
+                       $(
+                               BigSize($type).write(&mut len)?;
+                               let mut field_len = LengthCalculatingWriter(0);
+                               $field.write(&mut field_len)?;
+                               BigSize(field_len.0 as u64).write(&mut len)?;
+                               len.0 += field_len.0;
+                       )*
+               }
+
+               BigSize(len.0 as u64).write($stream)?;
+               encode_tlv!($stream, {
+                       $(($type, $field)),*
+               });
+       } }
+}
+
+macro_rules! decode_tlv {
+       ($stream: expr, {$(($reqtype: expr, $reqfield: ident)),*}, {$(($type: expr, $field: ident)),*}) => { {
+               use ln::msgs::DecodeError;
+               let mut last_seen_type: Option<u64> = None;
+               'tlv_read: loop {
+                       use util::ser;
+
+                       // First decode the type of this TLV:
+                       let typ: ser::BigSize = {
+                               // We track whether any bytes were read during the consensus_decode call to
+                               // determine whether we should break or return ShortRead if we get an
+                               // UnexpectedEof. This should in every case be largely cosmetic, but its nice to
+                               // pass the TLV test vectors exactly, which requre this distinction.
+                               let mut tracking_reader = ser::ReadTrackingReader::new($stream);
+                               match ser::Readable::read(&mut tracking_reader) {
+                                       Err(DecodeError::ShortRead) => {
+                                               if !tracking_reader.have_read {
+                                                       break 'tlv_read
+                                               } else {
+                                                       Err(DecodeError::ShortRead)?
+                                               }
+                                       },
+                                       Err(e) => Err(e)?,
+                                       Ok(t) => t,
+                               }
+                       };
+
+                       // Types must be unique and monotonically increasing:
+                       match last_seen_type {
+                               Some(t) if typ.0 <= t => {
+                                       Err(DecodeError::InvalidValue)?
+                               },
+                               _ => {},
+                       }
+                       // As we read types, make sure we hit every required type:
+                       $(if (last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype) && typ.0 > $reqtype {
+                               Err(DecodeError::InvalidValue)?
+                       })*
+                       last_seen_type = Some(typ.0);
+
+                       // Finally, read the length and value itself:
+                       let length: ser::BigSize = Readable::read($stream)?;
+                       let mut s = ser::FixedLengthReader::new($stream, length.0);
+                       match typ.0 {
+                               $($reqtype => {
+                                       $reqfield = ser::Readable::read(&mut s)?;
+                                       if s.bytes_remain() {
+                                               s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes
+                                               Err(DecodeError::InvalidValue)?
+                                       }
+                               },)*
+                               $($type => {
+                                       $field = Some(ser::Readable::read(&mut s)?);
+                                       if s.bytes_remain() {
+                                               s.eat_remaining()?; // Return ShortRead if there's actually not enough bytes
+                                               Err(DecodeError::InvalidValue)?
+                                       }
+                               },)*
+                               x if x % 2 == 0 => {
+                                       Err(DecodeError::UnknownRequiredFeature)?
+                               },
+                               _ => {},
+                       }
+                       s.eat_remaining()?;
+               }
+               // Make sure we got to each required type after we've read every TLV:
+               $(if last_seen_type.is_none() || last_seen_type.unwrap() < $reqtype {
+                       Err(DecodeError::InvalidValue)?
+               })*
+       } }
+}
+
 macro_rules! impl_writeable {
        ($st:ident, $len: expr, {$($field:ident),*}) => {
                impl ::util::ser::Writeable for $st {
@@ -40,3 +146,224 @@ macro_rules! impl_writeable_len_match {
                }
        }
 }
+
+#[cfg(test)]
+mod tests {
+       use std::io::{Cursor, Read};
+       use ln::msgs::DecodeError;
+       use util::ser::{Readable, Writeable, HighZeroBytesDroppedVarInt, VecWriter};
+       use secp256k1::PublicKey;
+
+       // The BOLT TLV test cases don't include any tests which use our "required-value" logic since
+       // the encoding layer in the BOLTs has no such concept, though it makes our macros easier to
+       // work with so they're baked into the decoder. Thus, we have a few additional tests below
+       fn tlv_reader(s: &[u8]) -> Result<(u64, u32, Option<u32>), DecodeError> {
+               let mut s = Cursor::new(s);
+               let mut a: u64 = 0;
+               let mut b: u32 = 0;
+               let mut c: Option<u32> = None;
+               decode_tlv!(&mut s, {(2, a), (3, b)}, {(4, c)});
+               Ok((a, b, c))
+       }
+
+       #[test]
+       fn tlv_v_short_read() {
+               // We only expect a u32 for type 3 (which we are given), but the L says its 8 bytes.
+               if let Err(DecodeError::ShortRead) = tlv_reader(&::hex::decode(
+                               concat!("0100", "0208deadbeef1badbeef", "0308deadbeef")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+       }
+
+       #[test]
+       fn tlv_types_out_of_order() {
+               if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode(
+                               concat!("0100", "0304deadbeef", "0208deadbeef1badbeef")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+               // ...even if its some field we don't understand
+               if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode(
+                               concat!("0208deadbeef1badbeef", "0100", "0304deadbeef")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+       }
+
+       #[test]
+       fn tlv_req_type_missing_or_extra() {
+               // It's also bad if they included even fields we don't understand
+               if let Err(DecodeError::UnknownRequiredFeature) = tlv_reader(&::hex::decode(
+                               concat!("0100", "0208deadbeef1badbeef", "0304deadbeef", "0600")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+               // ... or if they're missing fields we need
+               if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode(
+                               concat!("0100", "0208deadbeef1badbeef")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+               // ... even if that field is even
+               if let Err(DecodeError::InvalidValue) = tlv_reader(&::hex::decode(
+                               concat!("0304deadbeef", "0500")
+                               ).unwrap()[..]) {
+               } else { panic!(); }
+       }
+
+       #[test]
+       fn tlv_simple_good_cases() {
+               assert_eq!(tlv_reader(&::hex::decode(
+                               concat!("0208deadbeef1badbeef", "03041bad1dea")
+                               ).unwrap()[..]).unwrap(),
+                       (0xdeadbeef1badbeef, 0x1bad1dea, None));
+               assert_eq!(tlv_reader(&::hex::decode(
+                               concat!("0208deadbeef1badbeef", "03041bad1dea", "040401020304")
+                               ).unwrap()[..]).unwrap(),
+                       (0xdeadbeef1badbeef, 0x1bad1dea, Some(0x01020304)));
+       }
+
+       impl<R: Read> Readable<R> for (PublicKey, u64, u64) {
+               #[inline]
+               fn read(reader: &mut R) -> Result<(PublicKey, u64, u64), DecodeError> {
+                       Ok((Readable::read(reader)?, Readable::read(reader)?, Readable::read(reader)?))
+               }
+       }
+
+       // BOLT TLV test cases
+       fn tlv_reader_n1(s: &[u8]) -> Result<(Option<HighZeroBytesDroppedVarInt<u64>>, Option<u64>, Option<(PublicKey, u64, u64)>, Option<u16>), DecodeError> {
+               let mut s = Cursor::new(s);
+               let mut tlv1: Option<HighZeroBytesDroppedVarInt<u64>> = None;
+               let mut tlv2: Option<u64> = None;
+               let mut tlv3: Option<(PublicKey, u64, u64)> = None;
+               let mut tlv4: Option<u16> = None;
+               decode_tlv!(&mut s, {}, {(1, tlv1), (2, tlv2), (3, tlv3), (254, tlv4)});
+               Ok((tlv1, tlv2, tlv3, tlv4))
+       }
+
+       #[test]
+       fn bolt_tlv_bogus_stream() {
+               macro_rules! do_test {
+                       ($stream: expr, $reason: ident) => {
+                               if let Err(DecodeError::$reason) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) {
+                               } else { panic!(); }
+                       }
+               }
+
+               // TLVs from the BOLT test cases which should not decode as either n1 or n2
+               do_test!(concat!("fd01"), ShortRead);
+               do_test!(concat!("fd0001", "00"), InvalidValue);
+               do_test!(concat!("fd0101"), ShortRead);
+               do_test!(concat!("0f", "fd"), ShortRead);
+               do_test!(concat!("0f", "fd26"), ShortRead);
+               do_test!(concat!("0f", "fd2602"), ShortRead);
+               do_test!(concat!("0f", "fd0001", "00"), InvalidValue);
+               do_test!(concat!("0f", "fd0201", "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"), ShortRead);
+
+               do_test!(concat!("12", "00"), UnknownRequiredFeature);
+               do_test!(concat!("fd0102", "00"), UnknownRequiredFeature);
+               do_test!(concat!("fe01000002", "00"), UnknownRequiredFeature);
+               do_test!(concat!("ff0100000000000002", "00"), UnknownRequiredFeature);
+       }
+
+       #[test]
+       fn bolt_tlv_bogus_n1_stream() {
+               macro_rules! do_test {
+                       ($stream: expr, $reason: ident) => {
+                               if let Err(DecodeError::$reason) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) {
+                               } else { panic!(); }
+                       }
+               }
+
+               // TLVs from the BOLT test cases which should not decode as n1
+               do_test!(concat!("01", "09", "ffffffffffffffffff"), InvalidValue);
+               do_test!(concat!("01", "01", "00"), InvalidValue);
+               do_test!(concat!("01", "02", "0001"), InvalidValue);
+               do_test!(concat!("01", "03", "000100"), InvalidValue);
+               do_test!(concat!("01", "04", "00010000"), InvalidValue);
+               do_test!(concat!("01", "05", "0001000000"), InvalidValue);
+               do_test!(concat!("01", "06", "000100000000"), InvalidValue);
+               do_test!(concat!("01", "07", "00010000000000"), InvalidValue);
+               do_test!(concat!("01", "08", "0001000000000000"), InvalidValue);
+               do_test!(concat!("02", "07", "01010101010101"), ShortRead);
+               do_test!(concat!("02", "09", "010101010101010101"), InvalidValue);
+               do_test!(concat!("03", "21", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb"), ShortRead);
+               do_test!(concat!("03", "29", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001"), ShortRead);
+               do_test!(concat!("03", "30", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb000000000000000100000000000001"), ShortRead);
+               do_test!(concat!("03", "31", "043da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"), InvalidValue);
+               do_test!(concat!("03", "32", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb0000000000000001000000000000000001"), InvalidValue);
+               do_test!(concat!("fd00fe", "00"), ShortRead);
+               do_test!(concat!("fd00fe", "01", "01"), ShortRead);
+               do_test!(concat!("fd00fe", "03", "010101"), InvalidValue);
+               do_test!(concat!("00", "00"), UnknownRequiredFeature);
+
+               do_test!(concat!("02", "08", "0000000000000226", "01", "01", "2a"), InvalidValue);
+               do_test!(concat!("02", "08", "0000000000000231", "02", "08", "0000000000000451"), InvalidValue);
+               do_test!(concat!("1f", "00", "0f", "01", "2a"), InvalidValue);
+               do_test!(concat!("1f", "00", "1f", "01", "2a"), InvalidValue);
+
+               // The last BOLT test modified to not require creating a new decoder for one trivial test.
+               do_test!(concat!("ffffffffffffffffff", "00", "01", "00"), InvalidValue);
+       }
+
+       #[test]
+       fn bolt_tlv_valid_n1_stream() {
+               macro_rules! do_test {
+                       ($stream: expr, $tlv1: expr, $tlv2: expr, $tlv3: expr, $tlv4: expr) => {
+                               if let Ok((tlv1, tlv2, tlv3, tlv4)) = tlv_reader_n1(&::hex::decode($stream).unwrap()[..]) {
+                                       assert_eq!(tlv1.map(|v| v.0), $tlv1);
+                                       assert_eq!(tlv2, $tlv2);
+                                       assert_eq!(tlv3, $tlv3);
+                                       assert_eq!(tlv4, $tlv4);
+                               } else { panic!(); }
+                       }
+               }
+
+               do_test!(concat!(""), None, None, None, None);
+               do_test!(concat!("21", "00"), None, None, None, None);
+               do_test!(concat!("fd0201", "00"), None, None, None, None);
+               do_test!(concat!("fd00fd", "00"), None, None, None, None);
+               do_test!(concat!("fd00ff", "00"), None, None, None, None);
+               do_test!(concat!("fe02000001", "00"), None, None, None, None);
+               do_test!(concat!("ff0200000000000001", "00"), None, None, None, None);
+
+               do_test!(concat!("01", "00"), Some(0), None, None, None);
+               do_test!(concat!("01", "01", "01"), Some(1), None, None, None);
+               do_test!(concat!("01", "02", "0100"), Some(256), None, None, None);
+               do_test!(concat!("01", "03", "010000"), Some(65536), None, None, None);
+               do_test!(concat!("01", "04", "01000000"), Some(16777216), None, None, None);
+               do_test!(concat!("01", "05", "0100000000"), Some(4294967296), None, None, None);
+               do_test!(concat!("01", "06", "010000000000"), Some(1099511627776), None, None, None);
+               do_test!(concat!("01", "07", "01000000000000"), Some(281474976710656), None, None, None);
+               do_test!(concat!("01", "08", "0100000000000000"), Some(72057594037927936), None, None, None);
+               do_test!(concat!("02", "08", "0000000000000226"), None, Some((0 << 30) | (0 << 5) | (550 << 0)), None, None);
+               do_test!(concat!("03", "31", "023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb00000000000000010000000000000002"),
+                       None, None, Some((
+                               PublicKey::from_slice(&::hex::decode("023da092f6980e58d2c037173180e9a465476026ee50f96695963e8efe436f54eb").unwrap()[..]).unwrap(), 1, 2)),
+                       None);
+               do_test!(concat!("fd00fe", "02", "0226"), None, None, None, Some(550));
+       }
+
+       fn do_simple_test_tlv_write() -> Result<(), ::std::io::Error> {
+               let mut stream = VecWriter(Vec::new());
+
+               stream.0.clear();
+               encode_varint_length_prefixed_tlv!(&mut stream, { (1, 1u8) });
+               assert_eq!(stream.0, ::hex::decode("03010101").unwrap());
+
+               stream.0.clear();
+               encode_varint_length_prefixed_tlv!(&mut stream, { (4, 0xabcdu16) });
+               assert_eq!(stream.0, ::hex::decode("040402abcd").unwrap());
+
+               stream.0.clear();
+               encode_varint_length_prefixed_tlv!(&mut stream, { (0xff, 0xabcdu16) });
+               assert_eq!(stream.0, ::hex::decode("06fd00ff02abcd").unwrap());
+
+               stream.0.clear();
+               encode_varint_length_prefixed_tlv!(&mut stream, { (0, 1u64), (0xff, HighZeroBytesDroppedVarInt(0u64)) });
+               assert_eq!(stream.0, ::hex::decode("0e00080000000000000001fd00ff00").unwrap());
+
+               Ok(())
+       }
+
+       #[test]
+       fn simple_test_tlv_write() {
+               do_simple_test_tlv_write().unwrap();
+       }
+}
index aa68fdb1f1aeb4991be45ade7e23a9bdef350b59..b343ac35379f17195e785d70f6f6dea9dab5829e 100644 (file)
@@ -23,7 +23,7 @@ use secp256k1::{SecretKey, PublicKey};
 use std::time::{SystemTime, UNIX_EPOCH};
 use std::sync::{Arc,Mutex};
 use std::{mem};
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 pub struct TestVecWriter(pub Vec<u8>);
 impl Writer for TestVecWriter {
@@ -81,9 +81,19 @@ impl channelmonitor::ManyChannelMonitor<EnforcingChannelKeys> for TestChannelMon
 
 pub struct TestBroadcaster {
        pub txn_broadcasted: Mutex<Vec<Transaction>>,
+       pub broadcasted_txn: Mutex<HashSet<Sha256dHash>> // Temporary field while refactoring out tx duplication
 }
 impl chaininterface::BroadcasterInterface for TestBroadcaster {
        fn broadcast_transaction(&self, tx: &Transaction) {
+               {
+                       if let Some(_) = self.broadcasted_txn.lock().unwrap().get(&tx.txid()) {
+                               // If commitment tx, HTLC-timeout or HTLC-Success, duplicate broadcast are still ok
+                               if tx.input[0].sequence == 0xfffffffd {
+                                       return;
+                               }
+                       }
+               }
+               self.broadcasted_txn.lock().unwrap().insert(tx.txid());
                self.txn_broadcasted.lock().unwrap().push(tx.clone());
        }
 }
@@ -155,6 +165,9 @@ impl msgs::RoutingMessageHandler for TestRoutingMessageHandler {
        fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec<msgs::NodeAnnouncement> {
                Vec::new()
        }
+       fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool {
+               true
+       }
 }
 
 pub struct TestLogger {