X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser.rs;h=f88d9f36a72832ef1161c4ff65b48abb9e66a14a;hb=1d9e541c5766eb03dfaee7844b27b3bc1d60a05e;hp=366e6c8cb1efaef3767b0e8d4232c3763915eb20;hpb=09f5e50ed2c3ad4324a659d7c332815e03d97bda;p=rust-lightning diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 366e6c8c..f88d9f36 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -17,9 +17,8 @@ use crate::prelude::*; use crate::io::{self, Read, Seek, Write}; use crate::io_extras::{copy, sink}; use core::hash::Hash; -use crate::sync::Mutex; +use crate::sync::{Mutex, RwLock}; use core::cmp; -use core::convert::TryFrom; use core::ops::Deref; use alloc::collections::BTreeMap; @@ -29,20 +28,21 @@ use bitcoin::secp256k1::constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, COMPACT_SI use bitcoin::secp256k1::ecdsa; use bitcoin::secp256k1::schnorr; use bitcoin::blockdata::constants::ChainHash; -use bitcoin::blockdata::script::Script; +use bitcoin::blockdata::script::{self, ScriptBuf}; use bitcoin::blockdata::transaction::{OutPoint, Transaction, TxOut}; -use bitcoin::consensus; +use bitcoin::{consensus, Witness}; use bitcoin::consensus::Encodable; use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::hash_types::{Txid, BlockHash}; -use core::marker::Sized; use core::time::Duration; +use crate::chain::ClaimId; use crate::ln::msgs::DecodeError; #[cfg(taproot)] use crate::ln::msgs::PartialSignatureWithNonce; use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret}; use crate::util::byte_utils::{be48_to_array, slice_to_be48}; +use crate::util::string::UntrustedString; /// serialization buffer size pub const MAX_BUF_SIZE: usize = 64 * 1024; @@ -106,14 +106,14 @@ impl Writer for LengthCalculatingWriter { /// forward to ensure we always consume exactly the fixed length specified. /// /// This is not exported to bindings users as manual TLV building is not currently supported in bindings -pub struct FixedLengthReader { - read: R, +pub struct FixedLengthReader<'a, R: Read> { + read: &'a mut R, bytes_read: u64, total_bytes: u64, } -impl FixedLengthReader { +impl<'a, R: Read> FixedLengthReader<'a, R> { /// Returns a new [`FixedLengthReader`]. - pub fn new(read: R, total_bytes: u64) -> Self { + pub fn new(read: &'a mut R, total_bytes: u64) -> Self { Self { read, bytes_read: 0, total_bytes } } @@ -134,7 +134,7 @@ impl FixedLengthReader { } } } -impl Read for FixedLengthReader { +impl<'a, R: Read> Read for FixedLengthReader<'a, R> { #[inline] fn read(&mut self, dest: &mut [u8]) -> Result { if self.total_bytes == self.bytes_read { @@ -152,7 +152,7 @@ impl Read for FixedLengthReader { } } -impl LengthRead for FixedLengthReader { +impl<'a, R: Read> LengthRead for FixedLengthReader<'a, R> { #[inline] fn total_bytes(&self) -> u64 { self.total_bytes @@ -197,8 +197,14 @@ pub trait Writeable { /// Writes `self` out to a `Vec`. fn encode(&self) -> Vec { - let mut msg = VecWriter(Vec::new()); + let len = self.serialized_length(); + let mut msg = VecWriter(Vec::with_capacity(len)); self.write(&mut msg).unwrap(); + // Note that objects with interior mutability may change size between when we called + // serialized_length and when we called write. That's okay, but shouldn't happen during + // testing as most of our tests are not threaded. + #[cfg(test)] + debug_assert_eq!(len, msg.0.len()); msg.0 } @@ -209,6 +215,7 @@ pub trait Writeable { 0u16.write(&mut msg).unwrap(); self.write(&mut msg).unwrap(); let len = msg.0.len(); + debug_assert_eq!(len - 2, self.serialized_length()); msg.0[..2].copy_from_slice(&(len as u16 - 2).to_be_bytes()); msg.0 } @@ -356,19 +363,20 @@ impl Readable for U48 { /// 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. +#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] pub struct BigSize(pub u64); impl Writeable for BigSize { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { match self.0 { - 0...0xFC => { + 0..=0xFC => { (self.0 as u8).write(writer) }, - 0xFD...0xFFFF => { + 0xFD..=0xFFFF => { 0xFDu8.write(writer)?; (self.0 as u16).write(writer) }, - 0x10000...0xFFFFFFFF => { + 0x10000..=0xFFFFFFFF => { 0xFEu8.write(writer)?; (self.0 as u32).write(writer) }, @@ -512,6 +520,10 @@ impl_writeable_primitive!(u128, 16); impl_writeable_primitive!(u64, 8); impl_writeable_primitive!(u32, 4); impl_writeable_primitive!(u16, 2); +impl_writeable_primitive!(i64, 8); +impl_writeable_primitive!(i32, 4); +impl_writeable_primitive!(i16, 2); +impl_writeable_primitive!(i8, 1); impl Writeable for u8 { #[inline] @@ -546,61 +558,50 @@ impl Readable for bool { } } -// u8 arrays macro_rules! impl_array { - ( $size:expr ) => ( - impl Writeable for [u8; $size] - { + ($size:expr, $ty: ty) => ( + impl Writeable for [$ty; $size] { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { - w.write_all(self) + let mut out = [0; $size * core::mem::size_of::<$ty>()]; + for (idx, v) in self.iter().enumerate() { + let startpos = idx * core::mem::size_of::<$ty>(); + out[startpos..startpos + core::mem::size_of::<$ty>()].copy_from_slice(&v.to_be_bytes()); + } + w.write_all(&out) } } - impl Readable for [u8; $size] - { + impl Readable for [$ty; $size] { #[inline] fn read(r: &mut R) -> Result { - let mut buf = [0u8; $size]; + let mut buf = [0u8; $size * core::mem::size_of::<$ty>()]; r.read_exact(&mut buf)?; - Ok(buf) + let mut res = [0; $size]; + for (idx, v) in res.iter_mut().enumerate() { + let startpos = idx * core::mem::size_of::<$ty>(); + let mut arr = [0; core::mem::size_of::<$ty>()]; + arr.copy_from_slice(&buf[startpos..startpos + core::mem::size_of::<$ty>()]); + *v = <$ty>::from_be_bytes(arr); + } + Ok(res) } } ); } -impl_array!(3); // for rgb, ISO 4712 code -impl_array!(4); // for IPv4 -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!(64); // for ecdsa::Signature and schnorr::Signature -impl_array!(66); // for MuSig2 nonces -impl_array!(1300); // for OnionPacket.hop_data +impl_array!(3, u8); // for rgb, ISO 4712 code +impl_array!(4, u8); // for IPv4 +impl_array!(12, u8); // for OnionV2 +impl_array!(16, u8); // for IPv6 +impl_array!(32, u8); // for channel id & hmac +impl_array!(PUBLIC_KEY_SIZE, u8); // for PublicKey +impl_array!(64, u8); // for ecdsa::Signature and schnorr::Signature +impl_array!(66, u8); // for MuSig2 nonces +impl_array!(1300, u8); // for OnionPacket.hop_data -impl Writeable for [u16; 8] { - #[inline] - fn write(&self, w: &mut W) -> Result<(), io::Error> { - for v in self.iter() { - w.write_all(&v.to_be_bytes())? - } - Ok(()) - } -} - -impl Readable for [u16; 8] { - #[inline] - fn read(r: &mut R) -> Result { - 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) - } -} +impl_array!(8, u16); +impl_array!(32, u16); /// 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. @@ -625,6 +626,21 @@ impl<'a> From<&'a String> for WithoutLength<&'a String> { fn from(s: &'a String) -> Self { Self(s) } } + +impl Writeable for WithoutLength<&UntrustedString> { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + WithoutLength(&self.0.0).write(w) + } +} +impl Readable for WithoutLength { + #[inline] + fn read(r: &mut R) -> Result { + let s: WithoutLength = Readable::read(r)?; + Ok(Self(UntrustedString(s.0))) + } +} + impl<'a, T: Writeable> Writeable for WithoutLength<&'a Vec> { #[inline] fn write(&self, writer: &mut W) -> Result<(), io::Error> { @@ -657,6 +673,21 @@ impl<'a, T> From<&'a Vec> for WithoutLength<&'a Vec> { fn from(v: &'a Vec) -> Self { Self(v) } } +impl Writeable for WithoutLength<&ScriptBuf> { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + writer.write_all(self.0.as_bytes()) + } +} + +impl Readable for WithoutLength { + #[inline] + fn read(r: &mut R) -> Result { + let v: WithoutLength> = Readable::read(r)?; + Ok(WithoutLength(script::Builder::from(v.0).into_script())) + } +} + #[derive(Debug)] pub(crate) struct Iterable<'a, I: Iterator + Clone, T: 'a>(pub I); @@ -716,7 +747,7 @@ macro_rules! impl_for_map { } impl_for_map!(BTreeMap, Ord, |_| BTreeMap::new()); -impl_for_map!(HashMap, Hash, |len| HashMap::with_capacity(len)); +impl_for_map!(HashMap, Hash, |len| hash_map_with_capacity(len)); // HashSet impl Writeable for HashSet @@ -738,7 +769,7 @@ where T: Readable + Eq + Hash #[inline] fn read(r: &mut R) -> Result { 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::())); + let mut ret = hash_set_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) @@ -749,7 +780,7 @@ where T: Readable + Eq + Hash } // Vectors -macro_rules! impl_for_vec { +macro_rules! impl_writeable_for_vec { ($ty: ty $(, $name: ident)*) => { impl<$($name : Writeable),*> Writeable for Vec<$ty> { #[inline] @@ -761,7 +792,10 @@ macro_rules! impl_for_vec { Ok(()) } } - + } +} +macro_rules! impl_readable_for_vec { + ($ty: ty $(, $name: ident)*) => { impl<$($name : Readable),*> Readable for Vec<$ty> { #[inline] fn read(r: &mut R) -> Result { @@ -777,6 +811,55 @@ macro_rules! impl_for_vec { } } } +macro_rules! impl_for_vec { + ($ty: ty $(, $name: ident)*) => { + impl_writeable_for_vec!($ty $(, $name)*); + impl_readable_for_vec!($ty $(, $name)*); + } +} + +// Alternatives to impl_writeable_for_vec/impl_readable_for_vec that add a length prefix to each +// element in the Vec. Intended to be used when elements have variable lengths. +macro_rules! impl_writeable_for_vec_with_element_length_prefix { + ($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() { + CollectionLength(elem.serialized_length() as u64).write(w)?; + elem.write(w)?; + } + Ok(()) + } + } + } +} +macro_rules! impl_readable_for_vec_with_element_length_prefix { + ($ty: ty $(, $name: ident)*) => { + 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 { + let elem_len: CollectionLength = Readable::read(r)?; + let mut elem_reader = FixedLengthReader::new(r, elem_len.0); + if let Some(val) = MaybeReadable::read(&mut elem_reader)? { + ret.push(val); + } + } + Ok(ret) + } + } + } +} +macro_rules! impl_for_vec_with_element_length_prefix { + ($ty: ty $(, $name: ident)*) => { + impl_writeable_for_vec_with_element_length_prefix!($ty $(, $name)*); + impl_readable_for_vec_with_element_length_prefix!($ty $(, $name)*); + } +} impl Writeable for Vec { #[inline] @@ -803,22 +886,62 @@ impl Readable for Vec { } impl_for_vec!(ecdsa::Signature); +impl_for_vec!(crate::chain::channelmonitor::ChannelMonitorUpdate); impl_for_vec!(crate::ln::channelmanager::MonitorUpdateCompletionAction); +impl_for_vec!(crate::ln::msgs::SocketAddress); impl_for_vec!((A, B), A, B); +impl_writeable_for_vec!(&crate::routing::router::BlindedTail); +impl_readable_for_vec!(crate::routing::router::BlindedTail); +impl_for_vec_with_element_length_prefix!(crate::ln::msgs::UpdateAddHTLC); +impl_writeable_for_vec_with_element_length_prefix!(&crate::ln::msgs::UpdateAddHTLC); -impl Writeable for Script { +impl Writeable for Vec { + #[inline] + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.len() as u16).write(w)?; + for witness in self { + (witness.serialized_len() as u16).write(w)?; + witness.write(w)?; + } + Ok(()) + } +} + +impl Readable for Vec { + #[inline] + fn read(r: &mut R) -> Result { + let num_witnesses = ::read(r)? as usize; + let mut witnesses = Vec::with_capacity(num_witnesses); + for _ in 0..num_witnesses { + // Even though the length of each witness can be inferred in its consensus-encoded form, + // the spec includes a length prefix so that implementations don't have to deserialize + // each initially. We do that here anyway as in general we'll need to be able to make + // assertions on some properties of the witnesses when receiving a message providing a list + // of witnesses. We'll just do a sanity check for the lengths and error if there is a mismatch. + let witness_len = ::read(r)? as usize; + let witness = ::read(r)?; + if witness.serialized_len() != witness_len { + return Err(DecodeError::BadLengthDescriptor); + } + witnesses.push(witness); + } + Ok(witnesses) + } +} + +impl Writeable for ScriptBuf { fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; w.write_all(self.as_bytes()) } } -impl Readable for Script { +impl Readable for ScriptBuf { fn read(r: &mut R) -> Result { let len = ::read(r)? as usize; let mut buf = vec![0; len]; r.read_exact(&mut buf)?; - Ok(Script::from(buf)) + Ok(ScriptBuf::from(buf)) } } @@ -1061,7 +1184,7 @@ impl Writeable for ChainHash { impl Readable for ChainHash { fn read(r: &mut R) -> Result { let buf: [u8; 32] = Readable::read(r)?; - Ok(ChainHash::from(&buf[..])) + Ok(ChainHash::from(buf)) } } @@ -1109,6 +1232,7 @@ macro_rules! impl_consensus_ser { } impl_consensus_ser!(Transaction); impl_consensus_ser!(TxOut); +impl_consensus_ser!(Witness); impl Readable for Mutex { fn read(r: &mut R) -> Result { @@ -1122,6 +1246,18 @@ impl Writeable for Mutex { } } +impl Readable for RwLock { + fn read(r: &mut R) -> Result { + let t: T = Readable::read(r)?; + Ok(RwLock::new(t)) + } +} +impl Writeable for RwLock { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.read().unwrap().write(w) + } +} + impl Readable for (A, B) { fn read(r: &mut R) -> Result { let a: A = Readable::read(r)?; @@ -1204,7 +1340,7 @@ impl Readable for String { /// 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)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Hostname(String); impl Hostname { /// Returns the length of the hostname. @@ -1212,6 +1348,13 @@ impl Hostname { (&self.0).len() as u8 } } + +impl core::fmt::Display for Hostname { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.0)?; + Ok(()) + } +} impl Deref for Hostname { type Target = String; @@ -1268,6 +1411,7 @@ impl Readable for Hostname { } } +/// This is not exported to bindings users as `Duration`s are simply mapped as ints. impl Writeable for Duration { #[inline] fn write(&self, w: &mut W) -> Result<(), io::Error> { @@ -1275,6 +1419,7 @@ impl Writeable for Duration { self.subsec_nanos().write(w) } } +/// This is not exported to bindings users as `Duration`s are simply mapped as ints. impl Readable for Duration { #[inline] fn read(r: &mut R) -> Result { @@ -1284,11 +1429,73 @@ impl Readable for Duration { } } +/// A wrapper for a `Transaction` which can only be constructed with [`TransactionU16LenLimited::new`] +/// if the `Transaction`'s consensus-serialized length is <= u16::MAX. +/// +/// Use [`TransactionU16LenLimited::into_transaction`] to convert into the contained `Transaction`. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct TransactionU16LenLimited(Transaction); + +impl TransactionU16LenLimited { + /// Constructs a new `TransactionU16LenLimited` from a `Transaction` only if it's consensus- + /// serialized length is <= u16::MAX. + pub fn new(transaction: Transaction) -> Result { + if transaction.serialized_length() > (u16::MAX as usize) { + Err(()) + } else { + Ok(Self(transaction)) + } + } + + /// Consumes this `TransactionU16LenLimited` and returns its contained `Transaction`. + pub fn into_transaction(self) -> Transaction { + self.0 + } + + /// Returns a reference to the contained `Transaction` + pub fn as_transaction(&self) -> &Transaction { + &self.0 + } +} + +impl Writeable for TransactionU16LenLimited { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + (self.0.serialized_length() as u16).write(w)?; + self.0.write(w) + } +} + +impl Readable for TransactionU16LenLimited { + fn read(r: &mut R) -> Result { + let len = ::read(r)?; + let mut tx_reader = FixedLengthReader::new(r, len as u64); + let tx: Transaction = Readable::read(&mut tx_reader)?; + if tx_reader.bytes_remain() { + Err(DecodeError::BadLengthDescriptor) + } else { + Ok(Self(tx)) + } + } +} + +impl Writeable for ClaimId { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + self.0.write(writer) + } +} + +impl Readable for ClaimId { + fn read(reader: &mut R) -> Result { + Ok(Self(Readable::read(reader)?)) + } +} + #[cfg(test)] mod tests { - use core::convert::TryFrom; + use bitcoin::hashes::hex::FromHex; use bitcoin::secp256k1::ecdsa; use crate::util::ser::{Readable, Hostname, Writeable}; + use crate::prelude::*; #[test] fn hostname_conversion() { @@ -1335,11 +1542,11 @@ mod tests { "ffffffffffffffffff" ]; for i in 0..=7 { - let mut stream = crate::io::Cursor::new(::hex::decode(bytes[i]).unwrap()); + let mut stream = crate::io::Cursor::new(>::from_hex(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()); + assert_eq!(stream.0, >::from_hex(bytes[i]).unwrap()); } let err_bytes = vec![ "fd00fc", @@ -1354,7 +1561,7 @@ mod tests { "" ]; for i in 0..=9 { - let mut stream = crate::io::Cursor::new(::hex::decode(err_bytes[i]).unwrap()); + let mut stream = crate::io::Cursor::new(>::from_hex(err_bytes[i]).unwrap()); if i < 3 { assert_eq!(super::BigSize::read(&mut stream).err(), Some(crate::ln::msgs::DecodeError::InvalidValue)); } else {