mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
Converse of deser macro to make serialization of structs less verbose.
This commit is contained in:
parent
b50e1ab038
commit
9f780f6865
5 changed files with 70 additions and 49 deletions
|
@ -61,12 +61,13 @@ impl Default for BlockHeader {
|
||||||
// core. Readable is in the ser package.
|
// core. Readable is in the ser package.
|
||||||
impl Writeable for BlockHeader {
|
impl Writeable for BlockHeader {
|
||||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||||
try_m!(writer.write_u64(self.height));
|
ser_multiwrite!(writer,
|
||||||
try_m!(writer.write_fixed_bytes(&self.previous));
|
[write_u64, self.height],
|
||||||
try_m!(writer.write_i64(self.timestamp.to_timespec().sec));
|
[write_fixed_bytes, &self.previous],
|
||||||
try_m!(writer.write_fixed_bytes(&self.utxo_merkle));
|
[write_i64, self.timestamp.to_timespec().sec],
|
||||||
try_m!(writer.write_fixed_bytes(&self.tx_merkle));
|
[write_fixed_bytes, &self.utxo_merkle],
|
||||||
try_m!(writer.write_u64(self.total_fees));
|
[write_fixed_bytes, &self.tx_merkle],
|
||||||
|
[write_u64, self.total_fees]);
|
||||||
// make sure to not introduce any variable length data before the nonce to
|
// make sure to not introduce any variable length data before the nonce to
|
||||||
// avoid complicating PoW
|
// avoid complicating PoW
|
||||||
try_m!(writer.write_u64(self.nonce));
|
try_m!(writer.write_u64(self.nonce));
|
||||||
|
@ -103,9 +104,10 @@ impl Writeable for Block {
|
||||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||||
try_m!(self.header.write(writer));
|
try_m!(self.header.write(writer));
|
||||||
|
|
||||||
try_m!(writer.write_u64(self.inputs.len() as u64));
|
ser_multiwrite!(writer,
|
||||||
try_m!(writer.write_u64(self.outputs.len() as u64));
|
[write_u64, self.inputs.len() as u64],
|
||||||
try_m!(writer.write_u64(self.proofs.len() as u64));
|
[write_u64, self.outputs.len() as u64],
|
||||||
|
[write_u64, self.proofs.len() as u64]);
|
||||||
for inp in &self.inputs {
|
for inp in &self.inputs {
|
||||||
try_m!(inp.write(writer));
|
try_m!(inp.write(writer));
|
||||||
}
|
}
|
||||||
|
@ -123,8 +125,15 @@ impl Writeable for Block {
|
||||||
/// from a binary stream.
|
/// from a binary stream.
|
||||||
impl Readable<Block> for Block {
|
impl Readable<Block> for Block {
|
||||||
fn read(reader: &mut Reader) -> Result<Block, ser::Error> {
|
fn read(reader: &mut Reader) -> Result<Block, ser::Error> {
|
||||||
let (height, previous, timestamp, utxo_merkle, tx_merkle, total_fees, nonce) =
|
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);
|
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
|
// cuckoo cycle of 42 nodes
|
||||||
let mut pow = [0; PROOFSIZE];
|
let mut pow = [0; PROOFSIZE];
|
||||||
|
@ -132,11 +141,12 @@ impl Readable<Block> for Block {
|
||||||
pow[n] = try!(reader.read_u32());
|
pow[n] = try!(reader.read_u32());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (td, input_len, output_len, proof_len) =
|
let (td, input_len, output_len, proof_len) =
|
||||||
ser_multiread!(reader, read_u64, read_u64, read_u64, read_u64);
|
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 {
|
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()));
|
return Err(ser::Error::TooLargeReadErr("Too many inputs, outputs or proofs."
|
||||||
|
.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect());
|
let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect());
|
||||||
|
@ -373,7 +383,7 @@ impl Block {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::{Input, Output, Transaction};
|
use core::{Input, Output, Transaction};
|
||||||
use core::hash::{Hash, Hashed};
|
use core::hash::{Hash, Hashed};
|
||||||
use core::test::{tx1i1o, tx2i1o};
|
use core::test::{tx1i1o, tx2i1o};
|
||||||
|
|
||||||
|
@ -463,4 +473,3 @@ mod test {
|
||||||
assert_eq!(b3.outputs.len(), 4);
|
assert_eq!(b3.outputs.len(), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,4 +80,3 @@ impl Hashed for [u8] {
|
||||||
self.to_owned()
|
self.to_owned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl Writeable for TxProof {
|
||||||
|
|
||||||
impl Readable<TxProof> for TxProof {
|
impl Readable<TxProof> for TxProof {
|
||||||
fn read(reader: &mut Reader) -> Result<TxProof, ser::Error> {
|
fn read(reader: &mut Reader) -> Result<TxProof, ser::Error> {
|
||||||
let (remainder, sig) = ser_multiread!(reader, read_33_bytes, read_vec);
|
let (remainder, sig) = ser_multiread!(reader, read_33_bytes, read_vec);
|
||||||
Ok(TxProof {
|
Ok(TxProof {
|
||||||
remainder: Commitment::from_vec(remainder),
|
remainder: Commitment::from_vec(remainder),
|
||||||
sig: sig,
|
sig: sig,
|
||||||
|
@ -69,10 +69,11 @@ pub struct Transaction {
|
||||||
/// write the transaction as binary.
|
/// write the transaction as binary.
|
||||||
impl Writeable for Transaction {
|
impl Writeable for Transaction {
|
||||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||||
try_m!(writer.write_u64(self.fee));
|
ser_multiwrite!(writer,
|
||||||
try_m!(writer.write_vec(&mut self.zerosig.clone()));
|
[write_u64, self.fee],
|
||||||
try_m!(writer.write_u64(self.inputs.len() as u64));
|
[write_vec, &mut self.zerosig.clone()],
|
||||||
try_m!(writer.write_u64(self.outputs.len() as u64));
|
[write_u64, self.inputs.len() as u64],
|
||||||
|
[write_u64, self.outputs.len() as u64]);
|
||||||
for inp in &self.inputs {
|
for inp in &self.inputs {
|
||||||
try_m!(inp.write(writer));
|
try_m!(inp.write(writer));
|
||||||
}
|
}
|
||||||
|
@ -87,8 +88,8 @@ impl Writeable for Transaction {
|
||||||
/// transaction from a binary stream.
|
/// transaction from a binary stream.
|
||||||
impl Readable<Transaction> for Transaction {
|
impl Readable<Transaction> for Transaction {
|
||||||
fn read(reader: &mut Reader) -> Result<Transaction, ser::Error> {
|
fn read(reader: &mut Reader) -> Result<Transaction, ser::Error> {
|
||||||
let (fee, zerosig, input_len, output_len) =
|
let (fee, zerosig, input_len, output_len) =
|
||||||
ser_multiread!(reader, read_u64, read_vec, read_u64, read_u64);
|
ser_multiread!(reader, read_u64, read_vec, read_u64, read_u64);
|
||||||
|
|
||||||
// in case a facetious miner sends us more than what we can allocate
|
// 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 {
|
if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN {
|
||||||
|
@ -311,7 +312,7 @@ impl Writeable for Output {
|
||||||
/// an Output from a binary stream.
|
/// an Output from a binary stream.
|
||||||
impl Readable<Output> for Output {
|
impl Readable<Output> for Output {
|
||||||
fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
|
fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
|
||||||
let (commit, proof) = ser_multiread!(reader, read_33_bytes, read_vec);
|
let (commit, proof) = ser_multiread!(reader, read_33_bytes, read_vec);
|
||||||
Ok(Output::BlindOutput {
|
Ok(Output::BlindOutput {
|
||||||
commit: Commitment::from_vec(commit),
|
commit: Commitment::from_vec(commit),
|
||||||
proof: RangeProof::from_vec(proof),
|
proof: RangeProof::from_vec(proof),
|
||||||
|
@ -545,5 +546,3 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,8 @@ macro_rules! try_m {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Eliminate some of the boilerplate of deserialization (package ser) by passing just the list of reader function.
|
/// Eliminate some of the boilerplate of deserialization (package ser) by
|
||||||
|
/// passing just the list of reader function.
|
||||||
/// Example before:
|
/// Example before:
|
||||||
/// let foo = try!(reader.read_u64());
|
/// let foo = try!(reader.read_u64());
|
||||||
/// let bar = try!(reader.read_u32());
|
/// let bar = try!(reader.read_u32());
|
||||||
|
@ -85,3 +86,9 @@ macro_rules! ser_multiread {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! ser_multiwrite {
|
||||||
|
($wrtr:ident, $([ $write_call:ident, $val:expr ]),* ) => {
|
||||||
|
$( try_m!($wrtr.$write_call($val)) );*
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,11 +28,11 @@ use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Wraps an io error produced when reading or writing
|
/// Wraps an io error produced when reading or writing
|
||||||
IOErr(io::Error),
|
IOErr(io::Error),
|
||||||
/// Expected a given value that wasn't found
|
/// Expected a given value that wasn't found
|
||||||
UnexpectedData{
|
UnexpectedData {
|
||||||
expected: Vec<u8>,
|
expected: Vec<u8>,
|
||||||
received: Vec<u8>,
|
received: Vec<u8>,
|
||||||
},
|
},
|
||||||
/// When asked to read too much data
|
/// When asked to read too much data
|
||||||
TooLargeReadErr(String),
|
TooLargeReadErr(String),
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ pub trait AsFixedBytes {
|
||||||
/// written to an underlying stream or container (depending on implementation).
|
/// written to an underlying stream or container (depending on implementation).
|
||||||
pub trait Writer {
|
pub trait Writer {
|
||||||
/// Writes a u8 as bytes
|
/// Writes a u8 as bytes
|
||||||
fn write_u8(&mut self, n: u8) -> Option<Error>;
|
fn write_u8(&mut self, n: u8) -> Option<Error>;
|
||||||
/// Writes a u32 as bytes
|
/// Writes a u32 as bytes
|
||||||
fn write_u32(&mut self, n: u32) -> Option<Error>;
|
fn write_u32(&mut self, n: u32) -> Option<Error>;
|
||||||
/// Writes a u64 as bytes
|
/// Writes a u64 as bytes
|
||||||
|
@ -78,12 +78,13 @@ pub trait Reader {
|
||||||
fn read_vec(&mut self) -> Result<Vec<u8>, Error>;
|
fn read_vec(&mut self) -> Result<Vec<u8>, Error>;
|
||||||
/// Read a fixed number of bytes from the underlying reader.
|
/// Read a fixed number of bytes from the underlying reader.
|
||||||
fn read_fixed_bytes(&mut self, length: usize) -> Result<Vec<u8>, Error>;
|
fn read_fixed_bytes(&mut self, length: usize) -> Result<Vec<u8>, Error>;
|
||||||
/// Convenience function to read 32 fixed bytes
|
/// Convenience function to read 32 fixed bytes
|
||||||
fn read_32_bytes(&mut self) -> Result<Vec<u8>, Error>;
|
fn read_32_bytes(&mut self) -> Result<Vec<u8>, Error>;
|
||||||
/// Convenience function to read 33 fixed bytes
|
/// Convenience function to read 33 fixed bytes
|
||||||
fn read_33_bytes(&mut self) -> Result<Vec<u8>, Error>;
|
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
|
/// Consumes a byte from the reader, producing an error if it doesn't have
|
||||||
fn expect_u8(&mut self, val: u8) -> Result<u8, Error>;
|
/// 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.
|
/// Trait that every type that can be serialized as binary must implement.
|
||||||
|
@ -157,15 +158,22 @@ impl<'a> Reader for BinReader<'a> {
|
||||||
self.source.read_exact(&mut buf).map(move |_| buf).map_err(Error::IOErr)
|
self.source.read_exact(&mut buf).map(move |_| buf).map_err(Error::IOErr)
|
||||||
}
|
}
|
||||||
fn read_32_bytes(&mut self) -> Result<Vec<u8>, Error> {
|
fn read_32_bytes(&mut self) -> Result<Vec<u8>, Error> {
|
||||||
self.read_fixed_bytes(32)
|
self.read_fixed_bytes(32)
|
||||||
}
|
}
|
||||||
fn read_33_bytes(&mut self) -> Result<Vec<u8>, Error> {
|
fn read_33_bytes(&mut self) -> Result<Vec<u8>, Error> {
|
||||||
self.read_fixed_bytes(33)
|
self.read_fixed_bytes(33)
|
||||||
}
|
}
|
||||||
fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
|
fn expect_u8(&mut self, val: u8) -> Result<u8, Error> {
|
||||||
let b = try!(self.read_u8());
|
let b = try!(self.read_u8());
|
||||||
if b == val { Ok(b) } else { Err(Error::UnexpectedData{expected: vec![val], received: vec![b]}) }
|
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
|
/// Utility wrapper for an underlying byte Writer. Defines higher level methods
|
||||||
|
@ -228,4 +236,3 @@ impl AsFixedBytes for ::secp::pedersen::RangeProof {
|
||||||
&self.bytes()
|
&self.bytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue