Merge pull request #97 from paritytech/sp-more-convert

Move `ethereum-types` to `parity-common` repo and more conversion functions for U128
This commit is contained in:
Wei Tang 2019-01-26 01:16:17 +01:00 committed by GitHub
commit 52401dbe88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1217 additions and 9 deletions

View File

@ -20,4 +20,6 @@ members = [
"uint",
"parity-util-mem",
"primitive-types",
"ethereum-types",
"ethbloom",
]

25
ethbloom/Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
[package]
name = "ethbloom"
version = "0.6.0"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Ethereum bloom filter"
license = "MIT"
documentation = "https://docs.rs/ethbloom"
homepage = "https://github.com/paritytech/parity-common"
repository = "https://github.com/paritytech/parity-common"
[dependencies]
tiny-keccak = "1.4"
crunchy = { version = "0.2.1", default-features = false, features = ["limit_256"] }
fixed-hash = { path = "../fixed-hash", version = "0.3", default-features = false }
impl-serde = { path = "../primitive-types/impls/serde", version = "0.1", default-features = false, optional = true }
[dev-dependencies]
rand = { version = "0.4" }
hex-literal = "0.1.1"
[features]
default = ["std", "heapsize", "serialize", "fixed-hash/libc", "fixed-hash/rustc-hex"]
std = ["fixed-hash/std", "crunchy/std"]
heapsize = ["fixed-hash/heapsize"]
serialize = ["std", "impl-serde"]

126
ethbloom/benches/bloom.rs Normal file
View File

@ -0,0 +1,126 @@
#![feature(test)]
extern crate test;
extern crate rustc_hex;
extern crate tiny_keccak;
extern crate ethbloom;
use test::Bencher;
use rustc_hex::FromHex;
use tiny_keccak::keccak256;
use ethbloom::{Bloom, Input};
fn test_bloom() -> Bloom {
use std::str::FromStr;
Bloom::from_str(
"00000000000000000000000000000000\
00000000100000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000002020000000000000000000000\
00000000000000000000000800000000\
10000000000000000000000000000000\
00000000000000000000001000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000"
).unwrap()
}
fn test_topic() -> Vec<u8> {
"02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc".from_hex().unwrap()
}
fn test_address() -> Vec<u8> {
"ef2d6d194084c2de36e0dabfce45d046b37d1106".from_hex().unwrap()
}
fn test_dummy() -> Vec<u8> {
b"123456".to_vec()
}
fn test_dummy2() -> Vec<u8> {
b"654321".to_vec()
}
#[bench]
fn accrue_raw(b: &mut Bencher) {
let mut bloom = Bloom::default();
let topic = test_topic();
let address = test_address();
b.iter(|| {
bloom.accrue(Input::Raw(&topic));
bloom.accrue(Input::Raw(&address));
});
}
#[bench]
fn accrue_hash(b: &mut Bencher) {
let mut bloom = Bloom::default();
let topic = keccak256(&test_topic());
let address = keccak256(&test_address());
b.iter(|| {
bloom.accrue(Input::Hash(&topic));
bloom.accrue(Input::Hash(&address));
});
}
#[bench]
fn contains_input_raw(b: &mut Bencher) {
let bloom = test_bloom();
let topic = test_topic();
let address = test_address();
b.iter(|| {
assert!(bloom.contains_input(Input::Raw(&topic)));
assert!(bloom.contains_input(Input::Raw(&address)));
});
}
#[bench]
fn does_not_contain_raw(b: &mut Bencher) {
let bloom = test_bloom();
let dummy = test_dummy();
let dummy2 = test_dummy2();
b.iter(|| {
assert!(!bloom.contains_input(Input::Raw(&dummy)));
assert!(!bloom.contains_input(Input::Raw(&dummy2)));
});
}
#[bench]
fn contains_input_hash(b: &mut Bencher) {
let bloom = test_bloom();
let topic = keccak256(&test_topic());
let address = keccak256(&test_address());
b.iter(|| {
assert!(bloom.contains_input(Input::Hash(&topic)));
assert!(bloom.contains_input(Input::Hash(&address)));
});
}
#[bench]
fn does_not_contain_hash(b: &mut Bencher) {
let bloom = test_bloom();
let dummy = keccak256(&test_dummy());
let dummy2 = keccak256(&test_dummy2());
b.iter(|| {
assert!(!bloom.contains_input(Input::Hash(&dummy)));
assert!(!bloom.contains_input(Input::Hash(&dummy2)));
});
}
#[bench]
fn does_not_contain_random_hash(b: &mut Bencher) {
let bloom = test_bloom();
let dummy: Vec<_> = (0..255u8).into_iter().map(|i| keccak256(&[i])).collect();
b.iter(|| {
for d in &dummy {
assert!(!bloom.contains_input(Input::Hash(d)));
}
});
}

