mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-07-21 00:25:41 +00:00
Move Storage Parser from Bridge Pallet (#793)
* Move storage proof checker to runtime primtives * Add method for parsing storage proofs * Use finality-verifier pallet in runtime-common * Get bridge pallet compiling again * Use storage prover from bp-runtime in a few more places * Don't leak `std` items from proof helper into `no-std` builds * Fix benchmarking compilation * Remove unused import in fuzzer
This commit is contained in:
committed by
Bastian Köcher
parent
80533af331
commit
51db99ea79
@@ -19,7 +19,7 @@ bp-message-lane = { path = "../../primitives/message-lane", default-features = f
|
|||||||
bp-runtime = { path = "../../primitives/runtime", default-features = false }
|
bp-runtime = { path = "../../primitives/runtime", default-features = false }
|
||||||
pallet-bridge-call-dispatch = { path = "../../modules/call-dispatch", default-features = false }
|
pallet-bridge-call-dispatch = { path = "../../modules/call-dispatch", default-features = false }
|
||||||
pallet-message-lane = { path = "../../modules/message-lane", default-features = false }
|
pallet-message-lane = { path = "../../modules/message-lane", default-features = false }
|
||||||
pallet-substrate-bridge = { path = "../../modules/substrate", default-features = false }
|
pallet-finality-verifier = { path = "../../modules/finality-verifier", default-features = false }
|
||||||
|
|
||||||
# Substrate dependencies
|
# Substrate dependencies
|
||||||
|
|
||||||
@@ -40,8 +40,8 @@ std = [
|
|||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
"hash-db/std",
|
"hash-db/std",
|
||||||
"pallet-bridge-call-dispatch/std",
|
"pallet-bridge-call-dispatch/std",
|
||||||
|
"pallet-finality-verifier/std",
|
||||||
"pallet-message-lane/std",
|
"pallet-message-lane/std",
|
||||||
"pallet-substrate-bridge/std",
|
|
||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-state-machine/std",
|
"sp-state-machine/std",
|
||||||
@@ -50,7 +50,7 @@ std = [
|
|||||||
]
|
]
|
||||||
runtime-benchmarks = [
|
runtime-benchmarks = [
|
||||||
"ed25519-dalek/u64_backend",
|
"ed25519-dalek/u64_backend",
|
||||||
|
"pallet-finality-verifier/runtime-benchmarks",
|
||||||
"pallet-message-lane/runtime-benchmarks",
|
"pallet-message-lane/runtime-benchmarks",
|
||||||
"pallet-substrate-bridge/runtime-benchmarks",
|
|
||||||
"sp-state-machine",
|
"sp-state-machine",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -26,11 +26,10 @@ use bp_message_lane::{
|
|||||||
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
|
target_chain::{DispatchMessage, MessageDispatch, ProvedLaneMessages, ProvedMessages},
|
||||||
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
InboundLaneData, LaneId, Message, MessageData, MessageKey, MessageNonce, OutboundLaneData,
|
||||||
};
|
};
|
||||||
use bp_runtime::{InstanceId, Size};
|
use bp_runtime::{InstanceId, Size, StorageProofChecker};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_support::{traits::Instance, weights::Weight, RuntimeDebug};
|
use frame_support::{traits::Instance, weights::Weight, RuntimeDebug};
|
||||||
use hash_db::Hasher;
|
use hash_db::Hasher;
|
||||||
use pallet_substrate_bridge::StorageProofChecker;
|
|
||||||
use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul};
|
use sp_runtime::traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedDiv, CheckedMul};
|
||||||
use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive, vec::Vec};
|
use sp_std::{cmp::PartialOrd, convert::TryFrom, fmt::Debug, marker::PhantomData, ops::RangeInclusive, vec::Vec};
|
||||||
use sp_trie::StorageProof;
|
use sp_trie::StorageProof;
|
||||||
@@ -352,17 +351,17 @@ pub mod source {
|
|||||||
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
|
proof: FromBridgedChainMessagesDeliveryProof<HashOf<BridgedChain<B>>>,
|
||||||
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
|
) -> Result<ParsedMessagesDeliveryProofFromBridgedChain<B>, &'static str>
|
||||||
where
|
where
|
||||||
ThisRuntime: pallet_substrate_bridge::Config,
|
ThisRuntime: pallet_finality_verifier::Config,
|
||||||
ThisRuntime: pallet_message_lane::Config<MessageLaneInstanceOf<BridgedChain<B>>>,
|
ThisRuntime: pallet_message_lane::Config<MessageLaneInstanceOf<BridgedChain<B>>>,
|
||||||
HashOf<BridgedChain<B>>:
|
HashOf<BridgedChain<B>>:
|
||||||
Into<bp_runtime::HashOf<<ThisRuntime as pallet_substrate_bridge::Config>::BridgedChain>>,
|
Into<bp_runtime::HashOf<<ThisRuntime as pallet_finality_verifier::Config>::BridgedChain>>,
|
||||||
{
|
{
|
||||||
let FromBridgedChainMessagesDeliveryProof {
|
let FromBridgedChainMessagesDeliveryProof {
|
||||||
bridged_header_hash,
|
bridged_header_hash,
|
||||||
storage_proof,
|
storage_proof,
|
||||||
lane,
|
lane,
|
||||||
} = proof;
|
} = proof;
|
||||||
pallet_substrate_bridge::Module::<ThisRuntime>::parse_finalized_storage_proof(
|
pallet_finality_verifier::Module::<ThisRuntime>::parse_finalized_storage_proof(
|
||||||
bridged_header_hash.into(),
|
bridged_header_hash.into(),
|
||||||
StorageProof::new(storage_proof),
|
StorageProof::new(storage_proof),
|
||||||
|storage| {
|
|storage| {
|
||||||
@@ -506,16 +505,16 @@ pub mod target {
|
|||||||
messages_count: u32,
|
messages_count: u32,
|
||||||
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
|
) -> Result<ProvedMessages<Message<BalanceOf<BridgedChain<B>>>>, &'static str>
|
||||||
where
|
where
|
||||||
ThisRuntime: pallet_substrate_bridge::Config,
|
ThisRuntime: pallet_finality_verifier::Config,
|
||||||
ThisRuntime: pallet_message_lane::Config<MessageLaneInstanceOf<BridgedChain<B>>>,
|
ThisRuntime: pallet_message_lane::Config<MessageLaneInstanceOf<BridgedChain<B>>>,
|
||||||
HashOf<BridgedChain<B>>:
|
HashOf<BridgedChain<B>>:
|
||||||
Into<bp_runtime::HashOf<<ThisRuntime as pallet_substrate_bridge::Config>::BridgedChain>>,
|
Into<bp_runtime::HashOf<<ThisRuntime as pallet_finality_verifier::Config>::BridgedChain>>,
|
||||||
{
|
{
|
||||||
verify_messages_proof_with_parser::<B, _, _>(
|
verify_messages_proof_with_parser::<B, _, _>(
|
||||||
proof,
|
proof,
|
||||||
messages_count,
|
messages_count,
|
||||||
|bridged_header_hash, bridged_storage_proof| {
|
|bridged_header_hash, bridged_storage_proof| {
|
||||||
pallet_substrate_bridge::Module::<ThisRuntime>::parse_finalized_storage_proof(
|
pallet_finality_verifier::Module::<ThisRuntime>::parse_finalized_storage_proof(
|
||||||
bridged_header_hash.into(),
|
bridged_header_hash.into(),
|
||||||
StorageProof::new(bridged_storage_proof),
|
StorageProof::new(bridged_storage_proof),
|
||||||
|storage_adapter| storage_adapter,
|
|storage_adapter| storage_adapter,
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ pub fn prepare_message_proof<B, H, R, MM, ML, MH>(
|
|||||||
where
|
where
|
||||||
B: MessageBridge,
|
B: MessageBridge,
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
R: pallet_substrate_bridge::Config,
|
R: pallet_finality_verifier::Config,
|
||||||
<R::BridgedChain as bp_runtime::Chain>::Hash: Into<HashOf<BridgedChain<B>>>,
|
<R::BridgedChain as bp_runtime::Chain>::Hash: Into<HashOf<BridgedChain<B>>>,
|
||||||
MM: Fn(MessageKey) -> Vec<u8>,
|
MM: Fn(MessageKey) -> Vec<u8>,
|
||||||
ML: Fn(LaneId) -> Vec<u8>,
|
ML: Fn(LaneId) -> Vec<u8>,
|
||||||
@@ -129,7 +129,7 @@ where
|
|||||||
// prepare Bridged chain header and insert it into the Substrate pallet
|
// prepare Bridged chain header and insert it into the Substrate pallet
|
||||||
let bridged_header = make_bridged_header(root);
|
let bridged_header = make_bridged_header(root);
|
||||||
let bridged_header_hash = bridged_header.hash();
|
let bridged_header_hash = bridged_header.hash();
|
||||||
pallet_substrate_bridge::initialize_for_benchmarks::<R>(bridged_header);
|
pallet_finality_verifier::initialize_for_benchmarks::<R>(bridged_header);
|
||||||
|
|
||||||
(
|
(
|
||||||
FromBridgedChainMessagesProof {
|
FromBridgedChainMessagesProof {
|
||||||
@@ -154,7 +154,7 @@ pub fn prepare_message_delivery_proof<B, H, R, ML, MH>(
|
|||||||
where
|
where
|
||||||
B: MessageBridge,
|
B: MessageBridge,
|
||||||
H: Hasher,
|
H: Hasher,
|
||||||
R: pallet_substrate_bridge::Config,
|
R: pallet_finality_verifier::Config,
|
||||||
<R::BridgedChain as bp_runtime::Chain>::Hash: Into<HashOf<BridgedChain<B>>>,
|
<R::BridgedChain as bp_runtime::Chain>::Hash: Into<HashOf<BridgedChain<B>>>,
|
||||||
ML: Fn(LaneId) -> Vec<u8>,
|
ML: Fn(LaneId) -> Vec<u8>,
|
||||||
MH: Fn(H::Out) -> <R::BridgedChain as bp_runtime::Chain>::Header,
|
MH: Fn(H::Out) -> <R::BridgedChain as bp_runtime::Chain>::Header,
|
||||||
@@ -181,7 +181,7 @@ where
|
|||||||
// prepare Bridged chain header and insert it into the Substrate pallet
|
// prepare Bridged chain header and insert it into the Substrate pallet
|
||||||
let bridged_header = make_bridged_header(root);
|
let bridged_header = make_bridged_header(root);
|
||||||
let bridged_header_hash = bridged_header.hash();
|
let bridged_header_hash = bridged_header.hash();
|
||||||
pallet_substrate_bridge::initialize_for_benchmarks::<R>(bridged_header);
|
pallet_finality_verifier::initialize_for_benchmarks::<R>(bridged_header);
|
||||||
|
|
||||||
FromBridgedChainMessagesDeliveryProof {
|
FromBridgedChainMessagesDeliveryProof {
|
||||||
bridged_header_hash: bridged_header_hash.into(),
|
bridged_header_hash: bridged_header_hash.into(),
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ frame-system = { git = "https://github.com/paritytech/substrate.git", branch = "
|
|||||||
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-finality-grandpa = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
|
sp-trie = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
bp-test-utils = {path = "../../primitives/test-utils" }
|
bp-test-utils = {path = "../../primitives/test-utils" }
|
||||||
@@ -46,4 +47,6 @@ std = [
|
|||||||
"sp-finality-grandpa/std",
|
"sp-finality-grandpa/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
"sp-trie/std",
|
||||||
]
|
]
|
||||||
|
runtime-benchmarks = []
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub type BridgedBlockNumber<T> = BlockNumberOf<<T as Config>::BridgedChain>;
|
|||||||
/// Block hash of the bridged chain.
|
/// Block hash of the bridged chain.
|
||||||
pub type BridgedBlockHash<T> = HashOf<<T as Config>::BridgedChain>;
|
pub type BridgedBlockHash<T> = HashOf<<T as Config>::BridgedChain>;
|
||||||
/// Hasher of the bridged chain.
|
/// Hasher of the bridged chain.
|
||||||
pub type _BridgedBlockHasher<T> = HasherOf<<T as Config>::BridgedChain>;
|
pub type BridgedBlockHasher<T> = HasherOf<<T as Config>::BridgedChain>;
|
||||||
/// Header of the bridged chain.
|
/// Header of the bridged chain.
|
||||||
pub type BridgedHeader<T> = HeaderOf<<T as Config>::BridgedChain>;
|
pub type BridgedHeader<T> = HeaderOf<<T as Config>::BridgedChain>;
|
||||||
|
|
||||||
@@ -335,6 +335,8 @@ pub mod pallet {
|
|||||||
TooManyRequests,
|
TooManyRequests,
|
||||||
/// The header being imported is older than the best finalized header known to the pallet.
|
/// The header being imported is older than the best finalized header known to the pallet.
|
||||||
OldHeader,
|
OldHeader,
|
||||||
|
/// The header is unknown to the pallet.
|
||||||
|
UnknownHeader,
|
||||||
/// The scheduled authority set change found in the header is unsupported by the pallet.
|
/// The scheduled authority set change found in the header is unsupported by the pallet.
|
||||||
///
|
///
|
||||||
/// This is the case for non-standard (e.g forced) authority set changes.
|
/// This is the case for non-standard (e.g forced) authority set changes.
|
||||||
@@ -343,6 +345,8 @@ pub mod pallet {
|
|||||||
AlreadyInitialized,
|
AlreadyInitialized,
|
||||||
/// All pallet operations are halted.
|
/// All pallet operations are halted.
|
||||||
Halted,
|
Halted,
|
||||||
|
/// The storage proof doesn't contains storage root. So it is invalid for given header.
|
||||||
|
StorageRootMismatch,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import the given header to the pallet's storage.
|
/// Import the given header to the pallet's storage.
|
||||||
@@ -387,7 +391,7 @@ pub mod pallet {
|
|||||||
|
|
||||||
/// Since this writes to storage with no real checks this should only be used in functions that
|
/// Since this writes to storage with no real checks this should only be used in functions that
|
||||||
/// were called by a trusted origin.
|
/// were called by a trusted origin.
|
||||||
fn initialize_bridge<T: Config>(init_params: super::InitializationData<BridgedHeader<T>>) {
|
pub(crate) fn initialize_bridge<T: Config>(init_params: super::InitializationData<BridgedHeader<T>>) {
|
||||||
let super::InitializationData {
|
let super::InitializationData {
|
||||||
header,
|
header,
|
||||||
authority_list,
|
authority_list,
|
||||||
@@ -447,6 +451,21 @@ impl<T: Config> Pallet<T> {
|
|||||||
pub fn is_known_header(hash: BridgedBlockHash<T>) -> bool {
|
pub fn is_known_header(hash: BridgedBlockHash<T>) -> bool {
|
||||||
<ImportedHeaders<T>>::contains_key(hash)
|
<ImportedHeaders<T>>::contains_key(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify that the passed storage proof is valid, given it is crafted using
|
||||||
|
/// known finalized header. If the proof is valid, then the `parse` callback
|
||||||
|
/// is called and the function returns its result.
|
||||||
|
pub fn parse_finalized_storage_proof<R>(
|
||||||
|
hash: BridgedBlockHash<T>,
|
||||||
|
storage_proof: sp_trie::StorageProof,
|
||||||
|
parse: impl FnOnce(bp_runtime::StorageProofChecker<BridgedBlockHasher<T>>) -> R,
|
||||||
|
) -> Result<R, sp_runtime::DispatchError> {
|
||||||
|
let header = <ImportedHeaders<T>>::get(hash).ok_or(Error::<T>::UnknownHeader)?;
|
||||||
|
let storage_proof_checker = bp_runtime::StorageProofChecker::new(*header.state_root(), storage_proof)
|
||||||
|
.map_err(|_| Error::<T>::StorageRootMismatch)?;
|
||||||
|
|
||||||
|
Ok(parse(storage_proof_checker))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Data required for initializing the bridge pallet.
|
/// Data required for initializing the bridge pallet.
|
||||||
@@ -499,6 +518,17 @@ pub(crate) fn find_forced_change<H: HeaderT>(
|
|||||||
header.digest().convert_first(|l| l.try_to(id).and_then(filter_log))
|
header.digest().convert_first(|l| l.try_to(id).and_then(filter_log))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (Re)initialize bridge with given header for using it in external benchmarks.
|
||||||
|
#[cfg(feature = "runtime-benchmarks")]
|
||||||
|
pub fn initialize_for_benchmarks<T: Config>(header: BridgedHeader<T>) {
|
||||||
|
initialize_bridge::<T>(InitializationData {
|
||||||
|
header,
|
||||||
|
authority_list: Vec::new(), // we don't verify any proofs in external benchmarks
|
||||||
|
set_id: 0,
|
||||||
|
is_halted: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -864,6 +894,40 @@ mod tests {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_finalized_storage_proof_rejects_proof_on_unknown_header() {
|
||||||
|
run_test(|| {
|
||||||
|
assert_noop!(
|
||||||
|
Module::<TestRuntime>::parse_finalized_storage_proof(
|
||||||
|
Default::default(),
|
||||||
|
sp_trie::StorageProof::new(vec![]),
|
||||||
|
|_| (),
|
||||||
|
),
|
||||||
|
Error::<TestRuntime>::UnknownHeader,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_finalized_storage_accepts_valid_proof() {
|
||||||
|
run_test(|| {
|
||||||
|
let (state_root, storage_proof) = bp_runtime::craft_valid_storage_proof();
|
||||||
|
|
||||||
|
let mut header = test_header(2);
|
||||||
|
header.set_state_root(state_root);
|
||||||
|
|
||||||
|
let hash = header.hash();
|
||||||
|
<BestFinalized<TestRuntime>>::put(hash);
|
||||||
|
<ImportedHeaders<TestRuntime>>::insert(hash, header);
|
||||||
|
|
||||||
|
assert_ok!(
|
||||||
|
Module::<TestRuntime>::parse_finalized_storage_proof(hash, storage_proof, |_| (),),
|
||||||
|
(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rate_limiter_disallows_imports_once_limit_is_hit_in_single_block() {
|
fn rate_limiter_disallows_imports_once_limit_is_hit_in_single_block() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
|
|||||||
@@ -46,10 +46,7 @@ use sp_trie::StorageProof;
|
|||||||
// Re-export since the node uses these when configuring genesis
|
// Re-export since the node uses these when configuring genesis
|
||||||
pub use storage::{InitializationData, ScheduledChange};
|
pub use storage::{InitializationData, ScheduledChange};
|
||||||
|
|
||||||
pub use storage_proof::StorageProofChecker;
|
|
||||||
|
|
||||||
mod storage;
|
mod storage;
|
||||||
mod storage_proof;
|
|
||||||
mod verifier;
|
mod verifier;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -355,7 +352,7 @@ impl<T: Config> Module<T> {
|
|||||||
pub fn parse_finalized_storage_proof<R>(
|
pub fn parse_finalized_storage_proof<R>(
|
||||||
finalized_header_hash: BridgedBlockHash<T>,
|
finalized_header_hash: BridgedBlockHash<T>,
|
||||||
storage_proof: StorageProof,
|
storage_proof: StorageProof,
|
||||||
parse: impl FnOnce(StorageProofChecker<BridgedBlockHasher<T>>) -> R,
|
parse: impl FnOnce(bp_runtime::StorageProofChecker<BridgedBlockHasher<T>>) -> R,
|
||||||
) -> Result<R, sp_runtime::DispatchError> {
|
) -> Result<R, sp_runtime::DispatchError> {
|
||||||
let storage = PalletStorage::<T>::new();
|
let storage = PalletStorage::<T>::new();
|
||||||
let header = storage
|
let header = storage
|
||||||
@@ -365,8 +362,8 @@ impl<T: Config> Module<T> {
|
|||||||
return Err(Error::<T>::UnfinalizedHeader.into());
|
return Err(Error::<T>::UnfinalizedHeader.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let storage_proof_checker =
|
let storage_proof_checker = bp_runtime::StorageProofChecker::new(*header.state_root(), storage_proof)
|
||||||
StorageProofChecker::new(*header.state_root(), storage_proof).map_err(Error::<T>::from)?;
|
.map_err(|_| Error::<T>::StorageRootMismatch)?;
|
||||||
Ok(parse(storage_proof_checker))
|
Ok(parse(storage_proof_checker))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -898,7 +895,7 @@ mod tests {
|
|||||||
fn parse_finalized_storage_accepts_valid_proof() {
|
fn parse_finalized_storage_accepts_valid_proof() {
|
||||||
run_test(|| {
|
run_test(|| {
|
||||||
let mut storage = PalletStorage::<TestRuntime>::new();
|
let mut storage = PalletStorage::<TestRuntime>::new();
|
||||||
let (state_root, storage_proof) = storage_proof::tests::craft_valid_storage_proof();
|
let (state_root, storage_proof) = bp_runtime::craft_valid_storage_proof();
|
||||||
let mut header = unfinalized_header(1);
|
let mut header = unfinalized_header(1);
|
||||||
header.is_finalized = true;
|
header.is_finalized = true;
|
||||||
header.header.set_state_root(state_root);
|
header.header.set_state_root(state_root);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
|
codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false }
|
||||||
|
hash-db = { version = "0.15.2", default-features = false }
|
||||||
num-traits = { version = "0.2", default-features = false }
|
num-traits = { version = "0.2", default-features = false }
|
||||||
|
|
||||||
# Substrate Dependencies
|
# Substrate Dependencies
|
||||||
@@ -17,15 +18,23 @@ sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "maste
|
|||||||
sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
sp-std = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
|
sp-state-machine = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
|
||||||
|
sp-trie = { git = "https://github.com/paritytech/substrate.git", branch = "master" , default-features = false }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
"codec/std",
|
"codec/std",
|
||||||
"frame-support/std",
|
"frame-support/std",
|
||||||
|
"hash-db/std",
|
||||||
"num-traits/std",
|
"num-traits/std",
|
||||||
"sp-core/std",
|
"sp-core/std",
|
||||||
"sp-io/std",
|
"sp-io/std",
|
||||||
"sp-runtime/std",
|
"sp-runtime/std",
|
||||||
"sp-std/std",
|
"sp-std/std",
|
||||||
|
"sp-state-machine/std",
|
||||||
|
"sp-trie/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -24,8 +24,13 @@ use sp_io::hashing::blake2_256;
|
|||||||
use sp_std::convert::TryFrom;
|
use sp_std::convert::TryFrom;
|
||||||
|
|
||||||
pub use chain::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
pub use chain::{BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf};
|
||||||
|
pub use storage_proof::StorageProofChecker;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use storage_proof::craft_valid_storage_proof;
|
||||||
|
|
||||||
mod chain;
|
mod chain;
|
||||||
|
mod storage_proof;
|
||||||
|
|
||||||
/// Use this when something must be shared among all instances.
|
/// Use this when something must be shared among all instances.
|
||||||
pub const NO_INSTANCE_ID: InstanceId = [0, 0, 0, 0];
|
pub const NO_INSTANCE_ID: InstanceId = [0, 0, 0, 0];
|
||||||
|
|||||||
+27
-36
@@ -14,12 +14,10 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// 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/>.
|
// along with Parity Bridges Common. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// TODO: remove on actual use
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
//! Logic for checking Substrate storage proofs.
|
//! Logic for checking Substrate storage proofs.
|
||||||
|
|
||||||
use hash_db::{HashDB, Hasher, EMPTY_PREFIX};
|
use hash_db::{HashDB, Hasher, EMPTY_PREFIX};
|
||||||
|
use sp_core::H256;
|
||||||
use sp_runtime::RuntimeDebug;
|
use sp_runtime::RuntimeDebug;
|
||||||
use sp_std::vec::Vec;
|
use sp_std::vec::Vec;
|
||||||
use sp_trie::{read_trie_value, Layout, MemoryDB, StorageProof};
|
use sp_trie::{read_trie_value, Layout, MemoryDB, StorageProof};
|
||||||
@@ -65,49 +63,42 @@ pub enum Error {
|
|||||||
StorageValueUnavailable,
|
StorageValueUnavailable,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: crate::Config> From<Error> for crate::Error<T> {
|
/// Return valid storage proof and state root.
|
||||||
fn from(error: Error) -> Self {
|
///
|
||||||
match error {
|
/// NOTE: This should only be used for **testing**.
|
||||||
Error::StorageRootMismatch => crate::Error::StorageRootMismatch,
|
#[cfg(feature = "std")]
|
||||||
Error::StorageValueUnavailable => crate::Error::StorageValueUnavailable,
|
pub fn craft_valid_storage_proof() -> (H256, StorageProof) {
|
||||||
}
|
use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend};
|
||||||
}
|
|
||||||
|
// 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()))]),
|
||||||
|
// Value is too big to fit in a branch node
|
||||||
|
(None, vec![(b"key11".to_vec(), Some(vec![0u8; 32]))]),
|
||||||
|
]);
|
||||||
|
let root = backend.storage_root(std::iter::empty()).0;
|
||||||
|
let proof = StorageProof::new(
|
||||||
|
prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key22"[..]])
|
||||||
|
.unwrap()
|
||||||
|
.iter_nodes()
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
|
(root, proof)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use sp_core::{Blake2Hasher, H256};
|
|
||||||
use sp_state_machine::{backend::Backend, prove_read, InMemoryBackend};
|
|
||||||
|
|
||||||
/// Return valid storage proof and state root.
|
|
||||||
pub fn craft_valid_storage_proof() -> (H256, StorageProof) {
|
|
||||||
// construct storage proof
|
|
||||||
let backend = <InMemoryBackend<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()))]),
|
|
||||||
// Value is too big to fit in a branch node
|
|
||||||
(None, vec![(b"key11".to_vec(), Some(vec![0u8; 32]))]),
|
|
||||||
]);
|
|
||||||
let root = backend.storage_root(std::iter::empty()).0;
|
|
||||||
let proof = StorageProof::new(
|
|
||||||
prove_read(backend, &[&b"key1"[..], &b"key2"[..], &b"key22"[..]])
|
|
||||||
.unwrap()
|
|
||||||
.iter_nodes()
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
(root, proof)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage_proof_check() {
|
fn storage_proof_check() {
|
||||||
let (root, proof) = craft_valid_storage_proof();
|
let (root, proof) = craft_valid_storage_proof();
|
||||||
|
|
||||||
// check proof in runtime
|
// check proof in runtime
|
||||||
let checker = <StorageProofChecker<Blake2Hasher>>::new(root, proof.clone()).unwrap();
|
let 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"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"key2"), Ok(Some(b"value2".to_vec())));
|
||||||
assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable));
|
assert_eq!(checker.read_value(b"key11111"), Err(Error::StorageValueUnavailable));
|
||||||
@@ -115,7 +106,7 @@ pub mod tests {
|
|||||||
|
|
||||||
// checking proof against invalid commitment fails
|
// checking proof against invalid commitment fails
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
<StorageProofChecker<Blake2Hasher>>::new(H256::random(), proof).err(),
|
<StorageProofChecker<sp_core::Blake2Hasher>>::new(H256::random(), proof).err(),
|
||||||
Some(Error::StorageRootMismatch)
|
Some(Error::StorageRootMismatch)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user