X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser.rs;h=366e6c8cb1efaef3767b0e8d4232c3763915eb20;hb=a5ecb851716bc0819586894232653ec4b5e2c67f;hp=c06293269ec0ffc28727a3d2624e92a9f95d1319;hpb=ed3a6eeefdeae40d95a9b3a6b2f3fd033b95d072;p=rust-lightning diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index c0629326..366e6c8c 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -8,18 +8,27 @@ // licenses. //! A very simple serialization framework which is used to serialize/deserialize messages as well -//! as ChannelsManagers and ChannelMonitors. - -use prelude::*; -use io::{self, Read, Write}; -use io_extras::{copy, sink}; +//! as [`ChannelManager`]s and [`ChannelMonitor`]s. +//! +//! [`ChannelManager`]: crate::ln::channelmanager::ChannelManager +//! [`ChannelMonitor`]: crate::chain::channelmonitor::ChannelMonitor + +use crate::prelude::*; +use crate::io::{self, Read, Seek, Write}; +use crate::io_extras::{copy, sink}; use core::hash::Hash; -use sync::Mutex; +use crate::sync::Mutex; use core::cmp; +use core::convert::TryFrom; +use core::ops::Deref; + +use alloc::collections::BTreeMap; -use bitcoin::secp256k1::Signature; -use bitcoin::secp256k1::key::{PublicKey, SecretKey}; -use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SIGNATURE_SIZE}; +use bitcoin::secp256k1::{PublicKey, SecretKey}; +use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SIGNATURE_SIZE, SCHNORR_SIGNATURE_SIZE}; +use bitcoin::secp256k1::ecdsa; +use bitcoin::secp256k1::schnorr; +use bitcoin::blockdata::constants::ChainHash; use bitcoin::blockdata::script::Script; use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; use bitcoin::consensus; @@ -27,18 +36,21 @@ use bitcoin::consensus::Encodable; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{Txid, BlockHash}; use core::marker::Sized; -use ln::msgs::DecodeError; -use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; +use core::time::Duration; +use crate::ln::msgs::DecodeError; +#[cfg(taproot)] +use crate::ln::msgs::PartialSignatureWithNonce; +use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; -use util::byte_utils::{be48_to_array, slice_to_be48}; +use crate::util::byte_utils::{be48_to_array, slice_to_be48}; /// serialization buffer size pub const MAX_BUF_SIZE: usize = 64 * 1024; -/// A simplified version of std::io::Write that exists largely for backwards compatibility. -/// An impl is provided for any type that also impls std::io::Write. +/// A simplified version of [`std::io::Write`] that exists largely for backwards compatibility. +/// An impl is provided for any type that also impls [`std::io::Write`]. /// -/// (C-not exported) as we only export serialization to/from byte arrays instead +/// This is not exported to bindings users as we only export serialization to/from byte arrays instead pub trait Writer { /// Writes the given buf out. See std::io::Write::write_all for more fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error>; @@ -79,7 +91,9 @@ 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); +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct LengthCalculatingWriter(pub usize); impl Writer for LengthCalculatingWriter { #[inline] fn write_all(&mut self, buf: &[u8]) -> Result<(), io::Error> { @@ -88,23 +102,28 @@ impl Writer for LengthCalculatingWriter { } } -/// Essentially std::io::Take but a bit simpler and with a method to walk the underlying stream +/// 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 { +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct FixedLengthReader { read: R, bytes_read: u64, total_bytes: u64, } impl FixedLengthReader { + /// Returns a new [`FixedLengthReader`]. pub fn new(read: R, total_bytes: u64) -> Self { Self { read, bytes_read: 0, total_bytes } } + /// Returns whether some bytes are remaining or not. #[inline] pub fn bytes_remain(&mut self) -> bool { self.bytes_read != self.total_bytes } + /// Consumes the remaining bytes. #[inline] pub fn eat_remaining(&mut self) -> Result<(), DecodeError> { copy(self, &mut sink()).unwrap(); @@ -133,13 +152,24 @@ impl Read for FixedLengthReader { } } -/// A Read which tracks whether any bytes have been read at all. This allows us to distinguish +impl LengthRead for FixedLengthReader { + #[inline] + fn total_bytes(&self) -> u64 { + self.total_bytes + } +} + +/// A [`Read`] implementation 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 { +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct ReadTrackingReader { read: R, + /// Returns whether we have read from this reader or not yet. pub have_read: bool, } impl ReadTrackingReader { + /// Returns a new [`ReadTrackingReader`]. pub fn new(read: R) -> Self { Self { read, have_read: false } } @@ -158,21 +188,22 @@ impl Read for ReadTrackingReader { } } -/// A trait that various rust-lightning types implement allowing them to be written out to a Writer +/// A trait that various LDK types implement allowing them to be written out to a [`Writer`]. /// -/// (C-not exported) as we only export serialization to/from byte arrays instead +/// This is not exported to bindings users as we only export serialization to/from byte arrays instead pub trait Writeable { - /// Writes self out to the given Writer + /// Writes `self` out to the given [`Writer`]. fn write(&self, writer: &mut W) -> Result<(), io::Error>; - /// Writes self out to a Vec + /// Writes `self` out to a `Vec`. fn encode(&self) -> Vec { let mut msg = VecWriter(Vec::new()); self.write(&mut msg).unwrap(); msg.0 } - /// Writes self out to a Vec + /// Writes `self` out to a `Vec`. + #[cfg(test)] fn encode_with_len(&self) -> Vec { let mut msg = VecWriter(Vec::new()); 0u16.write(&mut msg).unwrap(); @@ -197,34 +228,64 @@ impl<'a, T: Writeable> Writeable for &'a T { fn write(&self, writer: &mut W) -> Result<(), io::Error> { (*self).write(writer) } } -/// A trait that various rust-lightning types implement allowing them to be read in from a Read +/// A trait that various LDK types implement allowing them to be read in from a [`Read`]. /// -/// (C-not exported) as we only export serialization to/from byte arrays instead +/// This is not exported to bindings users as we only export serialization to/from byte arrays instead pub trait Readable where Self: Sized { - /// Reads a Self in from the given Read + /// Reads a `Self` in from the given [`Read`]. fn read(reader: &mut R) -> Result; } -/// A trait that various higher-level rust-lightning types implement allowing them to be read in -/// from a Read given some additional set of arguments which is required to deserialize. +/// A trait that various LDK types implement allowing them to be read in from a +/// [`Read`]` + `[`Seek`]. +pub(crate) trait SeekReadable where Self: Sized { + /// Reads a `Self` in from the given [`Read`]. + fn read(reader: &mut R) -> Result; +} + +/// A trait that various higher-level LDK types implement allowing them to be read in +/// from a [`Read`] given some additional set of arguments which is required to deserialize. /// -/// (C-not exported) as we only export serialization to/from byte arrays instead +/// This is not exported to bindings users as we only export serialization to/from byte arrays instead pub trait ReadableArgs

