Merge branch 'master' into dp/chore/sort-out-patricia-trie-tests

* master:
  Address grumbles
  [kvdb-rocksdb] ethereum-types is a dev-dependency
  [kvdb] Use parity-rocksdb 0.5; bump version
  Use parity-rocksdb 0.1.2-beta.0
  [kvdb-rocksdb] bump to v0.1.1
  prep kvdb-memorydb
  Assert hash-to-uint conversions operate on same-sized types
  Fix scoring to favour lower insertion_ids.
  Set uint version
  Port over relevant tests and code from parity-hash
  Tweak CI to run all fixed-hash tests
  Use rustc-hex 2
This commit is contained in:
David Palm 2018-09-03 15:04:02 +02:00
commit 2fafec8b9f
11 changed files with 265 additions and 23 deletions

View File

@ -7,7 +7,8 @@ matrix:
- rust: nightly
script:
- cargo build
- cargo test --all --exclude uint
- cargo test --all --exclude uint --exclude fixed-hash
- cd fixed-hash/ && cargo test --features=std,heapsizeof,uint_conversions && cd ..
- cd uint/ && cargo test --features=std,impl_quickcheck_arbitrary --release && cd ..
- cd hashdb/ && cargo test --no-default-features && cd ..
- cd plain_hasher/ && cargo test --no-default-features && cd ..

View File

@ -1,6 +1,6 @@
[package]
name = "fixed-hash"
version = "0.2.2"
version = "0.2.3"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
homepage = "https://github.com/paritytech/parity-common"
@ -9,8 +9,11 @@ description = "Fixed-size hashes"
[dependencies]
heapsize = { version = "0.4", optional = true }
rand = { version = "0.4", optional = true }
rustc-hex = { version = "1.0", optional = true }
rustc-hex = { version = "2.0", optional = true }
quickcheck = { version = "0.6", optional = true }
uint = { version = "0.4", path = "../uint", optional = true, default-features = false }
serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true }
[target.'cfg(not(target_os = "unknown"))'.dependencies]
libc = { version = "0.2", optional = true, default-features = false }
@ -20,3 +23,5 @@ default = ["libc"]
std = ["rustc-hex", "rand"]
heapsizeof = ["heapsize"]
impl_quickcheck_arbitrary = ["quickcheck"]
serialize = ["serde", "serde_derive"]
uint_conversions = ["uint"]

30
fixed-hash/README.md Normal file
View File

@ -0,0 +1,30 @@
Macros to construct fixed-size hash types. Does not export any types.
Examples:
```rust
construct_hash!(H256, 32);
```
Add conversions between differently sized hashes:
```rust
construct_hash!(H256, 32);
construct_hash!(H160, 20);
impl_hash_conversions!(H256, 32, H160, 20);
```
Add conversions between a hash type and the equivalently sized unsigned int:
```rust
extern crate uint;
construct_hash!(H256, 32);
use uint::U256;
impl_hash_uint_conversions!(H256, U256);
```
Build a serde serializable hash type:
```rust
construct_hash!(H160, 20, cfg_attr(feature = "serialize", derive(Serialize, Deserialize)));
```

View File

