Merge pull request #86 from paritytech/sp-primitive-types-init
Unify primitive types for Parity Ethereum and Substrate
This commit is contained in:
commit
6e04748a72
|
@ -17,5 +17,6 @@ members = [
|
|||
"trace-time",
|
||||
"trie-standardmap",
|
||||
"triehash",
|
||||
"uint"
|
||||
"uint",
|
||||
"primitive-types",
|
||||
]
|
||||
|
|
|
@ -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"]
|
|
@ -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"]
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 }
|
|
@ -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))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 })
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue