diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0e69a91af1..d6fd1fd6c7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ variables: &default-vars GIT_DEPTH: 100 CARGO_INCREMENTAL: 0 ARCH: "x86_64" - CI_IMAGE: "paritytech/bridges-ci:staging" + CI_IMAGE: "paritytech/bridges-ci:e8a9ef25-20211215" RUST_BACKTRACE: full default: diff --git a/Cargo.lock b/Cargo.lock index 115fe33dee..5105d0adc0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -733,6 +733,7 @@ dependencies = [ "frame-support", "smallvec", "sp-api", + "sp-runtime", "sp-std", "sp-version", ] @@ -756,10 +757,13 @@ dependencies = [ "bp-runtime", "frame-support", "frame-system", + "hex", + "hex-literal", "impl-trait-for-tuples", "parity-scale-codec", "scale-info", "serde", + "sp-core", "sp-std", ] @@ -796,6 +800,7 @@ dependencies = [ "frame-support", "smallvec", "sp-api", + "sp-runtime", "sp-std", "sp-version", ] @@ -898,10 +903,14 @@ dependencies = [ name = "bp-token-swap" version = "0.1.0" dependencies = [ + "bp-runtime", "frame-support", + "hex", + "hex-literal", "parity-scale-codec", "scale-info", "sp-core", + "sp-io", "sp-std", ] @@ -910,7 +919,6 @@ name = "bp-westend" version = "0.1.0" dependencies = [ "bp-header-chain", - "bp-messages", "bp-polkadot-core", "bp-runtime", "frame-support", @@ -5341,8 +5349,6 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", - "hex", - "hex-literal", "log", "num-traits", "pallet-balances", @@ -7926,6 +7932,7 @@ dependencies = [ name = "relay-millau-client" version = "0.1.0" dependencies = [ + "bp-messages", "bp-millau", "frame-support", "frame-system", @@ -7964,6 +7971,7 @@ dependencies = [ name = "relay-rialto-client" version = "0.1.0" dependencies = [ + "bp-messages", "bp-rialto", "frame-support", "frame-system", @@ -8019,6 +8027,7 @@ dependencies = [ "async-std", "async-trait", "bp-header-chain", + "bp-messages", "bp-runtime", "finality-relay", "frame-support", @@ -8029,6 +8038,7 @@ dependencies = [ "log", "num-traits", "pallet-balances", + "pallet-bridge-messages", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", "parity-scale-codec", @@ -8075,6 +8085,7 @@ name = "relay-westend-client" version = "0.1.0" dependencies = [ "bp-westend", + "frame-support", "parity-scale-codec", "relay-substrate-client", "relay-utils", @@ -10950,7 +10961,7 @@ dependencies = [ [[package]] name = "substrate-relay" -version = "0.1.0" +version = "1.0.0" dependencies = [ "anyhow", "async-std", @@ -11024,6 +11035,7 @@ dependencies = [ "bp-header-chain", "bp-messages", "bp-millau", + "bp-rialto", "bp-rococo", "bp-runtime", "bp-wococo", @@ -11035,6 +11047,7 @@ dependencies = [ "log", "messages-relay", "num-traits", + "pallet-bridge-grandpa", "pallet-bridge-messages", "parity-scale-codec", "relay-rococo-client", diff --git a/Dockerfile b/Dockerfile index ff88c6a5a0..a22c5328f7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ # # See the `deployments/README.md` for all the available `PROJECT` values. -FROM paritytech/bridges-ci:latest as builder +FROM paritytech/bridges-ci:e8a9ef25-20211215 as builder WORKDIR /parity-bridges-common COPY . . diff --git a/bin/millau/node/src/chain_spec.rs b/bin/millau/node/src/chain_spec.rs index fbfca8692f..ad424ba463 100644 --- a/bin/millau/node/src/chain_spec.rs +++ b/bin/millau/node/src/chain_spec.rs @@ -88,15 +88,7 @@ impl Alternative { testnet_genesis( vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Alice"), - )), - ], + endowed_accounts(), true, ) }, @@ -120,48 +112,7 @@ impl Alternative { get_authority_keys_from_seed("Eve"), ], get_account_id_from_seed::("Alice"), - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("George"), - get_account_id_from_seed::("Harry"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - get_account_id_from_seed::("George//stash"), - get_account_id_from_seed::("Harry//stash"), - get_account_id_from_seed::("RialtoMessagesOwner"), - get_account_id_from_seed::("WithRialtoTokenSwap"), - 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::("Alice"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Bob"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Charlie"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Dave"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Eve"), - )), - derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Ferdie"), - )), - ], + endowed_accounts(), true, ) }, @@ -175,6 +126,55 @@ impl Alternative { } } +/// We're using the same set of endowed accounts on all Millau chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("George"), + get_account_id_from_seed::("Harry"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + get_account_id_from_seed::("George//stash"), + get_account_id_from_seed::("Harry//stash"), + get_account_id_from_seed::("RialtoMessagesOwner"), + get_account_id_from_seed::("WithRialtoTokenSwap"), + 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::("Alice"), + )), + derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Bob"), + )), + derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Charlie"), + )), + derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Dave"), + )), + derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Eve"), + )), + derive_account_from_rialto_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Ferdie"), + )), + ] +} + fn session_keys(aura: AuraId, beefy: BeefyId, grandpa: GrandpaId) -> SessionKeys { SessionKeys { aura, beefy, grandpa } } diff --git a/bin/millau/node/src/service.rs b/bin/millau/node/src/service.rs index b01c0bfca9..36e1b94875 100644 --- a/bin/millau/node/src/service.rs +++ b/bin/millau/node/src/service.rs @@ -66,6 +66,7 @@ type FullClient = type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; +#[allow(clippy::type_complexity)] pub fn new_partial( config: &Configuration, ) -> Result< @@ -89,7 +90,7 @@ pub fn new_partial( ServiceError, > { if config.keystore_remote.is_some() { - return Err(ServiceError::Other(format!("Remote Keystores are not supported."))) + return Err(ServiceError::Other("Remote Keystores are not supported.".into())) } let telemetry = config @@ -111,7 +112,7 @@ pub fn new_partial( let (client, backend, keystore_container, task_manager) = sc_service::new_full_parts::( - &config, + config, telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), executor, )?; @@ -178,7 +179,7 @@ pub fn new_partial( }) } -fn remote_keystore(_url: &String) -> Result, &'static str> { +fn remote_keystore(_url: &str) -> Result, &'static str> { // FIXME: here would the concrete keystore be built, // must return a concrete type (NOT `LocalKeystore`) that // implements `CryptoStore` and `SyncCryptoStore` diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index 288ff9a47d..8234b30ca1 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -52,7 +52,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{Block as BlockT, IdentityLookup, Keccak256, NumberFor, OpaqueKeys}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill, }; use sp_std::prelude::*; #[cfg(feature = "std")] @@ -407,9 +407,9 @@ impl pallet_shift_session_manager::Config for Runtime {} parameter_types! { pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE; + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE; + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; // `IdentityFee` is used by Millau => we may use weight directly pub const GetDeliveryConfirmationTransactionFee: Balance = bp_millau::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _; @@ -731,10 +731,6 @@ impl_runtime_apis! { let header = BridgeRialtoGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_rialto::Hash) -> bool { - BridgeRialtoGrandpa::is_known_header(hash) - } } impl bp_westend::WestendFinalityApi for Runtime { @@ -742,20 +738,18 @@ impl_runtime_apis! { let header = BridgeWestendGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_westend::Hash) -> bool { - BridgeWestendGrandpa::is_known_header(hash) - } } impl bp_rialto::ToRialtoOutboundLaneApi for Runtime { fn estimate_message_delivery_and_dispatch_fee( _lane_id: bp_messages::LaneId, payload: ToRialtoMessagePayload, + rialto_to_this_conversion_rate: Option, ) -> Option { estimate_message_dispatch_and_delivery_fee::( &payload, WithRialtoMessageBridge::RELAYER_FEE_PERCENT, + rialto_to_this_conversion_rate, ).ok() } @@ -774,10 +768,6 @@ impl_runtime_apis! { fn latest_received_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { BridgeRialtoMessages::outbound_latest_received_nonce(lane) } - - fn latest_generated_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { - BridgeRialtoMessages::outbound_latest_generated_nonce(lane) - } } impl bp_rialto::FromRialtoInboundLaneApi for Runtime { @@ -883,6 +873,7 @@ where #[cfg(test)] mod tests { use super::*; + use bp_runtime::Chain; use bridge_runtime_common::messages; #[test] @@ -899,36 +890,45 @@ mod tests { ); let max_incoming_message_proof_size = bp_rialto::EXTRA_STORAGE_PROOF_SIZE.saturating_add( - messages::target::maximal_incoming_message_size(bp_millau::max_extrinsic_size()), + messages::target::maximal_incoming_message_size(bp_millau::Millau::max_extrinsic_size()), ); pallet_bridge_messages::ensure_able_to_receive_message::( - bp_millau::max_extrinsic_size(), - bp_millau::max_extrinsic_weight(), + bp_millau::Millau::max_extrinsic_size(), + bp_millau::Millau::max_extrinsic_weight(), max_incoming_message_proof_size, messages::target::maximal_incoming_message_dispatch_weight( - bp_millau::max_extrinsic_weight(), + bp_millau::Millau::max_extrinsic_weight(), ), ); let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _, - bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE as _, + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, ) .unwrap_or(u32::MAX); pallet_bridge_messages::ensure_able_to_receive_confirmation::( - bp_millau::max_extrinsic_size(), - bp_millau::max_extrinsic_weight(), + bp_millau::Millau::max_extrinsic_size(), + bp_millau::Millau::max_extrinsic_weight(), max_incoming_inbound_lane_data_proof_size, - bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, DbWeight::get(), ); } #[test] fn call_size() { + const BRIDGES_PALLETS_MAX_CALL_SIZE: usize = 200; + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); const MAX_CALL_SIZE: usize = 230; // value from polkadot-runtime tests assert!(core::mem::size_of::() <= MAX_CALL_SIZE); } diff --git a/bin/millau/runtime/src/rialto_messages.rs b/bin/millau/runtime/src/rialto_messages.rs index 6d9677c45c..294b463084 100644 --- a/bin/millau/runtime/src/rialto_messages.rs +++ b/bin/millau/runtime/src/rialto_messages.rs @@ -23,7 +23,7 @@ use bp_messages::{ target_chain::{ProvedMessages, SourceHeaderChain}, InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; -use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; +use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; use codec::{Decode, Encode}; use frame_support::{ @@ -86,16 +86,19 @@ impl MessageBridge for WithRialtoMessageBridge { const RELAYER_FEE_PERCENT: u32 = 10; const THIS_CHAIN_ID: ChainId = MILLAU_CHAIN_ID; const BRIDGED_CHAIN_ID: ChainId = RIALTO_CHAIN_ID; - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME; + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; type ThisChain = Millau; type BridgedChain = Rialto; - fn bridged_balance_to_this_balance(bridged_balance: bp_rialto::Balance) -> bp_millau::Balance { - bp_millau::Balance::try_from( - RialtoToMillauConversionRate::get().saturating_mul_int(bridged_balance), - ) - .unwrap_or(bp_millau::Balance::MAX) + fn bridged_balance_to_this_balance( + bridged_balance: bp_rialto::Balance, + bridged_to_this_conversion_rate_override: Option, + ) -> bp_millau::Balance { + let conversion_rate = bridged_to_this_conversion_rate_override + .unwrap_or_else(|| RialtoToMillauConversionRate::get()); + bp_millau::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) + .unwrap_or(bp_millau::Balance::MAX) } } @@ -172,13 +175,13 @@ impl messages::ChainWithMessages for Rialto { impl messages::BridgedChainWithMessages for Rialto { fn maximal_extrinsic_size() -> u32 { - bp_rialto::max_extrinsic_size() + bp_rialto::Rialto::max_extrinsic_size() } fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive { // we don't want to relay too large messages + keep reserve for future upgrades let upper_limit = messages::target::maximal_incoming_message_dispatch_weight( - bp_rialto::max_extrinsic_weight(), + bp_rialto::Rialto::max_extrinsic_weight(), ); // we're charging for payload bytes in `WithRialtoMessageBridge::transaction_payment` diff --git a/bin/rialto-parachain/node/src/service.rs b/bin/rialto-parachain/node/src/service.rs index bd3afca307..54e626e0ea 100644 --- a/bin/rialto-parachain/node/src/service.rs +++ b/bin/rialto-parachain/node/src/service.rs @@ -14,6 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +//! Rialto parachain node service. +//! +//! The code is mostly copy of `polkadot-parachains/src/service.rs` file from Cumulus +//! repository with some parts removed. We have added two RPC extensions to the original +//! service: `pallet_transaction_payment_rpc::TransactionPaymentApi` and +//! `substrate_frame_rpc_system::SystemApi`. + // std use std::sync::Arc; @@ -212,7 +219,14 @@ where sc_client_api::StateBackendFor, Block>: sp_api::StateBackend, Executor: NativeExecutionDispatch + 'static, RB: Fn( + sc_rpc_api::DenyUnsafe, Arc>>, + Arc< + sc_transaction_pool::FullPool< + Block, + TFullClient>, + >, + >, ) -> jsonrpc_core::IoHandler + Send + 'static, @@ -288,7 +302,10 @@ where })?; let rpc_client = client.clone(); - let rpc_extensions_builder = Box::new(move |_, _| Ok(rpc_ext_builder(rpc_client.clone()))); + let rpc_transaction_pool = transaction_pool.clone(); + let rpc_extensions_builder = Box::new(move |deny_unsafe, _| { + Ok(rpc_ext_builder(deny_unsafe, rpc_client.clone(), rpc_transaction_pool.clone())) + }); sc_service::spawn_tasks(sc_service::SpawnTasksParams { rpc_extensions_builder, @@ -412,7 +429,19 @@ pub async fn start_node( parachain_config, polkadot_config, id, - |_| Default::default(), + |deny_unsafe, client, pool| { + use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; + use substrate_frame_rpc_system::{FullSystem, SystemApi}; + + let mut io = jsonrpc_core::IoHandler::default(); + io.extend_with(SystemApi::to_delegate(FullSystem::new( + client.clone(), + pool, + deny_unsafe, + ))); + io.extend_with(TransactionPaymentApi::to_delegate(TransactionPayment::new(client))); + io + }, parachain_build_import_queue, |client, prometheus_registry, diff --git a/bin/rialto/node/src/chain_spec.rs b/bin/rialto/node/src/chain_spec.rs index fb18a35a6a..527b5c051d 100644 --- a/bin/rialto/node/src/chain_spec.rs +++ b/bin/rialto/node/src/chain_spec.rs @@ -96,15 +96,7 @@ impl Alternative { testnet_genesis( vec![get_authority_keys_from_seed("Alice")], get_account_id_from_seed::("Alice"), - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Bob"), - )), - ], + endowed_accounts(), true, ) }, @@ -128,48 +120,7 @@ impl Alternative { get_authority_keys_from_seed("Eve"), ], get_account_id_from_seed::("Alice"), - vec![ - get_account_id_from_seed::("Alice"), - get_account_id_from_seed::("Bob"), - get_account_id_from_seed::("Charlie"), - get_account_id_from_seed::("Dave"), - get_account_id_from_seed::("Eve"), - get_account_id_from_seed::("Ferdie"), - get_account_id_from_seed::("George"), - get_account_id_from_seed::("Harry"), - get_account_id_from_seed::("Alice//stash"), - get_account_id_from_seed::("Bob//stash"), - get_account_id_from_seed::("Charlie//stash"), - get_account_id_from_seed::("Dave//stash"), - get_account_id_from_seed::("Eve//stash"), - get_account_id_from_seed::("Ferdie//stash"), - get_account_id_from_seed::("George//stash"), - get_account_id_from_seed::("Harry//stash"), - get_account_id_from_seed::("MillauMessagesOwner"), - get_account_id_from_seed::("WithMillauTokenSwap"), - 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::("Alice"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Bob"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Charlie"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Dave"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Eve"), - )), - derive_account_from_millau_id(bp_runtime::SourceAccount::Account( - get_account_id_from_seed::("Ferdie"), - )), - ], + endowed_accounts(), true, ) }, @@ -183,6 +134,55 @@ impl Alternative { } } +/// We're using the same set of endowed accounts on all Millau chains (dev/local) to make +/// sure that all accounts, required for bridge to be functional (e.g. relayers fund account, +/// accounts used by relayers in our test deployments, accounts used for demonstration +/// purposes), are all available on these chains. +fn endowed_accounts() -> Vec { + vec![ + get_account_id_from_seed::("Alice"), + get_account_id_from_seed::("Bob"), + get_account_id_from_seed::("Charlie"), + get_account_id_from_seed::("Dave"), + get_account_id_from_seed::("Eve"), + get_account_id_from_seed::("Ferdie"), + get_account_id_from_seed::("George"), + get_account_id_from_seed::("Harry"), + get_account_id_from_seed::("Alice//stash"), + get_account_id_from_seed::("Bob//stash"), + get_account_id_from_seed::("Charlie//stash"), + get_account_id_from_seed::("Dave//stash"), + get_account_id_from_seed::("Eve//stash"), + get_account_id_from_seed::("Ferdie//stash"), + get_account_id_from_seed::("George//stash"), + get_account_id_from_seed::("Harry//stash"), + get_account_id_from_seed::("MillauMessagesOwner"), + get_account_id_from_seed::("WithMillauTokenSwap"), + 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::("Alice"), + )), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Bob"), + )), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Charlie"), + )), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Dave"), + )), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Eve"), + )), + derive_account_from_millau_id(bp_runtime::SourceAccount::Account( + get_account_id_from_seed::("Ferdie"), + )), + ] +} + fn session_keys( babe: BabeId, beefy: BeefyId, diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index 0987184c73..e1e2b785b7 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -53,7 +53,7 @@ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{AccountIdLookup, Block as BlockT, Keccak256, NumberFor, OpaqueKeys}, transaction_validity::{TransactionSource, TransactionValidity}, - ApplyExtrinsicResult, FixedPointNumber, MultiSignature, MultiSigner, Perquintill, + ApplyExtrinsicResult, FixedPointNumber, FixedU128, MultiSignature, MultiSigner, Perquintill, }; use sp_std::{collections::btree_map::BTreeMap, prelude::*}; #[cfg(feature = "std")] @@ -434,9 +434,9 @@ impl pallet_shift_session_manager::Config for Runtime {} parameter_types! { pub const MaxMessagesToPruneAtOnce: bp_messages::MessageNonce = 8; pub const MaxUnrewardedRelayerEntriesAtInboundLane: bp_messages::MessageNonce = - bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE; + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; pub const MaxUnconfirmedMessagesAtInboundLane: bp_messages::MessageNonce = - bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE; + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; // `IdentityFee` is used by Rialto => we may use weight directly pub const GetDeliveryConfirmationTransactionFee: Balance = bp_rialto::MAX_SINGLE_MESSAGE_DELIVERY_CONFIRMATION_TX_WEIGHT as _; @@ -662,10 +662,6 @@ impl_runtime_apis! { let header = BridgeMillauGrandpa::best_finalized(); (header.number, header.hash()) } - - fn is_known_header(hash: bp_millau::Hash) -> bool { - BridgeMillauGrandpa::is_known_header(hash) - } } impl sp_transaction_pool::runtime_api::TaggedTransactionQueue for Runtime { @@ -896,10 +892,12 @@ impl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( _lane_id: bp_messages::LaneId, payload: ToMillauMessagePayload, + millau_to_this_conversion_rate: Option, ) -> Option { estimate_message_dispatch_and_delivery_fee::( &payload, WithMillauMessageBridge::RELAYER_FEE_PERCENT, + millau_to_this_conversion_rate, ).ok() } @@ -918,10 +916,6 @@ impl_runtime_apis! { fn latest_received_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { BridgeMillauMessages::outbound_latest_received_nonce(lane) } - - fn latest_generated_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { - BridgeMillauMessages::outbound_latest_generated_nonce(lane) - } } impl bp_millau::FromMillauInboundLaneApi for Runtime { @@ -1034,14 +1028,13 @@ impl_runtime_apis! { params: MessageProofParams, ) -> (millau_messages::FromMillauMessagesProof, Weight) { use crate::millau_messages::WithMillauMessageBridge; - use bp_messages::MessageKey; + use bp_messages::{MessageKey, storage_keys}; use bridge_runtime_common::{ messages::MessageBridge, messages_benchmarking::{ed25519_sign, prepare_message_proof}, }; use codec::Encode; use frame_support::weights::GetDispatchInfo; - use pallet_bridge_messages::storage_keys; use sp_runtime::traits::{Header, IdentifyAccount}; let remark = match params.size { @@ -1119,7 +1112,7 @@ impl_runtime_apis! { prepare_message_delivery_proof::( params, - |lane_id| pallet_bridge_messages::storage_keys::inbound_lane_data_key( + |lane_id| bp_messages::storage_keys::inbound_lane_data_key( ::BRIDGED_MESSAGES_PALLET_NAME, &lane_id, ).0, @@ -1187,6 +1180,7 @@ where #[cfg(test)] mod tests { use super::*; + use bp_runtime::Chain; use bridge_runtime_common::messages; #[test] @@ -1202,40 +1196,49 @@ mod tests { ); let max_incoming_message_proof_size = bp_millau::EXTRA_STORAGE_PROOF_SIZE.saturating_add( - messages::target::maximal_incoming_message_size(bp_rialto::max_extrinsic_size()), + messages::target::maximal_incoming_message_size(bp_rialto::Rialto::max_extrinsic_size()), ); pallet_bridge_messages::ensure_able_to_receive_message::( - bp_rialto::max_extrinsic_size(), - bp_rialto::max_extrinsic_weight(), + bp_rialto::Rialto::max_extrinsic_size(), + bp_rialto::Rialto::max_extrinsic_weight(), max_incoming_message_proof_size, messages::target::maximal_incoming_message_dispatch_weight( - bp_rialto::max_extrinsic_weight(), + bp_rialto::Rialto::max_extrinsic_weight(), ), ); let max_incoming_inbound_lane_data_proof_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, - bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE as _, - bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE as _, + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX as _, + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX as _, ) .unwrap_or(u32::MAX); pallet_bridge_messages::ensure_able_to_receive_confirmation::( - bp_rialto::max_extrinsic_size(), - bp_rialto::max_extrinsic_weight(), + bp_rialto::Rialto::max_extrinsic_size(), + bp_rialto::Rialto::max_extrinsic_weight(), max_incoming_inbound_lane_data_proof_size, - bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, DbWeight::get(), ); } #[test] fn call_size() { - const DOT_MAX_CALL_SZ: usize = 230; - assert!(core::mem::size_of::>() <= DOT_MAX_CALL_SZ); - // FIXME: get this down to 230. https://github.com/paritytech/grandpa-bridge-gadget/issues/359 - const BEEFY_MAX_CALL_SZ: usize = 232; - assert!(core::mem::size_of::>() <= BEEFY_MAX_CALL_SZ); + const BRIDGES_PALLETS_MAX_CALL_SIZE: usize = 200; + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + assert!( + core::mem::size_of::>() <= + BRIDGES_PALLETS_MAX_CALL_SIZE + ); + // Largest inner Call is `pallet_session::Call` with a size of 224 bytes. This size is a + // result of large `SessionKeys` struct. + // Total size of Rialto runtime Call is 232. + const MAX_CALL_SIZE: usize = 232; + assert!(core::mem::size_of::() <= MAX_CALL_SIZE); } } diff --git a/bin/rialto/runtime/src/millau_messages.rs b/bin/rialto/runtime/src/millau_messages.rs index 13a1c6b06e..c6c382b43d 100644 --- a/bin/rialto/runtime/src/millau_messages.rs +++ b/bin/rialto/runtime/src/millau_messages.rs @@ -23,7 +23,7 @@ use bp_messages::{ target_chain::{ProvedMessages, SourceHeaderChain}, InboundLaneData, LaneId, Message, MessageNonce, Parameter as MessagesParameter, }; -use bp_runtime::{ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; +use bp_runtime::{Chain, ChainId, MILLAU_CHAIN_ID, RIALTO_CHAIN_ID}; use bridge_runtime_common::messages::{self, MessageBridge, MessageTransaction}; use codec::{Decode, Encode}; use frame_support::{ @@ -86,16 +86,19 @@ impl MessageBridge for WithMillauMessageBridge { const RELAYER_FEE_PERCENT: u32 = 10; const THIS_CHAIN_ID: ChainId = RIALTO_CHAIN_ID; const BRIDGED_CHAIN_ID: ChainId = MILLAU_CHAIN_ID; - const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME; + const BRIDGED_MESSAGES_PALLET_NAME: &'static str = bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; type ThisChain = Rialto; type BridgedChain = Millau; - fn bridged_balance_to_this_balance(bridged_balance: bp_millau::Balance) -> bp_rialto::Balance { - bp_rialto::Balance::try_from( - MillauToRialtoConversionRate::get().saturating_mul_int(bridged_balance), - ) - .unwrap_or(bp_rialto::Balance::MAX) + fn bridged_balance_to_this_balance( + bridged_balance: bp_millau::Balance, + bridged_to_this_conversion_rate_override: Option, + ) -> bp_rialto::Balance { + let conversion_rate = bridged_to_this_conversion_rate_override + .unwrap_or_else(|| MillauToRialtoConversionRate::get()); + bp_rialto::Balance::try_from(conversion_rate.saturating_mul_int(bridged_balance)) + .unwrap_or(bp_rialto::Balance::MAX) } } @@ -170,13 +173,13 @@ impl messages::ChainWithMessages for Millau { impl messages::BridgedChainWithMessages for Millau { fn maximal_extrinsic_size() -> u32 { - bp_millau::max_extrinsic_size() + bp_millau::Millau::max_extrinsic_size() } fn message_weight_limits(_message_payload: &[u8]) -> RangeInclusive { // we don't want to relay too large messages + keep reserve for future upgrades let upper_limit = messages::target::maximal_incoming_message_dispatch_weight( - bp_millau::max_extrinsic_weight(), + bp_millau::Millau::max_extrinsic_weight(), ); // we're charging for payload bytes in `WithMillauMessageBridge::transaction_payment` diff --git a/bin/runtime-common/src/messages.rs b/bin/runtime-common/src/messages.rs index b34cbb8554..f88ed2f4af 100644 --- a/bin/runtime-common/src/messages.rs +++ b/bin/runtime-common/src/messages.rs @@ -70,6 +70,7 @@ pub trait MessageBridge { /// Convert Bridged chain balance into This chain balance. fn bridged_balance_to_this_balance( bridged_balance: BalanceOf>, + bridged_to_this_conversion_rate_override: Option, ) -> BalanceOf>; } @@ -316,8 +317,11 @@ pub mod source { pallet_bridge_dispatch::verify_message_origin(submitter, payload) .map_err(|_| BAD_ORIGIN)?; - let minimal_fee_in_this_tokens = - estimate_message_dispatch_and_delivery_fee::(payload, B::RELAYER_FEE_PERCENT)?; + let minimal_fee_in_this_tokens = estimate_message_dispatch_and_delivery_fee::( + payload, + B::RELAYER_FEE_PERCENT, + None, + )?; // compare with actual fee paid if *delivery_and_dispatch_fee < minimal_fee_in_this_tokens { @@ -371,6 +375,7 @@ pub mod source { pub fn estimate_message_dispatch_and_delivery_fee( payload: &FromThisChainMessagePayload, relayer_fee_percent: u32, + bridged_to_this_conversion_rate: Option, ) -> Result>, &'static str> { // the fee (in Bridged tokens) of all transactions that are made on the Bridged chain // @@ -391,8 +396,11 @@ pub mod source { ThisChain::::transaction_payment(confirmation_transaction); // minimal fee (in This tokens) is a sum of all required fees - let minimal_fee = B::bridged_balance_to_this_balance(delivery_transaction_fee) - .checked_add(&confirmation_transaction_fee); + let minimal_fee = B::bridged_balance_to_this_balance( + delivery_transaction_fee, + bridged_to_this_conversion_rate, + ) + .checked_add(&confirmation_transaction_fee); // before returning, add extra fee that is paid to the relayer (relayer interest) minimal_fee @@ -428,7 +436,7 @@ pub mod source { // Messages delivery proof is just proof of single storage key read => any error // is fatal. let storage_inbound_lane_data_key = - pallet_bridge_messages::storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane); + bp_messages::storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, &lane); let raw_inbound_lane_data = storage .read_value(storage_inbound_lane_data_key.0.as_ref()) .map_err(|_| "Failed to read inbound lane state from storage proof")? @@ -674,16 +682,15 @@ pub mod target { B: MessageBridge, { fn read_raw_outbound_lane_data(&self, lane_id: &LaneId) -> Option> { - let storage_outbound_lane_data_key = - pallet_bridge_messages::storage_keys::outbound_lane_data_key( - B::BRIDGED_MESSAGES_PALLET_NAME, - lane_id, - ); + let storage_outbound_lane_data_key = bp_messages::storage_keys::outbound_lane_data_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + lane_id, + ); self.storage.read_value(storage_outbound_lane_data_key.0.as_ref()).ok()? } fn read_raw_message(&self, message_key: &MessageKey) -> Option> { - let storage_message_key = pallet_bridge_messages::storage_keys::message_key( + let storage_message_key = bp_messages::storage_keys::message_key( B::BRIDGED_MESSAGES_PALLET_NAME, &message_key.lane_id, message_key.nonce, @@ -799,8 +806,12 @@ mod tests { fn bridged_balance_to_this_balance( bridged_balance: BridgedChainBalance, + bridged_to_this_conversion_rate_override: Option, ) -> ThisChainBalance { - ThisChainBalance(bridged_balance.0 * BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE as u32) + let conversion_rate = bridged_to_this_conversion_rate_override + .map(|r| r.to_float() as u32) + .unwrap_or(BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE); + ThisChainBalance(bridged_balance.0 * conversion_rate) } } @@ -818,7 +829,10 @@ mod tests { type ThisChain = BridgedChain; type BridgedChain = ThisChain; - fn bridged_balance_to_this_balance(_this_balance: ThisChainBalance) -> BridgedChainBalance { + fn bridged_balance_to_this_balance( + _this_balance: ThisChainBalance, + _bridged_to_this_conversion_rate_override: Option, + ) -> BridgedChainBalance { unreachable!() } } @@ -1096,6 +1110,7 @@ mod tests { source::estimate_message_dispatch_and_delivery_fee::( &payload, OnThisChainBridge::RELAYER_FEE_PERCENT, + None, ), Ok(ThisChainBalance(EXPECTED_MINIMAL_FEE)), ); @@ -1107,6 +1122,7 @@ mod tests { source::estimate_message_dispatch_and_delivery_fee::( &payload_with_pay_on_target, OnThisChainBridge::RELAYER_FEE_PERCENT, + None, ) .expect( "estimate_message_dispatch_and_delivery_fee failed for pay-at-target-chain message", @@ -1573,4 +1589,21 @@ mod tests { 100 + 50 * 10 + 777, ); } + + #[test] + fn conversion_rate_override_works() { + let payload = regular_outbound_message_payload(); + let regular_fee = source::estimate_message_dispatch_and_delivery_fee::( + &payload, + OnThisChainBridge::RELAYER_FEE_PERCENT, + None, + ); + let overrided_fee = source::estimate_message_dispatch_and_delivery_fee::( + &payload, + OnThisChainBridge::RELAYER_FEE_PERCENT, + Some(FixedU128::from_float((BRIDGED_CHAIN_TO_THIS_CHAIN_BALANCE_RATE * 2) as f64)), + ); + + assert!(regular_fee < overrided_fee); + } } diff --git a/deployments/bridges/rialto-millau/docker-compose.yml b/deployments/bridges/rialto-millau/docker-compose.yml index 1ff93869de..5d774a5780 100644 --- a/deployments/bridges/rialto-millau/docker-compose.yml +++ b/deployments/bridges/rialto-millau/docker-compose.yml @@ -108,6 +108,7 @@ services: LETSENCRYPT_EMAIL: admin@parity.io volumes: - ./bridges/rialto-millau/dashboard/grafana:/etc/grafana/dashboards/rialto-millau:ro + - ./networks/dashboard/grafana/beefy-dashboard.json:/etc/grafana/dashboards/beefy.json prometheus-metrics: volumes: diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh index 758dce2515..743cc47f07 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-millau-to-rialto-entrypoint.sh @@ -1,9 +1,7 @@ #!/bin/bash set -xeu -sleep 60 -curl -v http://millau-node-bob:9933/health -curl -v http://rialto-node-bob:9933/health +sleep 15 MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh index e0731e9058..2b536dbd81 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-rialto-to-millau-entrypoint.sh @@ -1,9 +1,7 @@ #!/bin/bash set -xeu -sleep 60 -curl -v http://millau-node-bob:9933/health -curl -v http://rialto-node-bob:9933/health +sleep 15 MESSAGE_LANE=${MSG_EXCHANGE_GEN_LANE:-00000000} diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh index b8d051a131..9cae01fc0c 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-millau-generator-entrypoint.sh @@ -36,7 +36,7 @@ BUNCH_OF_MESSAGES_TIME=3600 # give conversion rate updater some time to update Millau->Rialto conversion rate in Rialto # (initially rate=1 and rational relayer won't deliver any messages if it'll be changed to larger value) -sleep 180 +sleep 120 while true do diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh index 0365ebe1d8..ed733411f3 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-generator-entrypoint.sh @@ -36,7 +36,7 @@ BUNCH_OF_MESSAGES_TIME=3600 # give conversion rate updater some time to update Rialto->Millau conversion rate in Millau # (initially rate=1 and rational relayer won't deliver any messages if it'll be changed to larger value) -sleep 180 +sleep 120 while true do diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh index ca4c9f03a8..068560e150 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-messages-to-rialto-resubmitter-entrypoint.sh @@ -1,8 +1,7 @@ #!/bin/bash set -xeu -sleep 20 -curl -v http://millau-node-alice:9933/health +sleep 15 # //Dave is signing Millau -> Rialto message-send transactions, which are causing problems. # diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh index c87591fb6d..bab0e1c4af 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-millau-rialto-entrypoint.sh @@ -1,9 +1,7 @@ #!/bin/bash set -xeu -sleep 60 -curl -v http://millau-node-alice:9933/health -curl -v http://rialto-node-alice:9933/health +sleep 15 /home/user/substrate-relay init-bridge millau-to-rialto \ --source-host millau-node-alice \ @@ -27,10 +25,12 @@ sleep 6 --millau-port 9944 \ --millau-signer //Charlie \ --millau-messages-pallet-owner=//RialtoMessagesOwner \ + --millau-transactions-mortality=64 \ --rialto-host rialto-node-alice \ --rialto-port 9944 \ --rialto-signer //Charlie \ --rialto-messages-pallet-owner=//MillauMessagesOwner \ + --rialto-transactions-mortality=64 \ --lane=00000000 \ --lane=73776170 \ --prometheus-host=0.0.0.0 diff --git a/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh b/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh index 95bbe1e38f..b773d61595 100755 --- a/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh +++ b/deployments/bridges/rialto-millau/entrypoints/relay-token-swap-generator-entrypoint.sh @@ -25,7 +25,7 @@ rand_sleep() { # give conversion rate updater some time to update Rialto->Millau conversion rate in Millau # (initially rate=1 and rational relayer won't deliver any messages if it'll be changed to larger value) -sleep 180 +sleep 120 while true do diff --git a/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh index d3b6932983..f37ee69915 100755 --- a/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh +++ b/deployments/bridges/westend-millau/entrypoints/relay-headers-westend-to-millau-entrypoint.sh @@ -1,9 +1,7 @@ #!/bin/bash set -xeu -sleep 60 -curl -v http://millau-node-alice:9933/health -curl -v https://westend-rpc.polkadot.io:443/health +sleep 15 /home/user/substrate-relay init-bridge westend-to-millau \ --source-host westend-rpc.polkadot.io \ diff --git a/deployments/local-scripts/relay-messages-millau-to-rialto.sh b/deployments/local-scripts/relay-messages-millau-to-rialto.sh index d420dc56c2..36673d31be 100755 --- a/deployments/local-scripts/relay-messages-millau-to-rialto.sh +++ b/deployments/local-scripts/relay-messages-millau-to-rialto.sh @@ -10,6 +10,7 @@ RIALTO_PORT="${RIALTO_PORT:-9944}" RUST_LOG=bridge=debug \ ./target/debug/substrate-relay relay-messages millau-to-rialto \ + --relayer-mode=altruistic \ --lane 00000000 \ --source-host localhost \ --source-port $MILLAU_PORT \ diff --git a/deployments/local-scripts/relay-messages-rialto-to-millau.sh b/deployments/local-scripts/relay-messages-rialto-to-millau.sh index 0cd73c0045..89e2b81824 100755 --- a/deployments/local-scripts/relay-messages-rialto-to-millau.sh +++ b/deployments/local-scripts/relay-messages-rialto-to-millau.sh @@ -10,6 +10,7 @@ RIALTO_PORT="${RIALTO_PORT:-9944}" RUST_LOG=bridge=debug \ ./target/debug/substrate-relay relay-messages rialto-to-millau \ + --relayer-mode=altruistic \ --lane 00000000 \ --source-host localhost \ --source-port $RIALTO_PORT \ diff --git a/deployments/local-scripts/relay-millau-to-rialto.sh b/deployments/local-scripts/relay-millau-to-rialto.sh index 8b18cff2b5..35d88d1a64 100755 --- a/deployments/local-scripts/relay-millau-to-rialto.sh +++ b/deployments/local-scripts/relay-millau-to-rialto.sh @@ -15,6 +15,8 @@ RUST_LOG=bridge=debug \ --target-host localhost \ --target-port $RIALTO_PORT \ --target-signer //Alice \ + --source-version-mode Bundle \ + --target-version-mode Bundle sleep 5 RUST_LOG=bridge=debug \ diff --git a/deployments/networks/dashboard/grafana/beefy-dashboard.json b/deployments/networks/dashboard/grafana/beefy-dashboard.json new file mode 100644 index 0000000000..4a4de45628 --- /dev/null +++ b/deployments/networks/dashboard/grafana/beefy-dashboard.json @@ -0,0 +1,585 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "C", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 1 + ], + "type": "lt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "D", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Beefy best blocks not advancing", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 14, + "w": 12, + "x": 0, + "y": 0 + }, + "hiddenSeries": false, + "id": 2, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "polkadot_beefy_best_block", + "legendFormat": "Rialto(Charlie)", + "refId": "A" + }, + { + "expr": "substrate_beefy_best_block", + "legendFormat": "Millau(Charlie)", + "refId": "B" + }, + { + "expr": "max_over_time(substrate_beefy_best_block[5m]) - min_over_time(substrate_beefy_best_block[5m])", + "hide": true, + "legendFormat": "Millau Best Beefy blocks count in last 5 minutes", + "refId": "C" + }, + { + "expr": "max_over_time(polkadot_beefy_best_block[5m]) - min_over_time(polkadot_beefy_best_block[5m])", + "hide": true, + "legendFormat": "Rialto Best Beefy blocks count in last 5 minutes", + "refId": "D" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "lt", + "value": 1 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Best block", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {}, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "yellow", + "value": null + }, + { + "color": "yellow", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 11, + "x": 12, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "mean" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.3", + "targets": [ + { + "expr": "polkadot_beefy_should_vote_on", + "legendFormat": "Rialto(Charlie) Should-Vote-On", + "refId": "C" + }, + { + "expr": "polkadot_beefy_round_concluded", + "legendFormat": "Rialto(Charlie) Round-Concluded", + "refId": "A" + }, + { + "expr": "substrate_beefy_should_vote_on", + "legendFormat": "Millau(Charlie) Should-Vote-On", + "refId": "D" + }, + { + "expr": "substrate_beefy_round_concluded", + "legendFormat": "Millau(Charlie) Round-Concluded", + "refId": "B" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Beefy Voting Rounds", + "type": "stat" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 18, + "x": 0, + "y": 14 + }, + "hiddenSeries": false, + "id": 6, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "polkadot_beefy_votes_sent", + "legendFormat": "Rialto (node Charlie)", + "refId": "A" + }, + { + "expr": "substrate_beefy_votes_sent", + "legendFormat": "Millau (node Charlie)", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Votes Sent", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + }, + { + "alert": { + "alertRuleTags": {}, + "conditions": [ + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "and" + }, + "query": { + "params": [ + "A", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + }, + { + "evaluator": { + "params": [ + 0 + ], + "type": "gt" + }, + "operator": { + "type": "or" + }, + "query": { + "params": [ + "B", + "5m", + "now" + ] + }, + "reducer": { + "params": [], + "type": "max" + }, + "type": "query" + } + ], + "executionErrorState": "alerting", + "for": "5m", + "frequency": "1m", + "handler": 1, + "name": "Beefy Skipped Sessions alert", + "noDataState": "no_data", + "notifications": [] + }, + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 1 + } + ] + } + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 5, + "x": 18, + "y": 14 + }, + "hiddenSeries": false, + "id": 8, + "legend": { + "avg": false, + "current": false, + "max": false, + "min": false, + "show": true, + "total": false, + "values": false + }, + "lines": true, + "linewidth": 1, + "nullPointMode": "null", + "percentage": false, + "pluginVersion": "7.1.3", + "pointradius": 2, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "expr": "polkadot_beefy_skipped_sessions", + "legendFormat": "Rialto(Charlie)", + "refId": "A" + }, + { + "expr": "substrate_beefy_skipped_sessions", + "legendFormat": "Millau(Charlie)", + "refId": "B" + } + ], + "thresholds": [ + { + "colorMode": "critical", + "fill": true, + "line": true, + "op": "gt", + "value": 0 + } + ], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Beefy Skipped Sessions", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ], + "yaxis": { + "align": false, + "alignLevel": null + } + } + ], + "refresh": "5s", + "schemaVersion": 26, + "style": "dark", + "tags": [], + "templating": { + "list": [] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "Beefy", + "uid": "j6cRDRh7z", + "version": 1 +} diff --git a/deployments/networks/dashboard/prometheus/millau-targets.yml b/deployments/networks/dashboard/prometheus/millau-targets.yml new file mode 100644 index 0000000000..c7a0650927 --- /dev/null +++ b/deployments/networks/dashboard/prometheus/millau-targets.yml @@ -0,0 +1,2 @@ +- targets: + - millau-node-charlie:9615 diff --git a/deployments/networks/dashboard/prometheus/rialto-targets.yml b/deployments/networks/dashboard/prometheus/rialto-targets.yml new file mode 100644 index 0000000000..9de26b9a2d --- /dev/null +++ b/deployments/networks/dashboard/prometheus/rialto-targets.yml @@ -0,0 +1,2 @@ +- targets: + - rialto-node-charlie:9615 diff --git a/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh index 172502327c..519ab228e9 100755 --- a/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh +++ b/deployments/networks/entrypoints/rialto-parachain-registrar-entrypoint.sh @@ -1,9 +1,7 @@ #!/bin/bash set -xeu -sleep 60 -curl -v http://rialto-node-alice:9933/health -curl -v http://rialto-parachain-collator-alice:9933/health +sleep 15 /home/user/substrate-relay register-parachain rialto-parachain \ --parachain-host rialto-parachain-collator-alice \ diff --git a/deployments/networks/millau.yml b/deployments/networks/millau.yml index d42c1d7d07..13ac8d4877 100644 --- a/deployments/networks/millau.yml +++ b/deployments/networks/millau.yml @@ -17,6 +17,7 @@ services: - --alice - --node-key=0f900c89f4e626f4a217302ab8c7d213737d00627115f318ad6fb169717ac8e0 - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external environment: @@ -35,6 +36,7 @@ services: - --bob - --node-key=db383639ff2905d79f8e936fd5dc4416ef46b514b2f83823ec3c42753d7557bb - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: @@ -50,11 +52,14 @@ services: - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H - --charlie - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "20133:9933" - "20144:9944" + - "20615:9615" millau-node-dave: <<: *millau-bridge-node @@ -65,6 +70,7 @@ services: - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H - --dave - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: @@ -80,8 +86,16 @@ services: - --bootnodes=/dns4/millau-node-alice/tcp/30333/p2p/12D3KooWFqiV73ipQ1jpfVmCfLqBCp8G9PLH3zPkY9EhmdrSGA4H - --eve - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: - "20333:9933" - "20344:9944" + + # Note: These are being overridden from the top level `monitoring` compose file. + prometheus-metrics: + volumes: + - ./networks/dashboard/prometheus/millau-targets.yml:/etc/prometheus/targets-millau-nodes.yml + depends_on: + - millau-node-charlie diff --git a/deployments/networks/rialto.yml b/deployments/networks/rialto.yml index 0a484b2dad..40e881a37c 100644 --- a/deployments/networks/rialto.yml +++ b/deployments/networks/rialto.yml @@ -17,6 +17,7 @@ services: - --alice - --node-key=79cf382988364291a7968ae7825c01f68c50d679796a8983237d07fe0ccf363b - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external environment: @@ -35,6 +36,7 @@ services: - --bob - --node-key=4f9d0146dd9b7b3bf5a8089e3880023d1df92057f89e96e07bb4d8c2ead75bbd - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: @@ -50,11 +52,14 @@ services: - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE - --charlie - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external + - --prometheus-external ports: - "10133:9933" - "10144:9944" + - "10615:9615" rialto-node-dave: <<: *rialto-bridge-node @@ -65,6 +70,7 @@ services: - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE - --dave - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: @@ -80,6 +86,7 @@ services: - --bootnodes=/dns4/rialto-node-alice/tcp/30333/p2p/12D3KooWMF6JvV319a7kJn5pqkKbhR3fcM2cvK5vCbYZHeQhYzFE - --eve - --rpc-cors=all + - --enable-offchain-indexing=true - --unsafe-rpc-external - --unsafe-ws-external ports: @@ -93,6 +100,13 @@ services: - ./networks/entrypoints:/entrypoints - rialto-share:/rialto-share:z + # Note: These are being overridden from the top level `monitoring` compose file. + prometheus-metrics: + volumes: + - ./networks/dashboard/prometheus/rialto-targets.yml:/etc/prometheus/targets-rialto-nodes.yml + depends_on: + - rialto-node-charlie + # we're using `/rialto-share` to expose Rialto chain spec to those who are interested. Right # now it is Rialto Parachain collator nodes. Local + tmpfs combination allows sharing writable # in-memory volumes, which are dropped when containers are stopped. diff --git a/modules/grandpa/src/mock.rs b/modules/grandpa/src/mock.rs index f8b5e26932..37d93df779 100644 --- a/modules/grandpa/src/mock.rs +++ b/modules/grandpa/src/mock.rs @@ -106,6 +106,13 @@ impl Chain for TestBridgedChain { type Balance = u64; type Index = u64; type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + fn max_extrinsic_weight() -> Weight { + unreachable!() + } } pub fn run_test(test: impl FnOnce() -> T) -> T { diff --git a/modules/messages/Cargo.toml b/modules/messages/Cargo.toml index 6d52b899ea..47fb4323bc 100644 --- a/modules/messages/Cargo.toml +++ b/modules/messages/Cargo.toml @@ -30,8 +30,6 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } [dev-dependencies] -hex = "0.4" -hex-literal = "0.3" sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/modules/messages/src/lib.rs b/modules/messages/src/lib.rs index 119869d81e..20b5570794 100644 --- a/modules/messages/src/lib.rs +++ b/modules/messages/src/lib.rs @@ -801,32 +801,6 @@ pub mod pallet { } } -/// Getting storage keys for messages and lanes states. These keys are normally used when building -/// messages and lanes states proofs. -pub mod storage_keys { - use super::*; - use sp_core::storage::StorageKey; - - /// Storage key of the outbound message in the runtime storage. - pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { - bp_runtime::storage_map_final_key_blake2_128concat( - pallet_prefix, - "OutboundMessages", - &MessageKey { lane_id: *lane, nonce }.encode(), - ) - } - - /// Storage key of the outbound message lane state in the runtime storage. - pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { - bp_runtime::storage_map_final_key_blake2_128concat(pallet_prefix, "OutboundLanes", lane) - } - - /// Storage key of the inbound message lane state in the runtime storage. - pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { - bp_runtime::storage_map_final_key_blake2_128concat(pallet_prefix, "InboundLanes", lane) - } -} - /// AccountId of the shared relayer fund account. /// /// This account is passed to `MessageDeliveryAndDispatchPayment` trait, and depending @@ -1159,9 +1133,8 @@ mod tests { REGULAR_PAYLOAD, TEST_LANE_ID, TEST_RELAYER_A, TEST_RELAYER_B, }; use bp_messages::{UnrewardedRelayer, UnrewardedRelayersState}; - use frame_support::{assert_noop, assert_ok, weights::Weight}; + use frame_support::{assert_noop, assert_ok, storage::generator::StorageMap, weights::Weight}; use frame_system::{EventRecord, Pallet as System, Phase}; - use hex_literal::hex; use sp_runtime::DispatchError; fn get_ready_for_events() { @@ -1889,45 +1862,6 @@ mod tests { }); } - #[test] - fn storage_message_key_computed_properly() { - // If this test fails, then something has been changed in module storage that is breaking - // all previously crafted messages proofs. - let storage_key = storage_keys::message_key("BridgeMessages", &*b"test", 42).0; - assert_eq!( - storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), - "Unexpected storage key: {}", - hex::encode(&storage_key), - ); - } - - #[test] - fn outbound_lane_data_key_computed_properly() { - // If this test fails, then something has been changed in module storage that is breaking - // all previously crafted outbound lane state proofs. - let storage_key = storage_keys::outbound_lane_data_key("BridgeMessages", &*b"test").0; - assert_eq!( - storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), - "Unexpected storage key: {}", - hex::encode(&storage_key), - ); - } - - #[test] - fn inbound_lane_data_key_computed_properly() { - // If this test fails, then something has been changed in module storage that is breaking - // all previously crafted inbound lane state proofs. - let storage_key = storage_keys::inbound_lane_data_key("BridgeMessages", &*b"test").0; - assert_eq!( - storage_key, - hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), - "Unexpected storage key: {}", - hex::encode(&storage_key), - ); - } - #[test] fn actual_dispatch_weight_does_not_overlow() { run_test(|| { @@ -2359,4 +2293,25 @@ mod tests { ); }); } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + OutboundMessages::::storage_map_final_key(MessageKey { + lane_id: TEST_LANE_ID, + nonce: 42 + }), + bp_messages::storage_keys::message_key("Messages", &TEST_LANE_ID, 42).0, + ); + + assert_eq!( + OutboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::outbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); + + assert_eq!( + InboundLanes::::storage_map_final_key(TEST_LANE_ID), + bp_messages::storage_keys::inbound_lane_data_key("Messages", &TEST_LANE_ID).0, + ); + } } diff --git a/modules/token-swap/src/lib.rs b/modules/token-swap/src/lib.rs index 43fa13ba4b..59db89b6fd 100644 --- a/modules/token-swap/src/lib.rs +++ b/modules/token-swap/src/lib.rs @@ -95,9 +95,6 @@ pub mod weights_ext; pub use pallet::*; -/// Name of the `PendingSwaps` storage map. -pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps"; - // comes from #[pallet::event] #[allow(clippy::unused_unit)] #[frame_support::pallet] @@ -639,7 +636,7 @@ pub mod pallet { mod tests { use super::*; use crate::mock::*; - use frame_support::{assert_noop, assert_ok}; + use frame_support::{assert_noop, assert_ok, storage::generator::StorageMap}; const CAN_START_BLOCK_NUMBER: u64 = 10; const CAN_CLAIM_BLOCK_NUMBER: u64 = CAN_START_BLOCK_NUMBER + 1; @@ -1130,4 +1127,12 @@ mod tests { ); }); } + + #[test] + fn storage_keys_computed_properly() { + assert_eq!( + PendingSwaps::::storage_map_final_key(test_swap_hash()), + bp_token_swap::storage_keys::pending_swaps_key("TokenSwap", test_swap_hash()).0, + ); + } } diff --git a/modules/token-swap/src/mock.rs b/modules/token-swap/src/mock.rs index 63edb323e1..2c24e282af 100644 --- a/modules/token-swap/src/mock.rs +++ b/modules/token-swap/src/mock.rs @@ -142,6 +142,13 @@ impl bp_runtime::Chain for BridgedChain { type Balance = BridgedBalance; type Index = u64; type Signature = BridgedAccountSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + fn max_extrinsic_weight() -> Weight { + unreachable!() + } } pub struct TestMessagesBridge; diff --git a/primitives/chain-kusama/Cargo.toml b/primitives/chain-kusama/Cargo.toml index 6ff860357c..8d2f0e98a0 100644 --- a/primitives/chain-kusama/Cargo.toml +++ b/primitives/chain-kusama/Cargo.toml @@ -19,6 +19,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-runtime = { 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 } @@ -30,6 +31,7 @@ std = [ "bp-runtime/std", "frame-support/std", "sp-api/std", + "sp-runtime/std", "sp-std/std", "sp-version/std", ] diff --git a/primitives/chain-kusama/src/lib.rs b/primitives/chain-kusama/src/lib.rs index 9a6eb66d22..fc09bfcb8e 100644 --- a/primitives/chain-kusama/src/lib.rs +++ b/primitives/chain-kusama/src/lib.rs @@ -24,6 +24,7 @@ use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState} use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; +use sp_runtime::FixedU128; use sp_std::prelude::*; use sp_version::RuntimeVersion; @@ -81,8 +82,8 @@ pub const EXISTENTIAL_DEPOSIT: Balance = 1_000_000_000_000 / 30_000; /// conditions. pub const SESSION_LENGTH: BlockNumber = 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 With-Kusama messages pallet instance that is deployed at bridged chains. +pub const WITH_KUSAMA_MESSAGES_PALLET_NAME: &str = "BridgeKusamaMessages"; /// Name of the DOT->KSM conversion rate stored in the Kusama runtime. pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = @@ -90,8 +91,6 @@ pub const POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME: &str = /// 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. -pub const IS_KNOWN_KUSAMA_HEADER_METHOD: &str = "KusamaFinalityApi_is_known_header"; /// Name of the `ToKusamaOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -99,9 +98,6 @@ pub const TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD: &str = "ToKusamaOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToKusamaOutboundLaneApi::message_details` runtime method. pub const TO_KUSAMA_MESSAGE_DETAILS_METHOD: &str = "ToKusamaOutboundLaneApi_message_details"; -/// Name of the `ToKusamaOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_KUSAMA_LATEST_GENERATED_NONCE_METHOD: &str = - "ToKusamaOutboundLaneApi_latest_generated_nonce"; /// Name of the `ToKusamaOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD: &str = "ToKusamaOutboundLaneApi_latest_received_nonce"; @@ -124,8 +120,6 @@ sp_api::decl_runtime_apis! { pub trait KusamaFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Kusama chain. @@ -145,6 +139,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + kusama_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -158,8 +153,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Kusama chain. diff --git a/primitives/chain-millau/src/lib.rs b/primitives/chain-millau/src/lib.rs index 0092f7092b..df212509ad 100644 --- a/primitives/chain-millau/src/lib.rs +++ b/primitives/chain-millau/src/lib.rs @@ -33,7 +33,7 @@ use scale_info::TypeInfo; use sp_core::Hasher as HasherT; use sp_runtime::{ traits::{Convert, IdentifyAccount, Verify}, - MultiSignature, MultiSigner, Perbill, + FixedU128, MultiSignature, MultiSigner, Perbill, }; use sp_std::prelude::*; use sp_trie::{trie_types::Layout, TrieConfiguration}; @@ -68,11 +68,11 @@ pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// Represents the portion of a block that will be used by Normal extrinsics. pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// Maximal number of unrewarded relayer entries at inbound lane. -pub const MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE: MessageNonce = 1024; +/// Maximal number of unrewarded relayer entries in Millau confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128; -/// Maximal number of unconfirmed messages at inbound lane. -pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 1024; +/// Maximal number of unconfirmed messages in Millau confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 128; /// Weight of single regular message delivery transaction on Millau chain. /// @@ -172,6 +172,17 @@ impl Chain for Millau { type Balance = Balance; type Index = Index; type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) + } + + fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) + } } /// Millau Hasher (Blake2-256 ++ Keccak-256) implementation. @@ -246,21 +257,12 @@ frame_support::parameter_types! { .build_or_panic(); } -/// Get the maximum weight (compute time) that a Normal extrinsic on the Millau chain can use. -pub fn max_extrinsic_weight() -> Weight { - BlockWeights::get() - .get(DispatchClass::Normal) - .max_extrinsic - .unwrap_or(Weight::MAX) -} +/// Name of the With-Millau messages pallet instance that is deployed at bridged chains. +pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages"; -/// Get the maximum length in bytes that a Normal extrinsic on the Millau chain requires. -pub fn max_extrinsic_size() -> u32 { - *BlockLength::get().max.get(DispatchClass::Normal) -} +/// Name of the Rialto->Millau (actually DOT->KSM) conversion rate stored in the Millau runtime. +pub const RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME: &str = "RialtoToMillauConversionRate"; -/// Name of the With-Rialto messages pallet instance in the Millau runtime. -pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages"; /// Name of the With-Rialto token swap pallet instance in the Millau runtime. pub const WITH_RIALTO_TOKEN_SWAP_PALLET_NAME: &str = "BridgeRialtoTokenSwap"; @@ -276,9 +278,6 @@ pub const TO_MILLAU_MESSAGE_DETAILS_METHOD: &str = "ToMillauOutboundLaneApi_mess /// Name of the `ToMillauOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str = "ToMillauOutboundLaneApi_latest_received_nonce"; -/// Name of the `ToMillauOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_MILLAU_LATEST_GENERATED_NONCE_METHOD: &str = - "ToMillauOutboundLaneApi_latest_generated_nonce"; /// Name of the `FromMillauInboundLaneApi::latest_received_nonce` runtime method. pub const FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD: &str = @@ -298,8 +297,6 @@ sp_api::decl_runtime_apis! { pub trait MillauFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Millau chain. @@ -319,6 +316,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + millau_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -332,8 +330,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Millau chain. diff --git a/primitives/chain-polkadot/Cargo.toml b/primitives/chain-polkadot/Cargo.toml index 917c7f9747..710ed55e68 100644 --- a/primitives/chain-polkadot/Cargo.toml +++ b/primitives/chain-polkadot/Cargo.toml @@ -19,6 +19,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-runtime = { 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 } @@ -30,6 +31,7 @@ std = [ "bp-runtime/std", "frame-support/std", "sp-api/std", + "sp-runtime/std", "sp-std/std", "sp-version/std", ] diff --git a/primitives/chain-polkadot/src/lib.rs b/primitives/chain-polkadot/src/lib.rs index 26bad1ea86..51a4966534 100644 --- a/primitives/chain-polkadot/src/lib.rs +++ b/primitives/chain-polkadot/src/lib.rs @@ -24,6 +24,7 @@ use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState} use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; +use sp_runtime::FixedU128; use sp_std::prelude::*; use sp_version::RuntimeVersion; @@ -81,8 +82,8 @@ pub const EXISTENTIAL_DEPOSIT: Balance = 10_000_000_000; /// 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 With-Polkadot messages pallet instance that is deployed at bridged chains. +pub const WITH_POLKADOT_MESSAGES_PALLET_NAME: &str = "BridgePolkadotMessages"; /// Name of the KSM->DOT conversion rate stored in the Polkadot runtime. pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = @@ -90,8 +91,6 @@ pub const KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME: &str = /// 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. -pub const IS_KNOWN_POLKADOT_HEADER_METHOD: &str = "PolkadotFinalityApi_is_known_header"; /// Name of the `ToPolkadotOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -99,9 +98,6 @@ pub const TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD: &str = "ToPolkadotOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToPolkadotOutboundLaneApi::message_details` runtime method. pub const TO_POLKADOT_MESSAGE_DETAILS_METHOD: &str = "ToPolkadotOutboundLaneApi_message_details"; -/// Name of the `ToPolkadotOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_POLKADOT_LATEST_GENERATED_NONCE_METHOD: &str = - "ToPolkadotOutboundLaneApi_latest_generated_nonce"; /// Name of the `ToPolkadotOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD: &str = "ToPolkadotOutboundLaneApi_latest_received_nonce"; @@ -124,8 +120,6 @@ sp_api::decl_runtime_apis! { pub trait PolkadotFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Polkadot chain. @@ -145,6 +139,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + polkadot_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -158,8 +153,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Polkadot chain. diff --git a/primitives/chain-rialto-parachain/src/lib.rs b/primitives/chain-rialto-parachain/src/lib.rs index 826f6d39bd..786226cf93 100644 --- a/primitives/chain-rialto-parachain/src/lib.rs +++ b/primitives/chain-rialto-parachain/src/lib.rs @@ -92,6 +92,17 @@ impl Chain for RialtoParachain { type Balance = Balance; type Index = Index; type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) + } + + fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) + } } frame_support::parameter_types! { @@ -113,16 +124,3 @@ frame_support::parameter_types! { .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO) .build_or_panic(); } - -/// Get the maximum weight (compute time) that a Normal extrinsic on the Millau chain can use. -pub fn max_extrinsic_weight() -> Weight { - BlockWeights::get() - .get(DispatchClass::Normal) - .max_extrinsic - .unwrap_or(Weight::MAX) -} - -/// Get the maximum length in bytes that a Normal extrinsic on the Millau chain requires. -pub fn max_extrinsic_size() -> u32 { - *BlockLength::get().max.get(DispatchClass::Normal) -} diff --git a/primitives/chain-rialto/src/lib.rs b/primitives/chain-rialto/src/lib.rs index 6c4e48301e..39310a48ef 100644 --- a/primitives/chain-rialto/src/lib.rs +++ b/primitives/chain-rialto/src/lib.rs @@ -30,7 +30,7 @@ use frame_system::limits; use sp_core::Hasher as HasherT; use sp_runtime::{ traits::{BlakeTwo256, Convert, IdentifyAccount, Verify}, - MultiSignature, MultiSigner, Perbill, + FixedU128, MultiSignature, MultiSigner, Perbill, }; use sp_std::prelude::*; @@ -59,11 +59,11 @@ pub const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(10); /// Represents the portion of a block that will be used by Normal extrinsics. pub const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); -/// Maximal number of unrewarded relayer entries at inbound lane. -pub const MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE: MessageNonce = 128; +/// Maximal number of unrewarded relayer entries in Rialto confirmation transaction. +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 1024; -/// Maximal number of unconfirmed messages at inbound lane. -pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 128; +/// Maximal number of unconfirmed messages in Rialto confirmation transaction. +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 1024; /// Weight of single regular message delivery transaction on Rialto chain. /// @@ -171,6 +171,17 @@ impl Chain for Rialto { type Balance = Balance; type Index = Index; type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) + } + + fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) + } } /// Convert a 256-bit hash into an AccountId. @@ -215,21 +226,11 @@ frame_support::parameter_types! { .build_or_panic(); } -/// Get the maximum weight (compute time) that a Normal extrinsic on the Millau chain can use. -pub fn max_extrinsic_weight() -> Weight { - BlockWeights::get() - .get(DispatchClass::Normal) - .max_extrinsic - .unwrap_or(Weight::MAX) -} - -/// Get the maximum length in bytes that a Normal extrinsic on the Millau chain requires. -pub fn max_extrinsic_size() -> u32 { - *BlockLength::get().max.get(DispatchClass::Normal) -} +/// Name of the With-Rialto messages pallet instance that is deployed at bridged chains. +pub const WITH_RIALTO_MESSAGES_PALLET_NAME: &str = "BridgeRialtoMessages"; -/// Name of the With-Millau messages pallet instance in the Rialto runtime. -pub const WITH_MILLAU_MESSAGES_PALLET_NAME: &str = "BridgeMillauMessages"; +/// Name of the Millau->Rialto (actually KSM->DOT) conversion rate stored in the Rialto runtime. +pub const MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME: &str = "MillauToRialtoConversionRate"; /// Name of the parachain registrar pallet in the Rialto runtime. pub const PARAS_REGISTRAR_PALLET_NAME: &str = "Registrar"; @@ -246,9 +247,6 @@ pub const TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD: &str = "ToRialtoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToRialtoOutboundLaneApi::message_details` runtime method. pub const TO_RIALTO_MESSAGE_DETAILS_METHOD: &str = "ToRialtoOutboundLaneApi_message_details"; -/// Name of the `ToRialtoOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_RIALTO_LATEST_GENERATED_NONCE_METHOD: &str = - "ToRialtoOutboundLaneApi_latest_generated_nonce"; /// Name of the `ToRialtoOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToRialtoOutboundLaneApi_latest_received_nonce"; @@ -271,8 +269,6 @@ sp_api::decl_runtime_apis! { pub trait RialtoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Rialto chain. @@ -292,6 +288,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + rialto_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -305,8 +302,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Rialto chain. diff --git a/primitives/chain-rococo/src/lib.rs b/primitives/chain-rococo/src/lib.rs index b3bbc91976..5d95e7f1d1 100644 --- a/primitives/chain-rococo/src/lib.rs +++ b/primitives/chain-rococo/src/lib.rs @@ -24,6 +24,7 @@ use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState} use frame_support::weights::{ Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; +use sp_runtime::FixedU128; use sp_std::prelude::*; use sp_version::RuntimeVersion; @@ -42,9 +43,9 @@ pub const SESSION_LENGTH: BlockNumber = 10 * time_units::MINUTES; // NOTE: This needs to be kept up to date with the Rococo runtime found in the Polkadot repo. pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: sp_version::create_runtime_str!("rococo"), - impl_name: sp_version::create_runtime_str!("parity-rococo-v1.6"), + impl_name: sp_version::create_runtime_str!("parity-rococo-v2.0"), authoring_version: 0, - spec_version: 9100, + spec_version: 9140, impl_version: 0, apis: sp_version::create_apis_vec![[]], transaction_version: 0, @@ -74,13 +75,11 @@ pub fn derive_account_from_wococo_id(id: bp_runtime::SourceAccount) - AccountIdConverter::convert(encoded_id) } -/// Name of the With-Wococo messages pallet instance in the Rococo runtime. -pub const WITH_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; +/// Name of the With-Rococo messages pallet instance that is deployed at bridged chains. +pub const WITH_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; /// Name of the `RococoFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_best_finalized"; -/// Name of the `RococoFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_ROCOCO_HEADER_METHOD: &str = "RococoFinalityApi_is_known_header"; /// Name of the `ToRococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -88,9 +87,6 @@ pub const TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = "ToRococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToRococoOutboundLaneApi::message_details` runtime method. pub const TO_ROCOCO_MESSAGE_DETAILS_METHOD: &str = "ToRococoOutboundLaneApi_message_details"; -/// Name of the `ToRococoOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_ROCOCO_LATEST_GENERATED_NONCE_METHOD: &str = - "ToRococoOutboundLaneApi_latest_generated_nonce"; /// Name of the `ToRococoOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_ROCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToRococoOutboundLaneApi_latest_received_nonce"; @@ -105,6 +101,9 @@ pub const FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = pub const FROM_ROCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromRococoInboundLaneApi_unrewarded_relayers_state"; +/// Existential deposit on Rococo. +pub const EXISTENTIAL_DEPOSIT: Balance = 1_000_000_000_000 / 100; + /// Weight of pay-dispatch-fee operation for inbound messages at Rococo chain. /// /// This value corresponds to the result of @@ -122,8 +121,6 @@ sp_api::decl_runtime_apis! { pub trait RococoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Rococo chain. @@ -143,6 +140,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + rococo_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -156,8 +154,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Rococo chain. diff --git a/primitives/chain-westend/Cargo.toml b/primitives/chain-westend/Cargo.toml index 4fd1652744..cc2e912cea 100644 --- a/primitives/chain-westend/Cargo.toml +++ b/primitives/chain-westend/Cargo.toml @@ -14,7 +14,6 @@ smallvec = "1.7" # Bridge Dependencies bp-header-chain = { path = "../header-chain", default-features = false } -bp-messages = { path = "../messages", default-features = false } bp-polkadot-core = { path = "../polkadot-core", default-features = false } bp-runtime = { path = "../runtime", default-features = false } @@ -30,7 +29,6 @@ sp-version = { git = "https://github.com/paritytech/substrate", branch = "master default = ["std"] std = [ "bp-header-chain/std", - "bp-messages/std", "bp-polkadot-core/std", "bp-runtime/std", "frame-support/std", diff --git a/primitives/chain-westend/src/lib.rs b/primitives/chain-westend/src/lib.rs index 8beb897f59..268eea43ce 100644 --- a/primitives/chain-westend/src/lib.rs +++ b/primitives/chain-westend/src/lib.rs @@ -20,7 +20,6 @@ // Runtime-generated DecodeLimit::decode_all_with_depth_limit #![allow(clippy::unnecessary_mut_passed)] -use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; use frame_support::weights::{ WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial, }; @@ -90,31 +89,6 @@ pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) - /// Name of the `WestendFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_best_finalized"; -/// Name of the `WestendFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_WESTEND_HEADER_METHOD: &str = "WestendFinalityApi_is_known_header"; - -/// Name of the `ToWestendOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime -/// method. -pub const TO_WESTEND_ESTIMATE_MESSAGE_FEE_METHOD: &str = - "ToWestendOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; -/// Name of the `ToWestendOutboundLaneApi::message_details` runtime method. -pub const TO_WESTEND_MESSAGE_DETAILS_METHOD: &str = "ToWestendOutboundLaneApi_message_details"; -/// Name of the `ToWestendOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_WESTEND_LATEST_GENERATED_NONCE_METHOD: &str = - "ToWestendOutboundLaneApi_latest_generated_nonce"; -/// Name of the `ToWestendOutboundLaneApi::latest_received_nonce` runtime method. -pub const TO_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str = - "ToWestendOutboundLaneApi_latest_received_nonce"; - -/// Name of the `FromWestendInboundLaneApi::latest_received_nonce` runtime method. -pub const FROM_WESTEND_LATEST_RECEIVED_NONCE_METHOD: &str = - "FromWestendInboundLaneApi_latest_received_nonce"; -/// Name of the `FromWestendInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_WESTEND_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromWestendInboundLaneApi_latest_confirmed_nonce"; -/// Name of the `FromWestendInboundLaneApi::unrewarded_relayers_state` runtime method. -pub const FROM_WESTEND_UNREWARDED_RELAYERS_STATE: &str = - "FromWestendInboundLaneApi_unrewarded_relayers_state"; /// The target length of a session (how often authorities change) on Westend measured in of number /// of blocks. @@ -131,54 +105,5 @@ sp_api::decl_runtime_apis! { pub trait WestendFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; - } - - /// Outbound message lane API for messages that are sent to Westend chain. - /// - /// This API is implemented by runtimes that are sending messages to Westend chain, not the - /// Westend runtime itself. - pub trait ToWestendOutboundLaneApi { - /// Estimate message delivery and dispatch fee that needs to be paid by the sender on - /// this chain. - /// - /// Returns `None` if message is too expensive to be sent to Westend from this chain. - /// - /// Please keep in mind that this method returns the lowest message fee required for message - /// to be accepted to the lane. It may be good idea to pay a bit over this price to account - /// future exchange rate changes and guarantee that relayer would deliver your message - /// to the target chain. - fn estimate_message_delivery_and_dispatch_fee( - lane_id: LaneId, - payload: OutboundPayload, - ) -> Option; - /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all - /// messages in given inclusive range. - /// - /// If some (or all) messages are missing from the storage, they'll also will - /// be missing from the resulting vector. The vector is ordered by the nonce. - fn message_details( - lane: LaneId, - begin: MessageNonce, - end: MessageNonce, - ) -> Vec>; - /// Returns nonce of the latest message, received by bridged chain. - fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; - } - - /// Inbound message lane API for messages sent by Westend chain. - /// - /// This API is implemented by runtimes that are receiving messages from Westend chain, not the - /// Westend runtime itself. - pub trait FromWestendInboundLaneApi { - /// Returns nonce of the latest message, received by given lane. - fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Nonce of the latest message that has been confirmed to the bridged chain. - fn latest_confirmed_nonce(lane: LaneId) -> MessageNonce; - /// State of the unrewarded relayers set at given lane. - fn unrewarded_relayers_state(lane: LaneId) -> UnrewardedRelayersState; } } diff --git a/primitives/chain-wococo/src/lib.rs b/primitives/chain-wococo/src/lib.rs index fe2ce3a309..617688e8e4 100644 --- a/primitives/chain-wococo/src/lib.rs +++ b/primitives/chain-wococo/src/lib.rs @@ -21,11 +21,14 @@ #![allow(clippy::unnecessary_mut_passed)] use bp_messages::{LaneId, MessageDetails, MessageNonce, UnrewardedRelayersState}; +use sp_runtime::FixedU128; use sp_std::prelude::*; pub use bp_polkadot_core::*; // Rococo runtime = Wococo runtime -pub use bp_rococo::{WeightToFee, PAY_INBOUND_DISPATCH_FEE_WEIGHT, SESSION_LENGTH, VERSION}; +pub use bp_rococo::{ + WeightToFee, EXISTENTIAL_DEPOSIT, PAY_INBOUND_DISPATCH_FEE_WEIGHT, SESSION_LENGTH, VERSION, +}; /// Wococo Chain pub type Wococo = PolkadotLike; @@ -37,13 +40,11 @@ pub fn derive_account_from_rococo_id(id: bp_runtime::SourceAccount) - AccountIdConverter::convert(encoded_id) } -/// Name of the With-Rococo messages pallet instance in the Wococo runtime. -pub const WITH_ROCOCO_MESSAGES_PALLET_NAME: &str = "BridgeRococoMessages"; +/// Name of the With-Wococo messages pallet instance that is deployed at bridged chains. +pub const WITH_WOCOCO_MESSAGES_PALLET_NAME: &str = "BridgeWococoMessages"; /// Name of the `WococoFinalityApi::best_finalized` runtime method. pub const BEST_FINALIZED_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_best_finalized"; -/// Name of the `WococoFinalityApi::is_known_header` runtime method. -pub const IS_KNOWN_WOCOCO_HEADER_METHOD: &str = "WococoFinalityApi_is_known_header"; /// Name of the `ToWococoOutboundLaneApi::estimate_message_delivery_and_dispatch_fee` runtime /// method. @@ -51,9 +52,6 @@ pub const TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = "ToWococoOutboundLaneApi_estimate_message_delivery_and_dispatch_fee"; /// Name of the `ToWococoOutboundLaneApi::message_details` runtime method. pub const TO_WOCOCO_MESSAGE_DETAILS_METHOD: &str = "ToWococoOutboundLaneApi_message_details"; -/// Name of the `ToWococoOutboundLaneApi::latest_generated_nonce` runtime method. -pub const TO_WOCOCO_LATEST_GENERATED_NONCE_METHOD: &str = - "ToWococoOutboundLaneApi_latest_generated_nonce"; /// Name of the `ToWococoOutboundLaneApi::latest_received_nonce` runtime method. pub const TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD: &str = "ToWococoOutboundLaneApi_latest_received_nonce"; @@ -76,8 +74,6 @@ sp_api::decl_runtime_apis! { pub trait WococoFinalityApi { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); - /// Returns true if the header is known to the runtime. - fn is_known_header(hash: Hash) -> bool; } /// Outbound message lane API for messages that are sent to Wococo chain. @@ -97,6 +93,7 @@ sp_api::decl_runtime_apis! { fn estimate_message_delivery_and_dispatch_fee( lane_id: LaneId, payload: OutboundPayload, + wococo_to_this_conversion_rate: Option, ) -> Option; /// Returns dispatch weight, encoded payload size and delivery+dispatch fee of all /// messages in given inclusive range. @@ -110,8 +107,6 @@ sp_api::decl_runtime_apis! { ) -> Vec>; /// Returns nonce of the latest message, received by bridged chain. fn latest_received_nonce(lane: LaneId) -> MessageNonce; - /// Returns nonce of the latest message, generated by given lane. - fn latest_generated_nonce(lane: LaneId) -> MessageNonce; } /// Inbound message lane API for messages sent by Wococo chain. diff --git a/primitives/messages/Cargo.toml b/primitives/messages/Cargo.toml index 95dca2bea6..5afa25fb30 100644 --- a/primitives/messages/Cargo.toml +++ b/primitives/messages/Cargo.toml @@ -21,8 +21,13 @@ bp-runtime = { path = "../runtime", default-features = false } frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } frame-system = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +[dev-dependencies] +hex = "0.4" +hex-literal = "0.3" + [features] default = ["std"] std = [ @@ -32,5 +37,6 @@ std = [ "frame-system/std", "scale-info/std", "serde", + "sp-core/std", "sp-std/std" ] diff --git a/primitives/messages/src/lib.rs b/primitives/messages/src/lib.rs index abefe8d789..691ed57794 100644 --- a/primitives/messages/src/lib.rs +++ b/primitives/messages/src/lib.rs @@ -30,6 +30,7 @@ use scale_info::TypeInfo; use sp_std::{collections::vec_deque::VecDeque, prelude::*}; pub mod source_chain; +pub mod storage_keys; pub mod target_chain; // Weight is reexported to avoid additional frame-support dependencies in related crates. diff --git a/primitives/messages/src/storage_keys.rs b/primitives/messages/src/storage_keys.rs new file mode 100644 index 0000000000..3e8dc67254 --- /dev/null +++ b/primitives/messages/src/storage_keys.rs @@ -0,0 +1,102 @@ +// 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 . + +//! Storage keys of bridge messages pallet. + +/// Name of the `OutboundMessages` storage map. +pub const OUTBOUND_MESSAGES_MAP_NAME: &str = "OutboundMessages"; +/// Name of the `OutboundLanes` storage map. +pub const OUTBOUND_LANES_MAP_NAME: &str = "OutboundLanes"; +/// Name of the `InboundLanes` storage map. +pub const INBOUND_LANES_MAP_NAME: &str = "InboundLanes"; + +use crate::{LaneId, MessageKey, MessageNonce}; + +use codec::Encode; +use frame_support::Blake2_128Concat; +use sp_core::storage::StorageKey; + +/// Storage key of the outbound message in the runtime storage. +pub fn message_key(pallet_prefix: &str, lane: &LaneId, nonce: MessageNonce) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + OUTBOUND_MESSAGES_MAP_NAME, + &MessageKey { lane_id: *lane, nonce }.encode(), + ) +} + +/// Storage key of the outbound message lane state in the runtime storage. +pub fn outbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + OUTBOUND_LANES_MAP_NAME, + lane, + ) +} + +/// Storage key of the inbound message lane state in the runtime storage. +pub fn inbound_lane_data_key(pallet_prefix: &str, lane: &LaneId) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + INBOUND_LANES_MAP_NAME, + lane, + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn storage_message_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted messages proofs. + let storage_key = message_key("BridgeMessages", &*b"test", 42).0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed018a395e6242c6813b196ca31ed0547ea79446af0e09063bd4a7874aef8a997cec746573742a00000000000000").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn outbound_lane_data_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted outbound lane state proofs. + let storage_key = outbound_lane_data_key("BridgeMessages", &*b"test").0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed0196c246acb9b55077390e3ca723a0ca1f44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + + #[test] + fn inbound_lane_data_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // all previously crafted inbound lane state proofs. + let storage_key = inbound_lane_data_key("BridgeMessages", &*b"test").0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed01e5f83cf83f2127eb47afdc35d6e43fab44a8995dd50b6657a037a7839304535b74657374").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } +} diff --git a/primitives/polkadot-core/src/lib.rs b/primitives/polkadot-core/src/lib.rs index 38e43d312b..8be9cc17da 100644 --- a/primitives/polkadot-core/src/lib.rs +++ b/primitives/polkadot-core/src/lib.rs @@ -115,31 +115,17 @@ parameter_types! { .build_or_panic(); } -/// Get the maximum weight (compute time) that a Normal extrinsic on the Polkadot-like chain can -/// use. -pub fn max_extrinsic_weight() -> Weight { - BlockWeights::get() - .get(DispatchClass::Normal) - .max_extrinsic - .unwrap_or(Weight::MAX) -} - -/// Get the maximum length in bytes that a Normal extrinsic on the Polkadot-like chain requires. -pub fn max_extrinsic_size() -> u32 { - *BlockLength::get().max.get(DispatchClass::Normal) -} - // TODO [#78] may need to be updated after https://github.com/paritytech/parity-bridges-common/issues/78 /// Maximal number of messages in single delivery transaction. pub const MAX_MESSAGES_IN_DELIVERY_TRANSACTION: MessageNonce = 128; /// Maximal number of unrewarded relayer entries at inbound lane. -pub const MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE: MessageNonce = 128; +pub const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = 128; // TODO [#438] should be selected keeping in mind: // finality delay on both chains + reward payout cost + messages throughput. /// Maximal number of unconfirmed messages at inbound lane. -pub const MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE: MessageNonce = 8192; +pub const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = 8192; // One important thing about weight-related constants here is that actually we may have // different weights on different Polkadot-like chains. But now all deployments are @@ -279,7 +265,8 @@ impl parity_scale_codec::Decode for SignedExtensions { impl SignedExtensions { pub fn new( - version: sp_version::RuntimeVersion, + spec_version: u32, + transaction_version: u32, era: bp_runtime::TransactionEraOf, genesis_hash: Hash, nonce: Nonce, @@ -296,8 +283,8 @@ impl SignedExtensions { tip.into(), // transaction payment / tip (compact encoding) ), additional_signed: ( - version.spec_version, - version.transaction_version, + spec_version, + transaction_version, genesis_hash, era.signed_payload(genesis_hash), (), @@ -361,6 +348,17 @@ impl Chain for PolkadotLike { type Balance = Balance; type Index = Index; type Signature = Signature; + + fn max_extrinsic_size() -> u32 { + *BlockLength::get().max.get(DispatchClass::Normal) + } + + fn max_extrinsic_weight() -> Weight { + BlockWeights::get() + .get(DispatchClass::Normal) + .max_extrinsic + .unwrap_or(Weight::MAX) + } } /// Convert a 256-bit hash into an AccountId. diff --git a/primitives/runtime/src/chain.rs b/primitives/runtime/src/chain.rs index e24694bf8b..9dfe6216a7 100644 --- a/primitives/runtime/src/chain.rs +++ b/primitives/runtime/src/chain.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use frame_support::Parameter; -use num_traits::{AsPrimitive, Bounded, CheckedSub, SaturatingAdd, Zero}; +use frame_support::{weights::Weight, Parameter}; +use num_traits::{AsPrimitive, Bounded, CheckedSub, Saturating, SaturatingAdd, Zero}; use sp_runtime::{ traits::{ AtLeast32Bit, AtLeast32BitUnsigned, Hash as HashT, Header as HeaderT, MaybeDisplay, @@ -46,6 +46,7 @@ pub trait Chain: Send + Sync + 'static { + MaybeMallocSizeOf + AsPrimitive + Default + + Saturating // original `sp_runtime::traits::Header::BlockNumber` doesn't have this trait, but // `sp_runtime::generic::Era` requires block number -> `u64` conversion. + Into; @@ -119,6 +120,11 @@ pub trait Chain: Send + Sync + 'static { + Copy; /// Signature type, used on this chain. type Signature: Parameter + Verify; + + /// Get the maximum size (in bytes) of a Normal extrinsic at this chain. + fn max_extrinsic_size() -> u32; + /// Get the maximum weight (compute time) that a Normal extrinsic at this chain can use. + fn max_extrinsic_weight() -> Weight; } /// Block number used by the chain. diff --git a/primitives/runtime/src/lib.rs b/primitives/runtime/src/lib.rs index 051dc1f43c..c01e7bb305 100644 --- a/primitives/runtime/src/lib.rs +++ b/primitives/runtime/src/lib.rs @@ -201,47 +201,22 @@ impl, BlockHash: Copy> TransactionEra( pallet_prefix: &str, map_name: &str, key: &[u8], ) -> StorageKey { - storage_map_final_key_identity( - pallet_prefix, - map_name, - &frame_support::Blake2_128Concat::hash(key), - ) -} - -/// -pub fn storage_map_final_key_twox64_concat( - pallet_prefix: &str, - map_name: &str, - key: &[u8], -) -> StorageKey { - storage_map_final_key_identity(pallet_prefix, map_name, &frame_support::Twox64Concat::hash(key)) -} - -/// This is a copy of the -/// `frame_support::storage::generator::StorageMap::storage_map_final_key` for `Identity` maps. -/// -/// We're using it because to call `storage_map_final_key` directly, we need access to the runtime -/// and pallet instance, which (sometimes) is impossible. -pub fn storage_map_final_key_identity( - pallet_prefix: &str, - map_name: &str, - key_hashed: &[u8], -) -> StorageKey { + let key_hashed = H::hash(key); let pallet_prefix_hashed = frame_support::Twox128::hash(pallet_prefix.as_bytes()); let storage_prefix_hashed = frame_support::Twox128::hash(map_name.as_bytes()); let mut final_key = Vec::with_capacity( - pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.len(), + pallet_prefix_hashed.len() + storage_prefix_hashed.len() + key_hashed.as_ref().len(), ); final_key.extend_from_slice(&pallet_prefix_hashed[..]); diff --git a/primitives/token-swap/Cargo.toml b/primitives/token-swap/Cargo.toml index 4b16c3567e..4048ef5288 100644 --- a/primitives/token-swap/Cargo.toml +++ b/primitives/token-swap/Cargo.toml @@ -10,18 +10,29 @@ license = "GPL-3.0-or-later WITH Classpath-exception-2.0" codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false } scale-info = { version = "1.0", default-features = false, features = ["derive"] } +# Bridge Dependencies + +bp-runtime = { path = "../runtime", default-features = false } + # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-io = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +[dev-dependencies] +hex = "0.4" +hex-literal = "0.3" + [features] default = ["std"] std = [ + "bp-runtime/std", "codec/std", "frame-support/std", "scale-info/std", "sp-core/std", + "sp-io/std", "sp-std/std", ] diff --git a/primitives/token-swap/src/lib.rs b/primitives/token-swap/src/lib.rs index d46389e868..79363e5477 100644 --- a/primitives/token-swap/src/lib.rs +++ b/primitives/token-swap/src/lib.rs @@ -16,10 +16,13 @@ #![cfg_attr(not(feature = "std"), no_std)] +pub mod storage_keys; + use codec::{Decode, Encode}; use frame_support::{weights::Weight, RuntimeDebug}; use scale_info::TypeInfo; -use sp_core::U256; +use sp_core::{H256, U256}; +use sp_io::hashing::blake2_256; use sp_std::vec::Vec; /// Pending token swap state. @@ -85,6 +88,18 @@ pub struct TokenSwap + TokenSwap +where + TokenSwap: + Encode, +{ + /// Returns hash, used to identify this token swap. + pub fn hash(&self) -> H256 { + self.using_encoded(blake2_256).into() + } +} + /// SCALE-encoded `Currency::transfer` call on the bridged chain. pub type RawBridgedTransferCall = Vec; diff --git a/primitives/token-swap/src/storage_keys.rs b/primitives/token-swap/src/storage_keys.rs new file mode 100644 index 0000000000..d0aafc0d5c --- /dev/null +++ b/primitives/token-swap/src/storage_keys.rs @@ -0,0 +1,51 @@ +// 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 . + +//! Storage keys of bridge token swap pallet. + +use frame_support::Identity; +use sp_core::{storage::StorageKey, H256}; + +/// Name of the `PendingSwaps` storage map. +pub const PENDING_SWAPS_MAP_NAME: &str = "PendingSwaps"; + +/// Storage key of `PendingSwaps` value with given token swap hash. +pub fn pending_swaps_key(pallet_prefix: &str, token_swap_hash: H256) -> StorageKey { + bp_runtime::storage_map_final_key::( + pallet_prefix, + PENDING_SWAPS_MAP_NAME, + token_swap_hash.as_ref(), + ) +} + +#[cfg(test)] +mod tests { + use super::*; + use hex_literal::hex; + + #[test] + fn pending_swaps_key_computed_properly() { + // If this test fails, then something has been changed in module storage that may break + // all previous swaps. + let storage_key = pending_swaps_key("BridgeTokenSwap", [42u8; 32].into()).0; + assert_eq!( + storage_key, + hex!("76276da64e7a4f454760eedeb4bad11adca2227fef56ad07cc424f1f5d128b9a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } +} diff --git a/relays/bin-substrate/Cargo.toml b/relays/bin-substrate/Cargo.toml index a28c61262f..843340817e 100644 --- a/relays/bin-substrate/Cargo.toml +++ b/relays/bin-substrate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "substrate-relay" -version = "0.1.0" +version = "1.0.0" authors = ["Parity Technologies "] edition = "2018" license = "GPL-3.0-or-later WITH Classpath-exception-2.0" diff --git a/relays/bin-substrate/src/chains/kusama.rs b/relays/bin-substrate/src/chains/kusama.rs index b12d23f2a5..10afbdd8a5 100644 --- a/relays/bin-substrate/src/chains/kusama.rs +++ b/relays/bin-substrate/src/chains/kusama.rs @@ -17,8 +17,6 @@ use codec::Decode; use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; use relay_kusama_client::Kusama; -use sp_core::storage::StorageKey; -use sp_runtime::{FixedPointNumber, FixedU128}; use sp_version::RuntimeVersion; use crate::cli::{ @@ -33,14 +31,7 @@ use crate::cli::{ /// 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 { Ok(match call { Call::Remark { remark_payload, .. } => relay_kusama_client::runtime::Call::System( @@ -93,24 +84,9 @@ impl CliChain for Kusama { 42 } - fn max_extrinsic_weight() -> Weight { - bp_kusama::max_extrinsic_weight() - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { anyhow::bail!("Sending messages from Kusama is not yet supported.") } } - -/// Storage key and initial value of Polkadot -> Kusama conversion rate. -pub(crate) fn polkadot_to_kusama_conversion_rate_params() -> (StorageKey, FixedU128) { - ( - bp_runtime::storage_parameter_key( - bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME, - ), - // starting relay before this parameter will be set to some value may cause troubles - FixedU128::from_inner(FixedU128::DIV), - ) -} diff --git a/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs b/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs index ce631ef41e..c36c336718 100644 --- a/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs +++ b/relays/bin-substrate/src/chains/kusama_headers_to_polkadot.rs @@ -16,17 +16,8 @@ //! 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, -}; +use sp_core::Pair; +use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// 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; - +/// Description of Kusama -> Polkadot finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct KusamaFinalityToPolkadot { - finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot, -} - -impl KusamaFinalityToPolkadot { - pub fn new(target_client: Client, target_sign: PolkadotSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineKusamaFinalityToPolkadot::new( - target_client, - target_sign, - ), - } - } -} +pub struct KusamaFinalityToPolkadot; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + KusamaFinalityToPolkadot, + KusamaFinalityToPolkadotCallBuilder, + relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa, + relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof +); 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 SourceChain = relay_kusama_client::Kusama; + type TargetChain = relay_polkadot_client::Polkadot; - type TargetChain = Polkadot; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } + type SubmitFinalityProofCallBuilder = KusamaFinalityToPolkadotCallBuilder; + type TransactionSignScheme = relay_polkadot_client::Polkadot; - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + 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(), + target_client.clone(), + transaction_params.signer.public().into(), 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, - transaction_nonce: bp_runtime::IndexOf, - header: KusamaSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_polkadot_client::runtime::Call::BridgeKusamaGrandpa( - relay_polkadot_client::runtime::BridgeKusamaGrandpaCall::submit_finality_proof( - Box::new(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)] diff --git a/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs b/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs index 32133adc3e..82a3206b0d 100644 --- a/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs +++ b/relays/bin-substrate/src/chains/kusama_messages_to_polkadot.rs @@ -16,284 +16,49 @@ //! Kusama-to-Polkadot messages sync entrypoint. -use std::ops::RangeInclusive; - use codec::Encode; use frame_support::weights::Weight; use sp_core::{Bytes, Pair}; -use bp_messages::MessageNonce; -use bridge_runtime_common::messages::target::FromBridgedChainMessagesProof; -use messages_relay::{message_lane::MessageLane, relay_strategy::MixStrategy}; -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 substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, -}; - -/// Kusama-to-Polkadot message lane. -pub type MessageLaneKusamaMessagesToPolkadot = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct KusamaMessagesToPolkadot { - message_lane: MessageLaneKusamaMessagesToPolkadot, -} +use messages_relay::relay_strategy::MixStrategy; +use relay_kusama_client::Kusama; +use relay_polkadot_client::Polkadot; +use relay_substrate_client::{Client, SignParam, TransactionSignScheme, UnsignedTransaction}; +use substrate_relay_helper::messages_lane::SubstrateMessageLane; + +/// Description of Kusama -> Polkadot messages bridge. +#[derive(Clone, Debug)] +pub struct KusamaMessagesToPolkadot; +substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( + KusamaMessagesToPolkadot, + KusamaMessagesToPolkadotReceiveMessagesProofCallBuilder, + relay_polkadot_client::runtime::Call::BridgeKusamaMessages, + relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_proof +); +substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( + KusamaMessagesToPolkadot, + KusamaMessagesToPolkadotReceiveMessagesDeliveryProofCallBuilder, + relay_kusama_client::runtime::Call::BridgePolkadotMessages, + relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_delivery_proof +); 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; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME); 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, - best_block_id: KusamaHeaderId, - transaction_nonce: bp_runtime::IndexOf, - _generated_at_block: PolkadotHeaderId, - proof: ::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::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Polkadot -> Kusama confirmation transaction. Weight: /{}, 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() - } + type SourceTransactionSignScheme = Kusama; + type TargetTransactionSignScheme = Polkadot; - fn make_messages_delivery_transaction( - &self, - best_block_id: PolkadotHeaderId, - transaction_nonce: bp_runtime::IndexOf, - _generated_at_header: KusamaHeaderId, - _nonces: RangeInclusive, - proof: ::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::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Kusama -> Polkadot delivery transaction. Weight: /{}, 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; - -/// Polkadot node as messages target. -type PolkadotTargetClient = SubstrateMessagesTarget; - -/// Run Kusama-to-Polkadot messages sync. -pub async fn run( - params: MessagesRelayParams< - Kusama, - KusamaSigningParams, - Polkadot, - PolkadotSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Kusama::AVERAGE_BLOCK_INTERVAL, - Polkadot::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - 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 target_client = params.target_client; - let lane = KusamaMessagesToPolkadot { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - 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, - >( - 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_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, - relay_strategy: params.relay_strategy, - }, - }, - KusamaSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - PolkadotTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} + type ReceiveMessagesProofCallBuilder = KusamaMessagesToPolkadotReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + KusamaMessagesToPolkadotReceiveMessagesDeliveryProofCallBuilder; -/// Create standalone metrics for the Kusama -> Polkadot messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - Some(crate::chains::kusama::TOKEN_ID), - Some(crate::chains::polkadot::TOKEN_ID), - Some(crate::chains::polkadot::kusama_to_polkadot_conversion_rate_params()), - Some(crate::chains::kusama::polkadot_to_kusama_conversion_rate_params()), - ) + type RelayStrategy = MixStrategy; } /// Update Polkadot -> Kusama conversion rate, stored in Kusama runtime storage. @@ -304,14 +69,17 @@ pub(crate) async fn update_polkadot_to_kusama_conversion_rate( ) -> anyhow::Result<()> { let genesis_hash = *client.genesis_hash(); let signer_id = (*signer.public().as_array_ref()).into(); + let (spec_version, transaction_version) = client.simple_runtime_version().await?; client .submit_signed_extrinsic(signer_id, move |_, transaction_nonce| { Bytes( - Kusama::sign_transaction( + Kusama::sign_transaction(SignParam { + spec_version, + transaction_version, genesis_hash, - &signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( relay_kusama_client::runtime::Call::BridgePolkadotMessages( relay_kusama_client::runtime::BridgePolkadotMessagesCall::update_pallet_parameter( relay_kusama_client::runtime::BridgePolkadotMessagesParameter::PolkadotToKusamaConversionRate( @@ -321,8 +89,8 @@ pub(crate) async fn update_polkadot_to_kusama_conversion_rate( ), transaction_nonce, ), - ) - .encode(), + }) + .encode(), ) }) .await diff --git a/relays/bin-substrate/src/chains/millau.rs b/relays/bin-substrate/src/chains/millau.rs index 755d7cc443..3d599c2e54 100644 --- a/relays/bin-substrate/src/chains/millau.rs +++ b/relays/bin-substrate/src/chains/millau.rs @@ -26,24 +26,11 @@ use crate::cli::{ use anyhow::anyhow; use bp_message_dispatch::{CallOrigin, MessagePayload}; use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo, Weight}; +use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_millau_client::Millau; -use sp_core::storage::StorageKey; -use sp_runtime::FixedU128; use sp_version::RuntimeVersion; -// Millau/Rialto tokens have no any real value, so the conversion rate we use is always 1:1. But we -// want to test our code that is intended to work with real-value chains. So to keep it close to -// 1:1, we'll be treating Rialto as BTC and Millau as wBTC (only in relayer). - -/// The identifier of token, which value is associated with Millau token value by relayer. -pub(crate) const ASSOCIATED_TOKEN_ID: &str = crate::chains::kusama::TOKEN_ID; - impl CliEncodeCall for Millau { - fn max_extrinsic_size() -> u32 { - bp_millau::max_extrinsic_size() - } - fn encode_call(call: &Call) -> anyhow::Result { Ok(match call { Call::Raw { data } => Decode::decode(&mut &*data.0)?, @@ -96,10 +83,6 @@ impl CliChain for Millau { millau_runtime::SS58Prefix::get() as u16 } - fn max_extrinsic_weight() -> Weight { - bp_millau::max_extrinsic_weight() - } - // TODO [#854|#843] support multiple bridges? fn encode_message( message: encode_message::MessagePayload, @@ -132,11 +115,3 @@ impl CliChain for Millau { } } } - -/// Storage key and initial value of Rialto -> Millau conversion rate. -pub(crate) fn rialto_to_millau_conversion_rate_params() -> (StorageKey, FixedU128) { - ( - StorageKey(millau_runtime::rialto_messages::RialtoToMillauConversionRate::key().to_vec()), - millau_runtime::rialto_messages::INITIAL_RIALTO_TO_MILLAU_CONVERSION_RATE, - ) -} diff --git a/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs index 14a0430f6a..584f0a9bb1 100644 --- a/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs +++ b/relays/bin-substrate/src/chains/millau_headers_to_rialto.rs @@ -16,65 +16,22 @@ //! Millau-to-Rialto headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SyncHeader as MillauSyncHeader}; -use relay_rialto_client::{Rialto, SigningParams as RialtoSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Millau-to-Rialto finality sync pipeline. -pub(crate) type FinalityPipelineMillauToRialto = - SubstrateFinalityToSubstrate; - +/// Description of Millau -> Rialto finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct MillauFinalityToRialto { - finality_pipeline: FinalityPipelineMillauToRialto, -} - -impl MillauFinalityToRialto { - pub fn new(target_client: Client, target_sign: RialtoSigningParams) -> Self { - Self { finality_pipeline: FinalityPipelineMillauToRialto::new(target_client, target_sign) } - } -} +pub struct MillauFinalityToRialto; impl SubstrateFinalitySyncPipeline for MillauFinalityToRialto { - type FinalitySyncPipeline = FinalityPipelineMillauToRialto; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; - - type TargetChain = Rialto; - - fn transactions_author(&self) -> bp_rialto::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: MillauSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = rialto_runtime::BridgeGrandpaMillauCall::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Rialto::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SourceChain = relay_millau_client::Millau; + type TargetChain = relay_rialto_client::Rialto; + + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::MillauGrandpaInstance, + >; + type TransactionSignScheme = relay_rialto_client::Rialto; } diff --git a/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs b/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs index c4179eea33..a496602943 100644 --- a/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs +++ b/relays/bin-substrate/src/chains/millau_messages_to_rialto.rs @@ -16,279 +16,46 @@ //! Millau-to-Rialto messages sync entrypoint. -use std::ops::RangeInclusive; - use codec::Encode; -use frame_support::dispatch::GetDispatchInfo; 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, relay_strategy::MixStrategy}; -use relay_millau_client::{ - HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams, -}; -use relay_rialto_client::{ - HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams, -}; -use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, +use messages_relay::relay_strategy::MixStrategy; +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use relay_substrate_client::{Client, SignParam, TransactionSignScheme, UnsignedTransaction}; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, }; -/// Millau-to-Rialto message lane. -pub type MessageLaneMillauMessagesToRialto = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct MillauMessagesToRialto { - message_lane: MessageLaneMillauMessagesToRialto, -} +/// Description of Millau -> Rialto messages bridge. +#[derive(Clone, Debug)] +pub struct MillauMessagesToRialto; impl SubstrateMessageLane for MillauMessagesToRialto { - type MessageLane = MessageLaneMillauMessagesToRialto; - - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = - bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD; - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = - bp_rialto::TO_RIALTO_LATEST_GENERATED_NONCE_METHOD; - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_rialto::TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD; - - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_millau::FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD; - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = - bp_millau::FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD; - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = - bp_millau::FROM_MILLAU_UNREWARDED_RELAYERS_STATE; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = - bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; - - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME; - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME; - - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = - bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME); type SourceChain = Millau; type TargetChain = Rialto; - fn source_transactions_author(&self) -> bp_millau::AccountId { - (*self.message_lane.source_sign.public().as_array_ref()).into() - } - - fn make_messages_receiving_proof_transaction( - &self, - best_block_id: MillauHeaderId, - transaction_nonce: IndexOf, - _generated_at_block: RialtoHeaderId, - proof: ::MessagesReceivingProof, - ) -> Bytes { - let (relayers_state, proof) = proof; - let call: millau_runtime::Call = - millau_runtime::MessagesCall::receive_messages_delivery_proof { proof, relayers_state } - .into(); - let call_weight = call.get_dispatch_info().weight; - let genesis_hash = *self.message_lane.source_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Rialto -> Millau confirmation transaction. Weight: {}/{}, size: {}/{}", - call_weight, - bp_millau::max_extrinsic_weight(), - transaction.encode().len(), - bp_millau::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } - - fn target_transactions_author(&self) -> bp_rialto::AccountId { - (*self.message_lane.target_sign.public().as_array_ref()).into() - } - - fn make_messages_delivery_transaction( - &self, - best_block_id: RialtoHeaderId, - transaction_nonce: IndexOf, - _generated_at_header: MillauHeaderId, - _nonces: RangeInclusive, - proof: ::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: rialto_runtime::Call = rialto_runtime::MessagesCall::receive_messages_proof { - relayer_id_at_bridged_chain: self.message_lane.relayer_id_at_source.clone(), - proof, - messages_count: messages_count as _, - dispatch_weight, - } - .into(); - let call_weight = call.get_dispatch_info().weight; - let genesis_hash = *self.message_lane.target_client.genesis_hash(); - let transaction = Rialto::sign_transaction( - genesis_hash, - &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Millau -> Rialto delivery transaction. Weight: {}/{}, size: {}/{}", - call_weight, - bp_rialto::max_extrinsic_weight(), - transaction.encode().len(), - bp_rialto::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } -} - -/// Millau node as messages source. -type MillauSourceClient = SubstrateMessagesSource; - -/// Rialto node as messages target. -type RialtoTargetClient = SubstrateMessagesTarget; - -/// Run Millau-to-Rialto messages sync. -pub async fn run( - params: MessagesRelayParams< - Millau, - MillauSigningParams, - Rialto, - RialtoSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Millau::AVERAGE_BLOCK_INTERVAL, - Rialto::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - let relayer_id_at_millau = (*params.source_sign.public().as_array_ref()).into(); - - let lane_id = params.lane_id; - let source_client = params.source_client; - let target_client = params.target_client; - let lane = MillauMessagesToRialto { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - relayer_id_at_source: relayer_id_at_millau, - }, - }; - - // 2/3 is reserved for proofs and tx overhead - let max_messages_size_in_single_batch = bp_rialto::max_extrinsic_size() / 3; - // TODO: use Millau weights after https://github.com/paritytech/parity-bridges-common/issues/390 - let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = - select_delivery_transaction_limits::< - pallet_bridge_messages::weights::RialtoWeight, - >( - bp_rialto::max_extrinsic_weight(), - bp_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - ); - - log::info!( - target: "bridge", - "Starting Millau -> Rialto messages relay.\n\t\ - Millau 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_client.clone()))?; - messages_relay::message_lane_loop::run( - messages_relay::message_lane_loop::Params { - lane: lane_id, - source_tick: Millau::AVERAGE_BLOCK_INTERVAL, - target_tick: Rialto::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_rialto::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - max_unconfirmed_nonces_at_target: - bp_rialto::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, - max_messages_in_single_batch, - max_messages_weight_in_single_batch, - max_messages_size_in_single_batch, - relay_strategy: params.relay_strategy, - }, - }, - MillauSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - RialtoTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} - -/// Create standalone metrics for the Millau -> Rialto messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - Some(crate::chains::millau::ASSOCIATED_TOKEN_ID), - Some(crate::chains::rialto::ASSOCIATED_TOKEN_ID), - Some(crate::chains::rialto::millau_to_rialto_conversion_rate_params()), - Some(crate::chains::millau::rialto_to_millau_conversion_rate_params()), - ) + type SourceTransactionSignScheme = Millau; + type TargetTransactionSignScheme = Rialto; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, + >; + + type RelayStrategy = MixStrategy; } /// Update Rialto -> Millau conversion rate, stored in Millau runtime storage. @@ -299,23 +66,26 @@ pub(crate) async fn update_rialto_to_millau_conversion_rate( ) -> anyhow::Result<()> { let genesis_hash = *client.genesis_hash(); let signer_id = (*signer.public().as_array_ref()).into(); + let (spec_version, transaction_version) = client.simple_runtime_version().await?; client .submit_signed_extrinsic(signer_id, move |_, transaction_nonce| { Bytes( - Millau::sign_transaction( + Millau::sign_transaction(SignParam { + spec_version, + transaction_version, genesis_hash, - &signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( millau_runtime::MessagesCall::update_pallet_parameter { parameter: millau_runtime::rialto_messages::MillauToRialtoMessagesParameter::RialtoToMillauConversionRate( sp_runtime::FixedU128::from_float(updated_rate), ), } - .into(), + .into(), transaction_nonce, ), - ) + }) .encode(), ) }) diff --git a/relays/bin-substrate/src/chains/mod.rs b/relays/bin-substrate/src/chains/mod.rs index e9cb2d9b73..e2a7a9a2b1 100644 --- a/relays/bin-substrate/src/chains/mod.rs +++ b/relays/bin-substrate/src/chains/mod.rs @@ -39,27 +39,16 @@ mod rococo; mod westend; mod wococo; -use relay_utils::metrics::{MetricsParams, StandaloneMetric}; - -pub(crate) fn add_polkadot_kusama_price_metrics( - params: MetricsParams, -) -> anyhow::Result { - substrate_relay_helper::helpers::token_price_metric(polkadot::TOKEN_ID)? - .register_and_spawn(¶ms.registry)?; - substrate_relay_helper::helpers::token_price_metric(kusama::TOKEN_ID)? - .register_and_spawn(¶ms.registry)?; - Ok(params) -} - #[cfg(test)] mod tests { use crate::cli::{encode_call, send_message}; use bp_messages::source_chain::TargetHeaderChain; + use bp_runtime::Chain as _; use codec::Encode; use frame_support::dispatch::GetDispatchInfo; use relay_millau_client::Millau; use relay_rialto_client::Rialto; - use relay_substrate_client::{TransactionSignScheme, UnsignedTransaction}; + use relay_substrate_client::{SignParam, TransactionSignScheme, UnsignedTransaction}; use sp_core::Pair; use sp_runtime::traits::{IdentifyAccount, Verify}; @@ -114,8 +103,8 @@ mod tests { use rialto_runtime::millau_messages::Millau; let maximal_remark_size = encode_call::compute_maximal_message_arguments_size( - bp_rialto::max_extrinsic_size(), - bp_millau::max_extrinsic_size(), + bp_rialto::Rialto::max_extrinsic_size(), + bp_millau::Millau::max_extrinsic_size(), ); let call: millau_runtime::Call = @@ -147,8 +136,8 @@ mod tests { fn maximal_size_remark_to_rialto_is_generated_correctly() { assert!( bridge_runtime_common::messages::target::maximal_incoming_message_size( - bp_rialto::max_extrinsic_size() - ) > bp_millau::max_extrinsic_size(), + bp_rialto::Rialto::max_extrinsic_size() + ) > bp_millau::Millau::max_extrinsic_size(), "We can't actually send maximal messages to Rialto from Millau, because Millau extrinsics can't be that large", ) } @@ -158,7 +147,7 @@ mod tests { use rialto_runtime::millau_messages::Millau; let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight( - bp_millau::max_extrinsic_weight(), + bp_millau::Millau::max_extrinsic_weight(), ); let call: millau_runtime::Call = rialto_runtime::SystemCall::remark { remark: vec![] }.into(); @@ -187,7 +176,7 @@ mod tests { use millau_runtime::rialto_messages::Rialto; let maximal_dispatch_weight = send_message::compute_maximal_message_dispatch_weight( - bp_rialto::max_extrinsic_weight(), + bp_rialto::Rialto::max_extrinsic_weight(), ); let call: rialto_runtime::Call = millau_runtime::SystemCall::remark { remark: vec![] }.into(); @@ -215,12 +204,14 @@ mod tests { fn rialto_tx_extra_bytes_constant_is_correct() { let rialto_call = rialto_runtime::Call::System(rialto_runtime::SystemCall::remark { remark: vec![] }); - let rialto_tx = Rialto::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(rialto_call.clone(), 0), - ); + let rialto_tx = Rialto::sign_transaction(SignParam { + spec_version: 1, + transaction_version: 1, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(rialto_call.clone(), 0), + }); let extra_bytes_in_transaction = rialto_tx.encode().len() - rialto_call.encode().len(); assert!( bp_rialto::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, @@ -234,12 +225,14 @@ mod tests { fn millau_tx_extra_bytes_constant_is_correct() { let millau_call = millau_runtime::Call::System(millau_runtime::SystemCall::remark { remark: vec![] }); - let millau_tx = Millau::sign_transaction( - Default::default(), - &sp_keyring::AccountKeyring::Alice.pair(), - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(millau_call.clone(), 0), - ); + let millau_tx = Millau::sign_transaction(SignParam { + spec_version: 0, + transaction_version: 0, + genesis_hash: Default::default(), + signer: sp_keyring::AccountKeyring::Alice.pair(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(millau_call.clone(), 0), + }); let extra_bytes_in_transaction = millau_tx.encode().len() - millau_call.encode().len(); assert!( bp_millau::TX_EXTRA_BYTES as usize >= extra_bytes_in_transaction, diff --git a/relays/bin-substrate/src/chains/polkadot.rs b/relays/bin-substrate/src/chains/polkadot.rs index 7b6256d174..8c31792a54 100644 --- a/relays/bin-substrate/src/chains/polkadot.rs +++ b/relays/bin-substrate/src/chains/polkadot.rs @@ -17,8 +17,6 @@ use codec::Decode; use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; use relay_polkadot_client::Polkadot; -use sp_core::storage::StorageKey; -use sp_runtime::{FixedPointNumber, FixedU128}; use sp_version::RuntimeVersion; use crate::cli::{ @@ -33,14 +31,7 @@ use crate::cli::{ /// 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 { Ok(match call { Call::Remark { remark_payload, .. } => relay_polkadot_client::runtime::Call::System( @@ -93,24 +84,9 @@ impl CliChain for Polkadot { 42 } - fn max_extrinsic_weight() -> Weight { - bp_polkadot::max_extrinsic_weight() - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { anyhow::bail!("Sending messages from Polkadot is not yet supported.") } } - -/// Storage key and initial value of Kusama -> Polkadot conversion rate. -pub(crate) fn kusama_to_polkadot_conversion_rate_params() -> (StorageKey, FixedU128) { - ( - bp_runtime::storage_parameter_key( - bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME, - ), - // starting relay before this parameter will be set to some value may cause troubles - FixedU128::from_inner(FixedU128::DIV), - ) -} diff --git a/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs b/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs index b1948b234c..5f65d658b9 100644 --- a/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs +++ b/relays/bin-substrate/src/chains/polkadot_headers_to_kusama.rs @@ -16,17 +16,8 @@ //! 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, -}; +use sp_core::Pair; +use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// 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; - +/// Description of Polkadot -> Kusama finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct PolkadotFinalityToKusama { - finality_pipeline: FinalityPipelinePolkadotFinalityToKusama, -} - -impl PolkadotFinalityToKusama { - pub fn new(target_client: Client, target_sign: KusamaSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelinePolkadotFinalityToKusama::new( - target_client, - target_sign, - ), - } - } -} +pub struct PolkadotFinalityToKusama; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + PolkadotFinalityToKusama, + PolkadotFinalityToKusamaCallBuilder, + relay_kusama_client::runtime::Call::BridgePolkadotGrandpa, + relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof +); 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; + type SourceChain = relay_polkadot_client::Polkadot; + type TargetChain = relay_kusama_client::Kusama; - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } + type SubmitFinalityProofCallBuilder = PolkadotFinalityToKusamaCallBuilder; + type TransactionSignScheme = relay_kusama_client::Kusama; - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + 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(), + target_client.clone(), + transaction_params.signer.public().into(), 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, - transaction_nonce: bp_runtime::IndexOf, - header: PolkadotSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_kusama_client::runtime::Call::BridgePolkadotGrandpa( - relay_kusama_client::runtime::BridgePolkadotGrandpaCall::submit_finality_proof( - Box::new(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)] diff --git a/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs b/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs index bc7f222430..5eeb0df3f1 100644 --- a/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs +++ b/relays/bin-substrate/src/chains/polkadot_messages_to_kusama.rs @@ -16,283 +16,49 @@ //! Polkadot-to-Kusama messages sync entrypoint. -use std::ops::RangeInclusive; - 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, relay_strategy::MixStrategy}; -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 substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, -}; - -/// Polkadot-to-Kusama message lane. -pub type MessageLanePolkadotMessagesToKusama = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct PolkadotMessagesToKusama { - message_lane: MessageLanePolkadotMessagesToKusama, -} +use messages_relay::relay_strategy::MixStrategy; +use relay_kusama_client::Kusama; +use relay_polkadot_client::Polkadot; +use relay_substrate_client::{Client, SignParam, TransactionSignScheme, UnsignedTransaction}; +use substrate_relay_helper::messages_lane::SubstrateMessageLane; + +/// Description of Polkadot -> Kusama messages bridge. +#[derive(Clone, Debug)] +pub struct PolkadotMessagesToKusama; +substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( + PolkadotMessagesToKusama, + PolkadotMessagesToKusamaReceiveMessagesProofCallBuilder, + relay_kusama_client::runtime::Call::BridgePolkadotMessages, + relay_kusama_client::runtime::BridgePolkadotMessagesCall::receive_messages_proof +); +substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( + PolkadotMessagesToKusama, + PolkadotMessagesToKusamaReceiveMessagesDeliveryProofCallBuilder, + relay_polkadot_client::runtime::Call::BridgeKusamaMessages, + relay_polkadot_client::runtime::BridgeKusamaMessagesCall::receive_messages_delivery_proof +); 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; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_kusama::POLKADOT_TO_KUSAMA_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_polkadot::KUSAMA_TO_POLKADOT_CONVERSION_RATE_PARAMETER_NAME); 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, - best_block_id: PolkadotHeaderId, - transaction_nonce: bp_runtime::IndexOf, - _generated_at_block: KusamaHeaderId, - proof: ::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::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Kusama -> Polkadot confirmation transaction. Weight: /{}, 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, - best_block_id: KusamaHeaderId, - transaction_nonce: bp_runtime::IndexOf, - _generated_at_header: PolkadotHeaderId, - _nonces: RangeInclusive, - proof: ::MessagesProof, - ) -> Bytes { - let (dispatch_weight, proof) = proof; - let FromBridgedChainMessagesProof { ref nonces_start, ref nonces_end, .. } = proof; - let messages_count = nonces_end - nonces_start + 1; + type SourceTransactionSignScheme = Polkadot; + type TargetTransactionSignScheme = Kusama; - 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::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Polkadot -> Kusama delivery transaction. Weight: /{}, 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; - -/// Kusama node as messages target. -type KusamaTargetClient = SubstrateMessagesTarget; - -/// Run Polkadot-to-Kusama messages sync. -pub async fn run( - params: MessagesRelayParams< - Polkadot, - PolkadotSigningParams, - Kusama, - KusamaSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Polkadot::AVERAGE_BLOCK_INTERVAL, - Kusama::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - 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 target_client = params.target_client; - let lane = PolkadotMessagesToKusama { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - 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, - >( - 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_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, - relay_strategy: params.relay_strategy, - }, - }, - PolkadotSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - KusamaTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} + type ReceiveMessagesProofCallBuilder = PolkadotMessagesToKusamaReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + PolkadotMessagesToKusamaReceiveMessagesDeliveryProofCallBuilder; -/// Create standalone metrics for the Polkadot -> Kusama messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - Some(crate::chains::polkadot::TOKEN_ID), - Some(crate::chains::kusama::TOKEN_ID), - Some(crate::chains::kusama::polkadot_to_kusama_conversion_rate_params()), - Some(crate::chains::polkadot::kusama_to_polkadot_conversion_rate_params()), - ) + type RelayStrategy = MixStrategy; } /// Update Kusama -> Polkadot conversion rate, stored in Polkadot runtime storage. @@ -303,14 +69,17 @@ pub(crate) async fn update_kusama_to_polkadot_conversion_rate( ) -> anyhow::Result<()> { let genesis_hash = *client.genesis_hash(); let signer_id = (*signer.public().as_array_ref()).into(); + let (spec_version, transaction_version) = client.simple_runtime_version().await?; client .submit_signed_extrinsic(signer_id, move |_, transaction_nonce| { Bytes( - Polkadot::sign_transaction( + Polkadot::sign_transaction(SignParam { + spec_version, + transaction_version, genesis_hash, - &signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( relay_polkadot_client::runtime::Call::BridgeKusamaMessages( relay_polkadot_client::runtime::BridgeKusamaMessagesCall::update_pallet_parameter( relay_polkadot_client::runtime::BridgeKusamaMessagesParameter::KusamaToPolkadotConversionRate( @@ -319,8 +88,8 @@ pub(crate) async fn update_kusama_to_polkadot_conversion_rate( ) ), transaction_nonce, - ), - ) + ) + }) .encode(), ) }) diff --git a/relays/bin-substrate/src/chains/rialto.rs b/relays/bin-substrate/src/chains/rialto.rs index 2d873a24ba..8931c5112d 100644 --- a/relays/bin-substrate/src/chains/rialto.rs +++ b/relays/bin-substrate/src/chains/rialto.rs @@ -26,24 +26,11 @@ use crate::cli::{ use anyhow::anyhow; use bp_message_dispatch::{CallOrigin, MessagePayload}; use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo, Weight}; +use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_rialto_client::Rialto; -use sp_core::storage::StorageKey; -use sp_runtime::FixedU128; use sp_version::RuntimeVersion; -// Millau/Rialto tokens have no any real value, so the conversion rate we use is always 1:1. But we -// want to test our code that is intended to work with real-value chains. So to keep it close to -// 1:1, we'll be treating 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 ASSOCIATED_TOKEN_ID: &str = crate::chains::polkadot::TOKEN_ID; - impl CliEncodeCall for Rialto { - fn max_extrinsic_size() -> u32 { - bp_rialto::max_extrinsic_size() - } - fn encode_call(call: &Call) -> anyhow::Result { Ok(match call { Call::Raw { data } => Decode::decode(&mut &*data.0)?, @@ -96,10 +83,6 @@ impl CliChain for Rialto { rialto_runtime::SS58Prefix::get() as u16 } - fn max_extrinsic_weight() -> Weight { - bp_rialto::max_extrinsic_weight() - } - fn encode_message( message: encode_message::MessagePayload, ) -> anyhow::Result { @@ -131,11 +114,3 @@ impl CliChain for Rialto { } } } - -/// Storage key and initial value of Millau -> Rialto conversion rate. -pub(crate) fn millau_to_rialto_conversion_rate_params() -> (StorageKey, FixedU128) { - ( - StorageKey(rialto_runtime::millau_messages::MillauToRialtoConversionRate::key().to_vec()), - rialto_runtime::millau_messages::INITIAL_MILLAU_TO_RIALTO_CONVERSION_RATE, - ) -} diff --git a/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs index 7e76f403c5..a433f3562a 100644 --- a/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/rialto_headers_to_millau.rs @@ -16,73 +16,22 @@ //! Rialto-to-Millau headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_rialto_client::{Rialto, SyncHeader as RialtoSyncHeader}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Rialto-to-Millau finality sync pipeline. -pub(crate) type FinalityPipelineRialtoFinalityToMillau = - SubstrateFinalityToSubstrate; - +/// Description of Millau -> Rialto finalized headers bridge. #[derive(Clone, Debug)] -pub struct RialtoFinalityToMillau { - finality_pipeline: FinalityPipelineRialtoFinalityToMillau, -} - -impl RialtoFinalityToMillau { - pub fn new(target_client: Client, target_sign: MillauSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineRialtoFinalityToMillau::new( - target_client, - target_sign, - ), - } - } -} +pub struct RialtoFinalityToMillau; impl SubstrateFinalitySyncPipeline for RialtoFinalityToMillau { - type FinalitySyncPipeline = FinalityPipelineRialtoFinalityToMillau; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; - - type TargetChain = Millau; - - fn transactions_author(&self) -> bp_millau::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: RialtoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::RialtoGrandpaInstance, - >::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SourceChain = relay_rialto_client::Rialto; + type TargetChain = relay_millau_client::Millau; + + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::RialtoGrandpaInstance, + >; + type TransactionSignScheme = relay_millau_client::Millau; } diff --git a/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs b/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs index 774da017df..4c7ad8e621 100644 --- a/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs +++ b/relays/bin-substrate/src/chains/rialto_messages_to_millau.rs @@ -16,278 +16,46 @@ //! Rialto-to-Millau messages sync entrypoint. -use std::ops::RangeInclusive; - use codec::Encode; -use frame_support::dispatch::GetDispatchInfo; 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, relay_strategy::MixStrategy}; -use relay_millau_client::{ - HeaderId as MillauHeaderId, Millau, SigningParams as MillauSigningParams, -}; -use relay_rialto_client::{ - HeaderId as RialtoHeaderId, Rialto, SigningParams as RialtoSigningParams, -}; -use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, +use messages_relay::relay_strategy::MixStrategy; +use relay_millau_client::Millau; +use relay_rialto_client::Rialto; +use relay_substrate_client::{Client, SignParam, TransactionSignScheme, UnsignedTransaction}; +use substrate_relay_helper::messages_lane::{ + DirectReceiveMessagesDeliveryProofCallBuilder, DirectReceiveMessagesProofCallBuilder, + SubstrateMessageLane, }; -/// Rialto-to-Millau message lane. -pub type MessageLaneRialtoMessagesToMillau = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct RialtoMessagesToMillau { - message_lane: MessageLaneRialtoMessagesToMillau, -} +/// Description of Rialto -> Millau messages bridge. +#[derive(Clone, Debug)] +pub struct RialtoMessagesToMillau; impl SubstrateMessageLane for RialtoMessagesToMillau { - type MessageLane = MessageLaneRialtoMessagesToMillau; - - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = - bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD; - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = - bp_millau::TO_MILLAU_LATEST_GENERATED_NONCE_METHOD; - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_millau::TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD; - - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_rialto::FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD; - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = - bp_rialto::FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD; - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = - bp_rialto::FROM_RIALTO_UNREWARDED_RELAYERS_STATE; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = - bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; - - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rialto::WITH_MILLAU_MESSAGES_PALLET_NAME; - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_millau::WITH_RIALTO_MESSAGES_PALLET_NAME; - - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = - bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_millau::RIALTO_TO_MILLAU_CONVERSION_RATE_PARAMETER_NAME); + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = + Some(bp_rialto::MILLAU_TO_RIALTO_CONVERSION_RATE_PARAMETER_NAME); type SourceChain = Rialto; type TargetChain = Millau; - fn source_transactions_author(&self) -> bp_rialto::AccountId { - (*self.message_lane.source_sign.public().as_array_ref()).into() - } - - fn make_messages_receiving_proof_transaction( - &self, - best_block_id: RialtoHeaderId, - transaction_nonce: IndexOf, - _generated_at_block: MillauHeaderId, - proof: ::MessagesReceivingProof, - ) -> Bytes { - let (relayers_state, proof) = proof; - let call: rialto_runtime::Call = - rialto_runtime::MessagesCall::receive_messages_delivery_proof { proof, relayers_state } - .into(); - let call_weight = call.get_dispatch_info().weight; - let genesis_hash = *self.message_lane.source_client.genesis_hash(); - let transaction = Rialto::sign_transaction( - genesis_hash, - &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Millau -> Rialto confirmation transaction. Weight: {}/{}, size: {}/{}", - call_weight, - bp_rialto::max_extrinsic_weight(), - transaction.encode().len(), - bp_rialto::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } - - fn target_transactions_author(&self) -> bp_millau::AccountId { - (*self.message_lane.target_sign.public().as_array_ref()).into() - } - - fn make_messages_delivery_transaction( - &self, - best_block_id: MillauHeaderId, - transaction_nonce: IndexOf, - _generated_at_header: RialtoHeaderId, - _nonces: RangeInclusive, - proof: ::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: millau_runtime::Call = millau_runtime::MessagesCall::receive_messages_proof { - relayer_id_at_bridged_chain: self.message_lane.relayer_id_at_source.clone(), - proof, - messages_count: messages_count as _, - dispatch_weight, - } - .into(); - let call_weight = call.get_dispatch_info().weight; - let genesis_hash = *self.message_lane.target_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Rialto -> Millau delivery transaction. Weight: {}/{}, size: {}/{}", - call_weight, - bp_millau::max_extrinsic_weight(), - transaction.encode().len(), - bp_millau::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } -} - -/// Rialto node as messages source. -type RialtoSourceClient = SubstrateMessagesSource; - -/// Millau node as messages target. -type MillauTargetClient = SubstrateMessagesTarget; - -/// Run Rialto-to-Millau messages sync. -pub async fn run( - params: MessagesRelayParams< - Rialto, - RialtoSigningParams, - Millau, - MillauSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Rialto::AVERAGE_BLOCK_INTERVAL, - Millau::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - let relayer_id_at_rialto = (*params.source_sign.public().as_array_ref()).into(); - - let lane_id = params.lane_id; - let source_client = params.source_client; - let target_client = params.target_client; - let lane = RialtoMessagesToMillau { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - relayer_id_at_source: relayer_id_at_rialto, - }, - }; - - // 2/3 is reserved for proofs and tx overhead - let max_messages_size_in_single_batch = bp_millau::max_extrinsic_size() / 3; - let (max_messages_in_single_batch, max_messages_weight_in_single_batch) = - select_delivery_transaction_limits::< - pallet_bridge_messages::weights::RialtoWeight, - >( - bp_millau::max_extrinsic_weight(), - bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - ); - - log::info!( - target: "bridge", - "Starting Rialto -> Millau messages relay.\n\t\ - Rialto 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_client.clone()))?; - messages_relay::message_lane_loop::run( - messages_relay::message_lane_loop::Params { - lane: lane_id, - source_tick: Rialto::AVERAGE_BLOCK_INTERVAL, - target_tick: Millau::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_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - max_unconfirmed_nonces_at_target: - bp_millau::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, - max_messages_in_single_batch, - max_messages_weight_in_single_batch, - max_messages_size_in_single_batch, - relay_strategy: params.relay_strategy, - }, - }, - RialtoSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - MillauTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} - -/// Create standalone metrics for the Rialto -> Millau messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - Some(crate::chains::rialto::ASSOCIATED_TOKEN_ID), - Some(crate::chains::millau::ASSOCIATED_TOKEN_ID), - Some(crate::chains::millau::rialto_to_millau_conversion_rate_params()), - Some(crate::chains::rialto::millau_to_rialto_conversion_rate_params()), - ) + type SourceTransactionSignScheme = Rialto; + type TargetTransactionSignScheme = Millau; + + type ReceiveMessagesProofCallBuilder = DirectReceiveMessagesProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WithRialtoMessagesInstance, + >; + type ReceiveMessagesDeliveryProofCallBuilder = DirectReceiveMessagesDeliveryProofCallBuilder< + Self, + rialto_runtime::Runtime, + rialto_runtime::WithMillauMessagesInstance, + >; + + type RelayStrategy = MixStrategy; } /// Update Millau -> Rialto conversion rate, stored in Rialto runtime storage. @@ -298,14 +66,17 @@ pub(crate) async fn update_millau_to_rialto_conversion_rate( ) -> anyhow::Result<()> { let genesis_hash = *client.genesis_hash(); let signer_id = (*signer.public().as_array_ref()).into(); + let (spec_version, transaction_version) = client.simple_runtime_version().await?; client .submit_signed_extrinsic(signer_id, move |_, transaction_nonce| { Bytes( - Rialto::sign_transaction( + Rialto::sign_transaction(SignParam { + spec_version, + transaction_version, genesis_hash, - &signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( rialto_runtime::MessagesCall::update_pallet_parameter { parameter: rialto_runtime::millau_messages::RialtoToMillauMessagesParameter::MillauToRialtoConversionRate( sp_runtime::FixedU128::from_float(updated_rate), @@ -313,8 +84,8 @@ pub(crate) async fn update_millau_to_rialto_conversion_rate( } .into(), transaction_nonce, - ), - ) + ) + }) .encode(), ) }) diff --git a/relays/bin-substrate/src/chains/rialto_parachain.rs b/relays/bin-substrate/src/chains/rialto_parachain.rs index edd4ca3628..da400a4daf 100644 --- a/relays/bin-substrate/src/chains/rialto_parachain.rs +++ b/relays/bin-substrate/src/chains/rialto_parachain.rs @@ -22,15 +22,11 @@ use crate::cli::{ }; use bp_message_dispatch::MessagePayload; use codec::Decode; -use frame_support::weights::{DispatchInfo, GetDispatchInfo, Weight}; +use frame_support::weights::{DispatchInfo, GetDispatchInfo}; use relay_rialto_parachain_client::RialtoParachain; use sp_version::RuntimeVersion; impl CliEncodeCall for RialtoParachain { - fn max_extrinsic_size() -> u32 { - bp_rialto_parachain::max_extrinsic_size() - } - fn encode_call(call: &Call) -> anyhow::Result { Ok(match call { Call::Raw { data } => Decode::decode(&mut &*data.0)?, @@ -45,8 +41,9 @@ impl CliEncodeCall for RialtoParachain { value: amount.0, }, ), - Call::BridgeSendMessage { .. } => - anyhow::bail!("Bridge messages are not (yet) supported here",), + Call::BridgeSendMessage { .. } => { + anyhow::bail!("Bridge messages are not (yet) supported here",) + }, }) } @@ -70,10 +67,6 @@ impl CliChain for RialtoParachain { rialto_parachain_runtime::SS58Prefix::get() as u16 } - fn max_extrinsic_weight() -> Weight { - bp_rialto_parachain::max_extrinsic_weight() - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { diff --git a/relays/bin-substrate/src/chains/rococo.rs b/relays/bin-substrate/src/chains/rococo.rs index 4df60f89fa..ef49899ec7 100644 --- a/relays/bin-substrate/src/chains/rococo.rs +++ b/relays/bin-substrate/src/chains/rococo.rs @@ -33,10 +33,6 @@ use crate::cli::{ pub(crate) const SYSTEM_REMARK_CALL_WEIGHT: Weight = 2 * 1_345_000; impl CliEncodeCall for Rococo { - fn max_extrinsic_size() -> u32 { - bp_rococo::max_extrinsic_size() - } - fn encode_call(call: &Call) -> anyhow::Result { Ok(match call { Call::Remark { remark_payload, .. } => relay_rococo_client::runtime::Call::System( @@ -48,8 +44,8 @@ impl CliEncodeCall for Rococo { match *bridge_instance_index { bridge::ROCOCO_TO_WOCOCO_INDEX => { let payload = Decode::decode(&mut &*payload.0)?; - relay_rococo_client::runtime::Call::BridgeMessagesWococo( - relay_rococo_client::runtime::BridgeMessagesWococoCall::send_message( + relay_rococo_client::runtime::Call::BridgeWococoMessages( + relay_rococo_client::runtime::BridgeWococoMessagesCall::send_message( lane.0, payload, fee.0, ), ) @@ -89,10 +85,6 @@ impl CliChain for Rococo { 42 } - fn max_extrinsic_weight() -> Weight { - bp_wococo::max_extrinsic_weight() - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { diff --git a/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs b/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs index ec98cec1ec..d0f1896db8 100644 --- a/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs +++ b/relays/bin-substrate/src/chains/rococo_headers_to_wococo.rs @@ -16,89 +16,40 @@ //! Rococo-to-Wococo headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_rococo_client::{Rococo, SyncHeader as RococoSyncHeader}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo}; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; - use crate::chains::wococo_headers_to_rococo::MAXIMAL_BALANCE_DECREASE_PER_DAY; -/// Rococo-to-Wococo finality sync pipeline. -pub(crate) type FinalityPipelineRococoFinalityToWococo = - SubstrateFinalityToSubstrate; +use sp_core::Pair; +use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; +/// Description of Rococo -> Wococo finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct RococoFinalityToWococo { - finality_pipeline: FinalityPipelineRococoFinalityToWococo, -} - -impl RococoFinalityToWococo { - pub fn new(target_client: Client, target_sign: WococoSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineRococoFinalityToWococo::new( - target_client, - target_sign, - ), - } - } -} +pub struct RococoFinalityToWococo; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + RococoFinalityToWococo, + RococoFinalityToWococoCallBuilder, + relay_wococo_client::runtime::Call::BridgeGrandpaRococo, + relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for RococoFinalityToWococo { - type FinalitySyncPipeline = FinalityPipelineRococoFinalityToWococo; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; - - type TargetChain = Wococo; + type SourceChain = relay_rococo_client::Rococo; + type TargetChain = relay_wococo_client::Wococo; - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } + type SubmitFinalityProofCallBuilder = RococoFinalityToWococoCallBuilder; + type TransactionSignScheme = relay_wococo_client::Wococo; - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_wococo::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_wococo::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: RococoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_wococo_client::runtime::Call::BridgeGrandpaRococo( - relay_wococo_client::runtime::BridgeGrandpaRococoCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Wococo::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } diff --git a/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs b/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs index d6c9040e12..a85789bb1b 100644 --- a/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs +++ b/relays/bin-substrate/src/chains/rococo_messages_to_wococo.rs @@ -16,280 +16,41 @@ //! Rococo-to-Wococo messages sync entrypoint. -use std::ops::RangeInclusive; - -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, relay_strategy::MixStrategy}; -use relay_rococo_client::{ - HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams, -}; -use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_wococo_client::{ - HeaderId as WococoHeaderId, SigningParams as WococoSigningParams, Wococo, -}; -use substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, -}; - -/// Rococo-to-Wococo message lane. -pub type MessageLaneRococoMessagesToWococo = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct RococoMessagesToWococo { - message_lane: MessageLaneRococoMessagesToWococo, -} +use messages_relay::relay_strategy::MixStrategy; +use relay_rococo_client::Rococo; +use relay_wococo_client::Wococo; +use substrate_relay_helper::messages_lane::SubstrateMessageLane; + +/// Description of Rococo -> Wococo messages bridge. +#[derive(Clone, Debug)] +pub struct RococoMessagesToWococo; +substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( + RococoMessagesToWococo, + RococoMessagesToWococoReceiveMessagesProofCallBuilder, + relay_wococo_client::runtime::Call::BridgeRococoMessages, + relay_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_proof +); +substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( + RococoMessagesToWococo, + RococoMessagesToWococoReceiveMessagesDeliveryProofCallBuilder, + relay_rococo_client::runtime::Call::BridgeWococoMessages, + relay_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_delivery_proof +); impl SubstrateMessageLane for RococoMessagesToWococo { - type MessageLane = MessageLaneRococoMessagesToWococo; - - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = - bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_METHOD; - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = - bp_wococo::TO_WOCOCO_LATEST_GENERATED_NONCE_METHOD; - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_wococo::TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD; - - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_rococo::FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD; - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = - bp_rococo::FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD; - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = - bp_rococo::FROM_ROCOCO_UNREWARDED_RELAYERS_STATE; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = - bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; - - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_rococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_wococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; - - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = - bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; type SourceChain = Rococo; type TargetChain = Wococo; - fn source_transactions_author(&self) -> bp_rococo::AccountId { - (*self.message_lane.source_sign.public().as_array_ref()).into() - } - - fn make_messages_receiving_proof_transaction( - &self, - best_block_id: RococoHeaderId, - transaction_nonce: IndexOf, - _generated_at_block: WococoHeaderId, - proof: ::MessagesReceivingProof, - ) -> Bytes { - let (relayers_state, proof) = proof; - let call = relay_rococo_client::runtime::Call::BridgeMessagesWococo( - relay_rococo_client::runtime::BridgeMessagesWococoCall::receive_messages_delivery_proof( - proof, - relayers_state, - ), - ); - let genesis_hash = *self.message_lane.source_client.genesis_hash(); - let transaction = Rococo::sign_transaction( - genesis_hash, - &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Wococo -> Rococo confirmation transaction. Weight: /{}, size: {}/{}", - bp_rococo::max_extrinsic_weight(), - transaction.encode().len(), - bp_rococo::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } + type SourceTransactionSignScheme = Rococo; + type TargetTransactionSignScheme = Wococo; - fn target_transactions_author(&self) -> bp_wococo::AccountId { - (*self.message_lane.target_sign.public().as_array_ref()).into() - } - - fn make_messages_delivery_transaction( - &self, - best_block_id: WococoHeaderId, - transaction_nonce: IndexOf, - _generated_at_header: RococoHeaderId, - _nonces: RangeInclusive, - proof: ::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_wococo_client::runtime::Call::BridgeMessagesRococo( - relay_wococo_client::runtime::BridgeMessagesRococoCall::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 = Wococo::sign_transaction( - genesis_hash, - &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Rococo -> Wococo delivery transaction. Weight: /{}, size: {}/{}", - bp_wococo::max_extrinsic_weight(), - transaction.encode().len(), - bp_wococo::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } -} - -/// Rococo node as messages source. -type RococoSourceClient = SubstrateMessagesSource; - -/// Wococo node as messages target. -type WococoTargetClient = SubstrateMessagesTarget; - -/// Run Rococo-to-Wococo messages sync. -pub async fn run( - params: MessagesRelayParams< - Rococo, - RococoSigningParams, - Wococo, - WococoSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Rococo::AVERAGE_BLOCK_INTERVAL, - Wococo::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - let relayer_id_at_rococo = (*params.source_sign.public().as_array_ref()).into(); - - let lane_id = params.lane_id; - let source_client = params.source_client; - let target_client = params.target_client; - let lane = RococoMessagesToWococo { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - relayer_id_at_source: relayer_id_at_rococo, - }, - }; - - // 2/3 is reserved for proofs and tx overhead - let max_messages_size_in_single_batch = bp_wococo::max_extrinsic_size() / 3; - // we don't know exact weights of the Wococo 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, - >( - bp_wococo::max_extrinsic_weight(), - bp_wococo::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 Rococo -> Wococo messages relay.\n\t\ - Rococo 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_client.clone()))?; - messages_relay::message_lane_loop::run( - messages_relay::message_lane_loop::Params { - lane: lane_id, - source_tick: Rococo::AVERAGE_BLOCK_INTERVAL, - target_tick: Wococo::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_wococo::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - max_unconfirmed_nonces_at_target: - bp_wococo::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, - max_messages_in_single_batch, - max_messages_weight_in_single_batch, - max_messages_size_in_single_batch, - relay_strategy: params.relay_strategy, - }, - }, - RococoSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - WococoTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} + type ReceiveMessagesProofCallBuilder = RococoMessagesToWococoReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + RococoMessagesToWococoReceiveMessagesDeliveryProofCallBuilder; -/// Create standalone metrics for the Rococo -> Wococo messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - None, - None, - None, - None, - ) + type RelayStrategy = MixStrategy; } diff --git a/relays/bin-substrate/src/chains/westend.rs b/relays/bin-substrate/src/chains/westend.rs index a42e480551..5a3dd9956d 100644 --- a/relays/bin-substrate/src/chains/westend.rs +++ b/relays/bin-substrate/src/chains/westend.rs @@ -18,7 +18,6 @@ use crate::cli::{encode_message, CliChain}; use anyhow::anyhow; -use frame_support::weights::Weight; use relay_westend_client::Westend; use sp_version::RuntimeVersion; @@ -32,10 +31,6 @@ impl CliChain for Westend { 42 } - fn max_extrinsic_weight() -> Weight { - 0 - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { diff --git a/relays/bin-substrate/src/chains/westend_headers_to_millau.rs b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs index 211aa9da9b..2ec20a027f 100644 --- a/relays/bin-substrate/src/chains/westend_headers_to_millau.rs +++ b/relays/bin-substrate/src/chains/westend_headers_to_millau.rs @@ -16,78 +16,22 @@ //! Westend-to-Millau headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_millau_client::{Millau, SigningParams as MillauSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_westend_client::{SyncHeader as WestendSyncHeader, Westend}; use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, + DirectSubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, }; -/// Westend-to-Millau finality sync pipeline. -pub(crate) type FinalityPipelineWestendFinalityToMillau = - SubstrateFinalityToSubstrate; - +/// Description of Westend -> Millau finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct WestendFinalityToMillau { - finality_pipeline: FinalityPipelineWestendFinalityToMillau, -} - -impl WestendFinalityToMillau { - pub fn new(target_client: Client, target_sign: MillauSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineWestendFinalityToMillau::new( - target_client, - target_sign, - ), - } - } -} +pub struct WestendFinalityToMillau; impl SubstrateFinalitySyncPipeline for WestendFinalityToMillau { - type FinalitySyncPipeline = FinalityPipelineWestendFinalityToMillau; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; - - type TargetChain = Millau; - - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } - - fn transactions_author(&self) -> bp_millau::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: WestendSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = millau_runtime::BridgeGrandpaCall::< - millau_runtime::Runtime, - millau_runtime::WestendGrandpaInstance, - >::submit_finality_proof { - finality_target: Box::new(header.into_inner()), - justification: proof, - } - .into(); - - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Millau::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } + type SourceChain = relay_westend_client::Westend; + type TargetChain = relay_millau_client::Millau; + + type SubmitFinalityProofCallBuilder = DirectSubmitFinalityProofCallBuilder< + Self, + millau_runtime::Runtime, + millau_runtime::WestendGrandpaInstance, + >; + type TransactionSignScheme = relay_millau_client::Millau; } diff --git a/relays/bin-substrate/src/chains/wococo.rs b/relays/bin-substrate/src/chains/wococo.rs index 328397d14b..2acc8af484 100644 --- a/relays/bin-substrate/src/chains/wococo.rs +++ b/relays/bin-substrate/src/chains/wococo.rs @@ -16,7 +16,7 @@ use anyhow::anyhow; use codec::Decode; -use frame_support::weights::{DispatchClass, DispatchInfo, Pays, Weight}; +use frame_support::weights::{DispatchClass, DispatchInfo, Pays}; use relay_wococo_client::Wococo; use sp_version::RuntimeVersion; @@ -27,10 +27,6 @@ use crate::cli::{ }; impl CliEncodeCall for Wococo { - fn max_extrinsic_size() -> u32 { - bp_wococo::max_extrinsic_size() - } - fn encode_call(call: &Call) -> anyhow::Result { Ok(match call { Call::Remark { remark_payload, .. } => relay_wococo_client::runtime::Call::System( @@ -42,8 +38,8 @@ impl CliEncodeCall for Wococo { match *bridge_instance_index { bridge::WOCOCO_TO_ROCOCO_INDEX => { let payload = Decode::decode(&mut &*payload.0)?; - relay_wococo_client::runtime::Call::BridgeMessagesRococo( - relay_wococo_client::runtime::BridgeMessagesRococoCall::send_message( + relay_wococo_client::runtime::Call::BridgeRococoMessages( + relay_wococo_client::runtime::BridgeRococoMessagesCall::send_message( lane.0, payload, fee.0, ), ) @@ -83,10 +79,6 @@ impl CliChain for Wococo { 42 } - fn max_extrinsic_weight() -> Weight { - bp_wococo::max_extrinsic_weight() - } - fn encode_message( _message: encode_message::MessagePayload, ) -> anyhow::Result { diff --git a/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs b/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs index fe17976d06..2d8795fc83 100644 --- a/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs +++ b/relays/bin-substrate/src/chains/wococo_headers_to_rococo.rs @@ -16,17 +16,8 @@ //! Wococo-to-Rococo headers sync entrypoint. -use codec::Encode; -use sp_core::{Bytes, Pair}; - -use bp_header_chain::justification::GrandpaJustification; -use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams}; -use relay_substrate_client::{Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_utils::metrics::MetricsParams; -use relay_wococo_client::{SyncHeader as WococoSyncHeader, Wococo}; -use substrate_relay_helper::finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, -}; +use sp_core::Pair; +use substrate_relay_helper::{finality_pipeline::SubstrateFinalitySyncPipeline, TransactionParams}; /// Maximal saturating difference between `balance(now)` and `balance(now-24h)` to treat /// relay as gone wild. @@ -35,77 +26,37 @@ use substrate_relay_helper::finality_pipeline::{ /// Note that this is in plancks, so this corresponds to `1500 UNITS`. pub(crate) const MAXIMAL_BALANCE_DECREASE_PER_DAY: bp_rococo::Balance = 1_500_000_000_000_000; -/// Wococo-to-Rococo finality sync pipeline. -pub(crate) type FinalityPipelineWococoFinalityToRococo = - SubstrateFinalityToSubstrate; - +/// Description of Wococo -> Rococo finalized headers bridge. #[derive(Clone, Debug)] -pub(crate) struct WococoFinalityToRococo { - finality_pipeline: FinalityPipelineWococoFinalityToRococo, -} - -impl WococoFinalityToRococo { - pub fn new(target_client: Client, target_sign: RococoSigningParams) -> Self { - Self { - finality_pipeline: FinalityPipelineWococoFinalityToRococo::new( - target_client, - target_sign, - ), - } - } -} +pub struct WococoFinalityToRococo; +substrate_relay_helper::generate_mocked_submit_finality_proof_call_builder!( + WococoFinalityToRococo, + WococoFinalityToRococoCallBuilder, + relay_rococo_client::runtime::Call::BridgeGrandpaWococo, + relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof +); impl SubstrateFinalitySyncPipeline for WococoFinalityToRococo { - type FinalitySyncPipeline = FinalityPipelineWococoFinalityToRococo; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; - - type TargetChain = Rococo; + type SourceChain = relay_wococo_client::Wococo; + type TargetChain = relay_rococo_client::Rococo; - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - crate::chains::add_polkadot_kusama_price_metrics::(params) - } + type SubmitFinalityProofCallBuilder = WococoFinalityToRococoCallBuilder; + type TransactionSignScheme = relay_rococo_client::Rococo; - fn start_relay_guards(&self) { + fn start_relay_guards( + target_client: &relay_substrate_client::Client, + transaction_params: &TransactionParams, + ) { relay_substrate_client::guard::abort_on_spec_version_change( - self.finality_pipeline.target_client.clone(), + target_client.clone(), bp_rococo::VERSION.spec_version, ); relay_substrate_client::guard::abort_when_account_balance_decreased( - self.finality_pipeline.target_client.clone(), - self.transactions_author(), + target_client.clone(), + transaction_params.signer.public().into(), MAXIMAL_BALANCE_DECREASE_PER_DAY, ); } - - fn transactions_author(&self) -> bp_rococo::AccountId { - (*self.finality_pipeline.target_sign.public().as_array_ref()).into() - } - - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: IndexOf, - header: WococoSyncHeader, - proof: GrandpaJustification, - ) -> Bytes { - let call = relay_rococo_client::runtime::Call::BridgeGrandpaWococo( - relay_rococo_client::runtime::BridgeGrandpaWococoCall::submit_finality_proof( - Box::new(header.into_inner()), - proof, - ), - ); - let genesis_hash = *self.finality_pipeline.target_client.genesis_hash(); - let transaction = Rococo::sign_transaction( - genesis_hash, - &self.finality_pipeline.target_sign, - era, - UnsignedTransaction::new(call, transaction_nonce), - ); - - Bytes(transaction.encode()) - } } #[cfg(test)] diff --git a/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs b/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs index dcba89e43f..7c599e4139 100644 --- a/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs +++ b/relays/bin-substrate/src/chains/wococo_messages_to_rococo.rs @@ -16,279 +16,42 @@ //! Wococo-to-Rococo messages sync entrypoint. -use std::ops::RangeInclusive; - -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, relay_strategy::MixStrategy}; -use relay_rococo_client::{ - HeaderId as RococoHeaderId, Rococo, SigningParams as RococoSigningParams, -}; -use relay_substrate_client::{Chain, Client, IndexOf, TransactionSignScheme, UnsignedTransaction}; -use relay_wococo_client::{ - HeaderId as WococoHeaderId, SigningParams as WococoSigningParams, Wococo, -}; -use substrate_relay_helper::{ - messages_lane::{ - select_delivery_transaction_limits, MessagesRelayParams, StandaloneMessagesMetrics, - SubstrateMessageLane, SubstrateMessageLaneToSubstrate, - }, - messages_source::SubstrateMessagesSource, - messages_target::SubstrateMessagesTarget, - STALL_TIMEOUT, -}; -/// Wococo-to-Rococo message lane. -pub type MessageLaneWococoMessagesToRococo = - SubstrateMessageLaneToSubstrate; - -#[derive(Clone)] -pub struct WococoMessagesToRococo { - message_lane: MessageLaneWococoMessagesToRococo, -} +use messages_relay::relay_strategy::MixStrategy; +use relay_rococo_client::Rococo; +use relay_wococo_client::Wococo; +use substrate_relay_helper::messages_lane::SubstrateMessageLane; + +/// Description of Wococo -> Rococo messages bridge. +#[derive(Clone, Debug)] +pub struct WococoMessagesToRococo; +substrate_relay_helper::generate_mocked_receive_message_proof_call_builder!( + WococoMessagesToRococo, + WococoMessagesToRococoReceiveMessagesProofCallBuilder, + relay_rococo_client::runtime::Call::BridgeWococoMessages, + relay_rococo_client::runtime::BridgeWococoMessagesCall::receive_messages_proof +); +substrate_relay_helper::generate_mocked_receive_message_delivery_proof_call_builder!( + WococoMessagesToRococo, + WococoMessagesToRococoReceiveMessagesDeliveryProofCallBuilder, + relay_wococo_client::runtime::Call::BridgeRococoMessages, + relay_wococo_client::runtime::BridgeRococoMessagesCall::receive_messages_delivery_proof +); impl SubstrateMessageLane for WococoMessagesToRococo { - type MessageLane = MessageLaneWococoMessagesToRococo; - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = - bp_rococo::TO_ROCOCO_MESSAGE_DETAILS_METHOD; - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = - bp_rococo::TO_ROCOCO_LATEST_GENERATED_NONCE_METHOD; - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_rococo::TO_ROCOCO_LATEST_RECEIVED_NONCE_METHOD; - - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = - bp_wococo::FROM_WOCOCO_LATEST_RECEIVED_NONCE_METHOD; - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = - bp_wococo::FROM_WOCOCO_LATEST_CONFIRMED_NONCE_METHOD; - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = - bp_wococo::FROM_WOCOCO_UNREWARDED_RELAYERS_STATE; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = - bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = - bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; - - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = bp_wococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = bp_rococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; - - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = - bp_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str> = None; type SourceChain = Wococo; type TargetChain = Rococo; - fn source_transactions_author(&self) -> bp_wococo::AccountId { - (*self.message_lane.source_sign.public().as_array_ref()).into() - } - - fn make_messages_receiving_proof_transaction( - &self, - best_block_id: WococoHeaderId, - transaction_nonce: IndexOf, - _generated_at_block: RococoHeaderId, - proof: ::MessagesReceivingProof, - ) -> Bytes { - let (relayers_state, proof) = proof; - let call = relay_wococo_client::runtime::Call::BridgeMessagesRococo( - relay_wococo_client::runtime::BridgeMessagesRococoCall::receive_messages_delivery_proof( - proof, - relayers_state, - ), - ); - let genesis_hash = *self.message_lane.source_client.genesis_hash(); - let transaction = Wococo::sign_transaction( - genesis_hash, - &self.message_lane.source_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.source_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Rococo -> Wococo confirmation transaction. Weight: /{}, size: {}/{}", - bp_wococo::max_extrinsic_weight(), - transaction.encode().len(), - bp_wococo::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } - - fn target_transactions_author(&self) -> bp_rococo::AccountId { - (*self.message_lane.target_sign.public().as_array_ref()).into() - } + type SourceTransactionSignScheme = Wococo; + type TargetTransactionSignScheme = Rococo; - fn make_messages_delivery_transaction( - &self, - best_block_id: WococoHeaderId, - transaction_nonce: IndexOf, - _generated_at_header: WococoHeaderId, - _nonces: RangeInclusive, - proof: ::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_rococo_client::runtime::Call::BridgeMessagesWococo( - relay_rococo_client::runtime::BridgeMessagesWococoCall::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 = Rococo::sign_transaction( - genesis_hash, - &self.message_lane.target_sign, - relay_substrate_client::TransactionEra::new( - best_block_id, - self.message_lane.target_transactions_mortality, - ), - UnsignedTransaction::new(call, transaction_nonce), - ); - log::trace!( - target: "bridge", - "Prepared Wococo -> Rococo delivery transaction. Weight: /{}, size: {}/{}", - bp_rococo::max_extrinsic_weight(), - transaction.encode().len(), - bp_rococo::max_extrinsic_size(), - ); - Bytes(transaction.encode()) - } -} - -/// Wococo node as messages source. -type WococoSourceClient = SubstrateMessagesSource; - -/// Rococo node as messages target. -type RococoTargetClient = SubstrateMessagesTarget; - -/// Run Wococo-to-Rococo messages sync. -pub async fn run( - params: MessagesRelayParams< - Wococo, - WococoSigningParams, - Rococo, - RococoSigningParams, - MixStrategy, - >, -) -> anyhow::Result<()> { - let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( - params.source_transactions_mortality, - params.target_transactions_mortality, - Wococo::AVERAGE_BLOCK_INTERVAL, - Rococo::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, - ); - let relayer_id_at_wococo = (*params.source_sign.public().as_array_ref()).into(); - - let lane_id = params.lane_id; - let source_client = params.source_client; - let target_client = params.target_client; - let lane = WococoMessagesToRococo { - message_lane: SubstrateMessageLaneToSubstrate { - source_client: source_client.clone(), - source_sign: params.source_sign, - source_transactions_mortality: params.source_transactions_mortality, - target_client: target_client.clone(), - target_sign: params.target_sign, - target_transactions_mortality: params.target_transactions_mortality, - relayer_id_at_source: relayer_id_at_wococo, - }, - }; - - // 2/3 is reserved for proofs and tx overhead - let max_messages_size_in_single_batch = bp_rococo::max_extrinsic_size() / 3; - // we don't know exact weights of the Rococo 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, - >( - bp_rococo::max_extrinsic_weight(), - bp_rococo::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 Wococo -> Rococo messages relay.\n\t\ - Wococo 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\ - Tx mortality: {:?}/{:?}\n\t\ - Stall timeout: {:?}", - 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.source_transactions_mortality, - params.target_transactions_mortality, - stall_timeout, - ); - - let standalone_metrics = params - .standalone_metrics - .map(Ok) - .unwrap_or_else(|| standalone_metrics(source_client.clone(), target_client.clone()))?; - messages_relay::message_lane_loop::run( - messages_relay::message_lane_loop::Params { - lane: lane_id, - source_tick: Wococo::AVERAGE_BLOCK_INTERVAL, - target_tick: Rococo::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_rococo::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, - max_unconfirmed_nonces_at_target: - bp_rococo::MAX_UNCONFIRMED_MESSAGES_AT_INBOUND_LANE, - max_messages_in_single_batch, - max_messages_weight_in_single_batch, - max_messages_size_in_single_batch, - relay_strategy: params.relay_strategy, - }, - }, - WococoSourceClient::new( - source_client.clone(), - lane.clone(), - lane_id, - params.target_to_source_headers_relay, - ), - RococoTargetClient::new( - target_client, - lane, - lane_id, - standalone_metrics.clone(), - params.source_to_target_headers_relay, - ), - standalone_metrics.register_and_spawn(params.metrics_params)?, - futures::future::pending(), - ) - .await - .map_err(Into::into) -} + type ReceiveMessagesProofCallBuilder = WococoMessagesToRococoReceiveMessagesProofCallBuilder; + type ReceiveMessagesDeliveryProofCallBuilder = + WococoMessagesToRococoReceiveMessagesDeliveryProofCallBuilder; -/// Create standalone metrics for the Wococo -> Rococo messages loop. -pub(crate) fn standalone_metrics( - source_client: Client, - target_client: Client, -) -> anyhow::Result> { - substrate_relay_helper::messages_lane::standalone_metrics( - source_client, - target_client, - None, - None, - None, - None, - ) + type RelayStrategy = MixStrategy; } diff --git a/relays/bin-substrate/src/cli/bridge.rs b/relays/bin-substrate/src/cli/bridge.rs index 1af6142c53..ea16c92c92 100644 --- a/relays/bin-substrate/src/cli/bridge.rs +++ b/relays/bin-substrate/src/cli/bridge.rs @@ -68,7 +68,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::millau_messages_to_rialto::run as relay_messages; + use crate::chains::millau_messages_to_rialto::MillauMessagesToRialto as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -77,6 +77,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use millau_runtime::millau_to_rialto_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(millau_runtime::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(rialto_runtime::VERSION); + $generic } FullBridge::RialtoToMillau => { @@ -90,7 +95,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::rialto_messages_to_millau::run as relay_messages; + use crate::chains::rialto_messages_to_millau::RialtoMessagesToMillau as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -100,6 +105,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use rialto_runtime::rialto_to_millau_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(rialto_runtime::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(millau_runtime::VERSION); + $generic } FullBridge::RococoToWococo => { @@ -113,7 +123,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::rococo_messages_to_wococo::run as relay_messages; + use crate::chains::rococo_messages_to_wococo::RococoMessagesToWococo as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -122,6 +132,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use relay_rococo_client::runtime::rococo_to_wococo_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(bp_rococo::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(bp_wococo::VERSION); + $generic } FullBridge::WococoToRococo => { @@ -135,7 +150,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::wococo_messages_to_rococo::run as relay_messages; + use crate::chains::wococo_messages_to_rococo::WococoMessagesToRococo as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -144,6 +159,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use relay_wococo_client::runtime::wococo_to_rococo_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(bp_wococo::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(bp_rococo::VERSION); + $generic } FullBridge::KusamaToPolkadot => { @@ -157,7 +177,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::kusama_messages_to_polkadot::run as relay_messages; + use crate::chains::kusama_messages_to_polkadot::KusamaMessagesToPolkadot as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -166,6 +186,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use relay_kusama_client::runtime::kusama_to_polkadot_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(bp_kusama::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(bp_polkadot::VERSION); + $generic } FullBridge::PolkadotToKusama => { @@ -179,7 +204,7 @@ macro_rules! select_full_bridge { // Relay-messages #[allow(unused_imports)] - use crate::chains::polkadot_messages_to_kusama::run as relay_messages; + use crate::chains::polkadot_messages_to_kusama::PolkadotMessagesToKusama as MessagesLane; // Send-message / Estimate-fee #[allow(unused_imports)] @@ -188,6 +213,11 @@ macro_rules! select_full_bridge { #[allow(unused_imports)] use relay_polkadot_client::runtime::polkadot_to_kusama_account_ownership_digest as account_ownership_digest; + #[allow(dead_code)] + const SOURCE_RUNTIME_VERSION: Option = Some(bp_polkadot::VERSION); + #[allow(dead_code)] + const TARGET_RUNTIME_VERSION: Option = Some(bp_kusama::VERSION); + $generic } } diff --git a/relays/bin-substrate/src/cli/encode_call.rs b/relays/bin-substrate/src/cli/encode_call.rs index e17854662e..8be04a88ff 100644 --- a/relays/bin-substrate/src/cli/encode_call.rs +++ b/relays/bin-substrate/src/cli/encode_call.rs @@ -84,9 +84,6 @@ pub enum Call { } pub trait CliEncodeCall: Chain { - /// Maximal size (in bytes) of any extrinsic (from the runtime). - fn max_extrinsic_size() -> u32; - /// Encode a CLI call. fn encode_call(call: &Call) -> anyhow::Result; diff --git a/relays/bin-substrate/src/cli/estimate_fee.rs b/relays/bin-substrate/src/cli/estimate_fee.rs index d063ce544c..42ae354564 100644 --- a/relays/bin-substrate/src/cli/estimate_fee.rs +++ b/relays/bin-substrate/src/cli/estimate_fee.rs @@ -21,6 +21,7 @@ use crate::{ use bp_runtime::BalanceOf; use codec::{Decode, Encode}; use relay_substrate_client::Chain; +use sp_runtime::FixedU128; use structopt::StructOpt; use strum::VariantNames; @@ -46,7 +47,7 @@ impl EstimateFee { let Self { source, bridge, lane, payload } = self; select_full_bridge!(bridge, { - let source_client = source.to_client::().await?; + let source_client = source.to_client::(SOURCE_RUNTIME_VERSION).await?; let lane = lane.into(); let payload = Source::encode_message(payload).map_err(|e| anyhow::format_err!("{:?}", e))?; @@ -72,8 +73,13 @@ pub(crate) async fn estimate_message_delivery_and_dispatch_fee anyhow::Result { + let conversion_rate_override: Option = None; let encoded_response = client - .state_call(estimate_fee_method.into(), (lane, payload).encode().into(), None) + .state_call( + estimate_fee_method.into(), + (lane, payload, conversion_rate_override).encode().into(), + None, + ) .await?; let decoded_response: Option = Decode::decode(&mut &encoded_response.0[..]) .map_err(relay_substrate_client::Error::ResponseParseFailed)?; @@ -86,7 +92,7 @@ pub(crate) async fn estimate_message_delivery_and_dispatch_fee { type Source = relay_millau_client::Millau; type Target = relay_rialto_client::Rialto; + const SOURCE_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -74,6 +78,10 @@ macro_rules! select_bridge { InitBridgeName::RialtoToMillau => { type Source = relay_rialto_client::Rialto; type Target = relay_millau_client::Millau; + const SOURCE_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -92,6 +100,10 @@ macro_rules! select_bridge { InitBridgeName::WestendToMillau => { type Source = relay_westend_client::Westend; type Target = relay_millau_client::Millau; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_westend::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -114,6 +126,10 @@ macro_rules! select_bridge { InitBridgeName::RococoToWococo => { type Source = relay_rococo_client::Rococo; type Target = relay_wococo_client::Wococo; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_rococo::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_wococo::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -130,6 +146,10 @@ macro_rules! select_bridge { InitBridgeName::WococoToRococo => { type Source = relay_wococo_client::Wococo; type Target = relay_rococo_client::Rococo; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_wococo::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_rococo::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -146,6 +166,10 @@ macro_rules! select_bridge { InitBridgeName::KusamaToPolkadot => { type Source = relay_kusama_client::Kusama; type Target = relay_polkadot_client::Polkadot; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -162,6 +186,10 @@ macro_rules! select_bridge { InitBridgeName::PolkadotToKusama => { type Source = relay_polkadot_client::Polkadot; type Target = relay_kusama_client::Kusama; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); fn encode_init_bridge( init_data: InitializationData<::Header>, @@ -183,25 +211,29 @@ impl InitBridge { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let target_client = self.target.to_client::().await?; + let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; + let target_client = self.target.to_client::(TARGET_RUNTIME_VERSION).await?; let target_sign = self.target_sign.to_keypair::()?; + let (spec_version, transaction_version) = + target_client.simple_runtime_version().await?; substrate_relay_helper::headers_initialize::initialize( source_client, target_client.clone(), target_sign.public().into(), move |transaction_nonce, initialization_data| { Bytes( - Target::sign_transaction( - *target_client.genesis_hash(), - &target_sign, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + Target::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: *target_client.genesis_hash(), + signer: target_sign, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( encode_init_bridge(initialization_data), transaction_nonce, ), - ) + }) .encode(), ) }, diff --git a/relays/bin-substrate/src/cli/mod.rs b/relays/bin-substrate/src/cli/mod.rs index f1180059b9..2a087e59b6 100644 --- a/relays/bin-substrate/src/cli/mod.rs +++ b/relays/bin-substrate/src/cli/mod.rs @@ -18,11 +18,13 @@ use std::convert::TryInto; -use bp_messages::LaneId; use codec::{Decode, Encode}; -use frame_support::weights::Weight; +use relay_substrate_client::ChainRuntimeVersion; use sp_runtime::app_crypto::Ss58Codec; use structopt::{clap::arg_enum, StructOpt}; +use strum::{EnumString, EnumVariantNames}; + +use bp_messages::LaneId; pub(crate) mod bridge; pub(crate) mod encode_call; @@ -258,9 +260,6 @@ pub trait CliChain: relay_substrate_client::Chain { fn encode_message( message: crate::cli::encode_message::MessagePayload, ) -> anyhow::Result; - - /// Maximal extrinsic weight (from the runtime). - fn max_extrinsic_weight() -> Weight; } /// Lane id. @@ -368,6 +367,17 @@ where } } +#[doc = "Runtime version params."] +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, EnumString, EnumVariantNames)] +pub enum RuntimeVersionType { + /// Auto query version from chain + Auto, + /// Custom `spec_version` and `transaction_version` + Custom, + /// Read version from bundle dependencies directly. + Bundle, +} + /// Create chain-specific set of configuration objects: connection parameters, /// signing parameters and bridge initialization parameters. #[macro_export] @@ -386,6 +396,23 @@ macro_rules! declare_chain_options { #[doc = "Use secure websocket connection."] #[structopt(long)] pub [<$chain_prefix _secure>]: bool, + #[doc = "Custom runtime version"] + #[structopt(flatten)] + pub [<$chain_prefix _runtime_version>]: [<$chain RuntimeVersionParams>], + } + + #[doc = $chain " runtime version params."] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + pub struct [<$chain RuntimeVersionParams>] { + #[doc = "The type of runtime version for chain " $chain] + #[structopt(long, default_value = "Bundle")] + pub [<$chain_prefix _version_mode>]: RuntimeVersionType, + #[doc = "The custom sepc_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _spec_version>]: Option, + #[doc = "The custom transaction_version for chain " $chain] + #[structopt(long)] + pub [<$chain_prefix _transaction_version>]: Option, } #[doc = $chain " signing params."] @@ -504,11 +531,36 @@ macro_rules! declare_chain_options { /// Convert connection params into Substrate client. pub async fn to_client( &self, + bundle_runtime_version: Option ) -> anyhow::Result> { + let runtime_version_params = &self.[<$chain_prefix _runtime_version>]; + let chain_runtime_version = match runtime_version_params.[<$chain_prefix _version_mode>] { + RuntimeVersionType::Auto => ChainRuntimeVersion::Auto, + RuntimeVersionType::Custom => { + let except_spec_version = runtime_version_params.[<$chain_prefix _spec_version>] + .ok_or(anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?; + let except_transaction_version = runtime_version_params.[<$chain_prefix _transaction_version>] + .ok_or(anyhow::Error::msg(format!("The {}-transaction-version is required when choose custom mode", stringify!($chain_prefix))))?; + ChainRuntimeVersion::Custom( + except_spec_version, + except_transaction_version + ) + } + RuntimeVersionType::Bundle => { + match bundle_runtime_version { + Some(runtime_version) => ChainRuntimeVersion::Custom( + runtime_version.spec_version, + runtime_version.transaction_version + ), + None => ChainRuntimeVersion::Auto + } + } + }; Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { host: self.[<$chain_prefix _host>].clone(), port: self.[<$chain_prefix _port>], secure: self.[<$chain_prefix _secure>], + chain_runtime_version, }) .await ) @@ -525,9 +577,10 @@ declare_chain_options!(Parachain, parachain); #[cfg(test)] mod tests { - use sp_core::Pair; use std::str::FromStr; + use sp_core::Pair; + use super::*; #[test] diff --git a/relays/bin-substrate/src/cli/register_parachain.rs b/relays/bin-substrate/src/cli/register_parachain.rs index fecc431148..d42e10d708 100644 --- a/relays/bin-substrate/src/cli/register_parachain.rs +++ b/relays/bin-substrate/src/cli/register_parachain.rs @@ -20,6 +20,7 @@ use crate::cli::{ }; use codec::Encode; +use frame_support::Twox64Concat; use num_traits::Zero; use polkadot_parachain::primitives::{ HeadData as ParaHeadData, Id as ParaId, ValidationCode as ParaValidationCode, @@ -29,7 +30,7 @@ use polkadot_runtime_common::{ }; use polkadot_runtime_parachains::paras::ParaLifecycle; use relay_substrate_client::{ - AccountIdOf, CallOf, Chain, Client, TransactionSignScheme, UnsignedTransaction, + AccountIdOf, CallOf, Chain, Client, SignParam, TransactionSignScheme, UnsignedTransaction, }; use rialto_runtime::SudoCall; use sp_core::{ @@ -83,6 +84,11 @@ macro_rules! select_bridge { use bp_rialto::{PARAS_PALLET_NAME, PARAS_REGISTRAR_PALLET_NAME}; + const RELAY_CHAIN_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); + const PARA_CHAIN_RUNTIME_VERSION: Option = + Some(rialto_parachain_runtime::VERSION); + $generic }, } @@ -93,9 +99,13 @@ impl RegisterParachain { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.parachain, { - let relay_client = self.relay_connection.to_client::().await?; + let relay_client = self + .relay_connection + .to_client::(RELAY_CHAIN_RUNTIME_VERSION) + .await?; let relay_sign = self.relay_sign.to_keypair::()?; - let para_client = self.para_connection.to_client::().await?; + let para_client = + self.para_connection.to_client::(PARA_CHAIN_RUNTIME_VERSION).await?; // hopefully we're the only actor that is registering parachain right now // => read next parachain id @@ -116,21 +126,24 @@ impl RegisterParachain { let reserve_parachain_id_call: CallOf = ParaRegistrarCall::reserve {}.into(); let reserve_parachain_signer = relay_sign.clone(); + let (spec_version, transaction_version) = relay_client.simple_runtime_version().await?; wait_until_transaction_is_finalized::( relay_client .submit_and_watch_signed_extrinsic( relay_sudo_account.clone(), move |_, transaction_nonce| { Bytes( - Relaychain::sign_transaction( - relay_genesis_hash, - &reserve_parachain_signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + Relaychain::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: reserve_parachain_signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( reserve_parachain_id_call, transaction_nonce, ), - ) + }) .encode(), ) }, @@ -169,15 +182,17 @@ impl RegisterParachain { relay_sudo_account.clone(), move |_, transaction_nonce| { Bytes( - Relaychain::sign_transaction( - relay_genesis_hash, - ®ister_parathread_signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + Relaychain::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: register_parathread_signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( register_parathread_call, transaction_nonce, ), - ) + }) .encode(), ) }, @@ -188,7 +203,7 @@ impl RegisterParachain { log::info!(target: "bridge", "Registered parachain: {:?}. Waiting for onboarding", para_id); // wait until parathread is onboarded - let para_state_key = bp_runtime::storage_map_final_key_twox64_concat( + let para_state_key = bp_runtime::storage_map_final_key::( PARAS_PALLET_NAME, PARAS_LIFECYCLES_STORAGE_NAME, ¶_id.encode(), @@ -229,12 +244,14 @@ impl RegisterParachain { relay_client .submit_signed_extrinsic(relay_sudo_account.clone(), move |_, transaction_nonce| { Bytes( - Relaychain::sign_transaction( - relay_genesis_hash, - &force_lease_signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(force_lease_call, transaction_nonce), - ) + Relaychain::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: relay_genesis_hash, + signer: force_lease_signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(force_lease_call, transaction_nonce), + }) .encode(), ) }) @@ -292,6 +309,9 @@ async fn wait_para_state( #[cfg(test)] mod tests { use super::*; + use crate::cli::{ + ParachainRuntimeVersionParams, RelaychainRuntimeVersionParams, RuntimeVersionType, + }; #[test] fn register_rialto_parachain() { @@ -327,6 +347,11 @@ mod tests { relaychain_host: "127.0.0.1".into(), relaychain_port: 9944, relaychain_secure: false, + relaychain_runtime_version: RelaychainRuntimeVersionParams { + relaychain_version_mode: RuntimeVersionType::Bundle, + relaychain_spec_version: None, + relaychain_transaction_version: None, + } }, relay_sign: RelaychainSigningParams { relaychain_signer: Some("//Alice".into()), @@ -339,6 +364,11 @@ mod tests { parachain_host: "127.0.0.1".into(), parachain_port: 11949, parachain_secure: false, + parachain_runtime_version: ParachainRuntimeVersionParams { + parachain_version_mode: RuntimeVersionType::Bundle, + parachain_spec_version: None, + parachain_transaction_version: None, + } }, } ); diff --git a/relays/bin-substrate/src/cli/relay_headers.rs b/relays/bin-substrate/src/cli/relay_headers.rs index 82c55965a9..4b17a56819 100644 --- a/relays/bin-substrate/src/cli/relay_headers.rs +++ b/relays/bin-substrate/src/cli/relay_headers.rs @@ -64,6 +64,10 @@ macro_rules! select_bridge { type Source = relay_millau_client::Millau; type Target = relay_rialto_client::Rialto; type Finality = crate::chains::millau_headers_to_rialto::MillauFinalityToRialto; + const SOURCE_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); $generic }, @@ -71,6 +75,10 @@ macro_rules! select_bridge { type Source = relay_rialto_client::Rialto; type Target = relay_millau_client::Millau; type Finality = crate::chains::rialto_headers_to_millau::RialtoFinalityToMillau; + const SOURCE_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); $generic }, @@ -78,6 +86,10 @@ macro_rules! select_bridge { type Source = relay_westend_client::Westend; type Target = relay_millau_client::Millau; type Finality = crate::chains::westend_headers_to_millau::WestendFinalityToMillau; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_westend::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); $generic }, @@ -85,6 +97,10 @@ macro_rules! select_bridge { type Source = relay_rococo_client::Rococo; type Target = relay_wococo_client::Wococo; type Finality = crate::chains::rococo_headers_to_wococo::RococoFinalityToWococo; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_rococo::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_wococo::VERSION); $generic }, @@ -92,6 +108,10 @@ macro_rules! select_bridge { type Source = relay_wococo_client::Wococo; type Target = relay_rococo_client::Rococo; type Finality = crate::chains::wococo_headers_to_rococo::WococoFinalityToRococo; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_wococo::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_rococo::VERSION); $generic }, @@ -99,6 +119,10 @@ macro_rules! select_bridge { type Source = relay_kusama_client::Kusama; type Target = relay_polkadot_client::Polkadot; type Finality = crate::chains::kusama_headers_to_polkadot::KusamaFinalityToPolkadot; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); $generic }, @@ -106,6 +130,10 @@ macro_rules! select_bridge { type Source = relay_polkadot_client::Polkadot; type Target = relay_kusama_client::Kusama; type Finality = crate::chains::polkadot_headers_to_kusama::PolkadotFinalityToKusama; + const SOURCE_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); $generic }, @@ -117,22 +145,25 @@ impl RelayHeaders { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; - let target_client = self.target.to_client::().await?; + let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; + let target_client = self.target.to_client::(TARGET_RUNTIME_VERSION).await?; let target_transactions_mortality = self.target_sign.target_transactions_mortality; let target_sign = self.target_sign.to_keypair::()?; - let metrics_params = Finality::customize_metrics(self.prometheus_params.into())?; + + let metrics_params: relay_utils::metrics::MetricsParams = self.prometheus_params.into(); GlobalMetrics::new()?.register_and_spawn(&metrics_params.registry)?; - let finality = Finality::new(target_client.clone(), target_sign); - finality.start_relay_guards(); + let target_transactions_params = substrate_relay_helper::TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }; + Finality::start_relay_guards(&target_client, &target_transactions_params); - substrate_relay_helper::finality_pipeline::run( - finality, + substrate_relay_helper::finality_pipeline::run::( source_client, target_client, self.only_mandatory_headers, - target_transactions_mortality, + target_transactions_params, metrics_params, ) .await diff --git a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs index 9d76a0296f..3804513acd 100644 --- a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs @@ -29,16 +29,18 @@ use strum::VariantNames; use codec::Encode; use messages_relay::relay_strategy::MixStrategy; use relay_substrate_client::{ - AccountIdOf, Chain, Client, TransactionSignScheme, UnsignedTransaction, + AccountIdOf, CallOf, Chain, ChainRuntimeVersion, Client, SignParam, TransactionSignScheme, + UnsignedTransaction, }; use relay_utils::metrics::MetricsParams; use sp_core::{Bytes, Pair}; use substrate_relay_helper::{ - messages_lane::MessagesRelayParams, on_demand_headers::OnDemandHeadersRelay, + finality_pipeline::SubstrateFinalitySyncPipeline, messages_lane::MessagesRelayParams, + on_demand_headers::OnDemandHeadersRelay, TransactionParams, }; use crate::{ - cli::{relay_messages::RelayerMode, CliChain, HexLaneId, PrometheusParams}, + cli::{relay_messages::RelayerMode, CliChain, HexLaneId, PrometheusParams, RuntimeVersionType}, declare_chain_options, }; @@ -135,16 +137,19 @@ macro_rules! select_bridge { bp_millau::SESSION_LENGTH; const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_rialto::BlockNumber = bp_rialto::SESSION_LENGTH; + const LEFT_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); + const RIGHT_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); use crate::chains::{ millau_messages_to_rialto::{ - standalone_metrics as left_to_right_standalone_metrics, - run as left_to_right_messages, update_rialto_to_millau_conversion_rate as update_right_to_left_conversion_rate, + MillauMessagesToRialto as LeftToRightMessageLane, }, rialto_messages_to_millau::{ - run as right_to_left_messages, update_millau_to_rialto_conversion_rate as update_left_to_right_conversion_rate, + RialtoMessagesToMillau as RightToLeftMessageLane, }, }; @@ -185,14 +190,14 @@ macro_rules! select_bridge { const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_wococo::BlockNumber = bp_wococo::SESSION_LENGTH; + const LEFT_RUNTIME_VERSION: Option = + Some(bp_rococo::VERSION); + const RIGHT_RUNTIME_VERSION: Option = + Some(bp_wococo::VERSION); + use crate::chains::{ - rococo_messages_to_wococo::{ - standalone_metrics as left_to_right_standalone_metrics, - run as left_to_right_messages, - }, - wococo_messages_to_rococo::{ - run as right_to_left_messages, - }, + rococo_messages_to_wococo::RococoMessagesToWococo as LeftToRightMessageLane, + wococo_messages_to_rococo::WococoMessagesToRococo as RightToLeftMessageLane, }; async fn update_right_to_left_conversion_rate( @@ -212,19 +217,39 @@ macro_rules! select_bridge { } async fn left_create_account( - _left_client: Client, - _left_sign: ::AccountKeyPair, - _account_id: AccountIdOf, + left_client: Client, + left_sign: ::AccountKeyPair, + account_id: AccountIdOf, ) -> anyhow::Result<()> { - Err(anyhow::format_err!("Account creation is not supported by this bridge")) + 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_sign: ::AccountKeyPair, - _account_id: AccountIdOf, + right_client: Client, + right_sign: ::AccountKeyPair, + account_id: AccountIdOf, ) -> anyhow::Result<()> { - Err(anyhow::format_err!("Account creation is not supported by this bridge")) + 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 @@ -248,15 +273,19 @@ macro_rules! select_bridge { const MAX_MISSING_RIGHT_HEADERS_AT_LEFT: bp_polkadot::BlockNumber = bp_polkadot::SESSION_LENGTH; + const LEFT_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); + const RIGHT_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); + use crate::chains::{ kusama_messages_to_polkadot::{ - standalone_metrics as left_to_right_standalone_metrics, - run as left_to_right_messages, update_polkadot_to_kusama_conversion_rate as update_right_to_left_conversion_rate, + KusamaMessagesToPolkadot as LeftToRightMessageLane, }, polkadot_messages_to_kusama::{ - run as right_to_left_messages, update_kusama_to_polkadot_conversion_rate as update_left_to_right_conversion_rate, + PolkadotMessagesToKusama as RightToLeftMessageLane, }, }; @@ -265,29 +294,17 @@ macro_rules! select_bridge { left_sign: ::AccountKeyPair, account_id: AccountIdOf, ) -> 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)) + 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( @@ -295,29 +312,17 @@ macro_rules! select_bridge { right_sign: ::AccountKeyPair, account_id: AccountIdOf, ) -> 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)) + 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 @@ -344,12 +349,12 @@ impl RelayHeadersAndMessages { select_bridge!(self, { let params: Params = self.into(); - let left_client = params.left.to_client::().await?; + let left_client = params.left.to_client::(LEFT_RUNTIME_VERSION).await?; let left_transactions_mortality = params.left_sign.transactions_mortality()?; let left_sign = params.left_sign.to_keypair::()?; let left_messages_pallet_owner = params.left_messages_pallet_owner.to_keypair::()?; - let right_client = params.right.to_client::().await?; + let right_client = params.right.to_client::(RIGHT_RUNTIME_VERSION).await?; let right_transactions_mortality = params.right_sign.transactions_mortality()?; let right_sign = params.right_sign.to_keypair::()?; let right_messages_pallet_owner = @@ -363,7 +368,9 @@ impl RelayHeadersAndMessages { let metrics_params: MetricsParams = params.shared.prometheus_params.into(); let metrics_params = relay_utils::relay_metrics(metrics_params).into_params(); let left_to_right_metrics = - left_to_right_standalone_metrics(left_client.clone(), right_client.clone())?; + substrate_relay_helper::messages_metrics::standalone_metrics::< + LeftToRightMessageLane, + >(left_client.clone(), right_client.clone())?; let right_to_left_metrics = left_to_right_metrics.clone().reverse(); // start conversion rate update loops for left/right chains @@ -494,19 +501,33 @@ impl RelayHeadersAndMessages { } // start on-demand header relays - let left_to_right_on_demand_headers = OnDemandHeadersRelay::new( + let left_to_right_transaction_params = TransactionParams { + mortality: right_transactions_mortality, + signer: right_sign.clone(), + }; + let right_to_left_transaction_params = TransactionParams { + mortality: left_transactions_mortality, + signer: left_sign.clone(), + }; + LeftToRightFinality::start_relay_guards( + &right_client, + &left_to_right_transaction_params, + ); + RightToLeftFinality::start_relay_guards( + &left_client, + &right_to_left_transaction_params, + ); + let left_to_right_on_demand_headers = OnDemandHeadersRelay::new::( left_client.clone(), right_client.clone(), - right_transactions_mortality, - LeftToRightFinality::new(right_client.clone(), right_sign.clone()), + left_to_right_transaction_params, MAX_MISSING_LEFT_HEADERS_AT_RIGHT, params.shared.only_mandatory_headers, ); - let right_to_left_on_demand_headers = OnDemandHeadersRelay::new( + let right_to_left_on_demand_headers = OnDemandHeadersRelay::new::( right_client.clone(), left_client.clone(), - left_transactions_mortality, - RightToLeftFinality::new(left_client.clone(), left_sign.clone()), + right_to_left_transaction_params, MAX_MISSING_RIGHT_HEADERS_AT_LEFT, params.shared.only_mandatory_headers, ); @@ -515,13 +536,19 @@ impl RelayHeadersAndMessages { let mut message_relays = Vec::with_capacity(lanes.len() * 2); for lane in lanes { let lane = lane.into(); - let left_to_right_messages = left_to_right_messages(MessagesRelayParams { + let left_to_right_messages = substrate_relay_helper::messages_lane::run::< + LeftToRightMessageLane, + >(MessagesRelayParams { source_client: left_client.clone(), - source_sign: left_sign.clone(), - source_transactions_mortality: left_transactions_mortality, + source_transaction_params: TransactionParams { + signer: left_sign.clone(), + mortality: left_transactions_mortality, + }, target_client: right_client.clone(), - target_sign: right_sign.clone(), - target_transactions_mortality: right_transactions_mortality, + target_transaction_params: TransactionParams { + signer: right_sign.clone(), + mortality: right_transactions_mortality, + }, source_to_target_headers_relay: Some(left_to_right_on_demand_headers.clone()), target_to_source_headers_relay: Some(right_to_left_on_demand_headers.clone()), lane_id: lane, @@ -531,13 +558,19 @@ impl RelayHeadersAndMessages { }) .map_err(|e| anyhow::format_err!("{}", e)) .boxed(); - let right_to_left_messages = right_to_left_messages(MessagesRelayParams { + let right_to_left_messages = substrate_relay_helper::messages_lane::run::< + RightToLeftMessageLane, + >(MessagesRelayParams { source_client: right_client.clone(), - source_sign: right_sign.clone(), - source_transactions_mortality: right_transactions_mortality, + source_transaction_params: TransactionParams { + signer: right_sign.clone(), + mortality: right_transactions_mortality, + }, target_client: left_client.clone(), - target_sign: left_sign.clone(), - target_transactions_mortality: left_transactions_mortality, + target_transaction_params: TransactionParams { + signer: left_sign.clone(), + mortality: left_transactions_mortality, + }, source_to_target_headers_relay: Some(right_to_left_on_demand_headers.clone()), target_to_source_headers_relay: Some(left_to_right_on_demand_headers.clone()), lane_id: lane, @@ -561,3 +594,34 @@ impl RelayHeadersAndMessages { }) } } + +/// Sign and submit transaction with given call to the chain. +async fn submit_signed_extrinsic>( + client: Client, + sign: C::AccountKeyPair, + call: CallOf, +) -> anyhow::Result<()> +where + AccountIdOf: From<<::AccountKeyPair as Pair>::Public>, + CallOf: 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| { + Bytes( + C::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash, + signer: sign, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(call, transaction_nonce), + }) + .encode(), + ) + }) + .await + .map(drop) + .map_err(|e| anyhow::format_err!("{}", e)) +} diff --git a/relays/bin-substrate/src/cli/relay_messages.rs b/relays/bin-substrate/src/cli/relay_messages.rs index e47abfc5d9..521d00d50a 100644 --- a/relays/bin-substrate/src/cli/relay_messages.rs +++ b/relays/bin-substrate/src/cli/relay_messages.rs @@ -18,7 +18,7 @@ use structopt::StructOpt; use strum::{EnumString, EnumVariantNames, VariantNames}; use messages_relay::relay_strategy::MixStrategy; -use substrate_relay_helper::messages_lane::MessagesRelayParams; +use substrate_relay_helper::{messages_lane::MessagesRelayParams, TransactionParams}; use crate::{ cli::{ @@ -75,22 +75,26 @@ impl RelayMessages { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_full_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; + let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; let source_sign = self.source_sign.to_keypair::()?; let source_transactions_mortality = self.source_sign.transactions_mortality()?; - let target_client = self.target.to_client::().await?; + let target_client = self.target.to_client::(TARGET_RUNTIME_VERSION).await?; let target_sign = self.target_sign.to_keypair::()?; let target_transactions_mortality = self.target_sign.transactions_mortality()?; let relayer_mode = self.relayer_mode.into(); let relay_strategy = MixStrategy::new(relayer_mode); - relay_messages(MessagesRelayParams { + substrate_relay_helper::messages_lane::run::(MessagesRelayParams { source_client, - source_sign, - source_transactions_mortality, + source_transaction_params: TransactionParams { + signer: source_sign, + mortality: source_transactions_mortality, + }, target_client, - target_sign, - target_transactions_mortality, + target_transaction_params: TransactionParams { + signer: target_sign, + mortality: target_transactions_mortality, + }, source_to_target_headers_relay: None, target_to_source_headers_relay: None, lane_id: self.lane.into(), diff --git a/relays/bin-substrate/src/cli/resubmit_transactions.rs b/relays/bin-substrate/src/cli/resubmit_transactions.rs index 64663d7e8e..8b021df863 100644 --- a/relays/bin-substrate/src/cli/resubmit_transactions.rs +++ b/relays/bin-substrate/src/cli/resubmit_transactions.rs @@ -19,7 +19,8 @@ use crate::cli::{Balance, TargetConnectionParams, TargetSigningParams}; use codec::{Decode, Encode}; use num_traits::{One, Zero}; use relay_substrate_client::{ - BlockWithJustification, Chain, Client, Error as SubstrateError, HeaderOf, TransactionSignScheme, + BlockWithJustification, Chain, Client, Error as SubstrateError, HeaderOf, SignParam, + TransactionSignScheme, }; use relay_utils::FailedClient; use sp_core::Bytes; @@ -90,18 +91,24 @@ macro_rules! select_bridge { RelayChain::Millau => { type Target = relay_millau_client::Millau; type TargetSign = relay_millau_client::Millau; + const TARGET_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); $generic }, RelayChain::Kusama => { type Target = relay_kusama_client::Kusama; type TargetSign = relay_kusama_client::Kusama; + const TARGET_RUNTIME_VERSION: Option = + Some(bp_kusama::VERSION); $generic }, RelayChain::Polkadot => { type Target = relay_polkadot_client::Polkadot; type TargetSign = relay_polkadot_client::Polkadot; + const TARGET_RUNTIME_VERSION: Option = + Some(bp_polkadot::VERSION); $generic }, @@ -114,7 +121,7 @@ impl ResubmitTransactions { pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.chain, { let relay_loop_name = format!("ResubmitTransactions{}", Target::NAME); - let client = self.target.to_client::().await?; + let client = self.target.to_client::(TARGET_RUNTIME_VERSION).await?; let key_pair = self.target_sign.to_keypair::()?; relay_utils::relay_loop((), client) @@ -411,6 +418,7 @@ async fn update_transaction_tip>( })?; let old_tip = unsigned_tx.tip; + let (spec_version, transaction_version) = client.simple_runtime_version().await?; while current_priority < target_priority { let next_tip = unsigned_tx.tip + tip_step; if next_tip > tip_limit { @@ -430,12 +438,14 @@ async fn update_transaction_tip>( current_priority = client .validate_transaction( at_block, - S::sign_transaction( - *client.genesis_hash(), - key_pair, - relay_substrate_client::TransactionEra::immortal(), - unsigned_tx.clone(), - ), + S::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: key_pair.clone(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: unsigned_tx.clone(), + }), ) .await?? .priority; @@ -451,12 +461,14 @@ async fn update_transaction_tip>( Ok(( old_tip != unsigned_tx.tip, - S::sign_transaction( - *client.genesis_hash(), - key_pair, - relay_substrate_client::TransactionEra::immortal(), - unsigned_tx, - ), + S::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: *client.genesis_hash(), + signer: key_pair.clone(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: unsigned_tx, + }), )) } diff --git a/relays/bin-substrate/src/cli/send_message.rs b/relays/bin-substrate/src/cli/send_message.rs index 3e77ad8342..52eab9c64e 100644 --- a/relays/bin-substrate/src/cli/send_message.rs +++ b/relays/bin-substrate/src/cli/send_message.rs @@ -22,10 +22,10 @@ use crate::cli::{ SourceSigningParams, TargetSigningParams, }; use bp_message_dispatch::{CallOrigin, MessagePayload}; -use bp_runtime::BalanceOf; +use bp_runtime::{BalanceOf, Chain as _}; use codec::Encode; use frame_support::weights::Weight; -use relay_substrate_client::{Chain, TransactionSignScheme, UnsignedTransaction}; +use relay_substrate_client::{Chain, SignParam, TransactionSignScheme, UnsignedTransaction}; use sp_core::{Bytes, Pair}; use sp_runtime::{traits::IdentifyAccount, AccountId32, MultiSignature, MultiSigner}; use std::fmt::Debug; @@ -154,7 +154,7 @@ impl SendMessage { crate::select_full_bridge!(self.bridge, { let payload = self.encode_payload()?; - let source_client = self.source.to_client::().await?; + let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; let source_sign = self.source_sign.to_keypair::()?; let lane = self.lane.clone().into(); @@ -179,25 +179,31 @@ impl SendMessage { })?; let source_genesis_hash = *source_client.genesis_hash(); + let (spec_version, transaction_version) = + source_client.simple_runtime_version().await?; let estimated_transaction_fee = source_client .estimate_extrinsic_fee(Bytes( - Source::sign_transaction( - source_genesis_hash, - &source_sign, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(send_message_call.clone(), 0), - ) + Source::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: source_sign.clone(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(send_message_call.clone(), 0), + }) .encode(), )) .await?; source_client .submit_signed_extrinsic(source_sign.public().into(), move |_, transaction_nonce| { - let signed_source_call = Source::sign_transaction( - source_genesis_hash, - &source_sign, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(send_message_call, transaction_nonce), - ) + let signed_source_call = Source::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: source_sign.clone(), + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new(send_message_call, transaction_nonce), + }) .encode(); log::info!( diff --git a/relays/bin-substrate/src/cli/swap_tokens.rs b/relays/bin-substrate/src/cli/swap_tokens.rs index dbe46f4690..16ec0d6a6f 100644 --- a/relays/bin-substrate/src/cli/swap_tokens.rs +++ b/relays/bin-substrate/src/cli/swap_tokens.rs @@ -29,10 +29,10 @@ use strum::{EnumString, EnumVariantNames, VariantNames}; use frame_support::dispatch::GetDispatchInfo; use relay_substrate_client::{ AccountIdOf, AccountPublicOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithBalances, - Client, Error as SubstrateError, HashOf, SignatureOf, Subscription, TransactionSignScheme, - TransactionStatusOf, UnsignedTransaction, + Client, Error as SubstrateError, HashOf, SignParam, SignatureOf, Subscription, + TransactionSignScheme, TransactionStatusOf, UnsignedTransaction, }; -use sp_core::{blake2_256, storage::StorageKey, Bytes, Pair, H256, U256}; +use sp_core::{blake2_256, storage::StorageKey, Bytes, Pair, U256}; use sp_runtime::traits::{Convert, Header as HeaderT}; use crate::cli::{ @@ -98,6 +98,13 @@ macro_rules! select_bridge { SwapTokensBridge::MillauToRialto => { type Source = relay_millau_client::Millau; type Target = relay_rialto_client::Rialto; + const SOURCE_SPEC_VERSION: u32 = millau_runtime::VERSION.spec_version; + const TARGET_SPEC_VERSION: u32 = rialto_runtime::VERSION.spec_version; + + const SOURCE_RUNTIME_VERSION: Option = + Some(millau_runtime::VERSION); + const TARGET_RUNTIME_VERSION: Option = + Some(rialto_runtime::VERSION); type FromSwapToThisAccountIdConverter = bp_rialto::AccountIdConverter; @@ -114,9 +121,6 @@ macro_rules! select_bridge { const SOURCE_CHAIN_ID: bp_runtime::ChainId = bp_runtime::MILLAU_CHAIN_ID; const TARGET_CHAIN_ID: bp_runtime::ChainId = bp_runtime::RIALTO_CHAIN_ID; - const SOURCE_SPEC_VERSION: u32 = millau_runtime::VERSION.spec_version; - const TARGET_SPEC_VERSION: u32 = rialto_runtime::VERSION.spec_version; - const SOURCE_TO_TARGET_LANE_ID: bp_messages::LaneId = *b"swap"; const TARGET_TO_SOURCE_LANE_ID: bp_messages::LaneId = [0, 0, 0, 0]; @@ -130,9 +134,9 @@ impl SwapTokens { /// Run the command. pub async fn run(self) -> anyhow::Result<()> { select_bridge!(self.bridge, { - let source_client = self.source.to_client::().await?; + let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; let source_sign = self.source_sign.to_keypair::()?; - let target_client = self.target.to_client::().await?; + let target_client = self.target.to_client::(TARGET_RUNTIME_VERSION).await?; let target_sign = self.target_sign.to_keypair::()?; // names of variables in this function are matching names used by the @@ -234,18 +238,25 @@ impl SwapTokens { // start tokens swap let source_genesis_hash = *source_client.genesis_hash(); let create_swap_signer = source_sign.clone(); + let (spec_version, transaction_version) = + source_client.simple_runtime_version().await?; let swap_created_at = wait_until_transaction_is_finalized::( source_client .submit_and_watch_signed_extrinsic( accounts.source_account_at_this_chain.clone(), move |_, transaction_nonce| { Bytes( - Source::sign_transaction( - source_genesis_hash, - &create_swap_signer, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new(create_swap_call, transaction_nonce), - ) + Source::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: create_swap_signer, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( + create_swap_call, + transaction_nonce, + ), + }) .encode(), ) }, @@ -255,11 +266,10 @@ impl SwapTokens { .await?; // read state of swap after it has been created - let token_swap_hash: H256 = token_swap.using_encoded(blake2_256).into(); - let token_swap_storage_key = bp_runtime::storage_map_final_key_identity( + let token_swap_hash = token_swap.hash(); + let token_swap_storage_key = bp_token_swap::storage_keys::pending_swaps_key( TOKEN_SWAP_PALLET_NAME, - pallet_bridge_token_swap::PENDING_SWAPS_MAP_NAME, - token_swap_hash.as_ref(), + token_swap_hash, ); match read_token_swap_state(&source_client, swap_created_at, &token_swap_storage_key) .await? @@ -369,21 +379,25 @@ impl SwapTokens { // send `claim_swap` message let target_genesis_hash = *target_client.genesis_hash(); + let (spec_version, transaction_version) = + target_client.simple_runtime_version().await?; let _ = wait_until_transaction_is_finalized::( target_client .submit_and_watch_signed_extrinsic( accounts.target_account_at_bridged_chain.clone(), move |_, transaction_nonce| { Bytes( - Target::sign_transaction( - target_genesis_hash, - &target_sign, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + Target::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: target_genesis_hash, + signer: target_sign, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( send_message_call, transaction_nonce, ), - ) + }) .encode(), ) }, @@ -409,21 +423,25 @@ impl SwapTokens { log::info!(target: "bridge", "Cancelling the swap"); let cancel_swap_call: CallOf = pallet_bridge_token_swap::Call::cancel_swap { swap: token_swap.clone() }.into(); + let (spec_version, transaction_version) = + source_client.simple_runtime_version().await?; let _ = wait_until_transaction_is_finalized::( source_client .submit_and_watch_signed_extrinsic( accounts.source_account_at_this_chain.clone(), move |_, transaction_nonce| { Bytes( - Source::sign_transaction( - source_genesis_hash, - &source_sign, - relay_substrate_client::TransactionEra::immortal(), - UnsignedTransaction::new( + Source::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: source_genesis_hash, + signer: source_sign, + era: relay_substrate_client::TransactionEra::immortal(), + unsigned: UnsignedTransaction::new( cancel_swap_call, transaction_nonce, ), - ) + }) .encode(), ) }, @@ -673,6 +691,7 @@ async fn read_token_swap_state( #[cfg(test)] mod tests { use super::*; + use crate::cli::{RuntimeVersionType, SourceRuntimeVersionParams, TargetRuntimeVersionParams}; #[test] fn swap_tokens_millau_to_rialto_no_lock() { @@ -706,6 +725,11 @@ mod tests { source_host: "127.0.0.1".into(), source_port: 9000, source_secure: false, + source_runtime_version: SourceRuntimeVersionParams { + source_version_mode: RuntimeVersionType::Bundle, + source_spec_version: None, + source_transaction_version: None, + } }, source_sign: SourceSigningParams { source_signer: Some("//Alice".into()), @@ -718,6 +742,11 @@ mod tests { target_host: "127.0.0.1".into(), target_port: 9001, 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("//Bob".into()), @@ -767,6 +796,11 @@ mod tests { source_host: "127.0.0.1".into(), source_port: 9000, source_secure: false, + source_runtime_version: SourceRuntimeVersionParams { + source_version_mode: RuntimeVersionType::Bundle, + source_spec_version: None, + source_transaction_version: None, + } }, source_sign: SourceSigningParams { source_signer: Some("//Alice".into()), @@ -779,6 +813,11 @@ mod tests { target_host: "127.0.0.1".into(), target_port: 9001, 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("//Bob".into()), diff --git a/relays/client-kusama/src/lib.rs b/relays/client-kusama/src/lib.rs index a93726620f..bdd7b74ffb 100644 --- a/relays/client-kusama/src/lib.rs +++ b/relays/client-kusama/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Kusama chain. +use bp_messages::MessageNonce; use codec::Encode; +use frame_support::weights::Weight; use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, + Chain, ChainBase, ChainWithBalances, ChainWithMessages, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -44,10 +46,21 @@ impl ChainBase for Kusama { type Balance = bp_kusama::Balance; type Index = bp_kusama::Nonce; type Signature = bp_kusama::Signature; + + fn max_extrinsic_size() -> u32 { + bp_kusama::Kusama::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_kusama::Kusama::max_extrinsic_weight() + } } impl Chain for Kusama { const NAME: &'static str = "Kusama"; + const TOKEN_ID: Option<&'static str> = Some("kusama"); + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_kusama::BEST_FINALIZED_KUSAMA_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_kusama::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_kusama::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -57,6 +70,28 @@ impl Chain for Kusama { type WeightToFee = bp_kusama::WeightToFee; } +impl ChainWithMessages for Kusama { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_kusama::WITH_KUSAMA_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_kusama::TO_KUSAMA_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_kusama::FROM_KUSAMA_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_kusama::FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_kusama::FROM_KUSAMA_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_kusama::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_kusama::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_kusama::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + impl ChainWithBalances for Kusama { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_kusama::account_info_storage_key(account_id)) @@ -68,26 +103,22 @@ impl TransactionSignScheme for Kusama { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = crate::runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::new( - unsigned.call, + param.unsigned.call.clone(), bp_kusama::SignedExtensions::new( - bp_kusama::VERSION, - era, - genesis_hash, - unsigned.nonce, - unsigned.tip, + param.spec_version, + param.transaction_version, + param.era, + param.genesis_hash, + param.unsigned.nonce, + param.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 signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); bp_kusama::UncheckedExtrinsic::new_signed( diff --git a/relays/client-millau/Cargo.toml b/relays/client-millau/Cargo.toml index 49d9dade15..da3d4e7fe1 100644 --- a/relays/client-millau/Cargo.toml +++ b/relays/client-millau/Cargo.toml @@ -12,6 +12,7 @@ relay-utils = { path = "../utils" } # Supported Chains +bp-messages = { path = "../../primitives/messages" } bp-millau = { path = "../../primitives/chain-millau" } millau-runtime = { path = "../../bin/millau/runtime" } diff --git a/relays/client-millau/src/lib.rs b/relays/client-millau/src/lib.rs index 3f1aba1f3b..3b441e9a0e 100644 --- a/relays/client-millau/src/lib.rs +++ b/relays/client-millau/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Millau-Substrate chain. +use bp_messages::MessageNonce; use codec::{Compact, Decode, Encode}; +use frame_support::weights::Weight; use relay_substrate_client::{ - BalanceOf, Chain, ChainBase, ChainWithBalances, IndexOf, TransactionEraOf, + BalanceOf, Chain, ChainBase, ChainWithBalances, ChainWithMessages, IndexOf, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -42,10 +44,44 @@ impl ChainBase for Millau { type Balance = millau_runtime::Balance; type Index = millau_runtime::Index; type Signature = millau_runtime::Signature; + + fn max_extrinsic_size() -> u32 { + bp_millau::Millau::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_millau::Millau::max_extrinsic_weight() + } +} + +impl ChainWithMessages for Millau { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_millau::TO_MILLAU_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_millau::TO_MILLAU_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_millau::FROM_MILLAU_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_millau::FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_millau::FROM_MILLAU_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_millau::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_millau::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_millau::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); } impl Chain for Millau { const NAME: &'static str = "Millau"; + // Rialto token has no value, but we associate it with KSM token + const TOKEN_ID: Option<&'static str> = Some("kusama"); + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_millau::BEST_FINALIZED_MILLAU_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_millau::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_millau::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -69,35 +105,30 @@ impl TransactionSignScheme for Millau { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = millau_runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::from_raw( - unsigned.call, + param.unsigned.call.clone(), ( frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(era.frame_era()), - frame_system::CheckNonce::::from(unsigned.nonce), + frame_system::CheckEra::::from(param.era.frame_era()), + frame_system::CheckNonce::::from(param.unsigned.nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::::from(param.unsigned.tip), ), ( - millau_runtime::VERSION.spec_version, - millau_runtime::VERSION.transaction_version, - genesis_hash, - era.signed_payload(genesis_hash), + param.spec_version, + param.transaction_version, + param.genesis_hash, + param.era.signed_payload(param.genesis_hash), (), (), (), ), ); - let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); - let signer: sp_runtime::MultiSigner = signer.public().into(); + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); millau_runtime::UncheckedExtrinsic::new_signed( diff --git a/relays/client-polkadot/src/lib.rs b/relays/client-polkadot/src/lib.rs index e6ceabf583..ca23fe3199 100644 --- a/relays/client-polkadot/src/lib.rs +++ b/relays/client-polkadot/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Polkadot chain. +use bp_messages::MessageNonce; use codec::Encode; +use frame_support::weights::Weight; use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, + Chain, ChainBase, ChainWithBalances, ChainWithMessages, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -44,10 +46,21 @@ impl ChainBase for Polkadot { type Balance = bp_polkadot::Balance; type Index = bp_polkadot::Nonce; type Signature = bp_polkadot::Signature; + + fn max_extrinsic_size() -> u32 { + bp_polkadot::Polkadot::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_polkadot::Polkadot::max_extrinsic_weight() + } } impl Chain for Polkadot { const NAME: &'static str = "Polkadot"; + const TOKEN_ID: Option<&'static str> = Some("polkadot"); + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_polkadot::BEST_FINALIZED_POLKADOT_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_polkadot::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_polkadot::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -57,6 +70,28 @@ impl Chain for Polkadot { type WeightToFee = bp_polkadot::WeightToFee; } +impl ChainWithMessages for Polkadot { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_polkadot::WITH_POLKADOT_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_polkadot::TO_POLKADOT_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_polkadot::FROM_POLKADOT_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_polkadot::FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_polkadot::FROM_POLKADOT_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_polkadot::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_polkadot::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_polkadot::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + impl ChainWithBalances for Polkadot { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_polkadot::account_info_storage_key(account_id)) @@ -68,26 +103,22 @@ impl TransactionSignScheme for Polkadot { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = crate::runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::new( - unsigned.call, + param.unsigned.call.clone(), bp_polkadot::SignedExtensions::new( - bp_polkadot::VERSION, - era, - genesis_hash, - unsigned.nonce, - unsigned.tip, + param.spec_version, + param.transaction_version, + param.era, + param.genesis_hash, + param.unsigned.nonce, + param.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 signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); bp_polkadot::UncheckedExtrinsic::new_signed( diff --git a/relays/client-rialto-parachain/src/lib.rs b/relays/client-rialto-parachain/src/lib.rs index ca299a0eeb..65bf46f660 100644 --- a/relays/client-rialto-parachain/src/lib.rs +++ b/relays/client-rialto-parachain/src/lib.rs @@ -16,6 +16,7 @@ //! Types used to connect to the Rialto-Substrate chain. +use frame_support::weights::Weight; use relay_substrate_client::{Chain, ChainBase}; use std::time::Duration; @@ -37,10 +38,21 @@ impl ChainBase for RialtoParachain { type Balance = rialto_parachain_runtime::Balance; type Index = rialto_parachain_runtime::Index; type Signature = rialto_parachain_runtime::Signature; + + fn max_extrinsic_size() -> u32 { + bp_rialto::Rialto::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_rialto::Rialto::max_extrinsic_weight() + } } impl Chain for RialtoParachain { const NAME: &'static str = "RialtoParachain"; + const TOKEN_ID: Option<&'static str> = None; + // should be fixed/changed in https://github.com/paritytech/parity-bridges-common/pull/1199 + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = ""; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/relays/client-rialto/Cargo.toml b/relays/client-rialto/Cargo.toml index 3132b26d27..483812ca80 100644 --- a/relays/client-rialto/Cargo.toml +++ b/relays/client-rialto/Cargo.toml @@ -12,6 +12,7 @@ relay-utils = { path = "../utils" } # Bridge dependencies +bp-messages = { path = "../../primitives/messages" } bp-rialto = { path = "../../primitives/chain-rialto" } rialto-runtime = { path = "../../bin/rialto/runtime" } diff --git a/relays/client-rialto/src/lib.rs b/relays/client-rialto/src/lib.rs index 42ed8bce3b..b3a3bd1eaf 100644 --- a/relays/client-rialto/src/lib.rs +++ b/relays/client-rialto/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Rialto-Substrate chain. +use bp_messages::MessageNonce; use codec::{Compact, Decode, Encode}; +use frame_support::weights::Weight; use relay_substrate_client::{ - BalanceOf, Chain, ChainBase, ChainWithBalances, IndexOf, TransactionEraOf, + BalanceOf, Chain, ChainBase, ChainWithBalances, ChainWithMessages, IndexOf, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -42,10 +44,22 @@ impl ChainBase for Rialto { type Balance = rialto_runtime::Balance; type Index = rialto_runtime::Index; type Signature = rialto_runtime::Signature; + + fn max_extrinsic_size() -> u32 { + bp_rialto::Rialto::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_rialto::Rialto::max_extrinsic_weight() + } } impl Chain for Rialto { const NAME: &'static str = "Rialto"; + // Rialto token has no value, but we associate it with DOT token + const TOKEN_ID: Option<&'static str> = Some("polkadot"); + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rialto::BEST_FINALIZED_RIALTO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(5); const STORAGE_PROOF_OVERHEAD: u32 = bp_rialto::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rialto::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -55,6 +69,28 @@ impl Chain for Rialto { type WeightToFee = bp_rialto::WeightToFee; } +impl ChainWithMessages for Rialto { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rialto::TO_RIALTO_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_rialto::TO_RIALTO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_rialto::FROM_RIALTO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_rialto::FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_rialto::FROM_RIALTO_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_rialto::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_rialto::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + impl ChainWithBalances for Rialto { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { use frame_support::storage::generator::StorageMap; @@ -69,35 +105,30 @@ impl TransactionSignScheme for Rialto { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = rialto_runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::from_raw( - unsigned.call, + param.unsigned.call.clone(), ( frame_system::CheckSpecVersion::::new(), frame_system::CheckTxVersion::::new(), frame_system::CheckGenesis::::new(), - frame_system::CheckEra::::from(era.frame_era()), - frame_system::CheckNonce::::from(unsigned.nonce), + frame_system::CheckEra::::from(param.era.frame_era()), + frame_system::CheckNonce::::from(param.unsigned.nonce), frame_system::CheckWeight::::new(), - pallet_transaction_payment::ChargeTransactionPayment::::from(unsigned.tip), + pallet_transaction_payment::ChargeTransactionPayment::::from(param.unsigned.tip), ), ( - rialto_runtime::VERSION.spec_version, - rialto_runtime::VERSION.transaction_version, - genesis_hash, - era.signed_payload(genesis_hash), + param.spec_version, + param.transaction_version, + param.genesis_hash, + param.era.signed_payload(param.genesis_hash), (), (), (), ), ); - let signature = raw_payload.using_encoded(|payload| signer.sign(payload)); - let signer: sp_runtime::MultiSigner = signer.public().into(); + let signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); rialto_runtime::UncheckedExtrinsic::new_signed( diff --git a/relays/client-rococo/src/lib.rs b/relays/client-rococo/src/lib.rs index ad61e3cfd6..794e82efb0 100644 --- a/relays/client-rococo/src/lib.rs +++ b/relays/client-rococo/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Rococo-Substrate chain. +use bp_messages::MessageNonce; use codec::Encode; +use frame_support::weights::Weight; use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, + Chain, ChainBase, ChainWithBalances, ChainWithMessages, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -47,10 +49,21 @@ impl ChainBase for Rococo { type Balance = bp_rococo::Balance; type Index = bp_rococo::Nonce; type Signature = bp_rococo::Signature; + + fn max_extrinsic_size() -> u32 { + bp_rococo::Rococo::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_rococo::Rococo::max_extrinsic_weight() + } } impl Chain for Rococo { const NAME: &'static str = "Rococo"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_rococo::BEST_FINALIZED_ROCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_rococo::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_rococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -60,6 +73,28 @@ impl Chain for Rococo { type WeightToFee = bp_rococo::WeightToFee; } +impl ChainWithMessages for Rococo { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_rococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_rococo::TO_ROCOCO_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_rococo::TO_ROCOCO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_rococo::FROM_ROCOCO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_rococo::FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_rococo::FROM_ROCOCO_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_rococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_rococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_rococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + impl ChainWithBalances for Rococo { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_rococo::account_info_storage_key(account_id)) @@ -71,26 +106,22 @@ impl TransactionSignScheme for Rococo { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = crate::runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::new( - unsigned.call, + param.unsigned.call.clone(), bp_rococo::SignedExtensions::new( - bp_rococo::VERSION, - era, - genesis_hash, - unsigned.nonce, - unsigned.tip, + param.spec_version, + param.transaction_version, + param.era, + param.genesis_hash, + param.unsigned.nonce, + param.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 signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); bp_rococo::UncheckedExtrinsic::new_signed( diff --git a/relays/client-rococo/src/runtime.rs b/relays/client-rococo/src/runtime.rs index effe6e5c60..b138080599 100644 --- a/relays/client-rococo/src/runtime.rs +++ b/relays/client-rococo/src/runtime.rs @@ -17,9 +17,9 @@ //! Types that are specific to the Rococo runtime. use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::PolkadotLike; +use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; use bp_runtime::Chain; -use codec::{Decode, Encode}; +use codec::{Compact, Decode, Encode}; use frame_support::weights::Weight; use scale_info::TypeInfo; @@ -66,12 +66,15 @@ pub enum Call { /// System pallet. #[codec(index = 0)] System(SystemCall), + /// Balances pallet. + #[codec(index = 4)] + Balances(BalancesCall), /// Wococo bridge pallet. #[codec(index = 41)] BridgeGrandpaWococo(BridgeGrandpaWococoCall), /// Wococo messages pallet. #[codec(index = 44)] - BridgeMessagesWococo(BridgeMessagesWococoCall), + BridgeWococoMessages(BridgeWococoMessagesCall), } #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] @@ -81,6 +84,13 @@ pub enum SystemCall { remark(Vec), } +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BalancesCall { + #[codec(index = 0)] + transfer(AccountAddress, Compact), +} + #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] #[allow(non_camel_case_types)] pub enum BridgeGrandpaWococoCall { @@ -95,7 +105,7 @@ pub enum BridgeGrandpaWococoCall { #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] #[allow(non_camel_case_types)] -pub enum BridgeMessagesWococoCall { +pub enum BridgeWococoMessagesCall { #[codec(index = 3)] send_message( LaneId, diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml index 2eb07fdcde..eacaa929a9 100644 --- a/relays/client-substrate/Cargo.toml +++ b/relays/client-substrate/Cargo.toml @@ -20,7 +20,9 @@ thiserror = "1.0.26" # Bridge dependencies bp-header-chain = { path = "../../primitives/header-chain" } +bp-messages = { path = "../../primitives/messages" } bp-runtime = { path = "../../primitives/runtime" } +pallet-bridge-messages = { path = "../../modules/messages" } finality-relay = { path = "../finality" } relay-utils = { path = "../utils" } diff --git a/relays/client-substrate/src/chain.rs b/relays/client-substrate/src/chain.rs index 75789ce37f..48dcc48132 100644 --- a/relays/client-substrate/src/chain.rs +++ b/relays/client-substrate/src/chain.rs @@ -14,9 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . +use bp_messages::MessageNonce; use bp_runtime::{Chain as ChainBase, HashOf, TransactionEraOf}; use codec::{Codec, Encode}; -use frame_support::weights::WeightToFeePolynomial; +use frame_support::weights::{Weight, WeightToFeePolynomial}; use jsonrpsee_ws_client::types::{DeserializeOwned, Serialize}; use num_traits::Zero; use sc_transaction_pool_api::TransactionStatus; @@ -32,6 +33,18 @@ use std::{fmt::Debug, time::Duration}; pub trait Chain: ChainBase + Clone { /// Chain name. const NAME: &'static str; + /// Identifier of the basic token of the chain (if applicable). + /// + /// This identifier is used to fetch token price. In case of testnets, you may either + /// set it to `None`, or associate testnet with one of the existing tokens. + const TOKEN_ID: Option<&'static str>; + /// Name of the runtime API method that is returning best known finalized header number + /// and hash (as tuple). + /// + /// Keep in mind that this method is normally provided by the other chain, which is + /// bridged with this chain. + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str; + /// Average block interval. /// /// How often blocks are produced on that chain. It's suggested to set this value @@ -45,12 +58,53 @@ pub trait Chain: ChainBase + Clone { /// Block type. type SignedBlock: Member + Serialize + DeserializeOwned + BlockWithJustification; /// The aggregated `Call` type. - type Call: Clone + Dispatchable + Debug; + type Call: Clone + Codec + Dispatchable + Debug + Send; /// Type that is used by the chain, to convert from weight to fee. type WeightToFee: WeightToFeePolynomial; } +/// Substrate-based chain with messaging support from minimal relay-client point of view. +pub trait ChainWithMessages: Chain { + /// Name of the bridge messages pallet (used in `construct_runtime` macro call) that is deployed + /// at some other chain to bridge with this `ChainWithMessages`. + /// + /// We assume that all chains that are bridging with this `ChainWithMessages` are using + /// the same name. + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str; + + /// Name of the `ToOutboundLaneApi::message_details` runtime API method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str; + /// Name of the `ToOutboundLaneApi::latest_received_nonce` runtime API + /// method. The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str; + + /// Name of the `FromInboundLaneApi::latest_received_nonce` runtime method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str; + /// Name of the `FromInboundLaneApi::latest_confirmed_nonce` runtime method. + /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str; + /// Name of the `FromInboundLaneApi::unrewarded_relayers_state` runtime + /// method. The method is provided by the runtime that is bridged with this `ChainWithMessages`. + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str; + + /// Additional weight of the dispatch fee payment if dispatch is paid at the target chain + /// and this `ChainWithMessages` is the target chain. + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight; + + /// Maximal number of unrewarded relayers in a single confirmation transaction at this + /// `ChainWithMessages`. + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce; + /// Maximal number of unconfirmed messages in a single confirmation transaction at this + /// `ChainWithMessages`. + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce; + + /// Weights of message pallet calls. + type WeightInfo: pallet_bridge_messages::WeightInfoExt; +} + /// Call type used by the chain. pub type CallOf = ::Call; /// Weight-to-Fee type used by the chain. @@ -102,6 +156,9 @@ impl UnsignedTransaction { } } +/// Account key pair used by transactions signing scheme. +pub type AccountKeyPairOf = ::AccountKeyPair; + /// Substrate-based chain transactions signing scheme. pub trait TransactionSignScheme { /// Chain that this scheme is to be used. @@ -112,12 +169,9 @@ pub trait TransactionSignScheme { type SignedTransaction: Clone + Debug + Codec + Send + 'static; /// Create transaction for given runtime call, signed by given account. - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction; + fn sign_transaction(param: SignParam) -> Self::SignedTransaction + where + Self: Sized; /// Returns true if transaction is signed. fn is_signed(tx: &Self::SignedTransaction) -> bool; @@ -131,6 +185,22 @@ pub trait TransactionSignScheme { fn parse_transaction(tx: Self::SignedTransaction) -> Option>; } +/// Sign transaction parameters +pub struct SignParam { + /// Version of the runtime specification. + pub spec_version: u32, + /// Transaction version + pub transaction_version: u32, + /// Hash of the genesis block. + pub genesis_hash: ::Hash, + /// Signer account + pub signer: T::AccountKeyPair, + /// Transaction era used by the chain. + pub era: TransactionEraOf, + /// Transaction before it is signed. + pub unsigned: UnsignedTransaction, +} + impl BlockWithJustification for SignedBlock { fn header(&self) -> Block::Header { self.block.header().clone() diff --git a/relays/client-substrate/src/client.rs b/relays/client-substrate/src/client.rs index 1902875c93..74bf481d54 100644 --- a/relays/client-substrate/src/client.rs +++ b/relays/client-substrate/src/client.rs @@ -34,7 +34,7 @@ use jsonrpsee_ws_client::{ }, WsClient as RpcClient, WsClientBuilder as RpcClientBuilder, }; -use num_traits::{Bounded, Zero}; +use num_traits::{Bounded, CheckedSub, One, Zero}; use pallet_balances::AccountData; use pallet_transaction_payment::InclusionFee; use relay_utils::{relay_loop::RECONNECT_DELAY, HeaderId}; @@ -60,6 +60,17 @@ pub struct Subscription(Mutex>>); /// Opaque GRANDPA authorities set. pub type OpaqueGrandpaAuthoritiesSet = Vec; +/// Chain runtime version in client +#[derive(Clone, Debug)] +pub enum ChainRuntimeVersion { + /// Auto query from chain. + Auto, + /// Custom runtime version, defined by user. + /// the first is `spec_version` + /// the second is `transaction_version` + Custom(u32, u32), +} + /// Substrate client type. /// /// Cloning `Client` is a cheap operation. @@ -77,6 +88,8 @@ pub struct Client { /// transactions will be rejected from the pool. This lock is here to prevent situations like /// that. submit_signed_extrinsic_lock: Arc>, + /// Saved chain runtime version + chain_runtime_version: ChainRuntimeVersion, } #[async_trait] @@ -99,6 +112,7 @@ impl Clone for Client { client: self.client.clone(), genesis_hash: self.genesis_hash, submit_signed_extrinsic_lock: self.submit_signed_extrinsic_lock.clone(), + chain_runtime_version: self.chain_runtime_version.clone(), } } } @@ -144,12 +158,14 @@ impl Client { }) .await??; + let chain_runtime_version = params.chain_runtime_version.clone(); Ok(Self { tokio, params, client, genesis_hash, submit_signed_extrinsic_lock: Arc::new(Mutex::new(())), + chain_runtime_version, }) } @@ -178,6 +194,19 @@ impl Client { } impl Client { + /// Return simple runtime version, only include `spec_version` and `transaction_version`. + pub async fn simple_runtime_version(&self) -> Result<(u32, u32)> { + let (spec_version, transaction_version) = match self.chain_runtime_version { + ChainRuntimeVersion::Auto => { + let runtime_version = self.runtime_version().await?; + (runtime_version.spec_version, runtime_version.transaction_version) + }, + ChainRuntimeVersion::Custom(spec_version, transaction_version) => + (spec_version, transaction_version), + }; + Ok((spec_version, transaction_version)) + } + /// Returns true if client is connected to at least one peer and is in synced state. pub async fn ensure_synced(&self) -> Result<()> { self.jsonrpsee_execute(|client| async move { @@ -349,7 +378,17 @@ impl Client { let _guard = self.submit_signed_extrinsic_lock.lock().await; let transaction_nonce = self.next_account_index(extrinsic_signer).await?; let best_header = self.best_header().await?; - let best_header_id = HeaderId(*best_header.number(), best_header.hash()); + + // By using parent of best block here, we are protecing again best-block reorganizations. + // E.g. transaction my have been submitted when the best block was `A[num=100]`. Then it has + // been changed to `B[num=100]`. Hash of `A` has been included into transaction signature + // payload. So when signature will be checked, the check will fail and transaction will be + // dropped from the pool. + let best_header_id = match best_header.number().checked_sub(&One::one()) { + Some(parent_block_number) => HeaderId(parent_block_number, *best_header.parent_hash()), + None => HeaderId(*best_header.number(), best_header.hash()), + }; + self.jsonrpsee_execute(move |client| async move { let extrinsic = prepare_extrinsic(best_header_id, transaction_nonce); let tx_hash = Substrate::::author_submit_extrinsic(&*client, extrinsic).await?; diff --git a/relays/client-substrate/src/guard.rs b/relays/client-substrate/src/guard.rs index a064e36234..c31482eec3 100644 --- a/relays/client-substrate/src/guard.rs +++ b/relays/client-substrate/src/guard.rs @@ -181,7 +181,7 @@ impl Environment for Client { #[cfg(test)] mod tests { use super::*; - use frame_support::weights::IdentityFee; + use frame_support::weights::{IdentityFee, Weight}; use futures::{ channel::mpsc::{unbounded, UnboundedReceiver, UnboundedSender}, future::FutureExt, @@ -202,10 +202,19 @@ mod tests { type Balance = u32; type Index = u32; type Signature = sp_runtime::testing::TestSignature; + + fn max_extrinsic_size() -> u32 { + unreachable!() + } + fn max_extrinsic_weight() -> Weight { + unreachable!() + } } impl Chain for TestChain { const NAME: &'static str = "Test"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = "BestTestHeader"; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_millis(1); const STORAGE_PROOF_OVERHEAD: u32 = 0; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = 0; diff --git a/relays/client-substrate/src/lib.rs b/relays/client-substrate/src/lib.rs index 51ddf852b9..dc005506be 100644 --- a/relays/client-substrate/src/lib.rs +++ b/relays/client-substrate/src/lib.rs @@ -24,7 +24,6 @@ mod error; mod rpc; mod sync_header; -pub mod finality_source; pub mod guard; pub mod metrics; @@ -32,10 +31,11 @@ use std::time::Duration; pub use crate::{ chain::{ - BlockWithJustification, CallOf, Chain, ChainWithBalances, TransactionSignScheme, - TransactionStatusOf, UnsignedTransaction, WeightToFeeOf, + AccountKeyPairOf, BlockWithJustification, CallOf, Chain, ChainWithBalances, + ChainWithMessages, SignParam, TransactionSignScheme, TransactionStatusOf, + UnsignedTransaction, WeightToFeeOf, }, - client::{Client, OpaqueGrandpaAuthoritiesSet, Subscription}, + client::{ChainRuntimeVersion, Client, OpaqueGrandpaAuthoritiesSet, Subscription}, error::{Error, Result}, sync_header::SyncHeader, }; @@ -56,11 +56,18 @@ pub struct ConnectionParams { pub port: u16, /// Use secure websocket connection. pub secure: bool, + /// Defined chain runtime version + pub chain_runtime_version: ChainRuntimeVersion, } impl Default for ConnectionParams { fn default() -> Self { - ConnectionParams { host: "localhost".into(), port: 9944, secure: false } + ConnectionParams { + host: "localhost".into(), + port: 9944, + secure: false, + chain_runtime_version: ChainRuntimeVersion::Auto, + } } } diff --git a/relays/client-westend/Cargo.toml b/relays/client-westend/Cargo.toml index 24b05c4f48..9bbb0b6fb1 100644 --- a/relays/client-westend/Cargo.toml +++ b/relays/client-westend/Cargo.toml @@ -16,5 +16,6 @@ bp-westend = { path = "../../primitives/chain-westend" } # 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" } diff --git a/relays/client-westend/src/lib.rs b/relays/client-westend/src/lib.rs index c719d6ea55..004cb5476b 100644 --- a/relays/client-westend/src/lib.rs +++ b/relays/client-westend/src/lib.rs @@ -16,6 +16,7 @@ //! Types used to connect to the Westend chain. +use frame_support::weights::Weight; use relay_substrate_client::{Chain, ChainBase, ChainWithBalances}; use sp_core::storage::StorageKey; use std::time::Duration; @@ -40,10 +41,21 @@ impl ChainBase for Westend { type Balance = bp_westend::Balance; type Index = bp_westend::Nonce; type Signature = bp_westend::Signature; + + fn max_extrinsic_size() -> u32 { + bp_westend::Westend::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_westend::Westend::max_extrinsic_weight() + } } impl Chain for Westend { const NAME: &'static str = "Westend"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_westend::BEST_FINALIZED_WESTEND_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_westend::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_westend::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; diff --git a/relays/client-wococo/src/lib.rs b/relays/client-wococo/src/lib.rs index d61915ec12..1b634930db 100644 --- a/relays/client-wococo/src/lib.rs +++ b/relays/client-wococo/src/lib.rs @@ -16,9 +16,11 @@ //! Types used to connect to the Wococo-Substrate chain. +use bp_messages::MessageNonce; use codec::Encode; +use frame_support::weights::Weight; use relay_substrate_client::{ - Chain, ChainBase, ChainWithBalances, TransactionEraOf, TransactionSignScheme, + Chain, ChainBase, ChainWithBalances, ChainWithMessages, SignParam, TransactionSignScheme, UnsignedTransaction, }; use sp_core::{storage::StorageKey, Pair}; @@ -47,10 +49,21 @@ impl ChainBase for Wococo { type Balance = bp_wococo::Balance; type Index = bp_wococo::Nonce; type Signature = bp_wococo::Signature; + + fn max_extrinsic_size() -> u32 { + bp_wococo::Wococo::max_extrinsic_size() + } + + fn max_extrinsic_weight() -> Weight { + bp_wococo::Wococo::max_extrinsic_weight() + } } impl Chain for Wococo { const NAME: &'static str = "Wococo"; + const TOKEN_ID: Option<&'static str> = None; + const BEST_FINALIZED_HEADER_ID_METHOD: &'static str = + bp_wococo::BEST_FINALIZED_WOCOCO_HEADER_METHOD; const AVERAGE_BLOCK_INTERVAL: Duration = Duration::from_secs(6); const STORAGE_PROOF_OVERHEAD: u32 = bp_wococo::EXTRA_STORAGE_PROOF_SIZE; const MAXIMAL_ENCODED_ACCOUNT_ID_SIZE: u32 = bp_wococo::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE; @@ -60,6 +73,28 @@ impl Chain for Wococo { type WeightToFee = bp_wococo::WeightToFee; } +impl ChainWithMessages for Wococo { + const WITH_CHAIN_MESSAGES_PALLET_NAME: &'static str = + bp_wococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; + const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = + bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_METHOD; + const TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_wococo::TO_WOCOCO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD: &'static str = + bp_wococo::FROM_WOCOCO_LATEST_RECEIVED_NONCE_METHOD; + const FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD: &'static str = + bp_wococo::FROM_WOCOCO_LATEST_CONFIRMED_NONCE_METHOD; + const FROM_CHAIN_UNREWARDED_RELAYERS_STATE: &'static str = + bp_wococo::FROM_WOCOCO_UNREWARDED_RELAYERS_STATE; + const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN: Weight = + bp_wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT; + const MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX: MessageNonce = + bp_wococo::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX; + const MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX: MessageNonce = + bp_wococo::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX; + type WeightInfo = (); +} + impl ChainWithBalances for Wococo { fn account_info_storage_key(account_id: &Self::AccountId) -> StorageKey { StorageKey(bp_wococo::account_info_storage_key(account_id)) @@ -71,26 +106,22 @@ impl TransactionSignScheme for Wococo { type AccountKeyPair = sp_core::sr25519::Pair; type SignedTransaction = crate::runtime::UncheckedExtrinsic; - fn sign_transaction( - genesis_hash: ::Hash, - signer: &Self::AccountKeyPair, - era: TransactionEraOf, - unsigned: UnsignedTransaction, - ) -> Self::SignedTransaction { + fn sign_transaction(param: SignParam) -> Self::SignedTransaction { let raw_payload = SignedPayload::new( - unsigned.call, + param.unsigned.call.clone(), bp_wococo::SignedExtensions::new( - bp_wococo::VERSION, - era, - genesis_hash, - unsigned.nonce, - unsigned.tip, + param.spec_version, + param.transaction_version, + param.era, + param.genesis_hash, + param.unsigned.nonce, + param.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 signature = raw_payload.using_encoded(|payload| param.signer.sign(payload)); + let signer: sp_runtime::MultiSigner = param.signer.public().into(); let (call, extra, _) = raw_payload.deconstruct(); bp_wococo::UncheckedExtrinsic::new_signed( diff --git a/relays/client-wococo/src/runtime.rs b/relays/client-wococo/src/runtime.rs index 91d32d1aa7..b28e053086 100644 --- a/relays/client-wococo/src/runtime.rs +++ b/relays/client-wococo/src/runtime.rs @@ -17,9 +17,9 @@ //! Types that are specific to the Wococo runtime. use bp_messages::{LaneId, UnrewardedRelayersState}; -use bp_polkadot_core::PolkadotLike; +use bp_polkadot_core::{AccountAddress, Balance, PolkadotLike}; use bp_runtime::Chain; -use codec::{Decode, Encode}; +use codec::{Compact, Decode, Encode}; use frame_support::weights::Weight; use scale_info::TypeInfo; @@ -66,12 +66,15 @@ pub enum Call { /// System pallet. #[codec(index = 0)] System(SystemCall), + /// Balances pallet. + #[codec(index = 4)] + Balances(BalancesCall), /// Rococo bridge pallet. #[codec(index = 40)] BridgeGrandpaRococo(BridgeGrandpaRococoCall), /// Rococo messages pallet. #[codec(index = 43)] - BridgeMessagesRococo(BridgeMessagesRococoCall), + BridgeRococoMessages(BridgeRococoMessagesCall), } #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] @@ -81,6 +84,13 @@ pub enum SystemCall { remark(Vec), } +#[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] +#[allow(non_camel_case_types)] +pub enum BalancesCall { + #[codec(index = 0)] + transfer(AccountAddress, Compact), +} + #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] #[allow(non_camel_case_types)] pub enum BridgeGrandpaRococoCall { @@ -95,7 +105,7 @@ pub enum BridgeGrandpaRococoCall { #[derive(Encode, Decode, Debug, PartialEq, Eq, Clone, TypeInfo)] #[allow(non_camel_case_types)] -pub enum BridgeMessagesRococoCall { +pub enum BridgeRococoMessagesCall { #[codec(index = 3)] send_message( LaneId, diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml index 5bee10856d..1224d81439 100644 --- a/relays/lib-substrate-relay/Cargo.toml +++ b/relays/lib-substrate-relay/Cargo.toml @@ -27,6 +27,7 @@ relay-utils = { path = "../utils" } messages-relay = { path = "../messages" } relay-substrate-client = { path = "../client-substrate" } +pallet-bridge-grandpa = { path = "../../modules/grandpa" } pallet-bridge-messages = { path = "../../modules/messages" } bp-runtime = { path = "../../primitives/runtime" } @@ -41,6 +42,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master [dev-dependencies] bp-millau = { path = "../../primitives/chain-millau" } +bp-rialto = { path = "../../primitives/chain-rialto" } bp-rococo = { path = "../../primitives/chain-rococo" } bp-wococo = { path = "../../primitives/chain-wococo" } relay-rococo-client = { path = "../client-rococo" } diff --git a/relays/lib-substrate-relay/src/finality_pipeline.rs b/relays/lib-substrate-relay/src/finality_pipeline.rs index cdfbb3354d..87e50be039 100644 --- a/relays/lib-substrate-relay/src/finality_pipeline.rs +++ b/relays/lib-substrate-relay/src/finality_pipeline.rs @@ -14,18 +14,23 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -//! Substrate-to-Substrate headers sync entrypoint. +//! Types and functions intended to ease adding of new Substrate -> Substrate +//! finality proofs synchronization pipelines. -use crate::{finality_target::SubstrateFinalityTarget, STALL_TIMEOUT}; +use crate::{ + finality_source::SubstrateFinalitySource, finality_target::SubstrateFinalityTarget, + TransactionParams, +}; use bp_header_chain::justification::GrandpaJustification; -use bp_runtime::AccountIdOf; -use finality_relay::{FinalitySyncParams, FinalitySyncPipeline}; +use finality_relay::FinalitySyncPipeline; +use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ - finality_source::FinalitySource, BlockNumberOf, Chain, Client, HashOf, SyncHeader, + transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, + HashOf, HeaderOf, SyncHeader, TransactionSignScheme, }; -use relay_utils::{metrics::MetricsParams, BlockNumberBase}; -use sp_core::Bytes; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; use std::{fmt::Debug, marker::PhantomData}; /// Default limit of recent finality proofs. @@ -34,130 +39,143 @@ use std::{fmt::Debug, marker::PhantomData}; /// Substrate+GRANDPA based chains (good to know). pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; -/// Headers sync pipeline for Substrate <-> Substrate relays. +/// Substrate -> Substrate finality proofs synchronization pipeline. pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { - /// Pipeline for syncing finalized Source chain headers to Target chain. - type FinalitySyncPipeline: FinalitySyncPipeline; - - /// Name of the runtime method that returns id of best finalized source header at target chain. - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str; - - /// Chain with GRANDPA bridge pallet. + /// Headers of this chain are submitted to the `TargetChain`. + type SourceChain: Chain; + /// Headers of the `SourceChain` are submitted to this chain. type TargetChain: Chain; - /// Customize metrics exposed by headers sync loop. - fn customize_metrics(params: MetricsParams) -> anyhow::Result { - Ok(params) + /// How submit finality proof call is built? + type SubmitFinalityProofCallBuilder: SubmitFinalityProofCallBuilder; + /// Scheme used to sign target chain transactions. + type TransactionSignScheme: TransactionSignScheme; + + /// Add relay guards if required. + fn start_relay_guards( + _target_client: &Client, + _transaction_params: &TransactionParams>, + ) { } +} - /// Start finality relay guards. - /// - /// Different finality bridges may have different set of guards - e.g. on ephemeral chains we - /// don't need a version guards, on test chains we don't care that much about relayer account - /// balance, ... So the implementation is left to the specific bridges. - fn start_relay_guards(&self) {} - - /// Returns id of account that we're using to sign transactions at target chain. - fn transactions_author(&self) -> AccountIdOf; - - /// Make submit header transaction. - fn make_submit_finality_proof_transaction( - &self, - era: bp_runtime::TransactionEraOf, - transaction_nonce: bp_runtime::IndexOf, - header: ::Header, - proof: ::FinalityProof, - ) -> Bytes; +/// Adapter that allows all `SubstrateFinalitySyncPipeline` to act as `FinalitySyncPipeline`. +#[derive(Clone, Debug)] +pub(crate) struct FinalitySyncPipelineAdapter { + _phantom: PhantomData

, } -/// Substrate-to-Substrate finality proof pipeline. -#[derive(Clone)] -pub struct SubstrateFinalityToSubstrate { - /// Client for the target chain. - pub target_client: Client, - /// Data required to sign target chain transactions. - pub target_sign: TargetSign, - /// Unused generic arguments dump. - _marker: PhantomData, +impl FinalitySyncPipeline for FinalitySyncPipelineAdapter

{ + const SOURCE_NAME: &'static str = P::SourceChain::NAME; + const TARGET_NAME: &'static str = P::TargetChain::NAME; + + type Hash = HashOf; + type Number = BlockNumberOf; + type Header = relay_substrate_client::SyncHeader>; + type FinalityProof = GrandpaJustification>; } -impl Debug - for SubstrateFinalityToSubstrate -{ - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - f.debug_struct("SubstrateFinalityToSubstrate") - .field("target_client", &self.target_client) - .finish() - } +/// Different ways of building `submit_finality_proof` calls. +pub trait SubmitFinalityProofCallBuilder { + /// Given source chain header and its finality proofs, build call of `submit_finality_proof` + /// function of bridge GRANDPA module at the target chain. + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> CallOf; } -impl - SubstrateFinalityToSubstrate -{ - /// Create new Substrate-to-Substrate headers pipeline. - pub fn new(target_client: Client, target_sign: TargetSign) -> Self { - SubstrateFinalityToSubstrate { target_client, target_sign, _marker: Default::default() } - } +/// Building `submit_finality_proof` call when you have direct access to the target +/// chain runtime. +pub struct DirectSubmitFinalityProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, } -impl FinalitySyncPipeline - for SubstrateFinalityToSubstrate +impl SubmitFinalityProofCallBuilder

for DirectSubmitFinalityProofCallBuilder where - SourceChain: Clone + Chain + Debug, - BlockNumberOf: BlockNumberBase, - TargetChain: Clone + Chain + Debug, - TargetSign: 'static + Clone + Send + Sync, + P: SubstrateFinalitySyncPipeline, + R: BridgeGrandpaConfig, + I: 'static, + R::BridgedChain: bp_runtime::Chain

>, + CallOf: From>, { - const SOURCE_NAME: &'static str = SourceChain::NAME; - const TARGET_NAME: &'static str = TargetChain::NAME; + fn build_submit_finality_proof_call( + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> CallOf { + BridgeGrandpaCall::::submit_finality_proof { + finality_target: Box::new(header.into_inner()), + justification: proof, + } + .into() + } +} - type Hash = HashOf; - type Number = BlockNumberOf; - type Header = SyncHeader; - type FinalityProof = GrandpaJustification; +/// Macro that generates `SubmitFinalityProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of target chain runtime. In this case you +/// should provide "name" of the call variant for the bridge GRANDPA calls and the "name" of +/// the variant for the `submit_finality_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_mocked_submit_finality_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_grandpa:path, $submit_finality_proof:path) => { + pub struct $mocked_builder; + + impl $crate::finality_pipeline::SubmitFinalityProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_submit_finality_proof_call( + header: relay_substrate_client::SyncHeader< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + proof: bp_header_chain::justification::GrandpaJustification< + relay_substrate_client::HeaderOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::SourceChain + > + >, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::finality_pipeline::SubstrateFinalitySyncPipeline>::TargetChain + > { + $bridge_grandpa($submit_finality_proof(Box::new(header.into_inner()), proof)) + } + } + }; } -/// Run Substrate-to-Substrate finality sync. -pub async fn run( - pipeline: P, - source_client: Client, - target_client: Client, +/// Run Substrate-to-Substrate finality sync loop. +pub async fn run( + source_client: Client, + target_client: Client, only_mandatory_headers: bool, - transactions_mortality: Option, + transaction_params: TransactionParams>, metrics_params: MetricsParams, ) -> anyhow::Result<()> where - P: SubstrateFinalitySyncPipeline, - P::FinalitySyncPipeline: FinalitySyncPipeline< - Hash = HashOf, - Number = BlockNumberOf, - Header = SyncHeader, - FinalityProof = GrandpaJustification, - >, - SourceChain: Clone + Chain, - BlockNumberOf: BlockNumberBase, - TargetChain: Clone + Chain, + AccountIdOf: From< as Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { log::info!( target: "bridge", "Starting {} -> {} finality proof relay", - SourceChain::NAME, - TargetChain::NAME, + P::SourceChain::NAME, + P::TargetChain::NAME, ); finality_relay::run( - FinalitySource::new(source_client, None), - SubstrateFinalityTarget::new(target_client, pipeline, transactions_mortality), - FinalitySyncParams { + SubstrateFinalitySource::

::new(source_client, None), + SubstrateFinalityTarget::

::new(target_client, transaction_params.clone()), + finality_relay::FinalitySyncParams { tick: std::cmp::max( - SourceChain::AVERAGE_BLOCK_INTERVAL, - TargetChain::AVERAGE_BLOCK_INTERVAL, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, - stall_timeout: relay_substrate_client::transaction_stall_timeout( - transactions_mortality, - TargetChain::AVERAGE_BLOCK_INTERVAL, - STALL_TIMEOUT, + stall_timeout: transaction_stall_timeout( + transaction_params.mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + crate::STALL_TIMEOUT, ), only_mandatory_headers, }, diff --git a/relays/client-substrate/src/finality_source.rs b/relays/lib-substrate-relay/src/finality_source.rs similarity index 66% rename from relays/client-substrate/src/finality_source.rs rename to relays/lib-substrate-relay/src/finality_source.rs index 98526de178..804d321293 100644 --- a/relays/client-substrate/src/finality_source.rs +++ b/relays/lib-substrate-relay/src/finality_source.rs @@ -16,49 +16,59 @@ //! Default generic implementation of finality source for basic Substrate client. -use crate::{ - chain::{BlockWithJustification, Chain}, - client::Client, - error::Error, - sync_header::SyncHeader, -}; +use crate::finality_pipeline::{FinalitySyncPipelineAdapter, SubstrateFinalitySyncPipeline}; use async_std::sync::{Arc, Mutex}; use async_trait::async_trait; use bp_header_chain::justification::GrandpaJustification; use codec::Decode; -use finality_relay::{FinalitySyncPipeline, SourceClient, SourceHeader}; +use finality_relay::SourceClient; use futures::stream::{unfold, Stream, StreamExt}; +use relay_substrate_client::{ + BlockNumberOf, BlockWithJustification, Chain, Client, Error, HeaderOf, +}; use relay_utils::relay_loop::Client as RelayClient; use sp_runtime::traits::Header as HeaderT; -use std::{marker::PhantomData, pin::Pin}; +use std::pin::Pin; /// Shared updatable reference to the maximal header number that we want to sync from the source. pub type RequiredHeaderNumberRef = Arc::BlockNumber>>; +/// Substrate finality proofs stream. +pub type SubstrateFinalityProofsStream

= Pin< + Box< + dyn Stream< + Item = GrandpaJustification< + HeaderOf<

::SourceChain>, + >, + > + Send, + >, +>; + /// Substrate node as finality source. -pub struct FinalitySource { - client: Client, - maximal_header_number: Option>, - _phantom: PhantomData

, +pub struct SubstrateFinalitySource { + client: Client, + maximal_header_number: Option>, } -impl FinalitySource { +impl SubstrateFinalitySource

{ /// Create new headers source using given client. pub fn new( - client: Client, - maximal_header_number: Option>, + client: Client, + maximal_header_number: Option>, ) -> Self { - FinalitySource { client, maximal_header_number, _phantom: Default::default() } + SubstrateFinalitySource { client, maximal_header_number } } /// Returns reference to the underlying RPC client. - pub fn client(&self) -> &Client { + pub fn client(&self) -> &Client { &self.client } /// Returns best finalized block number. - pub async fn on_chain_best_finalized_block_number(&self) -> Result { + pub async fn on_chain_best_finalized_block_number( + &self, + ) -> Result, Error> { // we **CAN** continue to relay finality proofs if source node is out of sync, because // target node may be missing proofs that are already available at the source let finalized_header_hash = self.client.best_finalized_header_hash().await?; @@ -67,18 +77,17 @@ impl FinalitySource { } } -impl Clone for FinalitySource { +impl Clone for SubstrateFinalitySource

{ fn clone(&self) -> Self { - FinalitySource { + SubstrateFinalitySource { client: self.client.clone(), maximal_header_number: self.maximal_header_number.clone(), - _phantom: Default::default(), } } } #[async_trait] -impl RelayClient for FinalitySource { +impl RelayClient for SubstrateFinalitySource

{ type Error = Error; async fn reconnect(&mut self) -> Result<(), Error> { @@ -87,21 +96,12 @@ impl RelayClient for FinalitySource { } #[async_trait] -impl SourceClient

for FinalitySource -where - C: Chain, - C::BlockNumber: relay_utils::BlockNumberBase, - P: FinalitySyncPipeline< - Hash = C::Hash, - Number = C::BlockNumber, - Header = SyncHeader, - FinalityProof = GrandpaJustification, - >, - P::Header: SourceHeader, +impl SourceClient> + for SubstrateFinalitySource

{ - type FinalityProofsStream = Pin> + Send>>; + type FinalityProofsStream = SubstrateFinalityProofsStream

; - async fn best_finalized_block_number(&self) -> Result { + async fn best_finalized_block_number(&self) -> Result, Error> { let mut finalized_header_number = self.on_chain_best_finalized_block_number().await?; // never return block number larger than requested. This way we'll never sync headers // past `maximal_header_number` @@ -116,15 +116,23 @@ where async fn header_and_finality_proof( &self, - number: P::Number, - ) -> Result<(P::Header, Option), Error> { + number: BlockNumberOf, + ) -> Result< + ( + relay_substrate_client::SyncHeader>, + Option>>, + ), + Error, + > { let header_hash = self.client.block_hash_by_number(number).await?; let signed_block = self.client.get_block(Some(header_hash)).await?; let justification = signed_block .justification() .map(|raw_justification| { - GrandpaJustification::::decode(&mut raw_justification.as_slice()) + GrandpaJustification::>::decode( + &mut raw_justification.as_slice(), + ) }) .transpose() .map_err(Error::ResponseParseFailed)?; @@ -141,7 +149,7 @@ where log::error!( target: "bridge", "Failed to read justification target from the {} justifications stream: {:?}", - P::SOURCE_NAME, + P::SourceChain::NAME, err, ); }; @@ -153,7 +161,9 @@ where .ok()??; let decoded_justification = - GrandpaJustification::::decode(&mut &next_justification[..]); + GrandpaJustification::>::decode( + &mut &next_justification[..], + ); let justification = match decoded_justification { Ok(j) => j, diff --git a/relays/lib-substrate-relay/src/finality_target.rs b/relays/lib-substrate-relay/src/finality_target.rs index f50bd103f4..918c633d74 100644 --- a/relays/lib-substrate-relay/src/finality_target.rs +++ b/relays/lib-substrate-relay/src/finality_target.rs @@ -15,70 +15,80 @@ // along with Parity Bridges Common. If not, see . //! Substrate client as Substrate finality proof target. The chain we connect to should have -//! runtime that implements `FinalityApi` to allow bridging with -//! chain. +//! bridge GRANDPA pallet deployed and provide `FinalityApi` to allow bridging +//! with chain. -use crate::finality_pipeline::SubstrateFinalitySyncPipeline; +use crate::{ + finality_pipeline::{ + FinalitySyncPipelineAdapter, SubmitFinalityProofCallBuilder, SubstrateFinalitySyncPipeline, + }, + TransactionParams, +}; use async_trait::async_trait; -use codec::Decode; -use finality_relay::{FinalitySyncPipeline, TargetClient}; -use relay_substrate_client::{Chain, Client, Error as SubstrateError}; +use bp_header_chain::justification::GrandpaJustification; +use codec::Encode; +use finality_relay::TargetClient; +use relay_substrate_client::{ + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error, HashOf, HeaderOf, + SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, +}; use relay_utils::relay_loop::Client as RelayClient; +use sp_core::{Bytes, Pair}; /// Substrate client as Substrate finality target. -pub struct SubstrateFinalityTarget { - client: Client, - pipeline: P, - transactions_mortality: Option, +pub struct SubstrateFinalityTarget { + client: Client, + transaction_params: TransactionParams>, } -impl SubstrateFinalityTarget { +impl SubstrateFinalityTarget

{ /// Create new Substrate headers target. - pub fn new(client: Client, pipeline: P, transactions_mortality: Option) -> Self { - SubstrateFinalityTarget { client, pipeline, transactions_mortality } + pub fn new( + client: Client, + transaction_params: TransactionParams>, + ) -> Self { + SubstrateFinalityTarget { client, transaction_params } } } -impl Clone for SubstrateFinalityTarget { +impl Clone for SubstrateFinalityTarget

{ fn clone(&self) -> Self { SubstrateFinalityTarget { client: self.client.clone(), - pipeline: self.pipeline.clone(), - transactions_mortality: self.transactions_mortality, + transaction_params: self.transaction_params.clone(), } } } #[async_trait] -impl RelayClient for SubstrateFinalityTarget { - type Error = SubstrateError; +impl RelayClient for SubstrateFinalityTarget

{ + type Error = Error; - async fn reconnect(&mut self) -> Result<(), SubstrateError> { + async fn reconnect(&mut self) -> Result<(), Error> { self.client.reconnect().await } } #[async_trait] -impl TargetClient for SubstrateFinalityTarget +impl TargetClient> + for SubstrateFinalityTarget

where - C: Chain, - P: SubstrateFinalitySyncPipeline, - ::Number: Decode, - ::Hash: Decode, + AccountIdOf: From< as Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { async fn best_finalized_source_block_number( &self, - ) -> Result<::Number, SubstrateError> { + ) -> Result, Error> { // we can't continue to relay finality if target node is out of sync, because // it may have already received (some of) headers that we're going to relay self.client.ensure_synced().await?; Ok(crate::messages_source::read_client_state::< - C, - ::Hash, - ::Number, - >(&self.client, P::BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET) + P::TargetChain, + HashOf, + BlockNumberOf, + >(&self.client, P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD) .await? .best_finalized_peer_at_best_self .0) @@ -86,24 +96,28 @@ where async fn submit_finality_proof( &self, - header: ::Header, - proof: ::FinalityProof, - ) -> Result<(), SubstrateError> { - let transactions_author = self.pipeline.transactions_author(); - let pipeline = self.pipeline.clone(); - let transactions_mortality = self.transactions_mortality; + header: SyncHeader>, + proof: GrandpaJustification>, + ) -> Result<(), Error> { + let genesis_hash = *self.client.genesis_hash(); + let transaction_params = self.transaction_params.clone(); + let call = + P::SubmitFinalityProofCallBuilder::build_submit_finality_proof_call(header, proof); + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; self.client .submit_signed_extrinsic( - transactions_author, + self.transaction_params.signer.public().into(), move |best_block_id, transaction_nonce| { - pipeline.make_submit_finality_proof_transaction( - relay_substrate_client::TransactionEra::new( - best_block_id, - transactions_mortality, - ), - transaction_nonce, - header, - proof, + Bytes( + P::TransactionSignScheme::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(call, transaction_nonce), + }) + .encode(), ) }, ) diff --git a/relays/lib-substrate-relay/src/lib.rs b/relays/lib-substrate-relay/src/lib.rs index cc066bf501..c27aa7b708 100644 --- a/relays/lib-substrate-relay/src/lib.rs +++ b/relays/lib-substrate-relay/src/lib.rs @@ -23,10 +23,12 @@ use std::time::Duration; pub mod conversion_rate_update; pub mod error; pub mod finality_pipeline; +pub mod finality_source; pub mod finality_target; pub mod headers_initialize; pub mod helpers; pub mod messages_lane; +pub mod messages_metrics; pub mod messages_source; pub mod messages_target; pub mod on_demand_headers; @@ -39,3 +41,12 @@ pub mod on_demand_headers; /// blockchains) blocks. So 1 hour seems to be a good guess for (even congested) chains to mine /// transaction, or remove it from the pool. pub const STALL_TIMEOUT: Duration = Duration::from_secs(60 * 60); + +/// Transaction creation parameters. +#[derive(Clone, Debug)] +pub struct TransactionParams { + /// Transactions author. + pub signer: TS, + /// Transactions mortality. + pub mortality: Option, +} diff --git a/relays/lib-substrate-relay/src/messages_lane.rs b/relays/lib-substrate-relay/src/messages_lane.rs index 6cadb64754..4742ce6e48 100644 --- a/relays/lib-substrate-relay/src/messages_lane.rs +++ b/relays/lib-substrate-relay/src/messages_lane.rs @@ -17,194 +17,396 @@ //! Tools for supporting message lanes between two Substrate-based chains. use crate::{ - messages_source::SubstrateMessagesProof, messages_target::SubstrateMessagesReceivingProof, + messages_metrics::StandaloneMessagesMetrics, + messages_source::{SubstrateMessagesProof, SubstrateMessagesSource}, + messages_target::{SubstrateMessagesDeliveryProof, SubstrateMessagesTarget}, on_demand_headers::OnDemandHeadersRelay, + TransactionParams, STALL_TIMEOUT, }; -use async_trait::async_trait; use bp_messages::{LaneId, MessageNonce}; -use bp_runtime::{AccountIdOf, IndexOf}; -use frame_support::weights::Weight; -use messages_relay::{ - message_lane::{MessageLane, SourceHeaderIdOf, TargetHeaderIdOf}, - relay_strategy::RelayStrategy, +use bp_runtime::{AccountIdOf, Chain as _}; +use bridge_runtime_common::messages::{ + source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; +use codec::Encode; +use frame_support::weights::{GetDispatchInfo, Weight}; +use messages_relay::{message_lane::MessageLane, relay_strategy::RelayStrategy}; +use pallet_bridge_messages::{Call as BridgeMessagesCall, Config as BridgeMessagesConfig}; use relay_substrate_client::{ - metrics::{FloatStorageValueMetric, StorageProofOverheadMetric}, - BlockNumberOf, Chain, Client, HashOf, + AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithMessages, Client, HashOf, + TransactionSignScheme, }; -use relay_utils::{ - metrics::{ - FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric, - }, - BlockNumberBase, -}; -use sp_core::{storage::StorageKey, Bytes}; -use sp_runtime::FixedU128; -use std::ops::RangeInclusive; +use relay_utils::metrics::MetricsParams; +use sp_core::Pair; +use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; + +/// Substrate -> Substrate messages synchronization pipeline. +pub trait SubstrateMessageLane: 'static + Clone + Debug + Send + Sync { + /// Name of the source -> target tokens conversion rate parameter name. + /// + /// The parameter is stored at the target chain and the storage key is computed using + /// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed + /// to be 1. + const SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>; + /// Name of the target -> source tokens conversion rate parameter name. + /// + /// The parameter is stored at the source chain and the storage key is computed using + /// `bp_runtime::storage_parameter_key` function. If value is unknown, it is assumed + /// to be 1. + const TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME: Option<&'static str>; + + /// Messages of this chain are relayed to the `TargetChain`. + type SourceChain: ChainWithMessages; + /// Messages from the `SourceChain` are dispatched on this chain. + type TargetChain: ChainWithMessages; + + /// Scheme used to sign source chain transactions. + type SourceTransactionSignScheme: TransactionSignScheme; + /// Scheme used to sign target chain transactions. + type TargetTransactionSignScheme: TransactionSignScheme; + + /// How receive messages proof call is built? + type ReceiveMessagesProofCallBuilder: ReceiveMessagesProofCallBuilder; + /// How receive messages delivery proof call is built? + type ReceiveMessagesDeliveryProofCallBuilder: ReceiveMessagesDeliveryProofCallBuilder; + + /// Message relay strategy. + type RelayStrategy: RelayStrategy; +} + +/// Adapter that allows all `SubstrateMessageLane` to act as `MessageLane`. +#[derive(Clone, Debug)] +pub(crate) struct MessageLaneAdapter { + _phantom: PhantomData

, +} + +impl MessageLane for MessageLaneAdapter

{ + const SOURCE_NAME: &'static str = P::SourceChain::NAME; + const TARGET_NAME: &'static str = P::TargetChain::NAME; + + type MessagesProof = SubstrateMessagesProof; + type MessagesReceivingProof = SubstrateMessagesDeliveryProof; + + type SourceChainBalance = BalanceOf; + type SourceHeaderNumber = BlockNumberOf; + type SourceHeaderHash = HashOf; + + type TargetHeaderNumber = BlockNumberOf; + type TargetHeaderHash = HashOf; +} /// Substrate <-> Substrate messages relay parameters. -pub struct MessagesRelayParams { +pub struct MessagesRelayParams { /// Messages source client. - pub source_client: Client, - /// Sign parameters for messages source chain. - pub source_sign: SS, - /// Mortality of source transactions. - pub source_transactions_mortality: Option, + pub source_client: Client, + /// Source transaction params. + pub source_transaction_params: + TransactionParams>, /// Messages target client. - pub target_client: Client, - /// Sign parameters for messages target chain. - pub target_sign: TS, - /// Mortality of target transactions. - pub target_transactions_mortality: Option, + pub target_client: Client, + /// Target transaction params. + pub target_transaction_params: + TransactionParams>, /// Optional on-demand source to target headers relay. - pub source_to_target_headers_relay: Option>, + pub source_to_target_headers_relay: Option>, /// Optional on-demand target to source headers relay. - pub target_to_source_headers_relay: Option>, + pub target_to_source_headers_relay: Option>, /// Identifier of lane that needs to be served. pub lane_id: LaneId, /// Metrics parameters. pub metrics_params: MetricsParams, /// Pre-registered standalone metrics. - pub standalone_metrics: Option>, - /// Relay strategy - pub relay_strategy: Strategy, + pub standalone_metrics: Option>, + /// Relay strategy. + pub relay_strategy: P::RelayStrategy, } -/// Message sync pipeline for Substrate <-> Substrate relays. -#[async_trait] -pub trait SubstrateMessageLane: 'static + Clone + Send + Sync { - /// Underlying generic message lane. - type MessageLane: MessageLane; - - /// Name of the runtime method that returns dispatch weight of outbound messages at the source - /// chain. - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str; - /// Name of the runtime method that returns latest generated nonce at the source chain. - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str; - /// Name of the runtime method that returns latest received (confirmed) nonce at the the source - /// chain. - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str; - - /// Name of the runtime method that returns latest received nonce at the target chain. - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str; - /// Name of the runtime method that returns the latest confirmed (reward-paid) nonce at the - /// target chain. - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str; - /// Number of the runtime method that returns state of "unrewarded relayers" set at the target - /// chain. - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str; - - /// Name of the runtime method that returns id of best finalized source header at target chain. - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str; - /// Name of the runtime method that returns id of best finalized target header at source chain. - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str; - - /// Name of the messages pallet as it is declared in the `construct_runtime!()` at source chain. - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str; - /// Name of the messages pallet as it is declared in the `construct_runtime!()` at target chain. - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str; - - /// Extra weight of the delivery transaction at the target chain, that is paid to cover - /// dispatch fee payment. - /// - /// If dispatch fee is paid at the source chain, then this weight is refunded by the - /// delivery transaction. - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight; - - /// Source chain. - type SourceChain: Chain; - /// Target chain. - type TargetChain: Chain; - - /// Returns id of account that we're using to sign transactions at target chain (messages - /// proof). - fn target_transactions_author(&self) -> AccountIdOf; - - /// Make messages delivery transaction. - fn make_messages_delivery_transaction( - &self, - best_block_id: TargetHeaderIdOf, - transaction_nonce: IndexOf, - generated_at_header: SourceHeaderIdOf, - nonces: RangeInclusive, - proof: ::MessagesProof, - ) -> Bytes; - - /// Returns id of account that we're using to sign transactions at source chain (delivery - /// proof). - fn source_transactions_author(&self) -> AccountIdOf; - - /// Make messages receiving proof transaction. - fn make_messages_receiving_proof_transaction( - &self, - best_block_id: SourceHeaderIdOf, - transaction_nonce: IndexOf, - generated_at_header: TargetHeaderIdOf, - proof: ::MessagesReceivingProof, - ) -> Bytes; +/// Run Substrate-to-Substrate messages sync loop. +pub async fn run(params: MessagesRelayParams

) -> anyhow::Result<()> +where + AccountIdOf: + From< as Pair>::Public>, + AccountIdOf: + From< as Pair>::Public>, + BalanceOf: TryFrom>, + P::SourceTransactionSignScheme: TransactionSignScheme, + P::TargetTransactionSignScheme: TransactionSignScheme, +{ + let source_client = params.source_client; + let target_client = params.target_client; + let stall_timeout = relay_substrate_client::bidirectional_transaction_stall_timeout( + params.source_transaction_params.mortality, + params.target_transaction_params.mortality, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ); + let relayer_id_at_source: AccountIdOf = + params.source_transaction_params.signer.public().into(); + + // 2/3 is reserved for proofs and tx overhead + let max_messages_size_in_single_batch = P::TargetChain::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) = + crate::messages_lane::select_delivery_transaction_limits::< + ::WeightInfo, + >( + P::TargetChain::max_extrinsic_weight(), + P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + ); + 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); + + let standalone_metrics = params.standalone_metrics.map(Ok).unwrap_or_else(|| { + crate::messages_metrics::standalone_metrics::

( + source_client.clone(), + target_client.clone(), + ) + })?; + + log::info!( + target: "bridge", + "Starting {} -> {} messages relay.\n\t\ + {} 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\ + Tx mortality: {:?}/{:?}\n\t\ + Stall timeout: {:?}", + P::SourceChain::NAME, + P::TargetChain::NAME, + P::SourceChain::NAME, + relayer_id_at_source, + max_messages_in_single_batch, + max_messages_size_in_single_batch, + max_messages_weight_in_single_batch, + params.source_transaction_params.mortality, + params.target_transaction_params.mortality, + stall_timeout, + ); + + messages_relay::message_lane_loop::run( + messages_relay::message_lane_loop::Params { + lane: params.lane_id, + source_tick: P::SourceChain::AVERAGE_BLOCK_INTERVAL, + target_tick: P::TargetChain::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: + P::SourceChain::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, + max_unconfirmed_nonces_at_target: + P::SourceChain::MAX_UNCONFIRMED_MESSAGES_IN_CONFIRMATION_TX, + max_messages_in_single_batch, + max_messages_weight_in_single_batch, + max_messages_size_in_single_batch, + relay_strategy: params.relay_strategy, + }, + }, + SubstrateMessagesSource::

::new( + source_client, + params.lane_id, + params.source_transaction_params, + params.target_to_source_headers_relay, + ), + SubstrateMessagesTarget::

::new( + target_client, + params.lane_id, + relayer_id_at_source, + params.target_transaction_params, + standalone_metrics.clone(), + params.source_to_target_headers_relay, + ), + standalone_metrics.register_and_spawn(params.metrics_params)?, + futures::future::pending(), + ) + .await + .map_err(Into::into) +} + +/// Different ways of building `receive_messages_proof` calls. +pub trait ReceiveMessagesProofCallBuilder { + /// Given messages proof, build call of `receive_messages_proof` function of bridge + /// messages module at the target chain. + fn build_receive_messages_proof_call( + relayer_id_at_source: AccountIdOf, + proof: SubstrateMessagesProof, + messages_count: u32, + dispatch_weight: Weight, + trace_call: bool, + ) -> CallOf; } -/// Substrate-to-Substrate message lane. -#[derive(Debug)] -pub struct SubstrateMessageLaneToSubstrate< - Source: Chain, - SourceSignParams, - Target: Chain, - TargetSignParams, -> { - /// Client for the source Substrate chain. - pub source_client: Client, - /// Parameters required to sign transactions for source chain. - pub source_sign: SourceSignParams, - /// Source transactions mortality. - pub source_transactions_mortality: Option, - /// Client for the target Substrate chain. - pub target_client: Client, - /// Parameters required to sign transactions for target chain. - pub target_sign: TargetSignParams, - /// Target transactions mortality. - pub target_transactions_mortality: Option, - /// Account id of relayer at the source chain. - pub relayer_id_at_source: Source::AccountId, +/// Building `receive_messages_proof` call when you have direct access to the target +/// chain runtime. +pub struct DirectReceiveMessagesProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, } -impl Clone - for SubstrateMessageLaneToSubstrate +impl ReceiveMessagesProofCallBuilder

for DirectReceiveMessagesProofCallBuilder +where + P: SubstrateMessageLane, + R: BridgeMessagesConfig>, + I: 'static, + R::SourceHeaderChain: bp_messages::target_chain::SourceHeaderChain< + R::InboundMessageFee, + MessagesProof = FromBridgedChainMessagesProof>, + >, + CallOf: From> + GetDispatchInfo, { - fn clone(&self) -> Self { - Self { - source_client: self.source_client.clone(), - source_sign: self.source_sign.clone(), - source_transactions_mortality: self.source_transactions_mortality, - target_client: self.target_client.clone(), - target_sign: self.target_sign.clone(), - target_transactions_mortality: self.target_transactions_mortality, - relayer_id_at_source: self.relayer_id_at_source.clone(), + fn build_receive_messages_proof_call( + relayer_id_at_source: AccountIdOf, + proof: SubstrateMessagesProof, + messages_count: u32, + dispatch_weight: Weight, + trace_call: bool, + ) -> CallOf { + let call: CallOf = BridgeMessagesCall::::receive_messages_proof { + relayer_id_at_bridged_chain: relayer_id_at_source, + proof: proof.1, + messages_count, + dispatch_weight, + } + .into(); + if trace_call { + // this trace isn't super-accurate, because limits are for transactions and we + // have a call here, but it provides required information + log::trace!( + target: "bridge", + "Prepared {} -> {} messages delivery call. Weight: {}/{}, size: {}/{}", + P::SourceChain::NAME, + P::TargetChain::NAME, + call.get_dispatch_info().weight, + P::TargetChain::max_extrinsic_weight(), + call.encode().len(), + P::TargetChain::max_extrinsic_size(), + ); } + call } } -impl MessageLane - for SubstrateMessageLaneToSubstrate -where - SourceSignParams: Clone + Send + Sync + 'static, - TargetSignParams: Clone + Send + Sync + 'static, - BlockNumberOf: BlockNumberBase, - BlockNumberOf: BlockNumberBase, -{ - const SOURCE_NAME: &'static str = Source::NAME; - const TARGET_NAME: &'static str = Target::NAME; +/// Macro that generates `ReceiveMessagesProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of target chain runtime. In this case you +/// should provide "name" of the call variant for the bridge messages calls and the "name" of +/// the variant for the `receive_messages_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_mocked_receive_message_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_proof:path) => { + pub struct $mocked_builder; + + impl $crate::messages_lane::ReceiveMessagesProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_receive_messages_proof_call( + relayer_id_at_source: relay_substrate_client::AccountIdOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + >, + proof: $crate::messages_source::SubstrateMessagesProof< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + >, + messages_count: u32, + dispatch_weight: Weight, + _trace_call: bool, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + > { + $bridge_messages($receive_messages_proof( + relayer_id_at_source, + proof.1, + messages_count, + dispatch_weight, + )) + } + } + }; +} + +/// Different ways of building `receive_messages_delivery_proof` calls. +pub trait ReceiveMessagesDeliveryProofCallBuilder { + /// Given messages delivery proof, build call of `receive_messages_delivery_proof` function of + /// bridge messages module at the source chain. + fn build_receive_messages_delivery_proof_call( + proof: SubstrateMessagesDeliveryProof, + trace_call: bool, + ) -> CallOf; +} - type MessagesProof = SubstrateMessagesProof; - type MessagesReceivingProof = SubstrateMessagesReceivingProof; +/// Building `receive_messages_delivery_proof` call when you have direct access to the source +/// chain runtime. +pub struct DirectReceiveMessagesDeliveryProofCallBuilder { + _phantom: PhantomData<(P, R, I)>, +} - type SourceChainBalance = Source::Balance; - type SourceHeaderNumber = BlockNumberOf; - type SourceHeaderHash = HashOf; +impl ReceiveMessagesDeliveryProofCallBuilder

+ for DirectReceiveMessagesDeliveryProofCallBuilder +where + P: SubstrateMessageLane, + R: BridgeMessagesConfig, + I: 'static, + R::TargetHeaderChain: bp_messages::source_chain::TargetHeaderChain< + R::OutboundPayload, + R::AccountId, + MessagesDeliveryProof = FromBridgedChainMessagesDeliveryProof>, + >, + CallOf: From> + GetDispatchInfo, +{ + fn build_receive_messages_delivery_proof_call( + proof: SubstrateMessagesDeliveryProof, + trace_call: bool, + ) -> CallOf { + let call: CallOf = + BridgeMessagesCall::::receive_messages_delivery_proof { + proof: proof.1, + relayers_state: proof.0, + } + .into(); + if trace_call { + // this trace isn't super-accurate, because limits are for transactions and we + // have a call here, but it provides required information + log::trace!( + target: "bridge", + "Prepared {} -> {} delivery confirmation transaction. Weight: {}/{}, size: {}/{}", + P::TargetChain::NAME, + P::SourceChain::NAME, + call.get_dispatch_info().weight, + P::SourceChain::max_extrinsic_weight(), + call.encode().len(), + P::SourceChain::max_extrinsic_size(), + ); + } + call + } +} - type TargetHeaderNumber = BlockNumberOf; - type TargetHeaderHash = HashOf; +/// Macro that generates `ReceiveMessagesDeliveryProofCallBuilder` implementation for the case when +/// you only have an access to the mocked version of source chain runtime. In this case you +/// should provide "name" of the call variant for the bridge messages calls and the "name" of +/// the variant for the `receive_messages_delivery_proof` call within that first option. +#[rustfmt::skip] +#[macro_export] +macro_rules! generate_mocked_receive_message_delivery_proof_call_builder { + ($pipeline:ident, $mocked_builder:ident, $bridge_messages:path, $receive_messages_delivery_proof:path) => { + pub struct $mocked_builder; + + impl $crate::messages_lane::ReceiveMessagesDeliveryProofCallBuilder<$pipeline> + for $mocked_builder + { + fn build_receive_messages_delivery_proof_call( + proof: $crate::messages_target::SubstrateMessagesDeliveryProof< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::TargetChain + >, + _trace_call: bool, + ) -> relay_substrate_client::CallOf< + <$pipeline as $crate::messages_lane::SubstrateMessageLane>::SourceChain + > { + $bridge_messages($receive_messages_delivery_proof(proof.1, proof.0)) + } + } + }; } /// Returns maximal number of messages and their maximal cumulative dispatch weight, based @@ -245,155 +447,10 @@ pub fn select_delivery_transaction_limits { - /// Global metrics. - pub global: GlobalMetrics, - /// Storage chain proof overhead metric. - pub source_storage_proof_overhead: StorageProofOverheadMetric, - /// Target chain proof overhead metric. - pub target_storage_proof_overhead: StorageProofOverheadMetric, - /// Source tokens to base conversion rate metric. - pub source_to_base_conversion_rate: Option, - /// Target tokens to base conversion rate metric. - pub target_to_base_conversion_rate: Option, - /// Source tokens to target tokens conversion rate metric. This rate is stored by the target - /// chain. - pub source_to_target_conversion_rate: - Option>, - /// Target tokens to source tokens conversion rate metric. This rate is stored by the source - /// chain. - pub target_to_source_conversion_rate: - Option>, -} - -impl StandaloneMessagesMetrics { - /// Swap source and target sides. - pub fn reverse(self) -> StandaloneMessagesMetrics { - StandaloneMessagesMetrics { - global: self.global, - source_storage_proof_overhead: self.target_storage_proof_overhead, - target_storage_proof_overhead: self.source_storage_proof_overhead, - source_to_base_conversion_rate: self.target_to_base_conversion_rate, - target_to_base_conversion_rate: self.source_to_base_conversion_rate, - source_to_target_conversion_rate: self.target_to_source_conversion_rate, - target_to_source_conversion_rate: self.source_to_target_conversion_rate, - } - } - - /// Register all metrics in the registry. - pub fn register_and_spawn( - self, - metrics: MetricsParams, - ) -> Result { - self.global.register_and_spawn(&metrics.registry)?; - self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?; - self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?; - if let Some(m) = self.source_to_base_conversion_rate { - m.register_and_spawn(&metrics.registry)?; - } - if let Some(m) = self.target_to_base_conversion_rate { - m.register_and_spawn(&metrics.registry)?; - } - if let Some(m) = self.target_to_source_conversion_rate { - m.register_and_spawn(&metrics.registry)?; - } - Ok(metrics) - } - - /// Return conversion rate from target to source tokens. - pub async fn target_to_source_conversion_rate(&self) -> Option { - Self::compute_target_to_source_conversion_rate( - *self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await, - *self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await, - ) - } - - /// Return conversion rate from target to source tokens, given conversion rates from - /// target/source tokens to some base token. - fn compute_target_to_source_conversion_rate( - target_to_base_conversion_rate: Option, - source_to_base_conversion_rate: Option, - ) -> Option { - Some(source_to_base_conversion_rate? / target_to_base_conversion_rate?) - } -} - -/// Create standalone metrics for the message lane relay loop. -/// -/// All metrics returned by this function are exposed by loops that are serving given lane (`P`) -/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`). -pub fn standalone_metrics( - source_client: Client, - target_client: Client, - source_chain_token_id: Option<&str>, - target_chain_token_id: Option<&str>, - source_to_target_conversion_rate_params: Option<(StorageKey, FixedU128)>, - target_to_source_conversion_rate_params: Option<(StorageKey, FixedU128)>, -) -> anyhow::Result> { - Ok(StandaloneMessagesMetrics { - global: GlobalMetrics::new()?, - source_storage_proof_overhead: StorageProofOverheadMetric::new( - source_client.clone(), - format!("{}_storage_proof_overhead", SC::NAME.to_lowercase()), - format!("{} storage proof overhead", SC::NAME), - )?, - target_storage_proof_overhead: StorageProofOverheadMetric::new( - target_client.clone(), - format!("{}_storage_proof_overhead", TC::NAME.to_lowercase()), - format!("{} storage proof overhead", TC::NAME), - )?, - source_to_base_conversion_rate: source_chain_token_id - .map(|source_chain_token_id| { - crate::helpers::token_price_metric(source_chain_token_id).map(Some) - }) - .unwrap_or(Ok(None))?, - target_to_base_conversion_rate: target_chain_token_id - .map(|target_chain_token_id| { - crate::helpers::token_price_metric(target_chain_token_id).map(Some) - }) - .unwrap_or(Ok(None))?, - source_to_target_conversion_rate: source_to_target_conversion_rate_params - .map(|(key, rate)| { - FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( - target_client, - key, - Some(rate), - format!("{}_{}_to_{}_conversion_rate", TC::NAME, SC::NAME, TC::NAME), - format!( - "{} to {} tokens conversion rate (used by {})", - SC::NAME, - TC::NAME, - TC::NAME - ), - ) - .map(Some) - }) - .unwrap_or(Ok(None))?, - target_to_source_conversion_rate: target_to_source_conversion_rate_params - .map(|(key, rate)| { - FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( - source_client, - key, - Some(rate), - format!("{}_{}_to_{}_conversion_rate", SC::NAME, TC::NAME, SC::NAME), - format!( - "{} to {} tokens conversion rate (used by {})", - TC::NAME, - SC::NAME, - SC::NAME - ), - ) - .map(Some) - }) - .unwrap_or(Ok(None))?, - }) -} - #[cfg(test)] mod tests { use super::*; + use bp_runtime::Chain; type RialtoToMillauMessagesWeights = pallet_bridge_messages::weights::RialtoWeight; @@ -402,8 +459,8 @@ mod tests { fn select_delivery_transaction_limits_works() { let (max_count, max_weight) = select_delivery_transaction_limits::( - bp_millau::max_extrinsic_weight(), - bp_millau::MAX_UNREWARDED_RELAYER_ENTRIES_AT_INBOUND_LANE, + bp_millau::Millau::max_extrinsic_weight(), + bp_rialto::MAX_UNREWARDED_RELAYERS_IN_CONFIRMATION_TX, ); assert_eq!( (max_count, max_weight), @@ -415,12 +472,4 @@ mod tests { (782, 216_583_333_334), ); } - - #[async_std::test] - async fn target_to_source_conversion_rate_works() { - assert_eq!( - StandaloneMessagesMetrics::::compute_target_to_source_conversion_rate(Some(183.15), Some(12.32)), - Some(12.32 / 183.15), - ); - } } diff --git a/relays/lib-substrate-relay/src/messages_metrics.rs b/relays/lib-substrate-relay/src/messages_metrics.rs new file mode 100644 index 0000000000..54eef6c0ae --- /dev/null +++ b/relays/lib-substrate-relay/src/messages_metrics.rs @@ -0,0 +1,199 @@ +// 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 . + +//! Tools for supporting message lanes between two Substrate-based chains. + +use crate::messages_lane::SubstrateMessageLane; + +use num_traits::One; +use relay_substrate_client::{ + metrics::{FloatStorageValueMetric, StorageProofOverheadMetric}, + Chain, Client, +}; +use relay_utils::metrics::{ + FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric, +}; +use sp_runtime::FixedU128; +use std::fmt::Debug; + +/// Shared references to the standalone metrics of the message lane relay loop. +#[derive(Debug, Clone)] +pub struct StandaloneMessagesMetrics { + /// Global metrics. + pub global: GlobalMetrics, + /// Storage chain proof overhead metric. + pub source_storage_proof_overhead: StorageProofOverheadMetric, + /// Target chain proof overhead metric. + pub target_storage_proof_overhead: StorageProofOverheadMetric, + /// Source tokens to base conversion rate metric. + pub source_to_base_conversion_rate: Option, + /// Target tokens to base conversion rate metric. + pub target_to_base_conversion_rate: Option, + /// Source tokens to target tokens conversion rate metric. This rate is stored by the target + /// chain. + pub source_to_target_conversion_rate: + Option>, + /// Target tokens to source tokens conversion rate metric. This rate is stored by the source + /// chain. + pub target_to_source_conversion_rate: + Option>, +} + +impl StandaloneMessagesMetrics { + /// Swap source and target sides. + pub fn reverse(self) -> StandaloneMessagesMetrics { + StandaloneMessagesMetrics { + global: self.global, + source_storage_proof_overhead: self.target_storage_proof_overhead, + target_storage_proof_overhead: self.source_storage_proof_overhead, + source_to_base_conversion_rate: self.target_to_base_conversion_rate, + target_to_base_conversion_rate: self.source_to_base_conversion_rate, + source_to_target_conversion_rate: self.target_to_source_conversion_rate, + target_to_source_conversion_rate: self.source_to_target_conversion_rate, + } + } + + /// Register all metrics in the registry. + pub fn register_and_spawn( + self, + metrics: MetricsParams, + ) -> Result { + self.global.register_and_spawn(&metrics.registry)?; + self.source_storage_proof_overhead.register_and_spawn(&metrics.registry)?; + self.target_storage_proof_overhead.register_and_spawn(&metrics.registry)?; + if let Some(m) = self.source_to_base_conversion_rate { + m.register_and_spawn(&metrics.registry)?; + } + if let Some(m) = self.target_to_base_conversion_rate { + m.register_and_spawn(&metrics.registry)?; + } + if let Some(m) = self.target_to_source_conversion_rate { + m.register_and_spawn(&metrics.registry)?; + } + Ok(metrics) + } + + /// Return conversion rate from target to source tokens. + pub async fn target_to_source_conversion_rate(&self) -> Option { + Self::compute_target_to_source_conversion_rate( + *self.target_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await, + *self.source_to_base_conversion_rate.as_ref()?.shared_value_ref().read().await, + ) + } + + /// Return conversion rate from target to source tokens, given conversion rates from + /// target/source tokens to some base token. + fn compute_target_to_source_conversion_rate( + target_to_base_conversion_rate: Option, + source_to_base_conversion_rate: Option, + ) -> Option { + Some(source_to_base_conversion_rate? / target_to_base_conversion_rate?) + } +} + +/// Create standalone metrics for the message lane relay loop. +/// +/// All metrics returned by this function are exposed by loops that are serving given lane (`P`) +/// and by loops that are serving reverse lane (`P` with swapped `TargetChain` and `SourceChain`). +/// We assume that either conversion rate parameters have values in the storage, or they are +/// initialized with 1:1. +pub fn standalone_metrics( + source_client: Client, + target_client: Client, +) -> anyhow::Result> { + Ok(StandaloneMessagesMetrics { + global: GlobalMetrics::new()?, + source_storage_proof_overhead: StorageProofOverheadMetric::new( + source_client.clone(), + format!("{}_storage_proof_overhead", P::SourceChain::NAME.to_lowercase()), + format!("{} storage proof overhead", P::SourceChain::NAME), + )?, + target_storage_proof_overhead: StorageProofOverheadMetric::new( + target_client.clone(), + format!("{}_storage_proof_overhead", P::TargetChain::NAME.to_lowercase()), + format!("{} storage proof overhead", P::TargetChain::NAME), + )?, + source_to_base_conversion_rate: P::SourceChain::TOKEN_ID + .map(|source_chain_token_id| { + crate::helpers::token_price_metric(source_chain_token_id).map(Some) + }) + .unwrap_or(Ok(None))?, + target_to_base_conversion_rate: P::TargetChain::TOKEN_ID + .map(|target_chain_token_id| { + crate::helpers::token_price_metric(target_chain_token_id).map(Some) + }) + .unwrap_or(Ok(None))?, + source_to_target_conversion_rate: P::SOURCE_TO_TARGET_CONVERSION_RATE_PARAMETER_NAME + .map(bp_runtime::storage_parameter_key) + .map(|key| { + FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( + target_client, + key, + Some(FixedU128::one()), + format!( + "{}_{}_to_{}_conversion_rate", + P::TargetChain::NAME, + P::SourceChain::NAME, + P::TargetChain::NAME + ), + format!( + "{} to {} tokens conversion rate (used by {})", + P::SourceChain::NAME, + P::TargetChain::NAME, + P::TargetChain::NAME + ), + ) + .map(Some) + }) + .unwrap_or(Ok(None))?, + target_to_source_conversion_rate: P::TARGET_TO_SOURCE_CONVERSION_RATE_PARAMETER_NAME + .map(bp_runtime::storage_parameter_key) + .map(|key| { + FloatStorageValueMetric::<_, sp_runtime::FixedU128>::new( + source_client, + key, + Some(FixedU128::one()), + format!( + "{}_{}_to_{}_conversion_rate", + P::SourceChain::NAME, + P::TargetChain::NAME, + P::SourceChain::NAME + ), + format!( + "{} to {} tokens conversion rate (used by {})", + P::TargetChain::NAME, + P::SourceChain::NAME, + P::SourceChain::NAME + ), + ) + .map(Some) + }) + .unwrap_or(Ok(None))?, + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[async_std::test] + async fn target_to_source_conversion_rate_works() { + assert_eq!( + StandaloneMessagesMetrics::::compute_target_to_source_conversion_rate(Some(183.15), Some(12.32)), + Some(12.32 / 183.15), + ); + } +} diff --git a/relays/lib-substrate-relay/src/messages_source.rs b/relays/lib-substrate-relay/src/messages_source.rs index 5f066296e7..4918635550 100644 --- a/relays/lib-substrate-relay/src/messages_source.rs +++ b/relays/lib-substrate-relay/src/messages_source.rs @@ -19,12 +19,19 @@ //! chain. use crate::{ - messages_lane::SubstrateMessageLane, messages_target::SubstrateMessagesReceivingProof, + messages_lane::{ + MessageLaneAdapter, ReceiveMessagesDeliveryProofCallBuilder, SubstrateMessageLane, + }, + messages_target::SubstrateMessagesDeliveryProof, on_demand_headers::OnDemandHeadersRelay, + TransactionParams, }; use async_trait::async_trait; -use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState}; +use bp_messages::{ + storage_keys::outbound_lane_data_key, LaneId, MessageNonce, OutboundLaneData, + UnrewardedRelayersState, +}; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; @@ -39,15 +46,13 @@ use messages_relay::{ }; use num_traits::{Bounded, Zero}; use relay_substrate_client::{ - BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderIdOf, HeaderOf, - IndexOf, -}; -use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; -use sp_core::Bytes; -use sp_runtime::{ - traits::{AtLeast32BitUnsigned, Header as HeaderT}, - DeserializeOwned, + AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client, + Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra, + TransactionSignScheme, UnsignedTransaction, }; +use relay_utils::{relay_loop::Client as RelayClient, HeaderId}; +use sp_core::{Bytes, Pair}; +use sp_runtime::{traits::Header as HeaderT, DeserializeOwned}; use std::ops::RangeInclusive; /// Intermediate message proof returned by the source Substrate node. Includes everything @@ -58,8 +63,8 @@ pub type SubstrateMessagesProof = (Weight, FromBridgedChainMessagesProof { client: Client, - lane: P, lane_id: LaneId, + transaction_params: TransactionParams>, target_to_source_headers_relay: Option>, } @@ -67,11 +72,16 @@ impl SubstrateMessagesSource

{ /// Create new Substrate headers source. pub fn new( client: Client, - lane: P, lane_id: LaneId, + transaction_params: TransactionParams>, target_to_source_headers_relay: Option>, ) -> Self { - SubstrateMessagesSource { client, lane, lane_id, target_to_source_headers_relay } + SubstrateMessagesSource { + client, + lane_id, + transaction_params, + target_to_source_headers_relay, + } } } @@ -79,8 +89,8 @@ impl Clone for SubstrateMessagesSource

{ fn clone(&self) -> Self { Self { client: self.client.clone(), - lane: self.lane.clone(), lane_id: self.lane_id, + transaction_params: self.transaction_params.clone(), target_to_source_headers_relay: self.target_to_source_headers_relay.clone(), } } @@ -96,70 +106,53 @@ impl RelayClient for SubstrateMessagesSource

{ } #[async_trait] -impl

SourceClient for SubstrateMessagesSource

+impl SourceClient> for SubstrateMessagesSource

where - P: SubstrateMessageLane, - P::SourceChain: Chain< - Hash = ::SourceHeaderHash, - BlockNumber = ::SourceHeaderNumber, - Balance = ::SourceChainBalance, - >, - BalanceOf: Decode + Bounded, - IndexOf: DeserializeOwned, - HashOf: Copy, - BlockNumberOf: BlockNumberBase + Copy, - HeaderOf: DeserializeOwned, - P::TargetChain: Chain< - Hash = ::TargetHeaderHash, - BlockNumber = ::TargetHeaderNumber, - >, - - P::MessageLane: MessageLane< - MessagesProof = SubstrateMessagesProof, - MessagesReceivingProof = SubstrateMessagesReceivingProof, - >, - ::TargetHeaderNumber: Decode, - ::TargetHeaderHash: Decode, - ::SourceChainBalance: AtLeast32BitUnsigned, + AccountIdOf: + From< as Pair>::Public>, + P::SourceTransactionSignScheme: TransactionSignScheme, { - async fn state(&self) -> Result, SubstrateError> { + async fn state(&self) -> Result>, SubstrateError> { // we can't continue to deliver confirmations if source node is out of sync, because // it may have already received confirmations that we're going to deliver self.client.ensure_synced().await?; read_client_state::< _, - ::TargetHeaderHash, - ::TargetHeaderNumber, - >(&self.client, P::BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE) + as MessageLane>::TargetHeaderHash, + as MessageLane>::TargetHeaderNumber, + >(&self.client, P::TargetChain::BEST_FINALIZED_HEADER_ID_METHOD) .await } async fn latest_generated_nonce( &self, - id: SourceHeaderIdOf, - ) -> Result<(SourceHeaderIdOf, MessageNonce), SubstrateError> { - let encoded_response = self + id: SourceHeaderIdOf>, + ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { + let outbound_lane_data: Option = self .client - .state_call( - P::OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD.into(), - Bytes(self.lane_id.encode()), + .storage_value( + outbound_lane_data_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ), Some(id.1), ) .await?; - let latest_generated_nonce: MessageNonce = Decode::decode(&mut &encoded_response.0[..]) - .map_err(SubstrateError::ResponseParseFailed)?; + // lane data missing from the storage is fine until first message is sent + let latest_generated_nonce = + outbound_lane_data.map(|data| data.latest_generated_nonce).unwrap_or(0); Ok((id, latest_generated_nonce)) } async fn latest_confirmed_received_nonce( &self, - id: SourceHeaderIdOf, - ) -> Result<(SourceHeaderIdOf, MessageNonce), SubstrateError> { + id: SourceHeaderIdOf>, + ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { let encoded_response = self .client .state_call( - P::OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD.into(), + P::TargetChain::TO_CHAIN_LATEST_RECEIVED_NONCE_METHOD.into(), Bytes(self.lane_id.encode()), Some(id.1), ) @@ -171,16 +164,16 @@ where async fn generated_message_details( &self, - id: SourceHeaderIdOf, + id: SourceHeaderIdOf>, nonces: RangeInclusive, ) -> Result< - MessageDetailsMap<::SourceChainBalance>, + MessageDetailsMap< as MessageLane>::SourceChainBalance>, SubstrateError, > { let encoded_response = self .client .state_call( - P::OUTBOUND_LANE_MESSAGE_DETAILS_METHOD.into(), + P::TargetChain::TO_CHAIN_MESSAGE_DETAILS_METHOD.into(), Bytes((self.lane_id, nonces.start(), nonces.end()).encode()), Some(id.1), ) @@ -195,14 +188,14 @@ where async fn prove_messages( &self, - id: SourceHeaderIdOf, + id: SourceHeaderIdOf>, nonces: RangeInclusive, proof_parameters: MessageProofParameters, ) -> Result< ( - SourceHeaderIdOf, + SourceHeaderIdOf>, RangeInclusive, - ::MessagesProof, + as MessageLane>::MessagesProof, ), SubstrateError, > { @@ -210,8 +203,8 @@ where Vec::with_capacity(nonces.end().saturating_sub(*nonces.start()) as usize + 1); let mut message_nonce = *nonces.start(); while message_nonce <= *nonces.end() { - let message_key = pallet_bridge_messages::storage_keys::message_key( - P::MESSAGE_PALLET_NAME_AT_SOURCE, + let message_key = bp_messages::storage_keys::message_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, message_nonce, ); @@ -219,8 +212,8 @@ where message_nonce += 1; } if proof_parameters.outbound_state_proof_required { - storage_keys.push(pallet_bridge_messages::storage_keys::outbound_lane_data_key( - P::MESSAGE_PALLET_NAME_AT_SOURCE, + storage_keys.push(bp_messages::storage_keys::outbound_lane_data_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, )); } @@ -238,19 +231,25 @@ where async fn submit_messages_receiving_proof( &self, - generated_at_block: TargetHeaderIdOf, - proof: ::MessagesReceivingProof, + _generated_at_block: TargetHeaderIdOf>, + proof: as MessageLane>::MessagesReceivingProof, ) -> Result<(), SubstrateError> { - let lane = self.lane.clone(); + let genesis_hash = *self.client.genesis_hash(); + let transaction_params = self.transaction_params.clone(); + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; self.client .submit_signed_extrinsic( - self.lane.source_transactions_author(), + self.transaction_params.signer.public().into(), move |best_block_id, transaction_nonce| { - lane.make_messages_receiving_proof_transaction( + make_messages_delivery_proof_transaction::

( + spec_version, + transaction_version, + &genesis_hash, + &transaction_params, best_block_id, transaction_nonce, - generated_at_block, proof, + true, ) }, ) @@ -258,7 +257,7 @@ where Ok(()) } - async fn require_target_header_on_source(&self, id: TargetHeaderIdOf) { + async fn require_target_header_on_source(&self, id: TargetHeaderIdOf>) { if let Some(ref target_to_source_headers_relay) = self.target_to_source_headers_relay { target_to_source_headers_relay.require_finalized_header(id).await; } @@ -266,13 +265,21 @@ where async fn estimate_confirmation_transaction( &self, - ) -> ::SourceChainBalance { + ) -> as MessageLane>::SourceChainBalance { + let runtime_version = match self.client.runtime_version().await { + Ok(v) => v, + Err(_) => return BalanceOf::::max_value(), + }; self.client - .estimate_extrinsic_fee(self.lane.make_messages_receiving_proof_transaction( + .estimate_extrinsic_fee(make_messages_delivery_proof_transaction::

( + runtime_version.spec_version, + runtime_version.transaction_version, + self.client.genesis_hash(), + &self.transaction_params, HeaderId(Default::default(), Default::default()), Zero::zero(), - HeaderId(Default::default(), Default::default()), prepare_dummy_messages_delivery_proof::(), + false, )) .await .map(|fee| fee.inclusion_fee()) @@ -280,12 +287,43 @@ where } } +/// Make messages delivery proof transaction from given proof. +fn make_messages_delivery_proof_transaction( + spec_version: u32, + transaction_version: u32, + source_genesis_hash: &HashOf, + source_transaction_params: &TransactionParams>, + source_best_block_id: HeaderIdOf, + transaction_nonce: IndexOf, + proof: SubstrateMessagesDeliveryProof, + trace_call: bool, +) -> Bytes +where + P::SourceTransactionSignScheme: TransactionSignScheme, +{ + let call = + P::ReceiveMessagesDeliveryProofCallBuilder::build_receive_messages_delivery_proof_call( + proof, trace_call, + ); + Bytes( + P::SourceTransactionSignScheme::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: *source_genesis_hash, + signer: source_transaction_params.signer.clone(), + era: TransactionEra::new(source_best_block_id, source_transaction_params.mortality), + unsigned: UnsignedTransaction::new(call, transaction_nonce), + }) + .encode(), + ) +} + /// Prepare 'dummy' messages delivery proof that will compose the delivery confirmation transaction. /// /// We don't care about proof actually being the valid proof, because its validity doesn't /// affect the call weight - we only care about its size. fn prepare_dummy_messages_delivery_proof( -) -> SubstrateMessagesReceivingProof { +) -> SubstrateMessagesDeliveryProof { let single_message_confirmation_size = bp_messages::InboundLaneData::<()>::encoded_size_hint( SC::MAXIMAL_ENCODED_ACCOUNT_ID_SIZE, 1, diff --git a/relays/lib-substrate-relay/src/messages_target.rs b/relays/lib-substrate-relay/src/messages_target.rs index eafc6bd3fc..7e7722bb57 100644 --- a/relays/lib-substrate-relay/src/messages_target.rs +++ b/relays/lib-substrate-relay/src/messages_target.rs @@ -19,14 +19,15 @@ //! chain. use crate::{ - messages_lane::{StandaloneMessagesMetrics, SubstrateMessageLane}, + messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane}, + messages_metrics::StandaloneMessagesMetrics, messages_source::{read_client_state, SubstrateMessagesProof}, on_demand_headers::OnDemandHeadersRelay, + TransactionParams, }; use async_trait::async_trait; use bp_messages::{LaneId, MessageNonce, UnrewardedRelayersState}; - use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, }; @@ -38,23 +39,25 @@ use messages_relay::{ }; use num_traits::{Bounded, Zero}; use relay_substrate_client::{ - BalanceOf, BlockNumberOf, Chain, Client, Error as SubstrateError, HashOf, HeaderOf, IndexOf, - WeightToFeeOf, + AccountIdOf, AccountKeyPairOf, BalanceOf, Chain, ChainWithMessages, Client, + Error as SubstrateError, HashOf, HeaderIdOf, IndexOf, SignParam, TransactionEra, + TransactionSignScheme, UnsignedTransaction, WeightToFeeOf, }; -use relay_utils::{relay_loop::Client as RelayClient, BlockNumberBase, HeaderId}; -use sp_core::Bytes; -use sp_runtime::{traits::Saturating, DeserializeOwned, FixedPointNumber, FixedU128}; +use relay_utils::{relay_loop::Client as RelayClient, HeaderId}; +use sp_core::{Bytes, Pair}; +use sp_runtime::{traits::Saturating, FixedPointNumber, FixedU128}; use std::{convert::TryFrom, ops::RangeInclusive}; /// Message receiving proof returned by the target Substrate node. -pub type SubstrateMessagesReceivingProof = +pub type SubstrateMessagesDeliveryProof = (UnrewardedRelayersState, FromBridgedChainMessagesDeliveryProof>); /// Substrate client as Substrate messages target. pub struct SubstrateMessagesTarget { client: Client, - lane: P, lane_id: LaneId, + relayer_id_at_source: AccountIdOf, + transaction_params: TransactionParams>, metric_values: StandaloneMessagesMetrics, source_to_target_headers_relay: Option>, } @@ -63,15 +66,17 @@ impl SubstrateMessagesTarget

{ /// Create new Substrate headers target. pub fn new( client: Client, - lane: P, lane_id: LaneId, + relayer_id_at_source: AccountIdOf, + transaction_params: TransactionParams>, metric_values: StandaloneMessagesMetrics, source_to_target_headers_relay: Option>, ) -> Self { SubstrateMessagesTarget { client, - lane, lane_id, + relayer_id_at_source, + transaction_params, metric_values, source_to_target_headers_relay, } @@ -82,8 +87,9 @@ impl Clone for SubstrateMessagesTarget

{ fn clone(&self) -> Self { Self { client: self.client.clone(), - lane: self.lane.clone(), lane_id: self.lane_id, + relayer_id_at_source: self.relayer_id_at_source.clone(), + transaction_params: self.transaction_params.clone(), metric_values: self.metric_values.clone(), source_to_target_headers_relay: self.source_to_target_headers_relay.clone(), } @@ -100,52 +106,34 @@ impl RelayClient for SubstrateMessagesTarget

{ } #[async_trait] -impl

TargetClient for SubstrateMessagesTarget

+impl TargetClient> for SubstrateMessagesTarget

where - P: SubstrateMessageLane, - P::SourceChain: Chain< - Hash = ::SourceHeaderHash, - BlockNumber = ::SourceHeaderNumber, - Balance = ::SourceChainBalance, - >, - BalanceOf: TryFrom> + Bounded, - P::TargetChain: Chain< - Hash = ::TargetHeaderHash, - BlockNumber = ::TargetHeaderNumber, - >, - IndexOf: DeserializeOwned, - HashOf: Copy, - BlockNumberOf: Copy, - HeaderOf: DeserializeOwned, - BlockNumberOf: BlockNumberBase, - P::MessageLane: MessageLane< - MessagesProof = SubstrateMessagesProof, - MessagesReceivingProof = SubstrateMessagesReceivingProof, - >, - ::SourceHeaderNumber: Decode, - ::SourceHeaderHash: Decode, + AccountIdOf: + From< as Pair>::Public>, + P::TargetTransactionSignScheme: TransactionSignScheme, + BalanceOf: TryFrom>, { - async fn state(&self) -> Result, SubstrateError> { + async fn state(&self) -> Result>, SubstrateError> { // we can't continue to deliver messages if target node is out of sync, because // it may have already received (some of) messages that we're going to deliver self.client.ensure_synced().await?; read_client_state::< _, - ::SourceHeaderHash, - ::SourceHeaderNumber, - >(&self.client, P::BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET) + as MessageLane>::SourceHeaderHash, + as MessageLane>::SourceHeaderNumber, + >(&self.client, P::SourceChain::BEST_FINALIZED_HEADER_ID_METHOD) .await } async fn latest_received_nonce( &self, - id: TargetHeaderIdOf, - ) -> Result<(TargetHeaderIdOf, MessageNonce), SubstrateError> { + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { let encoded_response = self .client .state_call( - P::INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD.into(), + P::SourceChain::FROM_CHAIN_LATEST_RECEIVED_NONCE_METHOD.into(), Bytes(self.lane_id.encode()), Some(id.1), ) @@ -157,12 +145,12 @@ where async fn latest_confirmed_received_nonce( &self, - id: TargetHeaderIdOf, - ) -> Result<(TargetHeaderIdOf, MessageNonce), SubstrateError> { + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { let encoded_response = self .client .state_call( - P::INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD.into(), + P::SourceChain::FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD.into(), Bytes(self.lane_id.encode()), Some(id.1), ) @@ -174,12 +162,13 @@ where async fn unrewarded_relayers_state( &self, - id: TargetHeaderIdOf, - ) -> Result<(TargetHeaderIdOf, UnrewardedRelayersState), SubstrateError> { + id: TargetHeaderIdOf>, + ) -> Result<(TargetHeaderIdOf>, UnrewardedRelayersState), SubstrateError> + { let encoded_response = self .client .state_call( - P::INBOUND_LANE_UNREWARDED_RELAYERS_STATE.into(), + P::SourceChain::FROM_CHAIN_UNREWARDED_RELAYERS_STATE.into(), Bytes(self.lane_id.encode()), Some(id.1), ) @@ -192,14 +181,17 @@ where async fn prove_messages_receiving( &self, - id: TargetHeaderIdOf, + id: TargetHeaderIdOf>, ) -> Result< - (TargetHeaderIdOf, ::MessagesReceivingProof), + ( + TargetHeaderIdOf>, + as MessageLane>::MessagesReceivingProof, + ), SubstrateError, > { let (id, relayers_state) = self.unrewarded_relayers_state(id).await?; - let inbound_data_key = pallet_bridge_messages::storage_keys::inbound_lane_data_key( - P::MESSAGE_PALLET_NAME_AT_TARGET, + let inbound_data_key = bp_messages::storage_keys::inbound_lane_data_key( + P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, &self.lane_id, ); let proof = self @@ -218,22 +210,30 @@ where async fn submit_messages_proof( &self, - generated_at_header: SourceHeaderIdOf, + _generated_at_header: SourceHeaderIdOf>, nonces: RangeInclusive, - proof: ::MessagesProof, + proof: as MessageLane>::MessagesProof, ) -> Result, SubstrateError> { - let lane = self.lane.clone(); + let genesis_hash = *self.client.genesis_hash(); + let transaction_params = self.transaction_params.clone(); + let relayer_id_at_source = self.relayer_id_at_source.clone(); let nonces_clone = nonces.clone(); + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; self.client .submit_signed_extrinsic( - self.lane.target_transactions_author(), + self.transaction_params.signer.public().into(), move |best_block_id, transaction_nonce| { - lane.make_messages_delivery_transaction( + make_messages_delivery_transaction::

( + spec_version, + transaction_version, + &genesis_hash, + &transaction_params, best_block_id, transaction_nonce, - generated_at_header, + relayer_id_at_source, nonces_clone, proof, + true, ) }, ) @@ -241,7 +241,7 @@ where Ok(nonces) } - async fn require_source_header_on_target(&self, id: SourceHeaderIdOf) { + async fn require_source_header_on_target(&self, id: SourceHeaderIdOf>) { if let Some(ref source_to_target_headers_relay) = self.source_to_target_headers_relay { source_to_target_headers_relay.require_finalized_header(id).await; } @@ -253,7 +253,7 @@ where total_prepaid_nonces: MessageNonce, total_dispatch_weight: Weight, total_size: u32, - ) -> Result<::SourceChainBalance, SubstrateError> { + ) -> Result< as MessageLane>::SourceChainBalance, SubstrateError> { let conversion_rate = self.metric_values.target_to_source_conversion_rate().await.ok_or_else(|| { SubstrateError::Custom(format!( @@ -263,17 +263,23 @@ where )) })?; + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; // Prepare 'dummy' delivery transaction - we only care about its length and dispatch weight. - let delivery_tx = self.lane.make_messages_delivery_transaction( + let delivery_tx = make_messages_delivery_transaction::

( + spec_version, + transaction_version, + self.client.genesis_hash(), + &self.transaction_params, HeaderId(Default::default(), Default::default()), Zero::zero(), - HeaderId(Default::default(), Default::default()), + Default::default(), nonces.clone(), prepare_dummy_messages_proof::( nonces.clone(), total_dispatch_weight, total_size, ), + false, ); let delivery_tx_fee = self.client.estimate_extrinsic_fee(delivery_tx).await?; let inclusion_fee_in_target_tokens = delivery_tx_fee.inclusion_fee(); @@ -297,23 +303,29 @@ where let expected_refund_in_target_tokens = if total_prepaid_nonces != 0 { const WEIGHT_DIFFERENCE: Weight = 100; + let (spec_version, transaction_version) = self.client.simple_runtime_version().await?; let larger_dispatch_weight = total_dispatch_weight.saturating_add(WEIGHT_DIFFERENCE); let larger_delivery_tx_fee = self .client - .estimate_extrinsic_fee(self.lane.make_messages_delivery_transaction( + .estimate_extrinsic_fee(make_messages_delivery_transaction::

( + spec_version, + transaction_version, + self.client.genesis_hash(), + &self.transaction_params, HeaderId(Default::default(), Default::default()), Zero::zero(), - HeaderId(Default::default(), Default::default()), + Default::default(), nonces.clone(), prepare_dummy_messages_proof::( nonces.clone(), larger_dispatch_weight, total_size, ), + false, )) .await?; - compute_prepaid_messages_refund::

( + compute_prepaid_messages_refund::( total_prepaid_nonces, compute_fee_multiplier::( delivery_tx_fee.adjusted_weight_fee, @@ -359,6 +371,45 @@ where } } +/// Make messages delivery transaction from given proof. +#[allow(clippy::too_many_arguments)] +fn make_messages_delivery_transaction( + spec_version: u32, + transaction_version: u32, + target_genesis_hash: &HashOf, + target_transaction_params: &TransactionParams>, + target_best_block_id: HeaderIdOf, + transaction_nonce: IndexOf, + relayer_id_at_source: AccountIdOf, + nonces: RangeInclusive, + proof: SubstrateMessagesProof, + trace_call: bool, +) -> Bytes +where + P::TargetTransactionSignScheme: TransactionSignScheme, +{ + let messages_count = nonces.end() - nonces.start() + 1; + let dispatch_weight = proof.0; + let call = P::ReceiveMessagesProofCallBuilder::build_receive_messages_proof_call( + relayer_id_at_source, + proof, + messages_count as _, + dispatch_weight, + trace_call, + ); + Bytes( + P::TargetTransactionSignScheme::sign_transaction(SignParam { + spec_version, + transaction_version, + genesis_hash: *target_genesis_hash, + signer: target_transaction_params.signer.clone(), + era: TransactionEra::new(target_best_block_id, target_transaction_params.mortality), + unsigned: UnsignedTransaction::new(call, transaction_nonce), + }) + .encode(), + ) +} + /// Prepare 'dummy' messages proof that will compose the delivery transaction. /// /// We don't care about proof actually being the valid proof, because its validity doesn't @@ -425,80 +476,20 @@ fn compute_fee_multiplier( /// Compute fee that will be refunded to the relayer because dispatch of `total_prepaid_nonces` /// messages has been paid at the source chain. -fn compute_prepaid_messages_refund( +fn compute_prepaid_messages_refund( total_prepaid_nonces: MessageNonce, fee_multiplier: FixedU128, -) -> BalanceOf { - fee_multiplier.saturating_mul_int(WeightToFeeOf::::calc( - &P::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN.saturating_mul(total_prepaid_nonces), +) -> BalanceOf { + fee_multiplier.saturating_mul_int(WeightToFeeOf::::calc( + &C::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN.saturating_mul(total_prepaid_nonces), )) } #[cfg(test)] mod tests { use super::*; - use relay_rococo_client::{Rococo, SigningParams as RococoSigningParams}; - use relay_wococo_client::{SigningParams as WococoSigningParams, Wococo}; - - #[derive(Clone)] - struct TestSubstrateMessageLane; - - impl SubstrateMessageLane for TestSubstrateMessageLane { - type MessageLane = crate::messages_lane::SubstrateMessageLaneToSubstrate< - Rococo, - RococoSigningParams, - Wococo, - WococoSigningParams, - >; - - const OUTBOUND_LANE_MESSAGE_DETAILS_METHOD: &'static str = ""; - const OUTBOUND_LANE_LATEST_GENERATED_NONCE_METHOD: &'static str = ""; - const OUTBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = ""; - - const INBOUND_LANE_LATEST_RECEIVED_NONCE_METHOD: &'static str = ""; - const INBOUND_LANE_LATEST_CONFIRMED_NONCE_METHOD: &'static str = ""; - const INBOUND_LANE_UNREWARDED_RELAYERS_STATE: &'static str = ""; - - const BEST_FINALIZED_SOURCE_HEADER_ID_AT_TARGET: &'static str = ""; - const BEST_FINALIZED_TARGET_HEADER_ID_AT_SOURCE: &'static str = ""; - - const MESSAGE_PALLET_NAME_AT_SOURCE: &'static str = ""; - const MESSAGE_PALLET_NAME_AT_TARGET: &'static str = ""; - - const PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN: Weight = 100_000; - - type SourceChain = Rococo; - type TargetChain = Wococo; - - fn source_transactions_author(&self) -> bp_rococo::AccountId { - unreachable!() - } - - fn make_messages_receiving_proof_transaction( - &self, - _best_block_id: SourceHeaderIdOf, - _transaction_nonce: IndexOf, - _generated_at_block: TargetHeaderIdOf, - _proof: ::MessagesReceivingProof, - ) -> Bytes { - unreachable!() - } - - fn target_transactions_author(&self) -> bp_wococo::AccountId { - unreachable!() - } - - fn make_messages_delivery_transaction( - &self, - _best_block_id: TargetHeaderIdOf, - _transaction_nonce: IndexOf, - _generated_at_header: SourceHeaderIdOf, - _nonces: RangeInclusive, - _proof: ::MessagesProof, - ) -> Bytes { - unreachable!() - } - } + use relay_rococo_client::Rococo; + use relay_wococo_client::Wococo; #[test] fn prepare_dummy_messages_proof_works() { @@ -556,11 +547,10 @@ mod tests { #[test] fn compute_prepaid_messages_refund_returns_sane_results() { assert!( - compute_prepaid_messages_refund::( + compute_prepaid_messages_refund::( 10, FixedU128::saturating_from_rational(110, 100), - ) > (10 * TestSubstrateMessageLane::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_TARGET_CHAIN) - .into() + ) > (10 * Wococo::PAY_INBOUND_DISPATCH_FEE_WEIGHT_AT_CHAIN).into() ); } } diff --git a/relays/lib-substrate-relay/src/on_demand_headers.rs b/relays/lib-substrate-relay/src/on_demand_headers.rs index ee141866eb..d66aaba549 100644 --- a/relays/lib-substrate-relay/src/on_demand_headers.rs +++ b/relays/lib-substrate-relay/src/on_demand_headers.rs @@ -16,31 +16,24 @@ //! On-demand Substrate -> Substrate headers relay. -use std::fmt::Debug; - use async_std::sync::{Arc, Mutex}; use futures::{select, FutureExt}; use num_traits::{CheckedSub, One, Zero}; -use finality_relay::{ - FinalitySyncParams, FinalitySyncPipeline, SourceClient as FinalitySourceClient, SourceHeader, - TargetClient as FinalityTargetClient, -}; +use finality_relay::{FinalitySyncParams, SourceHeader, TargetClient as FinalityTargetClient}; use relay_substrate_client::{ - finality_source::{FinalitySource as SubstrateFinalitySource, RequiredHeaderNumberRef}, - Chain, Client, HeaderIdOf, SyncHeader, + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, HeaderIdOf, HeaderOf, SyncHeader, + TransactionSignScheme, }; use relay_utils::{ - metrics::MetricsParams, relay_loop::Client as RelayClient, BlockNumberBase, FailedClient, - MaybeConnectionError, + metrics::MetricsParams, relay_loop::Client as RelayClient, FailedClient, MaybeConnectionError, }; use crate::{ - finality_pipeline::{ - SubstrateFinalitySyncPipeline, SubstrateFinalityToSubstrate, RECENT_FINALITY_PROOFS_LIMIT, - }, + finality_pipeline::{SubstrateFinalitySyncPipeline, RECENT_FINALITY_PROOFS_LIMIT}, + finality_source::{RequiredHeaderNumberRef, SubstrateFinalitySource}, finality_target::SubstrateFinalityTarget, - STALL_TIMEOUT, + TransactionParams, STALL_TIMEOUT, }; /// On-demand Substrate <-> Substrate headers relay. @@ -58,40 +51,28 @@ pub struct OnDemandHeadersRelay { impl OnDemandHeadersRelay { /// Create new on-demand headers relay. - pub fn new( - source_client: Client, - target_client: Client, - target_transactions_mortality: Option, - pipeline: P, - maximal_headers_difference: SourceChain::BlockNumber, + pub fn new>( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + maximal_headers_difference: BlockNumberOf, only_mandatory_headers: bool, ) -> Self where - SourceChain: Chain + Debug, - SourceChain::BlockNumber: BlockNumberBase, - TargetChain: Chain + Debug, - TargetChain::BlockNumber: BlockNumberBase, - TargetSign: Clone + Send + Sync + 'static, - P: SubstrateFinalitySyncPipeline< - FinalitySyncPipeline = SubstrateFinalityToSubstrate< - SourceChain, - TargetChain, - TargetSign, - >, - TargetChain = TargetChain, - >, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { let required_header_number = Arc::new(Mutex::new(Zero::zero())); let this = OnDemandHeadersRelay { - relay_task_name: on_demand_headers_relay_name::(), + relay_task_name: on_demand_headers_relay_name::(), required_header_number: required_header_number.clone(), }; async_std::task::spawn(async move { - background_task( + background_task::

( source_client, target_client, - target_transactions_mortality, - pipeline, + target_transaction_params, maximal_headers_difference, only_mandatory_headers, required_header_number, @@ -120,35 +101,26 @@ impl OnDemandHeadersRelay { } /// Background task that is responsible for starting headers relay. -async fn background_task( - source_client: Client, - target_client: Client, - target_transactions_mortality: Option, - pipeline: P, - maximal_headers_difference: SourceChain::BlockNumber, +async fn background_task( + source_client: Client, + target_client: Client, + target_transaction_params: TransactionParams>, + maximal_headers_difference: BlockNumberOf, only_mandatory_headers: bool, - required_header_number: RequiredHeaderNumberRef, + required_header_number: RequiredHeaderNumberRef, ) where - SourceChain: Chain + Debug, - SourceChain::BlockNumber: BlockNumberBase, - TargetChain: Chain + Debug, - TargetChain::BlockNumber: BlockNumberBase, - TargetSign: Clone + Send + Sync + 'static, - P: SubstrateFinalitySyncPipeline< - FinalitySyncPipeline = SubstrateFinalityToSubstrate, - TargetChain = TargetChain, - >, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { - let relay_task_name = on_demand_headers_relay_name::(); - let mut finality_source = SubstrateFinalitySource::< - _, - SubstrateFinalityToSubstrate, - >::new(source_client.clone(), Some(required_header_number.clone())); - let mut finality_target = SubstrateFinalityTarget::new( - target_client.clone(), - pipeline.clone(), - target_transactions_mortality, + let relay_task_name = on_demand_headers_relay_name::(); + let target_transactions_mortality = target_transaction_params.mortality; + let mut finality_source = SubstrateFinalitySource::

::new( + source_client.clone(), + Some(required_header_number.clone()), ); + let mut finality_target = + SubstrateFinalityTarget::new(target_client.clone(), target_transaction_params); let mut latest_non_mandatory_at_source = Zero::zero(); let mut restart_relay = true; @@ -157,7 +129,7 @@ async fn background_task( loop { select! { - _ = async_std::task::sleep(TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, + _ = async_std::task::sleep(P::TargetChain::AVERAGE_BLOCK_INTERVAL).fuse() => {}, _ = finality_relay_task => { // this should never happen in practice given the current code restart_relay = true; @@ -179,12 +151,8 @@ async fn background_task( } // read best finalized source header number from target - let best_finalized_source_header_at_target = best_finalized_source_header_at_target::< - SourceChain, - _, - _, - >(&finality_target, &relay_task_name) - .await; + let best_finalized_source_header_at_target = + best_finalized_source_header_at_target::

(&finality_target, &relay_task_name).await; if matches!(best_finalized_source_header_at_target, Err(ref e) if e.is_connection_error()) { relay_utils::relay_loop::reconnect_failed_client( FailedClient::Target, @@ -199,7 +167,7 @@ async fn background_task( // submit mandatory header if some headers are missing let best_finalized_source_header_at_target_fmt = format!("{:?}", best_finalized_source_header_at_target); - let mandatory_scan_range = mandatory_headers_scan_range::( + let mandatory_scan_range = mandatory_headers_scan_range::( best_finalized_source_header_at_source.ok(), best_finalized_source_header_at_target.ok(), maximal_headers_difference, @@ -247,11 +215,15 @@ async fn background_task( finality_target.clone(), FinalitySyncParams { tick: std::cmp::max( - SourceChain::AVERAGE_BLOCK_INTERVAL, - TargetChain::AVERAGE_BLOCK_INTERVAL, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, ), recent_finality_proofs_limit: RECENT_FINALITY_PROOFS_LIMIT, - stall_timeout: STALL_TIMEOUT, + stall_timeout: relay_substrate_client::transaction_stall_timeout( + target_transactions_mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ), only_mandatory_headers, }, MetricsParams::disabled(), @@ -316,17 +288,13 @@ async fn mandatory_headers_scan_range( /// it. /// /// Returns `true` if header was found and (asked to be) relayed and `false` otherwise. -async fn relay_mandatory_header_from_range( - finality_source: &SubstrateFinalitySource, - required_header_number: &RequiredHeaderNumberRef, +async fn relay_mandatory_header_from_range( + finality_source: &SubstrateFinalitySource

, + required_header_number: &RequiredHeaderNumberRef, best_finalized_source_header_at_target: String, - range: (SourceChain::BlockNumber, SourceChain::BlockNumber), + range: (BlockNumberOf, BlockNumberOf), relay_task_name: &str, -) -> Result -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +) -> Result { // search for mandatory header first let mandatory_source_header_number = find_mandatory_header_in_range(finality_source, range).await?; @@ -347,7 +315,7 @@ where log::trace!( target: "bridge", "Too many {} headers missing at target in {} relay ({} vs {}). Going to sync up to the mandatory {}", - SourceChain::NAME, + P::SourceChain::NAME, relay_task_name, best_finalized_source_header_at_target, range.1, @@ -361,14 +329,10 @@ where /// Read best finalized source block number from source client. /// /// Returns `None` if we have failed to read the number. -async fn best_finalized_source_header_at_source( - finality_source: &SubstrateFinalitySource, +async fn best_finalized_source_header_at_source( + finality_source: &SubstrateFinalitySource

, relay_task_name: &str, -) -> Result -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +) -> Result, relay_substrate_client::Error> { finality_source.on_chain_best_finalized_block_number().await.map_err(|error| { log::error!( target: "bridge", @@ -384,14 +348,14 @@ where /// Read best finalized source block number from target client. /// /// Returns `None` if we have failed to read the number. -async fn best_finalized_source_header_at_target( - finality_target: &SubstrateFinalityTarget, +async fn best_finalized_source_header_at_target( + finality_target: &SubstrateFinalityTarget

, relay_task_name: &str, -) -> Result as RelayClient>::Error> +) -> Result, as RelayClient>::Error> where - SubstrateFinalityTarget: FinalityTargetClient, - P: SubstrateFinalitySyncPipeline, - P::FinalitySyncPipeline: FinalitySyncPipeline, + AccountIdOf: + From< as sp_core::Pair>::Public>, + P::TransactionSignScheme: TransactionSignScheme, { finality_target.best_finalized_source_block_number().await.map_err(|error| { log::error!( @@ -408,17 +372,13 @@ where /// Read first mandatory header in given inclusive range. /// /// Returns `Ok(None)` if there were no mandatory headers in the range. -async fn find_mandatory_header_in_range( - finality_source: &SubstrateFinalitySource, - range: (SourceChain::BlockNumber, SourceChain::BlockNumber), -) -> Result, relay_substrate_client::Error> -where - SubstrateFinalitySource: FinalitySourceClient

, - P: FinalitySyncPipeline, -{ +async fn find_mandatory_header_in_range( + finality_source: &SubstrateFinalitySource

, + range: (BlockNumberOf, BlockNumberOf), +) -> Result>, relay_substrate_client::Error> { let mut current = range.0; while current <= range.1 { - let header: SyncHeader = + let header: SyncHeader> = finality_source.client().header_by_number(current).await?.into(); if header.is_mandatory() { return Ok(Some(current))