Merge pull request #11 from merope07/option-t

core: Clean up serialization and hashing
This commit is contained in:
Ignotus Peverell 2016-11-01 10:25:35 -07:00 committed by GitHub
commit 1008539048
10 changed files with 252 additions and 217 deletions

View file

@ -26,7 +26,7 @@ use core::transaction::merkle_inputs_outputs;
use core::{PROOFSIZE, REWARD}; use core::{PROOFSIZE, REWARD};
use core::hash::{Hash, Hashed, ZERO_HASH}; use core::hash::{Hash, Hashed, ZERO_HASH};
use core::transaction::MAX_IN_OUT_LEN; use core::transaction::MAX_IN_OUT_LEN;
use ser::{self, Readable, Reader, Writeable, Writer, ser_vec}; use ser::{self, Readable, Reader, Writeable, Writer};
/// Block header, fairly standard compared to other blockchains. /// Block header, fairly standard compared to other blockchains.
pub struct BlockHeader { pub struct BlockHeader {
@ -60,7 +60,7 @@ impl Default for BlockHeader {
// Only Writeable implementation is required for hashing, which is part of // Only Writeable implementation is required for hashing, which is part of
// 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) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u64, self.height], [write_u64, self.height],
[write_fixed_bytes, &self.previous], [write_fixed_bytes, &self.previous],
@ -70,22 +70,15 @@ impl Writeable for BlockHeader {
[write_u64, self.total_fees]); [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_o!(writer.write_u64(self.nonce)); try!(writer.write_u64(self.nonce));
// cuckoo cycle of 42 nodes // cuckoo cycle of 42 nodes
for n in 0..42 { 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) writer.write_u64(self.td)
} }
} }
impl Hashed for BlockHeader {
fn bytes(&self) -> Vec<u8> {
// no serialization errors are applicable in this specific case
ser_vec(self).unwrap()
}
}
/// A block as expressed in the MimbleWimble protocol. The reward is /// A block as expressed in the MimbleWimble protocol. The reward is
/// non-explicit, assumed to be deductible from block height (similar to /// non-explicit, assumed to be deductible from block height (similar to
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H), /// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
@ -101,23 +94,23 @@ pub struct Block {
/// Implementation of Writeable for a block, defines how to write the full /// Implementation of Writeable for a block, defines how to write the full
/// block as binary. /// block as binary.
impl Writeable for Block { impl Writeable for Block {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try_o!(self.header.write(writer)); try!(self.header.write(writer));
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u64, self.inputs.len() as u64], [write_u64, self.inputs.len() as u64],
[write_u64, self.outputs.len() as u64], [write_u64, self.outputs.len() as u64],
[write_u64, self.proofs.len() as u64]); [write_u64, self.proofs.len() as u64]);
for inp in &self.inputs { for inp in &self.inputs {
try_o!(inp.write(writer)); try!(inp.write(writer));
} }
for out in &self.outputs { for out in &self.outputs {
try_o!(out.write(writer)); try!(out.write(writer));
} }
for proof in &self.proofs { for proof in &self.proofs {
try_o!(proof.write(writer)); try!(proof.write(writer));
} }
None Ok(())
} }
} }

View file

@ -17,10 +17,12 @@
//! Primary hash function used in the protocol //! Primary hash function used in the protocol
//! //!
use byteorder::{ByteOrder, BigEndian};
use std::fmt; use std::fmt;
use tiny_keccak::Keccak; use tiny_keccak::Keccak;
use ser::{self, AsFixedBytes};
/// A hash to uniquely (or close enough) identify one of the main blockchain /// A hash to uniquely (or close enough) identify one of the main blockchain
/// constructs. Used pervasively for blocks, transactions and ouputs. /// constructs. Used pervasively for blocks, transactions and ouputs.
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)] #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
@ -56,27 +58,58 @@ impl Hash {
pub const ZERO_HASH: Hash = Hash([0; 32]); pub const ZERO_HASH: Hash = Hash([0; 32]);
/// A trait for types that get their hash (double SHA256) from their byte /// Serializer that outputs a hash of the serialized object
/// serialzation. pub struct HashWriter {
pub trait Hashed { state: Keccak
fn hash(&self) -> Hash {
let data = self.bytes();
Hash(sha3(data))
}
fn bytes(&self) -> Vec<u8>;
} }
fn sha3(data: Vec<u8>) -> [u8; 32] { impl HashWriter {
let mut sha3 = Keccak::new_sha3_256(); fn finalize(self, output: &mut [u8]) {
let mut buf = [0; 32]; self.state.finalize(output);
sha3.update(&data); }
sha3.finalize(&mut buf); }
buf
impl Default for HashWriter {
fn default() -> HashWriter {
HashWriter {
state: Keccak::new_sha3_256()
}
}
}
impl ser::Writer for HashWriter {
fn serialization_mode(&self) -> ser::SerializationMode {
ser::SerializationMode::Hash
}
fn write_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Result<(), ser::Error> {
self.state.update(b32.as_fixed_bytes());
Ok(())
}
}
/// A trait for types that have a canonical hash
pub trait Hashed {
fn hash(&self) -> Hash;
}
impl<W: ser::Writeable> Hashed for W {
fn hash(&self) -> Hash {
let mut hasher = HashWriter::default();
ser::Writeable::write(self, &mut hasher).unwrap();
let mut ret = [0; 32];
hasher.finalize(&mut ret);
Hash(ret)
}
} }
impl Hashed for [u8] { impl Hashed for [u8] {
fn bytes(&self) -> Vec<u8> { fn hash(&self) -> Hash {
self.to_owned() let mut hasher = HashWriter::default();
let mut ret = [0; 32];
ser::Writer::write_bytes(&mut hasher, &self).unwrap();
hasher.finalize(&mut ret);
Hash(ret)
} }
} }

View file