View File

@ -0,0 +1,73 @@
#![feature(test)]
extern crate test;
extern crate rand;
#[macro_use]
extern crate crunchy;
use test::{Bencher, black_box};
use rand::Rng;
fn random_data() -> [u8; 256] {
let mut res = [0u8; 256];
rand::thread_rng().fill_bytes(&mut res);
res
}
#[bench]
fn forwards_with_crunchy(b: &mut Bencher) {
let mut data = random_data();
b.iter(|| {
let other_data = random_data();
unroll! {
for i in 0..255 {
data[i] |= other_data[i];
}
}
});
black_box(data);
}
#[bench]
fn backwards_with_crunchy(b: &mut Bencher) {
let mut data = random_data();
b.iter(|| {
let other_data = random_data();
unroll! {
for i in 0..255 {
data[255-i] |= other_data[255-i];
}
}
});
black_box(data);
}
#[bench]
fn forwards_without_crunchy(b: &mut Bencher) {
let mut data = random_data();
b.iter(|| {
let other_data = random_data();
for i in 0..255 {
data[i] |= other_data[i];
}
});
black_box(data);
}
#[bench]
fn backwards_without_crunchy(b: &mut Bencher) {
let mut data = random_data();
b.iter(|| {
let other_data = random_data();
for i in 0..255 {
data[255-i] |= other_data[255-i];
}
});
black_box(data);
}

301
ethbloom/src/lib.rs Normal file
View File

