mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 19:51:02 +00:00
Relay subcommands to initialize substrate bridge pallet (#483)
* initialize substrate bridge from relay * is_halted: false * initialize using su instead of owner * Fix wording in comments Co-authored-by: Hernando Castano <castano.ha@gmail.com>
This commit is contained in:
committed by
Bastian Köcher
parent
3f7655a056
commit
0c38193af7
@@ -37,5 +37,6 @@ rialto-runtime = { path = "../../bin/rialto/runtime" }
|
||||
|
||||
frame-support = "2.0"
|
||||
sp-core = "2.0"
|
||||
sp-finality-grandpa = "2.0"
|
||||
sp-runtime = "2.0"
|
||||
sp-trie = "2.0"
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
//! Deal with CLI args of substrate-to-substrate relay.
|
||||
|
||||
use bp_message_lane::LaneId;
|
||||
use sp_core::Bytes;
|
||||
use sp_finality_grandpa::SetId as GrandpaAuthoritiesSetId;
|
||||
use structopt::{clap::arg_enum, StructOpt};
|
||||
|
||||
/// Parse relay CLI args.
|
||||
@@ -28,6 +30,17 @@ pub fn parse_args() -> Command {
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(about = "Substrate-to-Substrate relay")]
|
||||
pub enum Command {
|
||||
/// Initialize Millau headers bridge in Rialto.
|
||||
InitializeMillauHeadersBridgeInRialto {
|
||||
#[structopt(flatten)]
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
rialto: RialtoConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
rialto_sign: RialtoSigningParams,
|
||||
#[structopt(flatten)]
|
||||
millau_bridge_params: MillauBridgeInitializationParams,
|
||||
},
|
||||
/// Relay Millau headers to Rialto.
|
||||
MillauHeadersToRialto {
|
||||
#[structopt(flatten)]
|
||||
@@ -39,6 +52,17 @@ pub enum Command {
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
},
|
||||
/// Initialize Rialto headers bridge in Millau.
|
||||
InitializeRialtoHeadersBridgeInMillau {
|
||||
#[structopt(flatten)]
|
||||
rialto: RialtoConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau_sign: MillauSigningParams,
|
||||
#[structopt(flatten)]
|
||||
rialto_bridge_params: RialtoBridgeInitializationParams,
|
||||
},
|
||||
/// Relay Rialto headers to Millau.
|
||||
RialtoHeadersToMillau {
|
||||
#[structopt(flatten)]
|
||||
@@ -165,6 +189,20 @@ macro_rules! declare_chain_options {
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _signer_password>]: Option<String>,
|
||||
}
|
||||
|
||||
#[doc = $chain " headers bridge initialization params."]
|
||||
#[derive(StructOpt)]
|
||||
pub struct [<$chain BridgeInitializationParams>] {
|
||||
#[doc = "Hex-encoded " $chain " header to initialize bridge with. If not specified, genesis header is used."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _initial_header>]: Option<Bytes>,
|
||||
#[doc = "Hex-encoded " $chain " GRANDPA authorities set to initialize bridge with. If not specified, set from genesis block is used."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _initial_authorities>]: Option<Bytes>,
|
||||
#[doc = "Id of the " $chain " GRANDPA authorities set to initialize bridge with. If not specified, zero is used."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _initial_authorities_set_id>]: Option<GrandpaAuthoritiesSetId>,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// Copyright 2019-2020 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/>.
|
||||
|
||||
//! Initialize Substrate -> Substrate headers bridge.
|
||||
//!
|
||||
//! Initialization is a transaction that calls `initialize()` function of the
|
||||
//! `pallet-substrate-bridge` pallet. This transaction brings initial header
|
||||
//! and authorities set from source to target chain. The headers sync starts
|
||||
//! with this header.
|
||||
|
||||
use codec::Decode;
|
||||
use pallet_substrate_bridge::InitializationData;
|
||||
use relay_substrate_client::{Chain, Client};
|
||||
use sp_core::Bytes;
|
||||
use sp_finality_grandpa::{AuthorityList as GrandpaAuthoritiesSet, SetId as GrandpaAuthoritiesSetId};
|
||||
|
||||
/// Submit headers-bridge initialization transaction.
|
||||
pub async fn initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
source_client: Client<SourceChain>,
|
||||
target_client: Client<TargetChain>,
|
||||
raw_initial_header: Option<Bytes>,
|
||||
raw_initial_authorities_set: Option<Bytes>,
|
||||
initial_authorities_set_id: Option<GrandpaAuthoritiesSetId>,
|
||||
prepare_initialize_transaction: impl FnOnce(InitializationData<SourceChain::Header>) -> Result<Bytes, String>,
|
||||
) {
|
||||
let result = do_initialize(
|
||||
source_client,
|
||||
target_client,
|
||||
raw_initial_header,
|
||||
raw_initial_authorities_set,
|
||||
initial_authorities_set_id,
|
||||
prepare_initialize_transaction,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(tx_hash) => log::info!(
|
||||
target: "bridge",
|
||||
"Successfully submitted {}-headers bridge initialization transaction to {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
TargetChain::NAME,
|
||||
tx_hash,
|
||||
),
|
||||
Err(err) => log::error!(
|
||||
target: "bridge",
|
||||
"Failed to submit {}-headers bridge initialization transaction to {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
TargetChain::NAME,
|
||||
err,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Craft and submit initialization transaction, returning any error that may occur.
|
||||
async fn do_initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
source_client: Client<SourceChain>,
|
||||
target_client: Client<TargetChain>,
|
||||
raw_initial_header: Option<Bytes>,
|
||||
raw_initial_authorities_set: Option<Bytes>,
|
||||
initial_authorities_set_id: Option<GrandpaAuthoritiesSetId>,
|
||||
prepare_initialize_transaction: impl FnOnce(InitializationData<SourceChain::Header>) -> Result<Bytes, String>,
|
||||
) -> Result<TargetChain::Hash, String> {
|
||||
let initialization_data = prepare_initialization_data(
|
||||
source_client,
|
||||
raw_initial_header,
|
||||
raw_initial_authorities_set,
|
||||
initial_authorities_set_id,
|
||||
)
|
||||
.await?;
|
||||
let initialization_tx = prepare_initialize_transaction(initialization_data)?;
|
||||
let initialization_tx_hash = target_client
|
||||
.submit_extrinsic(initialization_tx)
|
||||
.await
|
||||
.map_err(|err| format!("Failed to submit {} transaction: {:?}", TargetChain::NAME, err))?;
|
||||
Ok(initialization_tx_hash)
|
||||
}
|
||||
|
||||
/// Prepare initialization data for the headers-bridge pallet.
|
||||
async fn prepare_initialization_data<SourceChain: Chain>(
|
||||
source_client: Client<SourceChain>,
|
||||
raw_initial_header: Option<Bytes>,
|
||||
raw_initial_authorities_set: Option<Bytes>,
|
||||
initial_authorities_set_id: Option<GrandpaAuthoritiesSetId>,
|
||||
) -> Result<InitializationData<SourceChain::Header>, String> {
|
||||
let source_genesis_hash = *source_client.genesis_hash();
|
||||
|
||||
let initial_header = match raw_initial_header {
|
||||
Some(raw_initial_header) => SourceChain::Header::decode(&mut &raw_initial_header.0[..])
|
||||
.map_err(|err| format!("Failed to decode {} initial header: {:?}", SourceChain::NAME, err))?,
|
||||
None => source_client
|
||||
.header_by_hash(source_genesis_hash)
|
||||
.await
|
||||
.map_err(|err| format!("Failed to retrive {} genesis header: {:?}", SourceChain::NAME, err))?,
|
||||
};
|
||||
|
||||
let raw_initial_authorities_set = match raw_initial_authorities_set {
|
||||
Some(raw_initial_authorities_set) => raw_initial_authorities_set.0,
|
||||
None => source_client
|
||||
.grandpa_authorities_set(source_genesis_hash)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"Failed to retrive {} authorities set at genesis header: {:?}",
|
||||
SourceChain::NAME,
|
||||
err
|
||||
)
|
||||
})?,
|
||||
};
|
||||
let initial_authorities_set =
|
||||
GrandpaAuthoritiesSet::decode(&mut &raw_initial_authorities_set[..]).map_err(|err| {
|
||||
format!(
|
||||
"Failed to decode {} initial authorities set: {:?}",
|
||||
SourceChain::NAME,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(InitializationData {
|
||||
header: initial_header,
|
||||
authority_list: initial_authorities_set,
|
||||
set_id: initial_authorities_set_id.unwrap_or(0),
|
||||
// There may be multiple scheduled changes, so on real chains we should select proper
|
||||
// moment, when there's nothing scheduled. On ephemeral (temporary) chains, it is ok to
|
||||
// start with genesis.
|
||||
scheduled_change: None,
|
||||
is_halted: false,
|
||||
})
|
||||
}
|
||||
@@ -33,6 +33,7 @@ pub type MillauClient = relay_substrate_client::Client<Millau>;
|
||||
pub type RialtoClient = relay_substrate_client::Client<Rialto>;
|
||||
|
||||
mod cli;
|
||||
mod headers_initialize;
|
||||
mod headers_maintain;
|
||||
mod headers_pipeline;
|
||||
mod headers_target;
|
||||
@@ -53,6 +54,54 @@ fn main() {
|
||||
|
||||
async fn run_command(command: cli::Command) -> Result<(), String> {
|
||||
match command {
|
||||
cli::Command::InitializeMillauHeadersBridgeInRialto {
|
||||
millau,
|
||||
rialto,
|
||||
rialto_sign,
|
||||
millau_bridge_params,
|
||||
} => {
|
||||
let millau_client = MillauClient::new(ConnectionParams {
|
||||
host: millau.millau_host,
|
||||
port: millau.millau_port,
|
||||
})
|
||||
.await?;
|
||||
let rialto_client = RialtoClient::new(ConnectionParams {
|
||||
host: rialto.rialto_host,
|
||||
port: rialto.rialto_port,
|
||||
})
|
||||
.await?;
|
||||
let rialto_sign = RialtoSigningParams::from_suri(
|
||||
&rialto_sign.rialto_signer,
|
||||
rialto_sign.rialto_signer_password.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to parse rialto-signer: {:?}", e))?;
|
||||
let rialto_signer_next_index = rialto_client
|
||||
.next_account_index(rialto_sign.signer.public().into())
|
||||
.await?;
|
||||
|
||||
headers_initialize::initialize(
|
||||
millau_client,
|
||||
rialto_client.clone(),
|
||||
millau_bridge_params.millau_initial_header,
|
||||
millau_bridge_params.millau_initial_authorities,
|
||||
millau_bridge_params.millau_initial_authorities_set_id,
|
||||
move |initialization_data| {
|
||||
Ok(Bytes(
|
||||
Rialto::sign_transaction(
|
||||
&rialto_client,
|
||||
&rialto_sign.signer,
|
||||
rialto_signer_next_index,
|
||||
millau_runtime::SudoCall::sudo(Box::new(
|
||||
rialto_runtime::BridgeMillauCall::initialize(initialization_data).into(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
cli::Command::MillauHeadersToRialto {
|
||||
millau,
|
||||
rialto,
|
||||
@@ -76,6 +125,54 @@ async fn run_command(command: cli::Command) -> Result<(), String> {
|
||||
.map_err(|e| format!("Failed to parse rialto-signer: {:?}", e))?;
|
||||
millau_headers_to_rialto::run(millau_client, rialto_client, rialto_sign, prometheus_params.into()).await;
|
||||
}
|
||||
cli::Command::InitializeRialtoHeadersBridgeInMillau {
|
||||
rialto,
|
||||
millau,
|
||||
millau_sign,
|
||||
rialto_bridge_params,
|
||||
} => {
|
||||
let rialto_client = RialtoClient::new(ConnectionParams {
|
||||
host: rialto.rialto_host,
|
||||
port: rialto.rialto_port,
|
||||
})
|
||||
.await?;
|
||||
let millau_client = MillauClient::new(ConnectionParams {
|
||||
host: millau.millau_host,
|
||||
port: millau.millau_port,
|
||||
})
|
||||
.await?;
|
||||
let millau_sign = MillauSigningParams::from_suri(
|
||||
&millau_sign.millau_signer,
|
||||
millau_sign.millau_signer_password.as_deref(),
|
||||
)
|
||||
.map_err(|e| format!("Failed to parse millau-signer: {:?}", e))?;
|
||||
let millau_signer_next_index = millau_client
|
||||
.next_account_index(millau_sign.signer.public().into())
|
||||
.await?;
|
||||
|
||||
headers_initialize::initialize(
|
||||
rialto_client,
|
||||
millau_client.clone(),
|
||||
rialto_bridge_params.rialto_initial_header,
|
||||
rialto_bridge_params.rialto_initial_authorities,
|
||||
rialto_bridge_params.rialto_initial_authorities_set_id,
|
||||
move |initialization_data| {
|
||||
Ok(Bytes(
|
||||
Millau::sign_transaction(
|
||||
&millau_client,
|
||||
&millau_sign.signer,
|
||||
millau_signer_next_index,
|
||||
millau_runtime::SudoCall::sudo(Box::new(
|
||||
millau_runtime::BridgeRialtoCall::initialize(initialization_data).into(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
},
|
||||
)
|
||||
.await;
|
||||
}
|
||||
cli::Command::RialtoHeadersToMillau {
|
||||
rialto,
|
||||
millau,
|
||||
|
||||
Reference in New Issue
Block a user