X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fser.rs;h=1eb5e7424c82343d0bb88aef7df632dc408563f0;hb=83f0dbc0021335dce183450d7dce7e9f284ff0b6;hp=e276e72719e4853d7094af615caed56e1415fd8d;hpb=e94647ca4ebc63be4a8164804d08cf37e4655d6c;p=rust-lightning diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index e276e727..1eb5e742 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -31,18 +31,20 @@ use bitcoin::secp256k1::schnorr; use bitcoin::blockdata::constants::ChainHash; use bitcoin::blockdata::script::{self, Script}; 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; @@ -356,6 +358,7 @@ 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] @@ -512,6 +515,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] @@ -625,6 +632,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> { @@ -827,11 +849,46 @@ 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!((A, B), A, B); impl_writeable_for_vec!(&crate::routing::router::BlindedTail); impl_readable_for_vec!(crate::routing::router::BlindedTail); +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 Script { fn write(&self, w: &mut W) -> Result<(), io::Error> { (self.len() as u16).write(w)?; @@ -1135,6 +1192,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 { @@ -1294,6 +1352,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> { @@ -1301,6 +1360,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 { @@ -1310,6 +1370,62 @@ 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, 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 + } +} + +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;