@ -0,0 +1,301 @@
//!
//! ```rust
//! extern crate ethbloom;
//! #[macro_use] extern crate hex_literal;
//! use ethbloom::{Bloom, Input};
//!
//! fn main() {
//! use std::str::FromStr;
//! let bloom = Bloom::from_str(
//! "00000000000000000000000000000000\
//! 00000000100000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000002020000000000000000000000\
//! 00000000000000000000000800000000\
//! 10000000000000000000000000000000\
//! 00000000000000000000001000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000\
//! 00000000000000000000000000000000"
//! ).unwrap();
//! let address = hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106");
//! let topic = hex!("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc");
//!
//! let mut my_bloom = Bloom::default();
//! assert!(!my_bloom.contains_input(Input::Raw(&address)));
//! assert!(!my_bloom.contains_input(Input::Raw(&topic)));
//!
//! my_bloom.accrue(Input::Raw(&address));
//! assert!(my_bloom.contains_input(Input::Raw(&address)));
//! assert!(!my_bloom.contains_input(Input::Raw(&topic)));
//!
//! my_bloom.accrue(Input::Raw(&topic));
//! assert!(my_bloom.contains_input(Input::Raw(&address)));
//! assert!(my_bloom.contains_input(Input::Raw(&topic)));
//! assert_eq!(my_bloom, bloom);
//! }
//! ```
//!
#![cfg_attr(not(feature="std"), no_std)]
#[cfg(feature="std")]
extern crate core;
extern crate tiny_keccak;
#[macro_use]
extern crate crunchy;
#[macro_use]
extern crate fixed_hash;
#[cfg(feature="serialize")]
#[macro_use]
extern crate impl_serde;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
use core::{ops, mem};
use tiny_keccak::keccak256;
#[cfg(feature="std")]
use core::str;
// 3 according to yellowpaper
const BLOOM_BITS: u32 = 3;
const BLOOM_SIZE: usize = 256;
construct_fixed_hash!{
/// Bloom hash type with 256 bytes (2048 bits) size.
pub struct Bloom(BLOOM_SIZE);
}
/// Returns log2.
fn log2(x: usize) -> u32 {
if x <= 1 {
return 0;
}
let n = x.leading_zeros();
mem::size_of::<usize>() as u32 * 8 - n
}
pub enum Input<'a> {
Raw(&'a [u8]),
Hash(&'a [u8; 32]),
}
enum Hash<'a> {
Ref(&'a [u8; 32]),
Owned([u8; 32]),
}
impl<'a> From<Input<'a>> for Hash<'a> {
fn from(input: Input<'a>) -> Self {
match input {
Input::Raw(raw) => Hash::Owned(keccak256(raw)),
Input::Hash(hash) => Hash::Ref(hash),
}
}
}
impl<'a> ops::Index<usize> for Hash<'a> {
type Output = u8;
fn index(&self, index: usize) -> &u8 {
match *self {
Hash::Ref(r) => &r[index],
Hash::Owned(ref hash) => &hash[index],
}
}
}
impl<'a> Hash<'a> {
fn len(&self) -> usize {
match *self {
Hash::Ref(r) => r.len(),
Hash::Owned(ref hash) => hash.len(),
}
}
}
impl<'a> PartialEq<BloomRef<'a>> for Bloom {
fn eq(&self, other: &BloomRef<'a>) -> bool {
let s_ref: &[u8] = &self.0;
let o_ref: &[u8] = other.0;
s_ref.eq(o_ref)
}
}
impl<'a> From<Input<'a>> for Bloom {
fn from(input: Input<'a>) -> Bloom {
let mut bloom = Bloom::default();
bloom.accrue(input);
bloom
}
}
impl Bloom {
pub fn is_empty(&self) -> bool {
self.0.iter().all(|x| *x == 0)
}
pub fn contains_input<'a>(&self, input: Input<'a>) -> bool {
let bloom: Bloom = input.into();
self.contains_bloom(&bloom)
}
pub fn contains_bloom<'a, B>(&self, bloom: B) -> bool where BloomRef<'a>: From<B> {
let bloom_ref: BloomRef = bloom.into();
// workaround for https://github.com/rust-lang/rust/issues/43644
self.contains_bloom_ref(bloom_ref)
}
fn contains_bloom_ref(&self, bloom: BloomRef) -> bool {
let self_ref: BloomRef = self.into();
self_ref.contains_bloom(bloom)
}
pub fn accrue<'a>(&mut self, input: Input<'a>) {
let p = BLOOM_BITS;
let m = self.0.len();
let bloom_bits = m * 8;
let mask = bloom_bits - 1;
let bloom_bytes = (log2(bloom_bits) + 7) / 8;
let hash: Hash = input.into();
// must be a power of 2
assert_eq!(m & (m - 1), 0);
// out of range
assert!(p * bloom_bytes <= hash.len() as u32);
let mut ptr = 0;
assert_eq!(BLOOM_BITS, 3);
unroll! {
for i in 0..3 {
let _ = i;
let mut index = 0 as usize;
for _ in 0..bloom_bytes {
index = (index << 8) | hash[ptr] as usize;
ptr += 1;
}
index &= mask;
self.0[m - 1 - index / 8] |= 1 << (index % 8);
}
}
}
pub fn accrue_bloom<'a, B>(&mut self, bloom: B) where BloomRef<'a>: From<B> {
let bloom_ref: BloomRef = bloom.into();
assert_eq!(self.0.len(), BLOOM_SIZE);
assert_eq!(bloom_ref.0.len(), BLOOM_SIZE);
for i in 0..BLOOM_SIZE {
self.0[i] |= bloom_ref.0[i];
}
}
pub fn data(&self) -> &[u8; BLOOM_SIZE] {
&self.0
}
}
#[derive(Clone, Copy)]
pub struct BloomRef<'a>(&'a [u8; BLOOM_SIZE]);
impl<'a> BloomRef<'a> {
pub fn is_empty(&self) -> bool {
self.0.iter().all(|x| *x == 0)
}
pub fn contains_input<'b>(&self, input: Input<'b>) -> bool {
let bloom: Bloom = input.into();
self.contains_bloom(&bloom)
}
pub fn contains_bloom<'b, B>(&self, bloom: B) -> bool where BloomRef<'b>: From<B> {
let bloom_ref: BloomRef = bloom.into();
assert_eq!(self.0.len(), BLOOM_SIZE);
assert_eq!(bloom_ref.0.len(), BLOOM_SIZE);
for i in 0..BLOOM_SIZE {
let a = self.0[i];
let b = bloom_ref.0[i];
if (a & b) != b {
return false;
}
}
true
}
pub fn data(&self) -> &'a [u8; BLOOM_SIZE] {
self.0
}
}
impl<'a> From<&'a [u8; BLOOM_SIZE]> for BloomRef<'a> {
fn from(data: &'a [u8; BLOOM_SIZE]) -> Self {
BloomRef(data)
}
}
impl<'a> From<&'a Bloom> for BloomRef<'a> {
fn from(bloom: &'a Bloom) -> Self {
BloomRef(&bloom.0)
}
}
#[cfg(feature = "serialize")]
impl_fixed_hash_serde!(Bloom, BLOOM_SIZE);
#[cfg(test)]
mod tests {
use super::{Bloom, Input};
#[test]
fn it_works() {
use std::str::FromStr;
let bloom = Bloom::from_str(
"00000000000000000000000000000000\
00000000100000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000002020000000000000000000000\
00000000000000000000000800000000\
10000000000000000000000000000000\
00000000000000000000001000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000\
00000000000000000000000000000000"
).unwrap();
let address = hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106");
let topic = hex!("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc");
let mut my_bloom = Bloom::default();
assert!(!my_bloom.contains_input(Input::Raw(&address)));
assert!(!my_bloom.contains_input(Input::Raw(&topic)));
my_bloom.accrue(Input::Raw(&address));
assert!(my_bloom.contains_input(Input::Raw(&address)));
assert!(!my_bloom.contains_input(Input::Raw(&topic)));
my_bloom.accrue(Input::Raw(&topic));
assert!(my_bloom.contains_input(Input::Raw(&address)));
assert!(my_bloom.contains_input(Input::Raw(&topic)));
assert_eq!(my_bloom, bloom);
}
}