@ -18,25 +18,18 @@ pub mod block;
pub mod hash; pub mod hash;
pub mod transaction; pub mod transaction;
#[allow(dead_code)] #[allow(dead_code)]
#[macro_use]
pub use self::block::{Block, BlockHeader}; pub use self::block::{Block, BlockHeader};
pub use self::transaction::{Transaction, Input, Output, TxProof}; pub use self::transaction::{Transaction, Input, Output, TxProof};
use self::hash::{Hash, Hashed, ZERO_HASH}; use self::hash::{Hash, Hashed, ZERO_HASH};
use ser::{Writeable, Writer, Error, ser_vec}; use ser::{Writeable, Writer, Error};
use time;
use std::fmt; use std::fmt;
use std::cmp::Ordering; use std::cmp::Ordering;
use secp; use secp::{self, Secp256k1};
use secp::{Secp256k1, Signature, Message};
use secp::key::SecretKey;
use secp::pedersen::*; use secp::pedersen::*;
use tiny_keccak::Keccak;
/// The block subsidy amount /// The block subsidy amount
pub const REWARD: u64 = 1_000_000_000; pub const REWARD: u64 = 1_000_000_000;
@ -154,12 +147,12 @@ impl Proof {
/// Two hashes that will get hashed together in a Merkle tree to build the next /// Two hashes that will get hashed together in a Merkle tree to build the next
/// level up. /// level up.
struct HPair(Hash, Hash); struct HPair(Hash, Hash);
impl Hashed for HPair {
fn bytes(&self) -> Vec<u8> { impl Writeable for HPair {
let mut data = Vec::with_capacity(64); fn write(&self, writer: &mut Writer) -> Result<(), Error> {
data.extend_from_slice(self.0.to_slice()); try!(writer.write_bytes(&self.0.to_slice()));
data.extend_from_slice(self.1.to_slice()); try!(writer.write_bytes(&self.1.to_slice()));
return data; Ok(())
} }
} }
/// An iterator over hashes in a vector that pairs them to build a row in a /// An iterator over hashes in a vector that pairs them to build a row in a
@ -198,7 +191,7 @@ impl MerkleRow {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use super::hash::{Hash, Hashed, ZERO_HASH}; use core::hash::ZERO_HASH;
use secp; use secp;
use secp::Secp256k1; use secp::Secp256k1;
use secp::key::SecretKey; use secp::key::SecretKey;

View file

@ -16,7 +16,7 @@
use core::Committed; use core::Committed;
use core::MerkleRow; use core::MerkleRow;
use core::hash::{Hashed, Hash}; use core::hash::{Hash, Hashed};
use ser::{self, Reader, Writer, Readable, Writeable}; use ser::{self, Reader, Writer, Readable, Writeable};
use secp::{self, Secp256k1, Message, Signature}; use secp::{self, Secp256k1, Message, Signature};
@ -39,9 +39,9 @@ pub struct TxProof {
} }
impl Writeable for TxProof { impl Writeable for TxProof {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try_o!(writer.write_fixed_bytes(&self.remainder)); try!(writer.write_fixed_bytes(&self.remainder));
writer.write_vec(&mut self.sig.clone()) writer.write_bytes(&self.sig)
} }
} }
@ -68,19 +68,19 @@ pub struct Transaction {
/// Implementation of Writeable for a fully blinded transaction, defines how to /// Implementation of Writeable for a fully blinded transaction, defines how to
/// 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) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u64, self.fee], [write_u64, self.fee],
[write_vec, &mut self.zerosig.clone()], [write_bytes, &self.zerosig],
[write_u64, self.inputs.len() as u64], [write_u64, self.inputs.len() as u64],
[write_u64, self.outputs.len() as u64]); [write_u64, self.outputs.len() as u64]);
for inp in &self.inputs { for inp in &self.inputs {
try_o!(inp.write(writer)); try!(inp.write(writer));
} }
for out in &self.outputs { 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 /// Implementation of Writeable for a transaction Input, defines how to write
/// an Input as binary. /// an Input as binary.
impl Writeable for Input { 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()) writer.write_fixed_bytes(&self.output_hash())
} }
} }
@ -283,13 +283,6 @@ impl Input {
} }
} }
/// The hash of an input is the hash of the output hash it references.
impl Hashed for Input {
fn bytes(&self) -> Vec<u8> {
self.output_hash().to_vec()
}
}
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum Output { pub enum Output {
BlindOutput { BlindOutput {
@ -302,9 +295,13 @@ pub enum Output {
/// Implementation of Writeable for a transaction Output, defines how to write /// Implementation of Writeable for a transaction Output, defines how to write
/// an Output as binary. /// an Output as binary.
impl Writeable for Output { impl Writeable for Output {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try_o!(writer.write_fixed_bytes(&self.commitment().unwrap())); // The hash of an output is only the hash of its commitment.
writer.write_vec(&mut self.proof().unwrap().bytes().to_vec()) try!(writer.write_fixed_bytes(&self.commitment().unwrap()));
if writer.serialization_mode() == ser::SerializationMode::Full {
try!(writer.write_bytes(&self.proof().unwrap().bytes()))
}
Ok(())
} }
} }
@ -363,17 +360,6 @@ impl Output {
} }
} }
/// The hash of an output is the hash of its commitment.
impl Hashed for Output {
fn bytes(&self) -> Vec<u8> {
if let &Output::BlindOutput { commit, .. } = self {
return commit.bytes().to_vec();
} else {
panic!("cannot hash an overt output");
}
}
}
/// Utility function to calculate the Merkle root of vectors of inputs and /// Utility function to calculate the Merkle root of vectors of inputs and
/// outputs. /// outputs.
pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash { pub fn merkle_inputs_outputs(inputs: &Vec<Input>, outputs: &Vec<Output>) -> Hash {
@ -392,7 +378,6 @@ mod test {
use secp::{self, Secp256k1}; use secp::{self, Secp256k1};
use secp::key::SecretKey; use secp::key::SecretKey;
use rand::Rng;
use rand::os::OsRng; use rand::os::OsRng;
fn new_secp() -> Secp256k1 { fn new_secp() -> Secp256k1 {
@ -407,9 +392,7 @@ mod test {
let tx = tx2i1o(secp, &mut rng); let tx = tx2i1o(secp, &mut rng);
let btx = tx.blind(&secp).unwrap(); let btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new(); let mut vec = Vec::new();
if let Some(e) = serialize(&mut vec, &btx) { serialize(&mut vec, &btx).expect("serialized failed");
panic!(e);
}
assert!(vec.len() > 5320); assert!(vec.len() > 5320);
assert!(vec.len() < 5340); assert!(vec.len() < 5340);
} }
@ -420,14 +403,12 @@ mod test {
let ref secp = new_secp(); let ref secp = new_secp();
let tx = tx2i1o(secp, &mut rng); let tx = tx2i1o(secp, &mut rng);
let mut btx = tx.blind(&secp).unwrap(); let btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new(); let mut vec = Vec::new();
if let Some(e) = serialize(&mut vec, &btx) { serialize(&mut vec, &btx).expect("serialization failed");
panic!(e);
}
// let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..] // let mut dtx = Transaction::read(&mut BinReader { source: &mut &vec[..]
// }).unwrap(); // }).unwrap();
let mut dtx: Transaction = deserialize(&mut &vec[..]).unwrap(); let dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
assert_eq!(dtx.fee, 1); assert_eq!(dtx.fee, 1);
assert_eq!(dtx.inputs.len(), 2); assert_eq!(dtx.inputs.len(), 2);
assert_eq!(dtx.outputs.len(), 1); assert_eq!(dtx.outputs.len(), 1);
@ -441,15 +422,15 @@ mod test {
let ref secp = new_secp(); let ref secp = new_secp();
let tx = tx2i1o(secp, &mut rng); let tx = tx2i1o(secp, &mut rng);
let mut btx = tx.blind(&secp).unwrap(); let btx = tx.blind(&secp).unwrap();
let mut vec = Vec::new(); 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 dtx: Transaction = deserialize(&mut &vec[..]).unwrap();
let mut vec2 = Vec::new(); 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(); let dtx2: Transaction = deserialize(&mut &vec2[..]).unwrap();
assert_eq!(btx.hash(), dtx.hash()); assert_eq!(btx.hash(), dtx.hash());
assert_eq!(dtx.hash(), dtx2.hash()); assert_eq!(dtx.hash(), dtx2.hash());
@ -536,10 +517,10 @@ mod test {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
let tx1 = tx2i1o(secp, &mut rng); let tx1 = tx2i1o(secp, &mut rng);
let mut btx1 = tx1.blind(&secp).unwrap(); let btx1 = tx1.blind(&secp).unwrap();
let tx2 = tx1i1o(secp, &mut rng); let tx2 = tx1i1o(secp, &mut rng);
let mut btx2 = tx2.blind(&secp).unwrap(); let btx2 = tx2.blind(&secp).unwrap();
if btx1.hash() == btx2.hash() { if btx1.hash() == btx2.hash() {
panic!("diff txs have same hash") panic!("diff txs have same hash")

View file

@ -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_export]
macro_rules! try_to_o { macro_rules! try_to_o {
($trying:expr) => {{ ($trying:expr) => {{
@ -109,6 +96,6 @@ macro_rules! ser_multiread {
#[macro_export] #[macro_export]
macro_rules! ser_multiwrite { macro_rules! ser_multiwrite {
($wrtr:ident, $([ $write_call:ident, $val:expr ]),* ) => { ($wrtr:ident, $([ $write_call:ident, $val:expr ]),* ) => {
$( try_o!($wrtr.$write_call($val)) );* $( try!($wrtr.$write_call($val)) );*
} }
} }

View file

@ -19,7 +19,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::cmp; use std::cmp;
use std::fmt;
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha2::Sha256; use crypto::sha2::Sha256;

View file

@ -27,12 +27,12 @@ mod cuckoo;
use time; use time;
use core::{Block, BlockHeader, Proof, PROOFSIZE}; use core::{Block, Proof, PROOFSIZE};
use core::hash::{Hash, Hashed}; use core::hash::{Hash, Hashed};
use pow::cuckoo::{Cuckoo, Miner, Error}; use pow::cuckoo::{Cuckoo, Miner, Error};
use ser; use ser;
use ser::{Writeable, Writer, ser_vec}; use ser::{Writeable, Writer};
/// Default Cuckoo Cycle size shift used is 28. We may decide to increase it. /// Default Cuckoo Cycle size shift used is 28. We may decide to increase it.
/// when difficuty increases. /// when difficuty increases.
@ -71,27 +71,20 @@ struct PowHeader {
/// the data that gets hashed for PoW calculation. The nonce is written first /// the data that gets hashed for PoW calculation. The nonce is written first
/// to make incrementing from the serialized form trivial. /// to make incrementing from the serialized form trivial.
impl Writeable for PowHeader { impl Writeable for PowHeader {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
try_o!(writer.write_u64(self.nonce)); try!(writer.write_u64(self.nonce));
try_o!(writer.write_u64(self.height)); try!(writer.write_u64(self.height));
try_o!(writer.write_fixed_bytes(&self.previous)); try!(writer.write_fixed_bytes(&self.previous));
try_o!(writer.write_i64(self.timestamp.to_timespec().sec)); try!(writer.write_i64(self.timestamp.to_timespec().sec));
try_o!(writer.write_fixed_bytes(&self.utxo_merkle)); try!(writer.write_fixed_bytes(&self.utxo_merkle));
try_o!(writer.write_fixed_bytes(&self.tx_merkle)); try!(writer.write_fixed_bytes(&self.tx_merkle));
try_o!(writer.write_u64(self.total_fees)); try!(writer.write_u64(self.total_fees));
try_o!(writer.write_u64(self.n_in)); try!(writer.write_u64(self.n_in));
try_o!(writer.write_u64(self.n_out)); try!(writer.write_u64(self.n_out));
writer.write_u64(self.n_proofs) writer.write_u64(self.n_proofs)
} }
} }
impl Hashed for PowHeader {
fn bytes(&self) -> Vec<u8> {
// no serialization errors are applicable in this specific case
ser_vec(self).unwrap()
}
}
impl PowHeader { impl PowHeader {
fn from_block(b: &Block) -> PowHeader { fn from_block(b: &Block) -> PowHeader {
let ref h = b.header; let ref h = b.header;
@ -176,9 +169,7 @@ fn pow_size(b: &Block, target: Proof, sizeshift: u32) -> Result<(Proof, u64), Er
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use core::{BlockHeader, Proof}; use core::Proof;
use core::hash::Hash;
use std::time::Instant;
use genesis; use genesis;
#[test] #[test]

View file

@ -19,9 +19,9 @@
//! To use it simply implement `Writeable` or `Readable` and then use the //! To use it simply implement `Writeable` or `Readable` and then use the
//! `serialize` or `deserialize` functions on them as appropriate. //! `serialize` or `deserialize` functions on them as appropriate.
use std::io; use std::{error, fmt};
use std::io::{Write, Read}; use std::io::{self, Write, Read};
use byteorder::{ReadBytesExt, WriteBytesExt, BigEndian}; use byteorder::{ByteOrder, ReadBytesExt, BigEndian};
/// Possible errors deriving from serializing or deserializing. /// Possible errors deriving from serializing or deserializing.
#[derive(Debug)] #[derive(Debug)]
@ -33,12 +33,47 @@ pub enum Error {
expected: Vec<u8>, expected: Vec<u8>,
received: Vec<u8>, received: Vec<u8>,
}, },
/// Data wasn't in a consumable format /// Data wasn't in a consumable format
CorruptedData, CorruptedData,
/// When asked to read too much data /// When asked to read too much data
TooLargeReadErr(String), 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 /// Useful trait to implement on types that can be translated to byte slices
/// directly. Allows the use of `write_fixed_bytes` on them. /// directly. Allows the use of `write_fixed_bytes` on them.
pub trait AsFixedBytes { pub trait AsFixedBytes {
@ -46,25 +81,67 @@ pub trait AsFixedBytes {
fn as_fixed_bytes(&self) -> &[u8]; fn as_fixed_bytes(&self) -> &[u8];
} }
/// Signal to a serializable object how much of its data should be serialized
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum SerializationMode {
/// Serialize everything sufficiently to fully reconstruct the object
Full,
/// Serialize the data that defines the object
Hash,
/// Serialize everything that a signer of the object should know
SigHash
}
/// Implementations defined how different numbers and binary structures are /// Implementations defined how different numbers and binary structures are
/// 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 {
/// The mode this serializer is writing in
fn serialization_mode(&self) -> SerializationMode;
/// 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) -> Result<(), Error> {
self.write_fixed_bytes(&[n])
}
/// Writes a u16 as bytes /// Writes a u16 as bytes
fn write_u16(&mut self, n: u16) -> Option<Error>; fn write_u16(&mut self, n: u16) -> Result<(), Error> {
let mut bytes = [0; 2];
BigEndian::write_u16(&mut bytes, n);
self.write_fixed_bytes(&bytes)
}
/// 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) -> Result<(), Error> {
let mut bytes = [0; 4];
BigEndian::write_u32(&mut bytes, n);
self.write_fixed_bytes(&bytes)
}
/// Writes a u64 as bytes /// Writes a u64 as bytes
fn write_u64(&mut self, n: u64) -> Option<Error>; fn write_u64(&mut self, n: u64) -> Result<(), Error> {
let mut bytes = [0; 8];
BigEndian::write_u64(&mut bytes, n);
self.write_fixed_bytes(&bytes)
}
/// Writes a i64 as bytes /// 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 let mut bytes = [0; 8];
BigEndian::write_i64(&mut bytes, n);
self.write_fixed_bytes(&bytes)
}
/// Writes a variable number of bytes. The length is encoded as a 64-bit
/// prefix. /// prefix.
fn write_vec(&mut self, vec: &mut Vec<u8>) -> Option<Error>; fn write_bytes(&mut self, bytes: &AsFixedBytes) -> Result<(), Error> {
try!(self.write_u64(bytes.as_fixed_bytes().len() as u64));
self.write_fixed_bytes(bytes)
}
/// Writes a fixed number of bytes from something that can turn itself into /// 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. /// 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, fixed: &AsFixedBytes) -> Result<(), Error>;
} }
/// Implementations defined how different numbers and binary structures are /// Implementations defined how different numbers and binary structures are
@ -98,7 +175,7 @@ pub trait Reader {
/// underlying Write implementation. /// underlying Write implementation.
pub trait Writeable { pub trait Writeable {
/// Write the data held by this Writeable to the provided writer /// 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. /// Trait that every type that can be deserialized from binary must implement.
@ -116,7 +193,7 @@ pub fn deserialize<T: Readable<T>>(mut source: &mut Read) -> Result<T, Error> {
} }
/// Serializes a Writeable into any std::io::Write implementation. /// 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 }; let mut writer = BinWriter { sink: sink };
thing.write(&mut writer) thing.write(&mut writer)
} }
@ -125,9 +202,7 @@ pub fn serialize(mut sink: &mut Write, thing: &Writeable) -> Option<Error> {
/// Vec<u8>. /// Vec<u8>.
pub fn ser_vec(thing: &Writeable) -> Result<Vec<u8>, Error> { pub fn ser_vec(thing: &Writeable) -> Result<Vec<u8>, Error> {
let mut vec = Vec::new(); let mut vec = Vec::new();
if let Some(err) = serialize(&mut vec, thing) { try!(serialize(&mut vec, thing));
return Err(err);
}
Ok(vec) Ok(vec)
} }
@ -192,33 +267,14 @@ struct BinWriter<'a> {
} }
impl<'a> Writer for BinWriter<'a> { impl<'a> Writer for BinWriter<'a> {
fn write_u8(&mut self, n: u8) -> Option<Error> { fn serialization_mode(&self) -> SerializationMode {
self.sink.write_u8(n).err().map(Error::IOErr) SerializationMode::Full
}
fn write_u16(&mut self, n: u16) -> Option<Error> {
self.sink.write_u16::<BigEndian>(n).err().map(Error::IOErr)
}
fn write_u32(&mut self, n: u32) -> Option<Error> {
self.sink.write_u32::<BigEndian>(n).err().map(Error::IOErr)
} }
fn write_u64(&mut self, n: u64) -> Option<Error> { fn write_fixed_bytes(&mut self, fixed: &AsFixedBytes) -> Result<(), Error> {
self.sink.write_u64::<BigEndian>(n).err().map(Error::IOErr) let bs = fixed.as_fixed_bytes();
} try!(self.sink.write_all(bs));
Ok(())
fn write_i64(&mut self, n: i64) -> Option<Error> {
self.sink.write_i64::<BigEndian>(n).err().map(Error::IOErr)
}
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_fixed_bytes(&mut self, b32: &AsFixedBytes) -> Option<Error> {
let bs = b32.as_fixed_bytes();
self.sink.write_all(bs).err().map(Error::IOErr)
} }
} }
@ -236,6 +292,16 @@ impl_slice_bytes!(::secp::key::SecretKey);
impl_slice_bytes!(::secp::Signature); impl_slice_bytes!(::secp::Signature);
impl_slice_bytes!(::secp::pedersen::Commitment); impl_slice_bytes!(::secp::pedersen::Commitment);
impl_slice_bytes!(Vec<u8>); impl_slice_bytes!(Vec<u8>);
impl_slice_bytes!([u8; 1]);
impl_slice_bytes!([u8; 2]);
impl_slice_bytes!([u8; 4]);
impl_slice_bytes!([u8; 8]);
impl<'a> AsFixedBytes for &'a [u8] {
fn as_fixed_bytes(&self) -> &[u8] {
*self
}
}
impl AsFixedBytes for ::core::hash::Hash { impl AsFixedBytes for ::core::hash::Hash {
fn as_fixed_bytes(&self) -> &[u8] { fn as_fixed_bytes(&self) -> &[u8] {

View file

@ -51,19 +51,15 @@ impl Handshake {
// send the first part of the handshake // send the first part of the handshake
let sender_addr = conn.local_addr().unwrap(); let sender_addr = conn.local_addr().unwrap();
let receiver_addr = conn.peer_addr().unwrap(); let receiver_addr = conn.peer_addr().unwrap();
let opt_err = serialize(&mut conn, try!(serialize(&mut conn,
&Hand { &Hand {
version: PROTOCOL_VERSION, version: PROTOCOL_VERSION,
capabilities: FULL_SYNC, capabilities: FULL_SYNC,
nonce: nonce, nonce: nonce,
sender_addr: SockAddr(sender_addr), sender_addr: SockAddr(sender_addr),
receiver_addr: SockAddr(receiver_addr), receiver_addr: SockAddr(receiver_addr),
user_agent: USER_AGENT.to_string(), user_agent: USER_AGENT.to_string(),
}); }));
match opt_err {
Some(err) => return Err(err),
None => {}
}
// deserialize the handshake response and do version negotiation // deserialize the handshake response and do version negotiation
let shake = try!(deserialize::<Shake>(&mut conn)); let shake = try!(deserialize::<Shake>(&mut conn));
@ -127,16 +123,12 @@ impl Handshake {
}; };
// send our reply with our info // send our reply with our info
let opt_err = serialize(&mut conn, try!(serialize(&mut conn,
&Shake { &Shake {
version: PROTOCOL_VERSION, version: PROTOCOL_VERSION,
capabilities: FULL_SYNC, capabilities: FULL_SYNC,
user_agent: USER_AGENT.to_string(), user_agent: USER_AGENT.to_string(),
}); }));
match opt_err {
Some(err) => return Err(err),
None => {}
}
info!("Received connection from peer {:?}", peer_info); info!("Received connection from peer {:?}", peer_info);
// when more than one protocol version is supported, choosing should go here // when more than one protocol version is supported, choosing should go here

View file

@ -18,7 +18,7 @@ use std::net::*;
use num::FromPrimitive; use num::FromPrimitive;
use core::ser::{self, Writeable, Readable, Writer, Reader, Error}; use core::ser::{self, Writeable, Readable, Writer, Reader};
use types::*; use types::*;
@ -72,12 +72,12 @@ impl MsgHeader {
} }
impl Writeable for MsgHeader { impl Writeable for MsgHeader {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u8, self.magic[0]], [write_u8, self.magic[0]],
[write_u8, self.magic[1]], [write_u8, self.magic[1]],
[write_u8, self.msg_type as u8]); [write_u8, self.msg_type as u8]);
None Ok(())
} }
} }
@ -111,14 +111,14 @@ pub struct Hand {
} }
impl Writeable for Hand { impl Writeable for Hand {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u32, self.version], [write_u32, self.version],
[write_u32, self.capabilities.bits()], [write_u32, self.capabilities.bits()],
[write_u64, self.nonce]); [write_u64, self.nonce]);
self.sender_addr.write(writer); self.sender_addr.write(writer);
self.receiver_addr.write(writer); self.receiver_addr.write(writer);
writer.write_vec(&mut self.user_agent.clone().into_bytes()) writer.write_bytes(self.user_agent.as_bytes())
} }
} }
@ -153,12 +153,12 @@ pub struct Shake {
} }
impl Writeable for Shake { impl Writeable for Shake {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u32, self.version], [write_u32, self.version],
[write_u32, self.capabilities.bits()], [write_u32, self.capabilities.bits()],
[write_vec, &mut self.user_agent.as_bytes().to_vec()]); [write_bytes, self.user_agent.as_bytes()]);
None Ok(())
} }
} }
@ -233,11 +233,11 @@ pub struct PeerError {
} }
impl Writeable for PeerError { impl Writeable for PeerError {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
[write_u32, self.code], [write_u32, self.code],
[write_vec, &mut self.message.clone().into_bytes()]); [write_bytes, self.message.as_bytes()]);
None Ok(())
} }
} }
@ -258,7 +258,7 @@ impl Readable<PeerError> for PeerError {
pub struct SockAddr(pub SocketAddr); pub struct SockAddr(pub SocketAddr);
impl Writeable for SockAddr { impl Writeable for SockAddr {
fn write(&self, writer: &mut Writer) -> Option<ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
match self.0 { match self.0 {
SocketAddr::V4(sav4) => { SocketAddr::V4(sav4) => {
ser_multiwrite!(writer, ser_multiwrite!(writer,
@ -267,14 +267,14 @@ impl Writeable for SockAddr {
[write_u16, sav4.port()]); [write_u16, sav4.port()]);
} }
SocketAddr::V6(sav6) => { SocketAddr::V6(sav6) => {
try_o!(writer.write_u8(1)); try!(writer.write_u8(1));
for seg in &sav6.ip().segments() { for seg in &sav6.ip().segments() {
try_o!(writer.write_u16(*seg)); try!(writer.write_u16(*seg));
} }
try_o!(writer.write_u16(sav6.port())); try!(writer.write_u16(sav6.port()));
} }
} }
None Ok(())
} }
} }