mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-28 06:17:56 +00:00
Polkadot <> Kusama relayers (#1122)
* relay headers between Kusama and Polkadot * relay messages between Kusama and Polkadot * complex Kusama <> Polkadot relayer * expose relayer_fund_account_id from messages pallet * create relayers fund accounts on Kusama/Polkadot + some more fixes * fmt * fix compilation * compilation + clippy * compilation * MAXIMAL_BALANCE_DECREASE_PER_DAY for K<>P header relays * fmt * deduplicate tests * Update modules/messages/src/lib.rs Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * extract storage_parameter_key function * other grumbles * fix * fmt Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
This commit is contained in:
committed by
Bastian Köcher
parent
417903f9e7
commit
2db84b74cc
@@ -135,10 +135,10 @@ impl Alternative {
|
||||
get_account_id_from_seed::<sr25519::Public>("George//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Harry//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("RialtoMessagesOwner"),
|
||||
pallet_bridge_messages::Pallet::<
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WithRialtoMessagesInstance,
|
||||
>::relayer_fund_account_id(),
|
||||
pallet_bridge_messages::relayer_fund_account_id::<
|
||||
bp_millau::AccountId,
|
||||
bp_millau::AccountIdConverter,
|
||||
>(),
|
||||
derive_account_from_rialto_id(bp_runtime::SourceAccount::Account(
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
)),
|
||||
|
||||
@@ -151,10 +151,10 @@ impl Alternative {
|
||||
get_account_id_from_seed::<sr25519::Public>("George//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("Harry//stash"),
|
||||
get_account_id_from_seed::<sr25519::Public>("MillauMessagesOwner"),
|
||||
pallet_bridge_messages::Pallet::<
|
||||
rialto_runtime::Runtime,
|
||||
rialto_runtime::WithMillauMessagesInstance,
|
||||
>::relayer_fund_account_id(),
|
||||
pallet_bridge_messages::relayer_fund_account_id::<
|
||||
bp_rialto::AccountId,
|
||||
bp_rialto::AccountIdConverter,
|
||||
>(),
|
||||
derive_account_from_millau_id(bp_runtime::SourceAccount::Account(
|
||||
get_account_id_from_seed::<sr25519::Public>("Alice"),
|
||||
)),
|
||||
|
||||
@@ -484,7 +484,7 @@ benchmarks_instance_pallet! {
|
||||
//
|
||||
// This is base benchmark for all other confirmations delivery benchmarks.
|
||||
receive_delivery_proof_for_single_message {
|
||||
let relayers_fund_id = crate::Pallet::<T, I>::relayer_fund_account_id();
|
||||
let relayers_fund_id = crate::relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
let relayer_id: T::AccountId = account("relayer", 0, SEED);
|
||||
let relayer_balance = T::account_balance(&relayer_id);
|
||||
T::endow_account(&relayers_fund_id);
|
||||
@@ -524,7 +524,7 @@ benchmarks_instance_pallet! {
|
||||
// as `weight(receive_delivery_proof_for_two_messages_by_single_relayer)
|
||||
// - weight(receive_delivery_proof_for_single_message)`.
|
||||
receive_delivery_proof_for_two_messages_by_single_relayer {
|
||||
let relayers_fund_id = crate::Pallet::<T, I>::relayer_fund_account_id();
|
||||
let relayers_fund_id = crate::relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
let relayer_id: T::AccountId = account("relayer", 0, SEED);
|
||||
let relayer_balance = T::account_balance(&relayer_id);
|
||||
T::endow_account(&relayers_fund_id);
|
||||
@@ -564,7 +564,7 @@ benchmarks_instance_pallet! {
|
||||
// as `weight(receive_delivery_proof_for_two_messages_by_two_relayers)
|
||||
// - weight(receive_delivery_proof_for_two_messages_by_single_relayer)`.
|
||||
receive_delivery_proof_for_two_messages_by_two_relayers {
|
||||
let relayers_fund_id = crate::Pallet::<T, I>::relayer_fund_account_id();
|
||||
let relayers_fund_id = crate::relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
let relayer1_id: T::AccountId = account("relayer1", 1, SEED);
|
||||
let relayer1_balance = T::account_balance(&relayer1_id);
|
||||
let relayer2_id: T::AccountId = account("relayer2", 2, SEED);
|
||||
@@ -811,7 +811,7 @@ benchmarks_instance_pallet! {
|
||||
.try_into()
|
||||
.expect("Value of MaxUnrewardedRelayerEntriesAtInboundLane is too large");
|
||||
|
||||
let relayers_fund_id = crate::Pallet::<T, I>::relayer_fund_account_id();
|
||||
let relayers_fund_id = crate::relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
let relayer_id: T::AccountId = account("relayer", 0, SEED);
|
||||
let relayer_balance = T::account_balance(&relayer_id);
|
||||
T::endow_account(&relayers_fund_id);
|
||||
@@ -854,7 +854,7 @@ benchmarks_instance_pallet! {
|
||||
.try_into()
|
||||
.expect("Value of MaxUnconfirmedMessagesAtInboundLane is too large ");
|
||||
|
||||
let relayers_fund_id = crate::Pallet::<T, I>::relayer_fund_account_id();
|
||||
let relayers_fund_id = crate::relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
let confirmation_relayer_id = account("relayer", 0, SEED);
|
||||
let relayers: BTreeMap<T::AccountId, T::OutboundMessageFee> = (1..=i)
|
||||
.map(|j| {
|
||||
|
||||
@@ -64,7 +64,8 @@ use frame_support::{
|
||||
};
|
||||
use frame_system::RawOrigin;
|
||||
use num_traits::{SaturatingAdd, Zero};
|
||||
use sp_runtime::traits::BadOrigin;
|
||||
use sp_core::H256;
|
||||
use sp_runtime::traits::{BadOrigin, Convert};
|
||||
use sp_std::{cell::RefCell, cmp::PartialOrd, marker::PhantomData, prelude::*};
|
||||
|
||||
mod inbound_lane;
|
||||
@@ -286,16 +287,17 @@ pub mod pallet {
|
||||
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
||||
&submitter,
|
||||
&additional_fee,
|
||||
&Self::relayer_fund_account_id(),
|
||||
&relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::trace!(
|
||||
target: "runtime::bridge-messages",
|
||||
"Submitter {:?} can't pay additional fee {:?} for the message {:?}/{:?}: {:?}",
|
||||
"Submitter {:?} can't pay additional fee {:?} for the message {:?}/{:?} to {:?}: {:?}",
|
||||
submitter,
|
||||
additional_fee,
|
||||
lane_id,
|
||||
nonce,
|
||||
relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>(),
|
||||
err,
|
||||
);
|
||||
|
||||
@@ -604,7 +606,7 @@ pub mod pallet {
|
||||
|
||||
// if some new messages have been confirmed, reward relayers
|
||||
if !relayers_rewards.is_empty() {
|
||||
let relayer_fund_account = Self::relayer_fund_account_id();
|
||||
let relayer_fund_account = relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>();
|
||||
<T as Config<I>>::MessageDeliveryAndDispatchPayment::pay_relayers_rewards(
|
||||
&confirmation_relayer,
|
||||
relayers_rewards,
|
||||
@@ -768,17 +770,6 @@ pub mod pallet {
|
||||
total_messages: total_unrewarded_messages(&relayers).unwrap_or(MessageNonce::MAX),
|
||||
}
|
||||
}
|
||||
|
||||
/// AccountId of the shared relayer fund account.
|
||||
///
|
||||
/// This account is passed to `MessageDeliveryAndDispatchPayment` trait, and depending
|
||||
/// on the implementation it can be used to store relayers rewards.
|
||||
/// See [InstantCurrencyPayments] for a concrete implementation.
|
||||
pub fn relayer_fund_account_id() -> T::AccountId {
|
||||
use sp_runtime::traits::Convert;
|
||||
let encoded_id = bp_runtime::derive_relayer_fund_account_id(bp_runtime::NO_INSTANCE_ID);
|
||||
T::AccountIdConverter::convert(encoded_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -825,6 +816,16 @@ pub mod storage_keys {
|
||||
}
|
||||
}
|
||||
|
||||
/// AccountId of the shared relayer fund account.
|
||||
///
|
||||
/// This account is passed to `MessageDeliveryAndDispatchPayment` trait, and depending
|
||||
/// on the implementation it can be used to store relayers rewards.
|
||||
/// See [`InstantCurrencyPayments`] for a concrete implementation.
|
||||
pub fn relayer_fund_account_id<AccountId, AccountIdConverter: Convert<H256, AccountId>>() -> AccountId {
|
||||
let encoded_id = bp_runtime::derive_relayer_fund_account_id(bp_runtime::NO_INSTANCE_ID);
|
||||
AccountIdConverter::convert(encoded_id)
|
||||
}
|
||||
|
||||
impl<T, I> bp_messages::source_chain::MessagesBridge<T::AccountId, T::OutboundMessageFee, T::OutboundPayload>
|
||||
for Pallet<T, I>
|
||||
where
|
||||
@@ -894,7 +895,7 @@ fn send_message<T: Config<I>, I: 'static>(
|
||||
T::MessageDeliveryAndDispatchPayment::pay_delivery_and_dispatch_fee(
|
||||
&submitter,
|
||||
&delivery_and_dispatch_fee,
|
||||
&Pallet::<T, I>::relayer_fund_account_id(),
|
||||
&relayer_fund_account_id::<T::AccountId, T::AccountIdConverter>(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
log::trace!(
|
||||
|
||||
@@ -20,6 +20,7 @@ bp-runtime = { path = "../runtime", default-features = false }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
@@ -30,4 +31,5 @@ std = [
|
||||
"frame-support/std",
|
||||
"sp-api/std",
|
||||
"sp-std/std",
|
||||
"sp-version/std",
|
||||
]
|
||||
|
||||
@@ -23,12 +23,24 @@
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
pub use bp_polkadot_core::*;
|
||||
|
||||
/// Kusama Chain
|
||||
pub type Kusama = PolkadotLike;
|
||||
|
||||
// NOTE: This needs to be kept up to date with the Kusama runtime found in the Polkadot repo.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: sp_version::create_runtime_str!("kusama"),
|
||||
impl_name: sp_version::create_runtime_str!("parity-kusama"),
|
||||
authoring_version: 2,
|
||||
spec_version: 9100,
|
||||
impl_version: 0,
|
||||
apis: sp_version::create_apis_vec![[]],
|
||||
transaction_version: 5,
|
||||
};
|
||||
|
||||
// NOTE: This needs to be kept up to date with the Kusama runtime found in the Polkadot repo.
|
||||
pub struct WeightToFee;
|
||||
impl WeightToFeePolynomial for WeightToFee {
|
||||
@@ -57,9 +69,22 @@ pub fn derive_account_from_polkadot_id(id: bp_runtime::SourceAccount<AccountId>)
|
||||
/// Per-byte fee for Kusama transactions.
|
||||
pub const TRANSACTION_BYTE_FEE: Balance = 10 * 1_000_000_000_000 / 30_000 / 1_000;
|
||||
|
||||
/// Existential deposit on Kusama.
|
||||
pub const EXISTENTIAL_DEPOSIT: Balance = 1_000_000_000_000 / 30_000;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Kusama measured in of number of
|
||||
/// blocks.
|
||||
///
|
||||
/// Note that since this is a target sessions may change before/after this time depending on network
|
||||
/// conditions.
|
||||
pub const SESSION_LENGTH: BlockNumber = 1 * time_units::HOURS;
|
||||
|
||||
/// Name of the With-Polkadot messages pallet instance in the Kusama runtime.
|
||||
pub const WITH_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages";
|
||||
|
||||
/// Name of the DOT->KSM conversion rate stored in the Kusama runtime.
|
||||
pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = "PolkadotToKusamaConversionRate";
|
||||
|
||||
/// Name of the `KusamaFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_best_finalized";
|
||||
/// Name of the `KusamaFinalityApi::is_known_header` runtime method.
|
||||
|
||||
@@ -20,6 +20,7 @@ bp-runtime = { path = "../runtime", default-features = false }
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
@@ -30,4 +31,5 @@ std = [
|
||||
"frame-support/std",
|
||||
"sp-api/std",
|
||||
"sp-std/std",
|
||||
"sp-version/std",
|
||||
]
|
||||
|
||||
@@ -23,12 +23,24 @@
|
||||
use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState};
|
||||
use frame_support::weights::{WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial};
|
||||
use sp_std::prelude::*;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
pub use bp_polkadot_core::*;
|
||||
|
||||
/// Polkadot Chain
|
||||
pub type Polkadot = PolkadotLike;
|
||||
|
||||
// NOTE: This needs to be kept up to date with the Polkadot runtime found in the Polkadot repo.
|
||||
pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
spec_name: sp_version::create_runtime_str!("polkadot"),
|
||||
impl_name: sp_version::create_runtime_str!("parity-polkadot"),
|
||||
authoring_version: 0,
|
||||
spec_version: 9100,
|
||||
impl_version: 0,
|
||||
apis: sp_version::create_apis_vec![[]],
|
||||
transaction_version: 7,
|
||||
};
|
||||
|
||||
// NOTE: This needs to be kept up to date with the Polkadot runtime found in the Polkadot repo.
|
||||
pub struct WeightToFee;
|
||||
impl WeightToFeePolynomial for WeightToFee {
|
||||
@@ -57,9 +69,22 @@ pub fn derive_account_from_kusama_id(id: bp_runtime::SourceAccount<AccountId>) -
|
||||
/// Per-byte fee for Polkadot transactions.
|
||||
pub const TRANSACTION_BYTE_FEE: Balance = 10 * 10_000_000_000 / 100 / 1_000;
|
||||
|
||||
/// Existential deposit on Polkadot.
|
||||
pub const EXISTENTIAL_DEPOSIT: Balance = 10_000_000_000;
|
||||
|
||||
/// The target length of a session (how often authorities change) on Polkadot measured in of number of
|
||||
/// blocks.
|
||||
///
|
||||
/// Note that since this is a target sessions may change before/after this time depending on network
|
||||
/// conditions.
|
||||
pub const SESSION_LENGTH: BlockNumber = 4 * time_units::HOURS;
|
||||
|
||||
/// Name of the With-Kusama messages pallet instance in the Polkadot runtime.
|
||||
pub const WITH_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages";
|
||||
|
||||
/// Name of the KSM->DOT conversion rate stored in the Polkadot runtime.
|
||||
pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = "KusamaToPolkadotConversionRate";
|
||||
|
||||
/// Name of the `PolkadotFinalityApi::best_finalized` runtime method.
|
||||
pub const BEST_FINALIZED_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_best_finalized";
|
||||
/// Name of the `PolkadotFinalityApi::is_known_header` runtime method.
|
||||
|
||||
@@ -217,6 +217,9 @@ pub type AccountPublic = <Signature as Verify>::Signer;
|
||||
/// Id of account on Polkadot-like chains.
|
||||
pub type AccountId = <AccountPublic as IdentifyAccount>::AccountId;
|
||||
|
||||
/// Address of account on Polkadot-like chains.
|
||||
pub type AccountAddress = MultiAddress<AccountId, ()>;
|
||||
|
||||
/// Index of a transaction on the Polkadot-like chains.
|
||||
pub type Nonce = u32;
|
||||
|
||||
@@ -231,7 +234,7 @@ pub type Balance = u128;
|
||||
|
||||
/// Unchecked Extrinsic type.
|
||||
pub type UncheckedExtrinsic<Call> =
|
||||
generic::UncheckedExtrinsic<MultiAddress<AccountId, ()>, Call, Signature, SignedExtensions<Call>>;
|
||||
generic::UncheckedExtrinsic<AccountAddress, Call, Signature, SignedExtensions<Call>>;
|
||||
|
||||
/// Account address, used by the Polkadot-like chain.
|
||||
pub type Address = MultiAddress<AccountId, ()>;
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
use codec::Encode;
|
||||
use frame_support::RuntimeDebug;
|
||||
use sp_core::hash::H256;
|
||||
use sp_core::{hash::H256, storage::StorageKey};
|
||||
use sp_io::hashing::blake2_256;
|
||||
use sp_std::convert::TryFrom;
|
||||
use sp_std::{convert::TryFrom, vec::Vec};
|
||||
|
||||
pub use chain::{
|
||||
AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, Chain, HashOf, HasherOf, HeaderOf, IndexOf, SignatureOf,
|
||||
@@ -183,3 +183,15 @@ impl<BlockNumber: Copy + Into<u64>, BlockHash: Copy> TransactionEra<BlockNumber,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This is how a storage key of storage parameter (`parameter_types! { storage Param: bool = false; }`) is computed.
|
||||
///
|
||||
/// Copypaste from `frame_support::parameter_types` macro
|
||||
pub fn storage_parameter_key(parameter_name: &str) -> StorageKey {
|
||||
let mut buffer = Vec::with_capacity(1 + parameter_name.len() + 1 + 1);
|
||||
buffer.push(':' as u8);
|
||||
buffer.extend_from_slice(parameter_name.as_bytes());
|
||||
buffer.push(':' as u8);
|
||||
buffer.push(0);
|
||||
StorageKey(sp_io::hashing::twox_128(&buffer).to_vec())
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ substrate-relay-helper = { path = "../lib-substrate-relay" }
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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 codec::Decode;
|
||||
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
|
||||
use relay_kusama_client::Kusama;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_call::{Call, CliEncodeCall},
|
||||
encode_message, CliChain,
|
||||
};
|
||||
|
||||
/// Weight of the `system::remark` call at Kusama.
|
||||
///
|
||||
/// This weight is larger (x2) than actual weight at current Kusama runtime to avoid unsuccessful
|
||||
/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
|
||||
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
|
||||
|
||||
/// Id of Kusama token that is used to fetch token price.
|
||||
pub(crate) const TOKEN_ID: &str = "kusama";
|
||||
|
||||
impl CliEncodeCall for Kusama {
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
bp_kusama::max_extrinsic_size()
|
||||
}
|
||||
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Remark { remark_payload, .. } => {
|
||||
relay_kusama_client::runtime::Call::System(relay_kusama_client::runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::KUSAMA_TO_POLKADOT_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dispatch_info(call: &relay_kusama_client::runtime::Call) -> anyhow::Result<DispatchInfo> {
|
||||
match *call {
|
||||
relay_kusama_client::runtime::Call::System(relay_kusama_client::runtime::SystemCall::remark(_)) => {
|
||||
Ok(DispatchInfo {
|
||||
weight: crate::chains::kusama::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
})
|
||||
}
|
||||
_ => anyhow::bail!("Unsupported Kusama call: {:?}", call),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CliChain for Kusama {
|
||||
const RUNTIME_VERSION: RuntimeVersion = bp_kusama::VERSION;
|
||||
|
||||
type KeyPair = sp_core::sr25519::Pair;
|
||||
type MessagePayload = ();
|
||||
|
||||
fn ss58_format() -> u16 {
|
||||
42
|
||||
}
|
||||
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
bp_kusama::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
Err("Sending messages from Kusama is not yet supported.".into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// 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/>.
|
||||
|
||||
//! Kusama-to-Polkadot headers sync entrypoint.
|
||||
|
||||
use codec::Encode;
|
||||
use sp_core::{Bytes, Pair};
|
||||
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use relay_kusama_client::{Kusama, SyncHeader as KusamaSyncHeader};
|
||||
use relay_polkadot_client::{Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
|
||||
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
|
||||
/// relay as gone wild.
|
||||
///
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 21 DOT,
|
||||
/// but let's round up to 30 DOT here.
|
||||
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 30_000_000_000;
|
||||
|
||||
/// Kusama-to-Polkadot finality sync pipeline.
|
||||
pub(crate) type FinalityPipelineKusamaFinalityToPolkadot =
|
||||
SubstrateFinalityToSubstrate<Kusama, Polkadot, PolkadotSigningParams>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct KusamaFinalityToPolkadot {
|
||||
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot,
|
||||
}
|
||||
|
||||
impl KusamaFinalityToPolkadot {
|
||||
pub fn new(target_client: Client<Polkadot>, target_sign: PolkadotSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new(target_client, target_sign),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubstrateFinalitySyncPipeline for KusamaFinalityToPolkadot {
|
||||
type FinalitySyncPipeline = FinalityPipelineKusamaFinalityToPolkadot;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Polkadot;
|
||||
|
||||
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
|
||||
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(
|
||||
Some(finality_relay::metrics_prefix::<Self::FinalitySyncPipeline>()),
|
||||
params,
|
||||
)
|
||||
}
|
||||
|
||||
fn start_relay_guards(&self) {
|
||||
relay_substrate_client::guard::abort_on_spec_version_change(
|
||||
self.finality_pipeline.target_client.clone(),
|
||||
bp_polkadot::VERSION.spec_version,
|
||||
);
|
||||
relay_substrate_client::guard::abort_when_account_balance_decreased(
|
||||
self.finality_pipeline.target_client.clone(),
|
||||
self.transactions_author(),
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY,
|
||||
);
|
||||
}
|
||||
|
||||
fn transactions_author(&self) -> bp_polkadot::AccountId {
|
||||
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_submit_finality_proof_transaction(
|
||||
&self,
|
||||
era: bp_runtime::TransactionEraOf<Polkadot>,
|
||||
transaction_nonce: bp_runtime::IndexOf<Polkadot>,
|
||||
header: KusamaSyncHeader,
|
||||
proof: GrandpaJustification<bp_kusama::Header>,
|
||||
) -> Bytes {
|
||||
let call = relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa(
|
||||
relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof(header.into_inner(), proof),
|
||||
);
|
||||
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
|
||||
let transaction = Polkadot::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.finality_pipeline.target_sign,
|
||||
era,
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use frame_support::weights::WeightToFeePolynomial;
|
||||
use pallet_bridge_grandpa::weights::WeightInfo;
|
||||
|
||||
pub fn compute_maximal_balance_decrease_per_day<B, W>(expected_source_headers_per_day: u32) -> B
|
||||
where
|
||||
B: From<u32> + std::ops::Mul<Output = B>,
|
||||
W: WeightToFeePolynomial<Balance = B>,
|
||||
{
|
||||
// we assume that the GRANDPA is not lagging here => ancestry length will be near to 0 (let's round up to 2)
|
||||
const AVG_VOTES_ANCESTRIES_LEN: u32 = 2;
|
||||
// let's assume number of validators is 1024 (more than on any existing well-known chain atm)
|
||||
// => number of precommits is *2/3 + 1
|
||||
const AVG_PRECOMMITS_LEN: u32 = 1024 * 2 / 3 + 1;
|
||||
|
||||
// GRANDPA pallet weights. We're now using Rialto weights everywhere.
|
||||
//
|
||||
// Using Rialto runtime is slightly incorrect, because `DbWeight` of other runtimes may differ
|
||||
// from the `DbWeight` of Rialto runtime. But now (and most probably forever) it is the same.
|
||||
type GrandpaPalletWeights = pallet_bridge_grandpa::weights::RialtoWeight<rialto_runtime::Runtime>;
|
||||
|
||||
// The following formula shall not be treated as super-accurate - guard is to protect from mad relays,
|
||||
// not to protect from over-average loses.
|
||||
|
||||
// increase number of headers a bit
|
||||
let expected_source_headers_per_day = expected_source_headers_per_day * 110 / 100;
|
||||
let single_source_header_submit_call_weight =
|
||||
GrandpaPalletWeights::submit_finality_proof(AVG_VOTES_ANCESTRIES_LEN, AVG_PRECOMMITS_LEN);
|
||||
// for simplicity - add extra weight for base tx fee + fee that is paid for the tx size + adjusted fee
|
||||
let single_source_header_submit_tx_weight = single_source_header_submit_call_weight * 3 / 2;
|
||||
let single_source_header_tx_cost = W::calc(&single_source_header_submit_tx_weight);
|
||||
let maximal_expected_decrease = single_source_header_tx_cost * B::from(expected_source_headers_per_day);
|
||||
|
||||
maximal_expected_decrease
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn maximal_balance_decrease_per_day_is_sane() {
|
||||
// we expect Kusama -> Polkadot relay to be running in mandatory-headers-only mode
|
||||
// => we expect single header for every Kusama session
|
||||
let maximal_balance_decrease = compute_maximal_balance_decrease_per_day::<
|
||||
bp_polkadot::Balance,
|
||||
bp_polkadot::WeightToFee,
|
||||
>(bp_kusama::DAYS / bp_kusama::SESSION_LENGTH + 1);
|
||||
assert!(
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease,
|
||||
"Maximal expected loss per day {} is larger than hardcoded {}",
|
||||
maximal_balance_decrease,
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
// 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/>.
|
||||
|
||||
//! Kusama-to-Polkadot messages sync entrypoint.
|
||||
|
||||
use std::{ops::RangeInclusive, time::Duration};
|
||||
|
||||
use codec::Encode;
|
||||
use sp_core::{Bytes, Pair};
|
||||
|
||||
use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_kusama_client::{HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_substrate_client::{Chain, Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Kusama-to-Polkadot message lane.
|
||||
pub type MessageLaneKusamaMessagesToPolkadot =
|
||||
SubstrateMessageLaneToSubstrate<Kusama, KusamaSigningParams, Polkadot, PolkadotSigningParams>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct KusamaMessagesToPolkadot {
|
||||
message_lane: MessageLaneKusamaMessagesToPolkadot,
|
||||
}
|
||||
|
||||
impl SubstrateMessageLane for KusamaMessagesToPolkadot {
|
||||
type MessageLane = MessageLaneKusamaMessagesToPolkadot;
|
||||
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::TO_POLKADOT_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_kusama::FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_kusama::FROM_KUSAMA_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_polkadot::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Kusama;
|
||||
type TargetChain = Polkadot;
|
||||
|
||||
fn source_transactions_author(&self) -> bp_kusama::AccountId {
|
||||
(*self.message_lane.source_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
transaction_nonce: bp_runtime::IndexOf<Kusama>,
|
||||
_generated_at_block: PolkadotHeaderId,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesReceivingProof,
|
||||
) -> Bytes {
|
||||
let (relayers_state, proof) = proof;
|
||||
let call = relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_delivery_proof(
|
||||
proof,
|
||||
relayers_state,
|
||||
),
|
||||
);
|
||||
let genesis_hash = *self.message_lane.source_client.genesis_hash();
|
||||
let transaction = Kusama::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.message_lane.source_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared Polkadot -> Kusama confirmation transaction. Weight: <unknown>/{}, size: {}/{}",
|
||||
bp_kusama::max_extrinsic_weight(),
|
||||
transaction.encode().len(),
|
||||
bp_kusama::max_extrinsic_size(),
|
||||
);
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
|
||||
fn target_transactions_author(&self) -> bp_polkadot::AccountId {
|
||||
(*self.message_lane.target_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
transaction_nonce: bp_runtime::IndexOf<Polkadot>,
|
||||
_generated_at_header: KusamaHeaderId,
|
||||
_nonces: RangeInclusive<MessageNonce>,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
|
||||
let call = relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_proof(
|
||||
self.message_lane.relayer_id_at_source.clone(),
|
||||
proof,
|
||||
messages_count as _,
|
||||
dispatch_weight,
|
||||
),
|
||||
);
|
||||
let genesis_hash = *self.message_lane.target_client.genesis_hash();
|
||||
let transaction = Polkadot::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.message_lane.target_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared Kusama -> Polkadot delivery transaction. Weight: <unknown>/{}, size: {}/{}",
|
||||
bp_polkadot::max_extrinsic_weight(),
|
||||
transaction.encode().len(),
|
||||
bp_polkadot::max_extrinsic_size(),
|
||||
);
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
}
|
||||
|
||||
/// Kusama node as messages source.
|
||||
type KusamaSourceClient = SubstrateMessagesSource<KusamaMessagesToPolkadot>;
|
||||
|
||||
/// Polkadot node as messages target.
|
||||
type PolkadotTargetClient = SubstrateMessagesTarget<KusamaMessagesToPolkadot>;
|
||||
|
||||
/// Run Kusama-to-Polkadot messages sync.
|
||||
pub async fn run(
|
||||
params: MessagesRelayParams<Kusama, KusamaSigningParams, Polkadot, PolkadotSigningParams>,
|
||||
) -> anyhow::Result<()> {
|
||||
let stall_timeout = Duration::from_secs(5 * 60);
|
||||
let relayer_id_at_kusama = (*params.source_sign.public().as_array_ref()).into();
|
||||
|
||||
let lane_id = params.lane_id;
|
||||
let source_client = params.source_client;
|
||||
let lane = KusamaMessagesToPolkadot {
|
||||
message_lane: SubstrateMessageLaneToSubstrate {
|
||||
source_client: source_client.clone(),
|
||||
source_sign: params.source_sign,
|
||||
target_client: params.target_client.clone(),
|
||||
target_sign: params.target_sign,
|
||||
relayer_id_at_source: relayer_id_at_kusama,
|
||||
},
|
||||
};
|
||||
|
||||
// 2/3 is reserved for proofs and tx overhead
|
||||
let max_messages_size_in_single_batch = bp_polkadot::max_extrinsic_size() / 3;
|
||||
// we don't know exact weights of the Polkadot runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
bp_polkadot::max_extrinsic_weight(),
|
||||
bp_polkadot::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = (
|
||||
max_messages_in_single_batch / 2,
|
||||
max_messages_weight_in_single_batch / 2,
|
||||
);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting Kusama -> Polkadot messages relay.\n\t\
|
||||
Kusama relayer account id: {:?}\n\t\
|
||||
Max messages in single transaction: {}\n\t\
|
||||
Max messages size in single transaction: {}\n\t\
|
||||
Max messages weight in single transaction: {}\n\t\
|
||||
Relayer mode: {:?}",
|
||||
lane.message_lane.relayer_id_at_source,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
params.relayer_mode,
|
||||
);
|
||||
|
||||
let (metrics_params, metrics_values) = add_standalone_metrics(
|
||||
Some(messages_relay::message_lane_loop::metrics_prefix::<
|
||||
<KusamaMessagesToPolkadot as SubstrateMessageLane>::MessageLane,
|
||||
>(&lane_id)),
|
||||
params.metrics_params,
|
||||
source_client.clone(),
|
||||
)?;
|
||||
messages_relay::message_lane_loop::run(
|
||||
messages_relay::message_lane_loop::Params {
|
||||
lane: lane_id,
|
||||
source_tick: Kusama::AVERAGE_BLOCK_INTERVAL,
|
||||
target_tick: Polkadot::AVERAGE_BLOCK_INTERVAL,
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_polkadot::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_polkadot::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
relayer_mode: params.relayer_mode,
|
||||
},
|
||||
},
|
||||
KusamaSourceClient::new(
|
||||
source_client.clone(),
|
||||
lane.clone(),
|
||||
lane_id,
|
||||
params.target_to_source_headers_relay,
|
||||
),
|
||||
PolkadotTargetClient::new(
|
||||
params.target_client,
|
||||
lane,
|
||||
lane_id,
|
||||
metrics_values,
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
metrics_params,
|
||||
futures::future::pending(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Add standalone metrics for the Kusama -> Polkadot messages loop.
|
||||
pub(crate) fn add_standalone_metrics(
|
||||
metrics_prefix: Option<String>,
|
||||
metrics_params: MetricsParams,
|
||||
source_client: Client<Kusama>,
|
||||
) -> anyhow::Result<(MetricsParams, StandaloneMessagesMetrics)> {
|
||||
let polkadot_to_kusama_conversion_rate_key =
|
||||
bp_runtime::storage_parameter_key(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME).0;
|
||||
|
||||
substrate_relay_helper::messages_lane::add_standalone_metrics::<KusamaMessagesToPolkadot>(
|
||||
metrics_prefix,
|
||||
metrics_params,
|
||||
source_client,
|
||||
Some(crate::chains::polkadot::TOKEN_ID),
|
||||
Some(crate::chains::kusama::TOKEN_ID),
|
||||
Some((
|
||||
sp_core::storage::StorageKey(polkadot_to_kusama_conversion_rate_key),
|
||||
// starting relay before this parameter will be set to some value may cause troubles
|
||||
FixedU128::from_inner(FixedU128::DIV),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Update Polkadot -> Kusama conversion rate, stored in Kusama runtime storage.
|
||||
pub(crate) async fn update_polkadot_to_kusama_conversion_rate(
|
||||
client: Client<Kusama>,
|
||||
signer: <Kusama as TransactionSignScheme>::AccountKeyPair,
|
||||
updated_rate: f64,
|
||||
) -> anyhow::Result<()> {
|
||||
let genesis_hash = *client.genesis_hash();
|
||||
let signer_id = (*signer.public().as_array_ref()).into();
|
||||
client
|
||||
.submit_signed_extrinsic(signer_id, move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Kusama::sign_transaction(
|
||||
genesis_hash,
|
||||
&signer,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::update_pallet_parameter(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesParameter::PolkadotToKusamaConversionRate(
|
||||
sp_runtime::FixedU128::from_float(updated_rate),
|
||||
)
|
||||
)
|
||||
),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
.await
|
||||
.map(drop)
|
||||
.map_err(|err| anyhow::format_err!("{:?}", err))
|
||||
}
|
||||
@@ -16,8 +16,12 @@
|
||||
|
||||
//! Chain-specific relayer configuration.
|
||||
|
||||
pub mod kusama_headers_to_polkadot;
|
||||
pub mod kusama_messages_to_polkadot;
|
||||
pub mod millau_headers_to_rialto;
|
||||
pub mod millau_messages_to_rialto;
|
||||
pub mod polkadot_headers_to_kusama;
|
||||
pub mod polkadot_messages_to_kusama;
|
||||
pub mod rialto_headers_to_millau;
|
||||
pub mod rialto_messages_to_millau;
|
||||
pub mod rococo_headers_to_wococo;
|
||||
@@ -26,7 +30,9 @@ pub mod westend_headers_to_millau;
|
||||
pub mod wococo_headers_to_rococo;
|
||||
pub mod wococo_messages_to_rococo;
|
||||
|
||||
mod kusama;
|
||||
mod millau;
|
||||
mod polkadot;
|
||||
mod rialto;
|
||||
mod rococo;
|
||||
mod westend;
|
||||
@@ -37,9 +43,9 @@ mod wococo;
|
||||
// Rialto as BTC and Millau as wBTC (only in relayer).
|
||||
|
||||
/// The identifier of token, which value is associated with Rialto token value by relayer.
|
||||
pub(crate) const RIALTO_ASSOCIATED_TOKEN_ID: &str = "polkadot";
|
||||
pub(crate) const RIALTO_ASSOCIATED_TOKEN_ID: &str = polkadot::TOKEN_ID;
|
||||
/// The identifier of token, which value is associated with Millau token value by relayer.
|
||||
pub(crate) const MILLAU_ASSOCIATED_TOKEN_ID: &str = "kusama";
|
||||
pub(crate) const MILLAU_ASSOCIATED_TOKEN_ID: &str = kusama::TOKEN_ID;
|
||||
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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 codec::Decode;
|
||||
use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight};
|
||||
use relay_polkadot_client::Polkadot;
|
||||
use sp_version::RuntimeVersion;
|
||||
|
||||
use crate::cli::{
|
||||
bridge,
|
||||
encode_call::{Call, CliEncodeCall},
|
||||
encode_message, CliChain,
|
||||
};
|
||||
|
||||
/// Weight of the `system::remark` call at Polkadot.
|
||||
///
|
||||
/// This weight is larger (x2) than actual weight at current Polkadot runtime to avoid unsuccessful
|
||||
/// calls in the future. But since it is used only in tests (and on test chains), this is ok.
|
||||
pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000;
|
||||
|
||||
/// Id of Polkadot token that is used to fetch token price.
|
||||
pub(crate) const TOKEN_ID: &str = "polkadot";
|
||||
|
||||
impl CliEncodeCall for Polkadot {
|
||||
fn max_extrinsic_size() -> u32 {
|
||||
bp_polkadot::max_extrinsic_size()
|
||||
}
|
||||
|
||||
fn encode_call(call: &Call) -> anyhow::Result<Self::Call> {
|
||||
Ok(match call {
|
||||
Call::Remark { remark_payload, .. } => {
|
||||
relay_polkadot_client::runtime::Call::System(relay_polkadot_client::runtime::SystemCall::remark(
|
||||
remark_payload.as_ref().map(|x| x.0.clone()).unwrap_or_default(),
|
||||
))
|
||||
}
|
||||
Call::BridgeSendMessage {
|
||||
lane,
|
||||
payload,
|
||||
fee,
|
||||
bridge_instance_index,
|
||||
} => match *bridge_instance_index {
|
||||
bridge::POLKADOT_TO_KUSAMA_INDEX => {
|
||||
let payload = Decode::decode(&mut &*payload.0)?;
|
||||
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::send_message(lane.0, payload, fee.0),
|
||||
)
|
||||
}
|
||||
_ => anyhow::bail!(
|
||||
"Unsupported target bridge pallet with instance index: {}",
|
||||
bridge_instance_index
|
||||
),
|
||||
},
|
||||
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_dispatch_info(call: &relay_polkadot_client::runtime::Call) -> anyhow::Result<DispatchInfo> {
|
||||
match *call {
|
||||
relay_polkadot_client::runtime::Call::System(relay_polkadot_client::runtime::SystemCall::remark(_)) => {
|
||||
Ok(DispatchInfo {
|
||||
weight: crate::chains::polkadot::SYSTEM_REMARK_CALL_WEIGHT,
|
||||
class: DispatchClass::Normal,
|
||||
pays_fee: Pays::Yes,
|
||||
})
|
||||
}
|
||||
_ => anyhow::bail!("Unsupported Polkadot call: {:?}", call),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CliChain for Polkadot {
|
||||
const RUNTIME_VERSION: RuntimeVersion = bp_polkadot::VERSION;
|
||||
|
||||
type KeyPair = sp_core::sr25519::Pair;
|
||||
type MessagePayload = ();
|
||||
|
||||
fn ss58_format() -> u16 {
|
||||
42
|
||||
}
|
||||
|
||||
fn max_extrinsic_weight() -> Weight {
|
||||
bp_polkadot::max_extrinsic_weight()
|
||||
}
|
||||
|
||||
fn encode_message(_message: encode_message::MessagePayload) -> Result<Self::MessagePayload, String> {
|
||||
Err("Sending messages from Polkadot is not yet supported.".into())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// 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/>.
|
||||
|
||||
//! Polkadot-to-Kusama headers sync entrypoint.
|
||||
|
||||
use codec::Encode;
|
||||
use sp_core::{Bytes, Pair};
|
||||
|
||||
use bp_header_chain::justification::GrandpaJustification;
|
||||
use relay_kusama_client::{Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{Polkadot, SyncHeader as PolkadotSyncHeader};
|
||||
use relay_substrate_client::{Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use substrate_relay_helper::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
|
||||
/// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat
|
||||
/// relay as gone wild.
|
||||
///
|
||||
/// Actual value, returned by `maximal_balance_decrease_per_day_is_sane` test is approximately 0.001 KSM,
|
||||
/// but let's round up to 0.1 KSM here.
|
||||
pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_polkadot::Balance = 100_000_000_000;
|
||||
|
||||
/// Polkadot-to-Kusama finality sync pipeline.
|
||||
pub(crate) type FinalityPipelinePolkadotFinalityToKusama =
|
||||
SubstrateFinalityToSubstrate<Polkadot, Kusama, KusamaSigningParams>;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct PolkadotFinalityToKusama {
|
||||
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama,
|
||||
}
|
||||
|
||||
impl PolkadotFinalityToKusama {
|
||||
pub fn new(target_client: Client<Kusama>, target_sign: KusamaSigningParams) -> Self {
|
||||
Self {
|
||||
finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new(target_client, target_sign),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SubstrateFinalitySyncPipeline for PolkadotFinalityToKusama {
|
||||
type FinalitySyncPipeline = FinalityPipelinePolkadotFinalityToKusama;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
|
||||
type TargetChain = Kusama;
|
||||
|
||||
fn customize_metrics(params: MetricsParams) -> anyhow::Result<MetricsParams> {
|
||||
crate::chains::add_polkadot_kusama_price_metrics::<Self::FinalitySyncPipeline>(
|
||||
Some(finality_relay::metrics_prefix::<Self::FinalitySyncPipeline>()),
|
||||
params,
|
||||
)
|
||||
}
|
||||
|
||||
fn start_relay_guards(&self) {
|
||||
relay_substrate_client::guard::abort_on_spec_version_change(
|
||||
self.finality_pipeline.target_client.clone(),
|
||||
bp_kusama::VERSION.spec_version,
|
||||
);
|
||||
relay_substrate_client::guard::abort_when_account_balance_decreased(
|
||||
self.finality_pipeline.target_client.clone(),
|
||||
self.transactions_author(),
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY,
|
||||
);
|
||||
}
|
||||
|
||||
fn transactions_author(&self) -> bp_kusama::AccountId {
|
||||
(*self.finality_pipeline.target_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_submit_finality_proof_transaction(
|
||||
&self,
|
||||
era: bp_runtime::TransactionEraOf<Kusama>,
|
||||
transaction_nonce: bp_runtime::IndexOf<Kusama>,
|
||||
header: PolkadotSyncHeader,
|
||||
proof: GrandpaJustification<bp_polkadot::Header>,
|
||||
) -> Bytes {
|
||||
let call = relay_kusama_client::runtime::Call::BridgePolkadotGrandpa(
|
||||
relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof(header.into_inner(), proof),
|
||||
);
|
||||
let genesis_hash = *self.finality_pipeline.target_client.genesis_hash();
|
||||
let transaction = Kusama::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.finality_pipeline.target_sign,
|
||||
era,
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::chains::kusama_headers_to_polkadot::tests::compute_maximal_balance_decrease_per_day;
|
||||
|
||||
#[test]
|
||||
fn maximal_balance_decrease_per_day_is_sane() {
|
||||
// we expect Polkadot -> Kusama relay to be running in mandatory-headers-only mode
|
||||
// => we expect single header for every Polkadot session
|
||||
let maximal_balance_decrease = compute_maximal_balance_decrease_per_day::<
|
||||
bp_kusama::Balance,
|
||||
bp_kusama::WeightToFee,
|
||||
>(bp_polkadot::DAYS / bp_polkadot::SESSION_LENGTH + 1);
|
||||
assert!(
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease,
|
||||
"Maximal expected loss per day {} is larger than hardcoded {}",
|
||||
maximal_balance_decrease,
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
// 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/>.
|
||||
|
||||
//! Polkadot-to-Kusama messages sync entrypoint.
|
||||
|
||||
use std::{ops::RangeInclusive, time::Duration};
|
||||
|
||||
use codec::Encode;
|
||||
use sp_core::{Bytes, Pair};
|
||||
|
||||
use bp_messages::MessageNonce;
|
||||
use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof;
|
||||
use frame_support::weights::Weight;
|
||||
use messages_relay::message_lane::MessageLane;
|
||||
use relay_kusama_client::{HeaderId as KusamaHeaderId, Kusama, SigningParams as KusamaSigningParams};
|
||||
use relay_polkadot_client::{HeaderId as PolkadotHeaderId, Polkadot, SigningParams as PolkadotSigningParams};
|
||||
use relay_substrate_client::{Chain, Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_runtime::{FixedPointNumber, FixedU128};
|
||||
use substrate_relay_helper::messages_lane::{
|
||||
select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, SubstrateMessageLane,
|
||||
SubstrateMessageLaneToSubstrate,
|
||||
};
|
||||
use substrate_relay_helper::messages_source::SubstrateMessagesSource;
|
||||
use substrate_relay_helper::messages_target::SubstrateMessagesTarget;
|
||||
|
||||
/// Polkadot-to-Kusama message lane.
|
||||
pub type MessageLanePolkadotMessagesToKusama =
|
||||
SubstrateMessageLaneToSubstrate<Polkadot, PolkadotSigningParams, Kusama, KusamaSigningParams>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PolkadotMessagesToKusama {
|
||||
message_lane: MessageLanePolkadotMessagesToKusama,
|
||||
}
|
||||
|
||||
impl SubstrateMessageLane for PolkadotMessagesToKusama {
|
||||
type MessageLane = MessageLanePolkadotMessagesToKusama;
|
||||
const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str =
|
||||
bp_kusama::TO_KUSAMA_LATEST_GENERATED_NONCE_METHOD;
|
||||
const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = bp_kusama::TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD;
|
||||
|
||||
const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::FROM_POLKADOT_LATEST_RECEIVED_NONCE_METHOD;
|
||||
const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str =
|
||||
bp_polkadot::FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD;
|
||||
const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = bp_polkadot::FROM_POLKADOT_UNREWARDED_RELAYERS_STATE;
|
||||
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD;
|
||||
const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD;
|
||||
|
||||
const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_polkadot::WITH_KUSAMA_MESSAGES_PALLET_NAME;
|
||||
const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_kusama::WITH_POLKADOT_MESSAGES_PALLET_NAME;
|
||||
|
||||
const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = bp_kusama::PAY_INBOUND_DISPATCH_FEE_WEIGHT;
|
||||
|
||||
type SourceChain = Polkadot;
|
||||
type TargetChain = Kusama;
|
||||
|
||||
fn source_transactions_author(&self) -> bp_polkadot::AccountId {
|
||||
(*self.message_lane.source_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_messages_receiving_proof_transaction(
|
||||
&self,
|
||||
transaction_nonce: bp_runtime::IndexOf<Polkadot>,
|
||||
_generated_at_block: KusamaHeaderId,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesReceivingProof,
|
||||
) -> Bytes {
|
||||
let (relayers_state, proof) = proof;
|
||||
let call = relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_delivery_proof(
|
||||
proof,
|
||||
relayers_state,
|
||||
),
|
||||
);
|
||||
let genesis_hash = *self.message_lane.source_client.genesis_hash();
|
||||
let transaction = Polkadot::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.message_lane.source_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared Kusama -> Polkadot confirmation transaction. Weight: <unknown>/{}, size: {}/{}",
|
||||
bp_polkadot::max_extrinsic_weight(),
|
||||
transaction.encode().len(),
|
||||
bp_polkadot::max_extrinsic_size(),
|
||||
);
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
|
||||
fn target_transactions_author(&self) -> bp_kusama::AccountId {
|
||||
(*self.message_lane.target_sign.public().as_array_ref()).into()
|
||||
}
|
||||
|
||||
fn make_messages_delivery_transaction(
|
||||
&self,
|
||||
transaction_nonce: bp_runtime::IndexOf<Kusama>,
|
||||
_generated_at_header: PolkadotHeaderId,
|
||||
_nonces: RangeInclusive<MessageNonce>,
|
||||
proof: <Self::MessageLane as MessageLane>::MessagesProof,
|
||||
) -> Bytes {
|
||||
let (dispatch_weight, proof) = proof;
|
||||
let FromBridgedChainMessagesProof {
|
||||
ref nonces_start,
|
||||
ref nonces_end,
|
||||
..
|
||||
} = proof;
|
||||
let messages_count = nonces_end - nonces_start + 1;
|
||||
|
||||
let call = relay_kusama_client::runtime::Call::BridgePolkadotMessages(
|
||||
relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_proof(
|
||||
self.message_lane.relayer_id_at_source.clone(),
|
||||
proof,
|
||||
messages_count as _,
|
||||
dispatch_weight,
|
||||
),
|
||||
);
|
||||
let genesis_hash = *self.message_lane.target_client.genesis_hash();
|
||||
let transaction = Kusama::sign_transaction(
|
||||
genesis_hash,
|
||||
&self.message_lane.target_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(call, transaction_nonce),
|
||||
);
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Prepared Polkadot -> Kusama delivery transaction. Weight: <unknown>/{}, size: {}/{}",
|
||||
bp_kusama::max_extrinsic_weight(),
|
||||
transaction.encode().len(),
|
||||
bp_kusama::max_extrinsic_size(),
|
||||
);
|
||||
Bytes(transaction.encode())
|
||||
}
|
||||
}
|
||||
|
||||
/// Polkadot node as messages source.
|
||||
type PolkadotSourceClient = SubstrateMessagesSource<PolkadotMessagesToKusama>;
|
||||
|
||||
/// Kusama node as messages target.
|
||||
type KusamaTargetClient = SubstrateMessagesTarget<PolkadotMessagesToKusama>;
|
||||
|
||||
/// Run Polkadot-to-Kusama messages sync.
|
||||
pub async fn run(
|
||||
params: MessagesRelayParams<Polkadot, PolkadotSigningParams, Kusama, KusamaSigningParams>,
|
||||
) -> anyhow::Result<()> {
|
||||
let stall_timeout = Duration::from_secs(5 * 60);
|
||||
let relayer_id_at_polkadot = (*params.source_sign.public().as_array_ref()).into();
|
||||
|
||||
let lane_id = params.lane_id;
|
||||
let source_client = params.source_client;
|
||||
let lane = PolkadotMessagesToKusama {
|
||||
message_lane: SubstrateMessageLaneToSubstrate {
|
||||
source_client: source_client.clone(),
|
||||
source_sign: params.source_sign,
|
||||
target_client: params.target_client.clone(),
|
||||
target_sign: params.target_sign,
|
||||
relayer_id_at_source: relayer_id_at_polkadot,
|
||||
},
|
||||
};
|
||||
|
||||
// 2/3 is reserved for proofs and tx overhead
|
||||
let max_messages_size_in_single_batch = bp_kusama::max_extrinsic_size() / 3;
|
||||
// we don't know exact weights of the Kusama runtime. So to guess weights we'll be using
|
||||
// weights from Rialto and then simply dividing it by x2.
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) =
|
||||
select_delivery_transaction_limits::<pallet_bridge_messages::weights::RialtoWeight<rialto_runtime::Runtime>>(
|
||||
bp_kusama::max_extrinsic_weight(),
|
||||
bp_kusama::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
);
|
||||
let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = (
|
||||
max_messages_in_single_batch / 2,
|
||||
max_messages_weight_in_single_batch / 2,
|
||||
);
|
||||
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Starting Polkadot -> Kusama messages relay.\n\t\
|
||||
Polkadot relayer account id: {:?}\n\t\
|
||||
Max messages in single transaction: {}\n\t\
|
||||
Max messages size in single transaction: {}\n\t\
|
||||
Max messages weight in single transaction: {}\n\t\
|
||||
Relayer mode: {:?}",
|
||||
lane.message_lane.relayer_id_at_source,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
params.relayer_mode,
|
||||
);
|
||||
|
||||
let (metrics_params, metrics_values) = add_standalone_metrics(
|
||||
Some(messages_relay::message_lane_loop::metrics_prefix::<
|
||||
<PolkadotMessagesToKusama as SubstrateMessageLane>::MessageLane,
|
||||
>(&lane_id)),
|
||||
params.metrics_params,
|
||||
source_client.clone(),
|
||||
)?;
|
||||
messages_relay::message_lane_loop::run(
|
||||
messages_relay::message_lane_loop::Params {
|
||||
lane: lane_id,
|
||||
source_tick: Polkadot::AVERAGE_BLOCK_INTERVAL,
|
||||
target_tick: Kusama::AVERAGE_BLOCK_INTERVAL,
|
||||
reconnect_delay: relay_utils::relay_loop::RECONNECT_DELAY,
|
||||
stall_timeout,
|
||||
delivery_params: messages_relay::message_lane_loop::MessageDeliveryParams {
|
||||
max_unrewarded_relayer_entries_at_target: bp_kusama::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE,
|
||||
max_unconfirmed_nonces_at_target: bp_kusama::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE,
|
||||
max_messages_in_single_batch,
|
||||
max_messages_weight_in_single_batch,
|
||||
max_messages_size_in_single_batch,
|
||||
relayer_mode: params.relayer_mode,
|
||||
},
|
||||
},
|
||||
PolkadotSourceClient::new(
|
||||
source_client.clone(),
|
||||
lane.clone(),
|
||||
lane_id,
|
||||
params.target_to_source_headers_relay,
|
||||
),
|
||||
KusamaTargetClient::new(
|
||||
params.target_client,
|
||||
lane,
|
||||
lane_id,
|
||||
metrics_values,
|
||||
params.source_to_target_headers_relay,
|
||||
),
|
||||
metrics_params,
|
||||
futures::future::pending(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Add standalone metrics for the Polkadot -> Kusama messages loop.
|
||||
pub(crate) fn add_standalone_metrics(
|
||||
metrics_prefix: Option<String>,
|
||||
metrics_params: MetricsParams,
|
||||
source_client: Client<Polkadot>,
|
||||
) -> anyhow::Result<(MetricsParams, StandaloneMessagesMetrics)> {
|
||||
let kusama_to_polkadot_conversion_rate_key =
|
||||
bp_runtime::storage_parameter_key(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME).0;
|
||||
|
||||
substrate_relay_helper::messages_lane::add_standalone_metrics::<PolkadotMessagesToKusama>(
|
||||
metrics_prefix,
|
||||
metrics_params,
|
||||
source_client,
|
||||
Some(crate::chains::kusama::TOKEN_ID),
|
||||
Some(crate::chains::polkadot::TOKEN_ID),
|
||||
Some((
|
||||
sp_core::storage::StorageKey(kusama_to_polkadot_conversion_rate_key),
|
||||
// starting relay before this parameter will be set to some value may cause troubles
|
||||
FixedU128::from_inner(FixedU128::DIV),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Update Kusama -> Polkadot conversion rate, stored in Polkadot runtime storage.
|
||||
pub(crate) async fn update_kusama_to_polkadot_conversion_rate(
|
||||
client: Client<Polkadot>,
|
||||
signer: <Polkadot as TransactionSignScheme>::AccountKeyPair,
|
||||
updated_rate: f64,
|
||||
) -> anyhow::Result<()> {
|
||||
let genesis_hash = *client.genesis_hash();
|
||||
let signer_id = (*signer.public().as_array_ref()).into();
|
||||
client
|
||||
.submit_signed_extrinsic(signer_id, move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Polkadot::sign_transaction(
|
||||
genesis_hash,
|
||||
&signer,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
relay_polkadot_client::runtime::Call::BridgeKusamaMessages(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesCall::update_pallet_parameter(
|
||||
relay_polkadot_client::runtime::BridgeKusamaMessagesParameter::KusamaToPolkadotConversionRate(
|
||||
sp_runtime::FixedU128::from_float(updated_rate),
|
||||
)
|
||||
)
|
||||
),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
.await
|
||||
.map(drop)
|
||||
.map_err(|err| anyhow::format_err!("{:?}", err))
|
||||
}
|
||||
@@ -104,39 +104,18 @@ impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use frame_support::weights::WeightToFeePolynomial;
|
||||
|
||||
use pallet_bridge_grandpa::weights::WeightInfo;
|
||||
|
||||
use super::*;
|
||||
use crate::chains::kusama_headers_to_polkadot::tests::compute_maximal_balance_decrease_per_day;
|
||||
|
||||
#[test]
|
||||
fn maximal_balance_decrease_per_day_is_sane() {
|
||||
// Rococo/Wococo GRANDPA pallet weights. They're now using Rialto weights => using `RialtoWeight` is justified.
|
||||
//
|
||||
// Using Rialto runtime this is slightly incorrect, because `DbWeight` of Rococo/Wococo runtime may differ
|
||||
// from the `DbWeight` of Rialto runtime. But now (and most probably forever) it is the same.
|
||||
type RococoGrandpaPalletWeights = pallet_bridge_grandpa::weights::RialtoWeight<rialto_runtime::Runtime>;
|
||||
|
||||
// The following formula shall not be treated as super-accurate - guard is to protect from mad relays,
|
||||
// not to protect from over-average loses.
|
||||
//
|
||||
// Worst case: we're submitting proof for every source header. Since we submit every header, the number of
|
||||
// headers in ancestry proof is near to 0 (let's round up to 2). And the number of authorities is 1024,
|
||||
// which is (now) larger than on any existing chain => normally there'll be ~1024*2/3+1 commits.
|
||||
const AVG_VOTES_ANCESTRIES_LEN: u32 = 2;
|
||||
const AVG_PRECOMMITS_LEN: u32 = 1024 * 2 / 3 + 1;
|
||||
let number_of_source_headers_per_day: bp_wococo::Balance = bp_wococo::DAYS as _;
|
||||
let single_source_header_submit_call_weight =
|
||||
RococoGrandpaPalletWeights::submit_finality_proof(AVG_VOTES_ANCESTRIES_LEN, AVG_PRECOMMITS_LEN);
|
||||
// for simplicity - add extra weight for base tx fee + fee that is paid for the tx size + adjusted fee
|
||||
let single_source_header_submit_tx_weight = single_source_header_submit_call_weight * 3 / 2;
|
||||
let single_source_header_tx_cost = bp_rococo::WeightToFee::calc(&single_source_header_submit_tx_weight);
|
||||
let maximal_expected_decrease = single_source_header_tx_cost * number_of_source_headers_per_day;
|
||||
// we expect Wococo -> Rococo relay to be running in all-headers mode
|
||||
let maximal_balance_decrease =
|
||||
compute_maximal_balance_decrease_per_day::<bp_kusama::Balance, bp_kusama::WeightToFee>(bp_wococo::DAYS);
|
||||
assert!(
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_expected_decrease,
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY >= maximal_balance_decrease,
|
||||
"Maximal expected loss per day {} is larger than hardcoded {}",
|
||||
maximal_expected_decrease,
|
||||
maximal_balance_decrease,
|
||||
MAXIMAL_BALANCE_DECREASE_PER_DAY,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ pub enum FullBridge {
|
||||
RialtoToMillau,
|
||||
RococoToWococo,
|
||||
WococoToRococo,
|
||||
KusamaToPolkadot,
|
||||
PolkadotToKusama,
|
||||
}
|
||||
|
||||
impl FullBridge {
|
||||
@@ -34,6 +36,8 @@ impl FullBridge {
|
||||
Self::RialtoToMillau => RIALTO_TO_MILLAU_INDEX,
|
||||
Self::RococoToWococo => ROCOCO_TO_WOCOCO_INDEX,
|
||||
Self::WococoToRococo => WOCOCO_TO_ROCOCO_INDEX,
|
||||
Self::KusamaToPolkadot => KUSAMA_TO_POLKADOT_INDEX,
|
||||
Self::PolkadotToKusama => POLKADOT_TO_KUSAMA_INDEX,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,6 +46,8 @@ pub const RIALTO_TO_MILLAU_INDEX: u8 = 0;
|
||||
pub const MILLAU_TO_RIALTO_INDEX: u8 = 0;
|
||||
pub const ROCOCO_TO_WOCOCO_INDEX: u8 = 0;
|
||||
pub const WOCOCO_TO_ROCOCO_INDEX: u8 = 0;
|
||||
pub const KUSAMA_TO_POLKADOT_INDEX: u8 = 0;
|
||||
pub const POLKADOT_TO_KUSAMA_INDEX: u8 = 0;
|
||||
|
||||
/// The macro allows executing bridge-specific code without going fully generic.
|
||||
///
|
||||
@@ -138,6 +144,50 @@ macro_rules! select_full_bridge {
|
||||
#[allow(unused_imports)]
|
||||
use relay_wococo_client::runtime::wococo_to_rococo_account_ownership_digest as account_ownership_digest;
|
||||
|
||||
$generic
|
||||
}
|
||||
FullBridge::KusamaToPolkadot => {
|
||||
type Source = relay_kusama_client::Kusama;
|
||||
#[allow(dead_code)]
|
||||
type Target = relay_polkadot_client::Polkadot;
|
||||
|
||||
// Derive-account
|
||||
#[allow(unused_imports)]
|
||||
use bp_polkadot::derive_account_from_kusama_id as derive_account;
|
||||
|
||||
// Relay-messages
|
||||
#[allow(unused_imports)]
|
||||
use crate::chains::kusama_messages_to_polkadot::run as relay_messages;
|
||||
|
||||
// Send-message / Estimate-fee
|
||||
#[allow(unused_imports)]
|
||||
use bp_polkadot::TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
|
||||
// Send-message
|
||||
#[allow(unused_imports)]
|
||||
use relay_kusama_client::runtime::kusama_to_polkadot_account_ownership_digest as account_ownership_digest;
|
||||
|
||||
$generic
|
||||
}
|
||||
FullBridge::PolkadotToKusama => {
|
||||
type Source = relay_polkadot_client::Polkadot;
|
||||
#[allow(dead_code)]
|
||||
type Target = relay_kusama_client::Kusama;
|
||||
|
||||
// Derive-account
|
||||
#[allow(unused_imports)]
|
||||
use bp_kusama::derive_account_from_polkadot_id as derive_account;
|
||||
|
||||
// Relay-messages
|
||||
#[allow(unused_imports)]
|
||||
use crate::chains::polkadot_messages_to_kusama::run as relay_messages;
|
||||
|
||||
// Send-message / Estimate-fee
|
||||
#[allow(unused_imports)]
|
||||
use bp_kusama::TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
|
||||
// Send-message
|
||||
#[allow(unused_imports)]
|
||||
use relay_polkadot_client::runtime::polkadot_to_kusama_account_ownership_digest as account_ownership_digest;
|
||||
|
||||
$generic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ pub enum InitBridgeName {
|
||||
WestendToMillau,
|
||||
RococoToWococo,
|
||||
WococoToRococo,
|
||||
KusamaToPolkadot,
|
||||
PolkadotToKusama,
|
||||
}
|
||||
|
||||
macro_rules! select_bridge {
|
||||
@@ -127,6 +129,34 @@ macro_rules! select_bridge {
|
||||
)
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
InitBridgeName::KusamaToPolkadot => {
|
||||
type Source = relay_kusama_client::Kusama;
|
||||
type Target = relay_polkadot_client::Polkadot;
|
||||
|
||||
fn encode_init_bridge(
|
||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||
) -> <Target as Chain>::Call {
|
||||
relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa(
|
||||
relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::initialize(init_data),
|
||||
)
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
InitBridgeName::PolkadotToKusama => {
|
||||
type Source = relay_polkadot_client::Polkadot;
|
||||
type Target = relay_kusama_client::Kusama;
|
||||
|
||||
fn encode_init_bridge(
|
||||
init_data: InitializationData<<Source as ChainBase>::Header>,
|
||||
) -> <Target as Chain>::Call {
|
||||
relay_kusama_client::runtime::Call::BridgePolkadotGrandpa(
|
||||
relay_kusama_client::runtime::BridgePolkadotGrandpaCall::initialize(init_data),
|
||||
)
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ pub enum RelayHeadersBridge {
|
||||
WestendToMillau,
|
||||
RococoToWococo,
|
||||
WococoToRococo,
|
||||
KusamaToPolkadot,
|
||||
PolkadotToKusama,
|
||||
}
|
||||
|
||||
macro_rules! select_bridge {
|
||||
@@ -87,6 +89,20 @@ macro_rules! select_bridge {
|
||||
type Target = relay_rococo_client::Rococo;
|
||||
type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo;
|
||||
|
||||
$generic
|
||||
}
|
||||
RelayHeadersBridge::KusamaToPolkadot => {
|
||||
type Source = relay_kusama_client::Kusama;
|
||||
type Target = relay_polkadot_client::Polkadot;
|
||||
type Finality = crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot;
|
||||
|
||||
$generic
|
||||
}
|
||||
RelayHeadersBridge::PolkadotToKusama => {
|
||||
type Source = relay_polkadot_client::Polkadot;
|
||||
type Target = relay_kusama_client::Kusama;
|
||||
type Finality = crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama;
|
||||
|
||||
$generic
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,8 +26,10 @@ use futures::{FutureExt, TryFutureExt};
|
||||
use structopt::StructOpt;
|
||||
use strum::VariantNames;
|
||||
|
||||
use relay_substrate_client::{Chain, Client, TransactionSignScheme};
|
||||
use codec::Encode;
|
||||
use relay_substrate_client::{AccountIdOf, Chain, Client, TransactionSignScheme, UnsignedTransaction};
|
||||
use relay_utils::metrics::MetricsParams;
|
||||
use sp_core::{Bytes, Pair};
|
||||
use substrate_relay_helper::messages_lane::{MessagesRelayParams, SubstrateMessageLane};
|
||||
use substrate_relay_helper::on_demand_headers::OnDemandHeadersRelay;
|
||||
|
||||
@@ -47,6 +49,7 @@ const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
|
||||
pub enum RelayHeadersAndMessages {
|
||||
MillauRialto(MillauRialtoHeadersAndMessages),
|
||||
RococoWococo(RococoWococoHeadersAndMessages),
|
||||
KusamaPolkadot(KusamaPolkadotHeadersAndMessages),
|
||||
}
|
||||
|
||||
/// Parameters that have the same names across all bridges.
|
||||
@@ -57,6 +60,9 @@ pub struct HeadersAndMessagesSharedParams {
|
||||
lane: Vec<HexLaneId>,
|
||||
#[structopt(long, possible_values = RelayerMode::VARIANTS, case_insensitive = true, default_value = "rational")]
|
||||
relayer_mode: RelayerMode,
|
||||
/// Create relayers fund accounts on both chains, if it does not exists yet.
|
||||
#[structopt(long)]
|
||||
create_relayers_fund_accounts: bool,
|
||||
/// If passed, only mandatory headers (headers that are changing the GRANDPA authorities set) are relayed.
|
||||
#[structopt(long)]
|
||||
only_mandatory_headers: bool,
|
||||
@@ -89,7 +95,6 @@ macro_rules! declare_bridge_options {
|
||||
right_messages_pallet_owner: [<$chain2 MessagesPalletOwnerSigningParams>],
|
||||
}
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
impl From<RelayHeadersAndMessages> for [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
fn from(relay_params: RelayHeadersAndMessages) -> [<$chain1 $chain2 HeadersAndMessages>] {
|
||||
match relay_params {
|
||||
@@ -117,6 +122,9 @@ macro_rules! select_bridge {
|
||||
type LeftToRightMessages = crate::chains::millau_messages_to_rialto::MillauMessagesToRialto;
|
||||
type RightToLeftMessages = crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau;
|
||||
|
||||
type LeftAccountIdConverter = bp_millau::AccountIdConverter;
|
||||
type RightAccountIdConverter = bp_rialto::AccountIdConverter;
|
||||
|
||||
const MAX_MISSING_LEFT_HEADERS_AT_RIGHT: bp_millau::BlockNumber = bp_millau::SESSION_LENGTH;
|
||||
const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_rialto::BlockNumber = bp_rialto::SESSION_LENGTH;
|
||||
|
||||
@@ -129,6 +137,22 @@ macro_rules! select_bridge {
|
||||
update_millau_to_rialto_conversion_rate as update_left_to_right_conversion_rate,
|
||||
};
|
||||
|
||||
async fn left_create_account(
|
||||
_left_client: Client<Left>,
|
||||
_left_sign: <Left as TransactionSignScheme>::AccountKeyPair,
|
||||
_account_id: AccountIdOf<Left>,
|
||||
) -> anyhow::Result<()> {
|
||||
Err(anyhow::format_err!("Account creation is not supported by this bridge"))
|
||||
}
|
||||
|
||||
async fn right_create_account(
|
||||
_right_client: Client<Right>,
|
||||
_right_sign: <Right as TransactionSignScheme>::AccountKeyPair,
|
||||
_account_id: AccountIdOf<Right>,
|
||||
) -> anyhow::Result<()> {
|
||||
Err(anyhow::format_err!("Account creation is not supported by this bridge"))
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
RelayHeadersAndMessages::RococoWococo(_) => {
|
||||
@@ -143,6 +167,9 @@ macro_rules! select_bridge {
|
||||
type LeftToRightMessages = crate::chains::rococo_messages_to_wococo::RococoMessagesToWococo;
|
||||
type RightToLeftMessages = crate::chains::wococo_messages_to_rococo::WococoMessagesToRococo;
|
||||
|
||||
type LeftAccountIdConverter = bp_rococo::AccountIdConverter;
|
||||
type RightAccountIdConverter = bp_wococo::AccountIdConverter;
|
||||
|
||||
const MAX_MISSING_LEFT_HEADERS_AT_RIGHT: bp_rococo::BlockNumber = bp_rococo::SESSION_LENGTH;
|
||||
const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_wococo::BlockNumber = bp_wococo::SESSION_LENGTH;
|
||||
|
||||
@@ -169,6 +196,113 @@ macro_rules! select_bridge {
|
||||
Err(anyhow::format_err!("Conversion rate is not supported by this bridge"))
|
||||
}
|
||||
|
||||
async fn left_create_account(
|
||||
_left_client: Client<Left>,
|
||||
_left_sign: <Left as TransactionSignScheme>::AccountKeyPair,
|
||||
_account_id: AccountIdOf<Left>,
|
||||
) -> anyhow::Result<()> {
|
||||
Err(anyhow::format_err!("Account creation is not supported by this bridge"))
|
||||
}
|
||||
|
||||
async fn right_create_account(
|
||||
_right_client: Client<Right>,
|
||||
_right_sign: <Right as TransactionSignScheme>::AccountKeyPair,
|
||||
_account_id: AccountIdOf<Right>,
|
||||
) -> anyhow::Result<()> {
|
||||
Err(anyhow::format_err!("Account creation is not supported by this bridge"))
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
RelayHeadersAndMessages::KusamaPolkadot(_) => {
|
||||
type Params = KusamaPolkadotHeadersAndMessages;
|
||||
|
||||
type Left = relay_kusama_client::Kusama;
|
||||
type Right = relay_polkadot_client::Polkadot;
|
||||
|
||||
type LeftToRightFinality = crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot;
|
||||
type RightToLeftFinality = crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama;
|
||||
|
||||
type LeftToRightMessages = crate::chains::kusama_messages_to_polkadot::KusamaMessagesToPolkadot;
|
||||
type RightToLeftMessages = crate::chains::polkadot_messages_to_kusama::PolkadotMessagesToKusama;
|
||||
|
||||
type LeftAccountIdConverter = bp_kusama::AccountIdConverter;
|
||||
type RightAccountIdConverter = bp_polkadot::AccountIdConverter;
|
||||
|
||||
const MAX_MISSING_LEFT_HEADERS_AT_RIGHT: bp_kusama::BlockNumber = bp_kusama::SESSION_LENGTH;
|
||||
const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_polkadot::BlockNumber = bp_polkadot::SESSION_LENGTH;
|
||||
|
||||
use crate::chains::kusama_messages_to_polkadot::{
|
||||
add_standalone_metrics as add_left_to_right_standalone_metrics, run as left_to_right_messages,
|
||||
update_polkadot_to_kusama_conversion_rate as update_right_to_left_conversion_rate,
|
||||
};
|
||||
use crate::chains::polkadot_messages_to_kusama::{
|
||||
add_standalone_metrics as add_right_to_left_standalone_metrics, run as right_to_left_messages,
|
||||
update_kusama_to_polkadot_conversion_rate as update_left_to_right_conversion_rate,
|
||||
};
|
||||
|
||||
async fn left_create_account(
|
||||
left_client: Client<Left>,
|
||||
left_sign: <Left as TransactionSignScheme>::AccountKeyPair,
|
||||
account_id: AccountIdOf<Left>,
|
||||
) -> anyhow::Result<()> {
|
||||
let left_genesis_hash = *left_client.genesis_hash();
|
||||
left_client
|
||||
.submit_signed_extrinsic(left_sign.public().into(), move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Left::sign_transaction(
|
||||
left_genesis_hash,
|
||||
&left_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
relay_kusama_client::runtime::Call::Balances(
|
||||
relay_kusama_client::runtime::BalancesCall::transfer(
|
||||
bp_kusama::AccountAddress::Id(account_id),
|
||||
bp_kusama::EXISTENTIAL_DEPOSIT.into(),
|
||||
),
|
||||
),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
.await
|
||||
.map(drop)
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
}
|
||||
|
||||
async fn right_create_account(
|
||||
right_client: Client<Right>,
|
||||
right_sign: <Right as TransactionSignScheme>::AccountKeyPair,
|
||||
account_id: AccountIdOf<Right>,
|
||||
) -> anyhow::Result<()> {
|
||||
let right_genesis_hash = *right_client.genesis_hash();
|
||||
right_client
|
||||
.submit_signed_extrinsic(right_sign.public().into(), move |_, transaction_nonce| {
|
||||
Bytes(
|
||||
Right::sign_transaction(
|
||||
right_genesis_hash,
|
||||
&right_sign,
|
||||
relay_substrate_client::TransactionEra::immortal(),
|
||||
UnsignedTransaction::new(
|
||||
relay_polkadot_client::runtime::Call::Balances(
|
||||
relay_polkadot_client::runtime::BalancesCall::transfer(
|
||||
bp_polkadot::AccountAddress::Id(account_id),
|
||||
bp_polkadot::EXISTENTIAL_DEPOSIT.into(),
|
||||
),
|
||||
),
|
||||
transaction_nonce,
|
||||
),
|
||||
)
|
||||
.encode(),
|
||||
)
|
||||
})
|
||||
.await
|
||||
.map(drop)
|
||||
.map_err(|e| anyhow::format_err!("{}", e))
|
||||
}
|
||||
|
||||
$generic
|
||||
}
|
||||
}
|
||||
@@ -180,9 +314,12 @@ declare_chain_options!(Millau, millau);
|
||||
declare_chain_options!(Rialto, rialto);
|
||||
declare_chain_options!(Rococo, rococo);
|
||||
declare_chain_options!(Wococo, wococo);
|
||||
declare_chain_options!(Kusama, kusama);
|
||||
declare_chain_options!(Polkadot, polkadot);
|
||||
// All supported bridges.
|
||||
declare_bridge_options!(Millau, Rialto);
|
||||
declare_bridge_options!(Rococo, Wococo);
|
||||
declare_bridge_options!(Kusama, Polkadot);
|
||||
|
||||
impl RelayHeadersAndMessages {
|
||||
/// Run the command.
|
||||
@@ -275,6 +412,26 @@ impl RelayHeadersAndMessages {
|
||||
);
|
||||
}
|
||||
|
||||
if params.shared.create_relayers_fund_accounts {
|
||||
let relayer_fund_acount_id =
|
||||
pallet_bridge_messages::relayer_fund_account_id::<AccountIdOf<Left>, LeftAccountIdConverter>();
|
||||
let relayers_fund_account_balance =
|
||||
left_client.free_native_balance(relayer_fund_acount_id.clone()).await;
|
||||
if let Err(relay_substrate_client::Error::AccountDoesNotExist) = relayers_fund_account_balance {
|
||||
log::info!(target: "bridge", "Going to create relayers fund account at {}.", Left::NAME);
|
||||
left_create_account(left_client.clone(), left_sign.clone(), relayer_fund_acount_id).await?;
|
||||
}
|
||||
|
||||
let relayer_fund_acount_id =
|
||||
pallet_bridge_messages::relayer_fund_account_id::<AccountIdOf<Right>, RightAccountIdConverter>();
|
||||
let relayers_fund_account_balance =
|
||||
right_client.free_native_balance(relayer_fund_acount_id.clone()).await;
|
||||
if let Err(relay_substrate_client::Error::AccountDoesNotExist) = relayers_fund_account_balance {
|
||||
log::info!(target: "bridge", "Going to create relayers fund account at {}.", Right::NAME);
|
||||
right_create_account(right_client.clone(), right_sign.clone(), relayer_fund_acount_id).await?;
|
||||
}
|
||||
}
|
||||
|
||||
let left_to_right_on_demand_headers = OnDemandHeadersRelay::new(
|
||||
left_client.clone(),
|
||||
right_client.clone(),
|
||||
|
||||
@@ -6,9 +6,24 @@ edition = "2018"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.2.0" }
|
||||
relay-substrate-client = { path = "../client-substrate" }
|
||||
relay-utils = { path = "../utils" }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bp-header-chain = { path = "../../primitives/header-chain" }
|
||||
bp-kusama = { path = "../../primitives/chain-kusama" }
|
||||
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
|
||||
bp-messages = { path = "../../primitives/messages" }
|
||||
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
||||
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||
bp-runtime = { path = "../../primitives/runtime" }
|
||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
|
||||
|
||||
# Substrate Dependencies
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -16,9 +16,16 @@
|
||||
|
||||
//! Types used to connect to the Kusama chain.
|
||||
|
||||
use relay_substrate_client::{Chain, ChainBase};
|
||||
use codec::Encode;
|
||||
use relay_substrate_client::{
|
||||
Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, UnsignedTransaction,
|
||||
};
|
||||
use sp_core::{storage::StorageKey, Pair};
|
||||
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod runtime;
|
||||
|
||||
/// Kusama header id.
|
||||
pub type HeaderId = relay_utils::HeaderId<bp_kusama::Hash, bp_kusama::BlockNumber>;
|
||||
|
||||
@@ -45,9 +52,68 @@ impl Chain for Kusama {
|
||||
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
|
||||
|
||||
type SignedBlock = bp_kusama::SignedBlock;
|
||||
type Call = ();
|
||||
type Call = crate::runtime::Call;
|
||||
type WeightToFee = bp_kusama::WeightToFee;
|
||||
}
|
||||
|
||||
impl ChainWithBalances for Kusama {
|
||||
fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
|
||||
StorageKey(bp_kusama::account_info_storage_key(account_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionSignScheme for Kusama {
|
||||
type Chain = Kusama;
|
||||
type AccountKeyPair = sp_core::sr25519::Pair;
|
||||
type SignedTransaction = crate::runtime::UncheckedExtrinsic;
|
||||
|
||||
fn sign_transaction(
|
||||
genesis_hash: <Self::Chain as ChainBase>::Hash,
|
||||
signer: &Self::AccountKeyPair,
|
||||
era: TransactionEraOf<Self::Chain>,
|
||||
unsigned: UnsignedTransaction<Self::Chain>,
|
||||
) -> Self::SignedTransaction {
|
||||
let raw_payload = SignedPayload::new(
|
||||
unsigned.call,
|
||||
bp_kusama::SignedExtensions::new(bp_kusama::VERSION, era, genesis_hash, unsigned.nonce, unsigned.tip),
|
||||
)
|
||||
.expect("SignedExtension never fails.");
|
||||
|
||||
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
|
||||
let signer: sp_runtime::MultiSigner = signer.public().into();
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
|
||||
bp_kusama::UncheckedExtrinsic::new_signed(
|
||||
call,
|
||||
sp_runtime::MultiAddress::Id(signer.into_account()),
|
||||
signature.into(),
|
||||
extra,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_signed(tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature.is_some()
|
||||
}
|
||||
|
||||
fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature
|
||||
.as_ref()
|
||||
.map(|(address, _, _)| *address == bp_kusama::AccountId::from(*signer.public().as_array_ref()).into())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn parse_transaction(tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self::Chain>> {
|
||||
let extra = &tx.signature.as_ref()?.2;
|
||||
Some(UnsignedTransaction {
|
||||
call: tx.function,
|
||||
nonce: extra.nonce(),
|
||||
tip: extra.tip(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Kusama header type used in headers sync.
|
||||
pub type SyncHeader = relay_substrate_client::SyncHeader<bp_kusama::Header>;
|
||||
|
||||
/// Kusama signing params.
|
||||
pub type SigningParams = sp_core::sr25519::Pair;
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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/>.
|
||||
|
||||
//! Types that are specific to the Kusama runtime.
|
||||
|
||||
use bp_messages::{LaneId, UnrewardedRelayersState};
|
||||
use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike};
|
||||
use bp_runtime::Chain;
|
||||
use codec::{Compact, Decode, Encode};
|
||||
use frame_support::weights::Weight;
|
||||
use sp_runtime::FixedU128;
|
||||
|
||||
/// Unchecked Kusama extrinsic.
|
||||
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
|
||||
|
||||
/// Polkadot account ownership digest from Kusama.
|
||||
///
|
||||
/// The byte vector returned by this function should be signed with a Polkadot account private key.
|
||||
/// This way, the owner of `kusama_account_id` on Kusama proves that the Polkadot account private key
|
||||
/// is also under his control.
|
||||
pub fn kusama_to_polkadot_account_ownership_digest<Call, AccountId, SpecVersion>(
|
||||
polkadot_call: &Call,
|
||||
kusama_account_id: AccountId,
|
||||
polkadot_spec_version: SpecVersion,
|
||||
) -> Vec<u8>
|
||||
where
|
||||
Call: codec::Encode,
|
||||
AccountId: codec::Encode,
|
||||
SpecVersion: codec::Encode,
|
||||
{
|
||||
pallet_bridge_dispatch::account_ownership_digest(
|
||||
polkadot_call,
|
||||
kusama_account_id,
|
||||
polkadot_spec_version,
|
||||
bp_runtime::KUSAMA_CHAIN_ID,
|
||||
bp_runtime::POLKADOT_CHAIN_ID,
|
||||
)
|
||||
}
|
||||
|
||||
/// Kusama Runtime `Call` enum.
|
||||
///
|
||||
/// The enum represents a subset of possible `Call`s we can send to Kusama chain.
|
||||
/// Ideally this code would be auto-generated from metadata, because we want to
|
||||
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
|
||||
///
|
||||
/// All entries here (like pretty much in the entire file) must be kept in sync with Kusama
|
||||
/// `construct_runtime`, so that we maintain SCALE-compatibility.
|
||||
///
|
||||
/// See: [link](https://github.com/paritytech/polkadot/blob/master/runtime/kusama/src/lib.rs)
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Call {
|
||||
/// System pallet.
|
||||
#[codec(index = 0)]
|
||||
System(SystemCall),
|
||||
/// Balances pallet.
|
||||
#[codec(index = 4)]
|
||||
Balances(BalancesCall),
|
||||
/// Polkadot bridge pallet.
|
||||
#[codec(index = 110)]
|
||||
BridgePolkadotGrandpa(BridgePolkadotGrandpaCall),
|
||||
/// Polkadot messages pallet.
|
||||
#[codec(index = 111)]
|
||||
BridgePolkadotMessages(BridgePolkadotMessagesCall),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum SystemCall {
|
||||
#[codec(index = 1)]
|
||||
remark(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BalancesCall {
|
||||
#[codec(index = 0)]
|
||||
transfer(AccountAddress, Compact<Balance>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BridgePolkadotGrandpaCall {
|
||||
#[codec(index = 0)]
|
||||
submit_finality_proof(
|
||||
<PolkadotLike as Chain>::Header,
|
||||
bp_header_chain::justification::GrandpaJustification<<PolkadotLike as Chain>::Header>,
|
||||
),
|
||||
#[codec(index = 1)]
|
||||
initialize(bp_header_chain::InitializationData<<PolkadotLike as Chain>::Header>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BridgePolkadotMessagesCall {
|
||||
#[codec(index = 2)]
|
||||
update_pallet_parameter(BridgePolkadotMessagesParameter),
|
||||
#[codec(index = 3)]
|
||||
send_message(
|
||||
LaneId,
|
||||
bp_message_dispatch::MessagePayload<
|
||||
bp_kusama::AccountId,
|
||||
bp_polkadot::AccountId,
|
||||
bp_polkadot::AccountPublic,
|
||||
Vec<u8>,
|
||||
>,
|
||||
bp_kusama::Balance,
|
||||
),
|
||||
#[codec(index = 5)]
|
||||
receive_messages_proof(
|
||||
bp_polkadot::AccountId,
|
||||
bridge_runtime_common::messages::target::FromBridgedChainMessagesProof<bp_polkadot::Hash>,
|
||||
u32,
|
||||
Weight,
|
||||
),
|
||||
#[codec(index = 6)]
|
||||
receive_messages_delivery_proof(
|
||||
bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof<bp_polkadot::Hash>,
|
||||
UnrewardedRelayersState,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub enum BridgePolkadotMessagesParameter {
|
||||
#[codec(index = 0)]
|
||||
PolkadotToKusamaConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl sp_runtime::traits::Dispatchable for Call {
|
||||
type Origin = ();
|
||||
type Config = ();
|
||||
type Info = ();
|
||||
type PostInfo = ();
|
||||
|
||||
fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
|
||||
unimplemented!("The Call is not expected to be dispatched.")
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,24 @@ edition = "2018"
|
||||
license = "GPL-3.0-or-later WITH Classpath-exception-2.0"
|
||||
|
||||
[dependencies]
|
||||
codec = { package = "parity-scale-codec", version = "2.2.0" }
|
||||
relay-substrate-client = { path = "../client-substrate" }
|
||||
relay-utils = { path = "../utils" }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bp-header-chain = { path = "../../primitives/header-chain" }
|
||||
bp-kusama = { path = "../../primitives/chain-kusama" }
|
||||
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
|
||||
bp-messages = { path = "../../primitives/messages" }
|
||||
bp-polkadot = { path = "../../primitives/chain-polkadot" }
|
||||
bp-polkadot-core = { path = "../../primitives/polkadot-core" }
|
||||
bp-runtime = { path = "../../primitives/runtime" }
|
||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||
pallet-bridge-dispatch = { path = "../../modules/dispatch" }
|
||||
|
||||
# Substrate Dependencies
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -16,9 +16,16 @@
|
||||
|
||||
//! Types used to connect to the Polkadot chain.
|
||||
|
||||
use relay_substrate_client::{Chain, ChainBase};
|
||||
use codec::Encode;
|
||||
use relay_substrate_client::{
|
||||
Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, UnsignedTransaction,
|
||||
};
|
||||
use sp_core::{storage::StorageKey, Pair};
|
||||
use sp_runtime::{generic::SignedPayload, traits::IdentifyAccount};
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod runtime;
|
||||
|
||||
/// Polkadot header id.
|
||||
pub type HeaderId = relay_utils::HeaderId<bp_polkadot::Hash, bp_polkadot::BlockNumber>;
|
||||
|
||||
@@ -45,9 +52,68 @@ impl Chain for Polkadot {
|
||||
const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE;
|
||||
|
||||
type SignedBlock = bp_polkadot::SignedBlock;
|
||||
type Call = ();
|
||||
type Call = crate::runtime::Call;
|
||||
type WeightToFee = bp_polkadot::WeightToFee;
|
||||
}
|
||||
|
||||
impl ChainWithBalances for Polkadot {
|
||||
fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey {
|
||||
StorageKey(bp_polkadot::account_info_storage_key(account_id))
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionSignScheme for Polkadot {
|
||||
type Chain = Polkadot;
|
||||
type AccountKeyPair = sp_core::sr25519::Pair;
|
||||
type SignedTransaction = crate::runtime::UncheckedExtrinsic;
|
||||
|
||||
fn sign_transaction(
|
||||
genesis_hash: <Self::Chain as ChainBase>::Hash,
|
||||
signer: &Self::AccountKeyPair,
|
||||
era: TransactionEraOf<Self::Chain>,
|
||||
unsigned: UnsignedTransaction<Self::Chain>,
|
||||
) -> Self::SignedTransaction {
|
||||
let raw_payload = SignedPayload::new(
|
||||
unsigned.call,
|
||||
bp_polkadot::SignedExtensions::new(bp_polkadot::VERSION, era, genesis_hash, unsigned.nonce, unsigned.tip),
|
||||
)
|
||||
.expect("SignedExtension never fails.");
|
||||
|
||||
let signature = raw_payload.using_encoded(|payload| signer.sign(payload));
|
||||
let signer: sp_runtime::MultiSigner = signer.public().into();
|
||||
let (call, extra, _) = raw_payload.deconstruct();
|
||||
|
||||
bp_polkadot::UncheckedExtrinsic::new_signed(
|
||||
call,
|
||||
sp_runtime::MultiAddress::Id(signer.into_account()),
|
||||
signature.into(),
|
||||
extra,
|
||||
)
|
||||
}
|
||||
|
||||
fn is_signed(tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature.is_some()
|
||||
}
|
||||
|
||||
fn is_signed_by(signer: &Self::AccountKeyPair, tx: &Self::SignedTransaction) -> bool {
|
||||
tx.signature
|
||||
.as_ref()
|
||||
.map(|(address, _, _)| *address == bp_polkadot::AccountId::from(*signer.public().as_array_ref()).into())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn parse_transaction(tx: Self::SignedTransaction) -> Option<UnsignedTransaction<Self::Chain>> {
|
||||
let extra = &tx.signature.as_ref()?.2;
|
||||
Some(UnsignedTransaction {
|
||||
call: tx.function,
|
||||
nonce: extra.nonce(),
|
||||
tip: extra.tip(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Polkadot header type used in headers sync.
|
||||
pub type SyncHeader = relay_substrate_client::SyncHeader<bp_polkadot::Header>;
|
||||
|
||||
/// Polkadot signing params.
|
||||
pub type SigningParams = sp_core::sr25519::Pair;
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
// 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/>.
|
||||
|
||||
//! Types that are specific to the Polkadot runtime.
|
||||
|
||||
use bp_messages::{LaneId, UnrewardedRelayersState};
|
||||
use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike};
|
||||
use bp_runtime::Chain;
|
||||
use codec::{Compact, Decode, Encode};
|
||||
use frame_support::weights::Weight;
|
||||
use sp_runtime::FixedU128;
|
||||
|
||||
/// Unchecked Polkadot extrinsic.
|
||||
pub type UncheckedExtrinsic = bp_polkadot_core::UncheckedExtrinsic<Call>;
|
||||
|
||||
/// Kusama account ownership digest from Polkadot.
|
||||
///
|
||||
/// The byte vector returned by this function should be signed with a Kusama account private key.
|
||||
/// This way, the owner of `kusam_account_id` on Polkadot proves that the Kusama account private key
|
||||
/// is also under his control.
|
||||
pub fn polkadot_to_kusama_account_ownership_digest<Call, AccountId, SpecVersion>(
|
||||
kusama_call: &Call,
|
||||
kusam_account_id: AccountId,
|
||||
kusama_spec_version: SpecVersion,
|
||||
) -> Vec<u8>
|
||||
where
|
||||
Call: codec::Encode,
|
||||
AccountId: codec::Encode,
|
||||
SpecVersion: codec::Encode,
|
||||
{
|
||||
pallet_bridge_dispatch::account_ownership_digest(
|
||||
kusama_call,
|
||||
kusam_account_id,
|
||||
kusama_spec_version,
|
||||
bp_runtime::POLKADOT_CHAIN_ID,
|
||||
bp_runtime::KUSAMA_CHAIN_ID,
|
||||
)
|
||||
}
|
||||
|
||||
/// Polkadot Runtime `Call` enum.
|
||||
///
|
||||
/// The enum represents a subset of possible `Call`s we can send to Polkadot chain.
|
||||
/// Ideally this code would be auto-generated from metadata, because we want to
|
||||
/// avoid depending directly on the ENTIRE runtime just to get the encoding of `Dispatchable`s.
|
||||
///
|
||||
/// All entries here (like pretty much in the entire file) must be kept in sync with Polkadot
|
||||
/// `construct_runtime`, so that we maintain SCALE-compatibility.
|
||||
///
|
||||
/// See: [link](https://github.com/paritytech/kusama/blob/master/runtime/kusam/src/lib.rs)
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub enum Call {
|
||||
/// System pallet.
|
||||
#[codec(index = 0)]
|
||||
System(SystemCall),
|
||||
/// Balances pallet.
|
||||
#[codec(index = 5)]
|
||||
Balances(BalancesCall),
|
||||
/// Kusama bridge pallet.
|
||||
#[codec(index = 110)]
|
||||
BridgeKusamaGrandpa(BridgeKusamaGrandpaCall),
|
||||
/// Kusama messages pallet.
|
||||
#[codec(index = 111)]
|
||||
BridgeKusamaMessages(BridgeKusamaMessagesCall),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum SystemCall {
|
||||
#[codec(index = 1)]
|
||||
remark(Vec<u8>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BalancesCall {
|
||||
#[codec(index = 0)]
|
||||
transfer(AccountAddress, Compact<Balance>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BridgeKusamaGrandpaCall {
|
||||
#[codec(index = 0)]
|
||||
submit_finality_proof(
|
||||
<PolkadotLike as Chain>::Header,
|
||||
bp_header_chain::justification::GrandpaJustification<<PolkadotLike as Chain>::Header>,
|
||||
),
|
||||
#[codec(index = 1)]
|
||||
initialize(bp_header_chain::InitializationData<<PolkadotLike as Chain>::Header>),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BridgeKusamaMessagesCall {
|
||||
#[codec(index = 2)]
|
||||
update_pallet_parameter(BridgeKusamaMessagesParameter),
|
||||
#[codec(index = 3)]
|
||||
send_message(
|
||||
LaneId,
|
||||
bp_message_dispatch::MessagePayload<
|
||||
bp_polkadot::AccountId,
|
||||
bp_kusama::AccountId,
|
||||
bp_kusama::AccountPublic,
|
||||
Vec<u8>,
|
||||
>,
|
||||
bp_polkadot::Balance,
|
||||
),
|
||||
#[codec(index = 5)]
|
||||
receive_messages_proof(
|
||||
bp_kusama::AccountId,
|
||||
bridge_runtime_common::messages::target::FromBridgedChainMessagesProof<bp_kusama::Hash>,
|
||||
u32,
|
||||
Weight,
|
||||
),
|
||||
#[codec(index = 6)]
|
||||
receive_messages_delivery_proof(
|
||||
bridge_runtime_common::messages::source::FromBridgedChainMessagesDeliveryProof<bp_kusama::Hash>,
|
||||
UnrewardedRelayersState,
|
||||
),
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone)]
|
||||
pub enum BridgeKusamaMessagesParameter {
|
||||
#[codec(index = 0)]
|
||||
KusamaToPolkadotConversionRate(FixedU128),
|
||||
}
|
||||
|
||||
impl sp_runtime::traits::Dispatchable for Call {
|
||||
type Origin = ();
|
||||
type Config = ();
|
||||
type Info = ();
|
||||
type PostInfo = ();
|
||||
|
||||
fn dispatch(self, _origin: Self::Origin) -> sp_runtime::DispatchResultWithInfo<Self::PostInfo> {
|
||||
unimplemented!("The Call is not expected to be dispatched.")
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ relay-substrate-client = { path = "../client-substrate" }
|
||||
relay-utils = { path = "../utils" }
|
||||
|
||||
# Bridge dependencies
|
||||
|
||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||
bp-header-chain = { path = "../../primitives/header-chain" }
|
||||
bp-message-dispatch = { path = "../../primitives/message-dispatch" }
|
||||
@@ -23,6 +24,7 @@ pallet-bridge-dispatch = { path = "../../modules/dispatch" }
|
||||
pallet-bridge-messages = { path = "../../modules/messages" }
|
||||
|
||||
# Substrate Dependencies
|
||||
|
||||
frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
|
||||
|
||||
@@ -38,7 +38,8 @@ pub use crate::client::{Client, JustificationsSubscription, OpaqueGrandpaAuthori
|
||||
pub use crate::error::{Error, Result};
|
||||
pub use crate::sync_header::SyncHeader;
|
||||
pub use bp_runtime::{
|
||||
BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderOf, IndexOf, TransactionEra, TransactionEraOf,
|
||||
AccountIdOf, BalanceOf, BlockNumberOf, Chain as ChainBase, HashOf, HeaderOf, IndexOf, TransactionEra,
|
||||
TransactionEraOf,
|
||||
};
|
||||
|
||||
/// Header id used by the chain.
|
||||
|
||||
Reference in New Issue
Block a user