24
ethereum-types/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
name = "ethereum-types"
version = "0.5.0"
authors = ["Parity Technologies <admin@parity.io>"]
license = "MIT"
homepage = "https://github.com/paritytech/parity-common"
description = "Ethereum types"
[dependencies]
ethbloom = { path = "../ethbloom", version = "0.6", default-features = false }
fixed-hash = { path = "../fixed-hash", version = "0.3", default-features = false, features = ["byteorder", "rustc-hex"] }
uint = { path = "../uint", version = "0.6", default-features = false }
primitive-types = { path = "../primitive-types", version = "0.2", features = ["rlp", "byteorder", "rustc-hex"], default-features = false }
impl-serde = { path = "../primitive-types/impls/serde", version = "0.1", default-features = false, optional = true }
impl-rlp = { path = "../primitive-types/impls/rlp", version = "0.1", default-features = false }
[dev-dependencies]
serde_json = "1.0"
[features]
default = ["std", "heapsize", "serialize"]
std = ["uint/std", "fixed-hash/std", "ethbloom/std", "primitive-types/std"]
heapsize = ["uint/heapsize", "primitive-types/heapsize", "fixed-hash/heapsize", "ethbloom/heapsize"]
serialize = ["std", "impl-serde", "primitive-types/serde", "ethbloom/serialize"]

View File

@ -0,0 +1,216 @@
// Copyright 2015-2017 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! benchmarking for bigint
//! should be started with:
//! ```bash
//! rustup run nightly cargo bench
//! ```
#![feature(test)]
#![feature(asm)]
extern crate test;
extern crate bigint;
use test::{Bencher, black_box};
use bigint::{U256, U512, U128};
#[bench]
fn u256_add(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let zero = black_box(U256::zero());
(0..n).fold(zero, |old, new| {
old.overflowing_add(U256::from(black_box(new))).0
})
});
}
#[bench]
fn u256_sub(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let max = black_box(U256::max_value());
(0..n).fold(max, |old, new| {
old.overflowing_sub(U256::from(black_box(new))).0
})
});
}
#[bench]
fn u512_sub(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let max = black_box(U512::max_value());
(0..n).fold(max, |old, new| {
let new = black_box(new);
let p = new % 2;
old.overflowing_sub(U512([p, p, p, p, p, p, p, new])).0
})
});
}
#[bench]
fn u512_add(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let zero = black_box(U512::zero());
(0..n).fold(zero, |old, new| {
let new = black_box(new);
old.overflowing_add(U512([new, new, new, new, new, new, new, new]))
.0
})
});
}
#[bench]
fn u512_mul(b: &mut Bencher) {
b.iter(|| {
(1..10000).fold(black_box(U512::one()), |old, new| {
old.overflowing_mul(U512::from(black_box(new | 1))).0
})
});
}
#[bench]
fn u512_mul_small(b: &mut Bencher) {
b.iter(|| {
(1..153).fold(black_box(U512::one()), |old, _| {
old.overflowing_mul(U512::from(black_box(10))).0
})
});
}
#[bench]
fn u256_mul(b: &mut Bencher) {
b.iter(|| {
(1..10000).fold(black_box(U256::one()), |old, new| {
old.overflowing_mul(U256::from(black_box(new | 1))).0
})
});
}
#[bench]
fn u256_mul_small(b: &mut Bencher) {
b.iter(|| {
(1..77).fold(black_box(U256::one()), |old, _| {
old.overflowing_mul(U256::from(black_box(10))).0
})
});
}
#[bench]
fn u256_full_mul(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
let one = black_box(U256::one());
(1..n).map(|n| n | 1).fold(one, |old, new| {
let new = black_box(new);
let U512(ref u512words) = old.full_mul(U256([new, new, new, new]));
U256([u512words[0], u512words[2], u512words[2], u512words[3]])
})
});
}
#[bench]
fn u128_mul(b: &mut Bencher) {
b.iter(|| {
let n = black_box(10000);
(1..n).fold(U128([12345u64, 0u64]), |old, new| {
old.overflowing_mul(U128::from(new | 1)).0
})
});
}
#[bench]
fn u256_from_le(b: &mut Bencher) {
b.iter(|| {
let raw = black_box(
[
1u8,
2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
127,
],
);
let _ = U256::from_little_endian(&raw[..]);
});
}
#[bench]
fn u256_from_be(b: &mut Bencher) {
b.iter(|| {
let raw = black_box(
[
1u8,
2,
3,
5,
7,
11,
13,
17,
19,
23,
29,
31,
37,
41,
43,
47,
53,
59,
61,
67,
71,
73,
79,
83,
89,
97,
101,
103,
107,
109,
113,
127,
],
);
let _ = U256::from_big_endian(&raw[..]);
});
}

108
ethereum-types/src/hash.rs Normal file
View File

@ -0,0 +1,108 @@
use crate::{U64, U128, U256, U512};
pub trait BigEndianHash {
type Uint;
fn from_uint(val: &Self::Uint) -> Self;
fn into_uint(&self) -> Self::Uint;
}
construct_fixed_hash!{ pub struct H32(4); }
impl_fixed_hash_rlp!(H32, 4);
#[cfg(feature = "serialize")] impl_fixed_hash_serde!(H32, 4);
construct_fixed_hash!{ pub struct H64(8); }
impl_fixed_hash_rlp!(H64, 8);
#[cfg(feature = "serialize")] impl_fixed_hash_serde!(H64, 8);
construct_fixed_hash!{ pub struct H128(16); }
impl_fixed_hash_rlp!(H128, 16);
#[cfg(feature = "serialize")] impl_fixed_hash_serde!(H128, 16);
pub use primitive_types::H160;
pub use primitive_types::H256;
construct_fixed_hash!{ pub struct H264(33); }
impl_fixed_hash_rlp!(H264, 33);
#[cfg(feature = "serialize")] impl_fixed_hash_serde!(H264, 33);
pub use primitive_types::H512;
construct_fixed_hash!{ pub struct H520(65); }
impl_fixed_hash_rlp!(H520, 65);
#[cfg(feature = "serialize")] impl_fixed_hash_serde!(H520, 65);
macro_rules! impl_uint_conversions {
($hash: ident, $uint: ident) => {
impl BigEndianHash for $hash {
type Uint = $uint;
fn from_uint(value: &$uint) -> Self {
let mut ret = $hash::zero();
value.to_big_endian(ret.as_bytes_mut());
ret
}
fn into_uint(&self) -> $uint {
$uint::from(self.as_ref() as &[u8])
}
}
}
}
impl_uint_conversions!(H64, U64);
impl_uint_conversions!(H128, U128);
impl_uint_conversions!(H256, U256);
impl_uint_conversions!(H512, U512);
#[cfg(test)]
mod tests {
use super::{H160, H256};
use serde_json as ser;
#[test]
fn test_serialize_h160() {
let tests = vec![
(H160::from_low_u64_be(0), "0x0000000000000000000000000000000000000000"),
(H160::from_low_u64_be(2), "0x0000000000000000000000000000000000000002"),
(H160::from_low_u64_be(15), "0x000000000000000000000000000000000000000f"),
(H160::from_low_u64_be(16), "0x0000000000000000000000000000000000000010"),
(H160::from_low_u64_be(1_000), "0x00000000000000000000000000000000000003e8"),
(H160::from_low_u64_be(100_000), "0x00000000000000000000000000000000000186a0"),
(H160::from_low_u64_be(u64::max_value()), "0x000000000000000000000000ffffffffffffffff"),
];
for (number, expected) in tests {
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap());
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
}
}
#[test]
fn test_serialize_h256() {
let tests = vec![
(H256::from_low_u64_be(0), "0x0000000000000000000000000000000000000000000000000000000000000000"),
(H256::from_low_u64_be(2), "0x0000000000000000000000000000000000000000000000000000000000000002"),
(H256::from_low_u64_be(15), "0x000000000000000000000000000000000000000000000000000000000000000f"),
(H256::from_low_u64_be(16), "0x0000000000000000000000000000000000000000000000000000000000000010"),
(H256::from_low_u64_be(1_000), "0x00000000000000000000000000000000000000000000000000000000000003e8"),
(H256::from_low_u64_be(100_000), "0x00000000000000000000000000000000000000000000000000000000000186a0"),
(H256::from_low_u64_be(u64::max_value()), "0x000000000000000000000000000000000000000000000000ffffffffffffffff"),
];
for (number, expected) in tests {
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap());
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
}
}
#[test]
fn test_serialize_invalid() {
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0x000000000000000000000000000000000000000000000000000000000000000g\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0x00000000000000000000000000000000000000000000000000000000000000000\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"0\"").unwrap_err().is_data());
assert!(ser::from_str::<H256>("\"10\"").unwrap_err().is_data());
}
}

32
ethereum-types/src/lib.rs Normal file
View File

