Remove obsolete bridges (#1491)

* remove Rococo<>Wococo bridge mentions

* remove Kusama <> Polkadot bridge mentions

* fmt

* remove unneeded mocked runtimes && trait impls for obsolete bridges

* remove unused deps
This commit is contained in:
Svyatoslav Nikolsky
2022-07-06 11:23:43 +03:00
committed by Bastian Köcher
parent 46c0400f26
commit 88e95388bb
35 changed files with 24 additions and 2864 deletions
@@ -25,10 +25,6 @@ use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline;
pub enum FullBridge {
MillauToRialto,
RialtoToMillau,
RococoToWococo,
WococoToRococo,
KusamaToPolkadot,
PolkadotToKusama,
MillauToRialtoParachain,
RialtoParachainToMillau,
}
@@ -39,10 +35,6 @@ impl FullBridge {
match self {
Self::MillauToRialto => MILLAU_TO_RIALTO_INDEX,
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,
Self::MillauToRialtoParachain => MILLAU_TO_RIALTO_PARACHAIN_INDEX,
Self::RialtoParachainToMillau => RIALTO_PARACHAIN_TO_MILLAU_INDEX,
}
@@ -51,10 +43,6 @@ impl FullBridge {
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;
pub const MILLAU_TO_RIALTO_PARACHAIN_INDEX: u8 = 1;
pub const RIALTO_PARACHAIN_TO_MILLAU_INDEX: u8 = 0;
@@ -104,82 +92,6 @@ macro_rules! select_full_bridge {
$generic
},
FullBridge::RococoToWococo => {
type Source = relay_rococo_client::Rococo;
#[allow(dead_code)]
type Target = relay_wococo_client::Wococo;
// Derive-account
#[allow(unused_imports)]
use bp_wococo::derive_account_from_rococo_id as derive_account;
// Relay-messages
#[allow(unused_imports)]
use $crate::chains::rococo_messages_to_wococo::RococoMessagesToWococo as MessagesLane;
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_wococo::TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
$generic
},
FullBridge::WococoToRococo => {
type Source = relay_wococo_client::Wococo;
#[allow(dead_code)]
type Target = relay_rococo_client::Rococo;
// Derive-account
#[allow(unused_imports)]
use bp_rococo::derive_account_from_wococo_id as derive_account;
// Relay-messages
#[allow(unused_imports)]
use $crate::chains::wococo_messages_to_rococo::WococoMessagesToRococo as MessagesLane;
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_rococo::TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
$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::KusamaMessagesToPolkadot as MessagesLane;
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_polkadot::TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
$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::PolkadotMessagesToKusama as MessagesLane;
// Send-message / Estimate-fee
#[allow(unused_imports)]
use bp_kusama::TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD as ESTIMATE_MESSAGE_FEE_METHOD;
$generic
},
FullBridge::MillauToRialtoParachain => {
type Source = relay_millau_client::Millau;
#[allow(dead_code)]
@@ -279,54 +191,6 @@ impl CliBridge for WestendToMillauCliBridge {
type Finality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau;
}
//// `Rococo` to `Wococo` bridge definition.
pub struct RococoToWococoCliBridge {}
impl CliBridgeBase for RococoToWococoCliBridge {
type Source = relay_rococo_client::Rococo;
type Target = relay_wococo_client::Wococo;
}
impl CliBridge for RococoToWococoCliBridge {
type Finality = crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo;
}
//// `Wococo` to `Rococo` bridge definition.
pub struct WococoToRococoCliBridge {}
impl CliBridgeBase for WococoToRococoCliBridge {
type Source = relay_wococo_client::Wococo;
type Target = relay_rococo_client::Rococo;
}
impl CliBridge for WococoToRococoCliBridge {
type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo;
}
//// `Kusama` to `Polkadot` bridge definition.
pub struct KusamaToPolkadotCliBridge {}
impl CliBridgeBase for KusamaToPolkadotCliBridge {
type Source = relay_kusama_client::Kusama;
type Target = relay_polkadot_client::Polkadot;
}
impl CliBridge for KusamaToPolkadotCliBridge {
type Finality = crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot;
}
//// `Polkadot` to `Kusama` bridge definition.
pub struct PolkadotToKusamaCliBridge {}
impl CliBridgeBase for PolkadotToKusamaCliBridge {
type Source = relay_polkadot_client::Polkadot;
type Target = relay_kusama_client::Kusama;
}
impl CliBridge for PolkadotToKusamaCliBridge {
type Finality = crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama;
}
//// `Millau` to `RialtoParachain` bridge definition.
pub struct MillauToRialtoParachainCliBridge {}
@@ -18,9 +18,8 @@ use async_trait::async_trait;
use crate::cli::{
bridge::{
CliBridgeBase, KusamaToPolkadotCliBridge, MillauToRialtoCliBridge,
MillauToRialtoParachainCliBridge, PolkadotToKusamaCliBridge, RialtoToMillauCliBridge,
RococoToWococoCliBridge, WestendToMillauCliBridge, WococoToRococoCliBridge,
CliBridgeBase, MillauToRialtoCliBridge, MillauToRialtoParachainCliBridge,
RialtoToMillauCliBridge, WestendToMillauCliBridge,
},
SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
};
@@ -55,10 +54,6 @@ pub enum InitBridgeName {
MillauToRialto,
RialtoToMillau,
WestendToMillau,
RococoToWococo,
WococoToRococo,
KusamaToPolkadot,
PolkadotToKusama,
MillauToRialtoParachain,
}
@@ -175,54 +170,6 @@ impl BridgeInitializer for WestendToMillauCliBridge {
}
}
impl BridgeInitializer for RococoToWococoCliBridge {
type Engine = GrandpaFinalityEngine<Self::Source>;
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call {
relay_wococo_client::runtime::Call::BridgeGrandpaRococo(
relay_wococo_client::runtime::BridgeGrandpaRococoCall::initialize(init_data),
)
}
}
impl BridgeInitializer for WococoToRococoCliBridge {
type Engine = GrandpaFinalityEngine<Self::Source>;
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call {
relay_rococo_client::runtime::Call::BridgeGrandpaWococo(
relay_rococo_client::runtime::BridgeGrandpaWococoCall::initialize(init_data),
)
}
}
impl BridgeInitializer for KusamaToPolkadotCliBridge {
type Engine = GrandpaFinalityEngine<Self::Source>;
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call {
relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa(
relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::initialize(init_data),
)
}
}
impl BridgeInitializer for PolkadotToKusamaCliBridge {
type Engine = GrandpaFinalityEngine<Self::Source>;
fn encode_init_bridge(
init_data: <Self::Engine as Engine<Self::Source>>::InitializationData,
) -> <Self::Target as Chain>::Call {
relay_kusama_client::runtime::Call::BridgePolkadotGrandpa(
relay_kusama_client::runtime::BridgePolkadotGrandpaCall::initialize(init_data),
)
}
}
impl InitBridge {
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
@@ -230,10 +177,6 @@ impl InitBridge {
InitBridgeName::MillauToRialto => MillauToRialtoCliBridge::init_bridge(self),
InitBridgeName::RialtoToMillau => RialtoToMillauCliBridge::init_bridge(self),
InitBridgeName::WestendToMillau => WestendToMillauCliBridge::init_bridge(self),
InitBridgeName::RococoToWococo => RococoToWococoCliBridge::init_bridge(self),
InitBridgeName::WococoToRococo => WococoToRococoCliBridge::init_bridge(self),
InitBridgeName::KusamaToPolkadot => KusamaToPolkadotCliBridge::init_bridge(self),
InitBridgeName::PolkadotToKusama => PolkadotToKusamaCliBridge::init_bridge(self),
InitBridgeName::MillauToRialtoParachain =>
MillauToRialtoParachainCliBridge::init_bridge(self),
}
@@ -33,7 +33,6 @@ pub(crate) mod send_message;
mod init_bridge;
mod register_parachain;
mod reinit_bridge;
mod relay_headers;
mod relay_headers_and_messages;
mod relay_messages;
@@ -70,11 +69,6 @@ pub enum Command {
///
/// Sends initialization transaction to bootstrap the bridge with current finalized block data.
InitBridge(init_bridge::InitBridge),
/// Reinitialize on-chain bridge pallet with current header data.
///
/// Sends all missing mandatory headers to bootstrap the bridge with current finalized block
/// data.
ReinitBridge(reinit_bridge::ReinitBridge),
/// Send custom message over the bridge.
///
/// Allows interacting with the bridge by sending messages over `Messages` component.
@@ -117,7 +111,6 @@ impl Command {
Self::RelayMessages(arg) => arg.run().await?,
Self::RelayHeadersAndMessages(arg) => arg.run().await?,
Self::InitBridge(arg) => arg.run().await?,
Self::ReinitBridge(arg) => arg.run().await?,
Self::SendMessage(arg) => arg.run().await?,
Self::EstimateFee(arg) => arg.run().await?,
Self::ResubmitTransactions(arg) => arg.run().await?,
@@ -1,556 +0,0 @@
// 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 crate::{
chains::{
kusama_headers_to_polkadot::KusamaFinalityToPolkadot,
polkadot_headers_to_kusama::PolkadotFinalityToKusama,
},
cli::{
register_parachain::wait_until_transaction_is_finalized, SourceConnectionParams,
TargetConnectionParams, TargetSigningParams,
},
};
use bp_runtime::Chain;
use codec::Encode;
use finality_relay::{SourceClient, SourceHeader};
use frame_support::weights::Weight;
use num_traits::One;
use pallet_bridge_grandpa::weights::WeightInfo;
use relay_substrate_client::{
AccountIdOf, BlockNumberOf, Chain as _, Client, Error as SubstrateError, HeaderOf, SignParam,
SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction,
};
use sp_core::{Bytes, Pair};
use std::convert::{TryFrom, TryInto};
use structopt::StructOpt;
use strum::{EnumString, EnumVariantNames, VariantNames};
use substrate_relay_helper::{
finality::{
source::{SubstrateFinalityProof, SubstrateFinalitySource},
target::SubstrateFinalityTarget,
SubstrateFinalitySyncPipeline,
},
messages_source::read_client_state,
TransactionParams,
};
/// Reinitialize bridge pallet.
#[derive(Debug, PartialEq, Eq, StructOpt)]
pub struct ReinitBridge {
/// A bridge instance to reinitialize.
#[structopt(possible_values = ReinitBridgeName::VARIANTS, case_insensitive = true)]
bridge: ReinitBridgeName,
#[structopt(flatten)]
source: SourceConnectionParams,
#[structopt(flatten)]
target: TargetConnectionParams,
#[structopt(flatten)]
target_sign: TargetSigningParams,
}
#[derive(Debug, EnumString, EnumVariantNames, PartialEq, Eq)]
#[strum(serialize_all = "kebab_case")]
/// Bridge to initialize.
pub enum ReinitBridgeName {
KusamaToPolkadot,
PolkadotToKusama,
}
macro_rules! select_bridge {
($bridge: expr, $generic: tt) => {
match $bridge {
ReinitBridgeName::KusamaToPolkadot => {
use relay_polkadot_client::runtime;
type Finality = KusamaFinalityToPolkadot;
type Call = runtime::Call;
fn submit_finality_proof_call(
header_and_proof: HeaderAndProof<Finality>,
) -> runtime::Call {
runtime::Call::BridgeKusamaGrandpa(
runtime::BridgeKusamaGrandpaCall::submit_finality_proof(
Box::new(header_and_proof.0.into_inner()),
header_and_proof.1,
),
)
}
fn set_pallet_operation_mode_call(operational: bool) -> runtime::Call {
runtime::Call::BridgeKusamaGrandpa(
runtime::BridgeKusamaGrandpaCall::set_operational(operational),
)
}
fn batch_all_call(calls: Vec<Call>) -> runtime::Call {
runtime::Call::Utility(runtime::UtilityCall::batch_all(calls))
}
$generic
},
ReinitBridgeName::PolkadotToKusama => {
use relay_kusama_client::runtime;
type Finality = PolkadotFinalityToKusama;
type Call = runtime::Call;
fn submit_finality_proof_call(
header_and_proof: HeaderAndProof<Finality>,
) -> runtime::Call {
runtime::Call::BridgePolkadotGrandpa(
runtime::BridgePolkadotGrandpaCall::submit_finality_proof(
Box::new(header_and_proof.0.into_inner()),
header_and_proof.1,
),
)
}
fn set_pallet_operation_mode_call(operational: bool) -> runtime::Call {
runtime::Call::BridgePolkadotGrandpa(
runtime::BridgePolkadotGrandpaCall::set_operational(operational),
)
}
fn batch_all_call(calls: Vec<Call>) -> runtime::Call {
runtime::Call::Utility(runtime::UtilityCall::batch_all(calls))
}
$generic
},
}
};
}
impl ReinitBridge {
/// Run the command.
pub async fn run(self) -> anyhow::Result<()> {
select_bridge!(self.bridge, {
type Source = <Finality as SubstrateFinalitySyncPipeline>::SourceChain;
type Target = <Finality as SubstrateFinalitySyncPipeline>::TargetChain;
let source_client = self.source.to_client::<Source>().await?;
let target_client = self.target.to_client::<Target>().await?;
let target_sign = self.target_sign.to_keypair::<Target>()?;
let transaction_params = TransactionParams {
signer: target_sign,
mortality: self.target_sign.target_transactions_mortality,
};
let finality_source =
SubstrateFinalitySource::<Finality>::new(source_client.clone(), None);
let finality_target = SubstrateFinalityTarget::<Finality>::new(
target_client.clone(),
transaction_params.clone(),
);
// this subcommand assumes that the pallet at the target chain is halted
ensure_pallet_operating_mode(&finality_target, false).await?;
// we can't call `finality_target.best_finalized_source_block_id()`, because pallet is
// halted and the call will fail => just use what it uses internally
let current_number =
best_source_block_number_at_target::<Finality>(&target_client).await?;
let target_number = finality_source.best_finalized_block_number().await?;
log::info!(
target: "bridge",
"Best finalized {} header: at {}: {}, at {}: {}",
Source::NAME,
Source::NAME,
target_number,
Target::NAME,
current_number,
);
// prepare list of mandatory headers from the range `(current_number; target_number]`
let headers_to_submit = find_mandatory_headers_in_range(
&finality_source,
(current_number + 1, target_number),
)
.await?;
let latest_mandatory_header_number = headers_to_submit.last().map(|(h, _)| h.number());
log::info!(
target: "bridge",
"Missing {} mandatory {} headers at {}",
headers_to_submit.len(),
Source::NAME,
Target::NAME,
);
// split all mandatory headers into batches
let headers_batches =
make_mandatory_headers_batches::<Finality, _>(headers_to_submit, |(_, proof)| {
// we don't have an access to the Kusama/Polkadot chain runtimes here, so we'll
// be using Millau weights. It isn't super-critical, unless real weights are
// magnitude higher or so
pallet_bridge_grandpa::weights::MillauWeight::<millau_runtime::Runtime>::submit_finality_proof(
proof.commit.precommits.len().try_into().unwrap_or(u32::MAX),
proof.votes_ancestries.len().try_into().unwrap_or(u32::MAX),
)
});
log::info!(
target: "bridge",
"We're going to submit {} transactions to {} node",
headers_batches.len(),
Target::NAME,
);
// each batch is submitted as a separate transaction
let signer_account_id: AccountIdOf<Target> = transaction_params.signer.public().into();
let genesis_hash = *target_client.genesis_hash();
let (spec_version, transaction_version) =
target_client.simple_runtime_version().await?;
let last_batch_index = headers_batches.len() - 1;
for (i, headers_batch) in headers_batches.into_iter().enumerate() {
let is_last_batch = i == last_batch_index;
let expected_number =
headers_batch.last().expect("all batches are non-empty").0.number();
let transaction_params = transaction_params.clone();
log::info!(
target: "bridge",
"Going to submit transaction that updates best {} header at {} to {}",
Source::NAME,
Target::NAME,
expected_number,
);
// prepare `batch_all` call
let mut batch_calls = Vec::with_capacity(headers_batch.len() + 2);
// the first call is always resumes pallet operation
batch_calls.push(set_pallet_operation_mode_call(true));
// followed by submit-finality-proofs calls
for header_and_proof in headers_batch {
batch_calls.push(submit_finality_proof_call(header_and_proof));
}
// if it isn't the last batch, we shall halt pallet again
if !is_last_batch {
batch_calls.push(set_pallet_operation_mode_call(false));
}
let submit_batch_call = batch_all_call(batch_calls);
let batch_transaction_events = target_client
.submit_and_watch_signed_extrinsic(
signer_account_id.clone(),
move |best_block_id, transaction_nonce| {
Ok(Bytes(
Target::sign_transaction(SignParam {
spec_version,
transaction_version,
genesis_hash,
signer: transaction_params.signer.clone(),
era: TransactionEra::new(
best_block_id,
transaction_params.mortality,
),
unsigned: UnsignedTransaction::new(
submit_batch_call.into(),
transaction_nonce,
),
})?
.encode(),
))
},
)
.await?;
wait_until_transaction_is_finalized::<Target>(batch_transaction_events).await?;
// verify that the best finalized header at target has been updated
let current_number =
best_source_block_number_at_target::<Finality>(&target_client).await?;
if current_number != expected_number {
return Err(anyhow::format_err!(
"Transaction has failed to update best {} header at {} to {}. It is {}",
Source::NAME,
Target::NAME,
expected_number,
current_number,
))
}
// verify that the pallet is still halted (or operational if it is the last batch)
ensure_pallet_operating_mode(&finality_target, is_last_batch).await?;
}
if let Some(latest_mandatory_header_number) = latest_mandatory_header_number {
log::info!(
target: "bridge",
"Successfully updated best {} header at {} to {}. Pallet is now operational",
Source::NAME,
Target::NAME,
latest_mandatory_header_number,
);
}
Ok(())
})
}
}
/// Mandatory header and its finality proof.
type HeaderAndProof<P> = (
SyncHeader<HeaderOf<<P as SubstrateFinalitySyncPipeline>::SourceChain>>,
SubstrateFinalityProof<P>,
);
/// Vector of mandatory headers and their finality proofs.
type HeadersAndProofs<P> = Vec<HeaderAndProof<P>>;
/// Returns best finalized source header number known to the bridge GRANDPA pallet at the target
/// chain.
///
/// This function works even if bridge GRANDPA pallet at the target chain is halted.
async fn best_source_block_number_at_target<P: SubstrateFinalitySyncPipeline>(
target_client: &Client<P::TargetChain>,
) -> anyhow::Result<BlockNumberOf<P::SourceChain>> {
Ok(read_client_state::<P::TargetChain, P::SourceChain>(
target_client,
None,
P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD,
)
.await?
.best_finalized_peer_at_best_self
.0)
}
/// Verify that the bridge GRANDPA pallet at the target chain is either halted, or operational.
async fn ensure_pallet_operating_mode<P: SubstrateFinalitySyncPipeline>(
finality_target: &SubstrateFinalityTarget<P>,
operational: bool,
) -> anyhow::Result<()> {
match (operational, finality_target.ensure_pallet_active().await) {
(true, Ok(())) => Ok(()),
(false, Err(SubstrateError::BridgePalletIsHalted)) => Ok(()),
_ => Err(anyhow::format_err!(
"Bridge GRANDPA pallet at {} is expected to be {}, but it isn't",
P::TargetChain::NAME,
if operational { "operational" } else { "halted" },
)),
}
}
/// Returns list of all mandatory headers in given range.
async fn find_mandatory_headers_in_range<P: SubstrateFinalitySyncPipeline>(
finality_source: &SubstrateFinalitySource<P>,
range: (BlockNumberOf<P::SourceChain>, BlockNumberOf<P::SourceChain>),
) -> anyhow::Result<HeadersAndProofs<P>> {
let mut mandatory_headers = Vec::new();
let mut current = range.0;
while current <= range.1 {
let (header, proof) = finality_source.header_and_finality_proof(current).await?;
if header.is_mandatory() {
match proof {
Some(proof) => mandatory_headers.push((header, proof)),
None =>
return Err(anyhow::format_err!(
"Missing GRANDPA justification for {} header {}",
P::SourceChain::NAME,
current,
)),
}
}
current += One::one();
}
Ok(mandatory_headers)
}
/// Given list of mandatory headers, prepare batches of headers, so that every batch may fit into
/// single transaction.
fn make_mandatory_headers_batches<
P: SubstrateFinalitySyncPipeline,
F: Fn(&HeaderAndProof<P>) -> Weight,
>(
mut headers_to_submit: HeadersAndProofs<P>,
submit_header_weight: F,
) -> Vec<HeadersAndProofs<P>> {
// now that we have all mandatory headers, let's prepare transactions
// (let's keep all our transactions below 2/3 of max tx size/weight to have some reserve
// for utility overhead + for halting transaction)
let maximal_tx_size = P::TargetChain::max_extrinsic_size() * 2 / 3;
let maximal_tx_weight = P::TargetChain::max_extrinsic_weight() * 2 / 3;
let mut current_batch_size: u32 = 0;
let mut current_batch_weight: Weight = 0;
let mut batches = Vec::new();
let mut i = 0;
while i < headers_to_submit.len() {
let header_and_proof_size =
headers_to_submit[i].0.encode().len() + headers_to_submit[i].1.encode().len();
let header_and_proof_weight = submit_header_weight(&headers_to_submit[i]);
let new_batch_size = current_batch_size
.saturating_add(u32::try_from(header_and_proof_size).unwrap_or(u32::MAX));
let new_batch_weight = current_batch_weight.saturating_add(header_and_proof_weight);
let is_exceeding_tx_size = new_batch_size > maximal_tx_size;
let is_exceeding_tx_weight = new_batch_weight > maximal_tx_weight;
let is_new_batch_required = is_exceeding_tx_size || is_exceeding_tx_weight;
if is_new_batch_required {
// if `i` is 0 and we're here, it is a weird situation: even single header submission is
// larger than we've planned for a bunch of headers. Let's be optimistic and hope that
// the tx will still succeed.
let spit_off_index = std::cmp::max(i, 1);
let remaining_headers_to_submit = headers_to_submit.split_off(spit_off_index);
batches.push(headers_to_submit);
// we'll reiterate the same header again => so set `current_*` to zero
current_batch_size = 0;
current_batch_weight = 0;
headers_to_submit = remaining_headers_to_submit;
i = 0;
} else {
current_batch_size = new_batch_size;
current_batch_weight = new_batch_weight;
i += 1;
}
}
if !headers_to_submit.is_empty() {
batches.push(headers_to_submit);
}
batches
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams};
use bp_header_chain::justification::GrandpaJustification;
use bp_test_utils::{make_default_justification, test_header};
use relay_polkadot_client::Polkadot;
use sp_runtime::{traits::Header as _, DigestItem};
fn make_header_and_justification(
i: u32,
size: u32,
) -> (SyncHeader<bp_kusama::Header>, GrandpaJustification<bp_kusama::Header>) {
let size = size as usize;
let mut header: bp_kusama::Header = test_header(i);
let justification = make_default_justification(&header);
let actual_size = header.encode().len() + justification.encode().len();
// additional digest means some additional bytes, so let's decrease `additional_digest_size`
// a bit
let additional_digest_size = size.saturating_sub(actual_size).saturating_sub(100);
header.digest_mut().push(DigestItem::Other(vec![0u8; additional_digest_size]));
let justification = make_default_justification(&header);
println!("{} {}", size, header.encode().len() + justification.encode().len());
(header.into(), justification)
}
#[test]
fn should_parse_cli_options() {
// when
let res = ReinitBridge::from_iter(vec![
"reinit-bridge",
"kusama-to-polkadot",
"--source-host",
"127.0.0.1",
"--source-port",
"42",
"--target-host",
"127.0.0.1",
"--target-port",
"43",
"--target-signer",
"//Alice",
]);
// then
assert_eq!(
res,
ReinitBridge {
bridge: ReinitBridgeName::KusamaToPolkadot,
source: SourceConnectionParams {
source_host: "127.0.0.1".into(),
source_port: 42,
source_secure: false,
source_runtime_version: SourceRuntimeVersionParams {
source_version_mode: RuntimeVersionType::Bundle,
source_spec_version: None,
source_transaction_version: None,
}
},
target: TargetConnectionParams {
target_host: "127.0.0.1".into(),
target_port: 43,
target_secure: false,
target_runtime_version: TargetRuntimeVersionParams {
target_version_mode: RuntimeVersionType::Bundle,
target_spec_version: None,
target_transaction_version: None,
}
},
target_sign: TargetSigningParams {
target_signer: Some("//Alice".into()),
target_signer_password: None,
target_signer_file: None,
target_signer_password_file: None,
target_transactions_mortality: None,
},
}
);
}
#[test]
fn make_mandatory_headers_batches_and_empty_headers() {
let batches = make_mandatory_headers_batches::<KusamaFinalityToPolkadot, _>(vec![], |_| 0);
assert!(batches.is_empty());
}
#[test]
fn make_mandatory_headers_batches_with_single_batch() {
let headers_to_submit =
vec![make_header_and_justification(10, Polkadot::max_extrinsic_size() / 3)];
let batches =
make_mandatory_headers_batches::<KusamaFinalityToPolkadot, _>(headers_to_submit, |_| 0);
assert_eq!(batches.into_iter().map(|x| x.len()).collect::<Vec<_>>(), vec![1],);
}
#[test]
fn make_mandatory_headers_batches_group_by_size() {
let headers_to_submit = vec![
make_header_and_justification(10, Polkadot::max_extrinsic_size() / 3),
make_header_and_justification(20, Polkadot::max_extrinsic_size() / 3),
make_header_and_justification(30, Polkadot::max_extrinsic_size() * 2 / 3),
make_header_and_justification(40, Polkadot::max_extrinsic_size()),
];
let batches =
make_mandatory_headers_batches::<KusamaFinalityToPolkadot, _>(headers_to_submit, |_| 0);
assert_eq!(batches.into_iter().map(|x| x.len()).collect::<Vec<_>>(), vec![2, 1, 1],);
}
#[test]
fn make_mandatory_headers_batches_group_by_weight() {
let headers_to_submit = vec![
make_header_and_justification(10, 0),
make_header_and_justification(20, 0),
make_header_and_justification(30, 0),
make_header_and_justification(40, 0),
];
let batches = make_mandatory_headers_batches::<KusamaFinalityToPolkadot, _>(
headers_to_submit,
|(header, _)| {
if header.number() == 10 || header.number() == 20 {
Polkadot::max_extrinsic_weight() / 3
} else if header.number() == 30 {
Polkadot::max_extrinsic_weight() * 2 / 3
} else {
Polkadot::max_extrinsic_weight()
}
},
);
assert_eq!(batches.into_iter().map(|x| x.len()).collect::<Vec<_>>(), vec![2, 1, 1],);
}
}
@@ -25,9 +25,8 @@ use substrate_relay_helper::finality::SubstrateFinalitySyncPipeline;
use crate::cli::{
bridge::{
CliBridge, KusamaToPolkadotCliBridge, MillauToRialtoCliBridge,
MillauToRialtoParachainCliBridge, PolkadotToKusamaCliBridge, RialtoToMillauCliBridge,
RococoToWococoCliBridge, WestendToMillauCliBridge, WococoToRococoCliBridge,
CliBridge, MillauToRialtoCliBridge, MillauToRialtoParachainCliBridge,
RialtoToMillauCliBridge, WestendToMillauCliBridge,
},
PrometheusParams, SourceConnectionParams, TargetConnectionParams, TargetSigningParams,
};
@@ -59,10 +58,6 @@ pub enum RelayHeadersBridge {
MillauToRialto,
RialtoToMillau,
WestendToMillau,
RococoToWococo,
WococoToRococo,
KusamaToPolkadot,
PolkadotToKusama,
MillauToRialtoParachain,
}
@@ -106,10 +101,6 @@ where
impl HeadersRelayer for MillauToRialtoCliBridge {}
impl HeadersRelayer for RialtoToMillauCliBridge {}
impl HeadersRelayer for WestendToMillauCliBridge {}
impl HeadersRelayer for RococoToWococoCliBridge {}
impl HeadersRelayer for WococoToRococoCliBridge {}
impl HeadersRelayer for KusamaToPolkadotCliBridge {}
impl HeadersRelayer for PolkadotToKusamaCliBridge {}
impl HeadersRelayer for MillauToRialtoParachainCliBridge {}
impl RelayHeaders {
@@ -119,10 +110,6 @@ impl RelayHeaders {
RelayHeadersBridge::MillauToRialto => MillauToRialtoCliBridge::relay_headers(self),
RelayHeadersBridge::RialtoToMillau => RialtoToMillauCliBridge::relay_headers(self),
RelayHeadersBridge::WestendToMillau => WestendToMillauCliBridge::relay_headers(self),
RelayHeadersBridge::RococoToWococo => RococoToWococoCliBridge::relay_headers(self),
RelayHeadersBridge::WococoToRococo => WococoToRococoCliBridge::relay_headers(self),
RelayHeadersBridge::KusamaToPolkadot => KusamaToPolkadotCliBridge::relay_headers(self),
RelayHeadersBridge::PolkadotToKusama => PolkadotToKusamaCliBridge::relay_headers(self),
RelayHeadersBridge::MillauToRialtoParachain =>
MillauToRialtoParachainCliBridge::relay_headers(self),
}
@@ -28,15 +28,14 @@ use strum::VariantNames;
use async_std::sync::Arc;
use bp_polkadot_core::parachains::ParaHash;
use codec::Encode;
use messages_relay::relay_strategy::MixStrategy;
use pallet_bridge_parachains::{RelayBlockHash, RelayBlockHasher, RelayBlockNumber};
use relay_substrate_client::{
AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, ChainRuntimeVersion, Client,
SignParam, TransactionSignScheme, UnsignedTransaction,
AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, ChainRuntimeVersion, Client,
TransactionSignScheme,
};
use relay_utils::metrics::MetricsParams;
use sp_core::{Bytes, Pair};
use sp_core::Pair;
use substrate_relay_helper::{
finality::SubstrateFinalitySyncPipeline,
messages_lane::MessagesRelayParams,
@@ -68,8 +67,6 @@ pub(crate) const CONVERSION_RATE_ALLOWED_DIFFERENCE_RATIO: f64 = 0.05;
pub enum RelayHeadersAndMessages {
MillauRialto(MillauRialtoHeadersAndMessages),
MillauRialtoParachain(MillauRialtoParachainHeadersAndMessages),
RococoWococo(RococoWococoHeadersAndMessages),
KusamaPolkadot(KusamaPolkadotHeadersAndMessages),
}
/// Parameters that have the same names across all bridges.
@@ -309,168 +306,6 @@ macro_rules! select_bridge {
Err(anyhow::format_err!("Account creation is not supported by this bridge"))
}
$generic
},
RelayHeadersAndMessages::RococoWococo(_) => {
type Params = RococoWococoHeadersAndMessages;
type Left = relay_rococo_client::Rococo;
type Right = relay_wococo_client::Wococo;
type LeftAccountIdConverter = bp_rococo::AccountIdConverter;
type RightAccountIdConverter = bp_wococo::AccountIdConverter;
use crate::chains::{
rococo_messages_to_wococo::RococoMessagesToWococo as LeftToRightMessageLane,
wococo_messages_to_rococo::WococoMessagesToRococo as RightToLeftMessageLane,
};
async fn start_on_demand_relays(
params: &Params,
left_client: Client<Left>,
right_client: Client<Right>,
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Left>>>,
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Right>>>,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<BlockNumberOf<Left>>>,
Arc<dyn OnDemandRelay<BlockNumberOf<Right>>>,
)> {
start_on_demand_relay_to_relay::<
Left,
Right,
crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo,
crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo,
>(
left_client,
right_client,
params.left_headers_to_right_sign_override.transaction_params_or::<Right, _>(&params.right_sign)?,
params.right_headers_to_left_sign_override.transaction_params_or::<Left, _>(&params.left_sign)?,
params.shared.only_mandatory_headers,
params.shared.only_mandatory_headers,
params.left.can_start_version_guard(),
params.right.can_start_version_guard(),
at_left_relay_accounts,
at_right_relay_accounts,
).await
}
async fn left_create_account(
left_client: Client<Left>,
left_sign: <Left as TransactionSignScheme>::AccountKeyPair,
account_id: AccountIdOf<Left>,
) -> anyhow::Result<()> {
submit_signed_extrinsic(
left_client,
left_sign,
relay_rococo_client::runtime::Call::Balances(
relay_rococo_client::runtime::BalancesCall::transfer(
bp_rococo::AccountAddress::Id(account_id),
bp_rococo::EXISTENTIAL_DEPOSIT.into(),
),
),
)
.await
}
async fn right_create_account(
right_client: Client<Right>,
right_sign: <Right as TransactionSignScheme>::AccountKeyPair,
account_id: AccountIdOf<Right>,
) -> anyhow::Result<()> {
submit_signed_extrinsic(
right_client,
right_sign,
relay_wococo_client::runtime::Call::Balances(
relay_wococo_client::runtime::BalancesCall::transfer(
bp_wococo::AccountAddress::Id(account_id),
bp_wococo::EXISTENTIAL_DEPOSIT.into(),
),
),
)
.await
}
$generic
},
RelayHeadersAndMessages::KusamaPolkadot(_) => {
type Params = KusamaPolkadotHeadersAndMessages;
type Left = relay_kusama_client::Kusama;
type Right = relay_polkadot_client::Polkadot;
type LeftAccountIdConverter = bp_kusama::AccountIdConverter;
type RightAccountIdConverter = bp_polkadot::AccountIdConverter;
use crate::chains::{
kusama_messages_to_polkadot::KusamaMessagesToPolkadot as LeftToRightMessageLane,
polkadot_messages_to_kusama::PolkadotMessagesToKusama as RightToLeftMessageLane,
};
async fn start_on_demand_relays(
params: &Params,
left_client: Client<Left>,
right_client: Client<Right>,
at_left_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Left>>>,
at_right_relay_accounts: &mut Vec<TaggedAccount<AccountIdOf<Right>>>,
) -> anyhow::Result<(
Arc<dyn OnDemandRelay<BlockNumberOf<Left>>>,
Arc<dyn OnDemandRelay<BlockNumberOf<Right>>>,
)> {
start_on_demand_relay_to_relay::<
Left,
Right,
crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot,
crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama,
>(
left_client,
right_client,
params.left_headers_to_right_sign_override.transaction_params_or::<Right, _>(&params.right_sign)?,
params.right_headers_to_left_sign_override.transaction_params_or::<Left, _>(&params.left_sign)?,
params.shared.only_mandatory_headers,
params.shared.only_mandatory_headers,
params.left.can_start_version_guard(),
params.right.can_start_version_guard(),
at_left_relay_accounts,
at_right_relay_accounts,
).await
}
async fn left_create_account(
left_client: Client<Left>,
left_sign: <Left as TransactionSignScheme>::AccountKeyPair,
account_id: AccountIdOf<Left>,
) -> anyhow::Result<()> {
submit_signed_extrinsic(
left_client,
left_sign,
relay_kusama_client::runtime::Call::Balances(
relay_kusama_client::runtime::BalancesCall::transfer(
bp_kusama::AccountAddress::Id(account_id),
bp_kusama::EXISTENTIAL_DEPOSIT.into(),
),
),
)
.await
}
async fn right_create_account(
right_client: Client<Right>,
right_sign: <Right as TransactionSignScheme>::AccountKeyPair,
account_id: AccountIdOf<Right>,
) -> anyhow::Result<()> {
submit_signed_extrinsic(
right_client,
right_sign,
relay_polkadot_client::runtime::Call::Balances(
relay_polkadot_client::runtime::BalancesCall::transfer(
bp_polkadot::AccountAddress::Id(account_id),
bp_polkadot::EXISTENTIAL_DEPOSIT.into(),
),
),
)
.await
}
$generic
},
}
@@ -481,24 +316,14 @@ macro_rules! select_bridge {
declare_chain_options!(Millau, millau);
declare_chain_options!(Rialto, rialto);
declare_chain_options!(RialtoParachain, rialto_parachain);
declare_chain_options!(Rococo, rococo);
declare_chain_options!(Wococo, wococo);
declare_chain_options!(Kusama, kusama);
declare_chain_options!(Polkadot, polkadot);
// Means to override signers of different layer transactions.
declare_chain_options!(MillauHeadersToRialto, millau_headers_to_rialto);
declare_chain_options!(MillauHeadersToRialtoParachain, millau_headers_to_rialto_parachain);
declare_chain_options!(RialtoHeadersToMillau, rialto_headers_to_millau);
declare_chain_options!(RialtoParachainsToMillau, rialto_parachains_to_millau);
declare_chain_options!(WococoHeadersToRococo, wococo_headers_to_rococo);
declare_chain_options!(RococoHeadersToWococo, rococo_headers_to_wococo);
declare_chain_options!(KusamaHeadersToPolkadot, kusama_headers_to_polkadot);
declare_chain_options!(PolkadotHeadersToKusama, polkadot_headers_to_kusama);
// All supported bridges.
declare_bridge_options!(Millau, Rialto);
declare_bridge_options!(Millau, RialtoParachain, Rialto);
declare_bridge_options!(Rococo, Wococo);
declare_bridge_options!(Kusama, Polkadot);
impl RelayHeadersAndMessages {
/// Run the command.
@@ -912,37 +737,6 @@ where
Ok((Arc::new(left_to_right_on_demand_headers), Arc::new(right_to_left_on_demand_parachains)))
}
/// Sign and submit transaction with given call to the chain.
async fn submit_signed_extrinsic<C: Chain + TransactionSignScheme<Chain = C>>(
client: Client<C>,
sign: C::AccountKeyPair,
call: CallOf<C>,
) -> anyhow::Result<()>
where
AccountIdOf<C>: From<<<C as TransactionSignScheme>::AccountKeyPair as Pair>::Public>,
CallOf<C>: Send,
{
let genesis_hash = *client.genesis_hash();
let (spec_version, transaction_version) = client.simple_runtime_version().await?;
client
.submit_signed_extrinsic(sign.public().into(), move |_, transaction_nonce| {
Ok(Bytes(
C::sign_transaction(SignParam {
spec_version,
transaction_version,
genesis_hash,
signer: sign,
era: relay_substrate_client::TransactionEra::immortal(),
unsigned: UnsignedTransaction::new(call.into(), transaction_nonce),
})?
.encode(),
))
})
.await
.map(drop)
.map_err(|e| anyhow::format_err!("{}", e))
}
#[cfg(test)]
mod tests {
use super::*;
@@ -62,8 +62,6 @@ pub struct ResubmitTransactions {
#[strum(serialize_all = "kebab_case")]
pub enum RelayChain {
Millau,
Kusama,
Polkadot,
}
/// Strategy to use for priority selection.
@@ -93,18 +91,6 @@ macro_rules! select_bridge {
type Target = relay_millau_client::Millau;
type TargetSign = relay_millau_client::Millau;
$generic
},
RelayChain::Kusama => {
type Target = relay_kusama_client::Kusama;
type TargetSign = relay_kusama_client::Kusama;
$generic
},
RelayChain::Polkadot => {
type Target = relay_polkadot_client::Polkadot;
type TargetSign = relay_polkadot_client::Polkadot;
$generic
},
}