From 119ae9481637c040572a9cba645d83b689fccb1d Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 16 Apr 2016 20:11:18 +0300 Subject: [PATCH 1/9] raw bytes refactoring --- util/src/bytes.rs | 97 +++++++++++++++++++++++++++++++++++++++--- util/src/keys/store.rs | 14 +++--- 2 files changed, 98 insertions(+), 13 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 0683ea4df..c8dd9e38e 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -247,7 +247,7 @@ pub trait FromRawBytes : Sized { fn from_bytes(d: &[u8]) -> Result; } -impl FromRawBytes for T where T: Sized + FixedHash { +impl FromRawBytes for (T) where T: FixedHash { fn from_bytes(bytes: &[u8]) -> Result { use std::mem; use std::cmp::Ordering; @@ -263,15 +263,79 @@ impl FromRawBytes for T where T: Sized + FixedHash { } } -impl FromRawBytes for String { - fn from_bytes(bytes: &[u8]) -> Result { +impl FromRawBytes for u16 { + fn from_bytes(bytes: &[u8]) -> Result { + use std::mem; + use std::cmp::Ordering; + + match bytes.len().cmp(&2) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + let mut res: Self = unsafe { mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } +} + +impl FromRawBytes for u8 { + fn from_bytes(bytes: &[u8]) -> Result { + use std::mem; + use std::cmp::Ordering; + + match bytes.len().cmp(&1) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + let mut res: Self = unsafe { mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } +} + +pub trait FromRawBytesVariable : Sized { + fn from_bytes_var(d: &[u8], len: u64) -> Result; +} + +impl FromRawBytesVariable for T where T: FromRawBytes { + fn from_bytes_var(d: &[u8], _len: u64) -> Result { + T::from_bytes(d) + } +} + +impl FromRawBytesVariable for String { + fn from_bytes_var(bytes: &[u8], _len: u64) -> Result { Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) } } -impl FromRawBytes for Vec { - fn from_bytes(bytes: &[u8]) -> Result, FromBytesError> { - Ok(bytes.clone().to_vec()) +impl FromRawBytesVariable for Vec where T: FromRawBytes { + fn from_bytes_var(d: &[u8], len: u64) -> Result { + let size_of_t = ::std::mem::size_of::(); + assert_eq!(len, 8); + let length_in_chunks = len as usize / size_of_t; + + let mut result = Vec::with_capacity(length_in_chunks as usize); + unsafe { result.set_len(length_in_chunks as usize) }; + for i in 0..length_in_chunks { *result.get_mut(i).unwrap() = try!(T::from_bytes(&d[size_of_t * i..size_of_t * (i+1)])) } + Ok(result) + } +} + +impl FromRawBytes for (V1, T2) where V1: FromRawBytesVariable, T2: FromRawBytes { + fn from_bytes(d: &[u8]) -> Result { + let header = 8usize; + let mut map: (u64, ) = unsafe { ::std::mem::uninitialized() }; + + if d.len() < header { return Err(FromBytesError::NotLongEnough); } + map.copy_raw(&d[0..header]); + + Ok(( + try!(V1::from_bytes_var(&d[header..header + (map.0 as usize)], map.0)), + try!(T2::from_bytes(&d[header + (map.0 as usize)..d.len()])), + )) } } @@ -326,3 +390,24 @@ fn populate_big_types() { h.copy_raw_from(&a); assert_eq!(h, h256_from_hex("ffffffffffffffffffffffffffffffffffffffff000000000000000000000069")); } + +#[test] +fn raw_bytes_from_tuple() { + let tup = (vec![1u16, 1u16, 1u16, 1u16], 10u16); + let bytes = vec![ + // map + 8u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + // four 1u16 + 0u8, 1u8, + 0u8, 1u8, + 0u8, 1u8, + 0u8, 1u8, + // 10u16 + 0u8, 10u8]; + + type tup = (Vec, u16); + + let tup_from = tup::from_bytes(&bytes).unwrap(); + + assert_eq!(tup, tup_from); +} diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 36edb0ff1..8b53b3d85 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -34,11 +34,11 @@ const KEY_LENGTH_AES_USIZE: usize = KEY_LENGTH_AES as usize; /// Encrypted hash-map, each request should contain password pub trait EncryptedHashMap { /// Returns existing value for the key, if any - fn get(&self, key: &Key, password: &str) -> Result; + fn get(&self, key: &Key, password: &str) -> Result; /// Insert new encrypted key-value and returns previous if there was any - fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; /// Removes key-value by key and returns the removed one, if any exists and password was provided - fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; /// Deletes key-value by key and returns if the key-value existed fn delete(&mut self, key: &Key) -> bool { self.remove::(key, None).is_some() @@ -306,7 +306,7 @@ fn derive_mac(derived_left_bits: &[u8], cipher_text: &[u8]) -> Bytes { } impl EncryptedHashMap for SecretStore { - fn get(&self, key: &H128, password: &str) -> Result { + fn get(&self, key: &H128, password: &str) -> Result { match self.directory.get(key) { Some(key_file) => { let (derived_left_bits, derived_right_bits) = match key_file.crypto.kdf { @@ -324,7 +324,7 @@ impl EncryptedHashMap for SecretStore { } }; - match Value::from_bytes(&val) { + match Value::from_bytes_var(&val, val.len() as u64) { Ok(value) => Ok(value), Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) } @@ -333,7 +333,7 @@ impl EncryptedHashMap for SecretStore { } } - fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option { let previous = if let Ok(previous_value) = self.get(&key, password) { Some(previous_value) } else { None }; // crypto random initiators @@ -366,7 +366,7 @@ impl EncryptedHashMap for SecretStore { previous } - fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { let previous = if let Some(pass) = password { if let Ok(previous_value) = self.get(&key, pass) { Some(previous_value) } else { None } } From 2812dee8d4b0b6718cdf069210dc602c78a82e4f Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 10:40:35 +0300 Subject: [PATCH 2/9] ongoing change --- util/src/bytes.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index c8dd9e38e..cb54f8f0e 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -314,7 +314,6 @@ impl FromRawBytesVariable for String { impl FromRawBytesVariable for Vec where T: FromRawBytes { fn from_bytes_var(d: &[u8], len: u64) -> Result { let size_of_t = ::std::mem::size_of::(); - assert_eq!(len, 8); let length_in_chunks = len as usize / size_of_t; let mut result = Vec::with_capacity(length_in_chunks as usize); From 060e4bcd3235adc33bf50c1cda2a5af582895dc0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 11:06:59 +0300 Subject: [PATCH 3/9] adding docs --- util/src/bytes.rs | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index cb54f8f0e..47264db4d 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -247,7 +247,7 @@ pub trait FromRawBytes : Sized { fn from_bytes(d: &[u8]) -> Result; } -impl FromRawBytes for (T) where T: FixedHash { +impl FromRawBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> Result { use std::mem; use std::cmp::Ordering; @@ -279,28 +279,20 @@ impl FromRawBytes for u16 { } } -impl FromRawBytes for u8 { - fn from_bytes(bytes: &[u8]) -> Result { - use std::mem; - use std::cmp::Ordering; - - match bytes.len().cmp(&1) { - Ordering::Less => return Err(FromBytesError::NotLongEnough), - Ordering::Greater => return Err(FromBytesError::TooLong), - Ordering::Equal => () - }; - let mut res: Self = unsafe { mem::uninitialized() }; - res.copy_raw(bytes); - Ok(res) - } -} - +/// Value that can be serialized from variable-length byte array pub trait FromRawBytesVariable : Sized { + /// Create value from slice fn from_bytes_var(d: &[u8], len: u64) -> Result; } impl FromRawBytesVariable for T where T: FromRawBytes { - fn from_bytes_var(d: &[u8], _len: u64) -> Result { + fn from_bytes_var(bytes: &[u8], len: u64) -> Result { + match bytes.len().cmp(&len) { + Ordering::Less => return Err(FromBytesError::NotLongEnough), + Ordering::Greater => return Err(FromBytesError::TooLong), + Ordering::Equal => () + }; + T::from_bytes(d) } } @@ -395,18 +387,18 @@ fn raw_bytes_from_tuple() { let tup = (vec![1u16, 1u16, 1u16, 1u16], 10u16); let bytes = vec![ // map - 8u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, + 8u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, // four 1u16 - 0u8, 1u8, - 0u8, 1u8, - 0u8, 1u8, - 0u8, 1u8, + 1u8, 0u8, + 1u8, 0u8, + 1u8, 0u8, + 1u8, 0u8, // 10u16 - 0u8, 10u8]; + 10u8, 0u8]; - type tup = (Vec, u16); + type Tup = (Vec, u16); - let tup_from = tup::from_bytes(&bytes).unwrap(); + let tup_from = Tup::from_bytes(&bytes).unwrap(); assert_eq!(tup, tup_from); } From 3e2875f3d531a603c360756f4c2c6c2c50d223d6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 11:13:25 +0300 Subject: [PATCH 4/9] removing redundant implements --- util/src/bytes.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 47264db4d..231ad2512 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -282,12 +282,12 @@ impl FromRawBytes for u16 { /// Value that can be serialized from variable-length byte array pub trait FromRawBytesVariable : Sized { /// Create value from slice - fn from_bytes_var(d: &[u8], len: u64) -> Result; + fn from_bytes(d: &[u8]) -> Result; } impl FromRawBytesVariable for T where T: FromRawBytes { - fn from_bytes_var(bytes: &[u8], len: u64) -> Result { - match bytes.len().cmp(&len) { + fn from_bytes(bytes: &[u8],) -> Result { + match bytes.len().cmp(&::std::mem::size_of::()) { Ordering::Less => return Err(FromBytesError::NotLongEnough), Ordering::Greater => return Err(FromBytesError::TooLong), Ordering::Equal => () From ef34b3d9aa58e156623395d606be5fca16d21d27 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 14:06:14 +0300 Subject: [PATCH 5/9] convertables --- util/src/bytes.rs | 69 ++++++++++++++++++++++++++++-------------- util/src/keys/store.rs | 2 +- 2 files changed, 47 insertions(+), 24 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 231ad2512..f714b3d55 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -37,6 +37,8 @@ use std::slice; use std::ops::{Deref, DerefMut}; use hash::FixedHash; use elastic_array::*; +use std::mem; +use std::cmp::Ordering; /// Vector like object pub trait VecLike { @@ -249,8 +251,6 @@ pub trait FromRawBytes : Sized { impl FromRawBytes for T where T: FixedHash { fn from_bytes(bytes: &[u8]) -> Result { - use std::mem; - use std::cmp::Ordering; match bytes.len().cmp(&mem::size_of::()) { Ordering::Less => return Err(FromBytesError::NotLongEnough), Ordering::Greater => return Err(FromBytesError::TooLong), @@ -265,9 +265,6 @@ impl FromRawBytes for T where T: FixedHash { impl FromRawBytes for u16 { fn from_bytes(bytes: &[u8]) -> Result { - use std::mem; - use std::cmp::Ordering; - match bytes.len().cmp(&2) { Ordering::Less => return Err(FromBytesError::NotLongEnough), Ordering::Greater => return Err(FromBytesError::TooLong), @@ -282,54 +279,78 @@ impl FromRawBytes for u16 { /// Value that can be serialized from variable-length byte array pub trait FromRawBytesVariable : Sized { /// Create value from slice - fn from_bytes(d: &[u8]) -> Result; + fn from_bytes_variable(bytes: &[u8]) -> Result; } impl FromRawBytesVariable for T where T: FromRawBytes { - fn from_bytes(bytes: &[u8],) -> Result { - match bytes.len().cmp(&::std::mem::size_of::()) { + fn from_bytes_variable(bytes: &[u8]) -> Result { + match bytes.len().cmp(&mem::size_of::()) { Ordering::Less => return Err(FromBytesError::NotLongEnough), Ordering::Greater => return Err(FromBytesError::TooLong), Ordering::Equal => () }; - T::from_bytes(d) + T::from_bytes(bytes) } } impl FromRawBytesVariable for String { - fn from_bytes_var(bytes: &[u8], _len: u64) -> Result { + fn from_bytes_variable(bytes: &[u8]) -> Result { Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) } } impl FromRawBytesVariable for Vec where T: FromRawBytes { - fn from_bytes_var(d: &[u8], len: u64) -> Result { - let size_of_t = ::std::mem::size_of::(); - let length_in_chunks = len as usize / size_of_t; + fn from_bytes_variable(bytes: &[u8]) -> Result { + let size_of_t = mem::size_of::(); + let length_in_chunks = bytes.len() / size_of_t; - let mut result = Vec::with_capacity(length_in_chunks as usize); - unsafe { result.set_len(length_in_chunks as usize) }; - for i in 0..length_in_chunks { *result.get_mut(i).unwrap() = try!(T::from_bytes(&d[size_of_t * i..size_of_t * (i+1)])) } + let mut result = Vec::with_capacity(length_in_chunks ); + unsafe { result.set_len(length_in_chunks) }; + for i in 0..length_in_chunks { + *result.get_mut(i).unwrap() = try!(T::from_bytes( + &bytes[size_of_t * i..size_of_t * (i+1)])) + } Ok(result) } } impl FromRawBytes for (V1, T2) where V1: FromRawBytesVariable, T2: FromRawBytes { - fn from_bytes(d: &[u8]) -> Result { + fn from_bytes(bytes: &[u8]) -> Result { let header = 8usize; - let mut map: (u64, ) = unsafe { ::std::mem::uninitialized() }; + let mut map: (u64, ) = unsafe { mem::uninitialized() }; - if d.len() < header { return Err(FromBytesError::NotLongEnough); } - map.copy_raw(&d[0..header]); + if bytes.len() < header { return Err(FromBytesError::NotLongEnough); } + map.copy_raw(&bytes[0..header]); Ok(( - try!(V1::from_bytes_var(&d[header..header + (map.0 as usize)], map.0)), - try!(T2::from_bytes(&d[header + (map.0 as usize)..d.len()])), + try!(V1::from_bytes_variable(&bytes[header..header + (map.0 as usize)])), + try!(T2::from_bytes(&bytes[header + (map.0 as usize)..bytes.len()])), )) } } +impl BytesConvertable for (Vec, T2) where V1: BytesConvertable, T2: BytesConvertable { + fn bytes(&self) -> &[u8] { + let header = 8usize; + let mut result = Vec::new(header + self.0.len() * mem::size_of::() + mem::size_of::()); + + *result[0..header] = (self.0.len() as u64).as_slice(); + for i in 0..self.0.len() { + *result[header + i*mem::size_of::()..header + (i+1)*mem::size_of::()] = + self.0[i].as_slice(); + } + *result[header + self.0.len()..result.len()] = self.1.as_slice(); + } + +} + +impl FromRawBytesVariable for Vec { + fn from_bytes_variable(bytes: &[u8]) -> Result, FromBytesError> { + Ok(bytes.clone().to_vec()) + } +} + #[test] fn fax_raw() { let mut x = [255u8; 4]; @@ -399,6 +420,8 @@ fn raw_bytes_from_tuple() { type Tup = (Vec, u16); let tup_from = Tup::from_bytes(&bytes).unwrap(); - assert_eq!(tup, tup_from); + + let bytes_to = Tup::as_slice(); + assert_eq!(bytes_to, bytes); } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 8b53b3d85..ddd22bb6c 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -324,7 +324,7 @@ impl EncryptedHashMap for SecretStore { } }; - match Value::from_bytes_var(&val, val.len() as u64) { + match Value::from_bytes_variable(&val) { Ok(value) => Ok(value), Err(bytes_error) => Err(EncryptedHashMapError::InvalidValueFormat(bytes_error)) } From bd2149406d3fb3794531d2ca6cc563067a61f1a6 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 18:18:25 +0300 Subject: [PATCH 6/9] from/to for BlockLocation --- ethcore/src/blockchain/block_info.rs | 45 ++++++++-- ethcore/src/blockchain/blockchain.rs | 18 ++-- ethcore/src/blockchain/import_route.rs | 16 ++-- util/src/bytes.rs | 114 +++++++++++++++++++++++-- 4 files changed, 160 insertions(+), 33 deletions(-) diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index cf16a8834..28d3c8971 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -17,6 +17,8 @@ use util::numbers::{U256,H256}; use header::BlockNumber; +use util::bytes::{FromRawBytesVariable, FromBytesError, ToBytesWithMap}; + /// Brief info about inserted block. #[derive(Clone)] pub struct BlockInfo { @@ -40,12 +42,41 @@ pub enum BlockLocation { /// It's part of the fork which should become canon chain, /// because it's total difficulty is higher than current /// canon chain difficulty. - BranchBecomingCanonChain { - /// Hash of the newest common ancestor with old canon chain. - ancestor: H256, - /// Hashes of the blocks between ancestor and this block. - enacted: Vec, - /// Hashes of the blocks which were invalidated. - retracted: Vec, + BranchBecomingCanonChain(BranchBecomingCanonChainData), +} + +#[derive(Clone)] +pub struct BranchBecomingCanonChainData { + /// Hash of the newest common ancestor with old canon chain. + pub ancestor: H256, + /// Hashes of the blocks between ancestor and this block. + pub enacted: Vec, + /// Hashes of the blocks which were invalidated. + pub retracted: Vec, +} + +impl FromRawBytesVariable for BranchBecomingCanonChainData { + fn from_bytes_variable(bytes: &[u8]) -> Result { + type Tuple = (Vec, Vec, H256); + let (enacted, retracted, ancestor) = try!(Tuple::from_bytes_variable(bytes)); + Ok(BranchBecomingCanonChainData { ancestor: ancestor, enacted: enacted, retracted: retracted }) + } +} + +impl FromRawBytesVariable for BlockLocation { + fn from_bytes_variable(bytes: &[u8]) -> Result { + match bytes[0] { + 0 => Ok(BlockLocation::CanonChain), + 1 => Ok(BlockLocation::Branch), + 2 => Ok(BlockLocation::BranchBecomingCanonChain( + try!(BranchBecomingCanonChainData::from_bytes_variable(&bytes[1..bytes.len()])))), + _ => Err(FromBytesError::UnknownMarker) + } + } +} + +impl ToBytesWithMap for BranchBecomingCanonChainData { + fn to_bytes_map(&self) -> Vec { + (&self.enacted, &self.retracted, &self.ancestor).to_bytes_map() } } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index ebbae306e..1ade4037b 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -24,7 +24,7 @@ use transaction::*; use views::*; use receipt::Receipt; use chainfilter::{ChainFilter, BloomIndex, FilterDataSource}; -use blockchain::block_info::{BlockInfo, BlockLocation}; +use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::best_block::BestBlock; use blockchain::bloom_indexer::BloomIndexer; use blockchain::tree_route::TreeRoute; @@ -582,11 +582,11 @@ impl BlockChain { _ => { let retracted = route.blocks.iter().take(route.index).cloned().collect::>(); - BlockLocation::BranchBecomingCanonChain { + BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { ancestor: route.ancestor, enacted: route.blocks.into_iter().skip(route.index).collect(), retracted: retracted.into_iter().rev().collect(), - } + }) } } } else { @@ -607,11 +607,11 @@ impl BlockChain { BlockLocation::CanonChain => { block_hashes.insert(number, info.hash.clone()); }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { - let ancestor_number = self.block_number(ancestor).unwrap(); + BlockLocation::BranchBecomingCanonChain(ref data) => { + let ancestor_number = self.block_number(&data.ancestor).unwrap(); let start_number = ancestor_number + 1; - for (index, hash) in enacted.iter().cloned().enumerate() { + for (index, hash) in data.enacted.iter().cloned().enumerate() { block_hashes.insert(start_number + index as BlockNumber, hash); } @@ -696,11 +696,11 @@ impl BlockChain { ChainFilter::new(self, self.bloom_indexer.index_size(), self.bloom_indexer.levels()) .add_bloom(&header.log_bloom(), header.number() as usize) }, - BlockLocation::BranchBecomingCanonChain { ref ancestor, ref enacted, .. } => { - let ancestor_number = self.block_number(ancestor).unwrap(); + BlockLocation::BranchBecomingCanonChain(ref data) => { + let ancestor_number = self.block_number(&data.ancestor).unwrap(); let start_number = ancestor_number + 1; - let mut blooms: Vec = enacted.iter() + let mut blooms: Vec = data.enacted.iter() .map(|hash| self.block(hash).unwrap()) .map(|bytes| BlockView::new(&bytes).header_view().log_bloom()) .collect(); diff --git a/ethcore/src/blockchain/import_route.rs b/ethcore/src/blockchain/import_route.rs index 262b70899..253c4024a 100644 --- a/ethcore/src/blockchain/import_route.rs +++ b/ethcore/src/blockchain/import_route.rs @@ -45,11 +45,11 @@ impl From for ImportRoute { enacted: vec![info.hash], }, BlockLocation::Branch => ImportRoute::none(), - BlockLocation::BranchBecomingCanonChain { mut enacted, retracted, .. } => { - enacted.push(info.hash); + BlockLocation::BranchBecomingCanonChain(mut data) => { + data.enacted.push(info.hash); ImportRoute { - retracted: retracted, - enacted: enacted, + retracted: data.retracted, + enacted: data.enacted, } } } @@ -60,7 +60,7 @@ impl From for ImportRoute { mod tests { use util::hash::H256; use util::numbers::U256; - use blockchain::block_info::{BlockInfo, BlockLocation}; + use blockchain::block_info::{BlockInfo, BlockLocation, BranchBecomingCanonChainData}; use blockchain::ImportRoute; #[test] @@ -104,11 +104,11 @@ mod tests { hash: H256::from(U256::from(2)), number: 0, total_difficulty: U256::from(0), - location: BlockLocation::BranchBecomingCanonChain { - ancestor: H256::from(U256::from(0)), + location: BlockLocation::BranchBecomingCanonChain(BranchBecomingCanonChainData { + ancestor: H256::from(U256::from(0)), enacted: vec![H256::from(U256::from(1))], retracted: vec![H256::from(U256::from(3)), H256::from(U256::from(4))], - } + }) }; assert_eq!(ImportRoute::from(info), ImportRoute { diff --git a/util/src/bytes.rs b/util/src/bytes.rs index f714b3d55..055d2abdf 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -241,6 +241,8 @@ pub enum FromBytesError { NotLongEnough, /// Too many bytes for the requested type TooLong, + /// Invalid marker for (enums) + UnknownMarker, } /// Value that can be serialized from bytes array @@ -330,27 +332,120 @@ impl FromRawBytes for (V1, T2) where V1: FromRawBytesVariable, T2: FromR } } -impl BytesConvertable for (Vec, T2) where V1: BytesConvertable, T2: BytesConvertable { - fn bytes(&self) -> &[u8] { - let header = 8usize; - let mut result = Vec::new(header + self.0.len() * mem::size_of::() + mem::size_of::()); +impl FromRawBytes for (V1, V2, T3) + where V1: FromRawBytesVariable, + V2: FromRawBytesVariable, + T3: FromRawBytes +{ + fn from_bytes(bytes: &[u8]) -> Result { + let header = 16usize; + let mut map: (u64, u64, ) = unsafe { mem::uninitialized() }; + + if bytes.len() < header { return Err(FromBytesError::NotLongEnough); } + map.copy_raw(&bytes[0..header]); + + let map_1 = (header, header + map.0 as usize); + let map_2 = (map_1.1 as usize, map_1.1 as usize + map.1 as usize); + Ok(( + try!(V1::from_bytes_variable(&bytes[map_1.0..map_1.1])), + try!(V2::from_bytes_variable(&bytes[map_2.0..map_2.1])), + try!(T3::from_bytes(&bytes[map_2.1..bytes.len()])), + )) + } +} + +impl<'a, V1, T2> ToBytesWithMap for (&'a Vec, &'a T2) where V1: ToBytesWithMap, T2: ToBytesWithMap { + fn to_bytes_map(&self) -> Vec { + let header = 8usize; + let v1_size = mem::size_of::(); + let mut result = Vec::with_capacity(header + self.0.len() * v1_size + mem::size_of::()); + result.extend(((self.0.len() * v1_size) as u64).to_bytes_map()); - *result[0..header] = (self.0.len() as u64).as_slice(); for i in 0..self.0.len() { - *result[header + i*mem::size_of::()..header + (i+1)*mem::size_of::()] = - self.0[i].as_slice(); + result.extend(self.0[i].to_bytes_map()); } - *result[header + self.0.len()..result.len()] = self.1.as_slice(); + result.extend(self.1.to_bytes_map()); + + result } } +impl<'a, V1, V2, T3> ToBytesWithMap for (&'a Vec, &'a Vec, &'a T3) + where V1: ToBytesWithMap, + V2: ToBytesWithMap, + T3: ToBytesWithMap +{ + fn to_bytes_map(&self) -> Vec { + let header = 16usize; + let v1_size = mem::size_of::(); + let v2_size = mem::size_of::(); + let mut result = Vec::with_capacity( + header + + self.0.len() * v1_size + + self.1.len() * v2_size + + mem::size_of::() + ); + result.extend(((self.0.len() * v1_size) as u64).to_bytes_map()); + result.extend(((self.1.len() * v1_size) as u64).to_bytes_map()); + for i in 0..self.0.len() { + result.extend(self.0[i].to_bytes_map()); + } + for i in 0..self.1.len() { + result.extend(self.1[i].to_bytes_map()); + } + result.extend(self.2.to_bytes_map()); + + result + } +} + impl FromRawBytesVariable for Vec { fn from_bytes_variable(bytes: &[u8]) -> Result, FromBytesError> { Ok(bytes.clone().to_vec()) } } +pub trait ToBytesWithMap { + fn to_bytes_map(&self) -> Vec; +} + +impl ToBytesWithMap for T where T: FixedHash { + fn to_bytes_map(&self) -> Vec { + self.as_slice().to_vec() + } +} + +impl ToBytesWithMap for u16 { + fn to_bytes_map(&self) -> Vec { + let sz = mem::size_of::(); + let mut res = Vec::::with_capacity(sz); + + let ip: *const u16 = self; + let ptr: *const u8 = ip as *const _; + unsafe { + res.set_len(sz); + ::std::ptr::copy(ptr, res.as_mut_ptr(), sz); + } + res + } +} + +impl ToBytesWithMap for u64 { + fn to_bytes_map(&self) -> Vec { + let sz = mem::size_of::(); + let mut res = Vec::::with_capacity(sz); + + let ip: *const u64 = self; + let ptr: *const u8 = ip as *const _; + unsafe { + res.set_len(sz); + ::std::ptr::copy(ptr, res.as_mut_ptr(), sz); + } + res + } +} + #[test] fn fax_raw() { let mut x = [255u8; 4]; @@ -422,6 +517,7 @@ fn raw_bytes_from_tuple() { let tup_from = Tup::from_bytes(&bytes).unwrap(); assert_eq!(tup, tup_from); - let bytes_to = Tup::as_slice(); + let tup_to = (&tup_from.0, &tup_from.1); + let bytes_to = tup_to.to_bytes_map(); assert_eq!(bytes_to, bytes); } From 17f26ad58836e80bcc58e4d2eb3a41b7c22f4d17 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 18:30:42 +0300 Subject: [PATCH 7/9] finished for BlockLocation --- ethcore/src/blockchain/block_info.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ethcore/src/blockchain/block_info.rs b/ethcore/src/blockchain/block_info.rs index 28d3c8971..eb3677c25 100644 --- a/ethcore/src/blockchain/block_info.rs +++ b/ethcore/src/blockchain/block_info.rs @@ -80,3 +80,17 @@ impl ToBytesWithMap for BranchBecomingCanonChainData { (&self.enacted, &self.retracted, &self.ancestor).to_bytes_map() } } + +impl ToBytesWithMap for BlockLocation { + fn to_bytes_map(&self) -> Vec { + match *self { + BlockLocation::CanonChain => vec![0u8], + BlockLocation::Branch => vec![1u8], + BlockLocation::BranchBecomingCanonChain(ref data) => { + let mut bytes = (&data.enacted, &data.retracted, &data.ancestor).to_bytes_map(); + bytes.insert(0, 2u8); + bytes + } + } + } +} From 3138584320da50f83746dbb2a8133811bdaa6248 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 18:52:44 +0300 Subject: [PATCH 8/9] generalized fixedsized structs with macro --- ethcore/src/client/ids.rs | 5 +++ util/src/bytes.rs | 75 ++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs index 79302354f..94ce58b8a 100644 --- a/ethcore/src/client/ids.rs +++ b/ethcore/src/client/ids.rs @@ -18,6 +18,7 @@ use util::hash::H256; use header::BlockNumber; +use util::bytes::{FromRawBytes, FromBytesError, ToBytesWithMap, Populatable}; /// Uniquely identifies block. #[derive(Debug, PartialEq, Clone, Hash, Eq)] @@ -50,3 +51,7 @@ pub struct UncleId ( /// Position in block. pub usize ); + +sized_binary_map!(TransactionId); +sized_binary_map!(UncleId); +sized_binary_map!(BlockId); diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 055d2abdf..cbc06e3ad 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -265,19 +265,42 @@ impl FromRawBytes for T where T: FixedHash { } } -impl FromRawBytes for u16 { - fn from_bytes(bytes: &[u8]) -> Result { - match bytes.len().cmp(&2) { - Ordering::Less => return Err(FromBytesError::NotLongEnough), - Ordering::Greater => return Err(FromBytesError::TooLong), - Ordering::Equal => () - }; - let mut res: Self = unsafe { mem::uninitialized() }; - res.copy_raw(bytes); - Ok(res) +#[macro_export] +macro_rules! sized_binary_map { + ($target_ty: ident) => { + impl FromRawBytes for $target_ty { + fn from_bytes(bytes: &[u8]) -> Result { + match bytes.len().cmp(&::std::mem::size_of::<$target_ty>()) { + ::std::cmp::Ordering::Less => return Err(FromBytesError::NotLongEnough), + ::std::cmp::Ordering::Greater => return Err(FromBytesError::TooLong), + ::std::cmp::Ordering::Equal => () + }; + let mut res: Self = unsafe { ::std::mem::uninitialized() }; + res.copy_raw(bytes); + Ok(res) + } + } + impl ToBytesWithMap for $target_ty { + fn to_bytes_map(&self) -> Vec { + let sz = ::std::mem::size_of::<$target_ty>(); + let mut res = Vec::::with_capacity(sz); + + let ip: *const $target_ty = self; + let ptr: *const u8 = ip as *const _; + unsafe { + res.set_len(sz); + ::std::ptr::copy(ptr, res.as_mut_ptr(), sz); + } + res + } + } } } +sized_binary_map!(u16); +sized_binary_map!(u32); +sized_binary_map!(u64); + /// Value that can be serialized from variable-length byte array pub trait FromRawBytesVariable : Sized { /// Create value from slice @@ -406,7 +429,9 @@ impl FromRawBytesVariable for Vec { } } +/// Value that serializes directly to variable-sized byte array and stores map pub trait ToBytesWithMap { + /// serialize to variable-sized byte array and store map fn to_bytes_map(&self) -> Vec; } @@ -416,36 +441,6 @@ impl ToBytesWithMap for T where T: FixedHash { } } -impl ToBytesWithMap for u16 { - fn to_bytes_map(&self) -> Vec { - let sz = mem::size_of::(); - let mut res = Vec::::with_capacity(sz); - - let ip: *const u16 = self; - let ptr: *const u8 = ip as *const _; - unsafe { - res.set_len(sz); - ::std::ptr::copy(ptr, res.as_mut_ptr(), sz); - } - res - } -} - -impl ToBytesWithMap for u64 { - fn to_bytes_map(&self) -> Vec { - let sz = mem::size_of::(); - let mut res = Vec::::with_capacity(sz); - - let ip: *const u64 = self; - let ptr: *const u8 = ip as *const _; - unsafe { - res.set_len(sz); - ::std::ptr::copy(ptr, res.as_mut_ptr(), sz); - } - res - } -} - #[test] fn fax_raw() { let mut x = [255u8; 4]; From bde0a5b81177e85ce893c3cb4a9a9a1d2ab025d9 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sun, 17 Apr 2016 19:12:10 +0300 Subject: [PATCH 9/9] test for triples and bug fix --- util/src/bytes.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index cbc06e3ad..3a7457575 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -410,7 +410,7 @@ impl<'a, V1, V2, T3> ToBytesWithMap for (&'a Vec, &'a Vec, &'a T3) mem::size_of::() ); result.extend(((self.0.len() * v1_size) as u64).to_bytes_map()); - result.extend(((self.1.len() * v1_size) as u64).to_bytes_map()); + result.extend(((self.1.len() * v2_size) as u64).to_bytes_map()); for i in 0..self.0.len() { result.extend(self.0[i].to_bytes_map()); } @@ -516,3 +516,19 @@ fn raw_bytes_from_tuple() { let bytes_to = tup_to.to_bytes_map(); assert_eq!(bytes_to, bytes); } + +#[test] +fn bytes_map_from_triple() { + let data = (vec![2u16; 6], vec![6u32; 3], 12u64); + let bytes_map = (&data.0, &data.1, &data.2).to_bytes_map(); + assert_eq!(bytes_map, vec![ + // data map 2 x u64 + 12, 0, 0, 0, 0, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 0, + // vec![2u16; 6] + 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, + // vec![6u32; 3] + 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, + // 12u64 + 12, 0, 0, 0, 0, 0, 0, 0]); +}