@ -0,0 +1,32 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate core;
#[macro_use]
extern crate uint as uint_crate;
#[macro_use]
extern crate fixed_hash;
extern crate ethbloom;
extern crate primitive_types;
#[cfg(feature = "serialize")]
#[macro_use]
extern crate impl_serde;
#[macro_use]
extern crate impl_rlp;
#[cfg(test)]
extern crate serde_json;
mod hash;
mod uint;
pub use uint::{U64, U128, U256, U512};
pub use hash::{BigEndianHash, H32, H64, H128, H160, H256, H264, H512, H520};
pub use ethbloom::{Bloom, BloomRef, Input as BloomInput};
pub type Address = H160;
pub type Secret = H256;
pub type Public = H512;
pub type Signature = H520;

177
ethereum-types/src/uint.rs Normal file
View File

@ -0,0 +1,177 @@
construct_uint! {
/// Unsigned 64-bit integer.
pub struct U64(1);
}
impl_uint_rlp!(U64, 1);
#[cfg(feature = "serialize")] impl_uint_serde!(U64, 1);
pub use primitive_types::{U128, U256, U512};
#[cfg(test)]
mod tests {
use super::{U256, U512};
use std::u64::MAX;
use serde_json as ser;
macro_rules! test_serialize {
($name: ident, $test_name: ident) => {
#[test]
fn $test_name() {
let tests = vec![
($name::from(0), "0x0"),
($name::from(1), "0x1"),
($name::from(2), "0x2"),
($name::from(10), "0xa"),
($name::from(15), "0xf"),
($name::from(15), "0xf"),
($name::from(16), "0x10"),
($name::from(1_000), "0x3e8"),
($name::from(100_000), "0x186a0"),
($name::from(u64::max_value()), "0xffffffffffffffff"),
($name::from(u64::max_value()) + 1, "0x10000000000000000"),
];
for (number, expected) in tests {
assert_eq!(format!("{:?}", expected), ser::to_string_pretty(&number).unwrap());
assert_eq!(number, ser::from_str(&format!("{:?}", expected)).unwrap());
}
// Invalid examples
assert!(ser::from_str::<$name>("\"0x\"").unwrap_err().is_data());
assert!(ser::from_str::<$name>("\"0xg\"").unwrap_err().is_data());
assert!(ser::from_str::<$name>("\"\"").unwrap_err().is_data());
assert!(ser::from_str::<$name>("\"10\"").unwrap_err().is_data());
assert!(ser::from_str::<$name>("\"0\"").unwrap_err().is_data());
}
}
}
test_serialize!(U256, test_u256);
test_serialize!(U512, test_u512);
#[test]
fn test_serialize_large_values() {
assert_eq!(
ser::to_string_pretty(&!U256::zero()).unwrap(),
"\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\""
);
assert!(
ser::from_str::<U256>("\"0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\"").unwrap_err().is_data()
);
}
#[test]
fn fixed_arrays_roundtrip() {
let raw: U256 = "7094875209347850239487502394881".into();
let array: [u8; 32] = raw.into();
let new_raw = array.into();
assert_eq!(raw, new_raw);
}
#[test]
fn u256_multi_full_mul() {
let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0]));
assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result);
let result = U256([1, 0, 0, 0]).full_mul(U256([1, 0, 0, 0]));
assert_eq!(U512([1, 0, 0, 0, 0, 0, 0, 0]), result);
let result = U256([5, 0, 0, 0]).full_mul(U256([5, 0, 0, 0]));
assert_eq!(U512([25, 0, 0, 0, 0, 0, 0, 0]), result);
let result = U256([0, 5, 0, 0]).full_mul(U256([0, 5, 0, 0]));
assert_eq!(U512([0, 0, 25, 0, 0, 0, 0, 0]), result);
let result = U256([0, 0, 0, 4]).full_mul(U256([4, 0, 0, 0]));
assert_eq!(U512([0, 0, 0, 16, 0, 0, 0, 0]), result);
let result = U256([0, 0, 0, 5]).full_mul(U256([2, 0, 0, 0]));
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
let result = U256([0, 0, 2, 0]).full_mul(U256([0, 5, 0, 0]));
assert_eq!(U512([0, 0, 0, 10, 0, 0, 0, 0]), result);
let result = U256([0, 3, 0, 0]).full_mul(U256([0, 0, 3, 0]));
assert_eq!(U512([0, 0, 0, 9, 0, 0, 0, 0]), result);
let result = U256([0, 0, 8, 0]).full_mul(U256([0, 0, 6, 0]));
assert_eq!(U512([0, 0, 0, 0, 48, 0, 0, 0]), result);
let result = U256([9, 0, 0, 0]).full_mul(U256([0, 3, 0, 0]));
assert_eq!(U512([0, 27, 0, 0, 0, 0, 0, 0]), result);
let result = U256([MAX, 0, 0, 0]).full_mul(U256([MAX, 0, 0, 0]));
assert_eq!(U512([1, MAX-1, 0, 0, 0, 0, 0, 0]), result);
let result = U256([0, MAX, 0, 0]).full_mul(U256([MAX, 0, 0, 0]));
assert_eq!(U512([0, 1, MAX-1, 0, 0, 0, 0, 0]), result);
let result = U256([MAX, MAX, 0, 0]).full_mul(U256([MAX, 0, 0, 0]));
assert_eq!(U512([1, MAX, MAX-1, 0, 0, 0, 0, 0]), result);
let result = U256([MAX, 0, 0, 0]).full_mul(U256([MAX, MAX, 0, 0]));
assert_eq!(U512([1, MAX, MAX-1, 0, 0, 0, 0, 0]), result);
let result = U256([MAX, MAX, 0, 0]).full_mul(U256([MAX, MAX, 0, 0]));
assert_eq!(U512([1, 0, MAX-1, MAX, 0, 0, 0, 0]), result);
let result = U256([MAX, 0, 0, 0]).full_mul(U256([MAX, MAX, MAX, 0]));
assert_eq!(U512([1, MAX, MAX, MAX-1, 0, 0, 0, 0]), result);
let result = U256([MAX, MAX, MAX, 0]).full_mul(U256([MAX, 0, 0, 0]));
assert_eq!(U512([1, MAX, MAX, MAX-1, 0, 0, 0, 0]), result);
let result = U256([MAX, 0, 0, 0]).full_mul(U256([MAX, MAX, MAX, MAX]));
assert_eq!(U512([1, MAX, MAX, MAX, MAX-1, 0, 0, 0]), result);
let result = U256([MAX, MAX, MAX, MAX]).full_mul(U256([MAX, 0, 0, 0]));
assert_eq!(U512([1, MAX, MAX, MAX, MAX-1, 0, 0, 0]), result);
let result = U256([MAX, MAX, MAX, 0]).full_mul(U256([MAX, MAX, 0, 0]));
assert_eq!(U512([1, 0, MAX, MAX-1, MAX, 0, 0, 0]), result);
let result = U256([MAX, MAX, 0, 0]).full_mul(U256([MAX, MAX, MAX, 0]));
assert_eq!(U512([1, 0, MAX, MAX-1, MAX, 0, 0, 0]), result);
let result = U256([MAX, MAX, MAX, MAX]).full_mul(U256([MAX, MAX, 0, 0]));
assert_eq!(U512([1, 0, MAX, MAX, MAX-1, MAX, 0, 0]), result);
let result = U256([MAX, MAX, 0, 0]).full_mul(U256([MAX, MAX, MAX, MAX]));
assert_eq!(U512([1, 0, MAX, MAX, MAX-1, MAX, 0, 0]), result);
let result = U256([MAX, MAX, MAX, 0]).full_mul(U256([MAX, MAX, MAX, 0]));
assert_eq!(U512([1, 0, 0, MAX-1, MAX, MAX, 0, 0]), result);
let result = U256([MAX, MAX, MAX, 0]).full_mul(U256([MAX, MAX, MAX, MAX]));
assert_eq!(U512([1, 0, 0, MAX, MAX-1, MAX, MAX, 0]), result);
let result = U256([MAX, MAX, MAX, MAX]).full_mul(U256([MAX, MAX, MAX, 0]));
assert_eq!(U512([1, 0, 0, MAX, MAX-1, MAX, MAX, 0]), result);
let result = U256([MAX, MAX, MAX, MAX]).full_mul(U256([MAX, MAX, MAX, MAX]));
assert_eq!(U512([1, 0, 0, 0, MAX-1, MAX, MAX, MAX]), result);
let result = U256([0, 0, 0, MAX]).full_mul(U256([0, 0, 0, MAX]));
assert_eq!(U512([0, 0, 0, 0, 0, 0, 1, MAX-1]), result);
let result = U256([1, 0, 0, 0]).full_mul(U256([0, 0, 0, MAX]));
assert_eq!(U512([0, 0, 0, MAX, 0, 0, 0, 0]), result);
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 0, 0, 0]));
assert_eq!(U512([5, 10, 15, 20, 0, 0, 0, 0]), result);
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 6, 0, 0]));
assert_eq!(U512([0, 6, 12, 18, 24, 0, 0, 0]), result);
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 7, 0]));
assert_eq!(U512([0, 0, 7, 14, 21, 28, 0, 0]), result);
let result = U256([1, 2, 3, 4]).full_mul(U256([0, 0, 0, 8]));
assert_eq!(U512([0, 0, 0, 8, 16, 24, 32, 0]), result);
let result = U256([1, 2, 3, 4]).full_mul(U256([5, 6, 7, 8]));
assert_eq!(U512([5, 16, 34, 60, 61, 52, 32, 0]), result);
}
}

View File

@ -1,6 +1,6 @@
[package]
name = "primitive-types"
version = "0.2.1"
version = "0.2.2"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"

View File

@ -0,0 +1,67 @@
// Copyright 2015-2019 Parity Technologies
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// TODO: Remove TryFrom and TryInto when Rust trait is stablized
// https://github.com/paritytech/parity-common/issues/103
//! Error, `TryFrom` and `TryInto` trait, should be removed when standard library stablize those.
/// Error type for conversion.
pub enum Error {
/// Overflow encountered.
Overflow,
}
/// An attempted conversion that consumes `self`, which may or may not be
/// expensive.
///
/// Library authors should not directly implement this trait, but should prefer
/// implementing the [`TryFrom`] trait, which offers greater flexibility and
/// provides an equivalent `TryInto` implementation for free, thanks to a
/// blanket implementation in the standard library. For more information on this,
/// see the documentation for [`Into`].
///
/// [`TryFrom`]: trait.TryFrom.html
/// [`Into`]: trait.Into.html
pub trait TryInto<T>: Sized {
/// The type returned in the event of a conversion error.
type Error;
/// Performs the conversion.
fn try_into(self) -> Result<T, Self::Error>;
}
/// Attempt to construct `Self` via a conversion.
pub trait TryFrom<T>: Sized {
/// The type returned in the event of a conversion error.
type Error;
/// Performs the conversion.
fn try_from(value: T) -> Result<Self, Self::Error>;
}
// TryFrom implies TryInto
impl<T, U> TryInto<U> for T where U: TryFrom<T>
{
type Error = U::Error;
fn try_into(self) -> Result<U, U::Error> {
U::try_from(self)
}
}
pub enum Never { }
// Infallible conversions are semantically equivalent to fallible conversions
// with an uninhabited error type.
impl<T, U> TryFrom<U> for T where T: From<U> {
type Error = Never;
fn try_from(value: U) -> Result<Self, Self::Error> {
Ok(T::from(value))
}
}

