mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
core/ser: change serialization trait to use Result<(), Error> in place of Option<Error>
This commit is contained in:
parent
3ffc2f5d8c
commit
bc38016385
5 changed files with 104 additions and 81 deletions
|
@ -60,7 +60,7 @@ impl Default for BlockHeader {
|
|||
// Only Writeable implementation is required for hashing, which is part of
|
||||
// core. Readable is in the ser package.
|
||||
impl Writeable for BlockHeader {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.height],
|
||||
[write_fixed_bytes, &self.previous],
|
||||
|
@ -70,10 +70,10 @@ impl Writeable for BlockHeader {
|
|||
[write_u64, self.total_fees]);
|
||||
// make sure to not introduce any variable length data before the nonce to
|
||||
// avoid complicating PoW
|
||||
try_o!(writer.write_u64(self.nonce));
|
||||
try!(writer.write_u64(self.nonce));
|
||||
// cuckoo cycle of 42 nodes
|
||||
for n in 0..42 {
|
||||
try_o!(writer.write_u32(self.pow.0[n]));
|
||||
try!(writer.write_u32(self.pow.0[n]));
|
||||
}
|
||||
writer.write_u64(self.td)
|
||||
}
|
||||
|
@ -101,23 +101,23 @@ pub struct Block {
|
|||
/// Implementation of Writeable for a block, defines how to write the full
|
||||
/// block as binary.
|
||||
impl Writeable for Block {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
try_o!(self.header.write(writer));
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
try!(self.header.write(writer));
|
||||
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64],
|
||||
[write_u64, self.proofs.len() as u64]);
|
||||
for inp in &self.inputs {
|
||||
try_o!(inp.write(writer));
|
||||
try!(inp.write(writer));
|
||||
}
|
||||
for out in &self.outputs {
|
||||
try_o!(out.write(writer));
|
||||
try!(out.write(writer));
|
||||
}
|
||||
for proof in &self.proofs {
|
||||
try_o!(proof.write(writer));
|
||||
try!(proof.write(writer));
|
||||
}
|
||||
None
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ pub struct TxProof {
|
|||
}
|
||||
|
||||
impl Writeable for TxProof {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
try_o!(writer.write_fixed_bytes(&self.remainder));
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
try!(writer.write_fixed_bytes(&self.remainder));
|
||||
writer.write_vec(&mut self.sig.clone())
|
||||
}
|
||||
}
|
||||
|
@ -68,19 +68,19 @@ pub struct Transaction {
|
|||
/// Implementation of Writeable for a fully blinded transaction, defines how to
|
||||
/// write the transaction as binary.
|
||||
impl Writeable for Transaction {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
ser_multiwrite!(writer,
|
||||
[write_u64, self.fee],
|
||||
[write_vec, &mut self.zerosig.clone()],
|
||||
[write_u64, self.inputs.len() as u64],
|
||||
[write_u64, self.outputs.len() as u64]);
|
||||
for inp in &self.inputs {
|
||||
try_o!(inp.write(writer));
|
||||
try!(inp.write(writer));
|
||||
}
|
||||
for out in &self.outputs {
|
||||
try_o!(out.write(writer));
|
||||
try!(out.write(writer));
|
||||
}
|
||||
None
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ pub enum Input {
|
|||
/// Implementation of Writeable for a transaction Input, defines how to write
|
||||
/// an Input as binary.
|
||||
impl Writeable for Input {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
writer.write_fixed_bytes(&self.output_hash())
|
||||
}
|
||||
}
|
||||
|
@ -302,8 +302,8 @@ pub enum Output {
|
|||
/// Implementation of Writeable for a transaction Output, defines how to write
|
||||
/// an Output as binary.
|
||||
impl Writeable for Output {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
try_o!(writer.write_fixed_bytes(&self.commitment().unwrap()));
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
try!(writer.write_fixed_bytes(&self.commitment().unwrap()));
|
||||
writer.write_vec(&mut self.proof().unwrap().bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
@ -407,9 +407,7 @@ mod test {
|
|||
let tx = tx2i1o(secp, &mut rng);
|
||||
let btx = tx.blind(&secp).unwrap();
|
||||
let mut vec = Vec::new();
|
||||
if let Some(e) = serialize(&mut vec, &btx) {
|
||||
panic!(e);
|
||||
}
|
||||
serialize(&mut vec, &btx).expect("serialized failed");
|
||||
assert!(vec.len() > 5320);
|
||||
assert!(vec.len() < 5340);
|
||||
}
|
||||
|
@ -422,9 +420,7 @@ mod test {
|
|||
let tx = tx2i1o(secp, &mut rng);
|
||||
let mut btx = tx.blind(&secp).unwrap();
|
||||
let mut vec = Vec::new();
|
||||
if let Some(e) = serialize(&mut vec, &btx) {
|
||||
panic!(e);
|
||||
}
|
||||
serialize(&mut vec, &btx).expect("serialization failed");
|
||||
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
|
||||
// }).unwrap();
|
||||
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
|
@ -444,11 +440,11 @@ mod test {
|
|||
let mut btx = tx.blind(&secp).unwrap();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
assert!(serialize(&mut vec, &btx).is_none());
|
||||
assert!(serialize(&mut vec, &btx).is_ok());
|
||||
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
|
||||
|
||||
let mut vec2 = Vec::new();
|
||||
assert!(serialize(&mut vec2, &btx).is_none());
|
||||
assert!(serialize(&mut vec2, &btx).is_ok());
|
||||
let mut dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
|
||||
|
||||
assert_eq!(btx.hash(), dtx.hash());
|
||||
|
|
|
@ -61,19 +61,6 @@ macro_rules! tee {
|
|||
}
|
||||
}
|
||||
|
||||
/// Simple equivalent of try! but for an Option<Error>. Motivated mostly by the
|
||||
/// io package and our serialization as an alternative to silly Result<(),
|
||||
/// Error>.
|
||||
#[macro_export]
|
||||
macro_rules! try_o {
|
||||
($trying:expr) => {
|
||||
let tried = $trying;
|
||||
if let Some(_) = tried {
|
||||
return tried;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! try_to_o {
|
||||
($trying:expr) => {{
|
||||
|
@ -109,6 +96,6 @@ macro_rules! ser_multiread {
|
|||
#[macro_export]
|
||||
macro_rules! ser_multiwrite {
|
||||
($wrtr:ident, $([ $write_call:ident, $val:expr ]),* ) => {
|
||||
$( try_o!($wrtr.$write_call($val)) );*
|
||||
$( try!($wrtr.$write_call($val)) );*
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,16 +71,16 @@ struct PowHeader {
|
|||
/// the data that gets hashed for PoW calculation. The nonce is written first
|
||||
/// to make incrementing from the serialized form trivial.
|
||||
impl Writeable for PowHeader {
|
||||
fn write(&self, writer: &mut Writer) -> Option<ser::Error> {
|
||||
try_o!(writer.write_u64(self.nonce));
|
||||
try_o!(writer.write_u64(self.height));
|
||||
try_o!(writer.write_fixed_bytes(&self.previous));
|
||||
try_o!(writer.write_i64(self.timestamp.to_timespec().sec));
|
||||
try_o!(writer.write_fixed_bytes(&self.utxo_merkle));
|
||||
try_o!(writer.write_fixed_bytes(&self.tx_merkle));
|
||||
try_o!(writer.write_u64(self.total_fees));
|
||||
try_o!(writer.write_u64(self.n_in));
|
||||
try_o!(writer.write_u64(self.n_out));
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
try!(writer.write_u64(self.nonce));
|
||||
try!(writer.write_u64(self.height));
|
||||
try!(writer.write_fixed_bytes(&self.previous));
|
||||
try!(writer.write_i64(self.timestamp.to_timespec().sec));
|
||||
try!(writer.write_fixed_bytes(&self.utxo_merkle));
|
||||
try!(writer.write_fixed_bytes(&self.tx_merkle));
|
||||
try!(writer.write_u64(self.total_fees));
|
||||
try!(writer.write_u64(self.n_in));
|
||||
try!(writer.write_u64(self.n_out));
|
||||
writer.write_u64(self.n_proofs)
|
||||
}
|
||||
}
|
||||
|
|
102
core/src/ser.rs
102
core/src/ser.rs
|
@ -19,8 +19,8 @@
|
|||
//! To use it simply implement `Writeable` or `Readable` and then use the
|
||||
//! `serialize` or `deserialize` functions on them as appropriate.
|
||||
|
||||
use std::io;
|
||||
use std::io::{Write, Read};
|
||||
use std::{error, fmt};
|
||||
use std::io::{self, Write, Read};
|
||||
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian};
|
||||
|
||||
/// Possible errors deriving from serializing or deserializing.
|
||||
|
@ -33,12 +33,47 @@ pub enum Error {
|
|||
expected: Vec<u8>,
|
||||
received: Vec<u8>,
|
||||
},
|
||||
/// Data wasn't in a consumable format
|
||||
CorruptedData,
|
||||
/// Data wasn't in a consumable format
|
||||
CorruptedData,
|
||||
/// When asked to read too much data
|
||||
TooLargeReadErr(String),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(e: io::Error) -> Error {
|
||||
Error::IOErr(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::IOErr(ref e) => write!(f, "{}", e),
|
||||
Error::UnexpectedData { expected: ref e, received: ref r } => write!(f, "expected {:?}, got {:?}", e, r),
|
||||
Error::CorruptedData => f.write_str("corrupted data"),
|
||||
Error::TooLargeReadErr(ref s) => f.write_str(&s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn cause(&self) -> Option<&error::Error> {
|
||||
match *self {
|
||||
Error::IOErr(ref e) => Some(e),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
fn description(&self) -> &str {
|
||||
match *self {
|
||||
Error::IOErr(ref e) => error::Error::description(e),
|
||||
Error::UnexpectedData { expected: _, received: _ } => "unexpected data",
|
||||
Error::CorruptedData => "corrupted data",
|
||||
Error::TooLargeReadErr(ref s) => s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful trait to implement on types that can be translated to byte slices
|
||||
/// directly. Allows the use of `write_fixed_bytes` on them.
|
||||
pub trait AsFixedBytes {
|
||||
|
@ -50,21 +85,21 @@ pub trait AsFixedBytes {
|
|||
/// 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>;
|
||||
fn write_u8(&mut self, n: u8) -> Result<(), Error>;
|
||||
/// Writes a u16 as bytes
|
||||
fn write_u16(&mut self, n: u16) -> Option<Error>;
|
||||
fn write_u16(&mut self, n: u16) -> Result<(), Error>;
|
||||
/// Writes a u32 as bytes
|
||||
fn write_u32(&mut self, n: u32) -> Option<Error>;
|
||||
fn write_u32(&mut self, n: u32) -> Result<(), Error>;
|
||||
/// Writes a u64 as bytes
|
||||
fn write_u64(&mut self, n: u64) -> Option<Error>;
|
||||
fn write_u64(&mut self, n: u64) -> Result<(), Error>;
|
||||
/// Writes a i64 as bytes
|
||||
fn write_i64(&mut self, n: i64) -> Option<Error>;
|
||||
fn write_i64(&mut self, n: i64) -> Result<(), Error>;
|
||||
/// Writes a variable length `Vec`, the length of the `Vec` is encoded as a
|
||||
/// prefix.
|
||||
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error>;
|
||||
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Result<(), Error>;
|
||||
/// Writes a fixed number of bytes from something that can turn itself into
|
||||
/// a `&[u8]`. The reader is expected to know the actual length on read.
|
||||
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error>;
|
||||
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Implementations defined how different numbers and binary structures are
|
||||
|
@ -98,7 +133,7 @@ pub trait Reader {
|
|||
/// underlying Write implementation.
|
||||
pub trait Writeable {
|
||||
/// Write the data held by this Writeable to the provided writer
|
||||
fn write(&self, writer: &mut Writer) -> Option<Error>;
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Trait that every type that can be deserialized from binary must implement.
|
||||
|
@ -116,7 +151,7 @@ pub fn deserialize<T: Readable<T>>(mut source: &mut Read) -> Result<T, Error> {
|
|||
}
|
||||
|
||||
/// Serializes a Writeable into any std::io::Write implementation.
|
||||
pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
|
||||
pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Result<(), Error> {
|
||||
let mut writer = BinWriter { sink: sink };
|
||||
thing.write(&mut writer)
|
||||
}
|
||||
|
@ -125,9 +160,7 @@ pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
|
|||
/// Vec<u8>.
|
||||
pub fn ser_vec(thing: &Writeable) -> Result<Vec<u8>, Error> {
|
||||
let mut vec = Vec::new();
|
||||
if let Some(err) = serialize(&mut vec, thing) {
|
||||
return Err(err);
|
||||
}
|
||||
try!(serialize(&mut vec, thing));
|
||||
Ok(vec)
|
||||
}
|
||||
|
||||
|
@ -192,33 +225,40 @@ 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_u8(&mut self, n: u8) -> Result<(), Error> {
|
||||
try!(self.sink.write_u8(n));
|
||||
Ok(())
|
||||
}
|
||||
fn write_u16(&mut self, n: u16) -> Option<Error> {
|
||||
self.sink.write_u16::<BigEndian>(n).err().map(Error::IOErr)
|
||||
fn write_u16(&mut self, n: u16) -> Result<(), Error> {
|
||||
try!(self.sink.write_u16::<BigEndian>(n));
|
||||
Ok(())
|
||||
}
|
||||
fn write_u32(&mut self, n: u32) -> Option<Error> {
|
||||
self.sink.write_u32::<BigEndian>(n).err().map(Error::IOErr)
|
||||
fn write_u32(&mut self, n: u32) -> Result<(), Error> {
|
||||
try!(self.sink.write_u32::<BigEndian>(n));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, n: u64) -> Option<Error> {
|
||||
self.sink.write_u64::<BigEndian>(n).err().map(Error::IOErr)
|
||||
fn write_u64(&mut self, n: u64) -> Result<(), Error> {
|
||||
try!(self.sink.write_u64::<BigEndian>(n));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_i64(&mut self, n: i64) -> Option<Error> {
|
||||
self.sink.write_i64::<BigEndian>(n).err().map(Error::IOErr)
|
||||
fn write_i64(&mut self, n: i64) -> Result<(), Error> {
|
||||
try!(self.sink.write_i64::<BigEndian>(n));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error> {
|
||||
try_o!(self.write_u64(vec.len() as u64));
|
||||
self.sink.write_all(vec).err().map(Error::IOErr)
|
||||
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Result<(), Error> {
|
||||
try!(self.write_u64(vec.len() as u64));
|
||||
try!(self.sink.write_all(vec));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error> {
|
||||
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), Error> {
|
||||
let bs = b32.as_fixed_bytes();
|
||||
self.sink.write_all(bs).err().map(Error::IOErr)
|
||||
try!(self.sink.write_all(bs));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue