From cd36d1e15fa397e9dca9300fd963bd303e7ff9f9 Mon Sep 17 00:00:00 2001 From: Serban Iorga Date: Tue, 26 Jul 2022 22:50:04 +0300 Subject: [PATCH] Define StorageDoubleMapKeyProvider Signed-off-by: Serban Iorga --- bridges/modules/parachains/src/lib.rs | 22 ++++-- bridges/primitives/parachains/src/lib.rs | 25 +++---- bridges/primitives/runtime/src/lib.rs | 75 +++++++++++-------- bridges/relays/client-substrate/src/client.rs | 20 ++++- .../src/parachains/target.rs | 23 +++--- 5 files changed, 100 insertions(+), 65 deletions(-) diff --git a/bridges/modules/parachains/src/lib.rs b/bridges/modules/parachains/src/lib.rs index 7d12ee34e0..3cf0e60e3c 100644 --- a/bridges/modules/parachains/src/lib.rs +++ b/bridges/modules/parachains/src/lib.rs @@ -80,7 +80,8 @@ struct UpdateParachainHeadArtifacts { #[frame_support::pallet] pub mod pallet { use super::*; - use bp_runtime::{BasicOperatingMode, OwnedBridgeModule}; + use bp_parachains::ImportedParaHeadsKeyProvider; + use bp_runtime::{BasicOperatingMode, OwnedBridgeModule, StorageDoubleMapKeyProvider}; use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; @@ -165,8 +166,14 @@ pub mod pallet { /// Parachain heads which have been imported into the pallet. #[pallet::storage] - pub type ImportedParaHeads, I: 'static = ()> = - StorageDoubleMap<_, Blake2_128Concat, ParaId, Blake2_128Concat, ParaHash, ParaHead>; + pub type ImportedParaHeads, I: 'static = ()> = StorageDoubleMap< + _, + ::Hasher1, + ::Key1, + ::Hasher2, + ::Key2, + ::Value, + >; /// A ring buffer of imported parachain head hashes. Ordered by the insertion time. #[pallet::storage] @@ -513,7 +520,8 @@ mod tests { run_test, test_relay_header, Origin, TestRuntime, PARAS_PALLET_NAME, UNTRACKED_PARACHAIN_ID, }; - use bp_runtime::{BasicOperatingMode, OwnedBridgeModuleError}; + use bp_parachains::ImportedParaHeadsKeyProvider; + use bp_runtime::{BasicOperatingMode, OwnedBridgeModuleError, StorageDoubleMapKeyProvider}; use bp_test_utils::{ authority_list, generate_owned_bridge_module_tests, make_default_justification, }; @@ -985,10 +993,10 @@ mod tests { ParaHash::from([21u8; 32]) ) .to_vec(), - bp_parachains::imported_parachain_head_storage_key_at_target( + ImportedParaHeadsKeyProvider::final_key( "Parachains", - ParaId(42), - ParaHash::from([21u8; 32]) + &ParaId(42), + &ParaHash::from([21u8; 32]) ) .0, ); diff --git a/bridges/primitives/parachains/src/lib.rs b/bridges/primitives/parachains/src/lib.rs index 791d2bd47f..e6c9360d59 100644 --- a/bridges/primitives/parachains/src/lib.rs +++ b/bridges/primitives/parachains/src/lib.rs @@ -19,9 +19,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use bp_polkadot_core::{ - parachains::{ParaHash, ParaId}, + parachains::{ParaHash, ParaHead, ParaId}, BlockNumber as RelayBlockNumber, }; +use bp_runtime::StorageDoubleMapKeyProvider; use codec::{Decode, Encode}; use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat}; use scale_info::TypeInfo; @@ -67,18 +68,16 @@ pub fn best_parachain_head_hash_storage_key_at_target( ) } -/// Returns runtime storage key of the parachain head with given hash at the target chain. +/// Can be use to access the runtime storage key of the parachain head at the target chain. /// /// The head is stored by the `pallet-bridge-parachains` pallet in the `ImportedParaHeads` map. -pub fn imported_parachain_head_storage_key_at_target( - bridge_parachains_pallet_name: &str, - para_id: ParaId, - head_hash: ParaHash, -) -> StorageKey { - bp_runtime::storage_double_map_final_key::( - bridge_parachains_pallet_name, - "ImportedParaHeads", - ¶_id.encode(), - &head_hash.encode(), - ) +pub struct ImportedParaHeadsKeyProvider; +impl StorageDoubleMapKeyProvider for ImportedParaHeadsKeyProvider { + const MAP_NAME: &'static str = "ImportedParaHeads"; + + type Hasher1 = Blake2_128Concat; + type Key1 = ParaId; + type Hasher2 = Blake2_128Concat; + type Key2 = ParaHash; + type Value = ParaHead; } diff --git a/bridges/primitives/runtime/src/lib.rs b/bridges/primitives/runtime/src/lib.rs index 9807fa5086..ae7250c49b 100644 --- a/bridges/primitives/runtime/src/lib.rs +++ b/bridges/primitives/runtime/src/lib.rs @@ -246,38 +246,6 @@ pub fn storage_map_final_key( StorageKey(final_key) } -/// This is a copy of the -/// `frame_support::storage::generator::StorageDoubleMap::storage_double_map_final_key` for maps -/// based on selected hashers. -/// -/// 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. -pub fn storage_double_map_final_key( - pallet_prefix: &str, - map_name: &str, - key1: &[u8], - key2: &[u8], -) -> StorageKey { - let key1_hashed = H1::hash(key1); - let key2_hashed = H2::hash(key2); - 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() + - 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) -} - /// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false; /// }`) is computed. /// @@ -304,6 +272,49 @@ pub fn storage_value_key(pallet_prefix: &str, value_name: &str) -> StorageKey { StorageKey(final_key) } +/// 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, TypeInfo, PalletError)] pub enum OwnedBridgeModuleError { diff --git a/bridges/relays/client-substrate/src/client.rs b/bridges/relays/client-substrate/src/client.rs index e5309bb54e..9ba16b76f2 100644 --- a/bridges/relays/client-substrate/src/client.rs +++ b/bridges/relays/client-substrate/src/client.rs @@ -25,7 +25,7 @@ use crate::{ use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; -use bp_runtime::HeaderIdProvider; +use bp_runtime::{HeaderIdProvider, StorageDoubleMapKeyProvider}; use codec::{Decode, Encode}; use frame_system::AccountInfo; use futures::{SinkExt, StreamExt}; @@ -380,6 +380,24 @@ impl Client { .transpose() } + /// Read `DoubleMapStorage` value from runtime storage. + pub async fn storage_double_map_value( + &self, + pallet_prefix: &str, + key1: &T::Key1, + key2: &T::Key2, + block_hash: Option, + ) -> Result> { + let storage_key = T::final_key(pallet_prefix, key1, key2); + + self.raw_storage_value(storage_key, block_hash) + .await? + .map(|encoded_value| { + T::Value::decode(&mut &encoded_value.0[..]).map_err(Error::ResponseParseFailed) + }) + .transpose() + } + /// Read raw value from runtime storage. pub async fn raw_storage_value( &self, diff --git a/bridges/relays/lib-substrate-relay/src/parachains/target.rs b/bridges/relays/lib-substrate-relay/src/parachains/target.rs index 43168f2c85..b34cbc2eb1 100644 --- a/bridges/relays/lib-substrate-relay/src/parachains/target.rs +++ b/bridges/relays/lib-substrate-relay/src/parachains/target.rs @@ -25,10 +25,9 @@ use crate::{ use async_trait::async_trait; use bp_parachains::{ - best_parachain_head_hash_storage_key_at_target, imported_parachain_head_storage_key_at_target, - BestParaHeadHash, + best_parachain_head_hash_storage_key_at_target, BestParaHeadHash, ImportedParaHeadsKeyProvider, }; -use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId}; +use bp_polkadot_core::parachains::{ParaHash, ParaHeadsProof, ParaId}; use bp_runtime::HeaderIdProvider; use codec::{Decode, Encode}; use parachains_relay::{ @@ -131,14 +130,14 @@ where let best_para_head_hash: Option = self.client.storage_value(best_para_head_hash_key, Some(at_block.1)).await?; if let (Some(metrics), &Some(ref best_para_head_hash)) = (metrics, &best_para_head_hash) { - let imported_para_head_key = imported_parachain_head_storage_key_at_target( - P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME, - para_id, - best_para_head_hash.head_hash, - ); - let imported_para_header = self + let imported_para_head = self .client - .storage_value::(imported_para_head_key, Some(at_block.1)) + .storage_double_map_value::( + P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME, + ¶_id, + &best_para_head_hash.head_hash, + Some(at_block.1), + ) .await? .and_then(|h| match HeaderOf::::decode(&mut &h.0[..]) { Ok(header) => Some(header), @@ -154,9 +153,9 @@ where None }, }); - if let Some(imported_para_header) = imported_para_header { + if let Some(imported_para_head) = imported_para_head { metrics - .update_best_parachain_block_at_target(para_id, *imported_para_header.number()); + .update_best_parachain_block_at_target(para_id, *imported_para_head.number()); } }