Remove bridges subtree

This commit is contained in:
Serban Iorga
2024-04-09 16:02:09 +03:00
committed by Bastian Köcher
parent d38f6e6728
commit 9a3e2c8c5a
179 changed files with 0 additions and 34372 deletions
-414
View File
@@ -1,414 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
use crate::{ChainId, HeaderIdProvider};
use codec::{Codec, Decode, Encode, MaxEncodedLen};
use frame_support::{weights::Weight, Parameter};
use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero};
use sp_runtime::{
traits::{
AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay,
MaybeSerialize, MaybeSerializeDeserialize, Member, SimpleBitOps, Verify,
},
FixedPointOperand,
};
use sp_std::{convert::TryFrom, fmt::Debug, hash::Hash, str::FromStr, vec, vec::Vec};
/// Chain call, that is either SCALE-encoded, or decoded.
#[derive(Debug, Clone, PartialEq)]
pub enum EncodedOrDecodedCall<ChainCall> {
/// The call that is SCALE-encoded.
///
/// This variant is used when we the chain runtime is not bundled with the relay, but
/// we still need the represent call in some RPC calls or transactions.
Encoded(Vec<u8>),
/// The decoded call.
Decoded(ChainCall),
}
impl<ChainCall: Clone + Codec> EncodedOrDecodedCall<ChainCall> {
/// Returns decoded call.
pub fn to_decoded(&self) -> Result<ChainCall, codec::Error> {
match self {
Self::Encoded(ref encoded_call) =>
ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into),
Self::Decoded(ref decoded_call) => Ok(decoded_call.clone()),
}
}
/// Converts self to decoded call.
pub fn into_decoded(self) -> Result<ChainCall, codec::Error> {
match self {
Self::Encoded(encoded_call) =>
ChainCall::decode(&mut &encoded_call[..]).map_err(Into::into),
Self::Decoded(decoded_call) => Ok(decoded_call),
}
}
/// Converts self to encoded call.
pub fn into_encoded(self) -> Vec<u8> {
match self {
Self::Encoded(encoded_call) => encoded_call,
Self::Decoded(decoded_call) => decoded_call.encode(),
}
}
}
impl<ChainCall> From<ChainCall> for EncodedOrDecodedCall<ChainCall> {
fn from(call: ChainCall) -> EncodedOrDecodedCall<ChainCall> {
EncodedOrDecodedCall::Decoded(call)
}
}
impl<ChainCall: Decode> Decode for EncodedOrDecodedCall<ChainCall> {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
// having encoded version is better than decoded, because decoding isn't required
// everywhere and for mocked calls it may lead to **unneeded** errors
match input.remaining_len()? {
Some(remaining_len) => {
let mut encoded_call = vec![0u8; remaining_len];
input.read(&mut encoded_call)?;
Ok(EncodedOrDecodedCall::Encoded(encoded_call))
},
None => Ok(EncodedOrDecodedCall::Decoded(ChainCall::decode(input)?)),
}
}
}
impl<ChainCall: Encode> Encode for EncodedOrDecodedCall<ChainCall> {
fn encode(&self) -> Vec<u8> {
match *self {
Self::Encoded(ref encoded_call) => encoded_call.clone(),
Self::Decoded(ref decoded_call) => decoded_call.encode(),
}
}
}
/// Minimal Substrate-based chain representation that may be used from no_std environment.
pub trait Chain: Send + Sync + 'static {
/// Chain id.
const ID: ChainId;
/// A type that fulfills the abstract idea of what a Substrate block number is.
// Constraints come from the associated Number type of `sp_runtime::traits::Header`
// See here for more info:
// https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Number
//
// Note that the `AsPrimitive<usize>` trait is required by the GRANDPA justification
// verifier, and is not usually part of a Substrate Header's Number type.
type BlockNumber: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Hash
+ Copy
+ Default
+ MaybeDisplay
+ AtLeast32BitUnsigned
+ FromStr
+ AsPrimitive<usize>
+ Default
+ Saturating
+ MaxEncodedLen;
/// A type that fulfills the abstract idea of what a Substrate hash is.
// Constraints come from the associated Hash type of `sp_runtime::traits::Header`
// See here for more info:
// https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hash
type Hash: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Hash
+ Ord
+ Copy
+ MaybeDisplay
+ Default
+ SimpleBitOps
+ AsRef<[u8]>
+ AsMut<[u8]>
+ MaxEncodedLen;
/// A type that fulfills the abstract idea of what a Substrate hasher (a type
/// that produces hashes) is.
// Constraints come from the associated Hashing type of `sp_runtime::traits::Header`
// See here for more info:
// https://crates.parity.io/sp_runtime/traits/trait.Header.html#associatedtype.Hashing
type Hasher: HashT<Output = Self::Hash>;
/// A type that fulfills the abstract idea of what a Substrate header is.
// See here for more info:
// https://crates.parity.io/sp_runtime/traits/trait.Header.html
type Header: Parameter
+ HeaderT<Number = Self::BlockNumber, Hash = Self::Hash>
+ HeaderIdProvider<Self::Header>
+ MaybeSerializeDeserialize;
/// The user account identifier type for the runtime.
type AccountId: Parameter
+ Member
+ MaybeSerializeDeserialize
+ Debug
+ MaybeDisplay
+ Ord
+ MaxEncodedLen;
/// Balance of an account in native tokens.
///
/// The chain may support multiple tokens, but this particular type is for token that is used
/// to pay for transaction dispatch, to reward different relayers (headers, messages), etc.
type Balance: AtLeast32BitUnsigned
+ FixedPointOperand
+ Parameter
+ Member
+ MaybeSerializeDeserialize
+ Clone
+ Copy
+ Bounded
+ CheckedSub
+ PartialOrd
+ SaturatingAdd
+ Zero
+ TryFrom<sp_core::U256>
+ MaxEncodedLen;
/// Nonce of a transaction used by the chain.
type Nonce: Parameter
+ Member
+ MaybeSerialize
+ Debug
+ Default
+ MaybeDisplay
+ MaybeSerializeDeserialize
+ AtLeast32Bit
+ Copy
+ MaxEncodedLen;
/// Signature type, used on this chain.
type Signature: Parameter + Verify;
/// Get the maximum size (in bytes) of a Normal extrinsic at this chain.
fn max_extrinsic_size() -> u32;
/// Get the maximum weight (compute time) that a Normal extrinsic at this chain can use.
fn max_extrinsic_weight() -> Weight;
}
/// A trait that provides the type of the underlying chain.
pub trait UnderlyingChainProvider: Send + Sync + 'static {
/// Underlying chain type.
type Chain: Chain;
}
impl<T> Chain for T
where
T: Send + Sync + 'static + UnderlyingChainProvider,
{
const ID: ChainId = <T::Chain as Chain>::ID;
type BlockNumber = <T::Chain as Chain>::BlockNumber;
type Hash = <T::Chain as Chain>::Hash;
type Hasher = <T::Chain as Chain>::Hasher;
type Header = <T::Chain as Chain>::Header;
type AccountId = <T::Chain as Chain>::AccountId;
type Balance = <T::Chain as Chain>::Balance;
type Nonce = <T::Chain as Chain>::Nonce;
type Signature = <T::Chain as Chain>::Signature;
fn max_extrinsic_size() -> u32 {
<T::Chain as Chain>::max_extrinsic_size()
}
fn max_extrinsic_weight() -> Weight {
<T::Chain as Chain>::max_extrinsic_weight()
}
}
/// Minimal parachain representation that may be used from no_std environment.
pub trait Parachain: Chain {
/// Parachain identifier.
const PARACHAIN_ID: u32;
}
impl<T> Parachain for T
where
T: Chain + UnderlyingChainProvider,
<T as UnderlyingChainProvider>::Chain: Parachain,
{
const PARACHAIN_ID: u32 = <<T as UnderlyingChainProvider>::Chain as Parachain>::PARACHAIN_ID;
}
/// Adapter for `Get<u32>` to access `PARACHAIN_ID` from `trait Parachain`
pub struct ParachainIdOf<Para>(sp_std::marker::PhantomData<Para>);
impl<Para: Parachain> frame_support::traits::Get<u32> for ParachainIdOf<Para> {
fn get() -> u32 {
Para::PARACHAIN_ID
}
}
/// Underlying chain type.
pub type UnderlyingChainOf<C> = <C as UnderlyingChainProvider>::Chain;
/// Block number used by the chain.
pub type BlockNumberOf<C> = <C as Chain>::BlockNumber;
/// Hash type used by the chain.
pub type HashOf<C> = <C as Chain>::Hash;
/// Hasher type used by the chain.
pub type HasherOf<C> = <C as Chain>::Hasher;
/// Header type used by the chain.
pub type HeaderOf<C> = <C as Chain>::Header;
/// Account id type used by the chain.
pub type AccountIdOf<C> = <C as Chain>::AccountId;
/// Balance type used by the chain.
pub type BalanceOf<C> = <C as Chain>::Balance;
/// Transaction nonce type used by the chain.
pub type NonceOf<C> = <C as Chain>::Nonce;
/// Signature type used by the chain.
pub type SignatureOf<C> = <C as Chain>::Signature;
/// Account public type used by the chain.
pub type AccountPublicOf<C> = <SignatureOf<C> as Verify>::Signer;
/// Transaction era used by the chain.
pub type TransactionEraOf<C> = crate::TransactionEra<BlockNumberOf<C>, HashOf<C>>;
/// Convenience macro that declares bridge finality runtime apis and related constants for a chain.
/// This includes:
/// - chain-specific bridge runtime APIs:
/// - `<ThisChain>FinalityApi`
/// - constants that are stringified names of runtime API methods:
/// - `BEST_FINALIZED_<THIS_CHAIN>_HEADER_METHOD`
/// - `<THIS_CHAIN>_ACCEPTED_<CONSENSUS>_FINALITY_PROOFS_METHOD`
/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`).
#[macro_export]
macro_rules! decl_bridge_finality_runtime_apis {
($chain: ident $(, $consensus: ident => $justification_type: ty)?) => {
bp_runtime::paste::item! {
mod [<$chain _finality_api>] {
use super::*;
/// Name of the `<ThisChain>FinalityApi::best_finalized` runtime method.
pub const [<BEST_FINALIZED_ $chain:upper _HEADER_METHOD>]: &str =
stringify!([<$chain:camel FinalityApi_best_finalized>]);
$(
/// Name of the `<ThisChain>FinalityApi::accepted_<consensus>_finality_proofs`
/// runtime method.
pub const [<$chain:upper _SYNCED_HEADERS_ $consensus:upper _INFO_METHOD>]: &str =
stringify!([<$chain:camel FinalityApi_synced_headers_ $consensus:lower _info>]);
)?
sp_api::decl_runtime_apis! {
/// API for querying information about the finalized chain headers.
///
/// This API is implemented by runtimes that are receiving messages from this chain, not by this
/// chain's runtime itself.
pub trait [<$chain:camel FinalityApi>] {
/// Returns number and hash of the best finalized header known to the bridge module.
fn best_finalized() -> Option<bp_runtime::HeaderId<Hash, BlockNumber>>;
$(
/// Returns the justifications accepted in the current block.
fn [<synced_headers_ $consensus:lower _info>](
) -> sp_std::vec::Vec<$justification_type>;
)?
}
}
}
pub use [<$chain _finality_api>]::*;
}
};
($chain: ident, grandpa) => {
decl_bridge_finality_runtime_apis!($chain, grandpa => bp_header_chain::StoredHeaderGrandpaInfo<Header>);
};
}
/// Convenience macro that declares bridge messages runtime apis and related constants for a chain.
/// This includes:
/// - chain-specific bridge runtime APIs:
/// - `To<ThisChain>OutboundLaneApi`
/// - `From<ThisChain>InboundLaneApi`
/// - constants that are stringified names of runtime API methods:
/// - `FROM_<THIS_CHAIN>_MESSAGE_DETAILS_METHOD`,
/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`).
#[macro_export]
macro_rules! decl_bridge_messages_runtime_apis {
($chain: ident) => {
bp_runtime::paste::item! {
mod [<$chain _messages_api>] {
use super::*;
/// Name of the `To<ThisChain>OutboundLaneApi::message_details` runtime method.
pub const [<TO_ $chain:upper _MESSAGE_DETAILS_METHOD>]: &str =
stringify!([<To $chain:camel OutboundLaneApi_message_details>]);
/// Name of the `From<ThisChain>InboundLaneApi::message_details` runtime method.
pub const [<FROM_ $chain:upper _MESSAGE_DETAILS_METHOD>]: &str =
stringify!([<From $chain:camel InboundLaneApi_message_details>]);
sp_api::decl_runtime_apis! {
/// Outbound message lane API for messages that are sent to this chain.
///
/// This API is implemented by runtimes that are receiving messages from this chain, not by this
/// chain's runtime itself.
pub trait [<To $chain:camel OutboundLaneApi>] {
/// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all
/// messages in given inclusive range.
///
/// If some (or all) messages are missing from the storage, they'll also will
/// be missing from the resulting vector. The vector is ordered by the nonce.
fn message_details(
lane: bp_messages::LaneId,
begin: bp_messages::MessageNonce,
end: bp_messages::MessageNonce,
) -> sp_std::vec::Vec<bp_messages::OutboundMessageDetails>;
}
/// Inbound message lane API for messages sent by this chain.
///
/// This API is implemented by runtimes that are receiving messages from this chain, not by this
/// chain's runtime itself.
///
/// Entries of the resulting vector are matching entries of the `messages` vector. Entries of the
/// `messages` vector may (and need to) be read using `To<ThisChain>OutboundLaneApi::message_details`.
pub trait [<From $chain:camel InboundLaneApi>] {
/// Return details of given inbound messages.
fn message_details(
lane: bp_messages::LaneId,
messages: sp_std::vec::Vec<(bp_messages::MessagePayload, bp_messages::OutboundMessageDetails)>,
) -> sp_std::vec::Vec<bp_messages::InboundMessageDetails>;
}
}
}
pub use [<$chain _messages_api>]::*;
}
};
}
/// Convenience macro that declares bridge finality runtime apis, bridge messages runtime apis
/// and related constants for a chain.
/// The name of the chain has to be specified in snake case (e.g. `bridge_hub_polkadot`).
#[macro_export]
macro_rules! decl_bridge_runtime_apis {
($chain: ident $(, $consensus: ident)?) => {
bp_runtime::decl_bridge_finality_runtime_apis!($chain $(, $consensus)?);
bp_runtime::decl_bridge_messages_runtime_apis!($chain);
};
}
@@ -1,154 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Primitives that may be used for creating signed extensions for indirect runtimes.
use codec::{Compact, Decode, Encode};
use impl_trait_for_tuples::impl_for_tuples;
use scale_info::{StaticTypeInfo, TypeInfo};
use sp_runtime::{
traits::{DispatchInfoOf, SignedExtension},
transaction_validity::TransactionValidityError,
};
use sp_std::{fmt::Debug, marker::PhantomData};
/// Trait that describes some properties of a `SignedExtension` that are needed in order to send a
/// transaction to the chain.
pub trait SignedExtensionSchema: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo {
/// A type of the data encoded as part of the transaction.
type Payload: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo;
/// Parameters which are part of the payload used to produce transaction signature,
/// but don't end up in the transaction itself (i.e. inherent part of the runtime).
type AdditionalSigned: Encode + Debug + Eq + Clone + StaticTypeInfo;
}
impl SignedExtensionSchema for () {
type Payload = ();
type AdditionalSigned = ();
}
/// An implementation of `SignedExtensionSchema` using generic params.
#[derive(Encode, Decode, Clone, Debug, PartialEq, Eq, TypeInfo)]
pub struct GenericSignedExtensionSchema<P, S>(PhantomData<(P, S)>);
impl<P, S> SignedExtensionSchema for GenericSignedExtensionSchema<P, S>
where
P: Encode + Decode + Debug + Eq + Clone + StaticTypeInfo,
S: Encode + Debug + Eq + Clone + StaticTypeInfo,
{
type Payload = P;
type AdditionalSigned = S;
}
/// The `SignedExtensionSchema` for `frame_system::CheckNonZeroSender`.
pub type CheckNonZeroSender = GenericSignedExtensionSchema<(), ()>;
/// The `SignedExtensionSchema` for `frame_system::CheckSpecVersion`.
pub type CheckSpecVersion = GenericSignedExtensionSchema<(), u32>;
/// The `SignedExtensionSchema` for `frame_system::CheckTxVersion`.
pub type CheckTxVersion = GenericSignedExtensionSchema<(), u32>;
/// The `SignedExtensionSchema` for `frame_system::CheckGenesis`.
pub type CheckGenesis<Hash> = GenericSignedExtensionSchema<(), Hash>;
/// The `SignedExtensionSchema` for `frame_system::CheckEra`.
pub type CheckEra<Hash> = GenericSignedExtensionSchema<sp_runtime::generic::Era, Hash>;
/// The `SignedExtensionSchema` for `frame_system::CheckNonce`.
pub type CheckNonce<TxNonce> = GenericSignedExtensionSchema<Compact<TxNonce>, ()>;
/// The `SignedExtensionSchema` for `frame_system::CheckWeight`.
pub type CheckWeight = GenericSignedExtensionSchema<(), ()>;
/// The `SignedExtensionSchema` for `pallet_transaction_payment::ChargeTransactionPayment`.
pub type ChargeTransactionPayment<Balance> = GenericSignedExtensionSchema<Compact<Balance>, ()>;
/// The `SignedExtensionSchema` for `polkadot-runtime-common::PrevalidateAttests`.
pub type PrevalidateAttests = GenericSignedExtensionSchema<(), ()>;
/// The `SignedExtensionSchema` for `BridgeRejectObsoleteHeadersAndMessages`.
pub type BridgeRejectObsoleteHeadersAndMessages = GenericSignedExtensionSchema<(), ()>;
/// The `SignedExtensionSchema` for `RefundBridgedParachainMessages`.
/// This schema is dedicated for `RefundBridgedParachainMessages` signed extension as
/// wildcard/placeholder, which relies on the scale encoding for `()` or `((), ())`, or `((), (),
/// ())` is the same. So runtime can contains any kind of tuple:
/// `(BridgeRefundBridgeHubRococoMessages)`
/// `(BridgeRefundBridgeHubRococoMessages, BridgeRefundBridgeHubWestendMessages)`
/// `(BridgeRefundParachainMessages1, ..., BridgeRefundParachainMessagesN)`
pub type RefundBridgedParachainMessagesSchema = GenericSignedExtensionSchema<(), ()>;
#[impl_for_tuples(1, 12)]
impl SignedExtensionSchema for Tuple {
for_tuples!( type Payload = ( #( Tuple::Payload ),* ); );
for_tuples!( type AdditionalSigned = ( #( Tuple::AdditionalSigned ),* ); );
}
/// A simplified version of signed extensions meant for producing signed transactions
/// and signed payloads in the client code.
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)]
pub struct GenericSignedExtension<S: SignedExtensionSchema> {
/// A payload that is included in the transaction.
pub payload: S::Payload,
#[codec(skip)]
// It may be set to `None` if extensions are decoded. We are never reconstructing transactions
// (and it makes no sense to do that) => decoded version of `SignedExtensions` is only used to
// read fields of the `payload`. And when resigning transaction, we're reconstructing
// `SignedExtensions` from scratch.
additional_signed: Option<S::AdditionalSigned>,
}
impl<S: SignedExtensionSchema> GenericSignedExtension<S> {
/// Create new `GenericSignedExtension` object.
pub fn new(payload: S::Payload, additional_signed: Option<S::AdditionalSigned>) -> Self {
Self { payload, additional_signed }
}
}
impl<S> SignedExtension for GenericSignedExtension<S>
where
S: SignedExtensionSchema,
S::Payload: Send + Sync,
S::AdditionalSigned: Send + Sync,
{
const IDENTIFIER: &'static str = "Not needed.";
type AccountId = ();
type Call = ();
type AdditionalSigned = S::AdditionalSigned;
type Pre = ();
fn additional_signed(&self) -> Result<Self::AdditionalSigned, TransactionValidityError> {
// we shall not ever see this error in relay, because we are never signing decoded
// transactions. Instead we're constructing and signing new transactions. So the error code
// is kinda random here
self.additional_signed.clone().ok_or(
frame_support::unsigned::TransactionValidityError::Unknown(
frame_support::unsigned::UnknownTransaction::Custom(0xFF),
),
)
}
fn pre_dispatch(
self,
_who: &Self::AccountId,
_call: &Self::Call,
_info: &DispatchInfoOf<Self::Call>,
_len: usize,
) -> Result<Self::Pre, TransactionValidityError> {
Ok(())
}
}
-545
View File
@@ -1,545 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Primitives that may be used at (bridges) runtime level.
#![warn(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
use codec::{Decode, Encode, FullCodec, MaxEncodedLen};
use frame_support::{
pallet_prelude::DispatchResult, weights::Weight, PalletError, StorageHasher, StorageValue,
};
use frame_system::RawOrigin;
use scale_info::TypeInfo;
use serde::{Deserialize, Serialize};
use sp_core::storage::StorageKey;
use sp_runtime::{
traits::{BadOrigin, Header as HeaderT, UniqueSaturatedInto},
RuntimeDebug,
};
use sp_std::{convert::TryFrom, fmt::Debug, ops::RangeInclusive, vec, vec::Vec};
pub use chain::{
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, EncodedOrDecodedCall, HashOf,
HasherOf, HeaderOf, NonceOf, Parachain, ParachainIdOf, SignatureOf, TransactionEraOf,
UnderlyingChainOf, UnderlyingChainProvider,
};
pub use frame_support::storage::storage_prefix as storage_value_final_key;
use num_traits::{CheckedAdd, CheckedSub, One, SaturatingAdd, Zero};
pub use storage_proof::{
record_all_keys as record_all_trie_keys, Error as StorageProofError,
ProofSize as StorageProofSize, RawStorageProof, StorageProofChecker,
};
pub use storage_types::BoundedStorageValue;
#[cfg(feature = "std")]
pub use storage_proof::craft_valid_storage_proof;
pub mod extensions;
pub mod messages;
mod chain;
mod storage_proof;
mod storage_types;
// Re-export macro to avoid include paste dependency everywhere
pub use sp_runtime::paste;
/// Use this when something must be shared among all instances.
pub const NO_INSTANCE_ID: ChainId = [0, 0, 0, 0];
/// Generic header Id.
#[derive(
RuntimeDebug,
Default,
Clone,
Encode,
Decode,
Copy,
Eq,
Hash,
MaxEncodedLen,
PartialEq,
PartialOrd,
Ord,
TypeInfo,
)]
pub struct HeaderId<Hash, Number>(pub Number, pub Hash);
impl<Hash: Copy, Number: Copy> HeaderId<Hash, Number> {
/// Return header number.
pub fn number(&self) -> Number {
self.0
}
/// Return header hash.
pub fn hash(&self) -> Hash {
self.1
}
}
/// Header id used by the chain.
pub type HeaderIdOf<C> = HeaderId<HashOf<C>, BlockNumberOf<C>>;
/// Generic header id provider.
pub trait HeaderIdProvider<Header: HeaderT> {
/// Get the header id.
fn id(&self) -> HeaderId<Header::Hash, Header::Number>;
/// Get the header id for the parent block.
fn parent_id(&self) -> Option<HeaderId<Header::Hash, Header::Number>>;
}
impl<Header: HeaderT> HeaderIdProvider<Header> for Header {
fn id(&self) -> HeaderId<Header::Hash, Header::Number> {
HeaderId(*self.number(), self.hash())
}
fn parent_id(&self) -> Option<HeaderId<Header::Hash, Header::Number>> {
self.number()
.checked_sub(&One::one())
.map(|parent_number| HeaderId(parent_number, *self.parent_hash()))
}
}
/// Unique identifier of the chain.
///
/// In addition to its main function (identifying the chain), this type may also be used to
/// identify module instance. We have a bunch of pallets that may be used in different bridges. E.g.
/// messages pallet may be deployed twice in the same runtime to bridge ThisChain with Chain1 and
/// Chain2. Sometimes we need to be able to identify deployed instance dynamically. This type may be
/// used for that.
pub type ChainId = [u8; 4];
/// Anything that has size.
pub trait Size {
/// Return size of this object (in bytes).
fn size(&self) -> u32;
}
impl Size for () {
fn size(&self) -> u32 {
0
}
}
impl Size for Vec<u8> {
fn size(&self) -> u32 {
self.len() as _
}
}
/// Pre-computed size.
pub struct PreComputedSize(pub usize);
impl Size for PreComputedSize {
fn size(&self) -> u32 {
u32::try_from(self.0).unwrap_or(u32::MAX)
}
}
/// Era of specific transaction.
#[derive(RuntimeDebug, Clone, Copy, PartialEq)]
pub enum TransactionEra<BlockNumber, BlockHash> {
/// Transaction is immortal.
Immortal,
/// Transaction is valid for a given number of blocks, starting from given block.
Mortal(HeaderId<BlockHash, BlockNumber>, u32),
}
impl<BlockNumber: Copy + UniqueSaturatedInto<u64>, BlockHash: Copy>
TransactionEra<BlockNumber, BlockHash>
{
/// Prepare transaction era, based on mortality period and current best block number.
pub fn new(
best_block_id: HeaderId<BlockHash, BlockNumber>,
mortality_period: Option<u32>,
) -> Self {
mortality_period
.map(|mortality_period| TransactionEra::Mortal(best_block_id, mortality_period))
.unwrap_or(TransactionEra::Immortal)
}
/// Create new immortal transaction era.
pub fn immortal() -> Self {
TransactionEra::Immortal
}
/// Returns mortality period if transaction is mortal.
pub fn mortality_period(&self) -> Option<u32> {
match *self {
TransactionEra::Immortal => None,
TransactionEra::Mortal(_, period) => Some(period),
}
}
/// Returns era that is used by FRAME-based runtimes.
pub fn frame_era(&self) -> sp_runtime::generic::Era {
match *self {
TransactionEra::Immortal => sp_runtime::generic::Era::immortal(),
// `unique_saturated_into` is fine here - mortality `u64::MAX` is not something we
// expect to see on any chain
TransactionEra::Mortal(header_id, period) =>
sp_runtime::generic::Era::mortal(period as _, header_id.0.unique_saturated_into()),
}
}
/// Returns header hash that needs to be included in the signature payload.
pub fn signed_payload(&self, genesis_hash: BlockHash) -> BlockHash {
match *self {
TransactionEra::Immortal => genesis_hash,
TransactionEra::Mortal(header_id, _) => header_id.1,
}
}
}
/// This is a copy of the
/// `frame_support::storage::generator::StorageMap::storage_map_final_key` for maps based
/// on selected hasher.
///
/// We're using it because to call `storage_map_final_key` directly, we need access to the runtime
/// and pallet instance, which (sometimes) is impossible.
pub fn storage_map_final_key<H: StorageHasher>(
pallet_prefix: &str,
map_name: &str,
key: &[u8],
) -> StorageKey {
let key_hashed = H::hash(key);
let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes());
let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes());
let mut final_key = Vec::with_capacity(
pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len(),
);
final_key.extend_from_slice(&pallet_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key_hashed.as_ref());
StorageKey(final_key)
}
/// This is how a storage key of storage value is computed.
///
/// Copied from `frame_support::storage::storage_prefix`.
pub fn storage_value_key(pallet_prefix: &str, value_name: &str) -> StorageKey {
let pallet_hash = sp_io::hashing::twox_128(pallet_prefix.as_bytes());
let storage_hash = sp_io::hashing::twox_128(value_name.as_bytes());
let mut final_key = vec![0u8; 32];
final_key[..16].copy_from_slice(&pallet_hash);
final_key[16..].copy_from_slice(&storage_hash);
StorageKey(final_key)
}
/// Can be use to access the runtime storage key of a `StorageMap`.
pub trait StorageMapKeyProvider {
/// The name of the variable that holds the `StorageMap`.
const MAP_NAME: &'static str;
/// The same as `StorageMap::Hasher1`.
type Hasher: StorageHasher;
/// The same as `StorageMap::Key1`.
type Key: FullCodec;
/// The same as `StorageMap::Value`.
type Value: FullCodec;
/// This is a copy of the
/// `frame_support::storage::generator::StorageMap::storage_map_final_key`.
///
/// We're using it because to call `storage_map_final_key` directly, we need access
/// to the runtime and pallet instance, which (sometimes) is impossible.
fn final_key(pallet_prefix: &str, key: &Self::Key) -> StorageKey {
storage_map_final_key::<Self::Hasher>(pallet_prefix, Self::MAP_NAME, &key.encode())
}
}
/// Can be use to access the runtime storage key of a `StorageDoubleMap`.
pub trait StorageDoubleMapKeyProvider {
/// The name of the variable that holds the `StorageDoubleMap`.
const MAP_NAME: &'static str;
/// The same as `StorageDoubleMap::Hasher1`.
type Hasher1: StorageHasher;
/// The same as `StorageDoubleMap::Key1`.
type Key1: FullCodec;
/// The same as `StorageDoubleMap::Hasher2`.
type Hasher2: StorageHasher;
/// The same as `StorageDoubleMap::Key2`.
type Key2: FullCodec;
/// The same as `StorageDoubleMap::Value`.
type Value: FullCodec;
/// This is a copy of the
/// `frame_support::storage::generator::StorageDoubleMap::storage_double_map_final_key`.
///
/// We're using it because to call `storage_double_map_final_key` directly, we need access
/// to the runtime and pallet instance, which (sometimes) is impossible.
fn final_key(pallet_prefix: &str, key1: &Self::Key1, key2: &Self::Key2) -> StorageKey {
let key1_hashed = Self::Hasher1::hash(&key1.encode());
let key2_hashed = Self::Hasher2::hash(&key2.encode());
let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes());
let storage_prefix_hashed = frame_support::Twox128::hash(Self::MAP_NAME.as_bytes());
let mut final_key = Vec::with_capacity(
pallet_prefix_hashed.len() +
storage_prefix_hashed.len() +
key1_hashed.as_ref().len() +
key2_hashed.as_ref().len(),
);
final_key.extend_from_slice(&pallet_prefix_hashed[..]);
final_key.extend_from_slice(&storage_prefix_hashed[..]);
final_key.extend_from_slice(key1_hashed.as_ref());
final_key.extend_from_slice(key2_hashed.as_ref());
StorageKey(final_key)
}
}
/// Error generated by the `OwnedBridgeModule` trait.
#[derive(Encode, Decode, PartialEq, Eq, TypeInfo, PalletError)]
pub enum OwnedBridgeModuleError {
/// All pallet operations are halted.
Halted,
}
/// Operating mode for a bridge module.
pub trait OperatingMode: Send + Copy + Debug + FullCodec {
/// Returns true if the bridge module is halted.
fn is_halted(&self) -> bool;
}
/// Basic operating modes for a bridges module (Normal/Halted).
#[derive(
Encode,
Decode,
Clone,
Copy,
PartialEq,
Eq,
RuntimeDebug,
TypeInfo,
MaxEncodedLen,
Serialize,
Deserialize,
)]
pub enum BasicOperatingMode {
/// Normal mode, when all operations are allowed.
Normal,
/// The pallet is halted. All operations (except operating mode change) are prohibited.
Halted,
}
impl Default for BasicOperatingMode {
fn default() -> Self {
Self::Normal
}
}
impl OperatingMode for BasicOperatingMode {
fn is_halted(&self) -> bool {
*self == BasicOperatingMode::Halted
}
}
/// Bridge module that has owner and operating mode
pub trait OwnedBridgeModule<T: frame_system::Config> {
/// The target that will be used when publishing logs related to this module.
const LOG_TARGET: &'static str;
/// A storage entry that holds the module `Owner` account.
type OwnerStorage: StorageValue<T::AccountId, Query = Option<T::AccountId>>;
/// Operating mode type of the pallet.
type OperatingMode: OperatingMode;
/// A storage value that holds the pallet operating mode.
type OperatingModeStorage: StorageValue<Self::OperatingMode, Query = Self::OperatingMode>;
/// Check if the module is halted.
fn is_halted() -> bool {
Self::OperatingModeStorage::get().is_halted()
}
/// Ensure that the origin is either root, or `PalletOwner`.
fn ensure_owner_or_root(origin: T::RuntimeOrigin) -> Result<(), BadOrigin> {
match origin.into() {
Ok(RawOrigin::Root) => Ok(()),
Ok(RawOrigin::Signed(ref signer))
if Self::OwnerStorage::get().as_ref() == Some(signer) =>
Ok(()),
_ => Err(BadOrigin),
}
}
/// Ensure that the module is not halted.
fn ensure_not_halted() -> Result<(), OwnedBridgeModuleError> {
match Self::is_halted() {
true => Err(OwnedBridgeModuleError::Halted),
false => Ok(()),
}
}
/// Change the owner of the module.
fn set_owner(origin: T::RuntimeOrigin, maybe_owner: Option<T::AccountId>) -> DispatchResult {
Self::ensure_owner_or_root(origin)?;
match maybe_owner {
Some(owner) => {
Self::OwnerStorage::put(&owner);
log::info!(target: Self::LOG_TARGET, "Setting pallet Owner to: {:?}", owner);
},
None => {
Self::OwnerStorage::kill();
log::info!(target: Self::LOG_TARGET, "Removed Owner of pallet.");
},
}
Ok(())
}
/// Halt or resume all/some module operations.
fn set_operating_mode(
origin: T::RuntimeOrigin,
operating_mode: Self::OperatingMode,
) -> DispatchResult {
Self::ensure_owner_or_root(origin)?;
Self::OperatingModeStorage::put(operating_mode);
log::info!(target: Self::LOG_TARGET, "Setting operating mode to {:?}.", operating_mode);
Ok(())
}
}
/// All extra operations with weights that we need in bridges.
pub trait WeightExtraOps {
/// Checked division of individual components of two weights.
///
/// Divides components and returns minimal division result. Returns `None` if one
/// of `other` weight components is zero.
fn min_components_checked_div(&self, other: Weight) -> Option<u64>;
}
impl WeightExtraOps for Weight {
fn min_components_checked_div(&self, other: Weight) -> Option<u64> {
Some(sp_std::cmp::min(
self.ref_time().checked_div(other.ref_time())?,
self.proof_size().checked_div(other.proof_size())?,
))
}
}
/// Trait that provides a static `str`.
pub trait StaticStrProvider {
/// Static string.
const STR: &'static str;
}
/// A macro that generates `StaticStrProvider` with the string set to its stringified argument.
#[macro_export]
macro_rules! generate_static_str_provider {
($str:expr) => {
$crate::paste::item! {
pub struct [<Str $str>];
impl $crate::StaticStrProvider for [<Str $str>] {
const STR: &'static str = stringify!($str);
}
}
};
}
/// Error message that is only displayable in `std` environment.
#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, TypeInfo)]
#[scale_info(skip_type_params(T))]
pub struct StrippableError<T> {
_phantom_data: sp_std::marker::PhantomData<T>,
#[codec(skip)]
#[cfg(feature = "std")]
message: String,
}
impl<T: Debug> From<T> for StrippableError<T> {
fn from(_err: T) -> Self {
Self {
_phantom_data: Default::default(),
#[cfg(feature = "std")]
message: format!("{:?}", _err),
}
}
}
impl<T> Debug for StrippableError<T> {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
f.write_str(&self.message)
}
#[cfg(not(feature = "std"))]
fn fmt(&self, f: &mut sp_std::fmt::Formatter<'_>) -> sp_std::fmt::Result {
f.write_str("Stripped error")
}
}
/// A trait defining helper methods for `RangeInclusive` (start..=end)
pub trait RangeInclusiveExt<Idx> {
/// Computes the length of the `RangeInclusive`, checking for underflow and overflow.
fn checked_len(&self) -> Option<Idx>;
/// Computes the length of the `RangeInclusive`, saturating in case of underflow or overflow.
fn saturating_len(&self) -> Idx;
}
impl<Idx> RangeInclusiveExt<Idx> for RangeInclusive<Idx>
where
Idx: CheckedSub + CheckedAdd + SaturatingAdd + One + Zero,
{
fn checked_len(&self) -> Option<Idx> {
self.end()
.checked_sub(self.start())
.and_then(|len| len.checked_add(&Idx::one()))
}
fn saturating_len(&self) -> Idx {
let len = match self.end().checked_sub(self.start()) {
Some(len) => len,
None => return Idx::zero(),
};
len.saturating_add(&Idx::one())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn storage_value_key_works() {
assert_eq!(
storage_value_key("PalletTransactionPayment", "NextFeeMultiplier"),
StorageKey(
hex_literal::hex!(
"f0e954dfcca51a255ab12c60c789256a3f2edf3bdf381debe331ab7446addfdc"
)
.to_vec()
),
);
}
#[test]
fn generate_static_str_provider_works() {
generate_static_str_provider!(Test);
assert_eq!(StrTest::STR, "Test");
}
}
@@ -1,36 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Primitives that may be used by different message delivery and dispatch mechanisms.
use codec::{Decode, Encode};
use frame_support::weights::Weight;
use scale_info::TypeInfo;
use sp_runtime::RuntimeDebug;
/// Message dispatch result.
#[derive(Encode, Decode, RuntimeDebug, Clone, PartialEq, Eq, TypeInfo)]
pub struct MessageDispatchResult<DispatchLevelResult> {
/// Unspent dispatch weight. This weight that will be deducted from total delivery transaction
/// weight, thus reducing the transaction cost. This shall not be zero in (at least) two cases:
///
/// 1) if message has been dispatched successfully, but post-dispatch weight is less than the
/// weight, declared by the message sender;
/// 2) if message has not been dispatched at all.
pub unspent_weight: Weight,
/// Fine-grained result of single message dispatch (for better diagnostic purposes)
pub dispatch_level_result: DispatchLevelResult,
}
@@ -1,272 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Logic for checking Substrate storage proofs.
use crate::StrippableError;
use codec::{Decode, Encode};
use frame_support::PalletError;
use hash_db::{HashDB, Hasher, EMPTY_PREFIX};
use scale_info::TypeInfo;
use sp_std::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec};
use sp_trie::{
read_trie_value, LayoutV1, MemoryDB, Recorder, StorageProof, Trie, TrieConfiguration,
TrieDBBuilder, TrieError, TrieHash,
};
/// Raw storage proof type (just raw trie nodes).
pub type RawStorageProof = Vec<Vec<u8>>;
/// Storage proof size requirements.
///
/// This is currently used by benchmarks when generating storage proofs.
#[derive(Clone, Copy, Debug)]
pub enum ProofSize {
/// The proof is expected to be minimal. If value size may be changed, then it is expected to
/// have given size.
Minimal(u32),
/// The proof is expected to have at least given size and grow by increasing value that is
/// stored in the trie.
HasLargeLeaf(u32),
}
/// This struct is used to read storage values from a subset of a Merklized database. The "proof"
/// is a subset of the nodes in the Merkle structure of the database, so that it provides
/// authentication against a known Merkle root as well as the values in the
/// database themselves.
pub struct StorageProofChecker<H>
where
H: Hasher,
{
proof_nodes_count: usize,
root: H::Out,
db: MemoryDB<H>,
recorder: Recorder<LayoutV1<H>>,
}
impl<H> StorageProofChecker<H>
where
H: Hasher,
{
/// Constructs a new storage proof checker.
///
/// This returns an error if the given proof is invalid with respect to the given root.
pub fn new(root: H::Out, proof: RawStorageProof) -> Result<Self, Error> {
// 1. we don't want extra items in the storage proof
// 2. `StorageProof` is storing all trie nodes in the `BTreeSet`
//
// => someone could simply add duplicate items to the proof and we won't be
// able to detect that by just using `StorageProof`
//
// => let's check it when we are converting our "raw proof" into `StorageProof`
let proof_nodes_count = proof.len();
let proof = StorageProof::new(proof);
if proof_nodes_count != proof.iter_nodes().count() {
return Err(Error::DuplicateNodesInProof)
}
let db = proof.into_memory_db();
if !db.contains(&root, EMPTY_PREFIX) {
return Err(Error::StorageRootMismatch)
}
let recorder = Recorder::default();
let checker = StorageProofChecker { proof_nodes_count, root, db, recorder };
Ok(checker)
}
/// Returns error if the proof has some nodes that are left intact by previous `read_value`
/// calls.
pub fn ensure_no_unused_nodes(mut self) -> Result<(), Error> {
let visited_nodes = self
.recorder
.drain()
.into_iter()
.map(|record| record.data)
.collect::<BTreeSet<_>>();
let visited_nodes_count = visited_nodes.len();
if self.proof_nodes_count == visited_nodes_count {
Ok(())
} else {
Err(Error::UnusedNodesInTheProof)
}
}
/// Reads a value from the available subset of storage. If the value cannot be read due to an
/// incomplete or otherwise invalid proof, this function returns an error.
pub fn read_value(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
// LayoutV1 or LayoutV0 is identical for proof that only read values.
read_trie_value::<LayoutV1<H>, _>(&self.db, &self.root, key, Some(&mut self.recorder), None)
.map_err(|_| Error::StorageValueUnavailable)
}
/// Reads and decodes a value from the available subset of storage. If the value cannot be read
/// due to an incomplete or otherwise invalid proof, this function returns an error. If value is
/// read, but decoding fails, this function returns an error.
pub fn read_and_decode_value<T: Decode>(&mut self, key: &[u8]) -> Result<Option<T>, Error> {
self.read_value(key).and_then(|v| {
v.map(|v| T::decode(&mut &v[..]).map_err(|e| Error::StorageValueDecodeFailed(e.into())))
.transpose()
})
}
/// Reads and decodes a value from the available subset of storage. If the value cannot be read
/// due to an incomplete or otherwise invalid proof, or if the value is `None`, this function
/// returns an error. If value is read, but decoding fails, this function returns an error.
pub fn read_and_decode_mandatory_value<T: Decode>(&mut self, key: &[u8]) -> Result<T, Error> {
self.read_and_decode_value(key)?.ok_or(Error::StorageValueEmpty)
}
/// Reads and decodes a value from the available subset of storage. If the value cannot be read
/// due to an incomplete or otherwise invalid proof, this function returns `Ok(None)`.
/// If value is read, but decoding fails, this function returns an error.
pub fn read_and_decode_opt_value<T: Decode>(&mut self, key: &[u8]) -> Result<Option<T>, Error> {
match self.read_and_decode_value(key) {
Ok(outbound_lane_data) => Ok(outbound_lane_data),
Err(Error::StorageValueUnavailable) => Ok(None),
Err(e) => Err(e),
}
}
}
/// Storage proof related errors.
#[derive(Encode, Decode, Clone, Eq, PartialEq, PalletError, Debug, TypeInfo)]
pub enum Error {
/// Duplicate trie nodes are found in the proof.
DuplicateNodesInProof,
/// Unused trie nodes are found in the proof.
UnusedNodesInTheProof,
/// Expected storage root is missing from the proof.
StorageRootMismatch,
/// Unable to reach expected storage value using provided trie nodes.
StorageValueUnavailable,
/// The storage value is `None`.
StorageValueEmpty,
/// Failed to decode storage value.
StorageValueDecodeFailed(StrippableError<codec::Error>),
}
/// Return valid storage proof and state root.
///
/// NOTE: This should only be used for **testing**.
#[cfg(feature = "std")]
pub fn craft_valid_storage_proof() -> (sp_core::H256, RawStorageProof) {
use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend};
let state_version = sp_runtime::StateVersion::default();
// construct storage proof
let backend = <InMemoryBackend<sp_core::Blake2Hasher>>::from((
vec![
(None, vec![(b"key1".to_vec(), Some(b"value1".to_vec()))]),
(None, vec![(b"key2".to_vec(), Some(b"value2".to_vec()))]),
(None, vec![(b"key3".to_vec(), Some(b"value3".to_vec()))]),
(None, vec![(b"key4".to_vec(), Some((42u64, 42u32, 42u16, 42u8).encode()))]),
// Value is too big to fit in a branch node
(None, vec![(b"key11".to_vec(), Some(vec![0u8; 32]))]),
],
state_version,
));
let root = backend.storage_root(std::iter::empty(), state_version).0;
let proof =
prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key4"[..], &b"key22"[..]]).unwrap();
(root, proof.into_nodes().into_iter().collect())
}
/// Record all keys for a given root.
pub fn record_all_keys<L: TrieConfiguration, DB>(
db: &DB,
root: &TrieHash<L>,
) -> Result<RawStorageProof, Box<TrieError<L>>>
where
DB: hash_db::HashDBRef<L::Hash, trie_db::DBValue>,
{
let mut recorder = Recorder::<L>::new();
let trie = TrieDBBuilder::<L>::new(db, root).with_recorder(&mut recorder).build();
for x in trie.iter()? {
let (key, _) = x?;
trie.get(&key)?;
}
// recorder may record the same trie node multiple times and we don't want duplicate nodes
// in our proofs => let's deduplicate it by collecting to the BTreeSet first
Ok(recorder
.drain()
.into_iter()
.map(|n| n.data.to_vec())
.collect::<BTreeSet<_>>()
.into_iter()
.collect())
}
#[cfg(test)]
pub mod tests {
use super::*;
use codec::Encode;
#[test]
fn storage_proof_check() {
let (root, proof) = craft_valid_storage_proof();
// check proof in runtime
let mut checker =
<StorageProofChecker<sp_core::Blake2Hasher>>::new(root, proof.clone()).unwrap();
assert_eq!(checker.read_value(b"key1"), Ok(Some(b"value1".to_vec())));
assert_eq!(checker.read_value(b"key2"), Ok(Some(b"value2".to_vec())));
assert_eq!(checker.read_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8).encode())));
assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable));
assert_eq!(checker.read_value(b"key22"), Ok(None));
assert_eq!(checker.read_and_decode_value(b"key4"), Ok(Some((42u64, 42u32, 42u16, 42u8))),);
assert!(matches!(
checker.read_and_decode_value::<[u8; 64]>(b"key4"),
Err(Error::StorageValueDecodeFailed(_)),
));
// checking proof against invalid commitment fails
assert_eq!(
<StorageProofChecker<sp_core::Blake2Hasher>>::new(sp_core::H256::random(), proof).err(),
Some(Error::StorageRootMismatch)
);
}
#[test]
fn proof_with_duplicate_items_is_rejected() {
let (root, mut proof) = craft_valid_storage_proof();
proof.push(proof.first().unwrap().clone());
assert_eq!(
StorageProofChecker::<sp_core::Blake2Hasher>::new(root, proof).map(drop),
Err(Error::DuplicateNodesInProof),
);
}
#[test]
fn proof_with_unused_items_is_rejected() {
let (root, proof) = craft_valid_storage_proof();
let mut checker =
StorageProofChecker::<sp_core::Blake2Hasher>::new(root, proof.clone()).unwrap();
checker.read_value(b"key1").unwrap();
checker.read_value(b"key2").unwrap();
checker.read_value(b"key4").unwrap();
checker.read_value(b"key22").unwrap();
assert_eq!(checker.ensure_no_unused_nodes(), Ok(()));
let checker = StorageProofChecker::<sp_core::Blake2Hasher>::new(root, proof).unwrap();
assert_eq!(checker.ensure_no_unused_nodes(), Err(Error::UnusedNodesInTheProof));
}
}
@@ -1,91 +0,0 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity Bridges Common is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
//! Wrapper for a runtime storage value that checks if value exceeds given maximum
//! during conversion.
use codec::{Decode, Encode, MaxEncodedLen};
use frame_support::traits::Get;
use scale_info::{Type, TypeInfo};
use sp_runtime::RuntimeDebug;
use sp_std::{marker::PhantomData, ops::Deref};
/// Error that is returned when the value size exceeds maximal configured size.
#[derive(RuntimeDebug)]
pub struct MaximalSizeExceededError {
/// Size of the value.
pub value_size: usize,
/// Maximal configured size.
pub maximal_size: usize,
}
/// A bounded runtime storage value.
#[derive(Clone, Decode, Encode, Eq, PartialEq)]
pub struct BoundedStorageValue<B, V> {
value: V,
_phantom: PhantomData<B>,
}
impl<B, V: sp_std::fmt::Debug> sp_std::fmt::Debug for BoundedStorageValue<B, V> {
fn fmt(&self, fmt: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
self.value.fmt(fmt)
}
}
impl<B: Get<u32>, V: Encode> BoundedStorageValue<B, V> {
/// Construct `BoundedStorageValue` from the underlying `value` with all required checks.
///
/// Returns error if value size exceeds given bounds.
pub fn try_from_inner(value: V) -> Result<Self, MaximalSizeExceededError> {
// this conversion is heavy (since we do encoding here), so we may want to optimize it later
// (e.g. by introducing custom Encode implementation, and turning `BoundedStorageValue` into
// `enum BoundedStorageValue { Decoded(V), Encoded(Vec<u8>) }`)
let value_size = value.encoded_size();
let maximal_size = B::get() as usize;
if value_size > maximal_size {
Err(MaximalSizeExceededError { value_size, maximal_size })
} else {
Ok(BoundedStorageValue { value, _phantom: Default::default() })
}
}
/// Convert into the inner type
pub fn into_inner(self) -> V {
self.value
}
}
impl<B, V> Deref for BoundedStorageValue<B, V> {
type Target = V;
fn deref(&self) -> &Self::Target {
&self.value
}
}
impl<B: 'static, V: TypeInfo + 'static> TypeInfo for BoundedStorageValue<B, V> {
type Identity = Self;
fn type_info() -> Type {
V::type_info()
}
}
impl<B: Get<u32>, V: Encode> MaxEncodedLen for BoundedStorageValue<B, V> {
fn max_encoded_len() -> usize {
B::get() as usize
}
}