View File

@ -14,6 +14,10 @@
#![cfg_attr(not(feature = "std"), no_std)]
mod error;
pub use error::{Error, TryFrom, TryInto, Never};
#[macro_use]
extern crate uint;
@ -97,7 +101,6 @@ mod rlp {
impl_fixed_hash_rlp!(H512, 64);
}
impl_fixed_hash_conversions!(H256, H160);
impl U256 {
@ -121,17 +124,69 @@ impl From<U256> for U512 {
}
}
impl From<U512> for U256 {
fn from(value: U512) -> U256 {
impl TryFrom<U256> for U128 {
type Error = Error;
fn try_from(value: U256) -> Result<U128, Error> {
let U256(ref arr) = value;
if arr[2] | arr[3] != 0 {
return Err(Error::Overflow);
}
let mut ret = [0; 2];
ret[0] = arr[0];
ret[1] = arr[1];
Ok(U128(ret))
}
}
impl TryFrom<U512> for U256 {
type Error = Error;
fn try_from(value: U512) -> Result<U256, Error> {
let U512(ref arr) = value;
if arr[4] | arr[5] | arr[6] | arr[7] != 0 {
panic!("From<U512> for U256: encountered overflow")
return Err(Error::Overflow);
}
let mut ret = [0; 4];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
Ok(U256(ret))
}
}
impl TryFrom<U512> for U128 {
type Error = Error;
fn try_from(value: U512) -> Result<U128, Error> {
let U512(ref arr) = value;
if arr[2] | arr[3] | arr[4] | arr[5] | arr[6] | arr[7] != 0 {
return Err(Error::Overflow);
}
let mut ret = [0; 2];
ret[0] = arr[0];
ret[1] = arr[1];
Ok(U128(ret))
}
}
impl From<U128> for U512 {
fn from(value: U128) -> U512 {
let U128(ref arr) = value;
let mut ret = [0; 8];
ret[0] = arr[0];
ret[1] = arr[1];
U512(ret)
}
}
impl From<U128> for U256 {
fn from(value: U128) -> U256 {
let U128(ref arr) = value;
let mut ret = [0; 4];
ret[0] = arr[0];
ret[1] = arr[1];
U256(ret)
}
}
@ -148,17 +203,19 @@ impl<'a> From<&'a U256> for U512 {
}
}
impl<'a> From<&'a U512> for U256 {
fn from(value: &'a U512) -> U256 {
impl<'a> TryFrom<&'a U512> for U256 {
type Error = Error;
fn try_from(value: &'a U512) -> Result<U256, Error> {
let U512(ref arr) = *value;
if arr[4] | arr[5] | arr[6] | arr[7] != 0 {
panic!("From<&U512> for U256: encountered overflow")
return Err(Error::Overflow);
}
let mut ret = [0; 4];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
U256(ret)
Ok(U256(ret))
}
}