Implement Deserialize for SignedBlock and Header. (#3370)

* Implement Deserialize for SignedBlock.

* Implement Deserialize for Header.

* Deserialize number.

* Deserialize number (second try).

* Fix line length.

* Remove ::'s.
This commit is contained in:
David Craven
2019-08-12 17:07:11 +02:00
committed by GitHub
parent 36abb128f5
commit 6435df16f1
4 changed files with 75 additions and 30 deletions
@@ -17,7 +17,7 @@
//! Generic implementation of a block header.
#[cfg(feature = "std")]
use serde::Serialize;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use log::debug;
use crate::codec::{Decode, Encode, Codec, Input, Output, HasCompact, EncodeAsRef, Error};
@@ -26,37 +26,48 @@ use crate::traits::{
MaybeSerializeDebugButNotDeserialize
};
use crate::generic::Digest;
use primitives::U256;
use core::convert::TryFrom;
/// Abstraction over a block header for a substrate chain.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug, Serialize))]
#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Header<Number: Copy + Into<u128>, Hash: HashT> {
pub struct Header<Number: Copy + Into<U256> + TryFrom<U256>, Hash: HashT> {
/// The parent hash.
pub parent_hash: <Hash as HashT>::Output,
pub parent_hash: Hash::Output,
/// The block number.
#[cfg_attr(feature = "std", serde(serialize_with = "serialize_number"))]
#[cfg_attr(feature = "std", serde(
serialize_with = "serialize_number",
deserialize_with = "deserialize_number"))]
pub number: Number,
/// The state trie merkle root
pub state_root: <Hash as HashT>::Output,
pub state_root: Hash::Output,
/// The merkle root of the extrinsics.
pub extrinsics_root: <Hash as HashT>::Output,
pub extrinsics_root: Hash::Output,
/// A chain-specific digest of data useful for light clients or referencing auxiliary data.
pub digest: Digest<<Hash as HashT>::Output>,
pub digest: Digest<Hash::Output>,
}
#[cfg(feature = "std")]
pub fn serialize_number<S, T: Copy + Into<u128>>(val: &T, s: S) -> Result<S::Ok, S::Error> where S: ::serde::Serializer {
use primitives::uint::U256;
let v: u128 = (*val).into();
let lower = U256::from(v as u64);
let upper = U256::from(v.rotate_left(64) as u64) << 64;
::serde::Serialize::serialize(&(upper + lower), s)
pub fn serialize_number<S, T: Copy + Into<U256> + TryFrom<U256>>(
val: &T, s: S,
) -> Result<S::Ok, S::Error> where S: serde::Serializer {
let u256: U256 = (*val).into();
serde::Serialize::serialize(&u256, s)
}
#[cfg(feature = "std")]
pub fn deserialize_number<'a, D, T: Copy + Into<U256> + TryFrom<U256>>(
d: D,
) -> Result<T, D::Error> where D: serde::Deserializer<'a> {
let u256: U256 = serde::Deserialize::deserialize(d)?;
TryFrom::try_from(u256).map_err(|_| serde::de::Error::custom("Try from failed"))
}
impl<Number, Hash> Decode for Header<Number, Hash> where
Number: HasCompact + Copy + Into<u128>,
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Decode,
{
@@ -72,7 +83,7 @@ impl<Number, Hash> Decode for Header<Number, Hash> where
}
impl<Number, Hash> Encode for Header<Number, Hash> where
Number: HasCompact + Copy + Into<u128>,
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Encode,
{
@@ -86,15 +97,17 @@ impl<Number, Hash> Encode for Header<Number, Hash> where
}
impl<Number, Hash> codec::EncodeLike for Header<Number, Hash> where
Number: HasCompact + Copy + Into<u128>,
Number: HasCompact + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Encode,
{}
impl<Number, Hash> traits::Header for Header<Number, Hash> where
Number: Member + MaybeSerializeDebug + ::rstd::hash::Hash + MaybeDisplay + SimpleArithmetic + Codec + Copy + Into<u128>,
Number: Member + MaybeSerializeDebug + rstd::hash::Hash + MaybeDisplay +
SimpleArithmetic + Codec + Copy + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeSerializeDebugButNotDeserialize + MaybeDisplay + SimpleBitOps + Codec,
Hash::Output: Default + rstd::hash::Hash + Copy + Member +
MaybeSerializeDebugButNotDeserialize + MaybeDisplay + SimpleBitOps + Codec,
{
type Number = Number;
type Hash = <Hash as HashT>::Output;
@@ -141,9 +154,9 @@ impl<Number, Hash> traits::Header for Header<Number, Hash> where
}
impl<Number, Hash> Header<Number, Hash> where
Number: Member + ::rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec + Into<u128>,
Number: Member + rstd::hash::Hash + Copy + MaybeDisplay + SimpleArithmetic + Codec + Into<U256> + TryFrom<U256>,
Hash: HashT,
Hash::Output: Default + ::rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec,
Hash::Output: Default + rstd::hash::Hash + Copy + Member + MaybeDisplay + SimpleBitOps + Codec,
{
/// Convenience helper for computing the hash of the header without having
/// to import the trait.
@@ -161,7 +174,7 @@ mod tests {
fn serialize(num: u128) -> String {
let mut v = vec![];
{
let mut ser = ::serde_json::Serializer::new(::std::io::Cursor::new(&mut v));
let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v));
serialize_number(&num, &mut ser).unwrap();
}
String::from_utf8(v).unwrap()
@@ -173,4 +186,16 @@ mod tests {
assert_eq!(serialize(u64::max_value() as u128 + 1), "\"0x10000000000000000\"".to_owned());
}
#[test]
fn should_deserialize_number() {
fn deserialize(num: &str) -> u128 {
let mut der = serde_json::Deserializer::new(serde_json::de::StrRead::new(num));
deserialize_number(&mut der).unwrap()
}
assert_eq!(deserialize("\"0x0\""), 0);
assert_eq!(deserialize("\"0x1\""), 1);
assert_eq!(deserialize("\"0xffffffffffffffff\""), u64::max_value() as u128);
assert_eq!(deserialize("\"0x10000000000000000\""), u64::max_value() as u128 + 1);
}
}