mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 18:41:03 +00:00
Parachains finality relay (#1199)
This commit is contained in:
committed by
Bastian Köcher
parent
f64357e7e8
commit
03c2f06a27
@@ -26,6 +26,7 @@ bp-westend = { path = "../../../primitives/chain-westend", default-features = fa
|
|||||||
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
|
bridge-runtime-common = { path = "../../runtime-common", default-features = false }
|
||||||
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
|
pallet-bridge-grandpa = { path = "../../../modules/grandpa", default-features = false }
|
||||||
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
|
pallet-bridge-messages = { path = "../../../modules/messages", default-features = false }
|
||||||
|
pallet-bridge-parachains = { path = "../../../modules/parachains", default-features = false }
|
||||||
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
pallet-shift-session-manager = { path = "../../../modules/shift-session-manager", default-features = false }
|
||||||
|
|
||||||
# Substrate Dependencies
|
# Substrate Dependencies
|
||||||
@@ -102,6 +103,7 @@ std = [
|
|||||||
"pallet-beefy-mmr/std",
|
"pallet-beefy-mmr/std",
|
||||||
"pallet-bridge-grandpa/std",
|
"pallet-bridge-grandpa/std",
|
||||||
"pallet-bridge-messages/std",
|
"pallet-bridge-messages/std",
|
||||||
|
"pallet-bridge-parachains/std",
|
||||||
"pallet-grandpa/std",
|
"pallet-grandpa/std",
|
||||||
"pallet-mmr/std",
|
"pallet-mmr/std",
|
||||||
"pallet-randomness-collective-flip/std",
|
"pallet-randomness-collective-flip/std",
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ pub use frame_system::Call as SystemCall;
|
|||||||
pub use pallet_balances::Call as BalancesCall;
|
pub use pallet_balances::Call as BalancesCall;
|
||||||
pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall;
|
pub use pallet_bridge_grandpa::Call as BridgeGrandpaCall;
|
||||||
pub use pallet_bridge_messages::Call as MessagesCall;
|
pub use pallet_bridge_messages::Call as MessagesCall;
|
||||||
|
pub use pallet_bridge_parachains::Call as BridgeParachainsCall;
|
||||||
pub use pallet_sudo::Call as SudoCall;
|
pub use pallet_sudo::Call as SudoCall;
|
||||||
pub use pallet_timestamp::Call as TimestampCall;
|
pub use pallet_timestamp::Call as TimestampCall;
|
||||||
|
|
||||||
@@ -461,6 +462,19 @@ impl pallet_bridge_messages::Config<WithRialtoMessagesInstance> for Runtime {
|
|||||||
type BridgedChainId = RialtoChainId;
|
type BridgedChainId = RialtoChainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parameter_types! {
|
||||||
|
pub const RialtoParasPalletName: &'static str = bp_rialto::PARAS_PALLET_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Instance of the with-Rialto parachains token swap pallet.
|
||||||
|
pub type WitRialtoParachainsInstance = ();
|
||||||
|
|
||||||
|
impl pallet_bridge_parachains::Config<WitRialtoParachainsInstance> for Runtime {
|
||||||
|
type BridgesGrandpaPalletInstance = RialtoGrandpaInstance;
|
||||||
|
type ParasPalletName = RialtoParasPalletName;
|
||||||
|
type HeadsToKeep = HeadersToKeep;
|
||||||
|
}
|
||||||
|
|
||||||
construct_runtime!(
|
construct_runtime!(
|
||||||
pub enum Runtime where
|
pub enum Runtime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
@@ -495,6 +509,9 @@ construct_runtime!(
|
|||||||
// Westend bridge modules.
|
// Westend bridge modules.
|
||||||
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
|
BridgeWestendGrandpa: pallet_bridge_grandpa::<Instance1>::{Pallet, Call, Config<T>, Storage},
|
||||||
|
|
||||||
|
// Rialto parachains bridge modules.
|
||||||
|
BridgeRialtoParachains: pallet_bridge_parachains::{Pallet, Call, Storage},
|
||||||
|
|
||||||
// Pallet for sending XCM.
|
// Pallet for sending XCM.
|
||||||
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
|
XcmPallet: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config} = 99,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ serde = { version = "1.0.101", optional = true }
|
|||||||
|
|
||||||
# Bridge Dependencies
|
# Bridge Dependencies
|
||||||
|
|
||||||
|
bp-parachains = { path = "../../primitives/parachains", default-features = false }
|
||||||
bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false }
|
bp-polkadot-core = { path = "../../primitives/polkadot-core", default-features = false }
|
||||||
bp-runtime = { path = "../../primitives/runtime", default-features = false }
|
bp-runtime = { path = "../../primitives/runtime", default-features = false }
|
||||||
pallet-bridge-grandpa = { path = "../grandpa", default-features = false }
|
pallet-bridge-grandpa = { path = "../grandpa", default-features = false }
|
||||||
@@ -34,6 +35,7 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
|||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = [
|
std = [
|
||||||
|
"bp-parachains/std",
|
||||||
"bp-polkadot-core/std",
|
"bp-polkadot-core/std",
|
||||||
"bp-runtime/std",
|
"bp-runtime/std",
|
||||||
"codec/std",
|
"codec/std",
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaId, ParachainHeadsProof};
|
use bp_parachains::parachain_head_storage_key_at_source;
|
||||||
|
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||||
use codec::{Decode, Encode};
|
use codec::{Decode, Encode};
|
||||||
use frame_support::RuntimeDebug;
|
use frame_support::RuntimeDebug;
|
||||||
use scale_info::TypeInfo;
|
use scale_info::TypeInfo;
|
||||||
@@ -73,12 +74,16 @@ pub mod pallet {
|
|||||||
pub trait Config<I: 'static = ()>:
|
pub trait Config<I: 'static = ()>:
|
||||||
pallet_bridge_grandpa::Config<Self::BridgesGrandpaPalletInstance>
|
pallet_bridge_grandpa::Config<Self::BridgesGrandpaPalletInstance>
|
||||||
{
|
{
|
||||||
/// Instance of bridges GRANDPA pallet that this pallet is linked to.
|
/// Instance of bridges GRANDPA pallet (within this runtime) that this pallet is linked to.
|
||||||
///
|
///
|
||||||
/// The GRANDPA pallet instance must be configured to import headers of relay chain that
|
/// The GRANDPA pallet instance must be configured to import headers of relay chain that
|
||||||
/// we're interested in.
|
/// we're interested in.
|
||||||
type BridgesGrandpaPalletInstance: 'static;
|
type BridgesGrandpaPalletInstance: 'static;
|
||||||
|
|
||||||
|
/// Name of the `paras` pallet in the `construct_runtime!()` call at the bridged chain.
|
||||||
|
#[pallet::constant]
|
||||||
|
type ParasPalletName: Get<&'static str>;
|
||||||
|
|
||||||
/// Maximal number of single parachain heads to keep in the storage.
|
/// Maximal number of single parachain heads to keep in the storage.
|
||||||
///
|
///
|
||||||
/// The setting is there to prevent growing the on-chain state indefinitely. Note
|
/// The setting is there to prevent growing the on-chain state indefinitely. Note
|
||||||
@@ -129,7 +134,7 @@ pub mod pallet {
|
|||||||
_origin: OriginFor<T>,
|
_origin: OriginFor<T>,
|
||||||
relay_block_hash: RelayBlockHash,
|
relay_block_hash: RelayBlockHash,
|
||||||
parachains: Vec<ParaId>,
|
parachains: Vec<ParaId>,
|
||||||
parachain_heads_proof: ParachainHeadsProof,
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
) -> DispatchResult {
|
) -> DispatchResult {
|
||||||
// we'll need relay chain header to verify that parachains heads are always increasing.
|
// we'll need relay chain header to verify that parachains heads are always increasing.
|
||||||
let relay_block = pallet_bridge_grandpa::ImportedHeaders::<
|
let relay_block = pallet_bridge_grandpa::ImportedHeaders::<
|
||||||
@@ -190,7 +195,8 @@ pub mod pallet {
|
|||||||
storage: &bp_runtime::StorageProofChecker<RelayBlockHasher>,
|
storage: &bp_runtime::StorageProofChecker<RelayBlockHasher>,
|
||||||
parachain: ParaId,
|
parachain: ParaId,
|
||||||
) -> Option<ParaHead> {
|
) -> Option<ParaHead> {
|
||||||
let parachain_head_key = storage_keys::parachain_head_key(parachain);
|
let parachain_head_key =
|
||||||
|
parachain_head_storage_key_at_source(T::ParasPalletName::get(), parachain);
|
||||||
let parachain_head = storage.read_value(parachain_head_key.0.as_ref()).ok()??;
|
let parachain_head = storage.read_value(parachain_head_key.0.as_ref()).ok()??;
|
||||||
let parachain_head = ParaHead::decode(&mut ¶chain_head[..]).ok()?;
|
let parachain_head = ParaHead::decode(&mut ¶chain_head[..]).ok()?;
|
||||||
Some(parachain_head)
|
Some(parachain_head)
|
||||||
@@ -257,6 +263,12 @@ pub mod pallet {
|
|||||||
updated_head_hash,
|
updated_head_hash,
|
||||||
);
|
);
|
||||||
ImportedParaHeads::<T, I>::insert(parachain, updated_head_hash, updated_head);
|
ImportedParaHeads::<T, I>::insert(parachain, updated_head_hash, updated_head);
|
||||||
|
log::trace!(
|
||||||
|
target: "runtime::bridge-parachains",
|
||||||
|
"Updated head of parachain {:?} to {}",
|
||||||
|
parachain,
|
||||||
|
updated_head_hash,
|
||||||
|
);
|
||||||
|
|
||||||
// remove old head
|
// remove old head
|
||||||
if let Ok(head_hash_to_prune) = head_hash_to_prune {
|
if let Ok(head_hash_to_prune) = head_hash_to_prune {
|
||||||
@@ -274,22 +286,10 @@ pub mod pallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod storage_keys {
|
|
||||||
use super::*;
|
|
||||||
use bp_runtime::storage_map_final_key;
|
|
||||||
use frame_support::Twox64Concat;
|
|
||||||
use sp_core::storage::StorageKey;
|
|
||||||
|
|
||||||
/// Storage key of the parachain head in the runtime storage of relay chain.
|
|
||||||
pub fn parachain_head_key(parachain: ParaId) -> StorageKey {
|
|
||||||
storage_map_final_key::<Twox64Concat>("Paras", "Heads", ¶chain.encode())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::mock::{run_test, test_relay_header, Origin, TestRuntime};
|
use crate::mock::{run_test, test_relay_header, Origin, TestRuntime, PARAS_PALLET_NAME};
|
||||||
|
|
||||||
use bp_test_utils::{authority_list, make_default_justification};
|
use bp_test_utils::{authority_list, make_default_justification};
|
||||||
use frame_support::{assert_noop, assert_ok, traits::OnInitialize};
|
use frame_support::{assert_noop, assert_ok, traits::OnInitialize};
|
||||||
@@ -330,13 +330,14 @@ mod tests {
|
|||||||
|
|
||||||
fn prepare_parachain_heads_proof(
|
fn prepare_parachain_heads_proof(
|
||||||
heads: Vec<(ParaId, ParaHead)>,
|
heads: Vec<(ParaId, ParaHead)>,
|
||||||
) -> (RelayBlockHash, ParachainHeadsProof) {
|
) -> (RelayBlockHash, ParaHeadsProof) {
|
||||||
let mut root = Default::default();
|
let mut root = Default::default();
|
||||||
let mut mdb = MemoryDB::default();
|
let mut mdb = MemoryDB::default();
|
||||||
{
|
{
|
||||||
let mut trie = TrieDBMutV1::<RelayBlockHasher>::new(&mut mdb, &mut root);
|
let mut trie = TrieDBMutV1::<RelayBlockHasher>::new(&mut mdb, &mut root);
|
||||||
for (parachain, head) in heads {
|
for (parachain, head) in heads {
|
||||||
let storage_key = storage_keys::parachain_head_key(parachain);
|
let storage_key =
|
||||||
|
parachain_head_storage_key_at_source(PARAS_PALLET_NAME, parachain);
|
||||||
trie.insert(&storage_key.0, &head.encode())
|
trie.insert(&storage_key.0, &head.encode())
|
||||||
.map_err(|_| "TrieMut::insert has failed")
|
.map_err(|_| "TrieMut::insert has failed")
|
||||||
.expect("TrieMut::insert should not fail in tests");
|
.expect("TrieMut::insert should not fail in tests");
|
||||||
@@ -372,7 +373,7 @@ mod tests {
|
|||||||
fn import_parachain_1_head(
|
fn import_parachain_1_head(
|
||||||
relay_chain_block: RelayBlockNumber,
|
relay_chain_block: RelayBlockNumber,
|
||||||
relay_state_root: RelayBlockHash,
|
relay_state_root: RelayBlockHash,
|
||||||
proof: ParachainHeadsProof,
|
proof: ParaHeadsProof,
|
||||||
) -> sp_runtime::DispatchResult {
|
) -> sp_runtime::DispatchResult {
|
||||||
Pallet::<TestRuntime>::submit_parachain_heads(
|
Pallet::<TestRuntime>::submit_parachain_heads(
|
||||||
Origin::signed(1),
|
Origin::signed(1),
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ pub type RelayBlockHeader =
|
|||||||
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
type Block = frame_system::mocking::MockBlock<TestRuntime>;
|
||||||
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
|
type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<TestRuntime>;
|
||||||
|
|
||||||
|
pub const PARAS_PALLET_NAME: &str = "Paras";
|
||||||
|
|
||||||
construct_runtime! {
|
construct_runtime! {
|
||||||
pub enum TestRuntime where
|
pub enum TestRuntime where
|
||||||
Block = Block,
|
Block = Block,
|
||||||
@@ -103,10 +105,12 @@ impl pallet_bridge_grandpa::Config<pallet_bridge_grandpa::Instance2> for TestRun
|
|||||||
|
|
||||||
parameter_types! {
|
parameter_types! {
|
||||||
pub const HeadsToKeep: u32 = 4;
|
pub const HeadsToKeep: u32 = 4;
|
||||||
|
pub const ParasPalletName: &'static str = PARAS_PALLET_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl pallet_bridge_parachains::Config for TestRuntime {
|
impl pallet_bridge_parachains::Config for TestRuntime {
|
||||||
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
|
type BridgesGrandpaPalletInstance = pallet_bridge_grandpa::Instance1;
|
||||||
|
type ParasPalletName = ParasPalletName;
|
||||||
type HeadsToKeep = HeadsToKeep;
|
type HeadsToKeep = HeadsToKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -269,6 +269,9 @@ pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages";
|
|||||||
/// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime.
|
/// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime.
|
||||||
pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate";
|
pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate";
|
||||||
|
|
||||||
|
/// Name of the With-Rialto parachains bridge pallet name in the Millau runtime.
|
||||||
|
pub const BRIDGE_PARAS_PALLET_NAME: &str = "BridgeRialtoParachains";
|
||||||
|
|
||||||
/// Name of the `MillauFinalityApi::best_finalized` runtime method.
|
/// Name of the `MillauFinalityApi::best_finalized` runtime method.
|
||||||
pub const BEST_FINALIZED_MILLAU_HEADER_METHOD: &str = "MillauFinalityApi_best_finalized";
|
pub const BEST_FINALIZED_MILLAU_HEADER_METHOD: &str = "MillauFinalityApi_best_finalized";
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
[package]
|
||||||
|
name = "bp-parachains"
|
||||||
|
description = "Primitives of parachains module."
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive"] }
|
||||||
|
scale-info = { version = "2.1.1", default-features = false, features = ["derive"] }
|
||||||
|
serde = { version = "1.0", optional = true, features = ["derive"] }
|
||||||
|
|
||||||
|
# Bridge dependencies
|
||||||
|
|
||||||
|
bp-polkadot-core = { path = "../polkadot-core", default-features = false }
|
||||||
|
bp-runtime = { path = "../runtime", default-features = false }
|
||||||
|
|
||||||
|
# Substrate dependencies
|
||||||
|
|
||||||
|
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = [
|
||||||
|
"bp-polkadot-core/std",
|
||||||
|
"bp-runtime/std",
|
||||||
|
"codec/std",
|
||||||
|
"frame-support/std",
|
||||||
|
"scale-info/std",
|
||||||
|
"serde",
|
||||||
|
"sp-core/std",
|
||||||
|
]
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright 2019-2021 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 of parachains module.
|
||||||
|
|
||||||
|
#![cfg_attr(not(feature = "std"), no_std)]
|
||||||
|
|
||||||
|
use bp_polkadot_core::{
|
||||||
|
parachains::{ParaHash, ParaId},
|
||||||
|
BlockNumber as RelayBlockNumber,
|
||||||
|
};
|
||||||
|
use codec::{Decode, Encode};
|
||||||
|
use frame_support::{Blake2_128Concat, RuntimeDebug, Twox64Concat};
|
||||||
|
use scale_info::TypeInfo;
|
||||||
|
use sp_core::storage::StorageKey;
|
||||||
|
|
||||||
|
/// Best known parachain head hash.
|
||||||
|
#[derive(Clone, Decode, Encode, PartialEq, RuntimeDebug, TypeInfo)]
|
||||||
|
pub struct BestParaHeadHash {
|
||||||
|
/// Number of relay block where this head has been read.
|
||||||
|
///
|
||||||
|
/// Parachain head is opaque to relay chain. So we can't simply decode it as a header of
|
||||||
|
/// parachains and call `block_number()` on it. Instead, we're using the fact that parachain
|
||||||
|
/// head is always built on top of previous head (because it is blockchain) and relay chain
|
||||||
|
/// always imports parachain heads in order. What it means for us is that at any given
|
||||||
|
/// **finalized** relay block `B`, head of parachain will be ancestor (or the same) of all
|
||||||
|
/// parachain heads available at descendants of `B`.
|
||||||
|
pub at_relay_block_number: RelayBlockNumber,
|
||||||
|
/// Hash of parachain head.
|
||||||
|
pub head_hash: ParaHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns runtime storage key of given parachain head at the source chain.
|
||||||
|
///
|
||||||
|
/// The head is stored by the `paras` pallet in the `Heads` map.
|
||||||
|
pub fn parachain_head_storage_key_at_source(
|
||||||
|
paras_pallet_name: &str,
|
||||||
|
para_id: ParaId,
|
||||||
|
) -> StorageKey {
|
||||||
|
bp_runtime::storage_map_final_key::<Twox64Concat>(paras_pallet_name, "Heads", ¶_id.encode())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns runtime storage key of best known parachain head at the target chain.
|
||||||
|
///
|
||||||
|
/// The head is stored by the `pallet-bridge-parachains` pallet in the `BestParaHeads` map.
|
||||||
|
pub fn parachain_head_storage_key_at_target(
|
||||||
|
bridge_parachains_pallet_name: &str,
|
||||||
|
para_id: ParaId,
|
||||||
|
) -> StorageKey {
|
||||||
|
bp_runtime::storage_map_final_key::<Blake2_128Concat>(
|
||||||
|
bridge_parachains_pallet_name,
|
||||||
|
"BestParaHeads",
|
||||||
|
¶_id.encode(),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -79,4 +79,4 @@ impl ParaHead {
|
|||||||
pub type ParaHash = crate::Hash;
|
pub type ParaHash = crate::Hash;
|
||||||
|
|
||||||
/// Raw storage proof of parachain heads, stored in polkadot-like chain runtime.
|
/// Raw storage proof of parachain heads, stored in polkadot-like chain runtime.
|
||||||
pub type ParachainHeadsProof = Vec<Vec<u8>>;
|
pub type ParaHeadsProof = Vec<Vec<u8>>;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ bp-kusama = { path = "../../primitives/chain-kusama" }
|
|||||||
bp-messages = { path = "../../primitives/messages" }
|
bp-messages = { path = "../../primitives/messages" }
|
||||||
bp-millau = { path = "../../primitives/chain-millau" }
|
bp-millau = { path = "../../primitives/chain-millau" }
|
||||||
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
||||||
|
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||||
bp-rialto = { path = "../../primitives/chain-rialto" }
|
bp-rialto = { path = "../../primitives/chain-rialto" }
|
||||||
bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" }
|
bp-rialto-parachain = { path = "../../primitives/chain-rialto-parachain" }
|
||||||
bp-rococo = { path = "../../primitives/chain-rococo" }
|
bp-rococo = { path = "../../primitives/chain-rococo" }
|
||||||
@@ -39,6 +40,7 @@ messages-relay = { path = "../messages" }
|
|||||||
millau-runtime = { path = "../../bin/millau/runtime" }
|
millau-runtime = { path = "../../bin/millau/runtime" }
|
||||||
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
|
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
|
||||||
pallet-bridge-messages = { path = "../../modules/messages" }
|
pallet-bridge-messages = { path = "../../modules/messages" }
|
||||||
|
parachains-relay = { path = "../parachains" }
|
||||||
relay-kusama-client = { path = "../client-kusama" }
|
relay-kusama-client = { path = "../client-kusama" }
|
||||||
relay-millau-client = { path = "../client-millau" }
|
relay-millau-client = { path = "../client-millau" }
|
||||||
relay-polkadot-client = { path = "../client-polkadot" }
|
relay-polkadot-client = { path = "../client-polkadot" }
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ pub mod polkadot_headers_to_kusama;
|
|||||||
pub mod polkadot_messages_to_kusama;
|
pub mod polkadot_messages_to_kusama;
|
||||||
pub mod rialto_headers_to_millau;
|
pub mod rialto_headers_to_millau;
|
||||||
pub mod rialto_messages_to_millau;
|
pub mod rialto_messages_to_millau;
|
||||||
|
pub mod rialto_parachains_to_millau;
|
||||||
pub mod rococo_headers_to_wococo;
|
pub mod rococo_headers_to_wococo;
|
||||||
pub mod rococo_messages_to_wococo;
|
pub mod rococo_messages_to_wococo;
|
||||||
pub mod westend_headers_to_millau;
|
pub mod westend_headers_to_millau;
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
// Copyright 2019-2021 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/>.
|
||||||
|
|
||||||
|
//! Rialto-to-Millau parachains sync entrypoint.
|
||||||
|
|
||||||
|
use parachains_relay::ParachainsPipeline;
|
||||||
|
use relay_millau_client::Millau;
|
||||||
|
use relay_rialto_client::Rialto;
|
||||||
|
use substrate_relay_helper::parachains_target::DirectSubmitParachainHeadsCallBuilder;
|
||||||
|
|
||||||
|
/// Rialto-to-Millau parachains sync description.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct RialtoToMillauParachains;
|
||||||
|
|
||||||
|
impl ParachainsPipeline for RialtoToMillauParachains {
|
||||||
|
type SourceChain = Rialto;
|
||||||
|
type TargetChain = Millau;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `submit_parachain_heads` call builder for Rialto-to-Millau parachains sync pipeline.
|
||||||
|
pub type RialtoToMillauParachainsSubmitParachainHeadsCallBuilder =
|
||||||
|
DirectSubmitParachainHeadsCallBuilder<
|
||||||
|
RialtoToMillauParachains,
|
||||||
|
millau_runtime::Runtime,
|
||||||
|
millau_runtime::WitRialtoParachainsInstance,
|
||||||
|
>;
|
||||||
@@ -36,6 +36,7 @@ mod reinit_bridge;
|
|||||||
mod relay_headers;
|
mod relay_headers;
|
||||||
mod relay_headers_and_messages;
|
mod relay_headers_and_messages;
|
||||||
mod relay_messages;
|
mod relay_messages;
|
||||||
|
mod relay_parachains;
|
||||||
mod resubmit_transactions;
|
mod resubmit_transactions;
|
||||||
|
|
||||||
/// Parse relay CLI args.
|
/// Parse relay CLI args.
|
||||||
@@ -85,6 +86,8 @@ pub enum Command {
|
|||||||
ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
|
ResubmitTransactions(resubmit_transactions::ResubmitTransactions),
|
||||||
/// Register parachain.
|
/// Register parachain.
|
||||||
RegisterParachain(register_parachain::RegisterParachain),
|
RegisterParachain(register_parachain::RegisterParachain),
|
||||||
|
///
|
||||||
|
RelayParachains(relay_parachains::RelayParachains),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Command {
|
impl Command {
|
||||||
@@ -118,6 +121,7 @@ impl Command {
|
|||||||
Self::EstimateFee(arg) => arg.run().await?,
|
Self::EstimateFee(arg) => arg.run().await?,
|
||||||
Self::ResubmitTransactions(arg) => arg.run().await?,
|
Self::ResubmitTransactions(arg) => arg.run().await?,
|
||||||
Self::RegisterParachain(arg) => arg.run().await?,
|
Self::RegisterParachain(arg) => arg.run().await?,
|
||||||
|
Self::RelayParachains(arg) => arg.run().await?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright 2019-2021 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 bp_polkadot_core::parachains::ParaId;
|
||||||
|
use parachains_relay::{parachains_loop::ParachainSyncParams, ParachainsPipeline};
|
||||||
|
use relay_utils::metrics::{GlobalMetrics, StandaloneMetric};
|
||||||
|
use structopt::StructOpt;
|
||||||
|
use strum::{EnumString, EnumVariantNames, VariantNames};
|
||||||
|
use substrate_relay_helper::{
|
||||||
|
parachains_source::ParachainsSource, parachains_target::ParachainsTarget, TransactionParams,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::cli::{
|
||||||
|
PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Start parachain heads relayer process.
|
||||||
|
#[derive(StructOpt)]
|
||||||
|
pub struct RelayParachains {
|
||||||
|
/// A bridge instance to relay parachains heads for.
|
||||||
|
#[structopt(possible_values = RelayParachainsBridge::VARIANTS, case_insensitive = true)]
|
||||||
|
bridge: RelayParachainsBridge,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
source: SourceConnectionParams,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
target: TargetConnectionParams,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
target_sign: TargetSigningParams,
|
||||||
|
#[structopt(flatten)]
|
||||||
|
prometheus_params: PrometheusParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parachain heads relay bridge.
|
||||||
|
#[derive(Debug, EnumString, EnumVariantNames)]
|
||||||
|
#[strum(serialize_all = "kebab_case")]
|
||||||
|
pub enum RelayParachainsBridge {
|
||||||
|
RialtoToMillau,
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! select_bridge {
|
||||||
|
($bridge: expr, $generic: tt) => {
|
||||||
|
match $bridge {
|
||||||
|
RelayParachainsBridge::RialtoToMillau => {
|
||||||
|
use crate::chains::rialto_parachains_to_millau::{
|
||||||
|
RialtoToMillauParachains as Pipeline,
|
||||||
|
RialtoToMillauParachainsSubmitParachainHeadsCallBuilder as SubmitParachainHeadsCallBuilder,
|
||||||
|
};
|
||||||
|
|
||||||
|
use bp_millau::BRIDGE_PARAS_PALLET_NAME as BRIDGE_PARAS_PALLET_NAME_AT_TARGET;
|
||||||
|
use bp_rialto::PARAS_PALLET_NAME as PARAS_PALLET_NAME_AT_SOURCE;
|
||||||
|
|
||||||
|
use relay_millau_client::Millau as TargetTransactionSignScheme;
|
||||||
|
|
||||||
|
$generic
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RelayParachains {
|
||||||
|
/// Run the command.
|
||||||
|
pub async fn run(self) -> anyhow::Result<()> {
|
||||||
|
select_bridge!(self.bridge, {
|
||||||
|
type SourceChain = <Pipeline as ParachainsPipeline>::SourceChain;
|
||||||
|
type TargetChain = <Pipeline as ParachainsPipeline>::TargetChain;
|
||||||
|
|
||||||
|
let source_client = self.source.to_client::<SourceChain>().await?;
|
||||||
|
let source_client = ParachainsSource::<Pipeline>::new(
|
||||||
|
source_client,
|
||||||
|
PARAS_PALLET_NAME_AT_SOURCE.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let taret_transaction_params = TransactionParams {
|
||||||
|
signer: self.target_sign.to_keypair::<TargetChain>()?,
|
||||||
|
mortality: self.target_sign.target_transactions_mortality,
|
||||||
|
};
|
||||||
|
let target_client = self.target.to_client::<TargetChain>().await?;
|
||||||
|
let target_client = ParachainsTarget::<
|
||||||
|
Pipeline,
|
||||||
|
TargetTransactionSignScheme,
|
||||||
|
SubmitParachainHeadsCallBuilder,
|
||||||
|
>::new(
|
||||||
|
target_client.clone(),
|
||||||
|
taret_transaction_params,
|
||||||
|
BRIDGE_PARAS_PALLET_NAME_AT_TARGET.into(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let metrics_params: relay_utils::metrics::MetricsParams = self.prometheus_params.into();
|
||||||
|
GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?;
|
||||||
|
|
||||||
|
parachains_relay::parachains_loop::run(
|
||||||
|
source_client,
|
||||||
|
target_client,
|
||||||
|
ParachainSyncParams {
|
||||||
|
parachains: vec![ParaId(2000)],
|
||||||
|
stall_timeout: std::time::Duration::from_secs(60),
|
||||||
|
strategy: parachains_relay::parachains_loop::ParachainSyncStrategy::Any,
|
||||||
|
},
|
||||||
|
metrics_params,
|
||||||
|
futures::future::pending(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(|e| anyhow::format_err!("{}", e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
|||||||
async-std = { version = "1.6.5", features = ["attributes"] }
|
async-std = { version = "1.6.5", features = ["attributes"] }
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
codec = { package = "parity-scale-codec", version = "3.0.0" }
|
codec = { package = "parity-scale-codec", version = "3.0.0" }
|
||||||
|
futures = "0.3.7"
|
||||||
jsonrpsee = { version = "0.8", features = ["macros", "ws-client"] }
|
jsonrpsee = { version = "0.8", features = ["macros", "ws-client"] }
|
||||||
log = "0.4.11"
|
log = "0.4.11"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
@@ -44,5 +45,6 @@ sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master
|
|||||||
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
|
|
||||||
#[dev-dependencies]
|
[features]
|
||||||
futures = "0.3.7"
|
default = []
|
||||||
|
test-helpers = []
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ impl<C: ChainWithBalances> Environment<C> for Client<C> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use frame_support::weights::{IdentityFee, Weight};
|
use crate::test_chain::TestChain;
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender},
|
||||||
future::FutureExt,
|
future::FutureExt,
|
||||||
@@ -204,49 +204,6 @@ mod tests {
|
|||||||
SinkExt,
|
SinkExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct TestChain;
|
|
||||||
|
|
||||||
impl bp_runtime::Chain for TestChain {
|
|
||||||
type BlockNumber = u32;
|
|
||||||
type Hash = sp_core::H256;
|
|
||||||
type Hasher = sp_runtime::traits::BlakeTwo256;
|
|
||||||
type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
|
|
||||||
|
|
||||||
type AccountId = u32;
|
|
||||||
type Balance = u32;
|
|
||||||
type Index = u32;
|
|
||||||
type Signature = sp_runtime::testing::TestSignature;
|
|
||||||
|
|
||||||
fn max_extrinsic_size() -> u32 {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
fn max_extrinsic_weight() -> Weight {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Chain for TestChain {
|
|
||||||
const NAME: &'static str = "Test";
|
|
||||||
const TOKEN_ID: Option<&'static str> = None;
|
|
||||||
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader";
|
|
||||||
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1);
|
|
||||||
const STORAGE_PROOF_OVERHEAD: u32 = 0;
|
|
||||||
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0;
|
|
||||||
|
|
||||||
type SignedBlock = sp_runtime::generic::SignedBlock<
|
|
||||||
sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>,
|
|
||||||
>;
|
|
||||||
type Call = ();
|
|
||||||
type WeightToFee = IdentityFee<u32>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ChainWithBalances for TestChain {
|
|
||||||
fn account_info_storage_key(_account_id: &u32) -> sp_core::storage::StorageKey {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TestEnvironment {
|
struct TestEnvironment {
|
||||||
runtime_version_rx: UnboundedReceiver<RuntimeVersion>,
|
runtime_version_rx: UnboundedReceiver<RuntimeVersion>,
|
||||||
free_native_balance_rx: UnboundedReceiver<u32>,
|
free_native_balance_rx: UnboundedReceiver<u32>,
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ mod sync_header;
|
|||||||
|
|
||||||
pub mod guard;
|
pub mod guard;
|
||||||
pub mod metrics;
|
pub mod metrics;
|
||||||
|
pub mod test_chain;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
// Copyright 2019-2021 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/>.
|
||||||
|
|
||||||
|
//! Pallet provides a set of guard functions that are running in background threads
|
||||||
|
//! and are aborting process if some condition fails.
|
||||||
|
|
||||||
|
//! Test chain implementation to use in tests.
|
||||||
|
|
||||||
|
#![cfg(any(feature = "test-helpers", test))]
|
||||||
|
|
||||||
|
use crate::{Chain, ChainWithBalances};
|
||||||
|
use frame_support::weights::{IdentityFee, Weight};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
/// Chain that may be used in tests.
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct TestChain;
|
||||||
|
|
||||||
|
impl bp_runtime::Chain for TestChain {
|
||||||
|
type BlockNumber = u32;
|
||||||
|
type Hash = sp_core::H256;
|
||||||
|
type Hasher = sp_runtime::traits::BlakeTwo256;
|
||||||
|
type Header = sp_runtime::generic::Header<u32, sp_runtime::traits::BlakeTwo256>;
|
||||||
|
|
||||||
|
type AccountId = u32;
|
||||||
|
type Balance = u32;
|
||||||
|
type Index = u32;
|
||||||
|
type Signature = sp_runtime::testing::TestSignature;
|
||||||
|
|
||||||
|
fn max_extrinsic_size() -> u32 {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn max_extrinsic_weight() -> Weight {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Chain for TestChain {
|
||||||
|
const NAME: &'static str = "Test";
|
||||||
|
const TOKEN_ID: Option<&'static str> = None;
|
||||||
|
const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "TestMethod";
|
||||||
|
const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(0);
|
||||||
|
const STORAGE_PROOF_OVERHEAD: u32 = 0;
|
||||||
|
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0;
|
||||||
|
|
||||||
|
type SignedBlock = sp_runtime::generic::SignedBlock<
|
||||||
|
sp_runtime::generic::Block<Self::Header, sp_runtime::OpaqueExtrinsic>,
|
||||||
|
>;
|
||||||
|
type Call = ();
|
||||||
|
type WeightToFee = IdentityFee<u32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainWithBalances for TestChain {
|
||||||
|
fn account_info_storage_key(_account_id: &u32) -> sp_core::storage::StorageKey {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,16 +18,20 @@ log = "0.4.14"
|
|||||||
# Bridge dependencies
|
# Bridge dependencies
|
||||||
|
|
||||||
bp-header-chain = { path = "../../primitives/header-chain" }
|
bp-header-chain = { path = "../../primitives/header-chain" }
|
||||||
|
bp-parachains = { path = "../../primitives/parachains" }
|
||||||
|
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||||
|
|
||||||
finality-grandpa = { version = "0.15.0" }
|
finality-grandpa = { version = "0.15.0" }
|
||||||
finality-relay = { path = "../finality" }
|
finality-relay = { path = "../finality" }
|
||||||
|
parachains-relay = { path = "../parachains" }
|
||||||
relay-utils = { path = "../utils" }
|
relay-utils = { path = "../utils" }
|
||||||
messages-relay = { path = "../messages" }
|
messages-relay = { path = "../messages" }
|
||||||
relay-substrate-client = { path = "../client-substrate" }
|
relay-substrate-client = { path = "../client-substrate" }
|
||||||
|
|
||||||
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
|
pallet-bridge-grandpa = { path = "../../modules/grandpa" }
|
||||||
pallet-bridge-messages = { path = "../../modules/messages" }
|
pallet-bridge-messages = { path = "../../modules/messages" }
|
||||||
|
pallet-bridge-parachains = { path = "../../modules/parachains" }
|
||||||
|
|
||||||
bp-runtime = { path = "../../primitives/runtime" }
|
bp-runtime = { path = "../../primitives/runtime" }
|
||||||
bp-messages = { path = "../../primitives/messages" }
|
bp-messages = { path = "../../primitives/messages" }
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ pub mod messages_metrics;
|
|||||||
pub mod messages_source;
|
pub mod messages_source;
|
||||||
pub mod messages_target;
|
pub mod messages_target;
|
||||||
pub mod on_demand_headers;
|
pub mod on_demand_headers;
|
||||||
|
pub mod parachains_source;
|
||||||
|
pub mod parachains_target;
|
||||||
|
|
||||||
/// Default relay loop stall timeout. If transactions generated by relay are immortal, then
|
/// Default relay loop stall timeout. If transactions generated by relay are immortal, then
|
||||||
/// this timeout is used.
|
/// this timeout is used.
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
// Copyright 2019-2021 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/>.
|
||||||
|
|
||||||
|
//! Parachain heads source.
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use bp_parachains::parachain_head_storage_key_at_source;
|
||||||
|
use bp_polkadot_core::parachains::{ParaHash, ParaHead, ParaHeadsProof, ParaId};
|
||||||
|
use codec::Decode;
|
||||||
|
use parachains_relay::{parachains_loop::SourceClient, ParachainsPipeline};
|
||||||
|
use relay_substrate_client::{Client, Error as SubstrateError, HeaderIdOf};
|
||||||
|
use relay_utils::relay_loop::Client as RelayClient;
|
||||||
|
|
||||||
|
/// Substrate client as parachain heads source.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ParachainsSource<P: ParachainsPipeline> {
|
||||||
|
client: Client<P::SourceChain>,
|
||||||
|
paras_pallet_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: ParachainsPipeline> ParachainsSource<P> {
|
||||||
|
/// Creates new parachains source client.
|
||||||
|
pub fn new(client: Client<P::SourceChain>, paras_pallet_name: String) -> Self {
|
||||||
|
ParachainsSource { client, paras_pallet_name }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<P: ParachainsPipeline> RelayClient for ParachainsSource<P> {
|
||||||
|
type Error = SubstrateError;
|
||||||
|
|
||||||
|
async fn reconnect(&mut self) -> Result<(), SubstrateError> {
|
||||||
|
self.client.reconnect().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<P: ParachainsPipeline> SourceClient<P> for ParachainsSource<P> {
|
||||||
|
async fn ensure_synced(&self) -> Result<bool, Self::Error> {
|
||||||
|
match self.client.ensure_synced().await {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(SubstrateError::ClientNotSynced(_)) => Ok(false),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parachain_head(
|
||||||
|
&self,
|
||||||
|
at_block: HeaderIdOf<P::SourceChain>,
|
||||||
|
para_id: ParaId,
|
||||||
|
) -> Result<Option<ParaHash>, Self::Error> {
|
||||||
|
let storage_key = parachain_head_storage_key_at_source(&self.paras_pallet_name, para_id);
|
||||||
|
let para_head = self.client.raw_storage_value(storage_key, Some(at_block.1)).await?;
|
||||||
|
let para_head = para_head.map(|h| ParaHead::decode(&mut &h.0[..])).transpose()?;
|
||||||
|
let para_hash = para_head.map(|h| h.hash());
|
||||||
|
|
||||||
|
Ok(para_hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn prove_parachain_heads(
|
||||||
|
&self,
|
||||||
|
at_block: HeaderIdOf<P::SourceChain>,
|
||||||
|
parachains: &[ParaId],
|
||||||
|
) -> Result<ParaHeadsProof, Self::Error> {
|
||||||
|
let storage_keys = parachains
|
||||||
|
.iter()
|
||||||
|
.map(|para_id| parachain_head_storage_key_at_source(&self.paras_pallet_name, *para_id))
|
||||||
|
.collect();
|
||||||
|
let parachain_heads_proof = self
|
||||||
|
.client
|
||||||
|
.prove_storage(storage_keys, at_block.1)
|
||||||
|
.await?
|
||||||
|
.iter_nodes()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(parachain_heads_proof)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,211 @@
|
|||||||
|
// Copyright 2019-2021 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/>.
|
||||||
|
|
||||||
|
//! Parachain heads target.
|
||||||
|
|
||||||
|
use crate::TransactionParams;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use bp_parachains::{parachain_head_storage_key_at_target, BestParaHeadHash};
|
||||||
|
use bp_polkadot_core::parachains::{ParaHeadsProof, ParaId};
|
||||||
|
use codec::{Decode, Encode};
|
||||||
|
use pallet_bridge_parachains::{
|
||||||
|
Call as BridgeParachainsCall, Config as BridgeParachainsConfig, RelayBlockHash,
|
||||||
|
RelayBlockHasher, RelayBlockNumber,
|
||||||
|
};
|
||||||
|
use parachains_relay::{parachains_loop::TargetClient, ParachainsPipeline};
|
||||||
|
use relay_substrate_client::{
|
||||||
|
AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, Error as SubstrateError,
|
||||||
|
HashOf, HeaderIdOf, SignParam, TransactionEra, TransactionSignScheme, UnsignedTransaction,
|
||||||
|
};
|
||||||
|
use relay_utils::{relay_loop::Client as RelayClient, HeaderId};
|
||||||
|
use sp_core::{Bytes, Pair};
|
||||||
|
use sp_runtime::traits::Header as HeaderT;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
/// Different ways of building `submit_parachain_heads` calls.
|
||||||
|
pub trait SubmitParachainHeadsCallBuilder<P: ParachainsPipeline>: 'static + Send + Sync {
|
||||||
|
/// Given parachains and their heads proof, build call of `submit_parachain_heads`
|
||||||
|
/// function of bridge parachains module at the target chain.
|
||||||
|
fn build_submit_parachain_heads_call(
|
||||||
|
relay_block_hash: HashOf<P::SourceChain>,
|
||||||
|
parachains: Vec<ParaId>,
|
||||||
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
|
) -> CallOf<P::TargetChain>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Building `submit_parachain_heads` call when you have direct access to the target
|
||||||
|
/// chain runtime.
|
||||||
|
pub struct DirectSubmitParachainHeadsCallBuilder<P, R, I> {
|
||||||
|
_phantom: PhantomData<(P, R, I)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P, R, I> SubmitParachainHeadsCallBuilder<P> for DirectSubmitParachainHeadsCallBuilder<P, R, I>
|
||||||
|
where
|
||||||
|
P: ParachainsPipeline,
|
||||||
|
P::SourceChain: Chain<Hash = RelayBlockHash>,
|
||||||
|
R: BridgeParachainsConfig<I> + Send + Sync,
|
||||||
|
I: 'static + Send + Sync,
|
||||||
|
R::BridgedChain: bp_runtime::Chain<
|
||||||
|
BlockNumber = RelayBlockNumber,
|
||||||
|
Hash = RelayBlockHash,
|
||||||
|
Hasher = RelayBlockHasher,
|
||||||
|
>,
|
||||||
|
CallOf<P::TargetChain>: From<BridgeParachainsCall<R, I>>,
|
||||||
|
{
|
||||||
|
fn build_submit_parachain_heads_call(
|
||||||
|
relay_block_hash: HashOf<P::SourceChain>,
|
||||||
|
parachains: Vec<ParaId>,
|
||||||
|
parachain_heads_proof: ParaHeadsProof,
|
||||||
|
) -> CallOf<P::TargetChain> {
|
||||||
|
BridgeParachainsCall::<R, I>::submit_parachain_heads {
|
||||||
|
relay_block_hash,
|
||||||
|
parachains,
|
||||||
|
parachain_heads_proof,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Substrate client as parachain heads source.
|
||||||
|
pub struct ParachainsTarget<P: ParachainsPipeline, S: TransactionSignScheme, CB> {
|
||||||
|
client: Client<P::TargetChain>,
|
||||||
|
transaction_params: TransactionParams<AccountKeyPairOf<S>>,
|
||||||
|
bridge_paras_pallet_name: String,
|
||||||
|
_phantom: PhantomData<CB>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: ParachainsPipeline, S: TransactionSignScheme, CB> ParachainsTarget<P, S, CB> {
|
||||||
|
/// Creates new parachains target client.
|
||||||
|
pub fn new(
|
||||||
|
client: Client<P::TargetChain>,
|
||||||
|
transaction_params: TransactionParams<AccountKeyPairOf<S>>,
|
||||||
|
bridge_paras_pallet_name: String,
|
||||||
|
) -> Self {
|
||||||
|
ParachainsTarget {
|
||||||
|
client,
|
||||||
|
transaction_params,
|
||||||
|
bridge_paras_pallet_name,
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: ParachainsPipeline, S: TransactionSignScheme, CB> Clone for ParachainsTarget<P, S, CB> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ParachainsTarget {
|
||||||
|
client: self.client.clone(),
|
||||||
|
transaction_params: self.transaction_params.clone(),
|
||||||
|
bridge_paras_pallet_name: self.bridge_paras_pallet_name.clone(),
|
||||||
|
_phantom: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<
|
||||||
|
P: ParachainsPipeline,
|
||||||
|
S: 'static + TransactionSignScheme,
|
||||||
|
CB: SubmitParachainHeadsCallBuilder<P>,
|
||||||
|
> RelayClient for ParachainsTarget<P, S, CB>
|
||||||
|
{
|
||||||
|
type Error = SubstrateError;
|
||||||
|
|
||||||
|
async fn reconnect(&mut self) -> Result<(), SubstrateError> {
|
||||||
|
self.client.reconnect().await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<P, S, CB> TargetClient<P> for ParachainsTarget<P, S, CB>
|
||||||
|
where
|
||||||
|
P: ParachainsPipeline,
|
||||||
|
S: 'static + TransactionSignScheme<Chain = P::TargetChain>,
|
||||||
|
CB: SubmitParachainHeadsCallBuilder<P>,
|
||||||
|
AccountIdOf<P::TargetChain>: From<<AccountKeyPairOf<S> as Pair>::Public>,
|
||||||
|
{
|
||||||
|
async fn best_block(&self) -> Result<HeaderIdOf<P::TargetChain>, Self::Error> {
|
||||||
|
let best_header = self.client.best_header().await?;
|
||||||
|
let best_hash = best_header.hash();
|
||||||
|
let best_id = HeaderId(*best_header.number(), best_hash);
|
||||||
|
|
||||||
|
Ok(best_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn best_finalized_source_block(
|
||||||
|
&self,
|
||||||
|
at_block: &HeaderIdOf<P::TargetChain>,
|
||||||
|
) -> Result<HeaderIdOf<P::SourceChain>, Self::Error> {
|
||||||
|
let encoded_best_finalized_source_block = self
|
||||||
|
.client
|
||||||
|
.state_call(
|
||||||
|
P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD.into(),
|
||||||
|
Bytes(Vec::new()),
|
||||||
|
Some(at_block.1),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let decoded_best_finalized_source_block: (
|
||||||
|
BlockNumberOf<P::SourceChain>,
|
||||||
|
HashOf<P::SourceChain>,
|
||||||
|
) = Decode::decode(&mut &encoded_best_finalized_source_block.0[..])
|
||||||
|
.map_err(SubstrateError::ResponseParseFailed)?;
|
||||||
|
Ok(HeaderId(decoded_best_finalized_source_block.0, decoded_best_finalized_source_block.1))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn parachain_head(
|
||||||
|
&self,
|
||||||
|
at_block: HeaderIdOf<P::TargetChain>,
|
||||||
|
para_id: ParaId,
|
||||||
|
) -> Result<Option<BestParaHeadHash>, Self::Error> {
|
||||||
|
let storage_key =
|
||||||
|
parachain_head_storage_key_at_target(&self.bridge_paras_pallet_name, para_id);
|
||||||
|
let para_head = self.client.storage_value(storage_key, Some(at_block.1)).await?;
|
||||||
|
|
||||||
|
Ok(para_head)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn submit_parachain_heads_proof(
|
||||||
|
&self,
|
||||||
|
at_relay_block: HeaderIdOf<P::SourceChain>,
|
||||||
|
updated_parachains: Vec<ParaId>,
|
||||||
|
proof: ParaHeadsProof,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
let genesis_hash = *self.client.genesis_hash();
|
||||||
|
let transaction_params = self.transaction_params.clone();
|
||||||
|
let (spec_version, transaction_version) = self.client.simple_runtime_version().await?;
|
||||||
|
let call =
|
||||||
|
CB::build_submit_parachain_heads_call(at_relay_block.1, updated_parachains, proof);
|
||||||
|
self.client
|
||||||
|
.submit_signed_extrinsic(
|
||||||
|
self.transaction_params.signer.public().into(),
|
||||||
|
move |best_block_id, transaction_nonce| {
|
||||||
|
Ok(Bytes(
|
||||||
|
S::sign_transaction(SignParam {
|
||||||
|
spec_version,
|
||||||
|
transaction_version,
|
||||||
|
genesis_hash,
|
||||||
|
signer: transaction_params.signer,
|
||||||
|
era: TransactionEra::new(best_block_id, transaction_params.mortality),
|
||||||
|
unsigned: UnsignedTransaction::new(call.into(), transaction_nonce),
|
||||||
|
})?
|
||||||
|
.encode(),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map(drop)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
[package]
|
||||||
|
name = "parachains-relay"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
edition = "2018"
|
||||||
|
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
async-std = "1.6.5"
|
||||||
|
async-trait = "0.1.40"
|
||||||
|
backoff = "0.2"
|
||||||
|
futures = "0.3.5"
|
||||||
|
linked-hash-map = "0.5.3"
|
||||||
|
log = "0.4.11"
|
||||||
|
num-traits = "0.2"
|
||||||
|
parking_lot = "0.11.0"
|
||||||
|
relay-utils = { path = "../utils" }
|
||||||
|
|
||||||
|
# Bridge dependencies
|
||||||
|
|
||||||
|
bp-parachains = { path = "../../primitives/parachains" }
|
||||||
|
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||||
|
relay-substrate-client = { path = "../client-substrate" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
codec = { package = "parity-scale-codec", version = "3.0.0" }
|
||||||
|
relay-substrate-client = { path = "../client-substrate", features = ["test-helpers"] }
|
||||||
|
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright 2019-2021 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 std::fmt::Debug;
|
||||||
|
|
||||||
|
use relay_substrate_client::Chain;
|
||||||
|
|
||||||
|
pub mod parachains_loop;
|
||||||
|
pub mod parachains_loop_metrics;
|
||||||
|
|
||||||
|
/// Finality proofs synchronization pipeline.
|
||||||
|
pub trait ParachainsPipeline: 'static + Clone + Debug + Send + Sync {
|
||||||
|
/// Relay chain which is storing parachain heads in its `paras` module.
|
||||||
|
type SourceChain: Chain;
|
||||||
|
/// Target chain (either relay or para) which wants to know about new parachain heads.
|
||||||
|
type TargetChain: Chain;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright 2019-2021 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 relay_utils::metrics::{Metric, PrometheusError, Registry};
|
||||||
|
|
||||||
|
/// Parachains sync metrics.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct ParachainsLoopMetrics;
|
||||||
|
|
||||||
|
impl ParachainsLoopMetrics {
|
||||||
|
/// Create and register parachains loop metrics.
|
||||||
|
pub fn new(_prefix: Option<&str>) -> Result<Self, PrometheusError> {
|
||||||
|
Ok(ParachainsLoopMetrics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Metric for ParachainsLoopMetrics {
|
||||||
|
fn register(&self, _registry: &Registry) -> Result<(), PrometheusError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user