diff --git a/Cargo.toml b/Cargo.toml index c2692b72..d56f7501 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,7 +74,6 @@ itertools = { version = "0.14" } trybuild = { version = "1.0" } lru = { version = "0.16" } - # ETH # TODO 3.0.0 has issues with some transitive dependency enabling STD in non-STD environment ethabi-decode = { version = "2.0.0", default-features = false } diff --git a/core/Cargo.toml b/core/Cargo.toml index 61b58d38..87851c0f 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -41,7 +41,6 @@ sp-runtime-interface = { workspace = true, optional = true } sp-storage = { workspace = true, optional = true } sp-trie = { workspace = true, optional = true } - [dev-dependencies] hex-literal = { workspace = true } rand = { workspace = true } diff --git a/core/src/bench_randomness.rs b/core/src/bench_randomness.rs deleted file mode 100644 index 2b308abf..00000000 --- a/core/src/bench_randomness.rs +++ /dev/null @@ -1,20 +0,0 @@ -use frame_support::traits::Randomness; - -/// Provides an implementation of [`frame_support::traits::Randomness`] that should only be used in -/// on Benchmarks! -pub struct BenchRandomness(sp_std::marker::PhantomData); - -impl Randomness for BenchRandomness -where - Output: codec::Decode + Default, - T: Default, -{ - fn random(subject: &[u8]) -> (Output, T) { - use sp_runtime::traits::TrailingZeroInput; - - ( - Output::decode(&mut TrailingZeroInput::new(subject)).unwrap_or_default(), - T::default(), - ) - } -} diff --git a/core/src/constants.rs b/core/src/constants.rs index 65ebb46a..99b764a7 100644 --- a/core/src/constants.rs +++ b/core/src/constants.rs @@ -14,7 +14,6 @@ pub const BLOCK_CHUNK_SIZE: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(32) /// Money matters. pub mod currency { - pub type Balance = u128; /// `AVAIL` has 18 decimal positions. diff --git a/core/src/da_block.rs b/core/src/da_block.rs deleted file mode 100644 index a2bf24d9..00000000 --- a/core/src/da_block.rs +++ /dev/null @@ -1,154 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Generic implementation of a DA block and associated items. - -#[cfg(feature = "std")] -use std::fmt; - -use crate::traits::{ExtendedBlock, ExtendedHeader}; -use codec::{Codec, Decode, DecodeWithMemTracking, Encode}; -use sp_runtime::{ - traits::{ - self, Block as BlockT, Header as HeaderT, MaybeSerializeDeserialize, Member, NumberFor, - }, - Justifications, -}; -use sp_std::prelude::*; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -#[cfg(feature = "runtime")] -use sp_debug_derive::RuntimeDebug; - -/// Something to identify a block. -#[derive(PartialEq, Eq, Clone, Encode, Decode)] -#[cfg_attr(feature = "runtime", derive(RuntimeDebug))] -pub enum BlockId { - /// Identify by block header hash. - Hash(Block::Hash), - /// Identify by block number. - Number(NumberFor), -} - -impl BlockId { - /// Create a block ID from a hash. - pub const fn hash(hash: Block::Hash) -> Self { - BlockId::Hash(hash) - } - - /// Create a block ID from a number. - pub const fn number(number: NumberFor) -> Self { - BlockId::Number(number) - } - - /// Check if this block ID refers to the pre-genesis state. - pub fn is_pre_genesis(&self) -> bool { - match self { - BlockId::Hash(hash) => hash == &Default::default(), - BlockId::Number(_) => false, - } - } - - /// Create a block ID for a pre-genesis state. - pub fn pre_genesis() -> Self { - BlockId::Hash(Default::default()) - } -} - -impl Copy for BlockId {} - -#[cfg(feature = "std")] -impl fmt::Display for BlockId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -/// Abstraction over a substrate block. -#[derive( - PartialEq, Eq, Clone, Encode, Decode, DecodeWithMemTracking, RuntimeDebug, scale_info::TypeInfo, -)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] -#[cfg_attr(feature = "serde", serde(deny_unknown_fields))] -pub struct DaBlock -where - Header: Codec, - Extrinsic: Codec, -{ - /// The block header. - pub header: Header, - /// The accompanying extrinsics. - pub extrinsics: Vec, -} - -impl traits::HeaderProvider for DaBlock -where - Header: Codec + HeaderT, - Extrinsic: Codec, -{ - type HeaderT = Header; -} - -impl BlockT for DaBlock -where - Header: Codec + HeaderT + MaybeSerializeDeserialize, - Extrinsic: - Member + Codec + DecodeWithMemTracking + MaybeSerializeDeserialize + traits::ExtrinsicLike, -{ - type Extrinsic = Extrinsic; - type Header = Header; - type Hash = ::Hash; - - fn header(&self) -> &Self::Header { - &self.header - } - fn extrinsics(&self) -> &[Self::Extrinsic] { - &self.extrinsics[..] - } - fn deconstruct(self) -> (Self::Header, Vec) { - (self.header, self.extrinsics) - } - fn new(header: Self::Header, extrinsics: Vec) -> Self { - DaBlock { header, extrinsics } - } - fn encode_from(header: &Self::Header, extrinsics: &[Self::Extrinsic]) -> Vec { - (header, extrinsics).encode() - } -} - -impl ExtendedBlock for DaBlock -where - Header: Codec + ExtendedHeader + MaybeSerializeDeserialize, - Extrinsic: - Member + Codec + DecodeWithMemTracking + traits::ExtrinsicLike + MaybeSerializeDeserialize, -{ - type ExtHeader = Header; -} - -/// Abstraction over a substrate block and justification. -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] -#[cfg_attr(feature = "serde", serde(deny_unknown_fields))] -pub struct SignedBlock { - /// Full block. - pub block: Block, - /// Block justification. - pub justifications: Option, -} diff --git a/core/src/data_proof.rs b/core/src/data_proof/mod.rs similarity index 99% rename from core/src/data_proof.rs rename to core/src/data_proof/mod.rs index db5e6e12..2197edb0 100644 --- a/core/src/data_proof.rs +++ b/core/src/data_proof/mod.rs @@ -1,3 +1,5 @@ +pub mod message; + use bounded_collections::BoundedVec; use bounded_collections::ConstU32; use codec::{Decode, Encode}; @@ -17,8 +19,6 @@ pub const BOUNDED_DATA_MAX_LENGTH: u32 = 102_400; /// Maximum size of data allowed in the bridge pub type BoundedData = BoundedVec>; -pub mod message; - pub use message::{AddressedMessage, Message, MessageType}; /// Unique Tx identifier based on its block number and index. @@ -67,7 +67,6 @@ pub struct TxDataRoots { pub bridge_root: H256, } -#[cfg(feature = "runtime")] impl TxDataRoots { pub fn new(submitted: H256, bridged: H256) -> Self { use crate::from_substrate::keccak_256; diff --git a/core/src/header/mod.rs b/core/src/header/mod.rs index ae19bea0..95b2d5f0 100644 --- a/core/src/header/mod.rs +++ b/core/src/header/mod.rs @@ -1,512 +1,14 @@ -// This file is part of Substrate. - -// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: Apache-2.0 - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -//! Data-Avail implementation of a block header. - -use crate::from_substrate::HexDisplay; -use crate::traits::ExtendedHeader; -use codec::{Decode, DecodeWithMemTracking, Encode}; -use primitive_types::U256; -use sp_std::{ - convert::TryFrom, - fmt::{Debug, Formatter}, -}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; #[cfg(feature = "runtime")] -use { - scale_info::TypeInfo, - sp_runtime::{ - traits::{BlockNumber, Hash as HashT, Header as HeaderT}, - Digest, - }, -}; - -#[cfg(feature = "std")] -const LOG_TARGET: &str = "header"; - pub mod extension; +#[cfg(feature = "runtime")] +pub mod runtime; +#[cfg(feature = "runtime")] pub use extension::HeaderExtension; +#[cfg(feature = "runtime")] +pub use runtime::ExtendedHeader; -/// Abstraction over a block header for a substrate chain. -#[derive(PartialEq, Eq, Clone, TypeInfo, Encode, Decode, DecodeWithMemTracking)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr( - feature = "serde", - serde(deny_unknown_fields, rename_all = "camelCase") -)] -pub struct Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, -{ - /// The parent hash. - pub parent_hash: H::Output, - /// The block number. - #[cfg_attr(feature = "serde", serde(with = "number_serde"))] - #[codec(compact)] - pub number: N, - /// The state trie merkle root - pub state_root: H::Output, - /// The merkle root of the extrinsics. - pub extrinsics_root: H::Output, - /// A chain-specific digest of data useful for light clients or referencing auxiliary data. - pub digest: Digest, - /// Data Availability header extension. - pub extension: HeaderExtension, -} - -impl Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, -{ - /// Creates a header V1 - #[inline] - pub fn new( - number: N, - extrinsics_root: H::Output, - state_root: H::Output, - parent_hash: H::Output, - digest: Digest, - extension: HeaderExtension, - ) -> Self { - Self { - parent_hash, - number, - state_root, - extrinsics_root, - digest, - extension, - } - } - - /// Convenience helper for computing the hash of the header without having - /// to import the trait. - #[inline] - pub fn hash(&self) -> H::Output { - H::hash_of(self) - } -} - -impl Debug for Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, -{ - fn fmt(&self, f: &mut Formatter<'_>) -> sp_std::fmt::Result { - let parent_hash = self.parent_hash.as_ref(); - let state_root = self.state_root.as_ref(); - let extrinsics_root = self.extrinsics_root.as_ref(); - - f.debug_struct("Header") - .field("parent_hash", &HexDisplay(parent_hash)) - .field("number", &self.number) - .field("state_root", &HexDisplay(state_root)) - .field("extrinsics_root", &HexDisplay(extrinsics_root)) - .field("digest", &self.digest) - .field("extension", &self.extension) - .finish() - } -} - -/// This module adds serialization support to `Header::number` field. -#[cfg(feature = "serde")] -mod number_serde { - use serde::{de::Error, Deserializer, Serializer}; - - use super::*; - - pub fn serialize(n: &N, serializer: S) -> Result - where - N: BlockNumber, - S: Serializer, - { - let u256: U256 = (*n).into(); - serde::Serialize::serialize(&u256, serializer) - } - - pub fn deserialize<'de, D, T>(d: D) -> Result - where - T: BlockNumber, - D: Deserializer<'de>, - { - let u256: U256 = serde::Deserialize::deserialize(d)?; - TryFrom::try_from(u256).map_err(|_| Error::custom("Try from failed")) - } -} - -impl Default for Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, -{ - fn default() -> Self { - Self { - parent_hash: Default::default(), - number: Default::default(), - state_root: Default::default(), - extrinsics_root: Default::default(), - digest: Default::default(), - extension: Default::default(), - } - } -} - -impl HeaderT for Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, - Header: TypeInfo, -{ - type Hash = H::Output; - type Hashing = H; - type Number = N; - - fn number(&self) -> &Self::Number { - &self.number - } - - fn set_number(&mut self, num: Self::Number) { - self.number = num - } - - fn extrinsics_root(&self) -> &Self::Hash { - &self.extrinsics_root - } - - fn set_extrinsics_root(&mut self, root: Self::Hash) { - self.extrinsics_root = root - } - - fn state_root(&self) -> &Self::Hash { - &self.state_root - } - - fn set_state_root(&mut self, root: Self::Hash) { - self.state_root = root - } - - fn parent_hash(&self) -> &Self::Hash { - &self.parent_hash - } - - fn set_parent_hash(&mut self, hash: Self::Hash) { - self.parent_hash = hash - } - - fn digest(&self) -> &Digest { - &self.digest - } - - fn digest_mut(&mut self) -> &mut Digest { - #[cfg(feature = "std")] - log::debug!(target: LOG_TARGET, "Retrieving mutable reference to digest"); - &mut self.digest - } - - fn new( - number: Self::Number, - extrinsics_root: Self::Hash, - state_root: Self::Hash, - parent_hash: Self::Hash, - digest: Digest, - ) -> Self { - Self { - number, - parent_hash, - state_root, - digest, - extrinsics_root, - extension: Default::default(), - } - } -} - -impl ExtendedHeader for Header -where - N: BlockNumber, - H: HashT, - H::Output: TypeInfo, - Header: HeaderT, -{ - type Extension = HeaderExtension; - - /// Creates new header. - fn new( - n: Self::Number, - extrinsics: H::Output, - state: H::Output, - parent: H::Output, - digest: Digest, - extension: HeaderExtension, - ) -> Self { - Header::::new(n, extrinsics, state, parent, digest, extension) - } - - fn extension(&self) -> &HeaderExtension { - &self.extension - } - - fn set_extension(&mut self, extension: HeaderExtension) { - self.extension = extension; - } +#[derive(Debug, Clone, Copy, Eq, PartialEq, codec::Encode, codec::Decode, scale_info::TypeInfo)] +pub enum HeaderVersion { + V3 = 2, // Current one + V4 = 3, // Next version } - -// #[cfg(all(test, feature = "runtime"))] -// mod tests { -// use codec::Error; -// use hex_literal::hex; -// use primitive_types::H256; -// use sp_runtime::{traits::BlakeTwo256, DigestItem}; -// use test_case::test_case; - -// use super::*; -// use crate::{kate_commitment::v3, AppId, V3DataLookup::DataLookup}; - -// type THeader = Header; - -// #[test] -// fn should_serialize_numbers() { -// fn serialize(num: u128) -> String { -// let mut v = vec![]; -// { -// let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v)); -// number_serde::serialize(&num, &mut ser).unwrap(); -// } -// String::from_utf8(v).unwrap() -// } - -// assert_eq!(serialize(0), "\"0x0\"".to_owned()); -// assert_eq!(serialize(1), "\"0x1\"".to_owned()); -// assert_eq!( -// serialize(u64::max_value() as u128), -// "\"0xffffffffffffffff\"".to_owned() -// ); -// 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)); -// number_serde::deserialize(&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 -// ); -// } - -// /// The `commitment.data_root is none`. -// fn header_v3() -> THeader { -// let commitment = v3::KateCommitment { -// commitment: hex!("80e949ebdaf5c13e09649c587c6b1905fb770b4a6843abaac6b413e3a7405d9825ac764db2341db9b7965965073e975980e949ebdaf5c13e09649c587c6b1905fb770b4a6843abaac6b413e3a7405d9825ac764db2341db9b7965965073e9759").to_vec(), -// ..Default::default() -// }; -// let extension = extension::v3::HeaderExtension { -// commitment, -// ..Default::default() -// }; - -// THeader { -// extension: extension.into(), -// ..Default::default() -// } -// } - -// /// It creates a corrupted V3 header and the associated error on decodification. -// fn corrupted_header() -> (Vec, Error) { -// let mut encoded = header_v3().encode(); -// encoded.remove(110); - -// let error = THeader::decode(&mut encoded.as_slice()).unwrap_err(); - -// (encoded, error) -// } - -// #[test_case( header_v3().encode().as_ref() => Ok(header_v3()) ; "Decode V3 header")] -// #[test_case( corrupted_header().0.as_ref() => Err(corrupted_header().1) ; "Decode corrupted header")] -// fn header_decoding(mut encoded_header: &[u8]) -> Result { -// Header::decode(&mut encoded_header) -// } - -// fn header_serde_encode(header: Header) -> String -// where -// H::Output: TypeInfo, -// { -// serde_json::to_string(&header).unwrap_or_default() -// } - -// #[test_case(header_serde_encode(header_v3()) => Ok(header_v3()) ; "Serde V3 header")] -// fn header_serde(json_header: String) -> Result { -// serde_json::from_str(&json_header).map_err(|serde_err| format!("{}", serde_err)) -// } - -// fn header() -> (THeader, H256) { -// let commitment = v3::KateCommitment { -// rows:1, -// cols:4, -// data_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(), -// commitment: hex!("ace5bc6a21eef8b28987eb878e0b97b5ae3c8b8e05efe957802dc0008b23327b349f62ec96bcee48bdc30f6bb670f3d1ace5bc6a21eef8b28987eb878e0b97b5ae3c8b8e05efe957802dc0008b23327b349f62ec96bcee48bdc30f6bb670f3d1").into() -// }; -// let extension = extension::v3::HeaderExtension { -// commitment, -// app_lookup: DataLookup::from_id_and_len_iter([(AppId(0), 1)].into_iter()) -// .expect("Valid DataLookup .qed"), -// }; -// let digest = Digest { -// logs: vec![ -// DigestItem::PreRuntime( -// hex!("42414245").into(), -// hex!("0201000000aa23040500000000").into()), -// DigestItem::Seal( -// hex!("42414245").into(), -// hex!("82a0c0a19f4548adcd575cdc37555b3aeaaae4048a6d39013b98f412420977752459afdc5295d026a4d3476d4d8d3d5e55c3c109235350d9242b4e3132db7e88").into(), -// ), -// ] -// }; - -// let header = THeader { -// parent_hash: hex!("84a90eef1c4a75c3cbfdf5095450725f924f1a2696946f6d9cf8401f6db99128") -// .into(), -// number: 368726, -// state_root: hex!("586140044543d7bb7471781322bcc2d7e4290716fbac7267e001843162f151d8") -// .into(), -// extrinsics_root: hex!( -// "9ea39eed403afde19c6688785530654a601bb62f0c178c78563933e303e001b6" -// ) -// .into(), -// extension: extension.into(), -// digest, -// }; -// let hash = header.hash(); - -// // Check `hash` is what we have in the testnet. -// assert_eq!( -// hash, -// H256(hex!( -// "c9941af1cb862db9f2e4c0c94f457d1217b363ecf6e6cc0dbeb5cbfeb35fbc12" -// )) -// ); - -// (header, hash) -// } - -// fn corrupted_kate_commitment(header_and_hash: (THeader, H256)) -> (THeader, H256) { -// let (mut header, hash) = header_and_hash; - -// match header.extension { -// extension::HeaderExtension::V3(ref mut ext) => { -// ext.commitment.commitment = b"invalid commitment v3".to_vec(); -// }, -// extension::HeaderExtension::V4(ref mut ext) => { -// ext.commitment.commitment = b"invalid commitment v4".to_vec(); -// }, -// }; - -// (header, hash) -// } - -// fn corrupted_kate_data_root(header_and_hash: (THeader, H256)) -> (THeader, H256) { -// let (mut header, hash) = header_and_hash; - -// match header.extension { -// extension::HeaderExtension::V3(ref mut ext) => { -// ext.commitment.data_root = H256::repeat_byte(2u8); -// }, -// extension::HeaderExtension::V4(ref mut ext) => { -// ext.commitment.data_root = H256::repeat_byte(2u8); -// }, -// }; - -// (header, hash) -// } - -// fn corrupted_kate_cols(header_and_hash: (THeader, H256)) -> (THeader, H256) { -// let (mut header, hash) = header_and_hash; - -// match header.extension { -// extension::HeaderExtension::V3(ref mut ext) => { -// ext.commitment.cols += 2; -// }, -// extension::HeaderExtension::V4(ref mut ext) => { -// ext.commitment.cols += 2; -// }, -// }; - -// (header, hash) -// } - -// fn corrupted_kate_rows(header_and_hash: (THeader, H256)) -> (THeader, H256) { -// let (mut header, hash) = header_and_hash; - -// match header.extension { -// extension::HeaderExtension::V3(ref mut ext) => { -// ext.commitment.rows += 2; -// }, -// extension::HeaderExtension::V4(ref mut ext) => { -// ext.commitment.rows += 2; -// }, -// }; - -// (header, hash) -// } - -// fn corrupted_number(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { -// header_and_hash.0.number += 1; -// header_and_hash -// } - -// fn corrupted_state_root(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { -// header_and_hash.0.state_root.0[0] ^= 0xFFu8; -// header_and_hash -// } -// fn corrupted_parent(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { -// header_and_hash.0.parent_hash.0[0] ^= 0xFFu8; -// header_and_hash -// } - -// #[test_case( header() => true ; "Valid header hash")] -// #[test_case( corrupted_kate_commitment(header()) => false; "Corrupted commitment in kate")] -// #[test_case( corrupted_kate_data_root(header()) => false; "Corrupted data root in kate")] -// #[test_case( corrupted_kate_cols(header()) => false; "Corrupted cols in kate")] -// #[test_case( corrupted_kate_rows(header()) => false; "Corrupted rows in kate")] -// #[test_case( corrupted_number(header()) => false )] -// #[test_case( corrupted_state_root(header()) => false )] -// #[test_case( corrupted_parent(header()) => false )] -// fn header_corruption(header_and_hash: (THeader, H256)) -> bool { -// let (header, hash) = header_and_hash; -// header.hash() == hash -// } -// } diff --git a/core/src/header/runtime.rs b/core/src/header/runtime.rs new file mode 100644 index 00000000..3c7364a3 --- /dev/null +++ b/core/src/header/runtime.rs @@ -0,0 +1,522 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2022 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Data-Avail implementation of a block header. + +pub use super::extension::HeaderExtension; +use crate::from_substrate::HexDisplay; +use codec::Codec; +use codec::{Decode, DecodeWithMemTracking, Encode}; +use primitive_types::U256; +use scale_info::TypeInfo; +use sp_runtime::traits::{BlockNumber, Hash as HashT, Header as HeaderT}; +use sp_runtime::{generic::Digest, traits::MaybeSerialize}; +use sp_std::fmt::Debug; +use sp_std::{convert::TryFrom, fmt::Formatter}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "std")] +const LOG_TARGET: &str = "header"; + +/// Extended header access +pub trait ExtendedHeader: sp_runtime::traits::Header { + type Extension: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + TypeInfo + 'static; + + /// Creates new header. + fn new( + number: Self::Number, + extrinsics_root: Self::Hash, + state_root: Self::Hash, + parent_hash: Self::Hash, + digest: Digest, + extension: Self::Extension, + ) -> Self; + + fn extension(&self) -> &Self::Extension; + + fn set_extension(&mut self, extension: Self::Extension); +} + +/// Abstraction over a block header for a substrate chain. +#[derive(PartialEq, Eq, Clone, TypeInfo, Encode, Decode, DecodeWithMemTracking)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "serde", + serde(deny_unknown_fields, rename_all = "camelCase") +)] +pub struct Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, +{ + /// The parent hash. + pub parent_hash: H::Output, + /// The block number. + #[cfg_attr(feature = "serde", serde(with = "number_serde"))] + #[codec(compact)] + pub number: N, + /// The state trie merkle root + pub state_root: H::Output, + /// The merkle root of the extrinsics. + pub extrinsics_root: H::Output, + /// A chain-specific digest of data useful for light clients or referencing auxiliary data. + pub digest: Digest, + /// Data Availability header extension. + pub extension: HeaderExtension, +} + +impl Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, +{ + /// Creates a header V1 + #[inline] + pub fn new( + number: N, + extrinsics_root: H::Output, + state_root: H::Output, + parent_hash: H::Output, + digest: Digest, + extension: HeaderExtension, + ) -> Self { + Self { + parent_hash, + number, + state_root, + extrinsics_root, + digest, + extension, + } + } + + /// Convenience helper for computing the hash of the header without having + /// to import the trait. + #[inline] + pub fn hash(&self) -> H::Output { + H::hash_of(self) + } +} + +impl Debug for Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> sp_std::fmt::Result { + let parent_hash = self.parent_hash.as_ref(); + let state_root = self.state_root.as_ref(); + let extrinsics_root = self.extrinsics_root.as_ref(); + + f.debug_struct("Header") + .field("parent_hash", &HexDisplay(parent_hash)) + .field("number", &self.number) + .field("state_root", &HexDisplay(state_root)) + .field("extrinsics_root", &HexDisplay(extrinsics_root)) + .field("digest", &self.digest) + .field("extension", &self.extension) + .finish() + } +} + +/// This module adds serialization support to `Header::number` field. +#[cfg(feature = "serde")] +mod number_serde { + use serde::{de::Error, Deserializer, Serializer}; + + use super::*; + + pub fn serialize(n: &N, serializer: S) -> Result + where + N: BlockNumber, + S: Serializer, + { + let u256: U256 = (*n).into(); + serde::Serialize::serialize(&u256, serializer) + } + + pub fn deserialize<'de, D, T>(d: D) -> Result + where + T: BlockNumber, + D: Deserializer<'de>, + { + let u256: U256 = serde::Deserialize::deserialize(d)?; + TryFrom::try_from(u256).map_err(|_| Error::custom("Try from failed")) + } +} + +impl Default for Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, +{ + fn default() -> Self { + Self { + parent_hash: Default::default(), + number: Default::default(), + state_root: Default::default(), + extrinsics_root: Default::default(), + digest: Default::default(), + extension: Default::default(), + } + } +} + +impl HeaderT for Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, + Header: TypeInfo, +{ + type Hash = H::Output; + type Hashing = H; + type Number = N; + + fn number(&self) -> &Self::Number { + &self.number + } + + fn set_number(&mut self, num: Self::Number) { + self.number = num + } + + fn extrinsics_root(&self) -> &Self::Hash { + &self.extrinsics_root + } + + fn set_extrinsics_root(&mut self, root: Self::Hash) { + self.extrinsics_root = root + } + + fn state_root(&self) -> &Self::Hash { + &self.state_root + } + + fn set_state_root(&mut self, root: Self::Hash) { + self.state_root = root + } + + fn parent_hash(&self) -> &Self::Hash { + &self.parent_hash + } + + fn set_parent_hash(&mut self, hash: Self::Hash) { + self.parent_hash = hash + } + + fn digest(&self) -> &Digest { + &self.digest + } + + fn digest_mut(&mut self) -> &mut Digest { + #[cfg(feature = "std")] + log::debug!(target: LOG_TARGET, "Retrieving mutable reference to digest"); + &mut self.digest + } + + fn new( + number: Self::Number, + extrinsics_root: Self::Hash, + state_root: Self::Hash, + parent_hash: Self::Hash, + digest: Digest, + ) -> Self { + Self { + number, + parent_hash, + state_root, + digest, + extrinsics_root, + extension: Default::default(), + } + } +} + +impl ExtendedHeader for Header +where + N: BlockNumber, + H: HashT, + H::Output: TypeInfo, + Header: HeaderT, +{ + type Extension = HeaderExtension; + + /// Creates new header. + fn new( + n: Self::Number, + extrinsics: H::Output, + state: H::Output, + parent: H::Output, + digest: Digest, + extension: HeaderExtension, + ) -> Self { + Header::::new(n, extrinsics, state, parent, digest, extension) + } + + fn extension(&self) -> &HeaderExtension { + &self.extension + } + + fn set_extension(&mut self, extension: HeaderExtension) { + self.extension = extension; + } +} + +// #[cfg(all(test, feature = "runtime"))] +// mod tests { +// use codec::Error; +// use hex_literal::hex; +// use primitive_types::H256; +// use sp_runtime::{traits::BlakeTwo256, DigestItem}; +// use test_case::test_case; + +// use super::*; +// use crate::{kate_commitment::v3, AppId, V3DataLookup::DataLookup}; + +// type THeader = Header; + +// #[test] +// fn should_serialize_numbers() { +// fn serialize(num: u128) -> String { +// let mut v = vec![]; +// { +// let mut ser = serde_json::Serializer::new(std::io::Cursor::new(&mut v)); +// number_serde::serialize(&num, &mut ser).unwrap(); +// } +// String::from_utf8(v).unwrap() +// } + +// assert_eq!(serialize(0), "\"0x0\"".to_owned()); +// assert_eq!(serialize(1), "\"0x1\"".to_owned()); +// assert_eq!( +// serialize(u64::max_value() as u128), +// "\"0xffffffffffffffff\"".to_owned() +// ); +// 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)); +// number_serde::deserialize(&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 +// ); +// } + +// /// The `commitment.data_root is none`. +// fn header_v3() -> THeader { +// let commitment = v3::KateCommitment { +// commitment: hex!("80e949ebdaf5c13e09649c587c6b1905fb770b4a6843abaac6b413e3a7405d9825ac764db2341db9b7965965073e975980e949ebdaf5c13e09649c587c6b1905fb770b4a6843abaac6b413e3a7405d9825ac764db2341db9b7965965073e9759").to_vec(), +// ..Default::default() +// }; +// let extension = extension::v3::HeaderExtension { +// commitment, +// ..Default::default() +// }; + +// THeader { +// extension: extension.into(), +// ..Default::default() +// } +// } + +// /// It creates a corrupted V3 header and the associated error on decodification. +// fn corrupted_header() -> (Vec, Error) { +// let mut encoded = header_v3().encode(); +// encoded.remove(110); + +// let error = THeader::decode(&mut encoded.as_slice()).unwrap_err(); + +// (encoded, error) +// } + +// #[test_case( header_v3().encode().as_ref() => Ok(header_v3()) ; "Decode V3 header")] +// #[test_case( corrupted_header().0.as_ref() => Err(corrupted_header().1) ; "Decode corrupted header")] +// fn header_decoding(mut encoded_header: &[u8]) -> Result { +// Header::decode(&mut encoded_header) +// } + +// fn header_serde_encode(header: Header) -> String +// where +// H::Output: TypeInfo, +// { +// serde_json::to_string(&header).unwrap_or_default() +// } + +// #[test_case(header_serde_encode(header_v3()) => Ok(header_v3()) ; "Serde V3 header")] +// fn header_serde(json_header: String) -> Result { +// serde_json::from_str(&json_header).map_err(|serde_err| format!("{}", serde_err)) +// } + +// fn header() -> (THeader, H256) { +// let commitment = v3::KateCommitment { +// rows:1, +// cols:4, +// data_root: hex!("0000000000000000000000000000000000000000000000000000000000000000").into(), +// commitment: hex!("ace5bc6a21eef8b28987eb878e0b97b5ae3c8b8e05efe957802dc0008b23327b349f62ec96bcee48bdc30f6bb670f3d1ace5bc6a21eef8b28987eb878e0b97b5ae3c8b8e05efe957802dc0008b23327b349f62ec96bcee48bdc30f6bb670f3d1").into() +// }; +// let extension = extension::v3::HeaderExtension { +// commitment, +// app_lookup: DataLookup::from_id_and_len_iter([(AppId(0), 1)].into_iter()) +// .expect("Valid DataLookup .qed"), +// }; +// let digest = Digest { +// logs: vec![ +// DigestItem::PreRuntime( +// hex!("42414245").into(), +// hex!("0201000000aa23040500000000").into()), +// DigestItem::Seal( +// hex!("42414245").into(), +// hex!("82a0c0a19f4548adcd575cdc37555b3aeaaae4048a6d39013b98f412420977752459afdc5295d026a4d3476d4d8d3d5e55c3c109235350d9242b4e3132db7e88").into(), +// ), +// ] +// }; + +// let header = THeader { +// parent_hash: hex!("84a90eef1c4a75c3cbfdf5095450725f924f1a2696946f6d9cf8401f6db99128") +// .into(), +// number: 368726, +// state_root: hex!("586140044543d7bb7471781322bcc2d7e4290716fbac7267e001843162f151d8") +// .into(), +// extrinsics_root: hex!( +// "9ea39eed403afde19c6688785530654a601bb62f0c178c78563933e303e001b6" +// ) +// .into(), +// extension: extension.into(), +// digest, +// }; +// let hash = header.hash(); + +// // Check `hash` is what we have in the testnet. +// assert_eq!( +// hash, +// H256(hex!( +// "c9941af1cb862db9f2e4c0c94f457d1217b363ecf6e6cc0dbeb5cbfeb35fbc12" +// )) +// ); + +// (header, hash) +// } + +// fn corrupted_kate_commitment(header_and_hash: (THeader, H256)) -> (THeader, H256) { +// let (mut header, hash) = header_and_hash; + +// match header.extension { +// extension::HeaderExtension::V3(ref mut ext) => { +// ext.commitment.commitment = b"invalid commitment v3".to_vec(); +// }, +// extension::HeaderExtension::V4(ref mut ext) => { +// ext.commitment.commitment = b"invalid commitment v4".to_vec(); +// }, +// }; + +// (header, hash) +// } + +// fn corrupted_kate_data_root(header_and_hash: (THeader, H256)) -> (THeader, H256) { +// let (mut header, hash) = header_and_hash; + +// match header.extension { +// extension::HeaderExtension::V3(ref mut ext) => { +// ext.commitment.data_root = H256::repeat_byte(2u8); +// }, +// extension::HeaderExtension::V4(ref mut ext) => { +// ext.commitment.data_root = H256::repeat_byte(2u8); +// }, +// }; + +// (header, hash) +// } + +// fn corrupted_kate_cols(header_and_hash: (THeader, H256)) -> (THeader, H256) { +// let (mut header, hash) = header_and_hash; + +// match header.extension { +// extension::HeaderExtension::V3(ref mut ext) => { +// ext.commitment.cols += 2; +// }, +// extension::HeaderExtension::V4(ref mut ext) => { +// ext.commitment.cols += 2; +// }, +// }; + +// (header, hash) +// } + +// fn corrupted_kate_rows(header_and_hash: (THeader, H256)) -> (THeader, H256) { +// let (mut header, hash) = header_and_hash; + +// match header.extension { +// extension::HeaderExtension::V3(ref mut ext) => { +// ext.commitment.rows += 2; +// }, +// extension::HeaderExtension::V4(ref mut ext) => { +// ext.commitment.rows += 2; +// }, +// }; + +// (header, hash) +// } + +// fn corrupted_number(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { +// header_and_hash.0.number += 1; +// header_and_hash +// } + +// fn corrupted_state_root(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { +// header_and_hash.0.state_root.0[0] ^= 0xFFu8; +// header_and_hash +// } +// fn corrupted_parent(mut header_and_hash: (THeader, H256)) -> (THeader, H256) { +// header_and_hash.0.parent_hash.0[0] ^= 0xFFu8; +// header_and_hash +// } + +// #[test_case( header() => true ; "Valid header hash")] +// #[test_case( corrupted_kate_commitment(header()) => false; "Corrupted commitment in kate")] +// #[test_case( corrupted_kate_data_root(header()) => false; "Corrupted data root in kate")] +// #[test_case( corrupted_kate_cols(header()) => false; "Corrupted cols in kate")] +// #[test_case( corrupted_kate_rows(header()) => false; "Corrupted rows in kate")] +// #[test_case( corrupted_number(header()) => false )] +// #[test_case( corrupted_state_root(header()) => false )] +// #[test_case( corrupted_parent(header()) => false )] +// fn header_corruption(header_and_hash: (THeader, H256)) -> bool { +// let (header, hash) = header_and_hash; +// header.hash() == hash +// } +// } diff --git a/core/src/header_version/mod.rs b/core/src/header_version/mod.rs deleted file mode 100644 index 6eefeb8f..00000000 --- a/core/src/header_version/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -use codec::{Decode, Encode}; -use scale_info::TypeInfo; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode, TypeInfo)] -pub enum HeaderVersion { - V3 = 2, // Current one - V4 = 3, // Next version -} diff --git a/core/src/lib.rs b/core/src/lib.rs index 9db40246..e73342c8 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -8,33 +8,19 @@ use derive_more::{Add, Constructor, Deref, Into, Mul}; use num_traits::Zero; use scale_info::TypeInfo; -#[cfg(feature = "runtime")] -use sp_debug_derive::RuntimeDebug; - #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; pub mod from_substrate; -/// DA Block -#[cfg(feature = "runtime")] -pub mod da_block; -#[cfg(feature = "runtime")] -pub use da_block::*; - /// Customized headers. -#[cfg(feature = "runtime")] pub mod header; +pub use header::HeaderVersion; /// Kate Commitment on Headers. pub mod kate_commitment; pub use kate_commitment::*; -pub mod sha2; -pub use sha2::ShaTwo256; - -pub mod traits; - pub mod keccak256; pub use keccak256::Keccak256; @@ -51,14 +37,8 @@ pub use data_lookup::{v3_compact, v4_compact}; pub mod constants; pub use constants::*; -pub mod header_version; -pub use header_version::HeaderVersion; - pub mod const_generic_asserts; -#[cfg(feature = "runtime")] -pub mod bench_randomness; - #[repr(u8)] pub enum InvalidTransactionCustomId { /// The AppId is not registered. @@ -91,7 +71,7 @@ pub enum InvalidTransactionCustomId { MaxEncodedLen, )] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "runtime", derive(RuntimeDebug))] +#[cfg_attr(feature = "runtime", derive(sp_debug_derive::RuntimeDebug))] #[cfg_attr(not(feature = "runtime"), derive(Debug))] pub struct AppId(#[codec(compact)] pub u32); diff --git a/core/src/sha2.rs b/core/src/sha2.rs deleted file mode 100644 index aa84b3aa..00000000 --- a/core/src/sha2.rs +++ /dev/null @@ -1,54 +0,0 @@ -use hash_db::Hasher; -use scale_info::TypeInfo; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "runtime")] -use sp_debug_derive::RuntimeDebug; - -/// Sha2 256 wrapper which supports `binary-merkle-tree::Hasher`. -#[derive(PartialEq, Eq, Clone, TypeInfo)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "runtime", derive(RuntimeDebug))] -pub struct ShaTwo256 {} - -impl Hasher for ShaTwo256 { - type Out = primitive_types::H256; - type StdHasher = hash256_std_hasher::Hash256StdHasher; - const LENGTH: usize = 32; - - fn hash(s: &[u8]) -> Self::Out { - let sha2_out = crate::from_substrate::keccak_256(s); - sha2_out.into() - } -} - -#[cfg(feature = "runtime")] -pub mod hash { - use super::*; - use sp_std::vec::Vec; - use sp_storage::StateVersion; - use sp_trie::{LayoutV0, LayoutV1, TrieConfiguration as _}; - - impl sp_runtime::traits::Hash for ShaTwo256 { - type Output = primitive_types::H256; - - fn trie_root(input: Vec<(Vec, Vec)>, version: StateVersion) -> Self::Output { - match version { - StateVersion::V0 => LayoutV0::::trie_root(input), - StateVersion::V1 => LayoutV1::::trie_root(input), - } - } - - fn ordered_trie_root(input: Vec>, version: StateVersion) -> Self::Output { - match version { - StateVersion::V0 => LayoutV0::::ordered_trie_root(input), - StateVersion::V1 => LayoutV1::::ordered_trie_root(input), - } - } - } -} - -#[cfg(feature = "runtime")] -#[allow(unused_imports)] -pub use hash::*; diff --git a/core/src/traits.rs b/core/src/traits.rs deleted file mode 100644 index e7e55361..00000000 --- a/core/src/traits.rs +++ /dev/null @@ -1,16 +0,0 @@ -pub mod get_app_id; -pub use get_app_id::GetAppId; - -#[cfg(feature = "runtime")] -pub mod extended_header; -#[cfg(feature = "runtime")] -pub use extended_header::ExtendedHeader; - -#[cfg(feature = "runtime")] -pub mod extended_block; -#[cfg(feature = "runtime")] -pub use extended_block::ExtendedBlock; - -pub trait MaybeCaller { - fn caller(&self) -> Option<&A>; -} diff --git a/core/src/traits/extended_block.rs b/core/src/traits/extended_block.rs deleted file mode 100644 index 3a2be8bf..00000000 --- a/core/src/traits/extended_block.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::traits::ExtendedHeader; -use sp_runtime::traits::Block; - -/// Extended Block trait that extends substrate primitive Block to include ExtendedHeader in the header -pub trait ExtendedBlock: Block
{ - type ExtHeader: ExtendedHeader; -} diff --git a/core/src/traits/extended_header.rs b/core/src/traits/extended_header.rs deleted file mode 100644 index 07947ec3..00000000 --- a/core/src/traits/extended_header.rs +++ /dev/null @@ -1,26 +0,0 @@ -use codec::Codec; -use scale_info::TypeInfo; -use sp_runtime::{ - generic::Digest, - traits::{Header, MaybeSerialize}, -}; -use sp_std::fmt::Debug; - -/// Extended header access -pub trait ExtendedHeader: Header { - type Extension: Clone + Send + Sync + Codec + Eq + MaybeSerialize + Debug + TypeInfo + 'static; - - /// Creates new header. - fn new( - number: Self::Number, - extrinsics_root: Self::Hash, - state_root: Self::Hash, - parent_hash: Self::Hash, - digest: Digest, - extension: Self::Extension, - ) -> Self; - - fn extension(&self) -> &Self::Extension; - - fn set_extension(&mut self, extension: Self::Extension); -} diff --git a/core/src/traits/get_app_id.rs b/core/src/traits/get_app_id.rs deleted file mode 100644 index a7a280c1..00000000 --- a/core/src/traits/get_app_id.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::AppId; - -/// Get application Id trait -pub trait GetAppId { - fn app_id(&self) -> AppId { - AppId::default() - } -} - -impl GetAppId for (A, B, C, D, E, F, G, H) { - fn app_id(&self) -> AppId { - self.7.app_id() - } -} - -impl GetAppId for (A, B, C, D, E, F, G, H, I) { - fn app_id(&self) -> AppId { - self.8.app_id() - } -} - -impl GetAppId for (A, B, C, D, E, F, G, H, I, J) { - fn app_id(&self) -> AppId { - self.8.app_id() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::AppId; - - struct CustomAppId {} - - impl GetAppId for CustomAppId { - fn app_id(&self) -> AppId { - AppId(7) - } - } - - struct DefaultGetAppId {} - impl GetAppId for DefaultGetAppId {} - - #[test] - fn app_id_trait_on_tuples() { - let custom_app_id = (0, 1, 2, 3, 4, 5, 6, CustomAppId {}); - let default_app_id = (0, 1, 2, 3, 4, 5, 6, DefaultGetAppId {}); - - assert_eq!(custom_app_id.app_id(), AppId(7)); - assert_eq!(default_app_id.app_id(), AppId::default()); - } -}