Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions modules/parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;

Expand Down Expand Up @@ -165,8 +166,14 @@ pub mod pallet {

/// Parachain heads which have been imported into the pallet.
#[pallet::storage]
pub type ImportedParaHeads<T: Config<I>, I: 'static = ()> =
StorageDoubleMap<_, Blake2_128Concat, ParaId, Blake2_128Concat, ParaHash, ParaHead>;
pub type ImportedParaHeads<T: Config<I>, I: 'static = ()> = StorageDoubleMap<
_,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Hasher1,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key1,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Hasher2,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Key2,
<ImportedParaHeadsKeyProvider as StorageDoubleMapKeyProvider>::Value,
>;

/// A ring buffer of imported parachain head hashes. Ordered by the insertion time.
#[pallet::storage]
Expand Down Expand Up @@ -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,
};
Expand Down Expand Up @@ -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,
);
Expand Down
25 changes: 12 additions & 13 deletions primitives/parachains/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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::<Blake2_128Concat, Blake2_128Concat>(
bridge_parachains_pallet_name,
"ImportedParaHeads",
&para_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;
}
75 changes: 43 additions & 32 deletions primitives/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,38 +246,6 @@ pub fn storage_map_final_key<H: StorageHasher>(
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<H1: StorageHasher, H2: StorageHasher>(
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.
///
Expand All @@ -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 {
Expand Down
20 changes: 19 additions & 1 deletion relays/client-substrate/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -380,6 +380,24 @@ impl<C: Chain> Client<C> {
.transpose()
}

/// Read `DoubleMapStorage` value from runtime storage.
pub async fn storage_double_map_value<T: StorageDoubleMapKeyProvider>(
&self,
pallet_prefix: &str,
key1: &T::Key1,
key2: &T::Key2,
block_hash: Option<C::Hash>,
) -> Result<Option<T::Value>> {
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,
Expand Down
13 changes: 6 additions & 7 deletions relays/lib-substrate-relay/src/parachains/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,11 @@ where
)))
}

let mut para_hash_at_source = ParaHashAtSource::None;
let mut para_header_number_at_source = None;
let para_hash_at_source = match self.on_chain_parachain_header(at_block, para_id).await? {
match self.on_chain_parachain_header(at_block, para_id).await? {
Some(parachain_header) => {
let mut parachain_head = ParaHashAtSource::Some(parachain_header.hash());
para_hash_at_source = ParaHashAtSource::Some(parachain_header.hash());
para_header_number_at_source = Some(*parachain_header.number());
// never return head that is larger than requested. This way we'll never sync
// headers past `maximal_header_id`
Expand All @@ -130,21 +131,19 @@ where
{
// we don't want this header yet => let's report previously requested
// header
parachain_head = ParaHashAtSource::Some(maximal_header_id.1);
para_hash_at_source = ParaHashAtSource::Some(maximal_header_id.1);
para_header_number_at_source = Some(maximal_header_id.0);
},
Some(_) => (),
None => {
// on-demand relay has not yet asked us to sync anything let's do that
parachain_head = ParaHashAtSource::Unavailable;
para_hash_at_source = ParaHashAtSource::Unavailable;
para_header_number_at_source = None;
},
}
}

parachain_head
},
None => ParaHashAtSource::None,
None => {},
};

if let (Some(metrics), Some(para_header_number_at_source)) =
Expand Down
57 changes: 30 additions & 27 deletions relays/lib-substrate-relay/src/parachains/target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -131,32 +130,36 @@ where
let best_para_head_hash: Option<BestParaHeadHash> =
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::<ParaHead>(imported_para_head_key, Some(at_block.1))
.await?
.and_then(|h| match HeaderOf::<P::SourceParachain>::decode(&mut &h.0[..]) {
Ok(header) => Some(header),
Err(e) => {
log::error!(
target: "bridge-metrics",
"Failed to decode {} parachain header at {}: {:?}. Metric will have obsolete value",
P::SourceParachain::NAME,
P::TargetChain::NAME,
e,
);

None
},
});
if let Some(imported_para_header) = imported_para_header {
.storage_double_map_value::<ImportedParaHeadsKeyProvider>(
P::SourceRelayChain::PARACHAINS_FINALITY_PALLET_NAME,
&para_id,
&best_para_head_hash.head_hash,
Some(at_block.1),
)
.await
.and_then(|maybe_encoded_head| match maybe_encoded_head {
Some(encoded_head) =>
HeaderOf::<P::SourceParachain>::decode(&mut &encoded_head.0[..])
.map(|head| Some(head))
.map_err(Self::Error::ResponseParseFailed),
None => Ok(None),
})
.map_err(|e| {
log::error!(
target: "bridge-metrics",
"Failed to read or decode {} parachain header at {}: {:?}. Metric will have obsolete value",
P::SourceParachain::NAME,
P::TargetChain::NAME,
e,
);
e
})
.unwrap_or(None);
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());
}
}

Expand Down