mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 06:21:02 +00:00
Sync Westend to Millau (#824)
* make finality verifier pallet instantiable * add second instance of finality verifier pallet to the Millau runtime * add Westend -> Millau headers relay * use wss to connect to public westend nodes * initialize with best_finalized_block * typo * Revert "initialize with best_finalized_block" This reverts commit 954ed2832372d67618abc1a06d47e66faa93f674. * pass VoterSet by ref * new bridge initialization code * loop upper bound * Polkadot -> Westend * fixed tests compilation * default-features * assert
This commit is contained in:
committed by
Bastian Köcher
parent
249a8f73ff
commit
d749bc3a96
@@ -26,7 +26,9 @@ bp-millau = { path = "../../primitives/chains/millau" }
|
||||
bp-polkadot = { path = "../../primitives/chains/polkadot" }
|
||||
bp-runtime = { path = "../../primitives/runtime" }
|
||||
bp-rialto = { path = "../../primitives/chains/rialto" }
|
||||
bp-westend = { path = "../../primitives/chains/westend" }
|
||||
bridge-runtime-common = { path = "../../bin/runtime-common" }
|
||||
finality-grandpa = { version = "0.14.0" }
|
||||
finality-relay = { path = "../generic/finality" }
|
||||
headers-relay = { path = "../generic/headers" }
|
||||
messages-relay = { path = "../generic/messages" }
|
||||
@@ -39,6 +41,7 @@ relay-millau-client = { path = "../clients/millau" }
|
||||
relay-polkadot-client = { path = "../clients/polkadot" }
|
||||
relay-rialto-client = { path = "../clients/rialto" }
|
||||
relay-substrate-client = { path = "../clients/substrate" }
|
||||
relay-westend-client = { path = "../clients/westend" }
|
||||
relay-utils = { path = "../generic/utils" }
|
||||
rialto-runtime = { path = "../../bin/rialto/runtime" }
|
||||
|
||||
|
||||
@@ -396,6 +396,9 @@ macro_rules! declare_chain_options {
|
||||
#[doc = "Connect to " $chain " node websocket server at given port."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _port>]: u16,
|
||||
#[doc = "Use secure websocket connection."]
|
||||
#[structopt(long)]
|
||||
pub [<$chain_prefix _secure>]: bool,
|
||||
}
|
||||
|
||||
#[doc = $chain " signing params."]
|
||||
@@ -408,20 +411,6 @@ 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<sp_core::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<sp_core::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<sp_finality_grandpa::SetId>,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,30 +21,26 @@
|
||||
//! and authorities set from source to target chain. The headers sync starts
|
||||
//! with this header.
|
||||
|
||||
use bp_header_chain::{
|
||||
find_grandpa_authorities_scheduled_change,
|
||||
justification::{decode_justification_target, verify_justification},
|
||||
};
|
||||
use codec::Decode;
|
||||
use finality_grandpa::voter_set::VoterSet;
|
||||
use num_traits::{One, Zero};
|
||||
use pallet_finality_verifier::InitializationData;
|
||||
use relay_substrate_client::{Chain, Client};
|
||||
use sp_core::Bytes;
|
||||
use sp_finality_grandpa::{AuthorityList as GrandpaAuthoritiesSet, SetId as GrandpaAuthoritiesSetId};
|
||||
use sp_finality_grandpa::AuthorityList as GrandpaAuthoritiesSet;
|
||||
use sp_runtime::traits::Header as HeaderT;
|
||||
|
||||
/// 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;
|
||||
let result = do_initialize(source_client, target_client, prepare_initialize_transaction).await;
|
||||
|
||||
match result {
|
||||
Ok(tx_hash) => log::info!(
|
||||
@@ -68,18 +64,17 @@ pub async fn initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
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_data = prepare_initialization_data(source_client).await?;
|
||||
log::info!(
|
||||
target: "bridge",
|
||||
"Prepared initialization data for {}-headers bridge at {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
TargetChain::NAME,
|
||||
initialization_data,
|
||||
);
|
||||
|
||||
let initialization_tx = prepare_initialize_transaction(initialization_data)?;
|
||||
let initialization_tx_hash = target_client
|
||||
.submit_extrinsic(initialization_tx)
|
||||
@@ -88,50 +83,161 @@ async fn do_initialize<SourceChain: Chain, TargetChain: Chain>(
|
||||
Ok(initialization_tx_hash)
|
||||
}
|
||||
|
||||
/// Prepare initialization data for the headers-bridge pallet.
|
||||
/// Prepare initialization data for the finality-verifier 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();
|
||||
// In ideal world we just need to get best finalized header and then to read GRANDPA authorities
|
||||
// set (`pallet_grandpa::CurrentSetId` + `GrandpaApi::grandpa_authorities()`) at this header.
|
||||
//
|
||||
// But now there are problems with this approach - `CurrentSetId` may return invalid value. So here
|
||||
// we're waiting for the next justification, read the authorities set and then try to figure out
|
||||
// the set id with bruteforce.
|
||||
let mut justifications = source_client
|
||||
.subscribe_justifications()
|
||||
.await
|
||||
.map_err(|err| format!("Failed to subscribe to {} justifications: {:?}", SourceChain::NAME, err))?;
|
||||
|
||||
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))?,
|
||||
};
|
||||
// Read next justification - the header that it finalizes will be used as initial header.
|
||||
let justification = justifications.next().await.ok_or_else(|| {
|
||||
format!(
|
||||
"Failed to read {} justification from the stream: stream has ended unexpectedly",
|
||||
SourceChain::NAME,
|
||||
)
|
||||
})?;
|
||||
|
||||
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: {:?}",
|
||||
// Read initial header.
|
||||
let (initial_header_hash, initial_header_number) =
|
||||
decode_justification_target::<SourceChain::Header>(&justification.0)
|
||||
.map_err(|err| format!("Failed to decode {} justification: {:?}", SourceChain::NAME, err))?;
|
||||
let initial_header = source_header(&source_client, initial_header_hash).await?;
|
||||
log::trace!(target: "bridge", "Selected {} initial header: {}/{}",
|
||||
SourceChain::NAME,
|
||||
initial_header_number,
|
||||
initial_header_hash,
|
||||
);
|
||||
|
||||
// Read GRANDPA authorities set at initial header.
|
||||
let initial_authorities_set = source_authorities_set(&source_client, initial_header_hash).await?;
|
||||
log::trace!(target: "bridge", "Selected {} initial authorities set: {:?}",
|
||||
SourceChain::NAME,
|
||||
initial_authorities_set,
|
||||
);
|
||||
|
||||
// If initial header changes the GRANDPA authorities set, then we need previous authorities
|
||||
// to verify justification.
|
||||
let mut authorities_for_verification = initial_authorities_set.clone();
|
||||
let scheduled_change = find_grandpa_authorities_scheduled_change(&initial_header);
|
||||
assert!(
|
||||
scheduled_change.as_ref().map(|c| c.delay.is_zero()).unwrap_or(true),
|
||||
"GRANDPA authorities change at {} scheduled to happen in {:?} blocks. We expect\
|
||||
regular hange to have zero delay",
|
||||
initial_header_hash,
|
||||
scheduled_change.as_ref().map(|c| c.delay),
|
||||
);
|
||||
let schedules_change = scheduled_change.is_some();
|
||||
if schedules_change {
|
||||
authorities_for_verification = source_authorities_set(&source_client, *initial_header.parent_hash()).await?;
|
||||
log::trace!(
|
||||
target: "bridge",
|
||||
"Selected {} header is scheduling GRANDPA authorities set changes. Using previous set: {:?}",
|
||||
SourceChain::NAME,
|
||||
authorities_for_verification,
|
||||
);
|
||||
}
|
||||
|
||||
// Now let's try to guess authorities set id by verifying justification.
|
||||
let mut initial_authorities_set_id = 0;
|
||||
let mut min_possible_block_number = SourceChain::BlockNumber::zero();
|
||||
let authorities_for_verification = VoterSet::new(authorities_for_verification.clone()).ok_or_else(|| {
|
||||
format!(
|
||||
"Read invalid {} authorities set: {:?}",
|
||||
SourceChain::NAME,
|
||||
authorities_for_verification,
|
||||
)
|
||||
})?;
|
||||
loop {
|
||||
log::trace!(
|
||||
target: "bridge", "Trying {} GRANDPA authorities set id: {}",
|
||||
SourceChain::NAME,
|
||||
initial_authorities_set_id,
|
||||
);
|
||||
|
||||
let is_valid_set_id = verify_justification::<SourceChain::Header>(
|
||||
(initial_header_hash, initial_header_number),
|
||||
initial_authorities_set_id,
|
||||
&authorities_for_verification,
|
||||
&justification.0,
|
||||
)
|
||||
.is_ok();
|
||||
if is_valid_set_id {
|
||||
break;
|
||||
}
|
||||
|
||||
initial_authorities_set_id += 1;
|
||||
min_possible_block_number += One::one();
|
||||
if min_possible_block_number > initial_header_number {
|
||||
// there can't be more authorities set changes than headers => if we have reached `initial_block_number`
|
||||
// and still have not found correct value of `initial_authorities_set_id`, then something
|
||||
// else is broken => fail
|
||||
return Err(format!(
|
||||
"Failed to guess initial {} GRANDPA authorities set id: checked all\
|
||||
possible ids in range [0; {}]",
|
||||
SourceChain::NAME,
|
||||
err
|
||||
)
|
||||
})?;
|
||||
initial_header_number
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(InitializationData {
|
||||
header: initial_header,
|
||||
authority_list: initial_authorities_set,
|
||||
set_id: initial_authorities_set_id.unwrap_or(0),
|
||||
set_id: if schedules_change {
|
||||
initial_authorities_set_id + 1
|
||||
} else {
|
||||
initial_authorities_set_id
|
||||
},
|
||||
is_halted: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Read header by hash from the source client.
|
||||
async fn source_header<SourceChain: Chain>(
|
||||
source_client: &Client<SourceChain>,
|
||||
header_hash: SourceChain::Hash,
|
||||
) -> Result<SourceChain::Header, String> {
|
||||
source_client.header_by_hash(header_hash).await.map_err(|err| {
|
||||
format!(
|
||||
"Failed to retrive {} header with hash {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Read GRANDPA authorities set at given header.
|
||||
async fn source_authorities_set<SourceChain: Chain>(
|
||||
source_client: &Client<SourceChain>,
|
||||
header_hash: SourceChain::Hash,
|
||||
) -> Result<GrandpaAuthoritiesSet, String> {
|
||||
let raw_authorities_set = source_client
|
||||
.grandpa_authorities_set(header_hash)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
format!(
|
||||
"Failed to retrive {} GRANDPA authorities set at header {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
GrandpaAuthoritiesSet::decode(&mut &raw_authorities_set[..]).map_err(|err| {
|
||||
format!(
|
||||
"Failed to decode {} GRANDPA authorities set at header {}: {:?}",
|
||||
SourceChain::NAME,
|
||||
header_hash,
|
||||
err,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,6 +47,17 @@ pub enum RelayHeaders {
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
},
|
||||
/// Relay Westend headers to Millau.
|
||||
WestendToMillau {
|
||||
#[structopt(flatten)]
|
||||
westend: WestendConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau_sign: MillauSigningParams,
|
||||
#[structopt(flatten)]
|
||||
prometheus_params: PrometheusParams,
|
||||
},
|
||||
}
|
||||
|
||||
impl RelayHeaders {
|
||||
@@ -113,8 +124,6 @@ pub enum InitBridge {
|
||||
rialto: RialtoConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
rialto_sign: RialtoSigningParams,
|
||||
#[structopt(flatten)]
|
||||
millau_bridge_params: MillauBridgeInitializationParams,
|
||||
},
|
||||
/// Initialize Rialto headers bridge in Millau.
|
||||
RialtoToMillau {
|
||||
@@ -124,8 +133,15 @@ pub enum InitBridge {
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau_sign: MillauSigningParams,
|
||||
},
|
||||
/// Initialize Westend headers bridge in Millau.
|
||||
WestendToMillau {
|
||||
#[structopt(flatten)]
|
||||
rialto_bridge_params: RialtoBridgeInitializationParams,
|
||||
westend: WestendConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau: MillauConnectionParams,
|
||||
#[structopt(flatten)]
|
||||
millau_sign: MillauSigningParams,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -421,3 +437,4 @@ pub enum ToMillauMessage {
|
||||
|
||||
declare_chain_options!(Rialto, rialto);
|
||||
declare_chain_options!(Millau, millau);
|
||||
declare_chain_options!(Westend, westend);
|
||||
|
||||
@@ -21,11 +21,14 @@ pub mod millau_headers_to_rialto;
|
||||
pub mod millau_messages_to_rialto;
|
||||
pub mod rialto_headers_to_millau;
|
||||
pub mod rialto_messages_to_millau;
|
||||
pub mod westend_headers_to_millau;
|
||||
|
||||
/// Millau node client.
|
||||
pub type MillauClient = relay_substrate_client::Client<Millau>;
|
||||
/// Rialto node client.
|
||||
pub type RialtoClient = relay_substrate_client::Client<Rialto>;
|
||||
/// Westend node client.
|
||||
pub type WestendClient = relay_substrate_client::Client<Westend>;
|
||||
|
||||
use crate::cli::{ExplicitOrMaximal, HexBytes, Origins};
|
||||
use codec::{Decode, Encode};
|
||||
@@ -34,6 +37,7 @@ use pallet_bridge_call_dispatch::{CallOrigin, MessagePayload};
|
||||
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
|
||||
use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams};
|
||||
use relay_substrate_client::{Chain, ConnectionParams, TransactionSignScheme};
|
||||
use relay_westend_client::Westend;
|
||||
use sp_core::{Bytes, Pair};
|
||||
use sp_runtime::traits::IdentifyAccount;
|
||||
use std::fmt::Debug;
|
||||
@@ -44,7 +48,6 @@ async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> {
|
||||
millau,
|
||||
rialto,
|
||||
rialto_sign,
|
||||
millau_bridge_params,
|
||||
} => {
|
||||
let millau_client = millau.into_client().await?;
|
||||
let rialto_client = rialto.into_client().await?;
|
||||
@@ -54,34 +57,26 @@ async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> {
|
||||
.next_account_index(rialto_sign.signer.public().into())
|
||||
.await?;
|
||||
|
||||
crate::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.genesis_hash(),
|
||||
&rialto_sign.signer,
|
||||
rialto_signer_next_index,
|
||||
rialto_runtime::SudoCall::sudo(Box::new(
|
||||
rialto_runtime::FinalityBridgeMillauCall::initialize(initialization_data).into(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
},
|
||||
)
|
||||
crate::headers_initialize::initialize(millau_client, rialto_client.clone(), move |initialization_data| {
|
||||
Ok(Bytes(
|
||||
Rialto::sign_transaction(
|
||||
*rialto_client.genesis_hash(),
|
||||
&rialto_sign.signer,
|
||||
rialto_signer_next_index,
|
||||
rialto_runtime::SudoCall::sudo(Box::new(
|
||||
rialto_runtime::FinalityBridgeMillauCall::initialize(initialization_data).into(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
})
|
||||
.await;
|
||||
}
|
||||
cli::InitBridge::RialtoToMillau {
|
||||
rialto,
|
||||
millau,
|
||||
millau_sign,
|
||||
rialto_bridge_params,
|
||||
} => {
|
||||
let rialto_client = rialto.into_client().await?;
|
||||
let millau_client = millau.into_client().await?;
|
||||
@@ -90,27 +85,52 @@ async fn run_init_bridge(command: cli::InitBridge) -> Result<(), String> {
|
||||
.next_account_index(millau_sign.signer.public().into())
|
||||
.await?;
|
||||
|
||||
crate::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.genesis_hash(),
|
||||
&millau_sign.signer,
|
||||
millau_signer_next_index,
|
||||
millau_runtime::SudoCall::sudo(Box::new(
|
||||
millau_runtime::FinalityBridgeRialtoCall::initialize(initialization_data).into(),
|
||||
))
|
||||
.into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
},
|
||||
)
|
||||
crate::headers_initialize::initialize(rialto_client, millau_client.clone(), move |initialization_data| {
|
||||
let initialize_call = millau_runtime::FinalityBridgeRialtoCall::<
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::RialtoFinalityVerifierInstance,
|
||||
>::initialize(initialization_data);
|
||||
|
||||
Ok(Bytes(
|
||||
Millau::sign_transaction(
|
||||
*millau_client.genesis_hash(),
|
||||
&millau_sign.signer,
|
||||
millau_signer_next_index,
|
||||
millau_runtime::SudoCall::sudo(Box::new(initialize_call.into())).into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
})
|
||||
.await;
|
||||
}
|
||||
cli::InitBridge::WestendToMillau {
|
||||
westend,
|
||||
millau,
|
||||
millau_sign,
|
||||
} => {
|
||||
let westend_client = westend.into_client().await?;
|
||||
let millau_client = millau.into_client().await?;
|
||||
let millau_sign = millau_sign.parse()?;
|
||||
let millau_signer_next_index = millau_client
|
||||
.next_account_index(millau_sign.signer.public().into())
|
||||
.await?;
|
||||
|
||||
crate::headers_initialize::initialize(westend_client, millau_client.clone(), move |initialization_data| {
|
||||
let initialize_call = millau_runtime::FinalityBridgeWestendCall::<
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WestendFinalityVerifierInstance,
|
||||
>::initialize(initialization_data);
|
||||
|
||||
Ok(Bytes(
|
||||
Millau::sign_transaction(
|
||||
*millau_client.genesis_hash(),
|
||||
&millau_sign.signer,
|
||||
millau_signer_next_index,
|
||||
millau_runtime::SudoCall::sudo(Box::new(initialize_call.into())).into(),
|
||||
)
|
||||
.encode(),
|
||||
))
|
||||
})
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -141,6 +161,17 @@ async fn run_relay_headers(command: cli::RelayHeaders) -> Result<(), String> {
|
||||
let millau_sign = millau_sign.parse()?;
|
||||
rialto_headers_to_millau::run(rialto_client, millau_client, millau_sign, prometheus_params.into()).await;
|
||||
}
|
||||
cli::RelayHeaders::WestendToMillau {
|
||||
westend,
|
||||
millau,
|
||||
millau_sign,
|
||||
prometheus_params,
|
||||
} => {
|
||||
let westend_client = westend.into_client().await?;
|
||||
let millau_client = millau.into_client().await?;
|
||||
let millau_sign = millau_sign.parse()?;
|
||||
westend_headers_to_millau::run(westend_client, millau_client, millau_sign, prometheus_params.into()).await;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -661,16 +692,31 @@ impl cli::MillauConnectionParams {
|
||||
MillauClient::new(ConnectionParams {
|
||||
host: self.millau_host,
|
||||
port: self.millau_port,
|
||||
secure: self.millau_secure,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl cli::RialtoConnectionParams {
|
||||
/// Convert CLI connection parameters into Rialto RPC Client.
|
||||
pub async fn into_client(self) -> relay_substrate_client::Result<RialtoClient> {
|
||||
RialtoClient::new(ConnectionParams {
|
||||
host: self.rialto_host,
|
||||
port: self.rialto_port,
|
||||
secure: self.rialto_secure,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
impl cli::WestendConnectionParams {
|
||||
/// Convert CLI connection parameters into Westend RPC Client.
|
||||
pub async fn into_client(self) -> relay_substrate_client::Result<WestendClient> {
|
||||
WestendClient::new(ConnectionParams {
|
||||
host: self.westend_host,
|
||||
port: self.westend_port,
|
||||
secure: self.westend_secure,
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -41,9 +41,12 @@ impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau {
|
||||
) -> Result<Self::SignedTransaction, SubstrateError> {
|
||||
let account_id = self.target_sign.signer.public().as_array_ref().clone().into();
|
||||
let nonce = self.target_client.next_account_index(account_id).await?;
|
||||
let call =
|
||||
millau_runtime::FinalityBridgeRialtoCall::submit_finality_proof(header.into_inner(), proof.into_inner())
|
||||
.into();
|
||||
|
||||
let call = millau_runtime::FinalityBridgeRialtoCall::<
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::RialtoFinalityVerifierInstance,
|
||||
>::submit_finality_proof(header.into_inner(), proof.into_inner())
|
||||
.into();
|
||||
|
||||
let genesis_hash = *self.target_client.genesis_hash();
|
||||
let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign.signer, nonce, call);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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/>.
|
||||
|
||||
//! Westend-to-Millau headers sync entrypoint.
|
||||
|
||||
use super::{MillauClient, WestendClient};
|
||||
use crate::finality_pipeline::{SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use relay_millau_client::{Millau, SigningParams as MillauSigningParams};
|
||||
use relay_substrate_client::{finality_source::Justification, Error as SubstrateError, TransactionSignScheme};
|
||||
use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend};
|
||||
use sp_core::Pair;
|
||||
|
||||
/// Westend-to-Millau finality sync pipeline.
|
||||
pub(crate) type WestendFinalityToMillau = SubstrateFinalityToSubstrate<Westend, Millau, MillauSigningParams>;
|
||||
|
||||
#[async_trait]
|
||||
impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau {
|
||||
const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD;
|
||||
|
||||
type SignedTransaction = <Millau as TransactionSignScheme>::SignedTransaction;
|
||||
|
||||
async fn make_submit_finality_proof_transaction(
|
||||
&self,
|
||||
header: WestendSyncHeader,
|
||||
proof: Justification<bp_westend::BlockNumber>,
|
||||
) -> Result<Self::SignedTransaction, SubstrateError> {
|
||||
let account_id = self.target_sign.signer.public().as_array_ref().clone().into();
|
||||
let nonce = self.target_client.next_account_index(account_id).await?;
|
||||
|
||||
let call = millau_runtime::FinalityBridgeWestendCall::<
|
||||
millau_runtime::Runtime,
|
||||
millau_runtime::WestendFinalityVerifierInstance,
|
||||
>::submit_finality_proof(header.into_inner(), proof.into_inner())
|
||||
.into();
|
||||
|
||||
let genesis_hash = *self.target_client.genesis_hash();
|
||||
let transaction = Millau::sign_transaction(genesis_hash, &self.target_sign.signer, nonce, call);
|
||||
|
||||
Ok(transaction)
|
||||
}
|
||||
}
|
||||
|
||||
/// Run Westend-to-Millau finality sync.
|
||||
pub async fn run(
|
||||
westend_client: WestendClient,
|
||||
millau_client: MillauClient,
|
||||
millau_sign: MillauSigningParams,
|
||||
metrics_params: Option<relay_utils::metrics::MetricsParams>,
|
||||
) {
|
||||
crate::finality_pipeline::run(
|
||||
WestendFinalityToMillau::new(millau_client.clone(), millau_sign),
|
||||
westend_client,
|
||||
millau_client,
|
||||
metrics_params,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Reference in New Issue
Block a user