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:
commit
2fafec8b9f
|
@ -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 ..
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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)));
|
||||
```
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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::*;
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue