Merge pull request #86 from paritytech/sp-primitive-types-init

Unify primitive types for Parity Ethereum and Substrate
This commit is contained in:
Wei Tang 2019-01-07 21:49:45 +01:00 committed by GitHub
commit 6e04748a72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 515 additions and 1 deletions

View File

@ -17,5 +17,6 @@ members = [
"trace-time",
"trie-standardmap",
"triehash",
"uint"
"uint",
"primitive-types",
]

View File

@ -0,0 +1,25 @@
[package]
name = "primitive-types"
version = "0.1.5"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"
description = "Primitive types shared by Ethereum and Substrate"
[dependencies]
fixed-hash = { version = "0.3", path = "../fixed-hash", default-features = false }
uint = { version = "0.6", path = "../uint", default-features = false }
impl-serde = { version = "0.1", path = "impls/serde", default-features = false, optional = true }
impl-codec = { version = "0.1", path = "impls/codec", default-features = false, optional = true }
impl-rlp = { version = "0.1", path = "impls/rlp", default-features = false, optional = true }
[features]
default = ["std"]
std = ["uint/std", "fixed-hash/std", "impl-codec/std"]
heapsize = ["uint/heapsize", "fixed-hash/heapsize"]
byteorder = ["fixed-hash/byteorder"]
libc = ["fixed-hash/libc"]
rustc-hex = ["fixed-hash/rustc-hex"]
serde = ["std", "impl-serde"]
codec = ["impl-codec"]
rlp = ["std", "impl-rlp"]

View File

@ -0,0 +1,14 @@
[package]
name = "impl-codec"
version = "0.1.1"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"
description = "Parity Codec serialization support for uint and fixed hash."
[dependencies]
parity-codec = { version = "2.1", default-features = false }
[features]
default = ["std"]
std = ["parity-codec/std"]

View File

@ -0,0 +1,52 @@
// Copyright 2015-2018 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.
//! Parity Codec serialization support for uint and fixed hash.
#![cfg_attr(not(feature = "std"), no_std)]
#[doc(hidden)]
pub extern crate parity_codec as codec;
/// Add Parity Codec serialization support to an integer created by `construct_uint!`.
#[macro_export]
macro_rules! impl_uint_codec {
($name: ident, $len: expr) => {
impl $crate::codec::Encode for $name {
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let mut bytes = [0u8; $len * 8];
self.to_little_endian(&mut bytes);
bytes.using_encoded(f)
}
}
impl $crate::codec::Decode for $name {
fn decode<I: $crate::codec::Input>(input: &mut I) -> Option<Self> {
<[u8; $len * 8] as $crate::codec::Decode>::decode(input)
.map(|b| $name::from_little_endian(&b))
}
}
}
}
/// Add Parity Codec serialization support to a fixed-sized hash type created by `construct_fixed_hash!`.
#[macro_export]
macro_rules! impl_fixed_hash_codec {
($name: ident, $len: expr) => {
impl $crate::codec::Encode for $name {
fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
self.0.using_encoded(f)
}
}
impl $crate::codec::Decode for $name {
fn decode<I: $crate::codec::Input>(input: &mut I) -> Option<Self> {
<[u8; $len] as $crate::codec::Decode>::decode(input).map($name)
}
}
}
}

View File

@ -0,0 +1,10 @@
[package]
name = "impl-rlp"
version = "0.1.1"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"
description = "RLP serialization support for uint and fixed hash."
[dependencies]
rlp = { version = "0.3", path = "../../../rlp", default-features = false }

View File

@ -0,0 +1,70 @@
// Copyright 2015-2018 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.
//! RLP serialization support for uint and fixed hash.
#[doc(hidden)]
pub extern crate rlp;
#[doc(hidden)]
pub extern crate core as core_;
/// Add RLP serialization support to an integer created by `construct_uint!`.
#[macro_export]
macro_rules! impl_uint_rlp {
($name: ident, $size: expr) => {
impl $crate::rlp::Encodable for $name {
fn rlp_append(&self, s: &mut $crate::rlp::RlpStream) {
let leading_empty_bytes = $size - (self.bits() + 7) / 8;
let mut buffer = [0u8; $size];
self.to_big_endian(&mut buffer);
s.encoder().encode_value(&buffer[leading_empty_bytes..]);
}
}
impl $crate::rlp::Decodable for $name {
fn decode(rlp: &$crate::rlp::Rlp) -> Result<Self, $crate::rlp::DecoderError> {
rlp.decoder().decode_value(|bytes| {
if !bytes.is_empty() && bytes[0] == 0 {
Err($crate::rlp::DecoderError::RlpInvalidIndirection)
} else if bytes.len() <= $size {
Ok($name::from(bytes))
} else {
Err($crate::rlp::DecoderError::RlpIsTooBig)
}
})
}
}
}
}
/// Add RLP serialization support to a fixed-sized hash type created by `construct_fixed_hash!`.
#[macro_export]
macro_rules! impl_fixed_hash_rlp {
($name: ident, $size: expr) => {
impl $crate::rlp::Encodable for $name {
fn rlp_append(&self, s: &mut $crate::rlp::RlpStream) {
s.encoder().encode_value(self.as_ref());
}
}
impl $crate::rlp::Decodable for $name {
fn decode(rlp: &$crate::rlp::Rlp) -> Result<Self, $crate::rlp::DecoderError> {
rlp.decoder().decode_value(|bytes| match bytes.len().cmp(&$size) {
$crate::core_::cmp::Ordering::Less => Err($crate::rlp::DecoderError::RlpIsTooShort),
$crate::core_::cmp::Ordering::Greater => Err($crate::rlp::DecoderError::RlpIsTooBig),
$crate::core_::cmp::Ordering::Equal => {
let mut t = [0u8; $size];
t.copy_from_slice(bytes);
Ok($name(t))
}
})
}
}
}
}

View File

@ -0,0 +1,11 @@
[package]
name = "impl-serde"
version = "0.1.1"
authors = ["Parity Technologies <admin@parity.io>"]
license = "Apache-2.0/MIT"
homepage = "https://github.com/paritytech/parity-common"
description = "Serde serialization support for uint and fixed hash."
[dependencies]
serde = "1.0"
rustc-hex = "2"

View File

@ -0,0 +1,58 @@
// Copyright 2015-2018 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.
//! Serde serialization support for uint and fixed hash.
#[doc(hidden)]
pub extern crate serde;
#[doc(hidden)]
pub extern crate rustc_hex;
#[doc(hidden)]
pub mod serialize;
/// Add Serde serialization support to an integer created by `construct_uint!`.
#[macro_export]
macro_rules! impl_uint_serde {
($name: ident, $len: expr) => {
impl $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: $crate::serde::Serializer {
let mut bytes = [0u8; $len * 8];
self.to_big_endian(&mut bytes);
$crate::serialize::serialize_uint(&bytes, serializer)
}
}
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: $crate::serde::Deserializer<'de> {
$crate::serialize::deserialize_check_len(deserializer, $crate::serialize::ExpectedLen::Between(0, $len * 8))
.map(|x| (&*x).into())
}
}
}
}
/// Add Serde serialization support to a fixed-sized hash type created by `construct_fixed_hash!`.
#[macro_export]
macro_rules! impl_fixed_hash_serde {
($name: ident, $len: expr) => {
impl $crate::serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: $crate::serde::Serializer {
$crate::serialize::serialize(&self.0, serializer)
}
}
impl<'de> $crate::serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: $crate::serde::Deserializer<'de> {
$crate::serialize::deserialize_check_len(deserializer, $crate::serialize::ExpectedLen::Exact($len))
.map(|x| $name::from_slice(&x))
}
}
}
}

View File

@ -0,0 +1,120 @@
// Copyright 2015-2018 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.
use std::fmt;
use serde::{de, Serializer, Deserializer};
/// Serializes a slice of bytes.
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
let hex: String = ::rustc_hex::ToHex::to_hex(bytes);
serializer.serialize_str(&format!("0x{}", hex))
}
/// Serialize a slice of bytes as uint.
///
/// The representation will have all leading zeros trimmed.
pub fn serialize_uint<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
let non_zero = bytes.iter().take_while(|b| **b == 0).count();
let bytes = &bytes[non_zero..];
if bytes.is_empty() {
return serializer.serialize_str("0x0");
}
let hex: String = ::rustc_hex::ToHex::to_hex(bytes);
let has_leading_zero = !hex.is_empty() && &hex[0..1] == "0";
serializer.serialize_str(
&format!("0x{}", if has_leading_zero { &hex[1..] } else { &hex })
)
}
/// Expected length of bytes vector.
#[derive(PartialEq, Eq, Debug)]
pub enum ExpectedLen {
/// Any length in bytes.
Any,
/// Exact length in bytes.
Exact(usize),
/// A bytes length between (min; max].
Between(usize, usize),
}
impl fmt::Display for ExpectedLen {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
match *self {
ExpectedLen::Any => write!(fmt, "even length"),
ExpectedLen::Exact(v) => write!(fmt, "length of {}", v * 2),
ExpectedLen::Between(min, max) => write!(fmt, "length between ({}; {}]", min * 2, max * 2),
}
}
}
/// Deserialize into vector of bytes.
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error> where
D: Deserializer<'de>,
{
deserialize_check_len(deserializer, ExpectedLen::Any)
}
/// Deserialize into vector of bytes with additional size check.
pub fn deserialize_check_len<'de, D>(deserializer: D, len: ExpectedLen) -> Result<Vec<u8>, D::Error> where
D: Deserializer<'de>,
{
struct Visitor {
len: ExpectedLen,
}
impl<'a> de::Visitor<'a> for Visitor {
type Value = Vec<u8>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a 0x-prefixed hex string with {}", self.len)
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
if v.len() < 2 || &v[0..2] != "0x" {
return Err(E::custom("prefix is missing"))
}
let is_len_valid = match self.len {
// just make sure that we have all nibbles
ExpectedLen::Any => v.len() % 2 == 0,
ExpectedLen::Exact(len) => v.len() == 2 * len + 2,
ExpectedLen::Between(min, max) => v.len() <= 2 * max + 2 && v.len() > 2 * min + 2,
};
if !is_len_valid {
return Err(E::invalid_length(v.len() - 2, &self))
}
let bytes = match self.len {
ExpectedLen::Between(..) if v.len() % 2 != 0 => {
::rustc_hex::FromHex::from_hex(&*format!("0{}", &v[2..]))
},
_ => ::rustc_hex::FromHex::from_hex(&v[2..])
};
fn format_err(e: ::rustc_hex::FromHexError) -> String {
format!("invalid hex value: {:?}", e)
}
bytes.map_err(|e| E::custom(format_err(e)))
}
fn visit_string<E: de::Error>(self, v: String) -> Result<Self::Value, E> {
self.visit_str(&v)
}
}
// TODO [ToDr] Use raw bytes if we switch to RLP / binencoding
// (visit_bytes, visit_bytes_buf)
deserializer.deserialize_str(Visitor { len })
}

153
primitive-types/src/lib.rs Normal file
View File

@ -0,0 +1,153 @@
// Copyright 2015-2018 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.
//! Primitive types shared by Substrate and Parity Ethereum.
//!
//! Those are uint types `U256` and `U512`, and fixed hash types `H160`,
//! `H256` and `H512`, with optional serde serialization, parity-codec and
//! rlp encoding.
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate uint;
#[macro_use]
extern crate fixed_hash;
#[cfg(feature = "impl-serde")]
#[macro_use]
extern crate impl_serde;
#[cfg(feature = "impl-codec")]
#[macro_use]
extern crate impl_codec;
#[cfg(feature = "impl-rlp")]
#[macro_use]
extern crate impl_rlp;
construct_uint! {
/// 256-bit unsigned integer.
pub struct U256(4);
}
#[cfg(feature = "impl-serde")]
impl_uint_serde!(U256, 4);
#[cfg(feature = "impl-codec")]
impl_uint_codec!(U256, 4);
#[cfg(feature = "impl-rlp")]
impl_uint_rlp!(U256, 4);
impl U256 {
/// Multiplies two 256-bit integers to produce full 512-bit integer
/// No overflow possible
#[inline(always)]
pub fn full_mul(self, other: U256) -> U512 {
U512(uint_full_mul_reg!(U256, 4, self, other))
}
}
impl From<U256> for U512 {
fn from(value: U256) -> U512 {
let U256(ref arr) = value;
let mut ret = [0; 8];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
U512(ret)
}
}
impl From<U512> for U256 {
fn from(value: U512) -> U256 {
let U512(ref arr) = value;
if arr[4] | arr[5] | arr[6] | arr[7] != 0 {
panic!("From<U512> for U256: encountered overflow")
}
let mut ret = [0; 4];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
U256(ret)
}
}
impl<'a> From<&'a U256> for U512 {
fn from(value: &'a U256) -> U512 {
let U256(ref arr) = *value;
let mut ret = [0; 8];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
U512(ret)
}
}
impl<'a> From<&'a U512> for U256 {
fn from(value: &'a U512) -> U256 {
let U512(ref arr) = *value;
if arr[4] | arr[5] | arr[6] | arr[7] != 0 {
panic!("From<&U512> for U256: encountered overflow")
}
let mut ret = [0; 4];
ret[0] = arr[0];
ret[1] = arr[1];
ret[2] = arr[2];
ret[3] = arr[3];
U256(ret)
}
}
construct_uint! {
/// 512-bits unsigned integer.
pub struct U512(8);
}
#[cfg(feature = "impl-serde")]
impl_uint_serde!(U512, 8);
#[cfg(feature = "impl-codec")]
impl_uint_codec!(U512, 8);
#[cfg(feature = "impl-rlp")]
impl_uint_rlp!(U512, 8);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 20 bytes (160 bits) size.
pub struct H160(20);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H160, 20);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H160, 20);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H160, 20);
impl_fixed_hash_conversions!(H256, H160);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 32 bytes (256 bits) size.
pub struct H256(32);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H256, 32);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H256, 32);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H256, 32);
construct_fixed_hash! {
/// Fixed-size uninterpreted hash type with 64 bytes (512 bits) size.
pub struct H512(64);
}
#[cfg(feature = "impl-serde")]
impl_fixed_hash_serde!(H512, 64);
#[cfg(feature = "impl-codec")]
impl_fixed_hash_codec!(H512, 64);
#[cfg(feature = "impl-rlp")]
impl_fixed_hash_rlp!(H512, 64);