mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Simple macro to remove some of the verbosity in deserialization.
This commit is contained in:
parent
c8aa8d7c18
commit
b50e1ab038
4 changed files with 56 additions and 19 deletions
|
@ -123,23 +123,18 @@ impl Writeable for Block {
|
|||
/// from a binary stream.
|
||||
impl Readable<Block> for Block {
|
||||
fn read(reader: &mut Reader) -> Result<Block, ser::Error> {
|
||||
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<Block> 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,
|
||||
|
|
|
@ -47,8 +47,7 @@ impl Writeable for TxProof {
|
|||
|
||||
impl Readable<TxProof> for TxProof {
|
||||
fn read(reader: &mut Reader) -> Result<TxProof, ser::Error> {
|
||||
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<Transaction> for Transaction {
|
||||
fn read(reader: &mut Reader) -> Result<Transaction, ser::Error> {
|
||||
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<Output> for Output {
|
||||
fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
|
||||
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),
|
||||
|
|
|
@ -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())),* )
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<u8>,
|
||||
received: Vec<u8>,
|
||||
},
|
||||
/// 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<Error>;
|
||||
/// Writes a u32 as bytes
|
||||
fn write_u32(&mut self, n: u32) -> Option<Error>;
|
||||
/// 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<u8, Error>;
|
||||
/// Read a u32 from the underlying Read
|
||||
fn read_u32(&mut self) -> Result<u32, Error>;
|
||||
/// Read a u64 from the underlying Read
|
||||
|
@ -69,6 +78,12 @@ pub trait Reader {
|
|||
fn read_vec(&mut self) -> Result<Vec<u8>, Error>;
|
||||
/// Read a fixed number of bytes from the underlying reader.
|
||||
fn read_fixed_bytes(&mut self, length: usize) -> Result<Vec<u8>, Error>;
|
||||
/// Convenience function to read 32 fixed bytes
|
||||
fn read_32_bytes(&mut self) -> Result<Vec<u8>, Error>;
|
||||
/// Convenience function to read 33 fixed bytes
|
||||
fn read_33_bytes(&mut self) -> Result<Vec<u8>, 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<u8, Error>;
|
||||
}
|
||||
|
||||
/// 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<u8, Error> {
|
||||
self.source.read_u8().map_err(Error::IOErr)
|
||||
}
|
||||
fn read_u32(&mut self) -> Result<u32, Error> {
|
||||
self.source.read_u32::<BigEndian>().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<Vec<u8>, Error> {
|
||||
self.read_fixed_bytes(32)
|
||||
}
|
||||
fn read_33_bytes(&mut self) -> Result<Vec<u8>, Error> {
|
||||
self.read_fixed_bytes(33)
|
||||
}
|
||||
fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
|
||||
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<Error> {
|
||||
self.sink.write_u8(n).err().map(Error::IOErr)
|
||||
}
|
||||
fn write_u32(&mut self, n: u32) -> Option<Error> {
|
||||
self.sink.write_u32::<BigEndian>(n).err().map(Error::IOErr)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue