diff --git a/Cargo.lock b/Cargo.lock index 1f0ec406ec..b442088d98 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -920,7 +920,6 @@ name = "bp-westend" version = "0.1.0" dependencies = [ "bp-header-chain", - "bp-messages", "bp-polkadot-core", "bp-runtime", "frame-support", @@ -956,7 +955,9 @@ dependencies = [ "bp-runtime", "ed25519-dalek", "frame-support", + "frame-system", "hash-db", + "pallet-balances", "pallet-bridge-dispatch", "pallet-bridge-grandpa", "pallet-bridge-messages", @@ -968,6 +969,7 @@ dependencies = [ "sp-state-machine", "sp-std", "sp-trie", + "sp-version", ] [[package]] @@ -8048,6 +8050,7 @@ dependencies = [ "parity-scale-codec", "rand 0.7.3", "relay-utils", + "sc-chain-spec", "sc-rpc-api", "sc-transaction-pool-api", "sp-core", @@ -8185,34 +8188,10 @@ dependencies = [ "pallet-mmr-rpc", "pallet-transaction-payment-rpc", "pallet-transaction-payment-rpc-runtime-api", - "polkadot-approval-distribution", - "polkadot-availability-bitfield-distribution", - "polkadot-availability-distribution", - "polkadot-availability-recovery", - "polkadot-client", - "polkadot-collator-protocol", - "polkadot-dispute-distribution", - "polkadot-gossip-support", - "polkadot-network-bridge", - "polkadot-node-collation-generation", - "polkadot-node-core-approval-voting", - "polkadot-node-core-av-store", - "polkadot-node-core-backing", - "polkadot-node-core-bitfield-signing", - "polkadot-node-core-candidate-validation", - "polkadot-node-core-chain-api", - "polkadot-node-core-chain-selection", - "polkadot-node-core-dispute-coordinator", - "polkadot-node-core-parachains-inherent", - "polkadot-node-core-provisioner", "polkadot-node-core-pvf", - "polkadot-node-core-runtime-api", - "polkadot-node-network-protocol", - "polkadot-node-subsystem-util", - "polkadot-overseer", "polkadot-primitives", "polkadot-runtime-parachains", - "polkadot-statement-distribution", + "polkadot-service", "rialto-runtime", "sc-authority-discovery", "sc-basic-authorship", @@ -11048,10 +11027,12 @@ dependencies = [ "finality-grandpa", "finality-relay", "frame-support", + "frame-system", "futures 0.3.18", "log", "messages-relay", "num-traits", + "pallet-balances", "pallet-bridge-grandpa", "pallet-bridge-messages", "parity-scale-codec", diff --git a/bin/millau/runtime/src/lib.rs b/bin/millau/runtime/src/lib.rs index 4d6ecd8ba3..33839614e7 100644 --- a/bin/millau/runtime/src/lib.rs +++ b/bin/millau/runtime/src/lib.rs @@ -776,10 +776,6 @@ impl_runtime_apis! { } impl bp_rialto::FromRialtoInboundLaneApi for Runtime { - fn latest_confirmed_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { - BridgeRialtoMessages::inbound_latest_confirmed_nonce(lane) - } - fn unrewarded_relayers_state(lane: bp_messages::LaneId) -> bp_messages::UnrewardedRelayersState { BridgeRialtoMessages::inbound_unrewarded_relayers_state(lane) } @@ -828,7 +824,7 @@ impl_runtime_apis! { let mut batches = Vec::::new(); let params = (&config, &whitelist); - use bp_runtime::messages::DispatchFeePayment; + use bridge_runtime_common::messages_benchmarking::{prepare_message_delivery_proof, prepare_message_proof, prepare_outbound_message}; use bridge_runtime_common::messages; use pallet_bridge_messages::benchmarking::{ Pallet as MessagesBench, @@ -836,9 +832,8 @@ impl_runtime_apis! { MessageDeliveryProofParams, MessageParams, MessageProofParams, - ProofSize as MessagesProofSize, }; - use rialto_messages::{ToRialtoMessagePayload, WithRialtoMessageBridge}; + use rialto_messages::WithRialtoMessageBridge; impl MessagesConfig for Runtime { fn maximal_message_size() -> u32 { @@ -863,120 +858,24 @@ impl_runtime_apis! { fn prepare_outbound_message( params: MessageParams, ) -> (rialto_messages::ToRialtoMessagePayload, Balance) { - let message_payload = vec![0; params.size as usize]; - let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount( - params.sender_account, - ); - - let message = ToRialtoMessagePayload { - spec_version: 0, - weight: params.size as _, - origin: dispatch_origin, - call: message_payload, - dispatch_fee_payment: DispatchFeePayment::AtSourceChain, - }; - (message, pallet_bridge_messages::benchmarking::MESSAGE_FEE.into()) + prepare_outbound_message::(params) } fn prepare_message_proof( params: MessageProofParams, ) -> (rialto_messages::FromRialtoMessagesProof, Weight) { - 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 rialto_messages::WithRialtoMessageBridge; - use sp_runtime::traits::{Header, IdentifyAccount}; - - let remark = match params.size { - MessagesProofSize::Minimal(ref size) => vec![0u8; *size as _], - _ => vec![], - }; - let call = Call::System(SystemCall::remark { remark }); - let call_weight = call.get_dispatch_info().weight; - - let rialto_account_id: bp_rialto::AccountId = Default::default(); - let (millau_raw_public, millau_raw_signature) = ed25519_sign( - &call, - &rialto_account_id, - VERSION.spec_version, - bp_runtime::RIALTO_CHAIN_ID, - bp_runtime::MILLAU_CHAIN_ID, - ); - let millau_public = MultiSigner::Ed25519(sp_core::ed25519::Public::from_raw(millau_raw_public)); - let millau_signature = MultiSignature::Ed25519(sp_core::ed25519::Signature::from_raw( - millau_raw_signature, - )); - - if params.dispatch_fee_payment == DispatchFeePayment::AtTargetChain { - Self::endow_account(&millau_public.clone().into_account()); - } - - let make_rialto_message_key = |message_key: MessageKey| storage_keys::message_key( - ::BRIDGED_MESSAGES_PALLET_NAME, - &message_key.lane_id, message_key.nonce, - ).0; - let make_rialto_outbound_lane_data_key = |lane_id| storage_keys::outbound_lane_data_key( - ::BRIDGED_MESSAGES_PALLET_NAME, - &lane_id, - ).0; - - let make_rialto_header = |state_root| bp_rialto::Header::new( - 0, - Default::default(), - state_root, - Default::default(), - Default::default(), - ); - - let dispatch_fee_payment = params.dispatch_fee_payment.clone(); - prepare_message_proof::( + prepare_message_proof::( params, - make_rialto_message_key, - make_rialto_outbound_lane_data_key, - make_rialto_header, - call_weight, - bp_message_dispatch::MessagePayload { - spec_version: VERSION.spec_version, - weight: call_weight, - origin: bp_message_dispatch::CallOrigin::< - bp_rialto::AccountId, - MultiSigner, - Signature, - >::TargetAccount( - rialto_account_id, - millau_public, - millau_signature, - ), - dispatch_fee_payment, - call: call.encode(), - }.encode(), + &VERSION, + Balance::MAX / 100, ) } fn prepare_message_delivery_proof( params: MessageDeliveryProofParams, ) -> rialto_messages::ToRialtoMessagesDeliveryProof { - use bridge_runtime_common::messages_benchmarking::prepare_message_delivery_proof; - use rialto_messages::WithRialtoMessageBridge; - use sp_runtime::traits::Header; - - prepare_message_delivery_proof::( + prepare_message_delivery_proof::( params, - |lane_id| bp_messages::storage_keys::inbound_lane_data_key( - ::BRIDGED_MESSAGES_PALLET_NAME, - &lane_id, - ).0, - |state_root| bp_rialto::Header::new( - 0, - Default::default(), - state_root, - Default::default(), - Default::default(), - ), ) } diff --git a/bin/rialto/node/Cargo.toml b/bin/rialto/node/Cargo.toml index 2795f2eeca..77694e552a 100644 --- a/bin/rialto/node/Cargo.toml +++ b/bin/rialto/node/Cargo.toml @@ -50,7 +50,6 @@ sc-consensus-uncles = { git = "https://github.com/paritytech/substrate", branch sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-finality-grandpa-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } -#sc-finality-grandpa-warp-sync = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } @@ -77,37 +76,10 @@ substrate-prometheus-endpoint = { git = "https://github.com/paritytech/substrate # Polkadot Dependencies -polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } - -# Polkadot (parachain) Dependencies - -polkadot-approval-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-availability-bitfield-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-availability-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-availability-recovery = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-collator-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-dispute-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-gossip-support = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-network-bridge = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-collation-generation = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-approval-voting = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-av-store = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-backing = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-bitfield-signing = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-candidate-validation = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-chain-api = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-chain-selection = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-parachains-inherent = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-provisioner = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-node-core-pvf = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-runtime-api = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-core-dispute-coordinator = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-network-protocol = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-node-subsystem-util = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-overseer = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-primitives = { git = "https://github.com/paritytech/polkadot", branch = "master" } polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-statement-distribution = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master", default-features = false, features = [ "full-node", "polkadot-native" ] } [build-dependencies] substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/bin/rialto/node/src/chain_spec.rs b/bin/rialto/node/src/chain_spec.rs index 527b5c051d..7e08e63531 100644 --- a/bin/rialto/node/src/chain_spec.rs +++ b/bin/rialto/node/src/chain_spec.rs @@ -30,7 +30,8 @@ use sp_finality_grandpa::AuthorityId as GrandpaId; use sp_runtime::traits::{IdentifyAccount, Verify}; /// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type. -pub type ChainSpec = sc_service::GenericChainSpec; +pub type ChainSpec = + sc_service::GenericChainSpec; /// The chain specification option. This is expected to come in from the CLI and /// is little more than one of a number of alternatives which can easily be converted @@ -104,7 +105,7 @@ impl Alternative { None, None, properties, - None, + Default::default(), ), Alternative::LocalTestnet => ChainSpec::from_genesis( "Rialto Local", @@ -128,7 +129,7 @@ impl Alternative { None, None, properties, - None, + Default::default(), ), } } diff --git a/bin/rialto/node/src/command.rs b/bin/rialto/node/src/command.rs index 7be615a577..1d81de2cb0 100644 --- a/bin/rialto/node/src/command.rs +++ b/bin/rialto/node/src/command.rs @@ -14,13 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{ - cli::{Cli, Subcommand}, - service::new_partial, -}; +use crate::cli::{Cli, Subcommand}; use rialto_runtime::{Block, RuntimeApi}; use sc_cli::{ChainSpec, Role, RuntimeVersion, SubstrateCli}; -use sc_service::PartialComponents; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -67,6 +63,21 @@ impl SubstrateCli for Cli { } } +// Rialto native executor instance. +pub struct ExecutorDispatch; + +impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { + type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; + + fn dispatch(method: &str, data: &[u8]) -> Option> { + rialto_runtime::api::dispatch(method, data) + } + + fn native_version() -> sc_executor::NativeVersion { + rialto_runtime::native_version() + } +} + /// Parse and run command line arguments pub fn run() -> sc_cli::Result<()> { let cli = Cli::from_args(); @@ -79,7 +90,7 @@ pub fn run() -> sc_cli::Result<()> { if cfg!(feature = "runtime-benchmarks") { let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| cmd.run::(config)) + runner.sync_run(|config| cmd.run::(config)) } else { println!( "Benchmarking wasn't enabled when building the node. \ @@ -98,32 +109,32 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::CheckBlock(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { - let PartialComponents { client, task_manager, import_queue, .. } = - new_partial(&mut config).map_err(service_error)?; + let (client, _, import_queue, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; Ok((cmd.run(client, import_queue), task_manager)) }) }, Some(Subcommand::ExportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { - let PartialComponents { client, task_manager, .. } = - new_partial(&mut config).map_err(service_error)?; + let (client, _, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; Ok((cmd.run(client, config.database), task_manager)) }) }, Some(Subcommand::ExportState(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { - let PartialComponents { client, task_manager, .. } = - new_partial(&mut config).map_err(service_error)?; + let (client, _, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; Ok((cmd.run(client, config.chain_spec), task_manager)) }) }, Some(Subcommand::ImportBlocks(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { - let PartialComponents { client, task_manager, import_queue, .. } = - new_partial(&mut config).map_err(service_error)?; + let (client, _, import_queue, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; Ok((cmd.run(client, import_queue), task_manager)) }) }, @@ -134,16 +145,14 @@ pub fn run() -> sc_cli::Result<()> { Some(Subcommand::Revert(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|mut config| { - let PartialComponents { client, task_manager, backend, .. } = - new_partial(&mut config).map_err(service_error)?; + let (client, backend, _, task_manager) = + polkadot_service::new_chain_ops(&mut config, None).map_err(service_error)?; Ok((cmd.run(client, backend), task_manager)) }) }, Some(Subcommand::Inspect(cmd)) => { let runner = cli.create_runner(cmd)?; - runner.sync_run(|config| { - cmd.run::(config) - }) + runner.sync_run(|config| cmd.run::(config)) }, Some(Subcommand::PvfPrepareWorker(cmd)) => { let mut builder = sc_cli::LoggerBuilder::new(""); @@ -170,15 +179,33 @@ pub fn run() -> sc_cli::Result<()> { // let no_beefy = true; // let telemetry_worker_handler = None; // let is_collator = crate::service::IsCollator::No; - let overseer_gen = crate::overseer::RealOverseerGen; + let overseer_gen = polkadot_service::overseer::RealOverseerGen; runner.run_node_until_exit(|config| async move { match config.role { Role::Light => Err(sc_cli::Error::Service(sc_service::Error::Other( "Light client is not supported by this node".into(), ))), - _ => crate::service::build_full(config, overseer_gen) - .map(|full| full.task_manager) - .map_err(service_error), + _ => { + let is_collator = polkadot_service::IsCollator::No; + let grandpa_pause = None; + let enable_beefy = true; + let jaeger_agent = None; + let telemetry_worker_handle = None; + let program_path = None; + + polkadot_service::new_full::( + config, + is_collator, + grandpa_pause, + enable_beefy, + jaeger_agent, + telemetry_worker_handle, + program_path, + overseer_gen, + ) + .map(|full| full.task_manager) + .map_err(service_error) + }, } }) }, @@ -187,6 +214,6 @@ pub fn run() -> sc_cli::Result<()> { // We don't want to change 'service.rs' too much to ease future updates => it'll keep using // its own error enum like original polkadot service does. -fn service_error(err: crate::service::Error) -> sc_cli::Error { +fn service_error(err: polkadot_service::Error) -> sc_cli::Error { sc_cli::Error::Application(Box::new(err)) } diff --git a/bin/rialto/node/src/main.rs b/bin/rialto/node/src/main.rs index 824814224e..6dea84a309 100644 --- a/bin/rialto/node/src/main.rs +++ b/bin/rialto/node/src/main.rs @@ -19,12 +19,8 @@ #![warn(missing_docs)] mod chain_spec; -#[macro_use] -mod service; mod cli; mod command; -mod overseer; -mod parachains_db; /// Run the Rialto Node fn main() -> sc_cli::Result<()> { diff --git a/bin/rialto/node/src/overseer.rs b/bin/rialto/node/src/overseer.rs deleted file mode 100644 index 9a7025e77c..0000000000 --- a/bin/rialto/node/src/overseer.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! This is almost 1:1 copy of `node/service/src/overseer.rs` file from Polkadot repository. -//! The only exception is that we don't support db upgrades => no `upgrade.rs` module. - -// this warning comes from `polkadot_overseer::AllSubsystems` type -#![allow(clippy::type_complexity)] - -use crate::service::{AuthorityDiscoveryApi, Error}; -use rialto_runtime::{opaque::Block, Hash}; - -use lru::LruCache; -use polkadot_availability_distribution::IncomingRequestReceivers; -use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig; -use polkadot_node_core_av_store::Config as AvailabilityConfig; -use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig; -use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; -use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; -use polkadot_node_network_protocol::request_response::{v1 as request_v1, IncomingRequestReceiver}; -use polkadot_overseer::{ - metrics::Metrics as OverseerMetrics, BlockInfo, MetricsTrait, Overseer, OverseerBuilder, - OverseerConnector, OverseerHandle, -}; -use polkadot_primitives::v1::ParachainHost; -use sc_authority_discovery::Service as AuthorityDiscoveryService; -use sc_client_api::AuxStore; -use sc_keystore::LocalKeystore; -use sp_api::ProvideRuntimeApi; -use sp_blockchain::HeaderBackend; -use sp_consensus_babe::BabeApi; -use sp_core::traits::SpawnNamed; -use std::sync::Arc; -use substrate_prometheus_endpoint::Registry; - -pub use polkadot_approval_distribution::ApprovalDistribution as ApprovalDistributionSubsystem; -pub use polkadot_availability_bitfield_distribution::BitfieldDistribution as BitfieldDistributionSubsystem; -pub use polkadot_availability_distribution::AvailabilityDistributionSubsystem; -pub use polkadot_availability_recovery::AvailabilityRecoverySubsystem; -pub use polkadot_collator_protocol::{CollatorProtocolSubsystem, ProtocolSide}; -pub use polkadot_dispute_distribution::DisputeDistributionSubsystem; -pub use polkadot_gossip_support::GossipSupport as GossipSupportSubsystem; -pub use polkadot_network_bridge::NetworkBridge as NetworkBridgeSubsystem; -pub use polkadot_node_collation_generation::CollationGenerationSubsystem; -pub use polkadot_node_core_approval_voting::ApprovalVotingSubsystem; -pub use polkadot_node_core_av_store::AvailabilityStoreSubsystem; -pub use polkadot_node_core_backing::CandidateBackingSubsystem; -pub use polkadot_node_core_bitfield_signing::BitfieldSigningSubsystem; -pub use polkadot_node_core_candidate_validation::CandidateValidationSubsystem; -pub use polkadot_node_core_chain_api::ChainApiSubsystem; -pub use polkadot_node_core_chain_selection::ChainSelectionSubsystem; -pub use polkadot_node_core_dispute_coordinator::DisputeCoordinatorSubsystem; -pub use polkadot_node_core_provisioner::ProvisionerSubsystem; -pub use polkadot_node_core_runtime_api::RuntimeApiSubsystem; -pub use polkadot_statement_distribution::StatementDistribution as StatementDistributionSubsystem; - -/// Arguments passed for overseer construction. -pub struct OverseerGenArgs<'a, Spawner, RuntimeClient> -where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, - Spawner: 'static + SpawnNamed + Clone + Unpin, -{ - /// Set of initial relay chain leaves to track. - pub leaves: Vec, - /// The keystore to use for i.e. validator keys. - pub keystore: Arc, - /// Runtime client generic, providing the `ProvieRuntimeApi` trait besides others. - pub runtime_client: Arc, - /// The underlying key value store for the parachains. - pub parachains_db: Arc, - /// Underlying network service implementation. - pub network_service: Arc>, - /// Underlying authority discovery service. - pub authority_discovery_service: AuthorityDiscoveryService, - /// POV request receiver - pub pov_req_receiver: IncomingRequestReceiver, - pub chunk_req_receiver: IncomingRequestReceiver, - pub collation_req_receiver: IncomingRequestReceiver, - pub available_data_req_receiver: - IncomingRequestReceiver, - pub statement_req_receiver: IncomingRequestReceiver, - pub dispute_req_receiver: IncomingRequestReceiver, - /// Prometheus registry, commonly used for production systems, less so for test. - pub registry: Option<&'a Registry>, - /// Task spawner to be used throughout the overseer and the APIs it provides. - pub spawner: Spawner, - /// Configuration for the approval voting subsystem. - pub approval_voting_config: ApprovalVotingConfig, - /// Configuration for the availability store subsystem. - pub availability_config: AvailabilityConfig, - /// Configuration for the candidate validation subsystem. - pub candidate_validation_config: CandidateValidationConfig, - /// Configuration for the chain selection subsystem. - pub chain_selection_config: ChainSelectionConfig, - /// Configuration for the dispute coordinator subsystem. - pub dispute_coordinator_config: DisputeCoordinatorConfig, -} - -/// Obtain a prepared `OverseerBuilder`, that is initialized -/// with all default values. -pub fn prepared_overseer_builder( - OverseerGenArgs { - leaves, - keystore, - runtime_client, - parachains_db, - network_service, - authority_discovery_service, - pov_req_receiver, - chunk_req_receiver, - collation_req_receiver: _, - available_data_req_receiver, - statement_req_receiver, - dispute_req_receiver, - registry, - spawner, - approval_voting_config, - availability_config, - candidate_validation_config, - chain_selection_config, - dispute_coordinator_config, - }: OverseerGenArgs<'_, Spawner, RuntimeClient>, -) -> Result< - OverseerBuilder< - Spawner, - Arc, - CandidateValidationSubsystem, - CandidateBackingSubsystem, - StatementDistributionSubsystem, - AvailabilityDistributionSubsystem, - AvailabilityRecoverySubsystem, - BitfieldSigningSubsystem, - BitfieldDistributionSubsystem, - ProvisionerSubsystem, - RuntimeApiSubsystem, - AvailabilityStoreSubsystem, - NetworkBridgeSubsystem< - Arc>, - AuthorityDiscoveryService, - >, - ChainApiSubsystem, - CollationGenerationSubsystem, - CollatorProtocolSubsystem, - ApprovalDistributionSubsystem, - ApprovalVotingSubsystem, - GossipSupportSubsystem, - DisputeCoordinatorSubsystem, - DisputeDistributionSubsystem, - ChainSelectionSubsystem, - >, - Error, -> -where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, - Spawner: 'static + SpawnNamed + Clone + Unpin, -{ - use polkadot_node_subsystem_util::metrics::Metrics; - use std::iter::FromIterator; - - let metrics = ::register(registry)?; - - let builder = Overseer::builder() - .availability_distribution(AvailabilityDistributionSubsystem::new( - keystore.clone(), - IncomingRequestReceivers { pov_req_receiver, chunk_req_receiver }, - Metrics::register(registry)?, - )) - .availability_recovery(AvailabilityRecoverySubsystem::with_chunks_only( - available_data_req_receiver, - Metrics::register(registry)?, - )) - .availability_store(AvailabilityStoreSubsystem::new( - parachains_db.clone(), - availability_config, - Metrics::register(registry)?, - )) - .bitfield_distribution(BitfieldDistributionSubsystem::new(Metrics::register(registry)?)) - .bitfield_signing(BitfieldSigningSubsystem::new( - spawner.clone(), - keystore.clone(), - Metrics::register(registry)?, - )) - .candidate_backing(CandidateBackingSubsystem::new( - spawner.clone(), - keystore.clone(), - Metrics::register(registry)?, - )) - .candidate_validation(CandidateValidationSubsystem::with_config( - candidate_validation_config, - Metrics::register(registry)?, // candidate-validation metrics - Metrics::register(registry)?, // validation host metrics - )) - .chain_api(ChainApiSubsystem::new(runtime_client.clone(), Metrics::register(registry)?)) - .collation_generation(CollationGenerationSubsystem::new(Metrics::register(registry)?)) - .collator_protocol(CollatorProtocolSubsystem::new(ProtocolSide::Validator { - keystore: keystore.clone(), - eviction_policy: Default::default(), - metrics: Metrics::register(registry)?, - })) - .network_bridge(NetworkBridgeSubsystem::new( - network_service.clone(), - authority_discovery_service.clone(), - Box::new(network_service.clone()), - Metrics::register(registry)?, - )) - .provisioner(ProvisionerSubsystem::new(spawner.clone(), (), Metrics::register(registry)?)) - .runtime_api(RuntimeApiSubsystem::new( - runtime_client.clone(), - Metrics::register(registry)?, - spawner.clone(), - )) - .statement_distribution(StatementDistributionSubsystem::new( - keystore.clone(), - statement_req_receiver, - Metrics::register(registry)?, - )) - .approval_distribution(ApprovalDistributionSubsystem::new(Metrics::register(registry)?)) - .approval_voting(ApprovalVotingSubsystem::with_config( - approval_voting_config, - parachains_db.clone(), - keystore.clone(), - Box::new(network_service), - Metrics::register(registry)?, - )) - .gossip_support(GossipSupportSubsystem::new( - keystore.clone(), - authority_discovery_service.clone(), - )) - .dispute_coordinator(DisputeCoordinatorSubsystem::new( - parachains_db.clone(), - dispute_coordinator_config, - keystore.clone(), - Metrics::register(registry)?, - )) - .dispute_distribution(DisputeDistributionSubsystem::new( - keystore, - dispute_req_receiver, - authority_discovery_service, - Metrics::register(registry)?, - )) - .chain_selection(ChainSelectionSubsystem::new(chain_selection_config, parachains_db)) - .leaves(Vec::from_iter( - leaves - .into_iter() - .map(|BlockInfo { hash, parent_hash: _, number }| (hash, number)), - )) - .activation_external_listeners(Default::default()) - .span_per_active_leaf(Default::default()) - .active_leaves(Default::default()) - .supports_parachains(runtime_client) - .known_leaves(LruCache::new(KNOWN_LEAVES_CACHE_SIZE)) - .metrics(metrics) - .spawner(spawner); - Ok(builder) -} - -/// Trait for the `fn` generating the overseer. -/// -/// Default behavior is to create an unmodified overseer, as `RealOverseerGen` -/// would do. -pub trait OverseerGen { - /// Overwrite the full generation of the overseer, including the subsystems. - fn generate( - &self, - connector: OverseerConnector, - args: OverseerGenArgs<'_, Spawner, RuntimeClient>, - ) -> Result<(Overseer>, OverseerHandle), Error> - where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, - Spawner: 'static + SpawnNamed + Clone + Unpin, - { - let gen = RealOverseerGen; - RealOverseerGen::generate::(&gen, connector, args) - } - // It would be nice to make `create_subsystems` part of this trait, - // but the amount of generic arguments that would be required as - // as consequence make this rather annoying to implement and use. -} - -use polkadot_overseer::KNOWN_LEAVES_CACHE_SIZE; - -/// The regular set of subsystems. -pub struct RealOverseerGen; - -impl OverseerGen for RealOverseerGen { - fn generate( - &self, - connector: OverseerConnector, - args: OverseerGenArgs<'_, Spawner, RuntimeClient>, - ) -> Result<(Overseer>, OverseerHandle), Error> - where - RuntimeClient: 'static + ProvideRuntimeApi + HeaderBackend + AuxStore, - RuntimeClient::Api: ParachainHost + BabeApi + AuthorityDiscoveryApi, - Spawner: 'static + SpawnNamed + Clone + Unpin, - { - prepared_overseer_builder(args)? - .build_with_connector(connector) - .map_err(|e| e.into()) - } -} diff --git a/bin/rialto/node/src/parachains_db.rs b/bin/rialto/node/src/parachains_db.rs deleted file mode 100644 index bf2052043c..0000000000 --- a/bin/rialto/node/src/parachains_db.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! This is almost 1:1 copy of `node/service/parachains_db/mod.rs` file from Polkadot repository. -//! The only exception is that we don't support db upgrades => no `upgrade.rs` module. - -use kvdb::KeyValueDB; -use std::{io, path::PathBuf, sync::Arc}; - -mod columns { - pub const NUM_COLUMNS: u32 = 5; - - pub const COL_AVAILABILITY_DATA: u32 = 0; - pub const COL_AVAILABILITY_META: u32 = 1; - pub const COL_APPROVAL_DATA: u32 = 2; - pub const COL_CHAIN_SELECTION_DATA: u32 = 3; - pub const COL_DISPUTE_COORDINATOR_DATA: u32 = 4; -} - -/// Columns used by different subsystems. -#[derive(Debug, Clone)] -pub struct ColumnsConfig { - /// The column used by the av-store for data. - pub col_availability_data: u32, - /// The column used by the av-store for meta information. - pub col_availability_meta: u32, - /// The column used by approval voting for data. - pub col_approval_data: u32, - /// The column used by chain selection for data. - pub col_chain_selection_data: u32, - /// The column used by dispute coordinator for data. - pub col_dispute_coordinator_data: u32, -} - -/// The real columns used by the parachains DB. -pub const REAL_COLUMNS: ColumnsConfig = ColumnsConfig { - col_availability_data: columns::COL_AVAILABILITY_DATA, - col_availability_meta: columns::COL_AVAILABILITY_META, - col_approval_data: columns::COL_APPROVAL_DATA, - col_chain_selection_data: columns::COL_CHAIN_SELECTION_DATA, - col_dispute_coordinator_data: columns::COL_DISPUTE_COORDINATOR_DATA, -}; - -/// The cache size for each column, in megabytes. -#[derive(Debug, Clone)] -pub struct CacheSizes { - /// Cache used by availability data. - pub availability_data: usize, - /// Cache used by availability meta. - pub availability_meta: usize, - /// Cache used by approval data. - pub approval_data: usize, -} - -impl Default for CacheSizes { - fn default() -> Self { - CacheSizes { availability_data: 25, availability_meta: 1, approval_data: 5 } - } -} - -fn other_io_error(err: String) -> io::Error { - io::Error::new(io::ErrorKind::Other, err) -} - -/// Open the database on disk, creating it if it doesn't exist. -pub fn open_creating(root: PathBuf, cache_sizes: CacheSizes) -> io::Result> { - use kvdb_rocksdb::{Database, DatabaseConfig}; - - let path = root.join("parachains").join("db"); - - let mut db_config = DatabaseConfig::with_columns(columns::NUM_COLUMNS); - - let _ = db_config - .memory_budget - .insert(columns::COL_AVAILABILITY_DATA, cache_sizes.availability_data); - let _ = db_config - .memory_budget - .insert(columns::COL_AVAILABILITY_META, cache_sizes.availability_meta); - let _ = db_config - .memory_budget - .insert(columns::COL_APPROVAL_DATA, cache_sizes.approval_data); - - let path_str = path - .to_str() - .ok_or_else(|| other_io_error(format!("Bad database path: {:?}", path)))?; - - std::fs::create_dir_all(&path_str)?; - let db = Database::open(&db_config, path_str)?; - - Ok(Arc::new(db)) -} diff --git a/bin/rialto/node/src/service.rs b/bin/rialto/node/src/service.rs deleted file mode 100644 index 3349b09edb..0000000000 --- a/bin/rialto/node/src/service.rs +++ /dev/null @@ -1,756 +0,0 @@ -// Copyright 2019-2021 Parity Technologies (UK) Ltd. -// This file is part of Parity Bridges Common. - -// Parity Bridges Common is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity Bridges Common is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity Bridges Common. If not, see . - -//! Rialto chain node service. -//! -//! The code is mostly copy of `service/src/lib.rs` file from Polkadot repository -//! without optional functions, and with BEEFY added on top. - -use crate::overseer::{OverseerGen, OverseerGenArgs}; - -use polkadot_client::RuntimeApiCollection; -use polkadot_node_core_approval_voting::Config as ApprovalVotingConfig; -use polkadot_node_core_av_store::Config as AvailabilityConfig; -use polkadot_node_core_candidate_validation::Config as CandidateValidationConfig; -use polkadot_node_core_chain_selection::Config as ChainSelectionConfig; -use polkadot_node_core_dispute_coordinator::Config as DisputeCoordinatorConfig; -use polkadot_node_network_protocol::request_response::IncomingRequest; -use polkadot_overseer::{BlockInfo, OverseerConnector}; -use polkadot_primitives::v1::BlockId; -use rialto_runtime::{self, opaque::Block, RuntimeApi}; -use sc_client_api::ExecutorProvider; -use sc_executor::{NativeElseWasmExecutor, NativeExecutionDispatch}; -use sc_finality_grandpa::FinalityProofProvider as GrandpaFinalityProofProvider; -use sc_service::{config::PrometheusConfig, Configuration, TaskManager}; -use sc_telemetry::{Telemetry, TelemetryWorker}; -use sp_api::{ConstructRuntimeApi, HeaderT}; -use sp_consensus::SelectChain; -use sp_runtime::traits::Block as BlockT; -use std::{sync::Arc, time::Duration}; -use substrate_prometheus_endpoint::Registry; - -pub use polkadot_overseer::Handle; -pub use polkadot_primitives::v1::ParachainHost; -pub use sc_client_api::AuxStore; -pub use sp_authority_discovery::AuthorityDiscoveryApi; -pub use sp_blockchain::HeaderBackend; -pub use sp_consensus_babe::BabeApi; - -pub type Executor = NativeElseWasmExecutor; - -// Our native executor instance. -pub struct ExecutorDispatch; - -impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { - type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions; - - fn dispatch(method: &str, data: &[u8]) -> Option> { - rialto_runtime::api::dispatch(method, data) - } - - fn native_version() -> sc_executor::NativeVersion { - rialto_runtime::native_version() - } -} - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error(transparent)] - Io(#[from] std::io::Error), - - #[error(transparent)] - Cli(#[from] sc_cli::Error), - - #[error(transparent)] - Blockchain(#[from] sp_blockchain::Error), - - #[error(transparent)] - Consensus(#[from] sp_consensus::Error), - - #[error(transparent)] - Service(#[from] sc_service::Error), - - #[error(transparent)] - Telemetry(#[from] sc_telemetry::Error), - - #[error("Failed to create an overseer")] - Overseer(#[from] polkadot_overseer::SubsystemError), - - #[error(transparent)] - Prometheus(#[from] substrate_prometheus_endpoint::PrometheusError), - - #[error("Authorities require the real overseer implementation")] - AuthoritiesRequireRealOverseer, - - #[error("Creating a custom database is required for validators")] - DatabasePathRequired, -} - -type FullClient = sc_service::TFullClient; -type FullBackend = sc_service::TFullBackend; -type FullSelectChain = sc_consensus::LongestChain; -type FullGrandpaBlockImport = - sc_finality_grandpa::GrandpaBlockImport; -type FullTransactionPool = sc_transaction_pool::FullPool; -type FullBabeBlockImport = - sc_consensus_babe::BabeBlockImport; -type FullBabeLink = sc_consensus_babe::BabeLink; -type FullGrandpaLink = sc_finality_grandpa::LinkHalf; - -// If we're using prometheus, use a registry with a prefix of `polkadot`. -fn set_prometheus_registry(config: &mut Configuration) -> Result<(), Error> { - if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() { - *registry = Registry::new_custom(Some("polkadot".into()), None)?; - } - - Ok(()) -} - -// Needed here for complex return type while `impl Trait` in type aliases is unstable. -#[allow(clippy::type_complexity)] -pub fn new_partial( - config: &mut Configuration, -) -> Result< - sc_service::PartialComponents< - FullClient, - FullBackend, - FullSelectChain, - sc_consensus::DefaultImportQueue, - FullTransactionPool, - ( - impl Fn( - sc_rpc::DenyUnsafe, - sc_rpc::SubscriptionTaskExecutor, - ) -> Result, sc_service::Error>, - ( - FullBabeBlockImport, - FullGrandpaLink, - FullBabeLink, - beefy_gadget::notification::BeefySignedCommitmentSender, - ), - sc_finality_grandpa::SharedVoterState, - std::time::Duration, - Option, - ), - >, - Error, -> -where - RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static, - >::RuntimeApi: - RuntimeApiCollection>, - ExecutorDispatch: NativeExecutionDispatch + 'static, -{ - set_prometheus_registry(config)?; - - let telemetry = config - .telemetry_endpoints - .clone() - .filter(|x| !x.is_empty()) - .map(|endpoints| -> Result<_, sc_telemetry::Error> { - let worker = TelemetryWorker::new(16)?; - let telemetry = worker.handle().new_telemetry(endpoints); - Ok((worker, telemetry)) - }) - .transpose()?; - - let executor = NativeElseWasmExecutor::::new( - config.wasm_method, - config.default_heap_pages, - config.max_runtime_instances, - ); - - let (client, backend, keystore_container, task_manager) = - sc_service::new_full_parts::( - config, - telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()), - executor, - )?; - let client = Arc::new(client); - - let telemetry = telemetry.map(|(worker, telemetry)| { - task_manager.spawn_handle().spawn("telemetry", None, worker.run()); - telemetry - }); - - let select_chain = sc_consensus::LongestChain::new(backend.clone()); - - let transaction_pool = sc_transaction_pool::BasicPool::new_full( - config.transaction_pool.clone(), - config.role.is_authority().into(), - config.prometheus_registry(), - task_manager.spawn_essential_handle(), - client.clone(), - ); - - let (grandpa_block_import, grandpa_link) = - sc_finality_grandpa::block_import_with_authority_set_hard_forks( - client.clone(), - &(client.clone() as Arc<_>), - select_chain.clone(), - Vec::new(), - telemetry.as_ref().map(|x| x.handle()), - )?; - let justification_import = grandpa_block_import.clone(); - - let babe_config = sc_consensus_babe::Config::get_or_compute(&*client)?; - let (block_import, babe_link) = - sc_consensus_babe::block_import(babe_config.clone(), grandpa_block_import, client.clone())?; - - let slot_duration = babe_link.config().slot_duration(); - let import_queue = sc_consensus_babe::import_queue( - babe_link.clone(), - block_import.clone(), - Some(Box::new(justification_import)), - client.clone(), - select_chain.clone(), - move |_, ()| async move { - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = - sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( - *timestamp, - slot_duration, - ); - - Ok((timestamp, slot)) - }, - &task_manager.spawn_essential_handle(), - config.prometheus_registry(), - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()), - telemetry.as_ref().map(|x| x.handle()), - )?; - - let justification_stream = grandpa_link.justification_stream(); - let shared_authority_set = grandpa_link.shared_authority_set().clone(); - let shared_voter_state = sc_finality_grandpa::SharedVoterState::empty(); - - let (signed_commitment_sender, signed_commitment_stream) = - beefy_gadget::notification::BeefySignedCommitmentStream::channel(); - - let import_setup = (block_import, grandpa_link, babe_link, signed_commitment_sender); - let rpc_setup = shared_voter_state.clone(); - - let slot_duration = babe_config.slot_duration(); - - let rpc_extensions_builder = { - let client = client.clone(); - let transaction_pool = transaction_pool.clone(); - let backend = backend.clone(); - - move |deny_unsafe, - subscription_executor: sc_rpc::SubscriptionTaskExecutor| - -> Result, sc_service::Error> { - use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApi}; - use sc_finality_grandpa_rpc::{GrandpaApi, GrandpaRpcHandler}; - use substrate_frame_rpc_system::{FullSystem, SystemApi}; - - let backend = backend.clone(); - let client = client.clone(); - let pool = transaction_pool.clone(); - - let shared_voter_state = shared_voter_state.clone(); - - let finality_proof_provider = GrandpaFinalityProofProvider::new_for_service( - backend, - Some(shared_authority_set.clone()), - ); - - 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.clone(), - ))); - io.extend_with(GrandpaApi::to_delegate(GrandpaRpcHandler::new( - shared_authority_set.clone(), - shared_voter_state, - justification_stream.clone(), - subscription_executor.clone(), - finality_proof_provider, - ))); - io.extend_with(beefy_gadget_rpc::BeefyApi::to_delegate( - beefy_gadget_rpc::BeefyRpcHandler::new( - signed_commitment_stream.clone(), - subscription_executor, - ), - )); - io.extend_with(pallet_mmr_rpc::MmrApi::to_delegate(pallet_mmr_rpc::Mmr::new(client))); - - Ok(io) - } - }; - - Ok(sc_service::PartialComponents { - client, - backend, - task_manager, - keystore_container, - select_chain, - import_queue, - transaction_pool, - other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, telemetry), - }) -} - -pub struct NewFull { - pub task_manager: TaskManager, - pub client: C, - pub overseer_handle: Option, - pub network: Arc::Hash>>, - pub rpc_handlers: sc_service::RpcHandlers, - pub backend: Arc, -} - -/// The maximum number of active leaves we forward to the [`Overseer`] on start up. -const MAX_ACTIVE_LEAVES: usize = 4; - -/// Returns the active leaves the overseer should start with. -async fn active_leaves( - select_chain: &sc_consensus::LongestChain, - client: &FullClient, -) -> Result, Error> -where - RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static, - >::RuntimeApi: - RuntimeApiCollection>, - ExecutorDispatch: NativeExecutionDispatch + 'static, -{ - let best_block = select_chain.best_chain().await?; - - let mut leaves = select_chain - .leaves() - .await - .unwrap_or_default() - .into_iter() - .filter_map(|hash| { - let number = client.number(hash).ok()??; - - // Only consider leaves that are in maximum an uncle of the best block. - if number < best_block.number().saturating_sub(1) || hash == best_block.hash() { - return None - } - - let parent_hash = client.header(&BlockId::Hash(hash)).ok()??.parent_hash; - - Some(BlockInfo { hash, parent_hash, number }) - }) - .collect::>(); - - // Sort by block number and get the maximum number of leaves - leaves.sort_by_key(|b| b.number); - - leaves.push(BlockInfo { - hash: best_block.hash(), - parent_hash: *best_block.parent_hash(), - number: *best_block.number(), - }); - - Ok(leaves.into_iter().rev().take(MAX_ACTIVE_LEAVES).collect()) -} - -// Create a new full node. -pub fn new_full( - mut config: Configuration, - program_path: Option, - overseer_gen: impl OverseerGen, -) -> Result>, Error> -where - RuntimeApi: ConstructRuntimeApi + Send + Sync + 'static, - >::RuntimeApi: - RuntimeApiCollection>, - ExecutorDispatch: NativeExecutionDispatch + 'static, -{ - let is_collator = false; - - let role = config.role.clone(); - let force_authoring = config.force_authoring; - let backoff_authoring_blocks = - Some(sc_consensus_slots::BackoffAuthoringOnFinalizedHeadLagging::default()); - - let disable_grandpa = config.disable_grandpa; - let name = config.network.node_name.clone(); - - let sc_service::PartialComponents { - client, - backend, - mut task_manager, - keystore_container, - select_chain, - import_queue, - transaction_pool, - other: (rpc_extensions_builder, import_setup, rpc_setup, slot_duration, mut telemetry), - } = new_partial(&mut config)?; - - let prometheus_registry = config.prometheus_registry().cloned(); - - let overseer_connector = OverseerConnector::default(); - - let shared_voter_state = rpc_setup; - let auth_disc_publish_non_global_ips = config.network.allow_non_globals_in_dht; - - // Note: GrandPa is pushed before the Polkadot-specific protocols. This doesn't change - // anything in terms of behaviour, but makes the logs more consistent with the other - // Substrate nodes. - config.network.extra_sets.push(sc_finality_grandpa::grandpa_peers_set_config()); - - config.network.extra_sets.push(beefy_gadget::beefy_peers_set_config()); - - { - use polkadot_network_bridge::{peer_sets_info, IsAuthority}; - let is_authority = if role.is_authority() { IsAuthority::Yes } else { IsAuthority::No }; - config.network.extra_sets.extend(peer_sets_info(is_authority)); - } - - let (pov_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - let (chunk_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - let (collation_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - let (available_data_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - let (statement_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - let (dispute_req_receiver, cfg) = IncomingRequest::get_config_receiver(); - config.network.request_response_protocols.push(cfg); - - let warp_sync = Arc::new(sc_finality_grandpa::warp_proof::NetworkProvider::new( - backend.clone(), - import_setup.1.shared_authority_set().clone(), - vec![], - )); - - let (network, system_rpc_tx, network_starter) = - sc_service::build_network(sc_service::BuildNetworkParams { - config: &config, - client: client.clone(), - transaction_pool: transaction_pool.clone(), - spawn_handle: task_manager.spawn_handle(), - import_queue, - block_announce_validator_builder: None, - warp_sync: Some(warp_sync), - })?; - - if config.offchain_worker.enabled { - let _ = sc_service::build_offchain_workers( - &config, - task_manager.spawn_handle(), - client.clone(), - network.clone(), - ); - } - - let parachains_db = crate::parachains_db::open_creating( - config.database.path().ok_or(Error::DatabasePathRequired)?.into(), - crate::parachains_db::CacheSizes::default(), - )?; - - let availability_config = AvailabilityConfig { - col_data: crate::parachains_db::REAL_COLUMNS.col_availability_data, - col_meta: crate::parachains_db::REAL_COLUMNS.col_availability_meta, - }; - - let approval_voting_config = ApprovalVotingConfig { - col_data: crate::parachains_db::REAL_COLUMNS.col_approval_data, - slot_duration_millis: slot_duration.as_millis() as u64, - }; - - let candidate_validation_config = CandidateValidationConfig { - artifacts_cache_path: config - .database - .path() - .ok_or(Error::DatabasePathRequired)? - .join("pvf-artifacts"), - program_path: match program_path { - None => std::env::current_exe()?, - Some(p) => p, - }, - }; - - let chain_selection_config = ChainSelectionConfig { - col_data: crate::parachains_db::REAL_COLUMNS.col_chain_selection_data, - stagnant_check_interval: polkadot_node_core_chain_selection::StagnantCheckInterval::never(), - }; - - let dispute_coordinator_config = DisputeCoordinatorConfig { - col_data: crate::parachains_db::REAL_COLUMNS.col_dispute_coordinator_data, - }; - - let rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams { - config, - backend: backend.clone(), - client: client.clone(), - keystore: keystore_container.sync_keystore(), - network: network.clone(), - rpc_extensions_builder: Box::new(rpc_extensions_builder), - transaction_pool: transaction_pool.clone(), - task_manager: &mut task_manager, - system_rpc_tx, - telemetry: telemetry.as_mut(), - })?; - - let (block_import, link_half, babe_link, signed_commitment_sender) = import_setup; - - let overseer_client = client.clone(); - let spawner = task_manager.spawn_handle(); - let active_leaves = futures::executor::block_on(active_leaves(&select_chain, &*client))?; - - let authority_discovery_service = if role.is_authority() || is_collator { - use futures::StreamExt; - use sc_network::Event; - - let authority_discovery_role = if role.is_authority() { - sc_authority_discovery::Role::PublishAndDiscover(keystore_container.keystore()) - } else { - // don't publish our addresses when we're only a collator - sc_authority_discovery::Role::Discover - }; - let dht_event_stream = - network.event_stream("authority-discovery").filter_map(|e| async move { - match e { - Event::Dht(e) => Some(e), - _ => None, - } - }); - let (worker, service) = sc_authority_discovery::new_worker_and_service_with_config( - sc_authority_discovery::WorkerConfig { - publish_non_global_ips: auth_disc_publish_non_global_ips, - ..Default::default() - }, - client.clone(), - network.clone(), - Box::pin(dht_event_stream), - authority_discovery_role, - prometheus_registry.clone(), - ); - - task_manager - .spawn_handle() - .spawn("authority-discovery-worker", None, worker.run()); - Some(service) - } else { - None - }; - - // we'd say let overseer_handler = - // authority_discovery_service.map(|authority_discovery_service|, ...), but in that case we - // couldn't use ? to propagate errors - let local_keystore = keystore_container.local_keystore(); - let maybe_params = - local_keystore.and_then(move |k| authority_discovery_service.map(|a| (a, k))); - - let overseer_handle = if let Some((authority_discovery_service, keystore)) = maybe_params { - let (overseer, overseer_handle) = overseer_gen - .generate::( - overseer_connector, - OverseerGenArgs { - leaves: active_leaves, - keystore, - runtime_client: overseer_client.clone(), - parachains_db, - availability_config, - approval_voting_config, - network_service: network.clone(), - authority_discovery_service, - registry: prometheus_registry.as_ref(), - spawner, - candidate_validation_config, - available_data_req_receiver, - chain_selection_config, - chunk_req_receiver, - collation_req_receiver, - dispute_coordinator_config, - dispute_req_receiver, - pov_req_receiver, - statement_req_receiver, - }, - )?; - let handle = Handle::new(overseer_handle); - - { - let handle = handle.clone(); - task_manager.spawn_essential_handle().spawn_blocking( - "overseer", - None, - Box::pin(async move { - use futures::{pin_mut, select, FutureExt}; - - let forward = polkadot_overseer::forward_events(overseer_client, handle); - - let forward = forward.fuse(); - let overseer_fut = overseer.run().fuse(); - - pin_mut!(overseer_fut); - pin_mut!(forward); - - select! { - _ = forward => (), - _ = overseer_fut => (), - complete => (), - } - }), - ); - } - - Some(handle) - } else { - None - }; - - if role.is_authority() { - let can_author_with = - sp_consensus::CanAuthorWithNativeVersion::new(client.executor().clone()); - - let proposer = sc_basic_authorship::ProposerFactory::new( - task_manager.spawn_handle(), - client.clone(), - transaction_pool, - prometheus_registry.as_ref(), - telemetry.as_ref().map(|x| x.handle()), - ); - - let client_clone = client.clone(); - let overseer_handle = - overseer_handle.as_ref().ok_or(Error::AuthoritiesRequireRealOverseer)?.clone(); - let slot_duration = babe_link.config().slot_duration(); - let babe_config = sc_consensus_babe::BabeParams { - keystore: keystore_container.sync_keystore(), - client: client.clone(), - select_chain, - block_import, - env: proposer, - sync_oracle: network.clone(), - justification_sync_link: network.clone(), - create_inherent_data_providers: move |parent, ()| { - let client_clone = client_clone.clone(); - let overseer_handle = overseer_handle.clone(); - async move { - let parachain = polkadot_node_core_parachains_inherent::ParachainsInherentDataProvider::create( - &*client_clone, - overseer_handle, - parent, - ) - .await - .map_err(Box::new)?; - - let uncles = sc_consensus_uncles::create_uncles_inherent_data_provider( - &*client_clone, - parent, - )?; - - let timestamp = sp_timestamp::InherentDataProvider::from_system_time(); - - let slot = sp_consensus_babe::inherents::InherentDataProvider::from_timestamp_and_duration( - *timestamp, - slot_duration, - ); - - Ok((timestamp, slot, uncles, parachain)) - } - }, - force_authoring, - backoff_authoring_blocks, - babe_link, - can_author_with, - block_proposal_slot_portion: sc_consensus_babe::SlotProportion::new(2f32 / 3f32), - max_block_proposal_slot_portion: None, - telemetry: telemetry.as_ref().map(|x| x.handle()), - }; - - let babe = sc_consensus_babe::start_babe(babe_config)?; - task_manager.spawn_essential_handle().spawn_blocking("babe", None, babe); - } - - // if the node isn't actively participating in consensus then it doesn't - // need a keystore, regardless of which protocol we use below. - let keystore_opt = - if role.is_authority() { Some(keystore_container.sync_keystore()) } else { None }; - - let beefy_params = beefy_gadget::BeefyParams { - client: client.clone(), - backend: backend.clone(), - key_store: keystore_opt.clone(), - network: network.clone(), - signed_commitment_sender, - min_block_delta: 2, - prometheus_registry: prometheus_registry.clone(), - }; - - // Start the BEEFY bridge gadget. - task_manager.spawn_essential_handle().spawn_blocking( - "beefy-gadget", - None, - beefy_gadget::start_beefy_gadget::<_, _, _, _>(beefy_params), - ); - - let config = sc_finality_grandpa::Config { - // FIXME substrate#1578 make this available through chainspec - gossip_duration: Duration::from_millis(1000), - justification_period: 512, - name: Some(name), - observer_enabled: false, - keystore: keystore_opt, - local_role: role, - telemetry: telemetry.as_ref().map(|x| x.handle()), - }; - - let enable_grandpa = !disable_grandpa; - if enable_grandpa { - // start the full GRANDPA voter - // NOTE: unlike in substrate we are currently running the full - // GRANDPA voter protocol for all full nodes (regardless of whether - // they're validators or not). at this point the full voter should - // provide better guarantees of block and vote data availability than - // the observer. - - // add a custom voting rule to temporarily stop voting for new blocks - // after the given pause block is finalized and restarting after the - // given delay. - let builder = sc_finality_grandpa::VotingRulesBuilder::default(); - - let voting_rule = builder.build(); - let grandpa_config = sc_finality_grandpa::GrandpaParams { - config, - link: link_half, - network: network.clone(), - voting_rule, - prometheus_registry, - shared_voter_state, - telemetry: telemetry.as_ref().map(|x| x.handle()), - }; - - task_manager.spawn_essential_handle().spawn_blocking( - "grandpa-voter", - None, - sc_finality_grandpa::run_grandpa_voter(grandpa_config)?, - ); - } - - network_starter.start_network(); - - Ok(NewFull { task_manager, client, overseer_handle, network, rpc_handlers, backend }) -} - -pub fn build_full( - config: Configuration, - overseer_gen: impl OverseerGen, -) -> Result>, Error> { - new_full(config, None, overseer_gen) -} diff --git a/bin/rialto/runtime/src/lib.rs b/bin/rialto/runtime/src/lib.rs index a68de93069..5f940bb58e 100644 --- a/bin/rialto/runtime/src/lib.rs +++ b/bin/rialto/runtime/src/lib.rs @@ -899,10 +899,6 @@ impl_runtime_apis! { } impl bp_millau::FromMillauInboundLaneApi for Runtime { - fn latest_confirmed_nonce(lane: bp_messages::LaneId) -> bp_messages::MessageNonce { - BridgeMillauMessages::inbound_latest_confirmed_nonce(lane) - } - fn unrewarded_relayers_state(lane: bp_messages::LaneId) -> bp_messages::UnrewardedRelayersState { BridgeMillauMessages::inbound_unrewarded_relayers_state(lane) } diff --git a/bin/runtime-common/Cargo.toml b/bin/runtime-common/Cargo.toml index 0ae642ba55..ed3bb32d17 100644 --- a/bin/runtime-common/Cargo.toml +++ b/bin/runtime-common/Cargo.toml @@ -25,12 +25,15 @@ pallet-bridge-messages = { path = "../../modules/messages", default-features = f # Substrate dependencies 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, optional = true } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } pallet-transaction-payment = { 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-runtime = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } sp-std = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } sp-trie = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false } +sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false, optional = true } [features] default = ["std"] @@ -54,7 +57,10 @@ std = [ ] runtime-benchmarks = [ "ed25519-dalek/u64_backend", + "frame-system", + "pallet-balances", "pallet-bridge-grandpa/runtime-benchmarks", "pallet-bridge-messages/runtime-benchmarks", "sp-state-machine", + "sp-version", ] diff --git a/bin/runtime-common/src/messages.rs b/bin/runtime-common/src/messages.rs index dd03379ce5..47fb1c48f4 100644 --- a/bin/runtime-common/src/messages.rs +++ b/bin/runtime-common/src/messages.rs @@ -176,7 +176,7 @@ pub type BalanceOf = ::Balance; pub type CallOf = ::Call; /// Raw storage proof type (just raw trie nodes). -type RawStorageProof = Vec>; +pub type RawStorageProof = Vec>; /// Compute fee of transaction at runtime where regular transaction payment pallet is being used. /// diff --git a/bin/runtime-common/src/messages_benchmarking.rs b/bin/runtime-common/src/messages_benchmarking.rs index 217560e114..1b14ee30ae 100644 --- a/bin/runtime-common/src/messages_benchmarking.rs +++ b/bin/runtime-common/src/messages_benchmarking.rs @@ -20,162 +20,164 @@ #![cfg(feature = "runtime-benchmarks")] use crate::messages::{ - source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, - AccountIdOf, BalanceOf, BridgedChain, HashOf, MessageBridge, ThisChain, + source::{FromBridgedChainMessagesDeliveryProof, FromThisChainMessagePayload}, + target::FromBridgedChainMessagesProof, + AccountIdOf, BalanceOf, BridgedChain, CallOf, HashOf, MessageBridge, RawStorageProof, + SignatureOf, SignerOf, ThisChain, }; -use bp_messages::{LaneId, MessageData, MessageKey, MessagePayload}; -use bp_runtime::ChainId; +use bp_messages::{storage_keys, MessageData, MessageKey, MessagePayload}; +use bp_runtime::{messages::DispatchFeePayment, ChainId}; use codec::Encode; use ed25519_dalek::{PublicKey, SecretKey, Signer, KEYPAIR_LENGTH, SECRET_KEY_LENGTH}; -use frame_support::weights::Weight; +use frame_support::{ + traits::Currency, + weights::{GetDispatchInfo, Weight}, +}; use pallet_bridge_messages::benchmarking::{ - MessageDeliveryProofParams, MessageProofParams, ProofSize, + MessageDeliveryProofParams, MessageParams, MessageProofParams, ProofSize, }; use sp_core::Hasher; -use sp_runtime::traits::Header; -use sp_std::prelude::*; +use sp_runtime::traits::{Header, IdentifyAccount, MaybeSerializeDeserialize, Zero}; +use sp_std::{fmt::Debug, prelude::*}; use sp_trie::{record_all_keys, trie_types::TrieDBMut, Layout, MemoryDB, Recorder, TrieMut}; +use sp_version::RuntimeVersion; -/// Generate ed25519 signature to be used in -/// `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`. -/// -/// Returns public key of the signer and the signature itself. -pub fn ed25519_sign( - target_call: &impl Encode, - source_account_id: &impl Encode, - target_spec_version: u32, - source_chain_id: ChainId, - target_chain_id: ChainId, -) -> ([u8; 32], [u8; 64]) { - // key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html) - let target_secret = SecretKey::from_bytes(&[ - 157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073, - 197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096, - ]) - .expect("harcoded key is valid"); - let target_public: PublicKey = (&target_secret).into(); - - let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH]; - target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes()); - target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes()); - let target_pair = - ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid"); - - let signature_message = pallet_bridge_dispatch::account_ownership_digest( - target_call, - source_account_id, - target_spec_version, - source_chain_id, - target_chain_id, - ); - let target_origin_signature = target_pair - .try_sign(&signature_message) - .expect("Ed25519 try_sign should not fail in benchmarks"); +/// Prepare outbound message for the `send_message` call. +pub fn prepare_outbound_message( + params: MessageParams>>, +) -> (FromThisChainMessagePayload, BalanceOf>) +where + B: MessageBridge, + BalanceOf>: From, +{ + let message_payload = vec![0; params.size as usize]; + let dispatch_origin = bp_message_dispatch::CallOrigin::SourceAccount(params.sender_account); - (target_public.to_bytes(), target_origin_signature.to_bytes()) + let message = FromThisChainMessagePayload:: { + spec_version: 0, + weight: params.size as _, + origin: dispatch_origin, + call: message_payload, + dispatch_fee_payment: DispatchFeePayment::AtSourceChain, + }; + (message, pallet_bridge_messages::benchmarking::MESSAGE_FEE.into()) } /// Prepare proof of messages for the `receive_messages_proof` call. -pub fn prepare_message_proof( +/// +/// In addition to returning valid messages proof, environment is prepared to verify this message +/// proof. +pub fn prepare_message_proof( params: MessageProofParams, - make_bridged_message_storage_key: MM, - make_bridged_outbound_lane_data_key: ML, - make_bridged_header: MH, - message_dispatch_weight: Weight, - message_payload: MessagePayload, + version: &RuntimeVersion, + endow_amount: BalanceOf>, ) -> (FromBridgedChainMessagesProof>>, Weight) where + R: frame_system::Config>> + + pallet_balances::Config>> + + pallet_bridge_grandpa::Config, + R::BridgedChain: bp_runtime::Chain
, B: MessageBridge, - H: Hasher, - R: pallet_bridge_grandpa::Config, + BI: 'static, FI: 'static, - ::Hash: Into>>, - MM: Fn(MessageKey) -> Vec, - ML: Fn(LaneId) -> Vec, - MH: Fn(H::Out) -> ::Header, + BH: Header>>, + BHH: Hasher>>, + AccountIdOf>: From<[u8; 32]>, + BalanceOf>: Debug + MaybeSerializeDeserialize, + CallOf>: From> + GetDispatchInfo, + HashOf>: Copy + Default, + SignatureOf>: From, + SignerOf>: Clone + + From + + IdentifyAccount>>, { - // prepare Bridged chain storage with messages and (optionally) outbound lane state - let message_count = - params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1; - let mut storage_keys = Vec::with_capacity(message_count as usize + 1); - let mut root = Default::default(); - let mut mdb = MemoryDB::default(); - { - let mut trie = TrieDBMut::::new(&mut mdb, &mut root); + // we'll be dispatching the same call at This chain + let remark = match params.size { + ProofSize::Minimal(ref size) => vec![0u8; *size as _], + _ => vec![], + }; + let call: CallOf> = frame_system::Call::remark { remark }.into(); + let call_weight = call.get_dispatch_info().weight; - // insert messages - for nonce in params.message_nonces.clone() { - let message_key = MessageKey { lane_id: params.lane, nonce }; - let message_data = MessageData { - fee: BalanceOf::>::from(0), - payload: message_payload.clone(), - }; - let storage_key = make_bridged_message_storage_key(message_key); - trie.insert(&storage_key, &message_data.encode()) - .map_err(|_| "TrieMut::insert has failed") - .expect("TrieMut::insert should not fail in benchmarks"); - storage_keys.push(storage_key); - } + // message payload needs to be signed, because we use `TargetAccount` call origin + // (which is 'heaviest' to verify) + let bridged_account_id: AccountIdOf> = [0u8; 32].into(); + let (this_raw_public, this_raw_signature) = ed25519_sign( + &call, + &bridged_account_id, + version.spec_version, + B::BRIDGED_CHAIN_ID, + B::THIS_CHAIN_ID, + ); + let this_public: SignerOf> = + sp_core::ed25519::Public::from_raw(this_raw_public).into(); + let this_signature: SignatureOf> = + sp_core::ed25519::Signature::from_raw(this_raw_signature).into(); - // insert outbound lane state - if let Some(outbound_lane_data) = params.outbound_lane_data { - let storage_key = make_bridged_outbound_lane_data_key(params.lane); - trie.insert(&storage_key, &outbound_lane_data.encode()) - .map_err(|_| "TrieMut::insert has failed") - .expect("TrieMut::insert should not fail in benchmarks"); - storage_keys.push(storage_key); - } + // if dispatch fee is paid at this chain, endow relayer account + if params.dispatch_fee_payment == DispatchFeePayment::AtTargetChain { + pallet_balances::Pallet::::make_free_balance_be( + &this_public.clone().into_account(), + endow_amount, + ); } - root = grow_trie(root, &mut mdb, params.size); - // generate storage proof to be delivered to This chain - let mut proof_recorder = Recorder::::new(); - record_all_keys::, _>(&mdb, &root, &mut proof_recorder) - .map_err(|_| "record_all_keys has failed") - .expect("record_all_keys should not fail in benchmarks"); - let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); + // prepare message payload that is stored in the Bridged chain storage + let message_payload = bp_message_dispatch::MessagePayload { + spec_version: version.spec_version, + weight: call_weight, + origin: bp_message_dispatch::CallOrigin::< + AccountIdOf>, + SignerOf>, + SignatureOf>, + >::TargetAccount(bridged_account_id, this_public, this_signature), + dispatch_fee_payment: params.dispatch_fee_payment.clone(), + call: call.encode(), + } + .encode(); - // prepare Bridged chain header and insert it into the Substrate pallet - let bridged_header = make_bridged_header(root); - let bridged_header_hash = bridged_header.hash(); - pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); + // finally - prepare storage proof and update environment + let (state_root, storage_proof) = + prepare_messages_storage_proof::(¶ms, message_payload); + let bridged_header_hash = insert_bridged_chain_header::(state_root); ( FromBridgedChainMessagesProof { - bridged_header_hash: bridged_header_hash.into(), + bridged_header_hash, storage_proof, lane: params.lane, nonces_start: *params.message_nonces.start(), nonces_end: *params.message_nonces.end(), }, - message_dispatch_weight - .checked_mul(message_count) + call_weight + .checked_mul( + params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1, + ) .expect("too many messages requested by benchmark"), ) } /// Prepare proof of messages delivery for the `receive_messages_delivery_proof` call. -pub fn prepare_message_delivery_proof( +pub fn prepare_message_delivery_proof( params: MessageDeliveryProofParams>>, - make_bridged_inbound_lane_data_key: ML, - make_bridged_header: MH, ) -> FromBridgedChainMessagesDeliveryProof>> where - B: MessageBridge, - H: Hasher, R: pallet_bridge_grandpa::Config, + R::BridgedChain: bp_runtime::Chain
, FI: 'static, - ::Hash: Into>>, - ML: Fn(LaneId) -> Vec, - MH: Fn(H::Out) -> ::Header, + B: MessageBridge, + BH: Header>>, + BHH: Hasher>>, + HashOf>: Copy + Default, { // prepare Bridged chain storage with inbound lane state - let storage_key = make_bridged_inbound_lane_data_key(params.lane); + let storage_key = + storage_keys::inbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, ¶ms.lane).0; let mut root = Default::default(); let mut mdb = MemoryDB::default(); { - let mut trie = TrieDBMut::::new(&mut mdb, &mut root); + let mut trie = TrieDBMut::::new(&mut mdb, &mut root); trie.insert(&storage_key, ¶ms.inbound_lane_data.encode()) .map_err(|_| "TrieMut::insert has failed") .expect("TrieMut::insert should not fail in benchmarks"); @@ -183,16 +185,14 @@ where root = grow_trie(root, &mut mdb, params.size); // generate storage proof to be delivered to This chain - let mut proof_recorder = Recorder::::new(); - record_all_keys::, _>(&mdb, &root, &mut proof_recorder) + let mut proof_recorder = Recorder::::new(); + record_all_keys::, _>(&mdb, &root, &mut proof_recorder) .map_err(|_| "record_all_keys has failed") .expect("record_all_keys should not fail in benchmarks"); let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); - // prepare Bridged chain header and insert it into the Substrate pallet - let bridged_header = make_bridged_header(root); - let bridged_header_hash = bridged_header.hash(); - pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); + // finally insert header with given state root to our storage + let bridged_header_hash = insert_bridged_chain_header::(root); FromBridgedChainMessagesDeliveryProof { bridged_header_hash: bridged_header_hash.into(), @@ -201,6 +201,132 @@ where } } +/// Prepare storage proof of given messages. +/// +/// Returns state trie root and nodes with prepared messages. +fn prepare_messages_storage_proof( + params: &MessageProofParams, + message_payload: MessagePayload, +) -> (HashOf>, RawStorageProof) +where + B: MessageBridge, + BHH: Hasher>>, + HashOf>: Copy + Default, +{ + // prepare Bridged chain storage with messages and (optionally) outbound lane state + let message_count = + params.message_nonces.end().saturating_sub(*params.message_nonces.start()) + 1; + let mut storage_keys = Vec::with_capacity(message_count as usize + 1); + let mut root = Default::default(); + let mut mdb = MemoryDB::default(); + { + let mut trie = TrieDBMut::::new(&mut mdb, &mut root); + + // insert messages + for nonce in params.message_nonces.clone() { + let message_key = MessageKey { lane_id: params.lane, nonce }; + let message_data = MessageData { + fee: BalanceOf::>::from(0), + payload: message_payload.clone(), + }; + let storage_key = storage_keys::message_key( + B::BRIDGED_MESSAGES_PALLET_NAME, + &message_key.lane_id, + message_key.nonce, + ) + .0; + trie.insert(&storage_key, &message_data.encode()) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + } + + // insert outbound lane state + if let Some(ref outbound_lane_data) = params.outbound_lane_data { + let storage_key = + storage_keys::outbound_lane_data_key(B::BRIDGED_MESSAGES_PALLET_NAME, ¶ms.lane) + .0; + trie.insert(&storage_key, &outbound_lane_data.encode()) + .map_err(|_| "TrieMut::insert has failed") + .expect("TrieMut::insert should not fail in benchmarks"); + storage_keys.push(storage_key); + } + } + root = grow_trie(root, &mut mdb, params.size); + + // generate storage proof to be delivered to This chain + let mut proof_recorder = Recorder::::new(); + record_all_keys::, _>(&mdb, &root, &mut proof_recorder) + .map_err(|_| "record_all_keys has failed") + .expect("record_all_keys should not fail in benchmarks"); + let storage_proof = proof_recorder.drain().into_iter().map(|n| n.data.to_vec()).collect(); + + (root, storage_proof) +} + +/// Insert Bridged chain header with given state root into storage of GRANDPA pallet at This chain. +fn insert_bridged_chain_header( + state_root: HashOf>, +) -> HashOf> +where + R: pallet_bridge_grandpa::Config, + R::BridgedChain: bp_runtime::Chain
, + FI: 'static, + B: MessageBridge, + BH: Header>>, + HashOf>: Default, +{ + let bridged_header = BH::new( + Zero::zero(), + Default::default(), + state_root, + Default::default(), + Default::default(), + ); + let bridged_header_hash = bridged_header.hash(); + pallet_bridge_grandpa::initialize_for_benchmarks::(bridged_header); + bridged_header_hash +} + +/// Generate ed25519 signature to be used in +/// `pallet_brdige_call_dispatch::CallOrigin::TargetAccount`. +/// +/// Returns public key of the signer and the signature itself. +fn ed25519_sign( + target_call: &impl Encode, + source_account_id: &impl Encode, + target_spec_version: u32, + source_chain_id: ChainId, + target_chain_id: ChainId, +) -> ([u8; 32], [u8; 64]) { + // key from the repo example (https://docs.rs/ed25519-dalek/1.0.1/ed25519_dalek/struct.SecretKey.html) + let target_secret = SecretKey::from_bytes(&[ + 157, 097, 177, 157, 239, 253, 090, 096, 186, 132, 074, 244, 146, 236, 044, 196, 068, 073, + 197, 105, 123, 050, 105, 025, 112, 059, 172, 003, 028, 174, 127, 096, + ]) + .expect("harcoded key is valid"); + let target_public: PublicKey = (&target_secret).into(); + + let mut target_pair_bytes = [0u8; KEYPAIR_LENGTH]; + target_pair_bytes[..SECRET_KEY_LENGTH].copy_from_slice(&target_secret.to_bytes()); + target_pair_bytes[SECRET_KEY_LENGTH..].copy_from_slice(&target_public.to_bytes()); + let target_pair = + ed25519_dalek::Keypair::from_bytes(&target_pair_bytes).expect("hardcoded pair is valid"); + + let signature_message = pallet_bridge_dispatch::account_ownership_digest( + target_call, + source_account_id, + target_spec_version, + source_chain_id, + target_chain_id, + ); + let target_origin_signature = target_pair + .try_sign(&signature_message) + .expect("Ed25519 try_sign should not fail in benchmarks"); + + (target_public.to_bytes(), target_origin_signature.to_bytes()) +} + /// Populate trie with dummy keys+values until trie has at least given size. fn grow_trie(mut root: H::Out, mdb: &mut MemoryDB, trie_size: ProofSize) -> H::Out { let (iterations, leaf_size, minimal_trie_size) = match trie_size { diff --git a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json index 5280da7485..ad84e977c1 100644 --- a/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json +++ b/deployments/bridges/rialto-millau/dashboard/grafana/rialto-millau-maintenance-dashboard.json @@ -15,7 +15,6 @@ "editable": true, "gnetId": null, "graphTooltip": 0, - "id": 9, "links": [], "panels": [ { @@ -25,7 +24,9 @@ "dashes": false, "datasource": "Prometheus", "fieldConfig": { - "defaults": {}, + "defaults": { + "custom": {} + }, "overrides": [] }, "fill": 1, @@ -54,7 +55,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "7.5.3", + "pluginVersion": "7.1.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -129,7 +130,9 @@ "dashes": false, "datasource": "Prometheus", "fieldConfig": { - "defaults": {}, + "defaults": { + "custom": {} + }, "overrides": [] }, "fill": 1, @@ -158,7 +161,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "7.5.3", + "pluginVersion": "7.1.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -233,7 +236,9 @@ "dashes": false, "datasource": "Prometheus", "fieldConfig": { - "defaults": {}, + "defaults": { + "custom": {} + }, "overrides": [] }, "fill": 1, @@ -262,7 +267,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "7.5.3", + "pluginVersion": "7.1.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -337,7 +342,9 @@ "dashes": false, "datasource": "Prometheus", "fieldConfig": { - "defaults": {}, + "defaults": { + "custom": {} + }, "overrides": [] }, "fill": 1, @@ -366,7 +373,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "7.5.3", + "pluginVersion": "7.1.3", "pointradius": 2, "points": false, "renderer": "flot", @@ -433,22 +440,218 @@ "align": false, "alignLevel": null } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 16 + }, + "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": "at_Rialto_relay_balance", + "interval": "", + "legendFormat": "Relay account balance", + "refId": "A" + }, + { + "expr": "at_Rialto_messages_pallet_owner_balance", + "interval": "", + "legendFormat": "Messages pallet owner balance", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Rialto relay balances", + "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 + } + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "custom": {} + }, + "overrides": [] + }, + "fill": 1, + "fillGradient": 0, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 16 + }, + "hiddenSeries": false, + "id": 9, + "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": "at_Millau_relay_balance", + "interval": "", + "legendFormat": "Relay account balance", + "refId": "A" + }, + { + "expr": "at_Millau_messages_pallet_owner_balance", + "interval": "", + "legendFormat": "Messages pallet owner balance", + "refId": "B" + } + ], + "thresholds": [], + "timeFrom": null, + "timeRegions": [], + "timeShift": null, + "title": "Millau relay balances", + "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": "10s", - "schemaVersion": 27, + "schemaVersion": 26, "style": "dark", "tags": [], "templating": { "list": [] }, "time": { - "from": "now-1h", + "from": "now-15m", "to": "now" }, "timepicker": {}, "timezone": "", "title": "Rialto+Millau maintenance dashboard", "uid": "7AuyrjlMz", - "version": 2 -} + "version": 1 +} \ No newline at end of file diff --git a/deployments/networks/dashboard/grafana/beefy-dashboard.json b/deployments/networks/dashboard/grafana/beefy-dashboard.json index 4a4de45628..0216e14554 100644 --- a/deployments/networks/dashboard/grafana/beefy-dashboard.json +++ b/deployments/networks/dashboard/grafana/beefy-dashboard.json @@ -23,47 +23,24 @@ "conditions": [ { "evaluator": { - "params": [ - 1 - ], - "type": "lt" + "params": [ + 1 + ], + "type": "lt" }, "operator": { - "type": "and" + "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" - ] + "params": [ + "C", + "5m", + "now" + ] }, "reducer": { - "params": [], - "type": "max" + "params": [], + "type": "max" }, "type": "query" } @@ -378,29 +355,6 @@ "alert": { "alertRuleTags": {}, "conditions": [ - { - "evaluator": { - "params": [ - 0 - ], - "type": "gt" - }, - "operator": { - "type": "and" - }, - "query": { - "params": [ - "A", - "5m", - "now" - ] - }, - "reducer": { - "params": [], - "type": "max" - }, - "type": "query" - }, { "evaluator": { "params": [ diff --git a/modules/grandpa/src/lib.rs b/modules/grandpa/src/lib.rs index 1dadc58fe8..31b5280bb0 100644 --- a/modules/grandpa/src/lib.rs +++ b/modules/grandpa/src/lib.rs @@ -1151,6 +1151,11 @@ mod tests { #[test] fn storage_keys_computed_properly() { + assert_eq!( + IsHalted::::storage_value_final_key().to_vec(), + bp_header_chain::storage_keys::is_halted_key("Grandpa").0, + ); + assert_eq!( BestFinalized::::storage_value_final_key().to_vec(), bp_header_chain::storage_keys::best_finalized_hash_key("Grandpa").0, diff --git a/modules/messages/src/benchmarking.rs b/modules/messages/src/benchmarking.rs index f396365699..288ef4b2e8 100644 --- a/modules/messages/src/benchmarking.rs +++ b/modules/messages/src/benchmarking.rs @@ -41,6 +41,7 @@ const SEED: u32 = 0; pub struct Pallet, I: 'static>(crate::Pallet); /// Proof size requirements. +#[derive(Clone, Copy, Debug)] pub enum ProofSize { /// The proof is expected to be minimal. If value size may be changed, then it is expected to /// have given size. @@ -54,6 +55,7 @@ pub enum ProofSize { } /// Benchmark-specific message parameters. +#[derive(Debug)] pub struct MessageParams { /// Size of the message payload. pub size: u32, @@ -62,6 +64,7 @@ pub struct MessageParams { } /// Benchmark-specific message proof parameters. +#[derive(Debug)] pub struct MessageProofParams { /// Id of the lane. pub lane: LaneId, @@ -76,6 +79,7 @@ pub struct MessageProofParams { } /// Benchmark-specific message delivery proof parameters. +#[derive(Debug)] pub struct MessageDeliveryProofParams { /// Id of the lane. pub lane: LaneId, @@ -363,14 +367,9 @@ benchmarks_instance_pallet! { }); }: receive_messages_proof(RawOrigin::Signed(relayer_id_on_target), relayer_id_on_source, proof, 1, dispatch_weight) verify { - assert_eq!( - crate::InboundLanes::::get(&T::bench_lane_id()).last_delivered_nonce(), - 21, - ); - assert_eq!( - crate::Pallet::::inbound_latest_confirmed_nonce(T::bench_lane_id()), - 20, - ); + let lane_state = crate::InboundLanes::::get(&T::bench_lane_id()); + assert_eq!(lane_state.last_delivered_nonce(), 21); + assert_eq!(lane_state.last_confirmed_nonce, 20); assert!(T::is_message_dispatched(21)); } diff --git a/modules/messages/src/lib.rs b/modules/messages/src/lib.rs index 09298013a5..66bfecd259 100644 --- a/modules/messages/src/lib.rs +++ b/modules/messages/src/lib.rs @@ -764,11 +764,6 @@ pub mod pallet { OutboundMessages::::get(MessageKey { lane_id: lane, nonce }) } - /// Get nonce of the latest confirmed message at given inbound lane. - pub fn inbound_latest_confirmed_nonce(lane: LaneId) -> MessageNonce { - InboundLanes::::get(&lane).last_confirmed_nonce - } - /// Get state of unrewarded relayers set. pub fn inbound_unrewarded_relayers_state( lane: bp_messages::LaneId, @@ -1118,7 +1113,11 @@ 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, storage::generator::StorageMap, weights::Weight}; + use frame_support::{ + assert_noop, assert_ok, + storage::generator::{StorageMap, StorageValue}, + weights::Weight, + }; use frame_system::{EventRecord, Pallet as System, Phase}; use sp_runtime::DispatchError; @@ -2281,6 +2280,11 @@ mod tests { #[test] fn storage_keys_computed_properly() { + assert_eq!( + PalletOperatingMode::::storage_value_final_key().to_vec(), + bp_messages::storage_keys::operating_mode_key("Messages").0, + ); + assert_eq!( OutboundMessages::::storage_map_final_key(MessageKey { lane_id: TEST_LANE_ID, diff --git a/primitives/chain-kusama/src/lib.rs b/primitives/chain-kusama/src/lib.rs index 362e46d1ed..0f25ac710d 100644 --- a/primitives/chain-kusama/src/lib.rs +++ b/primitives/chain-kusama/src/lib.rs @@ -100,9 +100,6 @@ pub const TO_KUSAMA_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToKusamaOutboundLaneApi::message_details` runtime method. pub const TO_KUSAMA_MESSAGE_DETAILS_METHOD: &str = "ToKusamaOutboundLaneApi_message_details"; -/// Name of the `FromKusamaInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_KUSAMA_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromKusamaInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromKusamaInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_KUSAMA_UNREWARDED_RELAYERS_STATE: &str = "FromKusamaInboundLaneApi_unrewarded_relayers_state"; @@ -152,8 +149,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Kusama chain, not the /// Kusama runtime itself. pub trait FromKusamaInboundLaneApi { - /// 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-millau/src/lib.rs b/primitives/chain-millau/src/lib.rs index 6a8bbd3e33..2e671e901c 100644 --- a/primitives/chain-millau/src/lib.rs +++ b/primitives/chain-millau/src/lib.rs @@ -278,9 +278,6 @@ pub const TO_MILLAU_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToMillauOutboundLaneApi::message_details` runtime method. pub const TO_MILLAU_MESSAGE_DETAILS_METHOD: &str = "ToMillauOutboundLaneApi_message_details"; -/// Name of the `FromMillauInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_MILLAU_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromMillauInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromMillauInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_MILLAU_UNREWARDED_RELAYERS_STATE: &str = "FromMillauInboundLaneApi_unrewarded_relayers_state"; @@ -330,8 +327,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Millau chain, not the /// Millau runtime itself. pub trait FromMillauInboundLaneApi { - /// 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-polkadot/src/lib.rs b/primitives/chain-polkadot/src/lib.rs index 16c9a76bfd..19cf1a7970 100644 --- a/primitives/chain-polkadot/src/lib.rs +++ b/primitives/chain-polkadot/src/lib.rs @@ -100,9 +100,6 @@ pub const TO_POLKADOT_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToPolkadotOutboundLaneApi::message_details` runtime method. pub const TO_POLKADOT_MESSAGE_DETAILS_METHOD: &str = "ToPolkadotOutboundLaneApi_message_details"; -/// Name of the `FromPolkadotInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_POLKADOT_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromPolkadotInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromPolkadotInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_POLKADOT_UNREWARDED_RELAYERS_STATE: &str = "FromPolkadotInboundLaneApi_unrewarded_relayers_state"; @@ -152,8 +149,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Polkadot chain, not the /// Polkadot runtime itself. pub trait FromPolkadotInboundLaneApi { - /// 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-rialto/src/lib.rs b/primitives/chain-rialto/src/lib.rs index b995410a65..c6cb1bceb8 100644 --- a/primitives/chain-rialto/src/lib.rs +++ b/primitives/chain-rialto/src/lib.rs @@ -250,9 +250,6 @@ pub const TO_RIALTO_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToRialtoOutboundLaneApi::message_details` runtime method. pub const TO_RIALTO_MESSAGE_DETAILS_METHOD: &str = "ToRialtoOutboundLaneApi_message_details"; -/// Name of the `FromRialtoInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_RIALTO_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromRialtoInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromRialtoInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_RIALTO_UNREWARDED_RELAYERS_STATE: &str = "FromRialtoInboundLaneApi_unrewarded_relayers_state"; @@ -302,8 +299,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Rialto chain, not the /// Rialto runtime itself. pub trait FromRialtoInboundLaneApi { - /// 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-rococo/src/lib.rs b/primitives/chain-rococo/src/lib.rs index 222279e391..d485e916cf 100644 --- a/primitives/chain-rococo/src/lib.rs +++ b/primitives/chain-rococo/src/lib.rs @@ -89,9 +89,6 @@ pub const TO_ROCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToRococoOutboundLaneApi::message_details` runtime method. pub const TO_ROCOCO_MESSAGE_DETAILS_METHOD: &str = "ToRococoOutboundLaneApi_message_details"; -/// Name of the `FromRococoInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_ROCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromRococoInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromRococoInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_ROCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromRococoInboundLaneApi_unrewarded_relayers_state"; @@ -153,8 +150,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Rococo chain, not the /// Rococo runtime itself. pub trait FromRococoInboundLaneApi { - /// 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-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 fe804f93f7..68bc22c7cd 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, }; @@ -110,51 +109,4 @@ sp_api::decl_runtime_apis! { /// Returns number and hash of the best finalized header known to the bridge module. fn best_finalized() -> (BlockNumber, Hash); } - - /// 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 90eed6e33f..4f715c3994 100644 --- a/primitives/chain-wococo/src/lib.rs +++ b/primitives/chain-wococo/src/lib.rs @@ -54,9 +54,6 @@ pub const TO_WOCOCO_ESTIMATE_MESSAGE_FEE_METHOD: &str = /// Name of the `ToWococoOutboundLaneApi::message_details` runtime method. pub const TO_WOCOCO_MESSAGE_DETAILS_METHOD: &str = "ToWococoOutboundLaneApi_message_details"; -/// Name of the `FromWococoInboundLaneApi::latest_onfirmed_nonce` runtime method. -pub const FROM_WOCOCO_LATEST_CONFIRMED_NONCE_METHOD: &str = - "FromWococoInboundLaneApi_latest_confirmed_nonce"; /// Name of the `FromWococoInboundLaneApi::unrewarded_relayers_state` runtime method. pub const FROM_WOCOCO_UNREWARDED_RELAYERS_STATE: &str = "FromWococoInboundLaneApi_unrewarded_relayers_state"; @@ -106,8 +103,6 @@ sp_api::decl_runtime_apis! { /// This API is implemented by runtimes that are receiving messages from Wococo chain, not the /// Wococo runtime itself. pub trait FromWococoInboundLaneApi { - /// 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/header-chain/src/storage_keys.rs b/primitives/header-chain/src/storage_keys.rs index 460dbb8dc4..e123703eed 100644 --- a/primitives/header-chain/src/storage_keys.rs +++ b/primitives/header-chain/src/storage_keys.rs @@ -16,17 +16,30 @@ //! Storage keys of bridge GRANDPA pallet. -/// Name of the `BestFinalized` storage map. -pub const BEST_FINALIZED_MAP_NAME: &str = "BestFinalized"; +/// Name of the `IsHalted` storage value. +pub const IS_HALTED_VALUE_NAME: &str = "IsHalted"; +/// Name of the `BestFinalized` storage value. +pub const BEST_FINALIZED_VALUE_NAME: &str = "BestFinalized"; use sp_core::storage::StorageKey; +/// Storage key of the `IsHalted` flag in the runtime storage. +pub fn is_halted_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + IS_HALTED_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + /// Storage key of the best finalized header hash value in the runtime storage. pub fn best_finalized_hash_key(pallet_prefix: &str) -> StorageKey { StorageKey( bp_runtime::storage_value_final_key( pallet_prefix.as_bytes(), - BEST_FINALIZED_MAP_NAME.as_bytes(), + BEST_FINALIZED_VALUE_NAME.as_bytes(), ) .to_vec(), ) @@ -37,6 +50,19 @@ mod tests { use super::*; use hex_literal::hex; + #[test] + fn is_halted_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is breaking + // compatibility with previous pallet. + let storage_key = is_halted_key("BridgeGrandpa").0; + assert_eq!( + storage_key, + hex!("0b06f475eddb98cf933a12262e0388de9611a984bbd04e2fd39f97bbc006115f").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + #[test] fn best_finalized_hash_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking diff --git a/primitives/messages/src/storage_keys.rs b/primitives/messages/src/storage_keys.rs index 3e8dc67254..19494b8b85 100644 --- a/primitives/messages/src/storage_keys.rs +++ b/primitives/messages/src/storage_keys.rs @@ -16,6 +16,8 @@ //! Storage keys of bridge messages pallet. +/// Name of the `OPERATING_MODE_VALUE_NAME` storage value. +pub const OPERATING_MODE_VALUE_NAME: &str = "PalletOperatingMode"; /// Name of the `OutboundMessages` storage map. pub const OUTBOUND_MESSAGES_MAP_NAME: &str = "OutboundMessages"; /// Name of the `OutboundLanes` storage map. @@ -29,6 +31,17 @@ use codec::Encode; use frame_support::Blake2_128Concat; use sp_core::storage::StorageKey; +/// Storage key of the `PalletOperatingMode` value in the runtime storage. +pub fn operating_mode_key(pallet_prefix: &str) -> StorageKey { + StorageKey( + bp_runtime::storage_value_final_key( + pallet_prefix.as_bytes(), + OPERATING_MODE_VALUE_NAME.as_bytes(), + ) + .to_vec(), + ) +} + /// 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::( @@ -61,6 +74,19 @@ mod tests { use super::*; use hex_literal::hex; + #[test] + fn operating_mode_key_computed_properly() { + // If this test fails, then something has been changed in module storage that is possibly + // breaking all existing message relays. + let storage_key = operating_mode_key("BridgeMessages").0; + assert_eq!( + storage_key, + hex!("dd16c784ebd3390a9bc0357c7511ed010f4cf0917788d791142ff6c1f216e7b3").to_vec(), + "Unexpected storage key: {}", + hex::encode(&storage_key), + ); + } + #[test] fn storage_message_key_computed_properly() { // If this test fails, then something has been changed in module storage that is breaking diff --git a/relays/bin-substrate/src/cli/encode_call.rs b/relays/bin-substrate/src/cli/encode_call.rs index 8be04a88ff..b409cf383e 100644 --- a/relays/bin-substrate/src/cli/encode_call.rs +++ b/relays/bin-substrate/src/cli/encode_call.rs @@ -308,8 +308,8 @@ mod tests { ); } - #[test] - fn should_encode_bridge_send_message_call() { + #[async_std::test] + async fn should_encode_bridge_send_message_call() { // given let encode_message = SendMessage::from_iter(vec![ "send-message", @@ -325,6 +325,7 @@ mod tests { "remark", ]) .encode_payload() + .await .unwrap(); let mut encode_call = EncodeCall::from_iter(vec![ diff --git a/relays/bin-substrate/src/cli/mod.rs b/relays/bin-substrate/src/cli/mod.rs index 1ff46fdbb8..ae169f773e 100644 --- a/relays/bin-substrate/src/cli/mod.rs +++ b/relays/bin-substrate/src/cli/mod.rs @@ -240,7 +240,7 @@ impl AccountId { /// /// Used to abstract away CLI commands. pub trait CliChain: relay_substrate_client::Chain { - /// Chain's current version of the runtime. + /// Current version of the chain runtime, known to relay. const RUNTIME_VERSION: sp_version::RuntimeVersion; /// Crypto KeyPair type used to send messages. @@ -368,7 +368,7 @@ where } #[doc = "Runtime version params."] -#[derive(StructOpt, Debug, PartialEq, Eq, Clone, EnumString, EnumVariantNames)] +#[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy, EnumString, EnumVariantNames)] pub enum RuntimeVersionType { /// Auto query version from chain Auto, @@ -391,7 +391,7 @@ macro_rules! declare_chain_options { #[structopt(long, default_value = "127.0.0.1")] pub [<$chain_prefix _host>]: String, #[doc = "Connect to " $chain " node websocket server at given port."] - #[structopt(long)] + #[structopt(long, default_value = "9944")] pub [<$chain_prefix _port>]: u16, #[doc = "Use secure websocket connection."] #[structopt(long)] @@ -402,7 +402,7 @@ macro_rules! declare_chain_options { } #[doc = $chain " runtime version params."] - #[derive(StructOpt, Debug, PartialEq, Eq, Clone)] + #[derive(StructOpt, Debug, PartialEq, Eq, Clone, Copy)] pub struct [<$chain RuntimeVersionParams>] { #[doc = "The type of runtime version for chain " $chain] #[structopt(long, default_value = "Bundle")] @@ -543,29 +543,9 @@ macro_rules! declare_chain_options { &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 - } - } - }; + let chain_runtime_version = self + .[<$chain_prefix _runtime_version>] + .into_runtime_version(bundle_runtime_version)?; Ok(relay_substrate_client::Client::new(relay_substrate_client::ConnectionParams { host: self.[<$chain_prefix _host>].clone(), port: self.[<$chain_prefix _port>], @@ -575,6 +555,57 @@ macro_rules! declare_chain_options { .await ) } + + /// Return selected `chain_spec` version. + /// + /// This function only connects to the node if version mode is set to `Auto`. + #[allow(dead_code)] + pub async fn selected_chain_spec_version( + &self, + bundle_runtime_version: Option, + ) -> anyhow::Result { + let chain_runtime_version = self + .[<$chain_prefix _runtime_version>] + .into_runtime_version(bundle_runtime_version.clone())?; + Ok(match chain_runtime_version { + ChainRuntimeVersion::Auto => self + .to_client::(bundle_runtime_version) + .await? + .simple_runtime_version() + .await? + .0, + ChainRuntimeVersion::Custom(spec_version, _) => spec_version, + }) + } + } + + impl [<$chain RuntimeVersionParams>] { + /// Converts self into `ChainRuntimeVersion`. + pub fn into_runtime_version( + self, + bundle_runtime_version: Option, + ) -> anyhow::Result { + Ok(match self.[<$chain_prefix _version_mode>] { + RuntimeVersionType::Auto => ChainRuntimeVersion::Auto, + RuntimeVersionType::Custom => { + let except_spec_version = self.[<$chain_prefix _spec_version>] + .ok_or_else(|| anyhow::Error::msg(format!("The {}-spec-version is required when choose custom mode", stringify!($chain_prefix))))?; + let except_transaction_version = self.[<$chain_prefix _transaction_version>] + .ok_or_else(|| 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 + }, + }) + } } } }; 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 212eb9c6a0..11220af3e7 100644 --- a/relays/bin-substrate/src/cli/relay_headers_and_messages.rs +++ b/relays/bin-substrate/src/cli/relay_headers_and_messages.rs @@ -374,7 +374,7 @@ impl RelayHeadersAndMessages { let right_to_left_metrics = left_to_right_metrics.clone().reverse(); // start conversion rate update loops for left/right chains - if let Some(left_messages_pallet_owner) = left_messages_pallet_owner { + if let Some(left_messages_pallet_owner) = left_messages_pallet_owner.clone() { let left_client = left_client.clone(); let format_err = || { anyhow::format_err!( @@ -417,7 +417,7 @@ impl RelayHeadersAndMessages { }, ); } - if let Some(right_messages_pallet_owner) = right_messages_pallet_owner { + if let Some(right_messages_pallet_owner) = right_messages_pallet_owner.clone() { let right_client = right_client.clone(); let format_err = || { anyhow::format_err!( @@ -500,6 +500,24 @@ impl RelayHeadersAndMessages { } } + // add balance-related metrics + let metrics_params = + substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + left_client.clone(), + metrics_params, + Some(left_sign.public().into()), + left_messages_pallet_owner.map(|kp| kp.public().into()), + ) + .await?; + let metrics_params = + substrate_relay_helper::messages_metrics::add_relay_balances_metrics( + right_client.clone(), + metrics_params, + Some(right_sign.public().into()), + right_messages_pallet_owner.map(|kp| kp.public().into()), + ) + .await?; + // start on-demand header relays let left_to_right_transaction_params = TransactionParams { mortality: right_transactions_mortality, diff --git a/relays/bin-substrate/src/cli/send_message.rs b/relays/bin-substrate/src/cli/send_message.rs index 52eab9c64e..2d81576de3 100644 --- a/relays/bin-substrate/src/cli/send_message.rs +++ b/relays/bin-substrate/src/cli/send_message.rs @@ -19,7 +19,7 @@ use crate::cli::{ encode_call::{self, CliEncodeCall}, estimate_fee::estimate_message_delivery_and_dispatch_fee, Balance, CliChain, ExplicitOrMaximal, HexBytes, HexLaneId, Origins, SourceConnectionParams, - SourceSigningParams, TargetSigningParams, + SourceSigningParams, TargetConnectionParams, TargetSigningParams, }; use bp_message_dispatch::{CallOrigin, MessagePayload}; use bp_runtime::{BalanceOf, Chain as _}; @@ -88,10 +88,16 @@ pub struct SendMessage { /// `SourceAccount`. #[structopt(long, possible_values = &Origins::variants(), default_value = "Source")] origin: Origins, + + // Normally we don't need to connect to the target chain to send message. But for testing + // we may want to use **actual** `spec_version` of the target chain when composing a message. + // Then we'll need to read version from the target chain node. + #[structopt(flatten)] + target: TargetConnectionParams, } impl SendMessage { - pub fn encode_payload( + pub async fn encode_payload( &mut self, ) -> anyhow::Result>> { crate::select_full_bridge!(self.bridge, { @@ -110,6 +116,10 @@ impl SendMessage { encode_call::preprocess_call::(message, bridge.bridge_instance_index()); let target_call = Target::encode_call(message)?; + let target_spec_version = self + .target + .selected_chain_spec_version::(Some(Target::RUNTIME_VERSION)) + .await?; let payload = { let target_call_weight = prepare_call_dispatch_weight( @@ -121,7 +131,7 @@ impl SendMessage { let source_account_id = source_sender_public.into_account(); message_payload( - Target::RUNTIME_VERSION.spec_version, + target_spec_version, target_call_weight, match origin { Origins::Source => CallOrigin::SourceAccount(source_account_id), @@ -130,7 +140,7 @@ impl SendMessage { let digest = account_ownership_digest( &target_call, source_account_id.clone(), - Target::RUNTIME_VERSION.spec_version, + target_spec_version, ); let target_origin_public = target_sign.public(); let digest_signature = target_sign.sign(&digest); @@ -152,7 +162,7 @@ impl SendMessage { /// Run the command. pub async fn run(mut self) -> anyhow::Result<()> { crate::select_full_bridge!(self.bridge, { - let payload = self.encode_payload()?; + let payload = self.encode_payload().await?; let source_client = self.source.to_client::(SOURCE_RUNTIME_VERSION).await?; let source_sign = self.source_sign.to_keypair::()?; @@ -291,8 +301,8 @@ mod tests { use super::*; use hex_literal::hex; - #[test] - fn send_remark_rialto_to_millau() { + #[async_std::test] + async fn send_remark_rialto_to_millau() { // given let mut send_message = SendMessage::from_iter(vec![ "send-message", @@ -307,7 +317,7 @@ mod tests { ]); // when - let payload = send_message.encode_payload().unwrap(); + let payload = send_message.encode_payload().await.unwrap(); // then assert_eq!( @@ -324,8 +334,8 @@ mod tests { ); } - #[test] - fn send_remark_millau_to_rialto() { + #[async_std::test] + async fn send_remark_millau_to_rialto() { // given let mut send_message = SendMessage::from_iter(vec![ "send-message", @@ -344,7 +354,7 @@ mod tests { ]); // when - let payload = send_message.encode_payload().unwrap(); + let payload = send_message.encode_payload().await.unwrap(); // then // Since signatures are randomized we extract it from here and only check the rest. @@ -388,8 +398,8 @@ mod tests { assert!(send_message.is_ok()); } - #[test] - fn accepts_non_default_dispatch_fee_payment() { + #[async_std::test] + async fn accepts_non_default_dispatch_fee_payment() { // given let mut send_message = SendMessage::from_iter(vec![ "send-message", @@ -404,7 +414,7 @@ mod tests { ]); // when - let payload = send_message.encode_payload().unwrap(); + let payload = send_message.encode_payload().await.unwrap(); // then assert_eq!( diff --git a/relays/client-kusama/src/lib.rs b/relays/client-kusama/src/lib.rs index 55e8169941..982bf88d82 100644 --- a/relays/client-kusama/src/lib.rs +++ b/relays/client-kusama/src/lib.rs @@ -79,8 +79,6 @@ impl ChainWithMessages for Kusama { bp_kusama::WITH_KUSAMA_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_kusama::TO_KUSAMA_MESSAGE_DETAILS_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 = diff --git a/relays/client-millau/src/lib.rs b/relays/client-millau/src/lib.rs index 908ffc929c..3c159907f7 100644 --- a/relays/client-millau/src/lib.rs +++ b/relays/client-millau/src/lib.rs @@ -63,8 +63,6 @@ impl ChainWithMessages for Millau { bp_millau::WITH_MILLAU_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_millau::TO_MILLAU_MESSAGE_DETAILS_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 = diff --git a/relays/client-polkadot/src/lib.rs b/relays/client-polkadot/src/lib.rs index fbe1ffae08..6671b8c722 100644 --- a/relays/client-polkadot/src/lib.rs +++ b/relays/client-polkadot/src/lib.rs @@ -80,8 +80,6 @@ impl ChainWithMessages for Polkadot { bp_polkadot::WITH_POLKADOT_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_polkadot::TO_POLKADOT_MESSAGE_DETAILS_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 = diff --git a/relays/client-rialto/src/lib.rs b/relays/client-rialto/src/lib.rs index 61065b352f..4062a36b0d 100644 --- a/relays/client-rialto/src/lib.rs +++ b/relays/client-rialto/src/lib.rs @@ -78,8 +78,6 @@ impl ChainWithMessages for Rialto { bp_rialto::WITH_RIALTO_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_rialto::TO_RIALTO_MESSAGE_DETAILS_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 = diff --git a/relays/client-rococo/src/lib.rs b/relays/client-rococo/src/lib.rs index 7319b3f2ee..56ca95606a 100644 --- a/relays/client-rococo/src/lib.rs +++ b/relays/client-rococo/src/lib.rs @@ -82,8 +82,6 @@ impl ChainWithMessages for Rococo { bp_rococo::WITH_ROCOCO_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_rococo::TO_ROCOCO_MESSAGE_DETAILS_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 = diff --git a/relays/client-substrate/Cargo.toml b/relays/client-substrate/Cargo.toml index eacaa929a9..b6a702829f 100644 --- a/relays/client-substrate/Cargo.toml +++ b/relays/client-substrate/Cargo.toml @@ -33,9 +33,10 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "mast pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master" } pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-transaction-pool-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-rpc = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/client-substrate/src/chain.rs b/relays/client-substrate/src/chain.rs index d11e732d31..24b0127f3a 100644 --- a/relays/client-substrate/src/chain.rs +++ b/relays/client-substrate/src/chain.rs @@ -91,9 +91,6 @@ pub trait ChainWithMessages: Chain { /// The method is provided by the runtime that is bridged with this `ChainWithMessages`. const TO_CHAIN_MESSAGE_DETAILS_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; @@ -120,7 +117,7 @@ pub type WeightToFeeOf = ::WeightToFee; /// Transaction status of the chain. pub type TransactionStatusOf = TransactionStatus, HashOf>; -/// Substrate-based chain with `frame_system::Config::AccountData` set to +/// Substrate-based chain with `AccountData` generic argument of `frame_system::AccountInfo` set to /// the `pallet_balances::AccountData`. pub trait ChainWithBalances: Chain { /// Return runtime storage key for getting `frame_system::AccountInfo` of given account. diff --git a/relays/client-substrate/src/client.rs b/relays/client-substrate/src/client.rs index 74bf481d54..685f938d18 100644 --- a/relays/client-substrate/src/client.rs +++ b/relays/client-substrate/src/client.rs @@ -541,6 +541,15 @@ impl Client { .await } + /// Return `tokenDecimals` property from the set of chain properties. + pub async fn token_decimals(&self) -> Result> { + self.jsonrpsee_execute(move |client| async move { + let system_properties = Substrate::::system_properties(&*client).await?; + Ok(system_properties.get("tokenDecimals").and_then(|v| v.as_u64())) + }) + .await + } + /// Return new justifications stream. pub async fn subscribe_justifications(&self) -> Result> { let subscription = self diff --git a/relays/client-substrate/src/error.rs b/relays/client-substrate/src/error.rs index 33b9b22a03..309531dd26 100644 --- a/relays/client-substrate/src/error.rs +++ b/relays/client-substrate/src/error.rs @@ -51,6 +51,9 @@ pub enum Error { /// The client we're connected to is not synced, so we can't rely on its state. #[error("Substrate client is not synced {0}.")] ClientNotSynced(Health), + /// The bridge pallet is halted and all transactions will be rejected. + #[error("Bridge pallet is halted.")] + BridgePalletIsHalted, /// An error has happened when we have tried to parse storage proof. #[error("Error when parsing storage proof: {0:?}.")] StorageProofError(bp_runtime::StorageProofError), diff --git a/relays/client-substrate/src/metrics/float_storage_value.rs b/relays/client-substrate/src/metrics/float_storage_value.rs index 7dccf82b6f..7bb92693b3 100644 --- a/relays/client-substrate/src/metrics/float_storage_value.rs +++ b/relays/client-substrate/src/metrics/float_storage_value.rs @@ -14,48 +14,84 @@ // You should have received a copy of the GNU General Public License // along with Parity Bridges Common. If not, see . -use crate::{chain::Chain, client::Client}; +use crate::{chain::Chain, client::Client, Error as SubstrateError}; use async_std::sync::{Arc, RwLock}; use async_trait::async_trait; use codec::Decode; +use num_traits::One; use relay_utils::metrics::{ metric_name, register, F64SharedRef, Gauge, Metric, PrometheusError, Registry, StandaloneMetric, F64, }; -use sp_core::storage::StorageKey; -use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber}; -use std::time::Duration; +use sp_core::storage::{StorageData, StorageKey}; +use sp_runtime::{traits::UniqueSaturatedInto, FixedPointNumber, FixedU128}; +use std::{marker::PhantomData, time::Duration}; /// Storage value update interval (in blocks). const UPDATE_INTERVAL_IN_BLOCKS: u32 = 5; +/// Fied-point storage value and the way it is decoded from the raw storage value. +pub trait FloatStorageValue: 'static + Clone + Send + Sync { + /// Type of the value. + type Value: FixedPointNumber; + /// Try to decode value from the raw storage value. + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError>; +} + +/// Implementation of `FloatStorageValue` that expects encoded `FixedU128` value and returns `1` if +/// value is missing from the storage. +#[derive(Clone, Debug, Default)] +pub struct FixedU128OrOne; + +impl FloatStorageValue for FixedU128OrOne { + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + FixedU128::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(Some) + }) + .unwrap_or_else(|| Ok(Some(FixedU128::one()))) + } +} + /// Metric that represents fixed-point runtime storage value as float gauge. #[derive(Clone, Debug)] -pub struct FloatStorageValueMetric { +pub struct FloatStorageValueMetric { + value_converter: V, client: Client, storage_key: StorageKey, - maybe_default_value: Option, metric: Gauge, shared_value_ref: F64SharedRef, + _phantom: PhantomData, } -impl FloatStorageValueMetric { +impl FloatStorageValueMetric { /// Create new metric. pub fn new( + value_converter: V, client: Client, storage_key: StorageKey, - maybe_default_value: Option, name: String, help: String, ) -> Result { let shared_value_ref = Arc::new(RwLock::new(None)); Ok(FloatStorageValueMetric { + value_converter, client, storage_key, - maybe_default_value, metric: Gauge::new(metric_name(None, &name), help)?, shared_value_ref, + _phantom: Default::default(), }) } @@ -65,20 +101,14 @@ impl FloatStorageValueMetric { } } -impl Metric for FloatStorageValueMetric -where - T: 'static + Decode + Send + Sync + FixedPointNumber, -{ +impl Metric for FloatStorageValueMetric { fn register(&self, registry: &Registry) -> Result<(), PrometheusError> { register(self.metric.clone(), registry).map(drop) } } #[async_trait] -impl StandaloneMetric for FloatStorageValueMetric -where - T: 'static + Decode + Send + Sync + FixedPointNumber, -{ +impl StandaloneMetric for FloatStorageValueMetric { fn update_interval(&self) -> Duration { C::AVERAGE_BLOCK_INTERVAL * UPDATE_INTERVAL_IN_BLOCKS } @@ -86,16 +116,18 @@ where async fn update(&self) { let value = self .client - .storage_value::(self.storage_key.clone(), None) + .raw_storage_value(self.storage_key.clone(), None) .await - .map(|maybe_storage_value| { - maybe_storage_value.or(self.maybe_default_value).map(|storage_value| { - storage_value.into_inner().unique_saturated_into() as f64 / - T::DIV.unique_saturated_into() as f64 + .and_then(|maybe_storage_value| { + self.value_converter.decode(maybe_storage_value).map(|maybe_fixed_point_value| { + maybe_fixed_point_value.map(|fixed_point_value| { + fixed_point_value.into_inner().unique_saturated_into() as f64 / + V::Value::DIV.unique_saturated_into() as f64 + }) }) }) - .map_err(drop); - relay_utils::metrics::set_gauge_value(&self.metric, value); + .map_err(|e| e.to_string()); + relay_utils::metrics::set_gauge_value(&self.metric, value.clone()); *self.shared_value_ref.write().await = value.ok().and_then(|x| x); } } diff --git a/relays/client-substrate/src/metrics/mod.rs b/relays/client-substrate/src/metrics/mod.rs index 177e2a709c..3b63099e00 100644 --- a/relays/client-substrate/src/metrics/mod.rs +++ b/relays/client-substrate/src/metrics/mod.rs @@ -16,7 +16,7 @@ //! Contains several Substrate-specific metrics that may be exposed by relay. -pub use float_storage_value::FloatStorageValueMetric; +pub use float_storage_value::{FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric}; pub use storage_proof_overhead::StorageProofOverheadMetric; mod float_storage_value; diff --git a/relays/client-substrate/src/rpc.rs b/relays/client-substrate/src/rpc.rs index efd45ebe43..b792347d7a 100644 --- a/relays/client-substrate/src/rpc.rs +++ b/relays/client-substrate/src/rpc.rs @@ -31,6 +31,8 @@ jsonrpsee_proc_macros::rpc_client_api! { pub(crate) Substrate { #[rpc(method = "system_health", positional_params)] fn system_health() -> Health; + #[rpc(method = "system_properties", positional_params)] + fn system_properties() -> sc_chain_spec::Properties; #[rpc(method = "chain_getHeader", positional_params)] fn chain_get_header(block_hash: Option) -> C::Header; #[rpc(method = "chain_getFinalizedHead", positional_params)] diff --git a/relays/client-wococo/src/lib.rs b/relays/client-wococo/src/lib.rs index a6f6d734dd..fd45fc0dc1 100644 --- a/relays/client-wococo/src/lib.rs +++ b/relays/client-wococo/src/lib.rs @@ -82,8 +82,6 @@ impl ChainWithMessages for Wococo { bp_wococo::WITH_WOCOCO_MESSAGES_PALLET_NAME; const TO_CHAIN_MESSAGE_DETAILS_METHOD: &'static str = bp_wococo::TO_WOCOCO_MESSAGE_DETAILS_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 = diff --git a/relays/lib-substrate-relay/Cargo.toml b/relays/lib-substrate-relay/Cargo.toml index 1224d81439..5733e398f3 100644 --- a/relays/lib-substrate-relay/Cargo.toml +++ b/relays/lib-substrate-relay/Cargo.toml @@ -36,6 +36,8 @@ bp-messages = { path = "../../primitives/messages" } # Substrate Dependencies frame-support = { git = "https://github.com/paritytech/substrate", branch = "master" } +frame-system = { git = "https://github.com/paritytech/substrate", branch = "master" } +pallet-balances = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-finality-grandpa = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } diff --git a/relays/lib-substrate-relay/src/finality_pipeline.rs b/relays/lib-substrate-relay/src/finality_pipeline.rs index 07a1279ef4..84fb866101 100644 --- a/relays/lib-substrate-relay/src/finality_pipeline.rs +++ b/relays/lib-substrate-relay/src/finality_pipeline.rs @@ -27,8 +27,8 @@ use bp_header_chain::justification::GrandpaJustification; use finality_relay::FinalitySyncPipeline; use pallet_bridge_grandpa::{Call as BridgeGrandpaCall, Config as BridgeGrandpaConfig}; use relay_substrate_client::{ - transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, Client, - HashOf, HeaderOf, SyncHeader, TransactionSignScheme, + transaction_stall_timeout, AccountIdOf, AccountKeyPairOf, BlockNumberOf, CallOf, Chain, + ChainWithGrandpa, Client, HashOf, HeaderOf, SyncHeader, TransactionSignScheme, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; @@ -44,7 +44,7 @@ pub(crate) const RECENT_FINALITY_PROOFS_LIMIT: usize = 4096; #[async_trait] pub trait SubstrateFinalitySyncPipeline: 'static + Clone + Debug + Send + Sync { /// Headers of this chain are submitted to the `TargetChain`. - type SourceChain: Chain; + type SourceChain: ChainWithGrandpa; /// Headers of the `SourceChain` are submitted to this chain. type TargetChain: Chain; diff --git a/relays/lib-substrate-relay/src/finality_target.rs b/relays/lib-substrate-relay/src/finality_target.rs index 918c633d74..9a92c88a23 100644 --- a/relays/lib-substrate-relay/src/finality_target.rs +++ b/relays/lib-substrate-relay/src/finality_target.rs @@ -26,12 +26,12 @@ use crate::{ }; use async_trait::async_trait; -use bp_header_chain::justification::GrandpaJustification; +use bp_header_chain::{justification::GrandpaJustification, storage_keys::is_halted_key}; use codec::Encode; use finality_relay::TargetClient; use relay_substrate_client::{ - AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, Client, Error, HashOf, HeaderOf, - SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, + AccountIdOf, AccountKeyPairOf, BlockNumberOf, Chain, ChainWithGrandpa, Client, Error, HashOf, + HeaderOf, SignParam, SyncHeader, TransactionEra, TransactionSignScheme, UnsignedTransaction, }; use relay_utils::relay_loop::Client as RelayClient; use sp_core::{Bytes, Pair}; @@ -50,6 +50,19 @@ impl SubstrateFinalityTarget

{ ) -> Self { SubstrateFinalityTarget { client, transaction_params } } + + /// Ensure that the GRANDPA pallet at target chain is active. + async fn ensure_pallet_active(&self) -> Result<(), Error> { + let is_halted = self + .client + .storage_value(is_halted_key(P::SourceChain::WITH_CHAIN_GRANDPA_PALLET_NAME), None) + .await?; + if is_halted.unwrap_or(false) { + Err(Error::BridgePalletIsHalted) + } else { + Ok(()) + } + } } impl Clone for SubstrateFinalityTarget

{ @@ -83,6 +96,8 @@ where // 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?; + // we can't relay finality if GRANDPA pallet at target chain is halted + self.ensure_pallet_active().await?; Ok(crate::messages_source::read_client_state::< P::TargetChain, diff --git a/relays/lib-substrate-relay/src/messages_lane.rs b/relays/lib-substrate-relay/src/messages_lane.rs index 87146be489..380d1c9624 100644 --- a/relays/lib-substrate-relay/src/messages_lane.rs +++ b/relays/lib-substrate-relay/src/messages_lane.rs @@ -34,8 +34,8 @@ 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::{ - AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, ChainWithMessages, Client, HashOf, - TransactionSignScheme, + transaction_stall_timeout, AccountKeyPairOf, BalanceOf, BlockNumberOf, CallOf, Chain, + ChainWithMessages, Client, HashOf, TransactionSignScheme, }; use relay_utils::metrics::MetricsParams; use sp_core::Pair; @@ -173,7 +173,7 @@ where 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\ + Tx mortality: {:?} (~{}m)/{:?} (~{}m)\n\t\ Stall timeout: {:?}", P::SourceChain::NAME, P::TargetChain::NAME, @@ -183,7 +183,17 @@ where max_messages_size_in_single_batch, max_messages_weight_in_single_batch, params.source_transaction_params.mortality, + transaction_stall_timeout( + params.source_transaction_params.mortality, + P::SourceChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ).as_secs_f64() / 60.0f64, params.target_transaction_params.mortality, + transaction_stall_timeout( + params.target_transaction_params.mortality, + P::TargetChain::AVERAGE_BLOCK_INTERVAL, + STALL_TIMEOUT, + ).as_secs_f64() / 60.0f64, stall_timeout, ); diff --git a/relays/lib-substrate-relay/src/messages_metrics.rs b/relays/lib-substrate-relay/src/messages_metrics.rs index 54eef6c0ae..d2206094fe 100644 --- a/relays/lib-substrate-relay/src/messages_metrics.rs +++ b/relays/lib-substrate-relay/src/messages_metrics.rs @@ -18,16 +18,21 @@ use crate::messages_lane::SubstrateMessageLane; -use num_traits::One; +use codec::Decode; +use frame_system::AccountInfo; +use pallet_balances::AccountData; use relay_substrate_client::{ - metrics::{FloatStorageValueMetric, StorageProofOverheadMetric}, - Chain, Client, + metrics::{ + FixedU128OrOne, FloatStorageValue, FloatStorageValueMetric, StorageProofOverheadMetric, + }, + AccountIdOf, BalanceOf, Chain, ChainWithBalances, Client, Error as SubstrateError, IndexOf, }; use relay_utils::metrics::{ FloatJsonValueMetric, GlobalMetrics, MetricsParams, PrometheusError, StandaloneMetric, }; -use sp_runtime::FixedU128; -use std::fmt::Debug; +use sp_core::storage::StorageData; +use sp_runtime::{FixedPointNumber, FixedU128}; +use std::{convert::TryFrom, fmt::Debug, marker::PhantomData}; /// Shared references to the standalone metrics of the message lane relay loop. #[derive(Debug, Clone)] @@ -44,12 +49,10 @@ pub struct StandaloneMessagesMetrics { 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>, + 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>, + pub target_to_source_conversion_rate: Option>, } impl StandaloneMessagesMetrics { @@ -104,7 +107,7 @@ impl StandaloneMessagesMetrics { } } -/// Create standalone metrics for the message lane relay loop. +/// Create symmetric 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`). @@ -139,10 +142,10 @@ pub fn standalone_metrics( 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( + FloatStorageValueMetric::new( + FixedU128OrOne::default(), target_client, key, - Some(FixedU128::one()), format!( "{}_{}_to_{}_conversion_rate", P::TargetChain::NAME, @@ -162,10 +165,10 @@ pub fn standalone_metrics( 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( + FloatStorageValueMetric::new( + FixedU128OrOne::default(), source_client, key, - Some(FixedU128::one()), format!( "{}_{}_to_{}_conversion_rate", P::SourceChain::NAME, @@ -185,6 +188,90 @@ pub fn standalone_metrics( }) } +/// Add relay accounts balance metrics. +pub async fn add_relay_balances_metrics( + client: Client, + metrics: MetricsParams, + relay_account_id: Option>, + messages_pallet_owner_account_id: Option>, +) -> anyhow::Result +where + BalanceOf: Into + std::fmt::Debug, +{ + if relay_account_id.is_none() && messages_pallet_owner_account_id.is_none() { + return Ok(metrics) + } + + let token_decimals = client.token_decimals().await?.ok_or_else(|| { + SubstrateError::Custom(format!("Missing token decimals from {} system properties", C::NAME)) + })?; + let token_decimals = u32::try_from(token_decimals).map_err(|e| { + anyhow::format_err!( + "Token decimals value ({}) of {} doesn't fit into u32: {:?}", + token_decimals, + C::NAME, + e, + ) + })?; + if let Some(relay_account_id) = relay_account_id { + let relay_account_balance_metric = FloatStorageValueMetric::new( + FreeAccountBalance:: { token_decimals, _phantom: Default::default() }, + client.clone(), + C::account_info_storage_key(&relay_account_id), + format!("at_{}_relay_balance", C::NAME), + format!("Balance of the relay account at the {}", C::NAME), + )?; + relay_account_balance_metric.register_and_spawn(&metrics.registry)?; + } + if let Some(messages_pallet_owner_account_id) = messages_pallet_owner_account_id { + let pallet_owner_account_balance_metric = FloatStorageValueMetric::new( + FreeAccountBalance:: { token_decimals, _phantom: Default::default() }, + client.clone(), + C::account_info_storage_key(&messages_pallet_owner_account_id), + format!("at_{}_messages_pallet_owner_balance", C::NAME), + format!("Balance of the messages pallet owner at the {}", C::NAME), + )?; + pallet_owner_account_balance_metric.register_and_spawn(&metrics.registry)?; + } + Ok(metrics) +} + +/// Adapter for `FloatStorageValueMetric` to decode account free balance. +#[derive(Clone, Debug)] +struct FreeAccountBalance { + token_decimals: u32, + _phantom: PhantomData, +} + +impl FloatStorageValue for FreeAccountBalance +where + C: Chain, + BalanceOf: Into, +{ + type Value = FixedU128; + + fn decode( + &self, + maybe_raw_value: Option, + ) -> Result, SubstrateError> { + maybe_raw_value + .map(|raw_value| { + AccountInfo::, AccountData>>::decode(&mut &raw_value.0[..]) + .map_err(SubstrateError::ResponseParseFailed) + .map(|account_data| { + convert_to_token_balance(account_data.data.free.into(), self.token_decimals) + }) + }) + .transpose() + } +} + +/// Convert from raw `u128` balance (nominated in smallest chain token units) to the float regular +/// tokens value. +fn convert_to_token_balance(balance: u128, token_decimals: u32) -> FixedU128 { + FixedU128::from_inner(balance.saturating_mul(FixedU128::DIV / 10u128.pow(token_decimals))) +} + #[cfg(test)] mod tests { use super::*; @@ -196,4 +283,12 @@ mod tests { Some(12.32 / 183.15), ); } + + #[test] + fn token_decimals_used_properly() { + let plancks = 425_000_000_000; + let token_decimals = 10; + let dots = convert_to_token_balance(plancks, token_decimals); + assert_eq!(dots, FixedU128::saturating_from_rational(425, 10)); + } } diff --git a/relays/lib-substrate-relay/src/messages_source.rs b/relays/lib-substrate-relay/src/messages_source.rs index 87296457f8..de2306be3f 100644 --- a/relays/lib-substrate-relay/src/messages_source.rs +++ b/relays/lib-substrate-relay/src/messages_source.rs @@ -29,8 +29,8 @@ use crate::{ use async_trait::async_trait; use bp_messages::{ - storage_keys::outbound_lane_data_key, LaneId, MessageNonce, OutboundLaneData, - UnrewardedRelayersState, + storage_keys::{operating_mode_key, outbound_lane_data_key}, + LaneId, MessageNonce, OperatingMode, OutboundLaneData, UnrewardedRelayersState, }; use bridge_runtime_common::messages::{ source::FromBridgedChainMessagesDeliveryProof, target::FromBridgedChainMessagesProof, @@ -83,6 +83,27 @@ impl SubstrateMessagesSource

{ target_to_source_headers_relay, } } + + /// Read outbound lane state from the on-chain storage at given block. + async fn outbound_lane_data( + &self, + id: SourceHeaderIdOf>, + ) -> Result, SubstrateError> { + self.client + .storage_value( + outbound_lane_data_key( + P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ), + Some(id.1), + ) + .await + } + + /// Ensure that the messages pallet at source chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.client).await + } } impl Clone for SubstrateMessagesSource

{ @@ -116,6 +137,8 @@ where // 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?; + // we can't relay confirmations if messages pallet at source chain is halted + self.ensure_pallet_active().await?; read_client_state::< _, @@ -129,19 +152,12 @@ where &self, id: SourceHeaderIdOf>, ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { - let outbound_lane_data: Option = self - .client - .storage_value( - outbound_lane_data_key( - P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, - &self.lane_id, - ), - Some(id.1), - ) - .await?; // 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); + let latest_generated_nonce = self + .outbound_lane_data(id) + .await? + .map(|data| data.latest_generated_nonce) + .unwrap_or(0); Ok((id, latest_generated_nonce)) } @@ -149,19 +165,12 @@ where &self, id: SourceHeaderIdOf>, ) -> Result<(SourceHeaderIdOf>, MessageNonce), SubstrateError> { - let outbound_lane_data: Option = self - .client - .storage_value( - outbound_lane_data_key( - P::TargetChain::WITH_CHAIN_MESSAGES_PALLET_NAME, - &self.lane_id, - ), - Some(id.1), - ) - .await?; // lane data missing from the storage is fine until first message is sent - let latest_received_nonce = - outbound_lane_data.map(|data| data.latest_received_nonce).unwrap_or(0); + let latest_received_nonce = self + .outbound_lane_data(id) + .await? + .map(|data| data.latest_received_nonce) + .unwrap_or(0); Ok((id, latest_received_nonce)) } @@ -290,6 +299,25 @@ where } } +/// Ensure that the messages pallet at source chain is active. +pub(crate) async fn ensure_messages_pallet_active( + client: &Client, +) -> Result<(), SubstrateError> +where + AtChain: ChainWithMessages, + WithChain: ChainWithMessages, +{ + let operating_mode = client + .storage_value(operating_mode_key(WithChain::WITH_CHAIN_MESSAGES_PALLET_NAME), None) + .await?; + let is_halted = operating_mode == Some(OperatingMode::Halted); + if is_halted { + Err(SubstrateError::BridgePalletIsHalted) + } else { + Ok(()) + } +} + /// Make messages delivery proof transaction from given proof. fn make_messages_delivery_proof_transaction( spec_version: u32, diff --git a/relays/lib-substrate-relay/src/messages_target.rs b/relays/lib-substrate-relay/src/messages_target.rs index cdd25c64e5..f973cef897 100644 --- a/relays/lib-substrate-relay/src/messages_target.rs +++ b/relays/lib-substrate-relay/src/messages_target.rs @@ -21,7 +21,7 @@ use crate::{ messages_lane::{MessageLaneAdapter, ReceiveMessagesProofCallBuilder, SubstrateMessageLane}, messages_metrics::StandaloneMessagesMetrics, - messages_source::{read_client_state, SubstrateMessagesProof}, + messages_source::{ensure_messages_pallet_active, read_client_state, SubstrateMessagesProof}, on_demand_headers::OnDemandHeadersRelay, TransactionParams, }; @@ -84,6 +84,27 @@ impl SubstrateMessagesTarget

{ source_to_target_headers_relay, } } + + /// Read inbound lane state from the on-chain storage at given block. + async fn inbound_lane_data( + &self, + id: TargetHeaderIdOf>, + ) -> Result>>, SubstrateError> { + self.client + .storage_value( + inbound_lane_data_key( + P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, + &self.lane_id, + ), + Some(id.1), + ) + .await + } + + /// Ensure that the messages pallet at target chain is active. + async fn ensure_pallet_active(&self) -> Result<(), SubstrateError> { + ensure_messages_pallet_active::(&self.client).await + } } impl Clone for SubstrateMessagesTarget

{ @@ -120,6 +141,8 @@ where // 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?; + // we can't relay messages if messages pallet at target chain is halted + self.ensure_pallet_active().await?; read_client_state::< _, @@ -133,19 +156,12 @@ where &self, id: TargetHeaderIdOf>, ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { - let inbound_lane_data: Option>> = self - .client - .storage_value( - inbound_lane_data_key( - P::SourceChain::WITH_CHAIN_MESSAGES_PALLET_NAME, - &self.lane_id, - ), - Some(id.1), - ) - .await?; // lane data missing from the storage is fine until first message is received - let latest_received_nonce = - inbound_lane_data.map(|data| data.last_delivered_nonce()).unwrap_or(0); + let latest_received_nonce = self + .inbound_lane_data(id) + .await? + .map(|data| data.last_delivered_nonce()) + .unwrap_or(0); Ok((id, latest_received_nonce)) } @@ -153,17 +169,13 @@ where &self, id: TargetHeaderIdOf>, ) -> Result<(TargetHeaderIdOf>, MessageNonce), SubstrateError> { - let encoded_response = self - .client - .state_call( - P::SourceChain::FROM_CHAIN_LATEST_CONFIRMED_NONCE_METHOD.into(), - Bytes(self.lane_id.encode()), - Some(id.1), - ) - .await?; - let latest_received_nonce: MessageNonce = Decode::decode(&mut &encoded_response.0[..]) - .map_err(SubstrateError::ResponseParseFailed)?; - Ok((id, latest_received_nonce)) + // lane data missing from the storage is fine until first message is received + let last_confirmed_nonce = self + .inbound_lane_data(id) + .await? + .map(|data| data.last_confirmed_nonce) + .unwrap_or(0); + Ok((id, last_confirmed_nonce)) } async fn unrewarded_relayers_state(