@ -15,10 +15,15 @@ pub fn clean_0x(s: &str) -> &str {
}
}
/// Construct a fixed-size hash type.
/// Takes the name of the type and the size in bytes and an optional third argument for meta data
/// Example: `construct_hash!(H256, 32);`
/// Example: `construct_hash!(H160, 20, cfg_attr(feature = "serialize", derive(Serialize, Deserialize)));`
#[macro_export]
macro_rules! construct_hash {
($from: ident, $size: expr) => {
($from: ident, $size: expr $(, $m:meta)*) => {
#[repr(C)]
$(#[$m])*
/// Unformatted binary data of fixed length.
pub struct $from (pub [u8; $size]);
@ -88,6 +93,15 @@ macro_rules! construct_hash {
$size
}
/// Returns a constant raw pointer to the value
pub fn as_ptr(&self) -> *const u8 {
self.0.as_ptr()
}
pub fn as_mut_ptr(&mut self) -> *mut u8 {
(&mut self.0).as_mut_ptr()
}
#[inline]
/// Assign self to be of the same value as a slice of bytes of length `len()`.
pub fn clone_from_slice(&mut self, src: &[u8]) -> usize {
@ -321,6 +335,79 @@ macro_rules! construct_hash {
}
}
/// Implements conversion to and from hash types of different sizes. Uses the
/// last bytes, e.g. `From<H256> for H160` uses bytes 12..32
/// CAUTION: make sure to call with correct sizes and the bigger type first or
/// bad things will happen!
#[macro_export]
macro_rules! impl_hash_conversions {
($a: ident, $a_size: expr, $b: ident, $b_size: expr) => {
impl From<$b> for $a {
fn from(value: $b) -> $a {
debug_assert!($a_size > $b_size && $a_size % 2 == 0 && $b_size %2 == 0);
let mut ret = $a::new();
ret.0[($a_size - $b_size)..$a_size].copy_from_slice(&value);
ret
}
}
impl From<$a> for $b {
fn from(value: $a) -> $b {
debug_assert!($a_size > $b_size && $a_size % 2 == 0 && $b_size %2 == 0);
let mut ret = $b::new();
ret.0.copy_from_slice(&value[($a_size - $b_size)..$a_size]);
ret
}
}
impl<'a> From<&'a $b> for $a {
fn from(value: &'a $b) -> $a {
let mut ret = $a::new();
ret.0[($a_size - $b_size)..$a_size].copy_from_slice(value);
ret
}
}
}
}
/// Implements conversion to and from a hash type and the equally sized unsigned int.
/// CAUTION: Bad things will happen if the two types are not of the same size!
#[cfg(feature="uint_conversions")]
#[macro_export]
macro_rules! impl_hash_uint_conversions {
($hash: ident, $uint: ident) => {
debug_assert_eq!(::core::mem::size_of::<$hash>(), ::core::mem::size_of::<$uint>());
impl From<$uint> for $hash {
fn from(value: $uint) -> $hash {
let mut ret = $hash::new();
value.to_big_endian(&mut ret);
ret
}
}
impl<'a> From<&'a $uint> for $hash {
fn from(value: &'a $uint) -> $hash {
let mut ret: $hash = $hash::new();
value.to_big_endian(&mut ret);
ret
}
}
impl From<$hash> for $uint {
fn from(value: $hash) -> $uint {
$uint::from(&value as &[u8])
}
}
impl<'a> From<&'a $hash> for $uint {
fn from(value: &'a $hash) -> $uint {
$uint::from(value.as_ref() as &[u8])
}
}
}
}
#[cfg(all(feature="heapsizeof", feature="libc", not(target_os = "unknown")))]
#[macro_export]
#[doc(hidden)]
@ -367,7 +454,7 @@ macro_rules! impl_std_for_hash {
fn from_str(s: &str) -> Result<$from, $crate::rustc_hex::FromHexError> {
use $crate::rustc_hex::FromHex;
let a = s.from_hex()?;
let a : Vec<u8> = s.from_hex()?;
if a.len() != $size {
return Err($crate::rustc_hex::FromHexError::InvalidHexLength);
}
@ -492,7 +579,13 @@ macro_rules! impl_quickcheck_arbitrary_for_hash {
#[cfg(test)]
mod tests {
construct_hash!(H256, 32);
construct_hash!(H160, 20);
construct_hash!(H128, 16);
construct_hash!(H64, 8);
construct_hash!(H32, 4);
impl_hash_conversions!(H256, 32, H160, 20);
#[test]
fn test_construct_hash() {
@ -528,4 +621,67 @@ mod tests {
test(0xfff, "00000000000000000000000000000fff", "0000…0fff");
test(0x1000, "00000000000000000000000000001000", "0000…1000");
}
#[test]
fn hash_bitor() {
let a = H64([1; 8]);
let b = H64([2; 8]);
let c = H64([3; 8]);
// borrow
assert_eq!(&a | &b, c);
// move
assert_eq!(a | b, c);
}
#[test]
fn from_and_to_address() {
let address: H160 = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into();
let h = H256::from(address.clone());
let a = H160::from(h);
assert_eq!(address, a);
}
#[test]
fn from_u64() {
use core::str::FromStr;
assert_eq!(H128::from(0x1234567890abcdef), H128::from_str("00000000000000001234567890abcdef").unwrap());
assert_eq!(H64::from(0x1234567890abcdef), H64::from_str("1234567890abcdef").unwrap());
assert_eq!(H32::from(0x1234567890abcdef), H32::from_str("90abcdef").unwrap());
}
#[test]
fn from_str() {
assert_eq!(H64::from(0x1234567890abcdef), H64::from("0x1234567890abcdef"));
assert_eq!(H64::from(0x1234567890abcdef), H64::from("1234567890abcdef"));
assert_eq!(H64::from(0x234567890abcdef), H64::from("0x234567890abcdef"));
}
#[cfg(feature = "uint_conversions")]
#[test]
fn from_and_to_u256() {
use uint::U256;
impl_hash_uint_conversions!(H256, U256);
let u: U256 = 0x123456789abcdef0u64.into();
let h = H256::from(u);
assert_eq!(H256::from(u), H256::from("000000000000000000000000000000000000000000000000123456789abcdef0"));
let h_ref = H256::from(&u);
assert_eq!(h, h_ref);
let r_ref: U256 = From::from(&h);
assert!(r_ref == u);
let r: U256 = From::from(h);
assert!(r == u)
}
#[test]
#[should_panic]
fn converting_differently_sized_types_panics() {
use uint::U512;
impl_hash_uint_conversions!(H256, U512);
}
}

View File

@ -36,5 +36,15 @@ pub extern crate rand;
#[doc(hidden)]
pub extern crate quickcheck;
#[cfg(feature="uint_conversions")]
extern crate uint;
#[cfg(feature="serialize")]
extern crate serde;
#[cfg(feature="serialize")]
#[macro_use]
extern crate serde_derive;
mod hash;
pub use hash::*;

View File

@ -2,7 +2,10 @@
name = "kvdb-memorydb"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
repository = "https://github.com/paritytech/parity-common"
description = "A key-value in-memory database that implements the `KeyValueDB` trait"
license = "GPL-3.0"
[dependencies]
parking_lot = "0.6"
kvdb = { path = "../kvdb" }
kvdb = { version = "0.1", path = "../kvdb" }

View File

@ -1,6 +1,6 @@
[package]
name = "kvdb-rocksdb"
version = "0.1.0"
version = "0.1.3"
authors = ["Parity Technologies <admin@parity.io>"]
repository = "https://github.com/paritytech/parity-common"
description = "kvdb implementation backed by rocksDB"
@ -8,7 +8,6 @@ license = "GPL-3.0"
[dependencies]
elastic-array = "0.10"
ethereum-types = "0.4"
fs-swap = "0.2.1"
interleaved-ordered = "0.1.0"
kvdb = { version = "0.1", path = "../kvdb" }
@ -16,7 +15,8 @@ log = "0.3"
num_cpus = "1.0"
parking_lot = "0.6"
regex = "0.2"
rocksdb = { git = "https://github.com/paritytech/rust-rocksdb" }
parity-rocksdb = "0.5"
[dev-dependencies]
tempdir = "0.3"
ethereum-types = "0.4"

View File

@ -23,9 +23,11 @@ extern crate interleaved_ordered;
extern crate num_cpus;
extern crate parking_lot;
extern crate regex;
extern crate rocksdb;
extern crate parity_rocksdb;
#[cfg(test)]
extern crate ethereum_types;
extern crate kvdb;
use std::collections::HashMap;
@ -34,7 +36,7 @@ use std::{cmp, fs, io, mem, result, error};
use std::path::Path;
use parking_lot::{Mutex, MutexGuard, RwLock};
use rocksdb::{
use parity_rocksdb::{
DB, Writable, WriteBatch, WriteOptions, IteratorMode, DBIterator,
Options, BlockBasedOptions, Direction, Cache, Column, ReadOptions
};

View File

@ -3,7 +3,7 @@ name = "kvdb"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
repository = "https://github.com/paritytech/parity-common"
description = "Generic key-value database"
description = "Generic key-value trait"
license = "GPL-3.0"
[dependencies]

View File

@ -138,7 +138,7 @@ impl<T, S: Clone> Clone for ScoreWithRef<T, S> {
impl<S: cmp::Ord, T> Ord for ScoreWithRef<T, S> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
other.score.cmp(&self.score)
.then(other.transaction.insertion_id.cmp(&self.transaction.insertion_id))
.then(self.transaction.insertion_id.cmp(&other.transaction.insertion_id))
}
}
@ -155,3 +155,33 @@ impl<S: cmp::Ord, T> PartialEq for ScoreWithRef<T, S> {
}
impl<S: cmp::Ord, T> Eq for ScoreWithRef<T, S> {}
#[cfg(test)]
mod tests {
use super::*;
fn score(score: u64, insertion_id: u64) -> ScoreWithRef<(), u64> {
ScoreWithRef {
score,
transaction: Transaction {
insertion_id,
transaction: Default::default(),
},
}
}
#[test]
fn scoring_comparison() {
// the higher the score the better
assert_eq!(score(10, 0).cmp(&score(0, 0)), cmp::Ordering::Less);
assert_eq!(score(0, 0).cmp(&score(10, 0)), cmp::Ordering::Greater);
// equal is equal
assert_eq!(score(0, 0).cmp(&score(0, 0)), cmp::Ordering::Equal);
// lower insertion id is better
assert_eq!(score(0, 0).cmp(&score(0, 10)), cmp::Ordering::Less);
assert_eq!(score(0, 10).cmp(&score(0, 0)), cmp::Ordering::Greater);
}
}

View File

@ -210,6 +210,14 @@ fn should_construct_pending() {
let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
// this transaction doesn't get to the block despite high gas price
// because of block gas limit and simplistic ordering algorithm.
@ -217,14 +225,9 @@ fn should_construct_pending() {
//gap
txq.import(b.tx().nonce(5).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
// gap
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 11);
assert_eq!(txq.status(NonceReady::default()), Status {
stalled: 0,
@ -325,6 +328,13 @@ fn should_update_scoring_correctly() {
let b = TransactionBuilder::default();
let mut txq = TestPool::default();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
let tx0 = txq.import(b.tx().nonce(0).gas_price(5).new()).unwrap();
let tx1 = txq.import(b.tx().nonce(1).gas_price(5).new()).unwrap();
let tx2 = txq.import(b.tx().nonce(2).new()).unwrap();
@ -334,14 +344,9 @@ fn should_update_scoring_correctly() {
//gap
txq.import(b.tx().nonce(5).new()).unwrap();
let tx5 = txq.import(b.tx().sender(1).nonce(0).new()).unwrap();
let tx6 = txq.import(b.tx().sender(1).nonce(1).new()).unwrap();
let tx7 = txq.import(b.tx().sender(1).nonce(2).new()).unwrap();
let tx8 = txq.import(b.tx().sender(1).nonce(3).gas_price(4).new()).unwrap();
// gap
txq.import(b.tx().sender(1).nonce(5).new()).unwrap();
let tx9 = txq.import(b.tx().sender(2).nonce(0).new()).unwrap();
assert_eq!(txq.light_status().transaction_count, 11);
assert_eq!(txq.status(NonceReady::default()), Status {
stalled: 0,