where Self: Sized { - /// Reads a Self in from the given Read + /// Reads a `Self` in from the given [`Read`]. fn read(reader: &mut R, params: P) -> Result; } -/// A trait that various rust-lightning types implement allowing them to (maybe) be read in from a Read +/// A [`std::io::Read`] that also provides the total bytes available to be read. +pub(crate) trait LengthRead: Read { + /// The total number of bytes available to be read. + fn total_bytes(&self) -> u64; +} + +/// A trait that various higher-level LDK types implement allowing them to be read in +/// from a Read given some additional set of arguments which is required to deserialize, requiring +/// the implementer to provide the total length of the read. +pub(crate) trait LengthReadableArgs

where Self: Sized +{ + /// Reads a `Self` in from the given [`LengthRead`]. + fn read(reader: &mut R, params: P) -> Result; +} + +/// A trait that various higher-level LDK types implement allowing them to be read in +/// from a [`Read`], requiring the implementer to provide the total length of the read. +pub(crate) trait LengthReadable where Self: Sized +{ + /// Reads a `Self` in from the given [`LengthRead`]. + fn read(reader: &mut R) -> Result; +} + +/// A trait that various LDK types implement allowing them to (maybe) be read in from a [`Read`]. /// -/// (C-not exported) as we only export serialization to/from byte arrays instead +/// This is not exported to bindings users as we only export serialization to/from byte arrays instead pub trait MaybeReadable where Self: Sized { - /// Reads a Self in from the given Read + /// Reads a `Self` in from the given [`Read`]. fn read(reader: &mut R) -> Result, DecodeError>; } @@ -235,44 +296,40 @@ impl MaybeReadable for T { } } -pub(crate) struct OptionDeserWrapper(pub Option); -impl Readable for OptionDeserWrapper { +/// Wrapper to read a required (non-optional) TLV record. +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct RequiredWrapper(pub Option); +impl Readable for RequiredWrapper { #[inline] fn read(reader: &mut R) -> Result { Ok(Self(Some(Readable::read(reader)?))) } } - -/// Wrapper to write each element of a Vec with no length prefix -pub(crate) struct VecWriteWrapper<'a, T: Writeable>(pub &'a Vec); -impl<'a, T: Writeable> Writeable for VecWriteWrapper<'a, T> { +impl> ReadableArgs for RequiredWrapper { #[inline] - fn write(&self, writer: &mut W) -> Result<(), io::Error> { - for ref v in self.0.iter() { - v.write(writer)?; - } - Ok(()) + fn read(reader: &mut R, args: A) -> Result { + Ok(Self(Some(ReadableArgs::read(reader, args)?))) } } +/// When handling `default_values`, we want to map the default-value T directly +/// to a `RequiredWrapper` in a way that works for `field: T = t;` as +/// well. Thus, we assume `Into for T` does nothing and use that. +impl From for RequiredWrapper { + fn from(t: T) -> RequiredWrapper { RequiredWrapper(Some(t)) } +} -/// Wrapper to read elements from a given stream until it reaches the end of the stream. -pub(crate) struct VecReadWrapper(pub Vec); -impl Readable for VecReadWrapper { +/// Wrapper to read a required (non-optional) TLV record that may have been upgraded without +/// backwards compat. +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct UpgradableRequired(pub Option); +impl MaybeReadable for UpgradableRequired { #[inline] - fn read(mut reader: &mut R) -> Result { - let mut values = Vec::new(); - loop { - let mut track_read = ReadTrackingReader::new(&mut reader); - match MaybeReadable::read(&mut track_read) { - Ok(Some(v)) => { values.push(v); }, - Ok(None) => { }, - // If we failed to read any bytes at all, we reached the end of our TLV - // stream and have simply exhausted all entries. - Err(ref e) if e == &DecodeError::ShortRead && !track_read.have_read => break, - Err(e) => return Err(e), - } - } - Ok(Self(values)) + fn read(reader: &mut R) -> Result, DecodeError> { + let tlv = MaybeReadable::read(reader)?; + if let Some(tlv) = tlv { return Ok(Some(Self(Some(tlv)))) } + Ok(None) } } @@ -292,14 +349,14 @@ impl Readable for U48 { } } -/// Lightning TLV uses a custom variable-length integer called BigSize. It is similar to Bitcoin's +/// 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); +pub struct BigSize(pub u64); impl Writeable for BigSize { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { @@ -356,11 +413,45 @@ impl Readable for BigSize { } } +/// The lightning protocol uses u16s for lengths in most cases. As our serialization framework +/// primarily targets that, we must as well. However, because we may serialize objects that have +/// more than 65K entries, we need to be able to store larger values. Thus, we define a variable +/// length integer here that is backwards-compatible for values < 0xffff. We treat 0xffff as +/// "read eight more bytes". +/// +/// To ensure we only have one valid encoding per value, we add 0xffff to values written as eight +/// bytes. Thus, 0xfffe is serialized as 0xfffe, whereas 0xffff is serialized as +/// 0xffff0000000000000000 (i.e. read-eight-bytes then zero). +struct CollectionLength(pub u64); +impl Writeable for CollectionLength { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + if self.0 < 0xffff { + (self.0 as u16).write(writer) + } else { + 0xffffu16.write(writer)?; + (self.0 - 0xffff).write(writer) + } + } +} + +impl Readable for CollectionLength { + #[inline] + fn read(r: &mut R) -> Result { + let mut val: u64 = ::read(r)? as u64; + if val == 0xffff { + val = ::read(r)? + .checked_add(0xffff).ok_or(DecodeError::InvalidValue)?; + } + Ok(CollectionLength(val)) + } +} + /// 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(pub T); +/// encapsulates such integers implementing [`Readable`]/[`Writeable`] for them. +#[cfg_attr(test, derive(PartialEq, Eq, Debug))] +pub(crate) struct HighZeroBytesDroppedBigSize(pub T); macro_rules! impl_writeable_primitive { ($val_type:ty, $len: expr) => { @@ -370,7 +461,7 @@ macro_rules! impl_writeable_primitive { writer.write_all(&self.to_be_bytes()) } } - impl Writeable for HighZeroBytesDroppedVarInt<$val_type> { + impl Writeable for HighZeroBytesDroppedBigSize<$val_type> { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { // Skip any full leading 0 bytes when writing (in BE): @@ -385,9 +476,9 @@ macro_rules! impl_writeable_primitive { Ok(<$val_type>::from_be_bytes(buf)) } } - impl Readable for HighZeroBytesDroppedVarInt<$val_type> { + impl Readable for HighZeroBytesDroppedBigSize<$val_type> { #[inline] - fn read(reader: &mut R) -> Result, DecodeError> { + fn read(reader: &mut R) -> Result, 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 @@ -403,7 +494,7 @@ macro_rules! impl_writeable_primitive { let first_byte = $len - ($len - total_read_len); let mut bytes = [0; $len]; bytes.copy_from_slice(&buf[first_byte..first_byte + $len]); - Ok(HighZeroBytesDroppedVarInt(<$val_type>::from_be_bytes(bytes))) + Ok(HighZeroBytesDroppedBigSize(<$val_type>::from_be_bytes(bytes))) } 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) @@ -411,9 +502,13 @@ macro_rules! impl_writeable_primitive { } } } + impl From<$val_type> for HighZeroBytesDroppedBigSize<$val_type> { + fn from(val: $val_type) -> Self { Self(val) } + } } } +impl_writeable_primitive!(u128, 16); impl_writeable_primitive!(u64, 8); impl_writeable_primitive!(u32, 4); impl_writeable_primitive!(u16, 2); @@ -474,54 +569,162 @@ macro_rules! impl_array { ); } -//TODO: performance issue with [u8; size] with impl_array!() -impl_array!(3); // for rgb +impl_array!(3); // for rgb, ISO 4712 code impl_array!(4); // for IPv4 -impl_array!(10); // for OnionV2 +impl_array!(12); // for OnionV2 impl_array!(16); // for IPv6 impl_array!(32); // for channel id & hmac impl_array!(PUBLIC_KEY_SIZE); // for PublicKey -impl_array!(COMPACT_SIGNATURE_SIZE); // for Signature +impl_array!(64); // for ecdsa::Signature and schnorr::Signature +impl_array!(66); // for MuSig2 nonces impl_array!(1300); // for OnionPacket.hop_data -// HashMap -impl Writeable for HashMap - where K: Writeable + Eq + Hash, - V: Writeable -{ +impl Writeable for [u16; 8] { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { - (self.len() as u16).write(w)?; - for (key, value) in self.iter() { - key.write(w)?; - value.write(w)?; + for v in self.iter() { + w.write_all(&v.to_be_bytes())? } Ok(()) } } -impl Readable for HashMap - where K: Readable + Eq + Hash, - V: Readable -{ +impl Readable for [u16; 8] { #[inline] fn read(r: &mut R) -> Result { - let len: u16 = Readable::read(r)?; - let mut ret = HashMap::with_capacity(len as usize); - for _ in 0..len { - ret.insert(K::read(r)?, V::read(r)?); + let mut buf = [0u8; 16]; + r.read_exact(&mut buf)?; + let mut res = [0u16; 8]; + for (idx, v) in res.iter_mut().enumerate() { + *v = (buf[idx] as u16) << 8 | (buf[idx + 1] as u16) + } + Ok(res) + } +} + +/// A type for variable-length values within TLV record where the length is encoded as part of the record. +/// Used to prevent encoding the length twice. +/// +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +pub struct WithoutLength(pub T); + +impl Writeable for WithoutLength<&String> { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + w.write_all(self.0.as_bytes()) + } +} +impl Readable for WithoutLength { + #[inline] + fn read(r: &mut R) -> Result { + let v: WithoutLength> = Readable::read(r)?; + Ok(Self(String::from_utf8(v.0).map_err(|_| DecodeError::InvalidValue)?)) + } +} +impl<'a> From<&'a String> for WithoutLength<&'a String> { + fn from(s: &'a String) -> Self { Self(s) } +} + +impl<'a, T: Writeable> Writeable for WithoutLength<&'a Vec> { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + for ref v in self.0.iter() { + v.write(writer)?; + } + Ok(()) + } +} + +impl Readable for WithoutLength> { + #[inline] + fn read(mut reader: &mut R) -> Result { + let mut values = Vec::new(); + loop { + let mut track_read = ReadTrackingReader::new(&mut reader); + match MaybeReadable::read(&mut track_read) { + Ok(Some(v)) => { values.push(v); }, + Ok(None) => { }, + // If we failed to read any bytes at all, we reached the end of our TLV + // stream and have simply exhausted all entries. + Err(ref e) if e == &DecodeError::ShortRead && !track_read.have_read => break, + Err(e) => return Err(e), + } + } + Ok(Self(values)) + } +} +impl<'a, T> From<&'a Vec> for WithoutLength<&'a Vec> { + fn from(v: &'a Vec) -> Self { Self(v) } +} + +#[derive(Debug)] +pub(crate) struct Iterable<'a, I: Iterator + Clone, T: 'a>(pub I); + +impl<'a, I: Iterator + Clone, T: 'a + Writeable> Writeable for Iterable<'a, I, T> { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + for ref v in self.0.clone() { + v.write(writer)?; + } + Ok(()) + } +} + +#[cfg(test)] +impl<'a, I: Iterator + Clone, T: 'a + PartialEq> PartialEq for Iterable<'a, I, T> { + fn eq(&self, other: &Self) -> bool { + self.0.clone().collect::>() == other.0.clone().collect::>() + } +} + +macro_rules! impl_for_map { + ($ty: ident, $keybound: ident, $constr: expr) => { + impl Writeable for $ty + where K: Writeable + Eq + $keybound, V: Writeable + { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + CollectionLength(self.len() as u64).write(w)?; + for (key, value) in self.iter() { + key.write(w)?; + value.write(w)?; + } + Ok(()) + } + } + + impl Readable for $ty + where K: Readable + Eq + $keybound, V: MaybeReadable + { + #[inline] + fn read(r: &mut R) -> Result { + let len: CollectionLength = Readable::read(r)?; + let mut ret = $constr(len.0 as usize); + for _ in 0..len.0 { + let k = K::read(r)?; + let v_opt = V::read(r)?; + if let Some(v) = v_opt { + if ret.insert(k, v).is_some() { + return Err(DecodeError::InvalidValue); + } + } + } + Ok(ret) + } } - Ok(ret) } } +impl_for_map!(BTreeMap, Ord, |_| BTreeMap::new()); +impl_for_map!(HashMap, Hash, |len| HashMap::with_capacity(len)); + // HashSet impl Writeable for HashSet where T: Writeable + Eq + Hash { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { - (self.len() as u16).write(w)?; + CollectionLength(self.len() as u64).write(w)?; for item in self.iter() { item.write(w)?; } @@ -534,9 +737,9 @@ where T: Readable + Eq + Hash { #[inline] fn read(r: &mut R) -> Result { - let len: u16 = Readable::read(r)?; - let mut ret = HashSet::with_capacity(len as usize); - for _ in 0..len { + let len: CollectionLength = Readable::read(r)?; + let mut ret = HashSet::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::())); + for _ in 0..len.0 { if !ret.insert(T::read(r)?) { return Err(DecodeError::InvalidValue) } @@ -546,10 +749,39 @@ where T: Readable + Eq + Hash } // Vectors +macro_rules! impl_for_vec { + ($ty: ty $(, $name: ident)*) => { + impl<$($name : Writeable),*> Writeable for Vec<$ty> { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + CollectionLength(self.len() as u64).write(w)?; + for elem in self.iter() { + elem.write(w)?; + } + Ok(()) + } + } + + impl<$($name : Readable),*> Readable for Vec<$ty> { + #[inline] + fn read(r: &mut R) -> Result { + let len: CollectionLength = Readable::read(r)?; + let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>())); + for _ in 0..len.0 { + if let Some(val) = MaybeReadable::read(r)? { + ret.push(val); + } + } + Ok(ret) + } + } + } +} + impl Writeable for Vec { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { - (self.len() as u16).write(w)?; + CollectionLength(self.len() as u64).write(w)?; w.write_all(&self) } } @@ -557,40 +789,23 @@ impl Writeable for Vec { impl Readable for Vec { #[inline] fn read(r: &mut R) -> Result { - let len: u16 = Readable::read(r)?; - let mut ret = Vec::with_capacity(len as usize); - ret.resize(len as usize, 0); - r.read_exact(&mut ret)?; - Ok(ret) - } -} -impl Writeable for Vec { - #[inline] - fn write(&self, w: &mut W) -> Result<(), io::Error> { - (self.len() as u16).write(w)?; - for e in self.iter() { - e.write(w)?; + let mut len: CollectionLength = Readable::read(r)?; + let mut ret = Vec::new(); + while len.0 > 0 { + let readamt = cmp::min(len.0 as usize, MAX_BUF_SIZE); + let readstart = ret.len(); + ret.resize(readstart + readamt, 0); + r.read_exact(&mut ret[readstart..])?; + len.0 -= readamt as u64; } - Ok(()) - } -} - -impl Readable for Vec { - #[inline] - fn read(r: &mut R) -> Result { - let len: u16 = Readable::read(r)?; - let byte_size = (len as usize) - .checked_mul(COMPACT_SIGNATURE_SIZE) - .ok_or(DecodeError::BadLengthDescriptor)?; - if byte_size > MAX_BUF_SIZE { - return Err(DecodeError::BadLengthDescriptor); - } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { ret.push(Readable::read(r)?); } Ok(ret) } } +impl_for_vec!(ecdsa::Signature); +impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction); +impl_for_vec!((A, B), A, B); + impl Writeable for Script { fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; @@ -649,6 +864,39 @@ impl Readable for SecretKey { } } +#[cfg(taproot)] +impl Writeable for musig2::types::PublicNonce { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.serialize().write(w) + } +} + +#[cfg(taproot)] +impl Readable for musig2::types::PublicNonce { + fn read(r: &mut R) -> Result { + let buf: [u8; PUBLIC_KEY_SIZE * 2] = Readable::read(r)?; + musig2::types::PublicNonce::from_slice(&buf).map_err(|_| DecodeError::InvalidValue) + } +} + +#[cfg(taproot)] +impl Writeable for PartialSignatureWithNonce { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.serialize().write(w)?; + self.1.write(w) + } +} + +#[cfg(taproot)] +impl Readable for PartialSignatureWithNonce { + fn read(r: &mut R) -> Result { + let partial_signature_buf: [u8; SECRET_KEY_SIZE] = Readable::read(r)?; + let partial_signature = musig2::types::PartialSignature::from_slice(&partial_signature_buf).map_err(|_| DecodeError::InvalidValue)?; + let public_nonce: musig2::types::PublicNonce = Readable::read(r)?; + Ok(PartialSignatureWithNonce(partial_signature, public_nonce)) + } +} + impl Writeable for Sha256dHash { fn write(&self, w: &mut W) -> Result<(), io::Error> { w.write_all(&self[..]) @@ -664,20 +912,32 @@ impl Readable for Sha256dHash { } } -impl Writeable for Signature { +impl Writeable for ecdsa::Signature { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.serialize_compact().write(w) } - #[inline] - fn serialized_length(&self) -> usize { - COMPACT_SIGNATURE_SIZE - } } -impl Readable for Signature { +impl Readable for ecdsa::Signature { fn read(r: &mut R) -> Result { let buf: [u8; COMPACT_SIGNATURE_SIZE] = Readable::read(r)?; - match Signature::from_compact(&buf) { + match ecdsa::Signature::from_compact(&buf) { + Ok(sig) => Ok(sig), + Err(_) => return Err(DecodeError::InvalidValue), + } + } +} + +impl Writeable for schnorr::Signature { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.as_ref().write(w) + } +} + +impl Readable for schnorr::Signature { + fn read(r: &mut R) -> Result { + let buf: [u8; SCHNORR_SIGNATURE_SIZE] = Readable::read(r)?; + match schnorr::Signature::from_slice(&buf) { Ok(sig) => Ok(sig), Err(_) => return Err(DecodeError::InvalidValue), } @@ -792,6 +1052,19 @@ impl Readable for BlockHash { } } +impl Writeable for ChainHash { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + w.write_all(self.as_bytes()) + } +} + +impl Readable for ChainHash { + fn read(r: &mut R) -> Result { + let buf: [u8; 32] = Readable::read(r)?; + Ok(ChainHash::from(&buf[..])) + } +} + impl Writeable for OutPoint { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.txid.write(w)?; @@ -815,7 +1088,7 @@ macro_rules! impl_consensus_ser { ($bitcoin_type: ty) => { impl Writeable for $bitcoin_type { fn write(&self, writer: &mut W) -> Result<(), io::Error> { - match self.consensus_encode(WriterWriteAdaptor(writer)) { + match self.consensus_encode(&mut WriterWriteAdaptor(writer)) { Ok(_) => Ok(()), Err(e) => Err(e), } @@ -879,6 +1152,29 @@ impl Writeable for (A, B, C) { } } +impl Readable for (A, B, C, D) { + fn read(r: &mut R) -> Result { + let a: A = Readable::read(r)?; + let b: B = Readable::read(r)?; + let c: C = Readable::read(r)?; + let d: D = Readable::read(r)?; + Ok((a, b, c, d)) + } +} +impl Writeable for (A, B, C, D) { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.0.write(w)?; + self.1.write(w)?; + self.2.write(w)?; + self.3.write(w) + } +} + +impl Writeable for () { + fn write(&self, _: &mut W) -> Result<(), io::Error> { + Ok(()) + } +} impl Readable for () { fn read(_r: &mut R) -> Result { Ok(()) @@ -888,11 +1184,10 @@ impl Readable for () { impl Writeable for String { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { - (self.len() as u16).write(w)?; + CollectionLength(self.len() as u64).write(w)?; w.write_all(self.as_bytes()) } } - impl Readable for String { #[inline] fn read(r: &mut R) -> Result { @@ -901,3 +1196,170 @@ impl Readable for String { Ok(ret) } } + +/// Represents a hostname for serialization purposes. +/// Only the character set and length will be validated. +/// The character set consists of ASCII alphanumeric characters, hyphens, and periods. +/// Its length is guaranteed to be representable by a single byte. +/// This serialization is used by [`BOLT 7`] hostnames. +/// +/// [`BOLT 7`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Hostname(String); +impl Hostname { + /// Returns the length of the hostname. + pub fn len(&self) -> u8 { + (&self.0).len() as u8 + } +} +impl Deref for Hostname { + type Target = String; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} +impl From for String { + fn from(hostname: Hostname) -> Self { + hostname.0 + } +} +impl TryFrom> for Hostname { + type Error = (); + + fn try_from(bytes: Vec) -> Result { + if let Ok(s) = String::from_utf8(bytes) { + Hostname::try_from(s) + } else { + Err(()) + } + } +} +impl TryFrom for Hostname { + type Error = (); + + fn try_from(s: String) -> Result { + if s.len() <= 255 && s.chars().all(|c| + c.is_ascii_alphanumeric() || + c == '.' || + c == '-' + ) { + Ok(Hostname(s)) + } else { + Err(()) + } + } +} +impl Writeable for Hostname { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.len().write(w)?; + w.write_all(self.as_bytes()) + } +} +impl Readable for Hostname { + #[inline] + fn read(r: &mut R) -> Result { + let len: u8 = Readable::read(r)?; + let mut vec = Vec::with_capacity(len.into()); + vec.resize(len.into(), 0); + r.read_exact(&mut vec)?; + Hostname::try_from(vec).map_err(|_| DecodeError::InvalidValue) + } +} + +impl Writeable for Duration { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.as_secs().write(w)?; + self.subsec_nanos().write(w) + } +} +impl Readable for Duration { + #[inline] + fn read(r: &mut R) -> Result { + let secs = Readable::read(r)?; + let nanos = Readable::read(r)?; + Ok(Duration::new(secs, nanos)) + } +} + +#[cfg(test)] +mod tests { + use core::convert::TryFrom; + use bitcoin::secp256k1::ecdsa; + use crate::util::ser::{Readable, Hostname, Writeable}; + + #[test] + fn hostname_conversion() { + assert_eq!(Hostname::try_from(String::from("a-test.com")).unwrap().as_str(), "a-test.com"); + + assert!(Hostname::try_from(String::from("\"")).is_err()); + assert!(Hostname::try_from(String::from("$")).is_err()); + assert!(Hostname::try_from(String::from("⚡")).is_err()); + let mut large_vec = Vec::with_capacity(256); + large_vec.resize(256, b'A'); + assert!(Hostname::try_from(String::from_utf8(large_vec).unwrap()).is_err()); + } + + #[test] + fn hostname_serialization() { + let hostname = Hostname::try_from(String::from("test")).unwrap(); + let mut buf: Vec = Vec::new(); + hostname.write(&mut buf).unwrap(); + assert_eq!(Hostname::read(&mut buf.as_slice()).unwrap().as_str(), "test"); + } + + #[test] + /// Taproot will likely fill legacy signature fields with all 0s. + /// This test ensures that doing so won't break serialization. + fn null_signature_codec() { + let buffer = vec![0u8; 64]; + let mut cursor = crate::io::Cursor::new(buffer.clone()); + let signature = ecdsa::Signature::read(&mut cursor).unwrap(); + let serialization = signature.serialize_compact(); + assert_eq!(buffer, serialization.to_vec()) + } + + #[test] + fn bigsize_encoding_decoding() { + let values = vec![0, 252, 253, 65535, 65536, 4294967295, 4294967296, 18446744073709551615]; + let bytes = vec![ + "00", + "fc", + "fd00fd", + "fdffff", + "fe00010000", + "feffffffff", + "ff0000000100000000", + "ffffffffffffffffff" + ]; + for i in 0..=7 { + let mut stream = crate::io::Cursor::new(::hex::decode(bytes[i]).unwrap()); + assert_eq!(super::BigSize::read(&mut stream).unwrap().0, values[i]); + let mut stream = super::VecWriter(Vec::new()); + super::BigSize(values[i]).write(&mut stream).unwrap(); + assert_eq!(stream.0, ::hex::decode(bytes[i]).unwrap()); + } + let err_bytes = vec![ + "fd00fc", + "fe0000ffff", + "ff00000000ffffffff", + "fd00", + "feffff", + "ffffffffff", + "fd", + "fe", + "ff", + "" + ]; + for i in 0..=9 { + let mut stream = crate::io::Cursor::new(::hex::decode(err_bytes[i]).unwrap()); + if i < 3 { + assert_eq!(super::BigSize::read(&mut stream).err(), Some(crate::ln::msgs::DecodeError::InvalidValue)); + } else { + assert_eq!(super::BigSize::read(&mut stream).err(), Some(crate::ln::msgs::DecodeError::ShortRead)); + } + } + } +}