X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser.rs;h=f88d9f36a72832ef1161c4ff65b48abb9e66a14a;hb=1d9e541c5766eb03dfaee7844b27b3bc1d60a05e;hp=bef192585b5e486696068174b92539c0faa895ff;hpb=c5cc1ede2631fa85d7121c70981d27eb200a24e5;p=rust-lightning diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index bef19258..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,18 +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; @@ -48,7 +50,7 @@ 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`]. /// -/// (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>; @@ -90,7 +92,7 @@ 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. /// -/// (C-not exported) as manual TLV building is not currently supported in bindings +/// 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] @@ -103,15 +105,15 @@ impl Writer for LengthCalculatingWriter { /// 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. /// -/// (C-not exported) as manual TLV building is not currently supported in bindings -pub struct FixedLengthReader { - read: R, +/// This is not exported to bindings users as manual TLV building is not currently supported in bindings +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 } } @@ -132,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 { @@ -150,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 @@ -160,7 +162,7 @@ impl LengthRead for FixedLengthReader { /// 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". /// -/// (C-not exported) as manual TLV building is not currently supported in bindings +/// 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. @@ -188,15 +190,21 @@ impl Read for ReadTrackingReader { /// 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`]. fn write(&self, writer: &mut W) -> Result<(), io::Error>; /// 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 } @@ -207,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 } @@ -228,7 +237,7 @@ impl<'a, T: Writeable> Writeable for &'a T { /// 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 { @@ -246,7 +255,7 @@ pub(crate) trait SeekReadable where Self: Sized { /// 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 { @@ -279,7 +288,7 @@ pub(crate) trait LengthReadable where Self: Sized /// 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 { @@ -296,7 +305,7 @@ impl MaybeReadable for T { /// Wrapper to read a required (non-optional) TLV record. /// -/// (C-not exported) as manual TLV building is not currently supported in bindings +/// 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] @@ -320,7 +329,7 @@ impl From for RequiredWrapper { /// Wrapper to read a required (non-optional) TLV record that may have been upgraded without /// backwards compat. /// -/// (C-not exported) as manual TLV building is not currently supported in bindings +/// 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] @@ -354,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) }, @@ -510,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] @@ -544,65 +558,55 @@ 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!(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. /// -/// (C-not exported) as manual TLV building is not currently supported in bindings +/// 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> { @@ -622,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> { @@ -654,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); @@ -713,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 @@ -735,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) @@ -746,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] @@ -758,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 { @@ -774,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] @@ -800,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)) } } @@ -861,6 +987,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[..]) @@ -1025,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)) } } @@ -1073,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 { @@ -1086,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)?; @@ -1168,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. @@ -1176,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; @@ -1232,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> { @@ -1239,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 { @@ -1248,10 +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() { @@ -1272,4 +1516,57 @@ mod tests { 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(>::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, >::from_hex(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(>::from_hex(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)); + } + } + } }