diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 873741cf0..df38d906d 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -123,23 +123,18 @@ impl Writeable for Block { /// from a binary stream. impl Readable for Block { fn read(reader: &mut Reader) -> Result { - let height = try!(reader.read_u64()); - let previous = try!(reader.read_fixed_bytes(32)); - let timestamp = try!(reader.read_i64()); - let utxo_merkle = try!(reader.read_fixed_bytes(32)); - let tx_merkle = try!(reader.read_fixed_bytes(32)); - let total_fees = try!(reader.read_u64()); - let nonce = try!(reader.read_u64()); + let (height, previous, timestamp, utxo_merkle, tx_merkle, total_fees, nonce) = + ser_multiread!(reader, read_u64, read_32_bytes, read_i64, read_32_bytes, read_32_bytes, read_u64, read_u64); + // cuckoo cycle of 42 nodes let mut pow = [0; PROOFSIZE]; for n in 0..PROOFSIZE { pow[n] = try!(reader.read_u32()); } - let td = try!(reader.read_u64()); - let input_len = try!(reader.read_u64()); - let output_len = try!(reader.read_u64()); - let proof_len = try!(reader.read_u64()); + let (td, input_len, output_len, proof_len) = + ser_multiread!(reader, read_u64, read_u64, read_u64, read_u64); + if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN || proof_len > MAX_IN_OUT_LEN { return Err(ser::Error::TooLargeReadErr("Too many inputs, outputs or proofs.".to_string())); } @@ -147,6 +142,7 @@ impl Readable for Block { let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect()); let outputs = try!((0..output_len).map(|_| Output::read(reader)).collect()); let proofs = try!((0..proof_len).map(|_| TxProof::read(reader)).collect()); + Ok(Block { header: BlockHeader { height: height, diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index 581a0efe8..ff202559f 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -47,8 +47,7 @@ impl Writeable for TxProof { impl Readable for TxProof { fn read(reader: &mut Reader) -> Result { - let remainder = try!(reader.read_fixed_bytes(33)); - let sig = try!(reader.read_vec()); + let (remainder, sig) = ser_multiread!(reader, read_33_bytes, read_vec); Ok(TxProof { remainder: Commitment::from_vec(remainder), sig: sig, @@ -88,10 +87,8 @@ impl Writeable for Transaction { /// transaction from a binary stream. impl Readable for Transaction { fn read(reader: &mut Reader) -> Result { - let fee = try!(reader.read_u64()); - let zerosig = try!(reader.read_vec()); - let input_len = try!(reader.read_u64()); - let output_len = try!(reader.read_u64()); + let (fee, zerosig, input_len, output_len) = + ser_multiread!(reader, read_u64, read_vec, read_u64, read_u64); // in case a facetious miner sends us more than what we can allocate if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN { @@ -314,8 +311,7 @@ impl Writeable for Output { /// an Output from a binary stream. impl Readable for Output { fn read(reader: &mut Reader) -> Result { - let commit = try!(reader.read_fixed_bytes(33)); - let proof = try!(reader.read_vec()); + let (commit, proof) = ser_multiread!(reader, read_33_bytes, read_vec); Ok(Output::BlindOutput { commit: Commitment::from_vec(commit), proof: RangeProof::from_vec(proof), diff --git a/core/src/macros.rs b/core/src/macros.rs index 5a480dad5..de8988623 100644 --- a/core/src/macros.rs +++ b/core/src/macros.rs @@ -71,3 +71,17 @@ macro_rules! try_m { } } } + +/// Eliminate some of the boilerplate of deserialization (package ser) by passing just the list of reader function. +/// Example before: +/// let foo = try!(reader.read_u64()); +/// let bar = try!(reader.read_u32()); +/// Example after: +/// let (foo, bar) = ser_multiread!(reader, read_u64, read_u32); +#[macro_export] +macro_rules! ser_multiread { + ($rdr:ident, $($read_call:ident),*) => { + ( $(try!($rdr.$read_call())),* ) + } +} + diff --git a/core/src/ser.rs b/core/src/ser.rs index 3e08f3835..6ae913773 100644 --- a/core/src/ser.rs +++ b/core/src/ser.rs @@ -28,6 +28,11 @@ use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; pub enum Error { /// Wraps an io error produced when reading or writing IOErr(io::Error), + /// Expected a given value that wasn't found + UnexpectedData{ + expected: Vec, + received: Vec, + }, /// When asked to read too much data TooLargeReadErr(String), } @@ -42,6 +47,8 @@ pub trait AsFixedBytes { /// Implementations defined how different numbers and binary structures are /// written to an underlying stream or container (depending on implementation). pub trait Writer { + /// Writes a u8 as bytes + fn write_u8(&mut self, n: u8) -> Option; /// Writes a u32 as bytes fn write_u32(&mut self, n: u32) -> Option; /// Writes a u64 as bytes @@ -59,6 +66,8 @@ pub trait Writer { /// Implementations defined how different numbers and binary structures are /// read from an underlying stream or container (depending on implementation). pub trait Reader { + /// Read a u8 from the underlying Read + fn read_u8(&mut self) -> Result; /// Read a u32 from the underlying Read fn read_u32(&mut self) -> Result; /// Read a u64 from the underlying Read @@ -69,6 +78,12 @@ pub trait Reader { fn read_vec(&mut self) -> Result, Error>; /// Read a fixed number of bytes from the underlying reader. fn read_fixed_bytes(&mut self, length: usize) -> Result, Error>; + /// Convenience function to read 32 fixed bytes + fn read_32_bytes(&mut self) -> Result, Error>; + /// Convenience function to read 33 fixed bytes + fn read_33_bytes(&mut self) -> Result, Error>; + /// Consumes a byte from the reader, producing an error if it doesn't have the expected value + fn expect_u8(&mut self, val: u8) -> Result; } /// Trait that every type that can be serialized as binary must implement. @@ -116,6 +131,9 @@ struct BinReader<'a> { /// Utility wrapper for an underlying byte Reader. Defines higher level methods /// to read numbers, byte vectors, hashes, etc. impl<'a> Reader for BinReader<'a> { + fn read_u8(&mut self) -> Result { + self.source.read_u8().map_err(Error::IOErr) + } fn read_u32(&mut self) -> Result { self.source.read_u32::().map_err(Error::IOErr) } @@ -138,6 +156,16 @@ impl<'a> Reader for BinReader<'a> { let mut buf = vec![0; length]; self.source.read_exact(&mut buf).map(move |_| buf).map_err(Error::IOErr) } + fn read_32_bytes(&mut self) -> Result, Error> { + self.read_fixed_bytes(32) + } + fn read_33_bytes(&mut self) -> Result, Error> { + self.read_fixed_bytes(33) + } + fn expect_u8(&mut self, val: u8) -> Result { + let b = try!(self.read_u8()); + if b == val { Ok(b) } else { Err(Error::UnexpectedData{expected: vec![val], received: vec![b]}) } + } } /// Utility wrapper for an underlying byte Writer. Defines higher level methods @@ -147,6 +175,9 @@ struct BinWriter<'a> { } impl<'a> Writer for BinWriter<'a> { + fn write_u8(&mut self, n: u8) -> Option { + self.sink.write_u8(n).err().map(Error::IOErr) + } fn write_u32(&mut self, n: u32) -> Option { self.sink.write_u32::(n).err().map(Error::IOErr) }