From 3d7d22279997a9780eac7aec9d07d883ddf6dfcf Mon Sep 17 00:00:00 2001 From: skunert Date: Tue, 21 Dec 2021 12:00:18 +0100 Subject: [PATCH 01/31] Initial network interface preparations --- Cargo.lock | 256 ++++++++++++++++++-- client/network/Cargo.toml | 2 +- client/network/src/lib.rs | 2 +- client/network/src/tests.rs | 5 +- client/relay-chain-interface/src/lib.rs | 15 +- client/relay-chain-local/src/lib.rs | 4 +- client/relay-chain-network/Cargo.toml | 32 +++ client/relay-chain-network/src/lib.rs | 300 ++++++++++++++++++++++++ test/service/Cargo.toml | 2 +- test/service/src/lib.rs | 5 +- 10 files changed, 579 insertions(+), 44 deletions(-) create mode 100644 client/relay-chain-network/Cargo.toml create mode 100644 client/relay-chain-network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9a6ef3b0759..18966f83a90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1376,7 +1376,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" dependencies = [ - "sct", + "sct 0.6.1", ] [[package]] @@ -1881,6 +1881,33 @@ dependencies = [ "tracing", ] +[[package]] +name = "cumulus-relay-chain-network" +version = "0.1.0" +dependencies = [ + "async-trait", + "cumulus-primitives-core", + "cumulus-relay-chain-interface", + "futures 0.3.19", + "jsonrpsee 0.6.1", + "parking_lot 0.11.2", + "polkadot-client", + "polkadot-service", + "sc-client-api", + "sc-consensus-babe", + "sc-network", + "sc-service", + "sc-telemetry", + "sc-tracing", + "sp-api", + "sp-blockchain", + "sp-consensus", + "sp-core", + "sp-runtime", + "sp-state-machine", + "tracing", +] + [[package]] name = "cumulus-test-client" version = "0.1.0" @@ -1975,7 +2002,7 @@ dependencies = [ "cumulus-client-service", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", - "cumulus-relay-chain-local", + "cumulus-relay-chain-network", "cumulus-test-relay-validation-worker-provider", "cumulus-test-runtime", "frame-system", @@ -2845,8 +2872,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" dependencies = [ "futures-io", - "rustls", - "webpki", + "rustls 0.19.1", + "webpki 0.21.4", ] [[package]] @@ -3237,11 +3264,27 @@ dependencies = [ "futures-util", "hyper", "log", - "rustls", - "rustls-native-certs", + "rustls 0.19.1", + "rustls-native-certs 0.5.0", "tokio", - "tokio-rustls", - "webpki", + "tokio-rustls 0.22.0", + "webpki 0.21.4", +] + +[[package]] +name = "hyper-rustls" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "log", + "rustls 0.20.2", + "rustls-native-certs 0.6.1", + "tokio", + "tokio-rustls 0.23.2", + "webpki-roots 0.22.1", ] [[package]] @@ -3601,9 +3644,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ "jsonrpsee-proc-macros", - "jsonrpsee-types", - "jsonrpsee-utils", - "jsonrpsee-ws-client", + "jsonrpsee-types 0.4.1", + "jsonrpsee-utils 0.4.1", + "jsonrpsee-ws-client 0.4.1", +] + +[[package]] +name = "jsonrpsee" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceafa2f3d8cb796bf63364691fb875b079814064306cfd4cb067f95f800a673f" +dependencies = [ + "jsonrpsee-http-client", + "jsonrpsee-types 0.6.1", + "jsonrpsee-utils 0.6.1", + "jsonrpsee-ws-client 0.6.1", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5531d414c35725627559c9a228a63fa466067153686848e1db7cb9d3366e4b7" +dependencies = [ + "async-trait", + "fnv", + "hyper", + "hyper-rustls 0.23.0", + "jsonrpsee-types 0.6.1", + "jsonrpsee-utils 0.6.1", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url 2.2.2", ] [[package]] @@ -3638,6 +3713,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "jsonrpsee-types" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7589284e20eb3f40544c672370512e239d9704d6bfa2d3e7a7a7cd505a56e69" +dependencies = [ + "anyhow", + "async-trait", + "beef", + "futures-channel", + "futures-util", + "hyper", + "serde", + "serde_json", + "soketto", + "thiserror", + "tracing", +] + [[package]] name = "jsonrpsee-utils" version = "0.4.1" @@ -3646,7 +3740,20 @@ checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" dependencies = [ "arrayvec 0.7.2", "beef", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", +] + +[[package]] +name = "jsonrpsee-utils" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbc508d9e6169a81d2913035e8c97f2c49f699134cd3d93efa13c4457aa76252" +dependencies = [ + "arrayvec 0.7.2", + "beef", + "futures-util", + "hyper", + "jsonrpsee-types 0.6.1", ] [[package]] @@ -3660,17 +3767,41 @@ dependencies = [ "fnv", "futures 0.3.19", "http", - "jsonrpsee-types", + "jsonrpsee-types 0.4.1", "log", "pin-project 1.0.8", - "rustls-native-certs", + "rustls-native-certs 0.5.0", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tokio-rustls 0.22.0", + "tokio-util", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9267225fdfda02df5c5a9793c90cfe9f2ae5f91d42d4da78bd64f0116a28e9a" +dependencies = [ + "async-trait", + "fnv", + "futures 0.3.19", + "http", + "jsonrpsee-types 0.6.1", + "pin-project 1.0.8", + "rustls-native-certs 0.6.1", "serde", "serde_json", "soketto", "thiserror", "tokio", - "tokio-rustls", + "tokio-rustls 0.23.2", "tokio-util", + "tracing", + "webpki-roots 0.22.1", ] [[package]] @@ -4337,7 +4468,7 @@ dependencies = [ "rw-stream-sink", "soketto", "url 2.2.2", - "webpki-roots", + "webpki-roots 0.21.1", ] [[package]] @@ -8417,7 +8548,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#88a003283c6279bec634ba1630e738a8d0fdf8de" dependencies = [ "env_logger 0.9.0", - "jsonrpsee", + "jsonrpsee 0.4.1", "log", "parity-scale-codec", "serde", @@ -8697,8 +8828,20 @@ dependencies = [ "base64", "log", "ring", - "sct", - "webpki", + "sct 0.6.1", + "webpki 0.21.4", +] + +[[package]] +name = "rustls" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +dependencies = [ + "log", + "ring", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] @@ -8708,11 +8851,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ "openssl-probe", - "rustls", + "rustls 0.19.1", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" +dependencies = [ + "openssl-probe", + "rustls-pemfile", "schannel", "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] + [[package]] name = "rustversion" version = "1.0.5" @@ -9370,7 +9534,7 @@ dependencies = [ "futures-timer 3.0.2", "hex", "hyper", - "hyper-rustls", + "hyper-rustls 0.22.1", "num_cpus", "once_cell", "parity-scale-codec", @@ -9770,6 +9934,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -11487,9 +11661,20 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls", + "rustls 0.19.1", "tokio", - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +dependencies = [ + "rustls 0.20.2", + "tokio", + "webpki 0.22.0", ] [[package]] @@ -11606,7 +11791,7 @@ dependencies = [ "chrono", "lazy_static", "matchers", - "parking_lot 0.10.2", + "parking_lot 0.11.2", "regex", "serde", "serde_json", @@ -11695,7 +11880,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#88a003283c6279bec634ba1630e738a8d0fdf8de" dependencies = [ - "jsonrpsee", + "jsonrpsee 0.4.1", "log", "parity-scale-codec", "remote-externalities", @@ -12248,13 +12433,32 @@ dependencies = [ "untrusted", ] +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "webpki-roots" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "webpki", + "webpki 0.21.4", +] + +[[package]] +name = "webpki-roots" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c475786c6f47219345717a043a37ec04cb4bc185e28853adcc4fa0a947eba630" +dependencies = [ + "webpki 0.22.0", ] [[package]] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index 18a4a8c3a07..fe988055024 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -28,8 +28,8 @@ futures = { version = "0.3.1", features = ["compat"] } futures-timer = "3.0.2" tracing = "0.1.22" parking_lot = "0.11.1" -derive_more = "0.99.2" async-trait = "0.1.52" +derive_more = "0.99.2" [dev-dependencies] tokio = { version = "1.10", features = ["macros"] } diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 79e4f7c1b79..216c1415728 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -291,7 +291,7 @@ where async move { // Check if block is equal or higher than best (this requires a justification) - let relay_chain_best_hash = relay_chain_interface.best_block_hash(); + let relay_chain_best_hash = relay_chain_interface.best_block_hash().await; let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); let block_number = header.number(); diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 34584edd69d..8f369d3e06e 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -16,8 +16,7 @@ use super::*; use async_trait::async_trait; -use cumulus_relay_chain_interface::WaitError; -use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; +use cumulus_relay_chain_interface::BlockCheckResult; use cumulus_test_service::runtime::{Block, Hash, Header}; use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt}; use parking_lot::Mutex; @@ -91,7 +90,7 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_backend.blockchain().status(block_id) } - fn best_block_hash(&self) -> PHash { + async fn best_block_hash(&self) -> PHash { self.relay_backend.blockchain().info().best_hash } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 185e9a6f0a3..9587a586fe1 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -48,7 +48,7 @@ pub enum WaitError { BlockchainError(PHash, sp_blockchain::Error), } -/// Trait that provides all necessary methods for interaction between collator and relay chain. +/// Should be used for all interaction with the relay chain in cumulus. #[async_trait] pub trait RelayChainInterface: Send + Sync { /// Fetch a storage item by key. @@ -62,10 +62,9 @@ pub trait RelayChainInterface: Send + Sync { fn validators(&self, block_id: &BlockId) -> Result, ApiError>; /// Get the status of a given block. - fn block_status(&self, block_id: BlockId) -> Result; + async fn block_status(&self, block_id: BlockId) -> Result; - /// Get the hash of the current best block. - fn best_block_hash(&self) -> PHash; + async fn best_block_hash(&self) -> PHash; /// Returns the whole contents of the downward message queue for the parachain we are collating /// for. @@ -210,12 +209,12 @@ where (**self).storage_changes_notification_stream(filter_keys, child_filter_keys) } - fn best_block_hash(&self) -> PHash { - (**self).best_block_hash() + async fn best_block_hash(&self) -> PHash { + (**self).best_block_hash().await } - fn block_status(&self, block_id: BlockId) -> Result { - (**self).block_status(block_id) + async fn block_status(&self, block_id: BlockId) -> Result { + (**self).block_status(block_id).await } fn is_major_syncing(&self) -> bool { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 5177d1f4afb..65010e7a409 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -182,11 +182,11 @@ where .storage_changes_notification_stream(filter_keys, child_filter_keys) } - fn best_block_hash(&self) -> PHash { + async fn best_block_hash(&self) -> PHash { self.backend.blockchain().info().best_hash } - fn block_status(&self, block_id: BlockId) -> Result { + async fn block_status(&self, block_id: BlockId) -> Result { self.backend.blockchain().status(block_id) } diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml new file mode 100644 index 00000000000..52ebd001010 --- /dev/null +++ b/client/relay-chain-network/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["Parity Technologies "] +name = "cumulus-relay-chain-network" +version = "0.1.0" +edition = "2021" + + +[dependencies] +polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } +polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } + +cumulus-primitives-core = { path = "../../primitives/core" } +cumulus-relay-chain-interface = { path = "../relay-chain-interface" } + +sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +futures = { version = "0.3.1", features = ["compat"] } + +parking_lot = "0.11.1" +jsonrpsee = {version = "0.6.1", features = ["client"]} +tracing = "0.1.25" +async-trait = "0.1.52" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs new file mode 100644 index 00000000000..fa0ee2b9599 --- /dev/null +++ b/client/relay-chain-network/src/lib.rs @@ -0,0 +1,300 @@ +// Copyright 2021 Parity Technologies (UK) Ltd. +// This file is part of Cumulus. + +// Cumulus 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. + +// Cumulus 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 Cumulus. If not, see . + +use std::sync::Arc; + +use async_trait::async_trait; +use cumulus_primitives_core::{ + relay_chain::{ + v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, + v2::ParachainHost, + Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + }, + InboundDownwardMessage, ParaId, PersistedValidationData, +}; +use cumulus_relay_chain_interface::RelayChainInterface; + +use jsonrpsee::{ + http_client::{HttpClient, HttpClientBuilder}, + rpc_params, + types::traits::Client, +}; +use parking_lot::Mutex; +use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; +use polkadot_service::{ + AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, +}; +use sc_client_api::{ + blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, StorageProof, UsageProvider, +}; +use sc_telemetry::TelemetryWorkerHandle; +use sp_api::{ApiError, ProvideRuntimeApi}; +use sp_consensus::SyncOracle; +use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; +use sp_runtime::generic::SignedBlock; +use sp_state_machine::{Backend as StateBackend, StorageValue}; +const LOG_TARGET: &str = "relay-chain-local"; + +/// RelayChainNetwork is used to interact with a full node that is running locally +/// in the same process. +pub struct RelayChainNetwork { + full_client: Arc, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, + http_client: HttpClient, +} + +impl RelayChainNetwork { + pub fn new( + full_client: Arc, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, + ) -> Self { + let url = "http://localhost:9933"; + let http_client = HttpClientBuilder::default().build(url).expect("yo"); + Self { full_client, backend, sync_oracle, overseer_handle, http_client } + } +} + +impl Clone for RelayChainNetwork { + fn clone(&self) -> Self { + Self { + http_client: self.http_client.clone(), + full_client: self.full_client.clone(), + backend: self.backend.clone(), + sync_oracle: self.sync_oracle.clone(), + overseer_handle: self.overseer_handle.clone(), + } + } +} + +#[async_trait] +impl RelayChainInterface for RelayChainNetwork +where + Client: ProvideRuntimeApi + + BlockchainEvents + + AuxStore + + UsageProvider + + Sync + + Send, + Client::Api: ParachainHost + BabeApi, +{ + fn retrieve_dmq_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option> { + todo!("retreive_dmq_contents_not_implemented"); + } + + fn retrieve_all_inbound_hrmp_channel_contents( + &self, + para_id: ParaId, + relay_parent: PHash, + ) -> Option>> { + todo!("retrieve_all_inbound_hrmp_channel_contents"); + } + + fn persisted_validation_data( + &self, + block_id: &BlockId, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> Result, ApiError> { + todo!("persisted_validation_data"); + } + + fn candidate_pending_availability( + &self, + block_id: &BlockId, + para_id: ParaId, + ) -> Result, ApiError> { + todo!("candidate_pending_availability"); + } + + fn session_index_for_child(&self, block_id: &BlockId) -> Result { + todo!("session_index_for_child"); + } + + fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + todo!("validators"); + } + + fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { + todo!("import_notification_stream"); + } + + fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { + todo!("finality_notification_stream"); + } + + fn storage_changes_notification_stream( + &self, + filter_keys: Option<&[sc_client_api::StorageKey]>, + child_filter_keys: Option< + &[(sc_client_api::StorageKey, Option>)], + >, + ) -> sc_client_api::blockchain::Result> { + todo!("storage_changes_notification_stream"); + } + + async fn best_block_hash(&self) -> PHash { + let params = rpc_params!(); + let response: Option = + self.http_client.request("chain_getHead", params).await.expect("yo again"); + tracing::info!(target: LOG_TARGET, response = ?response); + response.unwrap() + } + + async fn block_status(&self, block_id: BlockId) -> Result { + let params = rpc_params!(block_id); + let response: Option> = + self.http_client.request("chain_getBlock", params).await.expect("yo again"); + tracing::info!(target: LOG_TARGET, response = ?response); + match response { + Some(_) => Ok(BlockStatus::InChain), + None => Ok(BlockStatus::Unknown), + } + } + + fn is_major_syncing(&self) -> bool { + todo!("major_syncing"); + } + + fn overseer_handle(&self) -> Option { + todo!("overseer_handle"); + } + + fn get_storage_by_key( + &self, + block_id: &BlockId, + key: &[u8], + ) -> Result, sp_blockchain::Error> { + todo!("storage_by_key"); + } + + fn prove_read( + &self, + block_id: &BlockId, + relevant_keys: &Vec>, + ) -> Result, Box> { + todo!("wait_for_block_not_implemented"); + } + + async fn wait_for_block( + &self, + hash: PHash, + ) -> Result<(), cumulus_relay_chain_interface::WaitError> { + todo!("wait_for_block_not_implemented"); + } +} + +/// Builder for a concrete relay chain interface, creatd from a full node. Builds +/// a [`RelayChainNetwork`] to access relay chain data necessary for parachain operation. +/// +/// The builder takes a [`polkadot_client::Client`] +/// that wraps a concrete instance. By using [`polkadot_client::ExecuteWithClient`] +/// the builder gets access to this concrete instance and instantiates a RelayChainNetwork with it. +struct RelayChainNetworkBuilder { + polkadot_client: polkadot_client::Client, + backend: Arc, + sync_oracle: Arc>>, + overseer_handle: Option, +} + +impl RelayChainNetworkBuilder { + pub fn build(self) -> Arc { + self.polkadot_client.clone().execute_with(self) + } +} + +impl ExecuteWithClient for RelayChainNetworkBuilder { + type Output = Arc; + + fn execute_with_client(self, client: Arc) -> Self::Output + where + Client: ProvideRuntimeApi + + BlockchainEvents + + AuxStore + + UsageProvider + + 'static + + Sync + + Send, + Client::Api: ParachainHost + BabeApi, + { + Arc::new(RelayChainNetwork::new( + client, + self.backend, + self.sync_oracle, + self.overseer_handle, + )) + } +} + +/// Build the Polkadot full node using the given `config`. +#[sc_tracing::logging::prefix_logs_with("Relaychain")] +fn build_polkadot_full_node( + config: Configuration, + telemetry_worker_handle: Option, +) -> Result<(NewFull, CollatorPair), polkadot_service::Error> { + let is_light = matches!(config.role, Role::Light); + if is_light { + Err(polkadot_service::Error::Sub("Light client not supported.".into())) + } else { + let collator_key = CollatorPair::generate().0; + + let relay_chain_full_node = polkadot_service::build_full( + config, + polkadot_service::IsCollator::Yes(collator_key.clone()), + None, + true, + None, + telemetry_worker_handle, + polkadot_service::RealOverseerGen, + )?; + + Ok((relay_chain_full_node, collator_key)) + } +} + +/// Builds a relay chain interface by constructing a full relay chain node +pub fn build_relay_chain_network( + polkadot_config: Configuration, + telemetry_worker_handle: Option, + task_manager: &mut TaskManager, +) -> Result<(Arc<(dyn RelayChainInterface + 'static)>, CollatorPair), polkadot_service::Error> { + let (full_node, collator_key) = + build_polkadot_full_node(polkadot_config, telemetry_worker_handle).map_err( + |e| match e { + polkadot_service::Error::Sub(x) => x, + s => format!("{}", s).into(), + }, + )?; + + let sync_oracle: Box = Box::new(full_node.network.clone()); + let sync_oracle = Arc::new(Mutex::new(sync_oracle)); + let relay_chain_interface_builder = RelayChainNetworkBuilder { + polkadot_client: full_node.client.clone(), + backend: full_node.backend.clone(), + sync_oracle, + overseer_handle: full_node.overseer_handle.clone(), + }; + task_manager.add_child(full_node.task_manager); + + Ok((relay_chain_interface_builder.build(), collator_key)) +} diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 02537138848..3ed36b8ec32 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -52,7 +52,7 @@ cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } -cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } +cumulus-relay-chain-network = { path = "../../client/relay-chain-network" } criterion = { version = "0.3.5", features = [ "async_tokio" ] } diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index 5022612d290..d4661500432 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -29,7 +29,7 @@ use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; -use cumulus_relay_chain_local::RelayChainLocal; +use cumulus_relay_chain_network::RelayChainNetwork; use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; use frame_system_rpc_runtime_api::AccountNonceApi; @@ -219,7 +219,8 @@ where let client = params.client.clone(); let backend = params.backend.clone(); - let relay_chain_interface = Arc::new(RelayChainLocal::new( + println!("initializing network;"); + let relay_chain_interface = Arc::new(RelayChainNetwork::new( relay_chain_full_node.client.clone(), relay_chain_full_node.backend.clone(), Arc::new(Mutex::new(Box::new(relay_chain_full_node.network.clone()))), From b23547c7eac3afa4db95cb6b53ca350c61423c5a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 4 Jan 2022 16:07:25 +0100 Subject: [PATCH 02/31] Implement get_storage_by_key --- Cargo.lock | 1 + client/relay-chain-interface/src/lib.rs | 6 ++-- client/relay-chain-local/src/lib.rs | 2 +- client/relay-chain-network/Cargo.toml | 1 + client/relay-chain-network/src/lib.rs | 26 ++++++++++---- parachain-template/node/src/service.rs | 9 ++--- polkadot-parachains/src/service.rs | 34 +++++++++++-------- .../parachain-inherent/src/client_side.rs | 10 +++--- test/service/src/lib.rs | 9 ++--- 9 files changed, 61 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18966f83a90..6509cf1565b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1905,6 +1905,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", + "sp-storage", "tracing", ] diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 9587a586fe1..1a35aa10ea0 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -52,7 +52,7 @@ pub enum WaitError { #[async_trait] pub trait RelayChainInterface: Send + Sync { /// Fetch a storage item by key. - fn get_storage_by_key( + async fn get_storage_by_key( &self, block_id: &BlockId, key: &[u8], @@ -225,12 +225,12 @@ where (**self).overseer_handle() } - fn get_storage_by_key( + async fn get_storage_by_key( &self, block_id: &BlockId, key: &[u8], ) -> Result, sp_blockchain::Error> { - (**self).get_storage_by_key(block_id, key) + (**self).get_storage_by_key(block_id, key).await } fn prove_read( diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 65010e7a409..ac820509d5d 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -199,7 +199,7 @@ where self.overseer_handle.clone() } - fn get_storage_by_key( + async fn get_storage_by_key( &self, block_id: &BlockId, key: &[u8], diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index 52ebd001010..1d8b9b62a7d 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -24,6 +24,7 @@ sc-network = { git = "https://github.com/paritytech/substrate", branch = "master sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } +sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index fa0ee2b9599..093b555d95e 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -38,7 +38,8 @@ use polkadot_service::{ AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, }; use sc_client_api::{ - blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, StorageProof, UsageProvider, + blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, StorageData, StorageProof, + UsageProvider, }; use sc_telemetry::TelemetryWorkerHandle; use sp_api::{ApiError, ProvideRuntimeApi}; @@ -154,15 +155,19 @@ where } async fn best_block_hash(&self) -> PHash { - let params = rpc_params!(); let response: Option = - self.http_client.request("chain_getHead", params).await.expect("yo again"); + self.http_client.request("chain_getHead", None).await.expect("yo again"); tracing::info!(target: LOG_TARGET, response = ?response); response.unwrap() } async fn block_status(&self, block_id: BlockId) -> Result { - let params = rpc_params!(block_id); + let hash = match block_id { + sp_api::BlockId::Hash(hash) => hash, + sp_api::BlockId::Number(_) => todo!(), + }; + + let params = rpc_params!(hash); let response: Option> = self.http_client.request("chain_getBlock", params).await.expect("yo again"); tracing::info!(target: LOG_TARGET, response = ?response); @@ -180,12 +185,21 @@ where todo!("overseer_handle"); } - fn get_storage_by_key( + async fn get_storage_by_key( &self, block_id: &BlockId, key: &[u8], ) -> Result, sp_blockchain::Error> { - todo!("storage_by_key"); + let storage_key = sp_storage::StorageKey(key.to_vec()); + let hash = match block_id { + sp_api::BlockId::Hash(hash) => hash, + sp_api::BlockId::Number(_) => todo!(), + }; + let params = rpc_params!(storage_key, hash); + let response: Option = + self.http_client.request("state_getStorage", params).await.expect("yo again"); + tracing::info!(target: LOG_TARGET, response = ?response); + Ok(response.map(|v| v.0)) } fn prove_read( diff --git a/parachain-template/node/src/service.rs b/parachain-template/node/src/service.rs index 3d87547ded2..951fba0afed 100644 --- a/parachain-template/node/src/service.rs +++ b/parachain-template/node/src/service.rs @@ -432,14 +432,15 @@ pub async fn start_parachain_node( BuildAuraConsensusParams { proposer_factory, create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_interface, + relay_chain_interface.clone(), &validation_data, id, - ); - async move { + ).await; let time = sp_timestamp::InherentDataProvider::from_system_time(); let slot = diff --git a/polkadot-parachains/src/service.rs b/polkadot-parachains/src/service.rs index d248240a5a7..8ce6c1aed4e 100644 --- a/polkadot-parachains/src/service.rs +++ b/polkadot-parachains/src/service.rs @@ -727,14 +727,15 @@ pub async fn start_rococo_parachain_node( >(BuildAuraConsensusParams { proposer_factory, create_inherent_data_providers: move |_, (relay_parent, validation_data)| { + let relay_chain_interface = relay_chain_interface.clone(); + async move { let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_interface, + relay_chain_interface.clone(), &validation_data, id, - ); - async move { + ).await; let time = sp_timestamp::InherentDataProvider::from_system_time(); let slot = @@ -864,14 +865,15 @@ where block_import: client.clone(), relay_chain_interface: relay_chain_interface.clone(), create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_interface, + relay_chain_interface.clone(), &validation_data, id, - ); - async move { + ).await; let parachain_inherent = parachain_inherent.ok_or_else(|| { Box::::from( "Failed to create parachain inherent", @@ -1137,14 +1139,15 @@ where proposer_factory, create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = + let relay_chain_for_aura = relay_chain_for_aura.clone(); + async move { + let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_for_aura, + relay_chain_for_aura.clone(), &validation_data, id, - ); - async move { + ).await; let time = sp_timestamp::InherentDataProvider::from_system_time(); @@ -1196,14 +1199,15 @@ where relay_chain_interface: relay_chain_interface.clone(), create_inherent_data_providers: move |_, (relay_parent, validation_data)| { - let parachain_inherent = + let relay_chain_interface = relay_chain_interface.clone(); + async move { + let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_interface, + relay_chain_interface.clone(), &validation_data, id, - ); - async move { + ).await; let parachain_inherent = parachain_inherent.ok_or_else(|| { Box::::from( diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index dab368dc6cd..c8d64851249 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -29,7 +29,7 @@ const LOG_TARGET: &str = "parachain-inherent"; /// Collect the relevant relay chain state in form of a proof for putting it into the validation /// data inherent. -fn collect_relay_storage_proof( +async fn collect_relay_storage_proof( relay_chain_interface: &impl RelayChainInterface, para_id: ParaId, relay_parent: PHash, @@ -42,6 +42,7 @@ fn collect_relay_storage_proof( &relay_parent_block_id, &relay_well_known_keys::hrmp_ingress_channel_index(para_id), ) + .await .map_err(|e| { tracing::error!( target: LOG_TARGET, @@ -70,6 +71,7 @@ fn collect_relay_storage_proof( &relay_parent_block_id, &relay_well_known_keys::hrmp_egress_channel_index(para_id), ) + .await .map_err(|e| { tracing::error!( target: LOG_TARGET, @@ -115,14 +117,14 @@ impl ParachainInherentData { /// Create the [`ParachainInherentData`] at the given `relay_parent`. /// /// Returns `None` if the creation failed. - pub fn create_at( + pub async fn create_at( relay_parent: PHash, - relay_chain_interface: &impl RelayChainInterface, + relay_chain_interface: impl RelayChainInterface, validation_data: &PersistedValidationData, para_id: ParaId, ) -> Option { let relay_chain_state = - collect_relay_storage_proof(relay_chain_interface, para_id, relay_parent)?; + collect_relay_storage_proof(&relay_chain_interface, para_id, relay_parent).await?; let downward_messages = relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent)?; diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index d4661500432..d357d862c33 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -289,15 +289,16 @@ where para_id, proposer_factory, move |_, (relay_parent, validation_data)| { - let parachain_inherent = + let relay_chain_interface = relay_chain_interface_for_closure.clone(); + async move { + let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - &relay_chain_interface_for_closure, + relay_chain_interface, &validation_data, para_id, - ); + ).await; - async move { let time = sp_timestamp::InherentDataProvider::from_system_time(); let parachain_inherent = parachain_inherent.ok_or_else(|| { From cfaa211a0b275a6acca806b497b83652ff252b9c Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 6 Jan 2022 18:34:15 +0100 Subject: [PATCH 03/31] Implement `validators` and `session_index_for_child` --- Cargo.lock | 1 + client/network/src/lib.rs | 15 +++++---- client/network/src/tests.rs | 23 ++++++++----- client/pov-recovery/src/lib.rs | 44 +++++++++++++------------ client/relay-chain-interface/src/lib.rs | 12 +++---- client/relay-chain-local/src/lib.rs | 4 +-- client/relay-chain-network/Cargo.toml | 1 + client/relay-chain-network/src/lib.rs | 23 ++++++++++--- 8 files changed, 74 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6509cf1565b..9441c47b158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,6 +1890,7 @@ dependencies = [ "cumulus-relay-chain-interface", "futures 0.3.19", "jsonrpsee 0.6.1", + "parity-scale-codec", "parking_lot 0.11.2", "polkadot-client", "polkadot-service", diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 216c1415728..9121f5ae637 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -128,7 +128,7 @@ impl BlockAnnounceData { /// Check the signature of the statement. /// /// Returns an `Err(_)` if it failed. - fn check_signature( + async fn check_signature( self, relay_chain_client: &RCInterface, ) -> Result @@ -138,16 +138,16 @@ impl BlockAnnounceData { let validator_index = self.statement.unchecked_validator_index(); let runtime_api_block_id = BlockId::Hash(self.relay_parent); - let session_index = match relay_chain_client.session_index_for_child(&runtime_api_block_id) - { - Ok(r) => r, - Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))), - }; + let session_index = + match relay_chain_client.session_index_for_child(&runtime_api_block_id).await { + Ok(r) => r, + Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))), + }; let signing_context = SigningContext { parent_hash: self.relay_parent, session_index }; // Check that the signer is a legit validator. - let authorities = match relay_chain_client.validators(&runtime_api_block_id) { + let authorities = match relay_chain_client.validators(&runtime_api_block_id).await { Ok(r) => r, Err(e) => return Err(BlockAnnounceError(format!("{:?}", e))), }; @@ -370,6 +370,7 @@ where block_announce_data .check_signature(&relay_chain_interface) + .await .map_err(|e| Box::new(e) as Box<_>) } .boxed() diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 8f369d3e06e..186287802fd 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -16,7 +16,8 @@ use super::*; use async_trait::async_trait; -use cumulus_relay_chain_interface::BlockCheckResult; +use cumulus_relay_chain_interface::WaitError; +use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt}; use parking_lot::Mutex; @@ -76,14 +77,14 @@ impl DummyRelayChainInterface { #[async_trait] impl RelayChainInterface for DummyRelayChainInterface { - fn validators( + async fn validators( &self, _: &cumulus_primitives_core::relay_chain::BlockId, ) -> Result, sp_api::ApiError> { Ok(self.data.lock().validators.clone()) } - fn block_status( + async fn block_status( &self, block_id: cumulus_primitives_core::relay_chain::BlockId, ) -> Result { @@ -151,7 +152,7 @@ impl RelayChainInterface for DummyRelayChainInterface { } } - fn session_index_for_child( + async fn session_index_for_child( &self, _: &cumulus_primitives_core::relay_chain::BlockId, ) -> Result { @@ -185,7 +186,7 @@ impl RelayChainInterface for DummyRelayChainInterface { unimplemented!("Not needed for test") } - fn get_storage_by_key( + async fn get_storage_by_key( &self, _: &polkadot_service::BlockId, _: &[u8], @@ -273,6 +274,7 @@ async fn make_gossip_message_and_header( .unwrap(); let session_index = relay_chain_interface .session_index_for_child(&BlockId::Hash(relay_parent)) + .await .unwrap(); let signing_context = SigningContext { parent_hash: relay_parent, session_index }; @@ -441,9 +443,9 @@ fn check_statement_is_correctly_signed() { assert_eq!(Validation::Failure { disconnect: true }, res.unwrap()); } -#[test] -fn check_statement_seconded() { - let (mut validator, api) = make_validator_and_api(); +#[tokio::test] +async fn check_statement_seconded() { + let (mut validator, relay_chain_interface) = make_validator_and_api(); let header = default_header(); let relay_parent = H256::from_low_u64_be(1); @@ -454,7 +456,10 @@ fn check_statement_seconded() { Some(&Sr25519Keyring::Alice.to_seed()), ) .unwrap(); - let session_index = api.session_index_for_child(&BlockId::Hash(relay_parent)).unwrap(); + let session_index = relay_chain_interface + .session_index_for_child(&BlockId::Hash(relay_parent)) + .await + .unwrap(); let signing_context = SigningContext { parent_hash: relay_parent, session_index }; let statement = Statement::Valid(Default::default()); diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 7e31f5000d6..76363761dc0 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -363,7 +363,9 @@ where let mut imported_blocks = self.parachain_client.import_notification_stream().fuse(); let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse(); let pending_candidates = - pending_candidates(self.relay_chain_interface.clone(), self.para_id).fuse(); + pending_candidates(self.relay_chain_interface.clone(), self.para_id) + .await + .fuse(); futures::pin_mut!(pending_candidates); loop { @@ -417,28 +419,28 @@ where } /// Returns a stream over pending candidates for the parachain corresponding to `para_id`. -fn pending_candidates( - relay_chain_client: impl RelayChainInterface, +async fn pending_candidates( + relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, ) -> impl Stream { relay_chain_client.import_notification_stream().filter_map(move |n| { - let res = relay_chain_client - .candidate_pending_availability(&BlockId::hash(n.hash), para_id) - .and_then(|pa| { - relay_chain_client - .session_index_for_child(&BlockId::hash(n.hash)) - .map(|v| pa.map(|pa| (pa, v))) - }) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - error = ?e, - "Failed fetch pending candidates.", - ) - }) - .ok() - .flatten(); - - async move { res } + let client_for_closure = relay_chain_client.clone(); + async move { + let pending_availability_result = + client_for_closure.candidate_pending_availability(&BlockId::hash(n.hash), para_id); + let session_index_result = + client_for_closure.session_index_for_child(&BlockId::hash(n.hash)).await; + session_index_result + .map(|v| pending_availability_result.ok().flatten().map(|pa| (pa, v))) + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + error = ?e, + "Failed fetch pending candidates.", + ) + }) + .ok() + .flatten() + } }) } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 1a35aa10ea0..d41911d3355 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -59,7 +59,7 @@ pub trait RelayChainInterface: Send + Sync { ) -> Result, sp_blockchain::Error>; /// Fetch a vector of current validators. - fn validators(&self, block_id: &BlockId) -> Result, ApiError>; + async fn validators(&self, block_id: &BlockId) -> Result, ApiError>; /// Get the status of a given block. async fn block_status(&self, block_id: BlockId) -> Result; @@ -107,7 +107,7 @@ pub trait RelayChainInterface: Send + Sync { ) -> Result, ApiError>; /// Returns the session index expected at a child of the block. - fn session_index_for_child(&self, block_id: &BlockId) -> Result; + async fn session_index_for_child(&self, block_id: &BlockId) -> Result; /// Get a stream of import block notifications. fn import_notification_stream(&self) -> sc_client_api::ImportNotifications; @@ -183,12 +183,12 @@ where (**self).candidate_pending_availability(block_id, para_id) } - fn session_index_for_child(&self, block_id: &BlockId) -> Result { - (**self).session_index_for_child(block_id) + async fn session_index_for_child(&self, block_id: &BlockId) -> Result { + (**self).session_index_for_child(block_id).await } - fn validators(&self, block_id: &BlockId) -> Result, ApiError> { - (**self).validators(block_id) + async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + (**self).validators(block_id).await } fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index ac820509d5d..9ac52b5e740 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -155,11 +155,11 @@ where self.full_client.runtime_api().candidate_pending_availability(block_id, para_id) } - fn session_index_for_child(&self, block_id: &BlockId) -> Result { + async fn session_index_for_child(&self, block_id: &BlockId) -> Result { self.full_client.runtime_api().session_index_for_child(block_id) } - fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { self.full_client.runtime_api().validators(block_id) } diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index 1d8b9b62a7d..b890b83010d 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -27,6 +27,7 @@ sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } futures = { version = "0.3.1", features = ["compat"] } +parity-scale-codec = "2.3.1" parking_lot = "0.11.1" jsonrpsee = {version = "0.6.1", features = ["client"]} tracing = "0.1.25" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 093b555d95e..a58bb0b13f0 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -26,6 +26,7 @@ use cumulus_primitives_core::{ InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::RelayChainInterface; +use parity_scale_codec::{Decode, Encode}; use jsonrpsee::{ http_client::{HttpClient, HttpClientBuilder}, @@ -128,12 +129,26 @@ where todo!("candidate_pending_availability"); } - fn session_index_for_child(&self, block_id: &BlockId) -> Result { - todo!("session_index_for_child"); + async fn session_index_for_child(&self, block_id: &BlockId) -> Result { + let params = rpc_params!("ParachainHost_session_index_for_child", block_id); + let response: Result = + self.http_client.request("state_call", params).await; + let bytes = response.expect("Should not explode"); + + let decoded = SessionIndex::decode(&mut &*bytes.0); + + Ok(decoded.unwrap()) } - fn validators(&self, block_id: &BlockId) -> Result, ApiError> { - todo!("validators"); + async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + let params = rpc_params!("ParachainHost_validators", block_id); + let response: Result = + self.http_client.request("state_call", params).await; + tracing::info!(target: LOG_TARGET, response = ?response); + let bytes = response.expect("Should not explode"); + + let decoded = Vec::::decode(&mut &*bytes.0); + Ok(decoded.unwrap()) } fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { From af362b4d1b44c50131e78c393f55e29ae43dda00 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 7 Jan 2022 16:19:05 +0100 Subject: [PATCH 04/31] Implement persisted_validation_data and candidate_pending_availability --- client/consensus/common/Cargo.toml | 2 +- .../common/src/parachain_consensus.rs | 48 +++++++++----- client/consensus/common/src/tests.rs | 7 ++- client/network/src/lib.rs | 17 +++-- client/network/src/tests.rs | 4 +- client/pov-recovery/src/lib.rs | 5 +- client/relay-chain-interface/src/lib.rs | 14 +++-- client/relay-chain-local/src/lib.rs | 4 +- client/relay-chain-network/src/lib.rs | 63 +++++++++++++++---- 9 files changed, 115 insertions(+), 49 deletions(-) diff --git a/client/consensus/common/Cargo.toml b/client/consensus/common/Cargo.toml index 057f0b34966..379f73740f2 100644 --- a/client/consensus/common/Cargo.toml +++ b/client/consensus/common/Cargo.toml @@ -25,7 +25,7 @@ cumulus-relay-chain-interface = { path = "../../relay-chain-interface" } futures = { version = "0.3.8", features = ["compat"] } codec = { package = "parity-scale-codec", version = "2.3.0", features = [ "derive" ] } tracing = "0.1.25" -async-trait = "0.1.42" +async-trait = "0.1.52" dyn-clone = "1.0.4" [dev-dependencies] diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 224e3e5fd9b..96f7bcbb4bb 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use async_trait::async_trait; use cumulus_relay_chain_interface::RelayChainInterface; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, @@ -34,6 +35,7 @@ use futures::{future, select, FutureExt, Stream, StreamExt}; use std::{pin::Pin, sync::Arc}; /// Helper for the relay chain client. This is expected to be a lightweight handle like an `Arc`. +#[async_trait] pub trait RelaychainClient: Clone + 'static { /// The error type for interacting with the Polkadot client. type Error: std::fmt::Debug + Send; @@ -42,13 +44,13 @@ pub trait RelaychainClient: Clone + 'static { type HeadStream: Stream> + Send + Unpin; /// Get a stream of new best heads for the given parachain. - fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream; + async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream; /// Get a stream of finalized heads for the given parachain. - fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream; + async fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream; /// Returns the parachain head for the given `para_id` at the given block id. - fn parachain_head_at( + async fn parachain_head_at( &self, at: &BlockId, para_id: ParaId, @@ -66,7 +68,7 @@ where R: RelaychainClient, B: Backend, { - let mut finalized_heads = relay_chain.finalized_heads(para_id); + let mut finalized_heads = relay_chain.finalized_heads(para_id).await; loop { let finalized_head = if let Some(h) = finalized_heads.next().await { @@ -165,7 +167,7 @@ async fn follow_new_best( R: RelaychainClient, B: Backend, { - let mut new_best_heads = relay_chain.new_best_heads(para_id).fuse(); + let mut new_best_heads = relay_chain.new_best_heads(para_id).await.fuse(); let mut imported_blocks = parachain.import_notification_stream().fuse(); // The unset best header of the parachain. Will be `Some(_)` when we have imported a relay chain // block before the parachain block it included. In this case we need to wait for this block to @@ -368,6 +370,7 @@ where } } +#[async_trait] impl RelaychainClient for RCInterface where RCInterface: RelayChainInterface + Clone + 'static, @@ -376,38 +379,51 @@ where type HeadStream = Pin> + Send>>; - fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream { + async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream { let relay_chain = self.clone(); self.import_notification_stream() .filter_map(move |n| { - future::ready(if n.is_new_best { - relay_chain.parachain_head_at(&BlockId::hash(n.hash), para_id).ok().flatten() - } else { - None - }) + let relay_chain = relay_chain.clone(); + async move { + if n.is_new_best { + relay_chain + .parachain_head_at(&BlockId::hash(n.hash), para_id) + .await + .ok() + .flatten() + } else { + None + } + } }) .boxed() } - fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream { + async fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream { let relay_chain = self.clone(); self.finality_notification_stream() .filter_map(move |n| { - future::ready( - relay_chain.parachain_head_at(&BlockId::hash(n.hash), para_id).ok().flatten(), - ) + let relay_chain = relay_chain.clone(); + async move { + relay_chain + .parachain_head_at(&BlockId::hash(n.hash), para_id) + .await + .ok() + .flatten() + } }) .boxed() } - fn parachain_head_at( + async fn parachain_head_at( &self, at: &BlockId, para_id: ParaId, ) -> ClientResult>> { self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut) + .await .map(|s| s.map(|s| s.parent_head.0)) .map_err(Into::into) } diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index 4340b7b681e..d529cdcbd4b 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -66,6 +66,7 @@ impl Relaychain { } } +#[async_trait] impl crate::parachain_consensus::RelaychainClient for Relaychain { type Error = ClientError; @@ -95,7 +96,11 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { Box::new(stream.map(|v| v.encode())) } - fn parachain_head_at(&self, _: &BlockId, _: ParaId) -> ClientResult>> { + async fn parachain_head_at( + &self, + _: &BlockId, + _: ParaId, + ) -> ClientResult>> { unimplemented!("Not required for tests") } } diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 9121f5ae637..5bf66bcb8f3 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -247,13 +247,14 @@ where RCInterface: RelayChainInterface + Clone, { /// Get the included block of the given parachain in the relay chain. - fn included_block( + async fn included_block( relay_chain_interface: &RCInterface, block_id: &BlockId, para_id: ParaId, ) -> Result { let validation_data = relay_chain_interface .persisted_validation_data(block_id, para_id, OccupiedCoreAssumption::TimedOut) + .await .map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)? .ok_or_else(|| { Box::new(BlockAnnounceError("Could not find parachain head in relay chain".into())) @@ -269,13 +270,14 @@ where } /// Get the backed block hash of the given parachain in the relay chain. - fn backed_block_hash( + async fn backed_block_hash( relay_chain_interface: &RCInterface, block_id: &BlockId, para_id: ParaId, ) -> Result, BoxedError> { let candidate_receipt = relay_chain_interface .candidate_pending_availability(block_id, para_id) + .await .map_err(|e| Box::new(BlockAnnounceError(format!("{:?}", e))) as Box<_>)?; Ok(candidate_receipt.map(|cr| cr.descriptor.para_head)) @@ -296,16 +298,19 @@ where let block_number = header.number(); let best_head = - Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id)?; + Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id) + .await?; let known_best_number = best_head.number(); - let backed_block = - || Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id); + let backed_block = || async { + Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id) + .await + }; if best_head == header { tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",); Ok(Validation::Success { is_new_best: true }) - } else if Some(HeadData(header.encode()).hash()) == backed_block()? { + } else if Some(HeadData(header.encode()).hash()) == backed_block().await? { tracing::debug!(target: LOG_TARGET, "Announced block matches latest backed block.",); Ok(Validation::Success { is_new_best: true }) diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 186287802fd..b92af6779cb 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -107,7 +107,7 @@ impl RelayChainInterface for DummyRelayChainInterface { Some(BTreeMap::new()) } - fn persisted_validation_data( + async fn persisted_validation_data( &self, _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, @@ -119,7 +119,7 @@ impl RelayChainInterface for DummyRelayChainInterface { })) } - fn candidate_pending_availability( + async fn candidate_pending_availability( &self, _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 76363761dc0..5bb7baeb8ed 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -426,8 +426,9 @@ async fn pending_candidates( relay_chain_client.import_notification_stream().filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); async move { - let pending_availability_result = - client_for_closure.candidate_pending_availability(&BlockId::hash(n.hash), para_id); + let pending_availability_result = client_for_closure + .candidate_pending_availability(&BlockId::hash(n.hash), para_id) + .await; let session_index_result = client_for_closure.session_index_for_child(&BlockId::hash(n.hash)).await; session_index_result diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index d41911d3355..9593a222f5a 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -91,7 +91,7 @@ pub trait RelayChainInterface: Send + Sync { /// /// Returns `None` if either the para is not registered or the assumption is `Freed` /// and the para already occupies a core. - fn persisted_validation_data( + async fn persisted_validation_data( &self, block_id: &BlockId, para_id: ParaId, @@ -100,7 +100,7 @@ pub trait RelayChainInterface: Send + Sync { /// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. - fn candidate_pending_availability( + async fn candidate_pending_availability( &self, block_id: &BlockId, para_id: ParaId, @@ -166,21 +166,23 @@ where (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) } - fn persisted_validation_data( + async fn persisted_validation_data( &self, block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, ) -> Result, ApiError> { - (**self).persisted_validation_data(block_id, para_id, occupied_core_assumption) + (**self) + .persisted_validation_data(block_id, para_id, occupied_core_assumption) + .await } - fn candidate_pending_availability( + async fn candidate_pending_availability( &self, block_id: &BlockId, para_id: ParaId, ) -> Result, ApiError> { - (**self).candidate_pending_availability(block_id, para_id) + (**self).candidate_pending_availability(block_id, para_id).await } async fn session_index_for_child(&self, block_id: &BlockId) -> Result { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 9ac52b5e740..cc476d0ca9c 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -134,7 +134,7 @@ where .ok() } - fn persisted_validation_data( + async fn persisted_validation_data( &self, block_id: &BlockId, para_id: ParaId, @@ -147,7 +147,7 @@ where ) } - fn candidate_pending_availability( + async fn candidate_pending_availability( &self, block_id: &BlockId, para_id: ParaId, diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index a58bb0b13f0..705787507c1 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -85,6 +85,25 @@ impl Clone for RelayChainNetwork { } } +impl RelayChainNetwork { + async fn call_remote_runtime_function( + &self, + method_name: &str, + block_id: &BlockId, + payload: Option>, + ) -> sp_core::Bytes { + let payload_bytes = + payload.map_or(sp_core::Bytes(Vec::new()), |pl| sp_core::Bytes(pl.encode().to_vec())); + let params = rpc_params! { + method_name, + payload_bytes, + block_id + }; + let response: Result = + self.http_client.request("state_call", params).await; + response.expect("Should not explode") + } +} #[async_trait] impl RelayChainInterface for RelayChainNetwork where @@ -112,28 +131,47 @@ where todo!("retrieve_all_inbound_hrmp_channel_contents"); } - fn persisted_validation_data( + async fn persisted_validation_data( &self, block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, ) -> Result, ApiError> { - todo!("persisted_validation_data"); + let bytes = self + .call_remote_runtime_function( + "ParachainHost_candidate_pending_availability", + block_id, + Some(para_id.encode()), + ) + .await; + + let decoded = Option::::decode(&mut &*bytes.0); + + Ok(decoded.unwrap()) } - fn candidate_pending_availability( + async fn candidate_pending_availability( &self, block_id: &BlockId, para_id: ParaId, ) -> Result, ApiError> { - todo!("candidate_pending_availability"); + let bytes = self + .call_remote_runtime_function( + "ParachainHost_candidate_pending_availability", + block_id, + Some(para_id.encode()), + ) + .await; + + let decoded = Option::>::decode(&mut &*bytes.0); + + Ok(decoded.unwrap()) } async fn session_index_for_child(&self, block_id: &BlockId) -> Result { - let params = rpc_params!("ParachainHost_session_index_for_child", block_id); - let response: Result = - self.http_client.request("state_call", params).await; - let bytes = response.expect("Should not explode"); + let bytes = self + .call_remote_runtime_function("ParachainHost_session_index_for_child", block_id, None) + .await; let decoded = SessionIndex::decode(&mut &*bytes.0); @@ -141,13 +179,12 @@ where } async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { - let params = rpc_params!("ParachainHost_validators", block_id); - let response: Result = - self.http_client.request("state_call", params).await; - tracing::info!(target: LOG_TARGET, response = ?response); - let bytes = response.expect("Should not explode"); + let bytes = self + .call_remote_runtime_function("ParachainHost_validators", block_id, None) + .await; let decoded = Vec::::decode(&mut &*bytes.0); + Ok(decoded.unwrap()) } From a8d80d5d3d317ffa0d7070e36b983d38ed46dc53 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Fri, 7 Jan 2022 16:36:28 +0100 Subject: [PATCH 05/31] Fix method name for persisted_validation_data and add encoded params --- client/relay-chain-network/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 705787507c1..dd16cd8a562 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -139,9 +139,9 @@ where ) -> Result, ApiError> { let bytes = self .call_remote_runtime_function( - "ParachainHost_candidate_pending_availability", + "ParachainHost_persisted_validation_data", block_id, - Some(para_id.encode()), + Some((para_id, occupied_core_assumption).encode()), ) .await; From 482ecd4e068a4d3cc5e00525a961560da9a807c7 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 10 Jan 2022 10:27:38 +0100 Subject: [PATCH 06/31] Implement `retrieve_dmq_contents` and `retrieve_all_inbound_hrmp_channel_contents` --- client/network/src/tests.rs | 4 +-- client/relay-chain-interface/src/lib.rs | 12 ++++---- client/relay-chain-local/src/lib.rs | 4 +-- client/relay-chain-network/src/lib.rs | 30 ++++++++++++++++--- .../parachain-inherent/src/client_side.rs | 5 ++-- 5 files changed, 39 insertions(+), 16 deletions(-) diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index b92af6779cb..098099c844f 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -95,11 +95,11 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_backend.blockchain().info().best_hash } - fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option> { + async fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option> { unimplemented!("Not needed for test") } - fn retrieve_all_inbound_hrmp_channel_contents( + async fn retrieve_all_inbound_hrmp_channel_contents( &self, _: ParaId, _: PHash, diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 9593a222f5a..107ce1e3ede 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -70,7 +70,7 @@ pub trait RelayChainInterface: Send + Sync { /// for. /// /// Returns `None` in case of an error. - fn retrieve_dmq_contents( + async fn retrieve_dmq_contents( &self, para_id: ParaId, relay_parent: PHash, @@ -80,7 +80,7 @@ pub trait RelayChainInterface: Send + Sync { /// collating for. /// /// Empty channels are also included. - fn retrieve_all_inbound_hrmp_channel_contents( + async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, @@ -150,20 +150,20 @@ impl RelayChainInterface for Arc where T: RelayChainInterface + ?Sized, { - fn retrieve_dmq_contents( + async fn retrieve_dmq_contents( &self, para_id: ParaId, relay_parent: PHash, ) -> Option> { - (**self).retrieve_dmq_contents(para_id, relay_parent) + (**self).retrieve_dmq_contents(para_id, relay_parent).await } - fn retrieve_all_inbound_hrmp_channel_contents( + async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, ) -> Option>> { - (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) + (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await } async fn persisted_validation_data( diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index cc476d0ca9c..e3a0aad71ff 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -88,7 +88,7 @@ where + Send, Client::Api: ParachainHost + BabeApi, { - fn retrieve_dmq_contents( + async fn retrieve_dmq_contents( &self, para_id: ParaId, relay_parent: PHash, @@ -111,7 +111,7 @@ where .ok() } - fn retrieve_all_inbound_hrmp_channel_contents( + async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index dd16cd8a562..90540a8f473 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -115,20 +115,42 @@ where + Send, Client::Api: ParachainHost + BabeApi, { - fn retrieve_dmq_contents( + async fn retrieve_dmq_contents( &self, para_id: ParaId, relay_parent: PHash, ) -> Option> { - todo!("retreive_dmq_contents_not_implemented"); + let block_id = BlockId::hash(relay_parent); + let bytes = self + .call_remote_runtime_function( + "ParachainHost_dmq_contents", + &block_id, + Some(para_id.encode()), + ) + .await; + + let decoded = Option::>::decode(&mut &*bytes.0); + + decoded.unwrap() } - fn retrieve_all_inbound_hrmp_channel_contents( + async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, ) -> Option>> { - todo!("retrieve_all_inbound_hrmp_channel_contents"); + let block_id = BlockId::hash(relay_parent); + let bytes = self + .call_remote_runtime_function( + "ParachainHost_inbound_hrmp_channels_contents", + &block_id, + Some(para_id.encode()), + ) + .await; + + let decoded = Option::>>::decode(&mut &*bytes.0); + + decoded.unwrap() } async fn persisted_validation_data( diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index c8d64851249..23709e90a46 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -127,9 +127,10 @@ impl ParachainInherentData { collect_relay_storage_proof(&relay_chain_interface, para_id, relay_parent).await?; let downward_messages = - relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent)?; + relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent).await?; let horizontal_messages = relay_chain_interface - .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent)?; + .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) + .await?; Some(ParachainInherentData { downward_messages, From c03ba54e79f0c85adfe58e5898b70fd70a75676b Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 10 Jan 2022 14:51:41 +0100 Subject: [PATCH 07/31] Implement `prove_read` --- Cargo.lock | 1 + client/network/src/tests.rs | 2 +- client/relay-chain-interface/src/lib.rs | 6 ++--- client/relay-chain-local/src/lib.rs | 2 +- client/relay-chain-network/Cargo.toml | 1 + client/relay-chain-network/src/lib.rs | 25 ++++++++++++++++--- .../parachain-inherent/src/client_side.rs | 5 +++- 7 files changed, 33 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9441c47b158..43041e09b2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1897,6 +1897,7 @@ dependencies = [ "sc-client-api", "sc-consensus-babe", "sc-network", + "sc-rpc-api", "sc-service", "sc-telemetry", "sc-tracing", diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 098099c844f..4f9ce2feece 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -194,7 +194,7 @@ impl RelayChainInterface for DummyRelayChainInterface { unimplemented!("Not needed for test") } - fn prove_read( + async fn prove_read( &self, _: &polkadot_service::BlockId, _: &Vec>, diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 107ce1e3ede..e762986453c 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -138,7 +138,7 @@ pub trait RelayChainInterface: Send + Sync { fn overseer_handle(&self) -> Option; /// Generate a storage read proof. - fn prove_read( + async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, @@ -235,12 +235,12 @@ where (**self).get_storage_by_key(block_id, key).await } - fn prove_read( + async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, ) -> Result, Box> { - (**self).prove_read(block_id, relevant_keys) + (**self).prove_read(block_id, relevant_keys).await } async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index e3a0aad71ff..0f5c430ac3c 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -208,7 +208,7 @@ where state.storage(key).map_err(sp_blockchain::Error::Storage) } - fn prove_read( + async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index b890b83010d..83948140b43 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -25,6 +25,7 @@ sc-service = { git = "https://github.com/paritytech/substrate", branch = "master sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } futures = { version = "0.3.1", features = ["compat"] } parity-scale-codec = "2.3.1" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 90540a8f473..fe4ffe72b63 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -42,12 +42,14 @@ use sc_client_api::{ blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, StorageData, StorageProof, UsageProvider, }; +use sc_rpc_api::state::ReadProof; use sc_telemetry::TelemetryWorkerHandle; use sp_api::{ApiError, ProvideRuntimeApi}; use sp_consensus::SyncOracle; use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; use sp_runtime::generic::SignedBlock; use sp_state_machine::{Backend as StateBackend, StorageValue}; +use sp_storage::StorageKey; const LOG_TARGET: &str = "relay-chain-local"; /// RelayChainNetwork is used to interact with a full node that is running locally @@ -264,7 +266,7 @@ where block_id: &BlockId, key: &[u8], ) -> Result, sp_blockchain::Error> { - let storage_key = sp_storage::StorageKey(key.to_vec()); + let storage_key = StorageKey(key.to_vec()); let hash = match block_id { sp_api::BlockId::Hash(hash) => hash, sp_api::BlockId::Number(_) => todo!(), @@ -276,12 +278,29 @@ where Ok(response.map(|v| v.0)) } - fn prove_read( + async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, ) -> Result, Box> { - todo!("wait_for_block_not_implemented"); + let cloned = relevant_keys.clone(); + let storage_keys: Vec = cloned.into_iter().map(StorageKey).collect(); + + let hash = match block_id { + sp_api::BlockId::Hash(hash) => hash, + sp_api::BlockId::Number(_) => todo!(), + }; + + let params = rpc_params!(storage_keys, hash); + let response: Option> = + self.http_client.request("state_getReadProof", params).await.expect("yo again"); + + Ok(response.map(|read_proof| { + let bytes: Vec> = + read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); + + StorageProof::new(bytes.to_vec()) + })) } async fn wait_for_block( diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index 23709e90a46..baebeaeef12 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -110,7 +110,10 @@ async fn collect_relay_storage_proof( relay_well_known_keys::hrmp_channels(HrmpChannelId { sender: para_id, recipient }) })); - relay_chain_interface.prove_read(&relay_parent_block_id, &relevant_keys).ok()? + relay_chain_interface + .prove_read(&relay_parent_block_id, &relevant_keys) + .await + .ok()? } impl ParachainInherentData { From b4ca285d3d86695b1bc6f6b44d97132d813d9d62 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 10 Jan 2022 19:51:04 +0100 Subject: [PATCH 08/31] Introduce separate RPC client, expose JsonRpSee errors --- Cargo.lock | 2 + .../common/src/parachain_consensus.rs | 2 +- client/relay-chain-network/Cargo.toml | 1 + client/relay-chain-network/src/lib.rs | 415 ++++++++---------- test/service/Cargo.toml | 2 + test/service/src/lib.rs | 10 +- 6 files changed, 195 insertions(+), 237 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43041e09b2a..36761ff6184 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1909,6 +1909,7 @@ dependencies = [ "sp-state-machine", "sp-storage", "tracing", + "url 2.2.2", ] [[package]] @@ -2045,6 +2046,7 @@ dependencies = [ "substrate-test-client", "substrate-test-utils", "tokio", + "url 2.2.2", ] [[package]] diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 96f7bcbb4bb..339f13ce06c 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -30,7 +30,7 @@ use sp_runtime::{ use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption}; use codec::Decode; -use futures::{future, select, FutureExt, Stream, StreamExt}; +use futures::{select, FutureExt, Stream, StreamExt}; use std::{pin::Pin, sync::Arc}; diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index 83948140b43..df93677a776 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -33,3 +33,4 @@ parking_lot = "0.11.1" jsonrpsee = {version = "0.6.1", features = ["client"]} tracing = "0.1.25" async-trait = "0.1.52" +url = "2.2.2" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index fe4ffe72b63..f3dc6ed0b01 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -14,13 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::sync::Arc; - use async_trait::async_trait; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, - v2::ParachainHost, Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, }, InboundDownwardMessage, ParaId, PersistedValidationData, @@ -31,69 +28,33 @@ use parity_scale_codec::{Decode, Encode}; use jsonrpsee::{ http_client::{HttpClient, HttpClientBuilder}, rpc_params, - types::traits::Client, -}; -use parking_lot::Mutex; -use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; -use polkadot_service::{ - AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, -}; -use sc_client_api::{ - blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, StorageData, StorageProof, - UsageProvider, + types::{error::Error as JsonRPSeeError, traits::Client, v2::ParamsSer}, }; +use polkadot_service::Handle; +use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; use sc_rpc_api::state::ReadProof; -use sc_telemetry::TelemetryWorkerHandle; -use sp_api::{ApiError, ProvideRuntimeApi}; -use sp_consensus::SyncOracle; -use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; -use sp_runtime::generic::SignedBlock; -use sp_state_machine::{Backend as StateBackend, StorageValue}; +use sp_api::ApiError; +use sp_core::sp_std::collections::btree_map::BTreeMap; +use sp_runtime::{generic::SignedBlock, DeserializeOwned}; +use sp_state_machine::StorageValue; use sp_storage::StorageKey; -const LOG_TARGET: &str = "relay-chain-local"; -/// RelayChainNetwork is used to interact with a full node that is running locally -/// in the same process. -pub struct RelayChainNetwork { - full_client: Arc, - backend: Arc, - sync_oracle: Arc>>, - overseer_handle: Option, - http_client: HttpClient, -} +pub use url::Url; -impl RelayChainNetwork { - pub fn new( - full_client: Arc, - backend: Arc, - sync_oracle: Arc>>, - overseer_handle: Option, - ) -> Self { - let url = "http://localhost:9933"; - let http_client = HttpClientBuilder::default().build(url).expect("yo"); - Self { full_client, backend, sync_oracle, overseer_handle, http_client } - } -} +const LOG_TARGET: &str = "relay_chain_network"; -impl Clone for RelayChainNetwork { - fn clone(&self) -> Self { - Self { - http_client: self.http_client.clone(), - full_client: self.full_client.clone(), - backend: self.backend.clone(), - sync_oracle: self.sync_oracle.clone(), - overseer_handle: self.overseer_handle.clone(), - } - } +#[derive(Clone)] +struct RelayChainRPCClient { + http_client: HttpClient, } -impl RelayChainNetwork { +impl RelayChainRPCClient { async fn call_remote_runtime_function( &self, method_name: &str, block_id: &BlockId, payload: Option>, - ) -> sp_core::Bytes { + ) -> Result { let payload_bytes = payload.map_or(sp_core::Bytes(Vec::new()), |pl| sp_core::Bytes(pl.encode().to_vec())); let params = rpc_params! { @@ -101,39 +62,164 @@ impl RelayChainNetwork { payload_bytes, block_id }; - let response: Result = - self.http_client.request("state_call", params).await; - response.expect("Should not explode") + self.request("state_call", params).await + } + + async fn request<'a, R>( + &self, + method: &'a str, + params: Option>, + ) -> Result + where + R: DeserializeOwned, + { + tracing::trace!(target: LOG_TARGET, method = ?method); + self.http_client.request(method, params).await + } + + async fn state_get_read_proof( + &self, + storage_keys: Vec, + at: Option, + ) -> Result>, JsonRPSeeError> { + let params = rpc_params!(storage_keys, at); + self.request("state_getReadProof", params).await + } + + async fn state_get_storage( + &self, + storage_key: StorageKey, + at: Option, + ) -> Result, JsonRPSeeError> { + let params = rpc_params!(storage_key, at); + self.request("state_getStorage", params).await + } + + async fn chain_get_block( + &self, + at: Option, + ) -> Result>, JsonRPSeeError> { + let params = rpc_params!(at); + self.request("chain_getBlock", params).await + } + + async fn chain_get_head(&self) -> Result { + self.request("chain_getHead", None).await + } + + async fn parachain_host_candidate_pending_availability( + &self, + at: &BlockId, + para_id: ParaId, + ) -> Result, JsonRPSeeError> { + let response_bytes = self + .call_remote_runtime_function( + "ParachainHost_candidate_pending_availability", + at, + Some(para_id.encode()), + ) + .await?; + + Ok(Option::>::decode(&mut &*response_bytes.0) + .expect("should deserialize")) + } + + async fn parachain_host_session_index_for_child( + &self, + at: &BlockId, + ) -> Result { + let response_bytes = self + .call_remote_runtime_function("ParachainHost_session_index_for_child", at, None) + .await?; + + Ok(SessionIndex::decode(&mut &*response_bytes.0).expect("should deserialize")) + } + + async fn parachain_host_validators( + &self, + at: &BlockId, + ) -> Result, JsonRPSeeError> { + let response_bytes = + self.call_remote_runtime_function("ParachainHost_validators", at, None).await?; + + Ok(Vec::::decode(&mut &*response_bytes.0).expect("should deserialize")) + } + + async fn parachain_host_persisted_validation_data( + &self, + block_id: &BlockId, + para_id: ParaId, + occupied_core_assumption: OccupiedCoreAssumption, + ) -> Result, JsonRPSeeError> { + let response_bytes = self + .call_remote_runtime_function( + "ParachainHost_persisted_validation_data", + block_id, + Some((para_id, occupied_core_assumption).encode()), + ) + .await?; + + Ok(Option::::decode(&mut &*response_bytes.0) + .expect("should deserialize")) + } + + async fn parachain_host_inbound_hrmp_channels_contents( + &self, + para_id: ParaId, + at: &BlockId, + ) -> Result>>, JsonRPSeeError> { + let response_bytes = self + .call_remote_runtime_function( + "ParachainHost_inbound_hrmp_channels_contents", + &at, + Some(para_id.encode()), + ) + .await?; + + Ok(Option::>>::decode(&mut &*response_bytes.0) + .expect("should deserialize")) + } + + async fn parachain_host_dmq_contents( + &self, + para_id: ParaId, + at: &BlockId, + ) -> Result>, JsonRPSeeError> { + let response_bytes = self + .call_remote_runtime_function("ParachainHost_dmq_contents", &at, Some(para_id.encode())) + .await?; + + Ok(Option::>::decode(&mut &*response_bytes.0) + .expect("should deserialize")) } } + +/// RelayChainNetwork is used to interact with a full node that is running locally +/// in the same process. +#[derive(Clone)] +pub struct RelayChainNetwork { + rpc_client: RelayChainRPCClient, +} + +impl RelayChainNetwork { + pub fn new(url: Url) -> Self { + let http_client = HttpClientBuilder::default().build(url.as_str()).expect("yo"); + + Self { rpc_client: RelayChainRPCClient { http_client } } + } +} + #[async_trait] -impl RelayChainInterface for RelayChainNetwork -where - Client: ProvideRuntimeApi - + BlockchainEvents - + AuxStore - + UsageProvider - + Sync - + Send, - Client::Api: ParachainHost + BabeApi, -{ +impl RelayChainInterface for RelayChainNetwork { async fn retrieve_dmq_contents( &self, para_id: ParaId, relay_parent: PHash, ) -> Option> { let block_id = BlockId::hash(relay_parent); - let bytes = self - .call_remote_runtime_function( - "ParachainHost_dmq_contents", - &block_id, - Some(para_id.encode()), - ) - .await; + let response = self.rpc_client.parachain_host_dmq_contents(para_id, &block_id).await; - let decoded = Option::>::decode(&mut &*bytes.0); - - decoded.unwrap() + response.expect("nope") } async fn retrieve_all_inbound_hrmp_channel_contents( @@ -142,17 +228,12 @@ where relay_parent: PHash, ) -> Option>> { let block_id = BlockId::hash(relay_parent); - let bytes = self - .call_remote_runtime_function( - "ParachainHost_inbound_hrmp_channels_contents", - &block_id, - Some(para_id.encode()), - ) + let response = self + .rpc_client + .parachain_host_inbound_hrmp_channels_contents(para_id, &block_id) .await; - let decoded = Option::>>::decode(&mut &*bytes.0); - - decoded.unwrap() + response.expect("nope") } async fn persisted_validation_data( @@ -161,17 +242,12 @@ where para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, ) -> Result, ApiError> { - let bytes = self - .call_remote_runtime_function( - "ParachainHost_persisted_validation_data", - block_id, - Some((para_id, occupied_core_assumption).encode()), - ) + let response = self + .rpc_client + .parachain_host_persisted_validation_data(block_id, para_id, occupied_core_assumption) .await; - let decoded = Option::::decode(&mut &*bytes.0); - - Ok(decoded.unwrap()) + Ok(response.expect("nope")) } async fn candidate_pending_availability( @@ -179,37 +255,24 @@ where block_id: &BlockId, para_id: ParaId, ) -> Result, ApiError> { - let bytes = self - .call_remote_runtime_function( - "ParachainHost_candidate_pending_availability", - block_id, - Some(para_id.encode()), - ) + let response = self + .rpc_client + .parachain_host_candidate_pending_availability(block_id, para_id) .await; - let decoded = Option::>::decode(&mut &*bytes.0); - - Ok(decoded.unwrap()) + Ok(response.expect("nope")) } async fn session_index_for_child(&self, block_id: &BlockId) -> Result { - let bytes = self - .call_remote_runtime_function("ParachainHost_session_index_for_child", block_id, None) - .await; + let response = self.rpc_client.parachain_host_session_index_for_child(block_id).await; - let decoded = SessionIndex::decode(&mut &*bytes.0); - - Ok(decoded.unwrap()) + Ok(response.expect("nope")) } async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { - let bytes = self - .call_remote_runtime_function("ParachainHost_validators", block_id, None) - .await; + let response = self.rpc_client.parachain_host_validators(block_id).await; - let decoded = Vec::::decode(&mut &*bytes.0); - - Ok(decoded.unwrap()) + Ok(response.expect("nope")) } fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { @@ -231,10 +294,8 @@ where } async fn best_block_hash(&self) -> PHash { - let response: Option = - self.http_client.request("chain_getHead", None).await.expect("yo again"); - tracing::info!(target: LOG_TARGET, response = ?response); - response.unwrap() + let response = self.rpc_client.chain_get_head().await; + response.expect("nope") } async fn block_status(&self, block_id: BlockId) -> Result { @@ -243,11 +304,8 @@ where sp_api::BlockId::Number(_) => todo!(), }; - let params = rpc_params!(hash); - let response: Option> = - self.http_client.request("chain_getBlock", params).await.expect("yo again"); - tracing::info!(target: LOG_TARGET, response = ?response); - match response { + let response = self.rpc_client.chain_get_block(Some(hash.clone())).await; + match response.expect("nope") { Some(_) => Ok(BlockStatus::InChain), None => Ok(BlockStatus::Unknown), } @@ -271,11 +329,9 @@ where sp_api::BlockId::Hash(hash) => hash, sp_api::BlockId::Number(_) => todo!(), }; - let params = rpc_params!(storage_key, hash); - let response: Option = - self.http_client.request("state_getStorage", params).await.expect("yo again"); - tracing::info!(target: LOG_TARGET, response = ?response); - Ok(response.map(|v| v.0)) + + let response = self.rpc_client.state_get_storage(storage_key, Some(*hash)).await; + Ok(response.expect("nope").map(|v| v.0)) } async fn prove_read( @@ -291,11 +347,9 @@ where sp_api::BlockId::Number(_) => todo!(), }; - let params = rpc_params!(storage_keys, hash); - let response: Option> = - self.http_client.request("state_getReadProof", params).await.expect("yo again"); + let result = self.rpc_client.state_get_read_proof(storage_keys, Some(*hash)).await; - Ok(response.map(|read_proof| { + Ok(result.expect("nope").map(|read_proof| { let bytes: Vec> = read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); @@ -310,98 +364,3 @@ where todo!("wait_for_block_not_implemented"); } } - -/// Builder for a concrete relay chain interface, creatd from a full node. Builds -/// a [`RelayChainNetwork`] to access relay chain data necessary for parachain operation. -/// -/// The builder takes a [`polkadot_client::Client`] -/// that wraps a concrete instance. By using [`polkadot_client::ExecuteWithClient`] -/// the builder gets access to this concrete instance and instantiates a RelayChainNetwork with it. -struct RelayChainNetworkBuilder { - polkadot_client: polkadot_client::Client, - backend: Arc, - sync_oracle: Arc>>, - overseer_handle: Option, -} - -impl RelayChainNetworkBuilder { - pub fn build(self) -> Arc { - self.polkadot_client.clone().execute_with(self) - } -} - -impl ExecuteWithClient for RelayChainNetworkBuilder { - type Output = Arc; - - fn execute_with_client(self, client: Arc) -> Self::Output - where - Client: ProvideRuntimeApi - + BlockchainEvents - + AuxStore - + UsageProvider - + 'static - + Sync - + Send, - Client::Api: ParachainHost + BabeApi, - { - Arc::new(RelayChainNetwork::new( - client, - self.backend, - self.sync_oracle, - self.overseer_handle, - )) - } -} - -/// Build the Polkadot full node using the given `config`. -#[sc_tracing::logging::prefix_logs_with("Relaychain")] -fn build_polkadot_full_node( - config: Configuration, - telemetry_worker_handle: Option, -) -> Result<(NewFull, CollatorPair), polkadot_service::Error> { - let is_light = matches!(config.role, Role::Light); - if is_light { - Err(polkadot_service::Error::Sub("Light client not supported.".into())) - } else { - let collator_key = CollatorPair::generate().0; - - let relay_chain_full_node = polkadot_service::build_full( - config, - polkadot_service::IsCollator::Yes(collator_key.clone()), - None, - true, - None, - telemetry_worker_handle, - polkadot_service::RealOverseerGen, - )?; - - Ok((relay_chain_full_node, collator_key)) - } -} - -/// Builds a relay chain interface by constructing a full relay chain node -pub fn build_relay_chain_network( - polkadot_config: Configuration, - telemetry_worker_handle: Option, - task_manager: &mut TaskManager, -) -> Result<(Arc<(dyn RelayChainInterface + 'static)>, CollatorPair), polkadot_service::Error> { - let (full_node, collator_key) = - build_polkadot_full_node(polkadot_config, telemetry_worker_handle).map_err( - |e| match e { - polkadot_service::Error::Sub(x) => x, - s => format!("{}", s).into(), - }, - )?; - - let sync_oracle: Box = Box::new(full_node.network.clone()); - let sync_oracle = Arc::new(Mutex::new(sync_oracle)); - let relay_chain_interface_builder = RelayChainNetworkBuilder { - polkadot_client: full_node.client.clone(), - backend: full_node.backend.clone(), - sync_oracle, - overseer_handle: full_node.overseer_handle.clone(), - }; - task_manager.add_child(full_node.task_manager); - - Ok((relay_chain_interface_builder.build(), collator_key)) -} diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 3ed36b8ec32..eea057ed13a 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -54,6 +54,8 @@ cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } cumulus-relay-chain-network = { path = "../../client/relay-chain-network" } +url = "2.2.2" + criterion = { version = "0.3.5", features = [ "async_tokio" ] } parking_lot = "0.11.1" diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index d357d862c33..482ce6650ad 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -33,7 +33,6 @@ use cumulus_relay_chain_network::RelayChainNetwork; use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; use frame_system_rpc_runtime_api::AccountNonceApi; -use parking_lot::Mutex; use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData}; use polkadot_service::ProvideRuntimeApi; use sc_client_api::execution_extensions::ExecutionStrategies; @@ -219,13 +218,8 @@ where let client = params.client.clone(); let backend = params.backend.clone(); - println!("initializing network;"); - let relay_chain_interface = Arc::new(RelayChainNetwork::new( - relay_chain_full_node.client.clone(), - relay_chain_full_node.backend.clone(), - Arc::new(Mutex::new(Box::new(relay_chain_full_node.network.clone()))), - relay_chain_full_node.overseer_handle.clone(), - )); + let relay_chain_url = url::Url::parse("http://localhost:9333").expect("should be valid url"); + let relay_chain_interface = Arc::new(RelayChainNetwork::new(relay_chain_url)); task_manager.add_child(relay_chain_full_node.task_manager); let block_announce_validator = From f0d6c18b0fcf8764e73330bfe378f4b3dfba42ec Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 10 Jan 2022 20:07:59 +0100 Subject: [PATCH 09/31] Simplify closure in call_remote_runtime_function --- client/relay-chain-network/src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index f3dc6ed0b01..6f7d15bf3b4 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -48,15 +48,16 @@ struct RelayChainRPCClient { http_client: HttpClient, } +/// Client that calls RPC endpoints and deserializes call results impl RelayChainRPCClient { + /// Call a runtime function via rpc async fn call_remote_runtime_function( &self, method_name: &str, block_id: &BlockId, payload: Option>, ) -> Result { - let payload_bytes = - payload.map_or(sp_core::Bytes(Vec::new()), |pl| sp_core::Bytes(pl.encode().to_vec())); + let payload_bytes = payload.map_or(sp_core::Bytes(Vec::new()), sp_core::Bytes); let params = rpc_params! { method_name, payload_bytes, From d4dada59bf7f6b8dca25d021346b2195abbcdc41 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 12 Jan 2022 15:58:28 +0100 Subject: [PATCH 10/31] Implement import stream, upgrade JsonRpSee --- Cargo.lock | 113 ++++++++++-------- .../common/src/parachain_consensus.rs | 21 ++-- client/network/src/tests.rs | 14 ++- client/pov-recovery/src/lib.rs | 16 +-- client/relay-chain-interface/Cargo.toml | 1 + client/relay-chain-interface/src/lib.rs | 21 +++- client/relay-chain-local/src/lib.rs | 32 +++-- client/relay-chain-network/Cargo.toml | 2 +- client/relay-chain-network/src/lib.rs | 84 +++++++++++-- test/service/Cargo.toml | 1 + test/service/src/lib.rs | 10 +- test/service/tests/runtime_upgrade.rs | 2 +- 12 files changed, 214 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 36761ff6184..a3ac5c990f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1840,6 +1840,7 @@ dependencies = [ "async-trait", "cumulus-primitives-core", "derive_more", + "futures 0.3.19", "parking_lot 0.11.2", "polkadot-overseer", "sc-client-api", @@ -1889,7 +1890,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures 0.3.19", - "jsonrpsee 0.6.1", + "jsonrpsee 0.7.0", "parity-scale-codec", "parking_lot 0.11.2", "polkadot-client", @@ -2006,6 +2007,7 @@ dependencies = [ "cumulus-client-service", "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", + "cumulus-relay-chain-local", "cumulus-relay-chain-network", "cumulus-test-relay-validation-worker-provider", "cumulus-test-runtime", @@ -3650,40 +3652,80 @@ checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ "jsonrpsee-proc-macros", "jsonrpsee-types 0.4.1", - "jsonrpsee-utils 0.4.1", + "jsonrpsee-utils", "jsonrpsee-ws-client 0.4.1", ] [[package]] name = "jsonrpsee" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceafa2f3d8cb796bf63364691fb875b079814064306cfd4cb067f95f800a673f" +checksum = "726b6cb76e568aefc4cc127fdb39cb9d92c176f4df0385eaf8053f770351719c" dependencies = [ + "jsonrpsee-core", "jsonrpsee-http-client", - "jsonrpsee-types 0.6.1", - "jsonrpsee-utils 0.6.1", - "jsonrpsee-ws-client 0.6.1", + "jsonrpsee-types 0.7.0", + "jsonrpsee-ws-client 0.7.0", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bc39096d2bd470ecbd5ed96c8464e2b2c2ef7ec6f8cb9611604255608624773" +dependencies = [ + "futures 0.3.19", + "http", + "jsonrpsee-core", + "jsonrpsee-types 0.7.0", + "pin-project 1.0.8", + "soketto", + "thiserror", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b863e5e86a11bfaf46bb3ab5aba184671bd62058e8e3ab741c3395904c7afbf3" +dependencies = [ + "anyhow", + "arrayvec 0.7.2", + "async-trait", + "beef", + "futures-channel", + "futures-util", + "hyper", + "jsonrpsee-types 0.7.0", + "rustc-hash", + "serde", + "serde_json", + "soketto", + "thiserror", + "tokio", + "tracing", ] [[package]] name = "jsonrpsee-http-client" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5531d414c35725627559c9a228a63fa466067153686848e1db7cb9d3366e4b7" +checksum = "b7ca9f9028b3a9cd3c7c5b876f037def9368c6ba6498fd2d3162bdbece1d0ef9" dependencies = [ "async-trait", - "fnv", "hyper", "hyper-rustls 0.23.0", - "jsonrpsee-types 0.6.1", - "jsonrpsee-utils 0.6.1", + "jsonrpsee-core", + "jsonrpsee-types 0.7.0", + "rustc-hash", "serde", "serde_json", "thiserror", "tokio", "tracing", - "url 2.2.2", ] [[package]] @@ -3720,19 +3762,14 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7589284e20eb3f40544c672370512e239d9704d6bfa2d3e7a7a7cd505a56e69" +checksum = "e169725e476234f3f96079fb9d8a6d00226db602d3fa056f044994239a490d78" dependencies = [ "anyhow", - "async-trait", "beef", - "futures-channel", - "futures-util", - "hyper", "serde", "serde_json", - "soketto", "thiserror", "tracing", ] @@ -3748,19 +3785,6 @@ dependencies = [ "jsonrpsee-types 0.4.1", ] -[[package]] -name = "jsonrpsee-utils" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc508d9e6169a81d2913035e8c97f2c49f699134cd3d93efa13c4457aa76252" -dependencies = [ - "arrayvec 0.7.2", - "beef", - "futures-util", - "hyper", - "jsonrpsee-types 0.6.1", -] - [[package]] name = "jsonrpsee-ws-client" version = "0.4.1" @@ -3787,26 +3811,13 @@ dependencies = [ [[package]] name = "jsonrpsee-ws-client" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9267225fdfda02df5c5a9793c90cfe9f2ae5f91d42d4da78bd64f0116a28e9a" +checksum = "c97f67449d58b8d90ad57986d12dacab8fd594759ff64eb5e6b6e84e470db977" dependencies = [ - "async-trait", - "fnv", - "futures 0.3.19", - "http", - "jsonrpsee-types 0.6.1", - "pin-project 1.0.8", - "rustls-native-certs 0.6.1", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tokio-rustls 0.23.2", - "tokio-util", - "tracing", - "webpki-roots 0.22.1", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types 0.7.0", ] [[package]] diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 339f13ce06c..e57388ecdcb 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -27,7 +27,9 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, }; -use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption}; +use polkadot_primitives::v1::{ + Block as PBlock, Header as PHeader, Id as ParaId, OccupiedCoreAssumption, +}; use codec::Decode; use futures::{select, FutureExt, Stream, StreamExt}; @@ -382,19 +384,16 @@ where async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream { let relay_chain = self.clone(); - self.import_notification_stream() + self.new_best_notification_stream() + .await .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { - if n.is_new_best { - relay_chain - .parachain_head_at(&BlockId::hash(n.hash), para_id) - .await - .ok() - .flatten() - } else { - None - } + relay_chain + .parachain_head_at(&BlockId::hash(n.hash()), para_id) + .await + .ok() + .flatten() } }) .boxed() diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 4f9ce2feece..40014521bda 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -24,9 +24,9 @@ use parking_lot::Mutex; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_primitives::v1::{ Block as PBlock, CandidateCommitments, CandidateDescriptor, CollatorPair, - CommittedCandidateReceipt, Hash as PHash, HeadData, Id as ParaId, InboundDownwardMessage, - InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, - SigningContext, ValidationCodeHash, ValidatorId, + CommittedCandidateReceipt, Hash as PHash, HeadData, Header as PHeader, Id as ParaId, + InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, + SessionIndex, SigningContext, ValidationCodeHash, ValidatorId, }; use polkadot_service::Handle; use polkadot_test_client::{ @@ -95,7 +95,11 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_backend.blockchain().info().best_hash } - async fn retrieve_dmq_contents(&self, _: ParaId, _: PHash) -> Option> { + async fn retrieve_dmq_contents( + &self, + _: ParaId, + _: PHash, + ) -> Option> { unimplemented!("Not needed for test") } @@ -159,7 +163,7 @@ impl RelayChainInterface for DummyRelayChainInterface { Ok(0) } - fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { + async fn import_notification_stream(&self) -> Pin + Send>> { self.relay_client.import_notification_stream() } diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 5bb7baeb8ed..0eac3a54c43 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -42,7 +42,7 @@ //! If we need to recover multiple PoV blocks (which should hopefully not happen in real life), we //! make sure that the blocks are imported in the correct order. -use sc_client_api::{BlockBackend, BlockchainEvents, UsageProvider}; +use sc_client_api::{BlockBackend, BlockImportNotification, BlockchainEvents, UsageProvider}; use sc_consensus::import_queue::{ImportQueue, IncomingBlock}; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ @@ -53,7 +53,7 @@ use sp_runtime::{ use polkadot_node_primitives::{AvailableData, POV_BOMB_LIMIT}; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::v1::{ - CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, + Block as PBlock, CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, }; use cumulus_primitives_core::ParachainBlockData; @@ -423,14 +423,14 @@ async fn pending_candidates( relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, ) -> impl Stream { - relay_chain_client.import_notification_stream().filter_map(move |n| { + let stream = relay_chain_client.import_notification_stream().await; + stream.filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); async move { - let pending_availability_result = client_for_closure - .candidate_pending_availability(&BlockId::hash(n.hash), para_id) - .await; - let session_index_result = - client_for_closure.session_index_for_child(&BlockId::hash(n.hash)).await; + let block_id = BlockId::hash(n.hash()); + let pending_availability_result = + client_for_closure.candidate_pending_availability(&block_id, para_id).await; + let session_index_result = client_for_closure.session_index_for_child(&block_id).await; session_index_result .map(|v| pending_availability_result.ok().flatten().map(|pa| (pa, v))) .map_err(|e| { diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index a962155ed1e..0b7dac2f4b3 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -16,6 +16,7 @@ sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "mas sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" derive_more = "0.99.2" async-trait = "0.1.52" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index e762986453c..9e4a3fb2ce2 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -14,17 +14,19 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{collections::BTreeMap, sync::Arc}; +use std::{collections::BTreeMap, pin::Pin, sync::Arc}; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, - Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; use polkadot_overseer::Handle as OverseerHandle; -use sc_client_api::{blockchain::BlockStatus, StorageProof}; +use sc_client_api::{blockchain::BlockStatus, BlockImportNotification, StorageProof}; + +use futures::Stream; use sp_api::ApiError; use sp_state_machine::StorageValue; @@ -110,7 +112,10 @@ pub trait RelayChainInterface: Send + Sync { async fn session_index_for_child(&self, block_id: &BlockId) -> Result; /// Get a stream of import block notifications. - fn import_notification_stream(&self) -> sc_client_api::ImportNotifications; + async fn import_notification_stream(&self) -> Pin + Send>>; + + /// Get a stream of new best block notifications. + async fn new_best_notification_stream(&self) -> Pin + Send>>; /// Wait for a block with a given hash in the relay chain. /// @@ -193,8 +198,8 @@ where (**self).validators(block_id).await } - fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { - (**self).import_notification_stream() + async fn import_notification_stream(&self) -> Pin + Send>> { + (**self).import_notification_stream().await } fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { @@ -246,4 +251,8 @@ where async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { (**self).wait_for_block(hash).await } + + async fn new_best_notification_stream(&self) -> Pin + Send>> { + (**self).new_best_notification_stream().await + } } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 0f5c430ac3c..a71c3d0bcc0 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -14,27 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . -use std::{sync::Arc, time::Duration}; +use std::{pin::Pin, sync::Arc, time::Duration}; use async_trait::async_trait; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, v2::ParachainHost, - Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; -use futures::{FutureExt, StreamExt}; +use futures::{stream::BoxStream, FutureExt, Stream, StreamExt}; use parking_lot::Mutex; use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; use polkadot_service::{ AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, }; use sc_client_api::{ - blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, ImportNotifications, - StorageProof, UsageProvider, + blockchain::BlockStatus, Backend, BlockImportNotification, BlockchainEvents, HeaderBackend, + ImportNotifications, StorageProof, UsageProvider, }; use sc_telemetry::TelemetryWorkerHandle; use sp_api::{ApiError, ProvideRuntimeApi}; @@ -163,8 +163,12 @@ where self.full_client.runtime_api().validators(block_id) } - fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { - self.full_client.import_notification_stream() + async fn import_notification_stream(&self) -> Pin + Send>> { + let notifications_stream = self + .full_client + .import_notification_stream() + .map(|notification| notification.header); + Box::pin(notifications_stream) } fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { @@ -280,6 +284,20 @@ where } } } + + async fn new_best_notification_stream(&self) -> Pin + Send>> { + let notifications_stream = + self.full_client + .import_notification_stream() + .filter_map(|notification| async move { + if notification.is_new_best { + Some(notification.header) + } else { + None + } + }); + Box::pin(notifications_stream) + } } pub enum BlockCheckStatus { diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index df93677a776..84d38d41153 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -30,7 +30,7 @@ futures = { version = "0.3.1", features = ["compat"] } parity-scale-codec = "2.3.1" parking_lot = "0.11.1" -jsonrpsee = {version = "0.6.1", features = ["client"]} +jsonrpsee = {version = "0.7.0", features = ["client"]} tracing = "0.1.25" async-trait = "0.1.52" url = "2.2.2" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 6f7d15bf3b4..3ce97892f41 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -14,30 +14,38 @@ // You should have received a copy of the GNU General Public License // along with Cumulus. If not, see . +use std::pin::Pin; + use async_trait::async_trait; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, - Block as PBlock, BlockId, Hash as PHash, InboundHrmpMessage, + Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::RelayChainInterface; +use futures::{Stream, StreamExt, TryStreamExt}; use parity_scale_codec::{Decode, Encode}; use jsonrpsee::{ - http_client::{HttpClient, HttpClientBuilder}, + core::{ + client::{Client as JsonRPCClient, ClientT, Subscription, SubscriptionClientT}, + Error as JsonRPSeeError, + }, rpc_params, - types::{error::Error as JsonRPSeeError, traits::Client, v2::ParamsSer}, + types::ParamsSer, + ws_client::WsClientBuilder, }; use polkadot_service::Handle; -use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; +use sc_client_api::{blockchain::BlockStatus, BlockImportNotification, StorageData, StorageProof}; use sc_rpc_api::state::ReadProof; use sp_api::ApiError; use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_runtime::{generic::SignedBlock, DeserializeOwned}; use sp_state_machine::StorageValue; use sp_storage::StorageKey; +use std::sync::Arc; pub use url::Url; @@ -45,7 +53,7 @@ const LOG_TARGET: &str = "relay_chain_network"; #[derive(Clone)] struct RelayChainRPCClient { - http_client: HttpClient, + ws_client: Arc, } /// Client that calls RPC endpoints and deserializes call results @@ -66,6 +74,19 @@ impl RelayChainRPCClient { self.request("state_call", params).await } + async fn subscribe<'a, R>( + &self, + sub_name: &'a str, + unsub_name: &'a str, + params: Option>, + ) -> Result, JsonRPSeeError> + where + R: DeserializeOwned, + { + tracing::trace!(target: LOG_TARGET, "Subscribing to stream: {}", sub_name); + self.ws_client.subscribe::(sub_name, params, unsub_name).await + } + async fn request<'a, R>( &self, method: &'a str, @@ -74,8 +95,8 @@ impl RelayChainRPCClient { where R: DeserializeOwned, { - tracing::trace!(target: LOG_TARGET, method = ?method); - self.http_client.request(method, params).await + tracing::trace!(target: LOG_TARGET, "Calling rpc endpoint: {}", method); + self.ws_client.request(method, params).await } async fn state_get_read_proof( @@ -193,6 +214,16 @@ impl RelayChainRPCClient { Ok(Option::>::decode(&mut &*response_bytes.0) .expect("should deserialize")) } + + async fn subscribe_all_heads(&self) -> Result, JsonRPSeeError> { + self.subscribe::("chain_subscribeAllHeads", "chain_unsubscribeAllHeads", None) + .await + } + + async fn subscribe_new_best_heads(&self) -> Result, JsonRPSeeError> { + self.subscribe::("subscribe_newHead", "unsubscribe_newHead", None) + .await + } } /// RelayChainNetwork is used to interact with a full node that is running locally @@ -203,10 +234,13 @@ pub struct RelayChainNetwork { } impl RelayChainNetwork { - pub fn new(url: Url) -> Self { - let http_client = HttpClientBuilder::default().build(url.as_str()).expect("yo"); + pub async fn new(url: Url) -> Self { + let ws_client = WsClientBuilder::default() + .build(url.as_str()) + .await + .expect("Should be able to initialize websocket client."); - Self { rpc_client: RelayChainRPCClient { http_client } } + Self { rpc_client: RelayChainRPCClient { ws_client: Arc::new(ws_client) } } } } @@ -276,8 +310,19 @@ impl RelayChainInterface for RelayChainNetwork { Ok(response.expect("nope")) } - fn import_notification_stream(&self) -> sc_client_api::ImportNotifications { - todo!("import_notification_stream"); + async fn import_notification_stream(&self) -> Pin + Send>> { + let imported_headers_stream = self + .rpc_client + .subscribe_all_heads() + .await + .expect("Should be able to subscribe"); + + Box::pin(imported_headers_stream.filter_map(|item| async move { + item.map_err(|err| { + tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) + }) + .ok() + })) } fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { @@ -364,4 +409,19 @@ impl RelayChainInterface for RelayChainNetwork { ) -> Result<(), cumulus_relay_chain_interface::WaitError> { todo!("wait_for_block_not_implemented"); } + + async fn new_best_notification_stream(&self) -> Pin + Send>> { + let imported_headers_stream = self + .rpc_client + .subscribe_new_best_heads() + .await + .expect("Should be able to subscribe"); + + Box::pin(imported_headers_stream.filter_map(|item| async move { + item.map_err(|err| { + tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) + }) + .ok() + })) + } } diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index eea057ed13a..489a7a36bb5 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -53,6 +53,7 @@ cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inh cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } cumulus-relay-chain-network = { path = "../../client/relay-chain-network" } +cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } url = "2.2.2" diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index 482ce6650ad..ecae5913809 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -29,8 +29,10 @@ use cumulus_client_service::{ prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams, }; use cumulus_primitives_core::ParaId; +use cumulus_relay_chain_local::RelayChainLocal; use cumulus_relay_chain_network::RelayChainNetwork; use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; +use parking_lot::Mutex; use frame_system_rpc_runtime_api::AccountNonceApi; use polkadot_primitives::v1::{CollatorPair, Hash as PHash, PersistedValidationData}; @@ -219,7 +221,13 @@ where let backend = params.backend.clone(); let relay_chain_url = url::Url::parse("http://localhost:9333").expect("should be valid url"); - let relay_chain_interface = Arc::new(RelayChainNetwork::new(relay_chain_url)); + // let relay_chain_interface = Arc::new(RelayChainNetwork::new(relay_chain_url)); + let relay_chain_interface = Arc::new(RelayChainLocal::new( + relay_chain_full_node.client.clone(), + relay_chain_full_node.backend.clone(), + Arc::new(Mutex::new(Box::new(relay_chain_full_node.network.clone()))), + relay_chain_full_node.overseer_handle.clone(), + )); task_manager.add_child(relay_chain_full_node.task_manager); let block_announce_validator = diff --git a/test/service/tests/runtime_upgrade.rs b/test/service/tests/runtime_upgrade.rs index 4731404fee8..4b2863870bf 100644 --- a/test/service/tests/runtime_upgrade.rs +++ b/test/service/tests/runtime_upgrade.rs @@ -85,7 +85,7 @@ async fn test_runtime_upgrade() { if notification.is_new_best { let runtime_version = dave .client - .runtime_version_at(&BlockId::Hash(notification.hash)) + .runtime_version_at(&BlockId::Hash(notification.hash())) .expect("Runtime version exists"); if expected_runtime_version == runtime_version { From dc5de785fd6ca1a62ff511171ea37a4c8db37621 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 12 Jan 2022 16:16:54 +0100 Subject: [PATCH 11/31] Implement finality stream --- .../common/src/parachain_consensus.rs | 3 ++- client/network/src/tests.rs | 2 +- client/relay-chain-interface/src/lib.rs | 6 ++--- client/relay-chain-local/src/lib.rs | 12 ++++++--- client/relay-chain-network/src/lib.rs | 26 ++++++++++++++++--- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index e57388ecdcb..d13458ad477 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -403,11 +403,12 @@ where let relay_chain = self.clone(); self.finality_notification_stream() + .await .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { relay_chain - .parachain_head_at(&BlockId::hash(n.hash), para_id) + .parachain_head_at(&BlockId::hash(n.hash()), para_id) .await .ok() .flatten() diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 40014521bda..4755b46b319 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -167,7 +167,7 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_client.import_notification_stream() } - fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { + async fn finality_notification_stream(&self) -> Pin + Send>> { self.relay_client.finality_notification_stream() } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 9e4a3fb2ce2..5bc21090add 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -124,7 +124,7 @@ pub trait RelayChainInterface: Send + Sync { async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError>; /// Get a stream of finality notifications. - fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications; + async fn finality_notification_stream(&self) -> Pin + Send>>; /// Get a stream of storage change notifications. fn storage_changes_notification_stream( @@ -202,8 +202,8 @@ where (**self).import_notification_stream().await } - fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { - (**self).finality_notification_stream() + async fn finality_notification_stream(&self) -> Pin + Send>> { + (**self).finality_notification_stream().await } fn storage_changes_notification_stream( diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index a71c3d0bcc0..fc2bb5fc729 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -164,15 +164,19 @@ where } async fn import_notification_stream(&self) -> Pin + Send>> { - let notifications_stream = self + let notification_stream = self .full_client .import_notification_stream() .map(|notification| notification.header); - Box::pin(notifications_stream) + Box::pin(notification_stream) } - fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { - self.full_client.finality_notification_stream() + async fn finality_notification_stream(&self) -> Pin + Send>> { + let notification_stream = self + .full_client + .finality_notification_stream() + .map(|notification| notification.header); + Box::pin(notification_stream) } fn storage_changes_notification_stream( diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 3ce97892f41..6fcc6217531 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -221,9 +221,18 @@ impl RelayChainRPCClient { } async fn subscribe_new_best_heads(&self) -> Result, JsonRPSeeError> { - self.subscribe::("subscribe_newHead", "unsubscribe_newHead", None) + self.subscribe::("chain_subscribeNewHeads", "chain_unsubscribeNewHeads", None) .await } + + async fn subscribe_finalized_heads(&self) -> Result, JsonRPSeeError> { + self.subscribe::( + "chain_subscribeFinalizedHeads", + "chain_unsubscribeFinalizedHeads", + None, + ) + .await + } } /// RelayChainNetwork is used to interact with a full node that is running locally @@ -325,8 +334,19 @@ impl RelayChainInterface for RelayChainNetwork { })) } - fn finality_notification_stream(&self) -> sc_client_api::FinalityNotifications { - todo!("finality_notification_stream"); + async fn finality_notification_stream(&self) -> Pin + Send>> { + let imported_headers_stream = self + .rpc_client + .subscribe_finalized_heads() + .await + .expect("Should be able to subscribe"); + + Box::pin(imported_headers_stream.filter_map(|item| async move { + item.map_err(|err| { + tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) + }) + .ok() + })) } fn storage_changes_notification_stream( From 2675a7d1560673903bbe8cb4c14b63981cb59cfc Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 12 Jan 2022 16:25:38 +0100 Subject: [PATCH 12/31] Remove unused method from interface --- client/network/src/tests.rs | 11 ----------- client/relay-chain-interface/src/lib.rs | 19 ------------------- client/relay-chain-local/src/lib.rs | 11 ----------- client/relay-chain-network/src/lib.rs | 14 ++------------ 4 files changed, 2 insertions(+), 53 deletions(-) diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 4755b46b319..74cbd6d8fe0 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -171,17 +171,6 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_client.finality_notification_stream() } - fn storage_changes_notification_stream( - &self, - filter_keys: Option<&[sc_client_api::StorageKey]>, - child_filter_keys: Option< - &[(sc_client_api::StorageKey, Option>)], - >, - ) -> sc_client_api::blockchain::Result> { - self.relay_client - .storage_changes_notification_stream(filter_keys, child_filter_keys) - } - fn is_major_syncing(&self) -> bool { false } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 5bc21090add..dea07c87b6d 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -126,15 +126,6 @@ pub trait RelayChainInterface: Send + Sync { /// Get a stream of finality notifications. async fn finality_notification_stream(&self) -> Pin + Send>>; - /// Get a stream of storage change notifications. - fn storage_changes_notification_stream( - &self, - filter_keys: Option<&[sc_client_api::StorageKey]>, - child_filter_keys: Option< - &[(sc_client_api::StorageKey, Option>)], - >, - ) -> sc_client_api::blockchain::Result>; - /// Whether the synchronization service is undergoing major sync. /// Returns true if so. fn is_major_syncing(&self) -> bool; @@ -206,16 +197,6 @@ where (**self).finality_notification_stream().await } - fn storage_changes_notification_stream( - &self, - filter_keys: Option<&[sc_client_api::StorageKey]>, - child_filter_keys: Option< - &[(sc_client_api::StorageKey, Option>)], - >, - ) -> sc_client_api::blockchain::Result> { - (**self).storage_changes_notification_stream(filter_keys, child_filter_keys) - } - async fn best_block_hash(&self) -> PHash { (**self).best_block_hash().await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index fc2bb5fc729..0cef053f387 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -179,17 +179,6 @@ where Box::pin(notification_stream) } - fn storage_changes_notification_stream( - &self, - filter_keys: Option<&[sc_client_api::StorageKey]>, - child_filter_keys: Option< - &[(sc_client_api::StorageKey, Option>)], - >, - ) -> sc_client_api::blockchain::Result> { - self.full_client - .storage_changes_notification_stream(filter_keys, child_filter_keys) - } - async fn best_block_hash(&self) -> PHash { self.backend.blockchain().info().best_hash } diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 6fcc6217531..51da3dc6573 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives_core::{ InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::RelayChainInterface; -use futures::{Stream, StreamExt, TryStreamExt}; +use futures::{Stream, StreamExt}; use parity_scale_codec::{Decode, Encode}; use jsonrpsee::{ @@ -38,7 +38,7 @@ use jsonrpsee::{ ws_client::WsClientBuilder, }; use polkadot_service::Handle; -use sc_client_api::{blockchain::BlockStatus, BlockImportNotification, StorageData, StorageProof}; +use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; use sc_rpc_api::state::ReadProof; use sp_api::ApiError; use sp_core::sp_std::collections::btree_map::BTreeMap; @@ -349,16 +349,6 @@ impl RelayChainInterface for RelayChainNetwork { })) } - fn storage_changes_notification_stream( - &self, - filter_keys: Option<&[sc_client_api::StorageKey]>, - child_filter_keys: Option< - &[(sc_client_api::StorageKey, Option>)], - >, - ) -> sc_client_api::blockchain::Result> { - todo!("storage_changes_notification_stream"); - } - async fn best_block_hash(&self) -> PHash { let response = self.rpc_client.chain_get_head().await; response.expect("nope") From f9a228dfe7d3d68f809ae6b6ecd87ba0e96709f8 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 12 Jan 2022 17:56:40 +0100 Subject: [PATCH 13/31] Implement `is_major_syncing` --- client/network/src/lib.rs | 39 +++++++++++++------------ client/network/src/tests.rs | 2 +- client/relay-chain-interface/src/lib.rs | 6 ++-- client/relay-chain-local/src/lib.rs | 2 +- client/relay-chain-network/src/lib.rs | 11 +++++-- 5 files changed, 33 insertions(+), 27 deletions(-) diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 5bf66bcb8f3..6d058807100 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -222,6 +222,7 @@ impl TryFrom<&'_ CollationSecondedSignal> for BlockAnnounceData { /// chain. If it is at the tip, it is required to provide a justification or otherwise we reject /// it. However, if the announcement is for a block below the tip the announcement is accepted /// as it probably comes from a node that is currently syncing the chain. +#[derive(Clone)] pub struct BlockAnnounceValidator { phantom: PhantomData, relay_chain_interface: RCInterface, @@ -338,30 +339,30 @@ where header: &Block::Header, mut data: &[u8], ) -> Pin> + Send>> { - if self.relay_chain_interface.is_major_syncing() { - return ready(Ok(Validation::Success { is_new_best: false })).boxed() - } + let relay_chain_interface = self.relay_chain_interface.clone(); + let mut data = data.to_vec(); + let header = header.clone(); + let header_encoded = header.encode(); + let block_announce_validator = self.clone(); - if data.is_empty() { - return self.handle_empty_block_announce_data(header.clone()).boxed() - } + async move { + if relay_chain_interface.is_major_syncing().await { + return Ok(Validation::Success { is_new_best: false }) + } - let block_announce_data = match BlockAnnounceData::decode_all(&mut data) { - Ok(r) => r, - Err(err) => - return async move { - Err(Box::new(BlockAnnounceError(format!( + if data.is_empty() { + return block_announce_validator.handle_empty_block_announce_data(header).await + } + + let block_announce_data = match BlockAnnounceData::decode_all(&mut data) { + Ok(r) => r, + Err(err) => + return Err(Box::new(BlockAnnounceError(format!( "Can not decode the `BlockAnnounceData`: {:?}", err - ))) as Box<_>) - } - .boxed(), - }; - - let relay_chain_interface = self.relay_chain_interface.clone(); - let header_encoded = header.encode(); + ))) as Box<_>), + }; - async move { if let Err(e) = block_announce_data.validate(header_encoded) { return Ok(e) } diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 74cbd6d8fe0..b462f8f999b 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -171,7 +171,7 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_client.finality_notification_stream() } - fn is_major_syncing(&self) -> bool { + async fn is_major_syncing(&self) -> bool { false } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index dea07c87b6d..77c0c8d9ba3 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -128,7 +128,7 @@ pub trait RelayChainInterface: Send + Sync { /// Whether the synchronization service is undergoing major sync. /// Returns true if so. - fn is_major_syncing(&self) -> bool; + async fn is_major_syncing(&self) -> bool; /// Get a handle to the overseer. fn overseer_handle(&self) -> Option; @@ -205,8 +205,8 @@ where (**self).block_status(block_id).await } - fn is_major_syncing(&self) -> bool { - (**self).is_major_syncing() + async fn is_major_syncing(&self) -> bool { + (**self).is_major_syncing().await } fn overseer_handle(&self) -> Option { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 0cef053f387..7aba9438a0f 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -187,7 +187,7 @@ where self.backend.blockchain().status(block_id) } - fn is_major_syncing(&self) -> bool { + async fn is_major_syncing(&self) -> bool { let mut network = self.sync_oracle.lock(); network.is_major_syncing() } diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 51da3dc6573..96c2ba5bb90 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -39,7 +39,7 @@ use jsonrpsee::{ }; use polkadot_service::Handle; use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; -use sc_rpc_api::state::ReadProof; +use sc_rpc_api::{state::ReadProof, system::Health}; use sp_api::ApiError; use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_runtime::{generic::SignedBlock, DeserializeOwned}; @@ -99,6 +99,10 @@ impl RelayChainRPCClient { self.ws_client.request(method, params).await } + async fn system_health(&self) -> Result { + self.request("system_health", None).await + } + async fn state_get_read_proof( &self, storage_keys: Vec, @@ -367,8 +371,9 @@ impl RelayChainInterface for RelayChainNetwork { } } - fn is_major_syncing(&self) -> bool { - todo!("major_syncing"); + async fn is_major_syncing(&self) -> bool { + let health = self.rpc_client.system_health().await.expect("Should be able to fetch health"); + health.is_syncing } fn overseer_handle(&self) -> Option { From 7a89c73b4c042890aed9988126c25c3b26481d7a Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 13 Jan 2022 12:19:26 +0100 Subject: [PATCH 14/31] Implement `wait_on_block` --- Cargo.lock | 1 + .../common/src/parachain_consensus.rs | 4 +- client/network/src/lib.rs | 6 +- client/pov-recovery/src/lib.rs | 4 +- client/relay-chain-interface/src/lib.rs | 4 +- client/relay-chain-local/src/lib.rs | 6 +- client/relay-chain-network/Cargo.toml | 3 +- client/relay-chain-network/src/lib.rs | 55 ++++++++++++++++--- 8 files changed, 60 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3ac5c990f4..0a352294818 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1890,6 +1890,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures 0.3.19", + "futures-timer 3.0.2", "jsonrpsee 0.7.0", "parity-scale-codec", "parking_lot 0.11.2", diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index d13458ad477..a5b5072d461 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -27,9 +27,7 @@ use sp_runtime::{ traits::{Block as BlockT, Header as HeaderT}, }; -use polkadot_primitives::v1::{ - Block as PBlock, Header as PHeader, Id as ParaId, OccupiedCoreAssumption, -}; +use polkadot_primitives::v1::{Block as PBlock, Id as ParaId, OccupiedCoreAssumption}; use codec::Decode; use futures::{select, FutureExt, Stream, StreamExt}; diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 6d058807100..a33573a8524 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -38,11 +38,7 @@ use polkadot_primitives::v1::{ }; use codec::{Decode, DecodeAll, Encode}; -use futures::{ - channel::oneshot, - future::{ready, FutureExt}, - Future, -}; +use futures::{channel::oneshot, future::FutureExt, Future}; use std::{convert::TryFrom, fmt, marker::PhantomData, pin::Pin, sync::Arc}; diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 0eac3a54c43..f3708904e05 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -42,7 +42,7 @@ //! If we need to recover multiple PoV blocks (which should hopefully not happen in real life), we //! make sure that the blocks are imported in the correct order. -use sc_client_api::{BlockBackend, BlockImportNotification, BlockchainEvents, UsageProvider}; +use sc_client_api::{BlockBackend, BlockchainEvents, UsageProvider}; use sc_consensus::import_queue::{ImportQueue, IncomingBlock}; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ @@ -53,7 +53,7 @@ use sp_runtime::{ use polkadot_node_primitives::{AvailableData, POV_BOMB_LIMIT}; use polkadot_overseer::Handle as OverseerHandle; use polkadot_primitives::v1::{ - Block as PBlock, CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, + CandidateReceipt, CommittedCandidateReceipt, Id as ParaId, SessionIndex, }; use cumulus_primitives_core::ParachainBlockData; diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 77c0c8d9ba3..4bfef1085c1 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -19,12 +19,12 @@ use std::{collections::BTreeMap, pin::Pin, sync::Arc}; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, - Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, + BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, }, InboundDownwardMessage, ParaId, PersistedValidationData, }; use polkadot_overseer::Handle as OverseerHandle; -use sc_client_api::{blockchain::BlockStatus, BlockImportNotification, StorageProof}; +use sc_client_api::{blockchain::BlockStatus, StorageProof}; use futures::Stream; diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 7aba9438a0f..e9e8fede060 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -26,15 +26,15 @@ use cumulus_primitives_core::{ InboundDownwardMessage, ParaId, PersistedValidationData, }; use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; -use futures::{stream::BoxStream, FutureExt, Stream, StreamExt}; +use futures::{FutureExt, Stream, StreamExt}; use parking_lot::Mutex; use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; use polkadot_service::{ AuxStore, BabeApi, CollatorPair, Configuration, Handle, NewFull, Role, TaskManager, }; use sc_client_api::{ - blockchain::BlockStatus, Backend, BlockImportNotification, BlockchainEvents, HeaderBackend, - ImportNotifications, StorageProof, UsageProvider, + blockchain::BlockStatus, Backend, BlockchainEvents, HeaderBackend, ImportNotifications, + StorageProof, UsageProvider, }; use sc_telemetry::TelemetryWorkerHandle; use sp_api::{ApiError, ProvideRuntimeApi}; diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml index 84d38d41153..dbcc23d4a90 100644 --- a/client/relay-chain-network/Cargo.toml +++ b/client/relay-chain-network/Cargo.toml @@ -26,8 +26,9 @@ sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "mast sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -futures = { version = "0.3.1", features = ["compat"] } +futures = { version = "0.3.1", features = ["compat"] } +futures-timer = "3.0.2" parity-scale-codec = "2.3.1" parking_lot = "0.11.1" jsonrpsee = {version = "0.7.0", features = ["client"]} diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 96c2ba5bb90..b9c185d2e2d 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -17,6 +17,7 @@ use std::pin::Pin; use async_trait::async_trait; +use core::time::Duration; use cumulus_primitives_core::{ relay_chain::{ v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, @@ -24,10 +25,8 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::RelayChainInterface; -use futures::{Stream, StreamExt}; -use parity_scale_codec::{Decode, Encode}; - +use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; +use futures::{FutureExt, Stream, StreamExt}; use jsonrpsee::{ core::{ client::{Client as JsonRPCClient, ClientT, Subscription, SubscriptionClientT}, @@ -37,6 +36,7 @@ use jsonrpsee::{ types::ParamsSer, ws_client::WsClientBuilder, }; +use parity_scale_codec::{Decode, Encode}; use polkadot_service::Handle; use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; use sc_rpc_api::{state::ReadProof, system::Health}; @@ -49,7 +49,8 @@ use std::sync::Arc; pub use url::Url; -const LOG_TARGET: &str = "relay_chain_network"; +const LOG_TARGET: &str = "relay-chain-network"; +const TIMEOUT_IN_SECONDS: u64 = 6; #[derive(Clone)] struct RelayChainRPCClient { @@ -133,6 +134,14 @@ impl RelayChainRPCClient { self.request("chain_getHead", None).await } + async fn chain_get_header( + &self, + hash: Option, + ) -> Result, JsonRPSeeError> { + let params = hash.map(|hash| rpc_params!(hash)).flatten(); + self.request("chain_getHeader", params).await + } + async fn parachain_host_candidate_pending_availability( &self, at: &BlockId, @@ -418,11 +427,43 @@ impl RelayChainInterface for RelayChainNetwork { })) } + /// Wait for a given relay chain block + /// + /// The hash of the block to wait for is passed. We wait for the block to arrive or return after a timeout. + /// + /// Implementation: + /// 1. Register a listener to all new blocks. + /// 2. Check if the block is already in chain. If yes, succeed early. + /// 3. Wait for the block to be imported via subscription. + /// 4. If timeout is reached, we return an error. async fn wait_for_block( &self, - hash: PHash, + wait_for_hash: PHash, ) -> Result<(), cumulus_relay_chain_interface::WaitError> { - todo!("wait_for_block_not_implemented"); + let mut head_stream = self + .rpc_client + .subscribe_all_heads() + .await + .expect("Should be able to subscribe"); + + let block_header = self.rpc_client.chain_get_header(Some(wait_for_hash)).await; + if block_header.ok().is_some() { + return Ok(()) + } + + let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse(); + + loop { + futures::select! { + _ = timeout => return Err(WaitError::Timeout(wait_for_hash)), + evt = head_stream.next().fuse() => match evt { + Some(Ok(evt)) if evt.hash() == wait_for_hash => return Ok(()), + // Not the event we waited on. + Some(_) => continue, + None => return Err(WaitError::ImportListenerClosed(wait_for_hash)), + } + } + } } async fn new_best_notification_stream(&self) -> Pin + Send>> { From 532ba1d220d3dce5d8510238c6930c1f8d2b443d Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 13 Jan 2022 15:36:27 +0100 Subject: [PATCH 15/31] Fix tests --- client/consensus/common/src/tests.rs | 5 ++-- client/network/src/tests.rs | 36 +++++++++++++++++++++------ test/service/tests/runtime_upgrade.rs | 2 +- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index d529cdcbd4b..fe79c3a9bf5 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -16,6 +16,7 @@ use crate::*; +use async_trait::async_trait; use codec::Encode; use cumulus_test_client::{ runtime::{Block, Header}, @@ -72,7 +73,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { type HeadStream = Box> + Send + Unpin>; - fn new_best_heads(&self, _: ParaId) -> Self::HeadStream { + async fn new_best_heads(&self, _: ParaId) -> Self::HeadStream { let stream = self .inner .lock() @@ -84,7 +85,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { Box::new(stream.map(|v| v.encode())) } - fn finalized_heads(&self, _: ParaId) -> Self::HeadStream { + async fn finalized_heads(&self, _: ParaId) -> Self::HeadStream { let stream = self .inner .lock() diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index b462f8f999b..be309564b91 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -19,14 +19,14 @@ use async_trait::async_trait; use cumulus_relay_chain_interface::WaitError; use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; -use futures::{executor::block_on, poll, task::Poll, FutureExt, StreamExt}; +use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt}; use parking_lot::Mutex; use polkadot_node_primitives::{SignedFullStatement, Statement}; use polkadot_primitives::v1::{ - Block as PBlock, CandidateCommitments, CandidateDescriptor, CollatorPair, - CommittedCandidateReceipt, Hash as PHash, HeadData, Header as PHeader, Id as ParaId, - InboundDownwardMessage, InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, - SessionIndex, SigningContext, ValidationCodeHash, ValidatorId, + CandidateCommitments, CandidateDescriptor, CollatorPair, CommittedCandidateReceipt, + Hash as PHash, HeadData, Header as PHeader, Id as ParaId, InboundDownwardMessage, + InboundHrmpMessage, OccupiedCoreAssumption, PersistedValidationData, SessionIndex, + SigningContext, ValidationCodeHash, ValidatorId, }; use polkadot_service::Handle; use polkadot_test_client::{ @@ -164,11 +164,19 @@ impl RelayChainInterface for DummyRelayChainInterface { } async fn import_notification_stream(&self) -> Pin + Send>> { - self.relay_client.import_notification_stream() + Box::pin( + self.relay_client + .import_notification_stream() + .map(|notification| notification.header), + ) } async fn finality_notification_stream(&self) -> Pin + Send>> { - self.relay_client.finality_notification_stream() + Box::pin( + self.relay_client + .finality_notification_stream() + .map(|notification| notification.header), + ) } async fn is_major_syncing(&self) -> bool { @@ -222,6 +230,20 @@ impl RelayChainInterface for DummyRelayChainInterface { } } } + + async fn new_best_notification_stream(&self) -> Pin + Send>> { + let notifications_stream = + self.relay_client + .import_notification_stream() + .filter_map(|notification| async move { + if notification.is_new_best { + Some(notification.header) + } else { + None + } + }); + Box::pin(notifications_stream) + } } fn make_validator_and_api( diff --git a/test/service/tests/runtime_upgrade.rs b/test/service/tests/runtime_upgrade.rs index 4b2863870bf..4731404fee8 100644 --- a/test/service/tests/runtime_upgrade.rs +++ b/test/service/tests/runtime_upgrade.rs @@ -85,7 +85,7 @@ async fn test_runtime_upgrade() { if notification.is_new_best { let runtime_version = dave .client - .runtime_version_at(&BlockId::Hash(notification.hash())) + .runtime_version_at(&BlockId::Hash(notification.hash)) .expect("Runtime version exists"); if expected_runtime_version == runtime_version { From d49e25bd0a2c71fcdbf000ab1c22cc1ea8a54b10 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 13 Jan 2022 15:54:18 +0100 Subject: [PATCH 16/31] Unify error handling `ApiError` --- Cargo.lock | 6 +-- .../common/src/parachain_consensus.rs | 7 ++-- client/consensus/common/src/tests.rs | 3 +- client/network/src/tests.rs | 10 ++--- client/relay-chain-interface/src/lib.rs | 38 ++++++++++++++---- client/relay-chain-local/src/lib.rs | 39 ++++++++++++------- client/relay-chain-network/src/lib.rs | 14 ++++--- 7 files changed, 76 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1234be353b..6854e3f431f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1913,7 +1913,7 @@ dependencies = [ "cumulus-primitives-core", "cumulus-relay-chain-interface", "futures 0.3.19", - "futures-timer 3.0.2", + "futures-timer", "jsonrpsee 0.7.0", "parity-scale-codec", "parking_lot 0.11.2", @@ -3703,7 +3703,7 @@ dependencies = [ "http", "jsonrpsee-core", "jsonrpsee-types 0.7.0", - "pin-project 1.0.8", + "pin-project 1.0.10", "soketto", "thiserror", "tokio", @@ -3824,7 +3824,7 @@ dependencies = [ "jsonrpsee-types 0.4.1", "log", "pin-project 1.0.10", - "rustls-native-certs", + "rustls-native-certs 0.5.0", "serde", "serde_json", "soketto", diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index a5b5072d461..8eb70271f84 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see . use async_trait::async_trait; -use cumulus_relay_chain_interface::RelayChainInterface; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, }; @@ -54,7 +54,7 @@ pub trait RelaychainClient: Clone + 'static { &self, at: &BlockId, para_id: ParaId, - ) -> ClientResult>>; + ) -> Result>, RelayChainError>; } /// Follow the finalized head of the given parachain. @@ -419,10 +419,9 @@ where &self, at: &BlockId, para_id: ParaId, - ) -> ClientResult>> { + ) -> Result>, RelayChainError> { self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut) .await .map(|s| s.map(|s| s.parent_head.0)) - .map_err(Into::into) } } diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index fe79c3a9bf5..0f39115e309 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -18,6 +18,7 @@ use crate::*; use async_trait::async_trait; use codec::Encode; +use cumulus_relay_chain_interface::RelayChainError; use cumulus_test_client::{ runtime::{Block, Header}, Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, @@ -101,7 +102,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { &self, _: &BlockId, _: ParaId, - ) -> ClientResult>> { + ) -> Result>, RelayChainError> { unimplemented!("Not required for tests") } } diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index be309564b91..38878a23d06 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -16,7 +16,7 @@ use super::*; use async_trait::async_trait; -use cumulus_relay_chain_interface::WaitError; +use cumulus_relay_chain_interface::{RelayChainError, WaitError}; use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt}; @@ -80,7 +80,7 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn validators( &self, _: &cumulus_primitives_core::relay_chain::BlockId, - ) -> Result, sp_api::ApiError> { + ) -> Result, sp_api::RelayChainError> { Ok(self.data.lock().validators.clone()) } @@ -116,7 +116,7 @@ impl RelayChainInterface for DummyRelayChainInterface { _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, _: OccupiedCoreAssumption, - ) -> Result, sp_api::ApiError> { + ) -> Result, sp_api::RelayChainError> { Ok(Some(PersistedValidationData { parent_head: HeadData(default_header().encode()), ..Default::default() @@ -127,7 +127,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, - ) -> Result, sp_api::ApiError> { + ) -> Result, RelayChainError> { if self.data.lock().has_pending_availability { Ok(Some(CommittedCandidateReceipt { descriptor: CandidateDescriptor { @@ -159,7 +159,7 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn session_index_for_child( &self, _: &cumulus_primitives_core::relay_chain::BlockId, - ) -> Result { + ) -> Result { Ok(0) } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 4bfef1085c1..6c1de1e9c25 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -33,6 +33,22 @@ use sp_state_machine::StorageValue; use async_trait::async_trait; +#[derive(Debug, derive_more::Display)] +pub enum RelayChainError { + #[display(fmt = "Error occured while calling relay chain runtime: {:?}", _0)] + ApiError(ApiError), + #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] + WaitTimeout(PHash), + #[display( + fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", + _0, + _1 + )] + WaitBlockchainError(PHash, sp_blockchain::Error), + #[display(fmt = "Error occures while calling relay chain method '{}' over the network ", _0)] + NetworkError(String), +} + #[derive(Debug, derive_more::Display)] pub enum WaitError { #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] @@ -61,7 +77,7 @@ pub trait RelayChainInterface: Send + Sync { ) -> Result, sp_blockchain::Error>; /// Fetch a vector of current validators. - async fn validators(&self, block_id: &BlockId) -> Result, ApiError>; + async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError>; /// Get the status of a given block. async fn block_status(&self, block_id: BlockId) -> Result; @@ -98,7 +114,7 @@ pub trait RelayChainInterface: Send + Sync { block_id: &BlockId, para_id: ParaId, _: OccupiedCoreAssumption, - ) -> Result, ApiError>; + ) -> Result, RelayChainError>; /// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. @@ -106,10 +122,13 @@ pub trait RelayChainInterface: Send + Sync { &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, ApiError>; + ) -> Result, RelayChainError>; /// Returns the session index expected at a child of the block. - async fn session_index_for_child(&self, block_id: &BlockId) -> Result; + async fn session_index_for_child( + &self, + block_id: &BlockId, + ) -> Result; /// Get a stream of import block notifications. async fn import_notification_stream(&self) -> Pin + Send>>; @@ -167,7 +186,7 @@ where block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, ApiError> { + ) -> Result, RelayChainError> { (**self) .persisted_validation_data(block_id, para_id, occupied_core_assumption) .await @@ -177,15 +196,18 @@ where &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, ApiError> { + ) -> Result, RelayChainError> { (**self).candidate_pending_availability(block_id, para_id).await } - async fn session_index_for_child(&self, block_id: &BlockId) -> Result { + async fn session_index_for_child( + &self, + block_id: &BlockId, + ) -> Result { (**self).session_index_for_child(block_id).await } - async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { (**self).validators(block_id).await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index e9e8fede060..47363bf45c2 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -25,8 +25,8 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; -use futures::{FutureExt, Stream, StreamExt}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, WaitError}; +use futures::{FutureExt, Stream, StreamExt, TryFutureExt}; use parking_lot::Mutex; use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; use polkadot_service::{ @@ -139,28 +139,39 @@ where block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, ApiError> { - self.full_client.runtime_api().persisted_validation_data( - block_id, - para_id, - occupied_core_assumption, - ) + ) -> Result, RelayChainError> { + self.full_client + .runtime_api() + .persisted_validation_data(block_id, para_id, occupied_core_assumption) + .map_err(RelayChainError::ApiError) } async fn candidate_pending_availability( &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, ApiError> { - self.full_client.runtime_api().candidate_pending_availability(block_id, para_id) + ) -> Result, RelayChainError> { + self.full_client + .runtime_api() + .candidate_pending_availability(block_id, para_id) + .map_err(RelayChainError::ApiError) } - async fn session_index_for_child(&self, block_id: &BlockId) -> Result { - self.full_client.runtime_api().session_index_for_child(block_id) + async fn session_index_for_child( + &self, + block_id: &BlockId, + ) -> Result { + self.full_client + .runtime_api() + .session_index_for_child(block_id) + .map_err(RelayChainError::ApiError) } - async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { - self.full_client.runtime_api().validators(block_id) + async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { + self.full_client + .runtime_api() + .validators(block_id) + .map_err(RelayChainError::ApiError) } async fn import_notification_stream(&self) -> Pin + Send>> { diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index b9c185d2e2d..5d3960e06d0 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainInterface, WaitError}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, WaitError}; use futures::{FutureExt, Stream, StreamExt}; use jsonrpsee::{ core::{ @@ -40,7 +40,6 @@ use parity_scale_codec::{Decode, Encode}; use polkadot_service::Handle; use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; use sc_rpc_api::{state::ReadProof, system::Health}; -use sp_api::ApiError; use sp_core::sp_std::collections::btree_map::BTreeMap; use sp_runtime::{generic::SignedBlock, DeserializeOwned}; use sp_state_machine::StorageValue; @@ -298,7 +297,7 @@ impl RelayChainInterface for RelayChainNetwork { block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, ApiError> { + ) -> Result, RelayChainError> { let response = self .rpc_client .parachain_host_persisted_validation_data(block_id, para_id, occupied_core_assumption) @@ -311,7 +310,7 @@ impl RelayChainInterface for RelayChainNetwork { &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, ApiError> { + ) -> Result, RelayChainError> { let response = self .rpc_client .parachain_host_candidate_pending_availability(block_id, para_id) @@ -320,13 +319,16 @@ impl RelayChainInterface for RelayChainNetwork { Ok(response.expect("nope")) } - async fn session_index_for_child(&self, block_id: &BlockId) -> Result { + async fn session_index_for_child( + &self, + block_id: &BlockId, + ) -> Result { let response = self.rpc_client.parachain_host_session_index_for_child(block_id).await; Ok(response.expect("nope")) } - async fn validators(&self, block_id: &BlockId) -> Result, ApiError> { + async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { let response = self.rpc_client.parachain_host_validators(block_id).await; Ok(response.expect("nope")) From 051068f4b797daebc8738a809491777c9838bf43 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 13 Jan 2022 16:06:09 +0100 Subject: [PATCH 17/31] Replace WaitError with RelayChainError --- .../common/src/parachain_consensus.rs | 2 +- client/network/src/lib.rs | 2 +- client/network/src/tests.rs | 13 +++++------- client/relay-chain-interface/src/lib.rs | 20 +++++++------------ client/relay-chain-local/src/lib.rs | 18 ++++++++--------- client/relay-chain-network/src/lib.rs | 11 ++++------ 6 files changed, 27 insertions(+), 39 deletions(-) diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 8eb70271f84..18b66abd920 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -20,7 +20,7 @@ use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, }; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; -use sp_blockchain::{Error as ClientError, Result as ClientResult}; +use sp_blockchain::Error as ClientError; use sp_consensus::{BlockOrigin, BlockStatus}; use sp_runtime::{ generic::BlockId, diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index a33573a8524..4a1dc9cd7c3 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -333,7 +333,7 @@ where fn validate( &mut self, header: &Block::Header, - mut data: &[u8], + data: &[u8], ) -> Pin> + Send>> { let relay_chain_interface = self.relay_chain_interface.clone(); let mut data = data.to_vec(); diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 38878a23d06..c37be530c2c 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -16,7 +16,7 @@ use super::*; use async_trait::async_trait; -use cumulus_relay_chain_interface::{RelayChainError, WaitError}; +use cumulus_relay_chain_interface::RelayChainError; use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt}; @@ -80,7 +80,7 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn validators( &self, _: &cumulus_primitives_core::relay_chain::BlockId, - ) -> Result, sp_api::RelayChainError> { + ) -> Result, RelayChainError> { Ok(self.data.lock().validators.clone()) } @@ -203,10 +203,7 @@ impl RelayChainInterface for DummyRelayChainInterface { unimplemented!("Not needed for test") } - async fn wait_for_block( - &self, - hash: PHash, - ) -> Result<(), cumulus_relay_chain_interface::WaitError> { + async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { let mut listener = match check_block_in_chain( self.relay_backend.clone(), self.relay_client.clone(), @@ -220,12 +217,12 @@ impl RelayChainInterface for DummyRelayChainInterface { loop { futures::select! { - _ = timeout => return Err(WaitError::Timeout(hash)), + _ = timeout => return Err(RelayChainError::WaitTimeout(hash)), evt = listener.next() => match evt { Some(evt) if evt.hash == hash => return Ok(()), // Not the event we waited on. Some(_) => continue, - None => return Err(WaitError::ImportListenerClosed(hash)), + None => return Err(RelayChainError::ImportListenerClosed(hash)), } } } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 6c1de1e9c25..7e25d70b804 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -39,6 +39,11 @@ pub enum RelayChainError { ApiError(ApiError), #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] WaitTimeout(PHash), + #[display( + fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.", + _0 + )] + ImportListenerClosed(PHash), #[display( fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", _0, @@ -47,17 +52,6 @@ pub enum RelayChainError { WaitBlockchainError(PHash, sp_blockchain::Error), #[display(fmt = "Error occures while calling relay chain method '{}' over the network ", _0)] NetworkError(String), -} - -#[derive(Debug, derive_more::Display)] -pub enum WaitError { - #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] - Timeout(PHash), - #[display( - fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.", - _0 - )] - ImportListenerClosed(PHash), #[display( fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", _0, @@ -140,7 +134,7 @@ pub trait RelayChainInterface: Send + Sync { /// /// This method returns immediately on error or if the block is already /// reported to be in chain. Otherwise, it waits for the block to arrive. - async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError>; + async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError>; /// Get a stream of finality notifications. async fn finality_notification_stream(&self) -> Pin + Send>>; @@ -251,7 +245,7 @@ where (**self).prove_read(block_id, relevant_keys).await } - async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { + async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { (**self).wait_for_block(hash).await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 47363bf45c2..795c591a6a4 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -25,8 +25,8 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, WaitError}; -use futures::{FutureExt, Stream, StreamExt, TryFutureExt}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use futures::{FutureExt, Stream, StreamExt}; use parking_lot::Mutex; use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; use polkadot_service::{ @@ -37,7 +37,7 @@ use sc_client_api::{ StorageProof, UsageProvider, }; use sc_telemetry::TelemetryWorkerHandle; -use sp_api::{ApiError, ProvideRuntimeApi}; +use sp_api::ProvideRuntimeApi; use sp_consensus::SyncOracle; use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; use sp_state_machine::{Backend as StateBackend, StorageValue}; @@ -267,7 +267,7 @@ where /// /// The timeout is set to 6 seconds. This should be enough time to import the block in the current /// round and if not, the new round of the relay chain already started anyway. - async fn wait_for_block(&self, hash: PHash) -> Result<(), WaitError> { + async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { let mut listener = match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? { BlockCheckStatus::InChain => return Ok(()), @@ -278,12 +278,12 @@ where loop { futures::select! { - _ = timeout => return Err(WaitError::Timeout(hash)), + _ = timeout => return Err(RelayChainError::WaitTimeout(hash)), evt = listener.next() => match evt { Some(evt) if evt.hash == hash => return Ok(()), // Not the event we waited on. Some(_) => continue, - None => return Err(WaitError::ImportListenerClosed(hash)), + None => return Err(RelayChainError::ImportListenerClosed(hash)), } } } @@ -316,7 +316,7 @@ pub fn check_block_in_chain( backend: Arc, client: Arc, hash: PHash, -) -> Result +) -> Result where Client: BlockchainEvents, { @@ -325,7 +325,7 @@ where let block_id = BlockId::Hash(hash); match backend.blockchain().status(block_id) { Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain), - Err(err) => return Err(WaitError::BlockchainError(hash, err)), + Err(err) => return Err(RelayChainError::BlockchainError(hash, err)), _ => {}, } @@ -517,7 +517,7 @@ mod tests { assert!(matches!( block_on(relay_chain_interface.wait_for_block(hash)), - Err(WaitError::Timeout(_)) + Err(RelayChainError::WaitTimeout(_)) )); } diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 5d3960e06d0..32e1bad5fca 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, WaitError}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; use futures::{FutureExt, Stream, StreamExt}; use jsonrpsee::{ core::{ @@ -438,10 +438,7 @@ impl RelayChainInterface for RelayChainNetwork { /// 2. Check if the block is already in chain. If yes, succeed early. /// 3. Wait for the block to be imported via subscription. /// 4. If timeout is reached, we return an error. - async fn wait_for_block( - &self, - wait_for_hash: PHash, - ) -> Result<(), cumulus_relay_chain_interface::WaitError> { + async fn wait_for_block(&self, wait_for_hash: PHash) -> Result<(), RelayChainError> { let mut head_stream = self .rpc_client .subscribe_all_heads() @@ -457,12 +454,12 @@ impl RelayChainInterface for RelayChainNetwork { loop { futures::select! { - _ = timeout => return Err(WaitError::Timeout(wait_for_hash)), + _ = timeout => return Err(RelayChainError::WaitTimeout(wait_for_hash)), evt = head_stream.next().fuse() => match evt { Some(Ok(evt)) if evt.hash() == wait_for_hash => return Ok(()), // Not the event we waited on. Some(_) => continue, - None => return Err(WaitError::ImportListenerClosed(wait_for_hash)), + None => return Err(RelayChainError::ImportListenerClosed(wait_for_hash)), } } } From 4b664a7673196b02a7eed07cfa1b48d95bf7bef9 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Thu, 13 Jan 2022 16:19:02 +0100 Subject: [PATCH 18/31] Wrap BlockChainError in RelayChainError --- client/consensus/common/src/tests.rs | 2 +- client/network/src/tests.rs | 11 +++++++---- client/relay-chain-interface/src/lib.rs | 16 ++++++---------- client/relay-chain-local/src/lib.rs | 18 ++++++++++++------ client/relay-chain-network/src/lib.rs | 4 ++-- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index 0f39115e309..48db6fbd4a2 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -28,7 +28,7 @@ use futures_timer::Delay; use polkadot_primitives::v1::{Block as PBlock, Id as ParaId}; use sc_client_api::UsageProvider; use sc_consensus::{BlockImport, BlockImportParams, ForkChoiceStrategy}; -use sp_blockchain::{Error as ClientError, Result as ClientResult}; +use sp_blockchain::Error as ClientError; use sp_consensus::BlockOrigin; use sp_runtime::generic::BlockId; use std::{ diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index c37be530c2c..85b944eb765 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -87,8 +87,11 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn block_status( &self, block_id: cumulus_primitives_core::relay_chain::BlockId, - ) -> Result { - self.relay_backend.blockchain().status(block_id) + ) -> Result { + self.relay_backend + .blockchain() + .status(block_id) + .map_err(|err| RelayChainError::BlockchainError(err.to_string())) } async fn best_block_hash(&self) -> PHash { @@ -116,7 +119,7 @@ impl RelayChainInterface for DummyRelayChainInterface { _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, _: OccupiedCoreAssumption, - ) -> Result, sp_api::RelayChainError> { + ) -> Result, RelayChainError> { Ok(Some(PersistedValidationData { parent_head: HeadData(default_header().encode()), ..Default::default() @@ -191,7 +194,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &polkadot_service::BlockId, _: &[u8], - ) -> Result, sp_blockchain::Error> { + ) -> Result, RelayChainError> { unimplemented!("Not needed for test") } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 7e25d70b804..bfb93f552b6 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -52,12 +52,8 @@ pub enum RelayChainError { WaitBlockchainError(PHash, sp_blockchain::Error), #[display(fmt = "Error occures while calling relay chain method '{}' over the network ", _0)] NetworkError(String), - #[display( - fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", - _0, - _1 - )] - BlockchainError(PHash, sp_blockchain::Error), + #[display(fmt = "Blockchain returned an error: {:?}", _0)] + BlockchainError(String), } /// Should be used for all interaction with the relay chain in cumulus. @@ -68,13 +64,13 @@ pub trait RelayChainInterface: Send + Sync { &self, block_id: &BlockId, key: &[u8], - ) -> Result, sp_blockchain::Error>; + ) -> Result, RelayChainError>; /// Fetch a vector of current validators. async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError>; /// Get the status of a given block. - async fn block_status(&self, block_id: BlockId) -> Result; + async fn block_status(&self, block_id: BlockId) -> Result; async fn best_block_hash(&self) -> PHash; @@ -217,7 +213,7 @@ where (**self).best_block_hash().await } - async fn block_status(&self, block_id: BlockId) -> Result { + async fn block_status(&self, block_id: BlockId) -> Result { (**self).block_status(block_id).await } @@ -233,7 +229,7 @@ where &self, block_id: &BlockId, key: &[u8], - ) -> Result, sp_blockchain::Error> { + ) -> Result, RelayChainError> { (**self).get_storage_by_key(block_id, key).await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 795c591a6a4..9cdc6eace79 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -194,8 +194,11 @@ where self.backend.blockchain().info().best_hash } - async fn block_status(&self, block_id: BlockId) -> Result { - self.backend.blockchain().status(block_id) + async fn block_status(&self, block_id: BlockId) -> Result { + self.backend + .blockchain() + .status(block_id) + .map_err(|err| RelayChainError::BlockchainError(err.to_string())) } async fn is_major_syncing(&self) -> bool { @@ -211,9 +214,12 @@ where &self, block_id: &BlockId, key: &[u8], - ) -> Result, sp_blockchain::Error> { - let state = self.backend.state_at(*block_id)?; - state.storage(key).map_err(sp_blockchain::Error::Storage) + ) -> Result, RelayChainError> { + let state = self + .backend + .state_at(*block_id) + .map_err(|err| RelayChainError::BlockchainError(err.to_string()))?; + state.storage(key).map_err(RelayChainError::BlockchainError) } async fn prove_read( @@ -325,7 +331,7 @@ where let block_id = BlockId::Hash(hash); match backend.blockchain().status(block_id) { Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain), - Err(err) => return Err(RelayChainError::BlockchainError(hash, err)), + Err(err) => return Err(RelayChainError::BlockchainError(err.to_string())), _ => {}, } diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 32e1bad5fca..52b7614967b 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -369,7 +369,7 @@ impl RelayChainInterface for RelayChainNetwork { response.expect("nope") } - async fn block_status(&self, block_id: BlockId) -> Result { + async fn block_status(&self, block_id: BlockId) -> Result { let hash = match block_id { sp_api::BlockId::Hash(hash) => hash, sp_api::BlockId::Number(_) => todo!(), @@ -395,7 +395,7 @@ impl RelayChainInterface for RelayChainNetwork { &self, block_id: &BlockId, key: &[u8], - ) -> Result, sp_blockchain::Error> { + ) -> Result, RelayChainError> { let storage_key = StorageKey(key.to_vec()); let hash = match block_id { sp_api::BlockId::Hash(hash) => hash, From 40432e8519f7ee23ce99ea7d8ec0d5d67b307fe1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 17 Jan 2022 11:00:39 +0100 Subject: [PATCH 19/31] Unify error handling in relay chain intefaces --- Cargo.lock | 1 + .../common/src/parachain_consensus.rs | 3 + client/network/src/lib.rs | 6 +- client/network/src/tests.rs | 42 +++--- client/pov-recovery/src/lib.rs | 3 +- client/relay-chain-interface/Cargo.toml | 1 + client/relay-chain-interface/src/lib.rs | 71 ++++++--- client/relay-chain-local/src/lib.rs | 44 +++--- client/relay-chain-network/src/lib.rs | 142 +++++++++--------- client/service/src/lib.rs | 6 + .../parachain-inherent/src/client_side.rs | 6 +- 11 files changed, 192 insertions(+), 133 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6854e3f431f..e7f5199d1b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1864,6 +1864,7 @@ dependencies = [ "cumulus-primitives-core", "derive_more", "futures 0.3.19", + "jsonrpsee-core", "parking_lot 0.11.2", "polkadot-overseer", "sc-client-api", diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index 18b66abd920..d0c9c031e07 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -382,8 +382,10 @@ where async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream { let relay_chain = self.clone(); + //TODO: Error handling self.new_best_notification_stream() .await + .expect("") .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { @@ -402,6 +404,7 @@ where self.finality_notification_stream() .await + .expect("") .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 4a1dc9cd7c3..dc2aeef183e 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -290,7 +290,8 @@ where async move { // Check if block is equal or higher than best (this requires a justification) - let relay_chain_best_hash = relay_chain_interface.best_block_hash().await; + // TODO: error handling + let relay_chain_best_hash = relay_chain_interface.best_block_hash().await.expect(""); let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); let block_number = header.number(); @@ -342,7 +343,8 @@ where let block_announce_validator = self.clone(); async move { - if relay_chain_interface.is_major_syncing().await { + // TODO: Error handling + if relay_chain_interface.is_major_syncing().await.expect("") { return Ok(Validation::Success { is_new_best: false }) } diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 85b944eb765..76106f2105e 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -16,7 +16,7 @@ use super::*; use async_trait::async_trait; -use cumulus_relay_chain_interface::RelayChainError; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_relay_chain_local::{check_block_in_chain, BlockCheckStatus}; use cumulus_test_service::runtime::{Block, Hash, Header}; use futures::{executor::block_on, poll, task::Poll, FutureExt, Stream, StreamExt}; @@ -94,15 +94,15 @@ impl RelayChainInterface for DummyRelayChainInterface { .map_err(|err| RelayChainError::BlockchainError(err.to_string())) } - async fn best_block_hash(&self) -> PHash { - self.relay_backend.blockchain().info().best_hash + async fn best_block_hash(&self) -> RelayChainResult { + Ok(self.relay_backend.blockchain().info().best_hash) } async fn retrieve_dmq_contents( &self, _: ParaId, _: PHash, - ) -> Option> { + ) -> RelayChainResult> { unimplemented!("Not needed for test") } @@ -110,8 +110,8 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: ParaId, _: PHash, - ) -> Option>> { - Some(BTreeMap::new()) + ) -> RelayChainResult>> { + Ok(BTreeMap::new()) } async fn persisted_validation_data( @@ -166,27 +166,31 @@ impl RelayChainInterface for DummyRelayChainInterface { Ok(0) } - async fn import_notification_stream(&self) -> Pin + Send>> { - Box::pin( + async fn import_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { + Ok(Box::pin( self.relay_client .import_notification_stream() .map(|notification| notification.header), - ) + )) } - async fn finality_notification_stream(&self) -> Pin + Send>> { - Box::pin( + async fn finality_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { + Ok(Box::pin( self.relay_client .finality_notification_stream() .map(|notification| notification.header), - ) + )) } - async fn is_major_syncing(&self) -> bool { - false + async fn is_major_syncing(&self) -> RelayChainResult { + Ok(false) } - fn overseer_handle(&self) -> Option { + fn overseer_handle(&self) -> RelayChainResult> { unimplemented!("Not needed for test") } @@ -202,7 +206,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &polkadot_service::BlockId, _: &Vec>, - ) -> Result, Box> { + ) -> Result, RelayChainError> { unimplemented!("Not needed for test") } @@ -231,7 +235,9 @@ impl RelayChainInterface for DummyRelayChainInterface { } } - async fn new_best_notification_stream(&self) -> Pin + Send>> { + async fn new_best_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let notifications_stream = self.relay_client .import_notification_stream() @@ -242,7 +248,7 @@ impl RelayChainInterface for DummyRelayChainInterface { None } }); - Box::pin(notifications_stream) + Ok(Box::pin(notifications_stream)) } } diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index f3708904e05..6aec6a5b30d 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -423,7 +423,8 @@ async fn pending_candidates( relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, ) -> impl Stream { - let stream = relay_chain_client.import_notification_stream().await; + // TODO: error handling + let stream = relay_chain_client.import_notification_stream().await.expect("should work"); stream.filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); async move { diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 0b7dac2f4b3..6b7a8788152 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -20,3 +20,4 @@ futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" derive_more = "0.99.2" async-trait = "0.1.52" +jsonrpsee-core = "0.7.0" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index bfb93f552b6..5457330fbf5 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -28,10 +28,12 @@ use sc_client_api::{blockchain::BlockStatus, StorageProof}; use futures::Stream; +use async_trait::async_trait; +use jsonrpsee_core::Error as JsonRPSeeError; use sp_api::ApiError; use sp_state_machine::StorageValue; -use async_trait::async_trait; +pub type RelayChainResult = Result; #[derive(Debug, derive_more::Display)] pub enum RelayChainError { @@ -50,10 +52,21 @@ pub enum RelayChainError { _1 )] WaitBlockchainError(PHash, sp_blockchain::Error), - #[display(fmt = "Error occures while calling relay chain method '{}' over the network ", _0)] - NetworkError(String), + #[display( + fmt = "Error occures while calling relay chain method '{}' over the network: {:?}", + _0, + _1 + )] + NetworkError(String, String), #[display(fmt = "Blockchain returned an error: {:?}", _0)] BlockchainError(String), + StateMachineError(String), +} + +impl From for RelayChainError { + fn from(error: ApiError) -> Self { + RelayChainError::ApiError(error) + } } /// Should be used for all interaction with the relay chain in cumulus. @@ -72,7 +85,7 @@ pub trait RelayChainInterface: Send + Sync { /// Get the status of a given block. async fn block_status(&self, block_id: BlockId) -> Result; - async fn best_block_hash(&self) -> PHash; + async fn best_block_hash(&self) -> Result; /// Returns the whole contents of the downward message queue for the parachain we are collating /// for. @@ -82,7 +95,7 @@ pub trait RelayChainInterface: Send + Sync { &self, para_id: ParaId, relay_parent: PHash, - ) -> Option>; + ) -> Result, RelayChainError>; /// Returns channels contents for each inbound HRMP channel addressed to the parachain we are /// collating for. @@ -92,7 +105,7 @@ pub trait RelayChainInterface: Send + Sync { &self, para_id: ParaId, relay_parent: PHash, - ) -> Option>>; + ) -> Result>, RelayChainError>; /// Yields the persisted validation data for the given `ParaId` along with an assumption that /// should be used if the para currently occupies a core. @@ -121,10 +134,14 @@ pub trait RelayChainInterface: Send + Sync { ) -> Result; /// Get a stream of import block notifications. - async fn import_notification_stream(&self) -> Pin + Send>>; + async fn import_notification_stream( + &self, + ) -> Result + Send>>, RelayChainError>; /// Get a stream of new best block notifications. - async fn new_best_notification_stream(&self) -> Pin + Send>>; + async fn new_best_notification_stream( + &self, + ) -> Result + Send>>, RelayChainError>; /// Wait for a block with a given hash in the relay chain. /// @@ -133,21 +150,23 @@ pub trait RelayChainInterface: Send + Sync { async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError>; /// Get a stream of finality notifications. - async fn finality_notification_stream(&self) -> Pin + Send>>; + async fn finality_notification_stream( + &self, + ) -> Result + Send>>, RelayChainError>; /// Whether the synchronization service is undergoing major sync. /// Returns true if so. - async fn is_major_syncing(&self) -> bool; + async fn is_major_syncing(&self) -> Result; /// Get a handle to the overseer. - fn overseer_handle(&self) -> Option; + fn overseer_handle(&self) -> Result, RelayChainError>; /// Generate a storage read proof. async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, Box>; + ) -> Result, RelayChainError>; } #[async_trait] @@ -159,7 +178,7 @@ where &self, para_id: ParaId, relay_parent: PHash, - ) -> Option> { + ) -> RelayChainResult> { (**self).retrieve_dmq_contents(para_id, relay_parent).await } @@ -167,7 +186,7 @@ where &self, para_id: ParaId, relay_parent: PHash, - ) -> Option>> { + ) -> RelayChainResult>> { (**self).retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent).await } @@ -176,7 +195,7 @@ where block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { (**self) .persisted_validation_data(block_id, para_id, occupied_core_assumption) .await @@ -201,15 +220,19 @@ where (**self).validators(block_id).await } - async fn import_notification_stream(&self) -> Pin + Send>> { + async fn import_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { (**self).import_notification_stream().await } - async fn finality_notification_stream(&self) -> Pin + Send>> { + async fn finality_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { (**self).finality_notification_stream().await } - async fn best_block_hash(&self) -> PHash { + async fn best_block_hash(&self) -> RelayChainResult { (**self).best_block_hash().await } @@ -217,11 +240,11 @@ where (**self).block_status(block_id).await } - async fn is_major_syncing(&self) -> bool { + async fn is_major_syncing(&self) -> RelayChainResult { (**self).is_major_syncing().await } - fn overseer_handle(&self) -> Option { + fn overseer_handle(&self) -> RelayChainResult> { (**self).overseer_handle() } @@ -237,15 +260,17 @@ where &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, Box> { + ) -> RelayChainResult> { (**self).prove_read(block_id, relevant_keys).await } - async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { + async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> { (**self).wait_for_block(hash).await } - async fn new_best_notification_stream(&self) -> Pin + Send>> { + async fn new_best_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { (**self).new_best_notification_stream().await } } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 9cdc6eace79..15c021e99a2 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; use futures::{FutureExt, Stream, StreamExt}; use parking_lot::Mutex; use polkadot_client::{ClientHandle, ExecuteWithClient, FullBackend}; @@ -92,7 +92,7 @@ where &self, para_id: ParaId, relay_parent: PHash, - ) -> Option> { + ) -> RelayChainResult> { self.full_client .runtime_api() .dmq_contents_with_context( @@ -107,15 +107,15 @@ where error = ?e, "An error occured during requesting the downward messages.", ); + RelayChainError::ApiError(e) }) - .ok() } async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, - ) -> Option>> { + ) -> RelayChainResult>> { self.full_client .runtime_api() .inbound_hrmp_channels_contents_with_context( @@ -130,8 +130,8 @@ where error = ?e, "An error occured during requesting the inbound HRMP messages.", ); + RelayChainError::ApiError(e) }) - .ok() } async fn persisted_validation_data( @@ -174,24 +174,28 @@ where .map_err(RelayChainError::ApiError) } - async fn import_notification_stream(&self) -> Pin + Send>> { + async fn import_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let notification_stream = self .full_client .import_notification_stream() .map(|notification| notification.header); - Box::pin(notification_stream) + Ok(Box::pin(notification_stream)) } - async fn finality_notification_stream(&self) -> Pin + Send>> { + async fn finality_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let notification_stream = self .full_client .finality_notification_stream() .map(|notification| notification.header); - Box::pin(notification_stream) + Ok(Box::pin(notification_stream)) } - async fn best_block_hash(&self) -> PHash { - self.backend.blockchain().info().best_hash + async fn best_block_hash(&self) -> RelayChainResult { + Ok(self.backend.blockchain().info().best_hash) } async fn block_status(&self, block_id: BlockId) -> Result { @@ -201,13 +205,13 @@ where .map_err(|err| RelayChainError::BlockchainError(err.to_string())) } - async fn is_major_syncing(&self) -> bool { + async fn is_major_syncing(&self) -> RelayChainResult { let mut network = self.sync_oracle.lock(); - network.is_major_syncing() + Ok(network.is_major_syncing()) } - fn overseer_handle(&self) -> Option { - self.overseer_handle.clone() + fn overseer_handle(&self) -> RelayChainResult> { + Ok(self.overseer_handle.clone()) } async fn get_storage_by_key( @@ -226,7 +230,7 @@ where &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, Box> { + ) -> Result, RelayChainError> { let state_backend = self .backend .state_at(*block_id) @@ -249,7 +253,7 @@ where error = ?e, "Failed to collect required relay chain state storage proof.", ); - e + RelayChainError::StateMachineError(e.to_string()) }) .map(Some), None => Ok(None), @@ -295,7 +299,9 @@ where } } - async fn new_best_notification_stream(&self) -> Pin + Send>> { + async fn new_best_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let notifications_stream = self.full_client .import_notification_stream() @@ -306,7 +312,7 @@ where None } }); - Box::pin(notifications_stream) + Ok(Box::pin(notifications_stream)) } } diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 52b7614967b..4f619575e28 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -25,7 +25,7 @@ use cumulus_primitives_core::{ }, InboundDownwardMessage, ParaId, PersistedValidationData, }; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; use futures::{FutureExt, Stream, StreamExt}; use jsonrpsee::{ core::{ @@ -64,14 +64,16 @@ impl RelayChainRPCClient { method_name: &str, block_id: &BlockId, payload: Option>, - ) -> Result { + ) -> Result { let payload_bytes = payload.map_or(sp_core::Bytes(Vec::new()), sp_core::Bytes); let params = rpc_params! { method_name, payload_bytes, block_id }; - self.request("state_call", params).await + self.request("state_call", params) + .await + .map_err(|err| RelayChainError::NetworkError(method_name.to_string(), err.to_string())) } async fn subscribe<'a, R>( @@ -79,27 +81,33 @@ impl RelayChainRPCClient { sub_name: &'a str, unsub_name: &'a str, params: Option>, - ) -> Result, JsonRPSeeError> + ) -> Result, RelayChainError> where R: DeserializeOwned, { tracing::trace!(target: LOG_TARGET, "Subscribing to stream: {}", sub_name); - self.ws_client.subscribe::(sub_name, params, unsub_name).await + self.ws_client + .subscribe::(sub_name, params, unsub_name) + .await + .map_err(|err| RelayChainError::NetworkError(sub_name.to_string(), err.to_string())) } async fn request<'a, R>( &self, method: &'a str, params: Option>, - ) -> Result + ) -> Result where R: DeserializeOwned, { tracing::trace!(target: LOG_TARGET, "Calling rpc endpoint: {}", method); - self.ws_client.request(method, params).await + self.ws_client + .request(method, params) + .await + .map_err(|err| RelayChainError::NetworkError(method.to_string(), err.to_string())) } - async fn system_health(&self) -> Result { + async fn system_health(&self) -> Result { self.request("system_health", None).await } @@ -107,7 +115,7 @@ impl RelayChainRPCClient { &self, storage_keys: Vec, at: Option, - ) -> Result>, JsonRPSeeError> { + ) -> Result>, RelayChainError> { let params = rpc_params!(storage_keys, at); self.request("state_getReadProof", params).await } @@ -116,7 +124,7 @@ impl RelayChainRPCClient { &self, storage_key: StorageKey, at: Option, - ) -> Result, JsonRPSeeError> { + ) -> Result, RelayChainError> { let params = rpc_params!(storage_key, at); self.request("state_getStorage", params).await } @@ -124,19 +132,19 @@ impl RelayChainRPCClient { async fn chain_get_block( &self, at: Option, - ) -> Result>, JsonRPSeeError> { + ) -> Result>, RelayChainError> { let params = rpc_params!(at); self.request("chain_getBlock", params).await } - async fn chain_get_head(&self) -> Result { + async fn chain_get_head(&self) -> Result { self.request("chain_getHead", None).await } async fn chain_get_header( &self, hash: Option, - ) -> Result, JsonRPSeeError> { + ) -> Result, RelayChainError> { let params = hash.map(|hash| rpc_params!(hash)).flatten(); self.request("chain_getHeader", params).await } @@ -145,7 +153,7 @@ impl RelayChainRPCClient { &self, at: &BlockId, para_id: ParaId, - ) -> Result, JsonRPSeeError> { + ) -> Result, RelayChainError> { let response_bytes = self .call_remote_runtime_function( "ParachainHost_candidate_pending_availability", @@ -161,7 +169,7 @@ impl RelayChainRPCClient { async fn parachain_host_session_index_for_child( &self, at: &BlockId, - ) -> Result { + ) -> Result { let response_bytes = self .call_remote_runtime_function("ParachainHost_session_index_for_child", at, None) .await?; @@ -172,7 +180,7 @@ impl RelayChainRPCClient { async fn parachain_host_validators( &self, at: &BlockId, - ) -> Result, JsonRPSeeError> { + ) -> Result, RelayChainError> { let response_bytes = self.call_remote_runtime_function("ParachainHost_validators", at, None).await?; @@ -184,7 +192,7 @@ impl RelayChainRPCClient { block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, JsonRPSeeError> { + ) -> Result, RelayChainError> { let response_bytes = self .call_remote_runtime_function( "ParachainHost_persisted_validation_data", @@ -201,7 +209,7 @@ impl RelayChainRPCClient { &self, para_id: ParaId, at: &BlockId, - ) -> Result>>, JsonRPSeeError> { + ) -> Result>, RelayChainError> { let response_bytes = self .call_remote_runtime_function( "ParachainHost_inbound_hrmp_channels_contents", @@ -210,7 +218,7 @@ impl RelayChainRPCClient { ) .await?; - Ok(Option::>>::decode(&mut &*response_bytes.0) + Ok(BTreeMap::>::decode(&mut &*response_bytes.0) .expect("should deserialize")) } @@ -218,26 +226,26 @@ impl RelayChainRPCClient { &self, para_id: ParaId, at: &BlockId, - ) -> Result>, JsonRPSeeError> { + ) -> Result, RelayChainError> { let response_bytes = self .call_remote_runtime_function("ParachainHost_dmq_contents", &at, Some(para_id.encode())) .await?; - Ok(Option::>::decode(&mut &*response_bytes.0) + Ok(Vec::::decode(&mut &*response_bytes.0) .expect("should deserialize")) } - async fn subscribe_all_heads(&self) -> Result, JsonRPSeeError> { + async fn subscribe_all_heads(&self) -> Result, RelayChainError> { self.subscribe::("chain_subscribeAllHeads", "chain_unsubscribeAllHeads", None) .await } - async fn subscribe_new_best_heads(&self) -> Result, JsonRPSeeError> { + async fn subscribe_new_best_heads(&self) -> Result, RelayChainError> { self.subscribe::("chain_subscribeNewHeads", "chain_unsubscribeNewHeads", None) .await } - async fn subscribe_finalized_heads(&self) -> Result, JsonRPSeeError> { + async fn subscribe_finalized_heads(&self) -> Result, RelayChainError> { self.subscribe::( "chain_subscribeFinalizedHeads", "chain_unsubscribeFinalizedHeads", @@ -271,25 +279,25 @@ impl RelayChainInterface for RelayChainNetwork { &self, para_id: ParaId, relay_parent: PHash, - ) -> Option> { + ) -> RelayChainResult> { let block_id = BlockId::hash(relay_parent); let response = self.rpc_client.parachain_host_dmq_contents(para_id, &block_id).await; - response.expect("nope") + response } async fn retrieve_all_inbound_hrmp_channel_contents( &self, para_id: ParaId, relay_parent: PHash, - ) -> Option>> { + ) -> RelayChainResult>> { let block_id = BlockId::hash(relay_parent); let response = self .rpc_client .parachain_host_inbound_hrmp_channels_contents(para_id, &block_id) .await; - response.expect("nope") + response } async fn persisted_validation_data( @@ -303,7 +311,7 @@ impl RelayChainInterface for RelayChainNetwork { .parachain_host_persisted_validation_data(block_id, para_id, occupied_core_assumption) .await; - Ok(response.expect("nope")) + response } async fn candidate_pending_availability( @@ -316,7 +324,7 @@ impl RelayChainInterface for RelayChainNetwork { .parachain_host_candidate_pending_availability(block_id, para_id) .await; - Ok(response.expect("nope")) + response } async fn session_index_for_child( @@ -325,48 +333,47 @@ impl RelayChainInterface for RelayChainNetwork { ) -> Result { let response = self.rpc_client.parachain_host_session_index_for_child(block_id).await; - Ok(response.expect("nope")) + response } async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { let response = self.rpc_client.parachain_host_validators(block_id).await; - Ok(response.expect("nope")) + response } - async fn import_notification_stream(&self) -> Pin + Send>> { - let imported_headers_stream = self - .rpc_client - .subscribe_all_heads() - .await - .expect("Should be able to subscribe"); - - Box::pin(imported_headers_stream.filter_map(|item| async move { + async fn import_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { + let imported_headers_stream = self.rpc_client.subscribe_all_heads().await?; + Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { item.map_err(|err| { tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) }) .ok() - })) + }))) } - async fn finality_notification_stream(&self) -> Pin + Send>> { + async fn finality_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let imported_headers_stream = self .rpc_client .subscribe_finalized_heads() .await .expect("Should be able to subscribe"); - Box::pin(imported_headers_stream.filter_map(|item| async move { + Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { item.map_err(|err| { tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) }) .ok() - })) + }))) } - async fn best_block_hash(&self) -> PHash { + async fn best_block_hash(&self) -> RelayChainResult { let response = self.rpc_client.chain_get_head().await; - response.expect("nope") + response } async fn block_status(&self, block_id: BlockId) -> Result { @@ -376,18 +383,17 @@ impl RelayChainInterface for RelayChainNetwork { }; let response = self.rpc_client.chain_get_block(Some(hash.clone())).await; - match response.expect("nope") { - Some(_) => Ok(BlockStatus::InChain), - None => Ok(BlockStatus::Unknown), + match response { + Ok(Some(_)) => Ok(BlockStatus::InChain), + _ => Ok(BlockStatus::Unknown), } } - async fn is_major_syncing(&self) -> bool { - let health = self.rpc_client.system_health().await.expect("Should be able to fetch health"); - health.is_syncing + async fn is_major_syncing(&self) -> RelayChainResult { + self.rpc_client.system_health().await.map(|h| h.is_syncing) } - fn overseer_handle(&self) -> Option { + fn overseer_handle(&self) -> RelayChainResult> { todo!("overseer_handle"); } @@ -403,14 +409,14 @@ impl RelayChainInterface for RelayChainNetwork { }; let response = self.rpc_client.state_get_storage(storage_key, Some(*hash)).await; - Ok(response.expect("nope").map(|v| v.0)) + response.map(|v| v.map(|sv| sv.0)) } async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, Box> { + ) -> RelayChainResult> { let cloned = relevant_keys.clone(); let storage_keys: Vec = cloned.into_iter().map(StorageKey).collect(); @@ -421,12 +427,14 @@ impl RelayChainInterface for RelayChainNetwork { let result = self.rpc_client.state_get_read_proof(storage_keys, Some(*hash)).await; - Ok(result.expect("nope").map(|read_proof| { - let bytes: Vec> = - read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); + result.map(|value| { + value.map(|read_proof| { + let bytes: Vec> = + read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); - StorageProof::new(bytes.to_vec()) - })) + StorageProof::new(bytes.to_vec()) + }) + }) } /// Wait for a given relay chain block @@ -439,11 +447,7 @@ impl RelayChainInterface for RelayChainNetwork { /// 3. Wait for the block to be imported via subscription. /// 4. If timeout is reached, we return an error. async fn wait_for_block(&self, wait_for_hash: PHash) -> Result<(), RelayChainError> { - let mut head_stream = self - .rpc_client - .subscribe_all_heads() - .await - .expect("Should be able to subscribe"); + let mut head_stream = self.rpc_client.subscribe_all_heads().await?; let block_header = self.rpc_client.chain_get_header(Some(wait_for_hash)).await; if block_header.ok().is_some() { @@ -465,18 +469,20 @@ impl RelayChainInterface for RelayChainNetwork { } } - async fn new_best_notification_stream(&self) -> Pin + Send>> { + async fn new_best_notification_stream( + &self, + ) -> RelayChainResult + Send>>> { let imported_headers_stream = self .rpc_client .subscribe_new_best_heads() .await .expect("Should be able to subscribe"); - Box::pin(imported_headers_stream.filter_map(|item| async move { + Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { item.map_err(|err| { tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) }) .ok() - })) + }))) } } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 925c957c6fd..6920e7120c2 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -107,9 +107,12 @@ where .spawn_essential_handle() .spawn("cumulus-consensus", None, consensus); + //TODO: error handling let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( relay_chain_interface .overseer_handle() + .ok() + .flatten() .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, slot_duration, client.clone(), @@ -122,12 +125,15 @@ where .spawn_essential_handle() .spawn("cumulus-pov-recovery", None, pov_recovery.run()); + //TODO: error handling cumulus_client_collator::start_collator(cumulus_client_collator::StartCollatorParams { runtime_api: client.clone(), block_status, announce_block, overseer_handle: relay_chain_interface .overseer_handle() + .ok() + .flatten() .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, spawner, para_id, diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index baebeaeef12..1ca72c3135d 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -129,11 +129,13 @@ impl ParachainInherentData { let relay_chain_state = collect_relay_storage_proof(&relay_chain_interface, para_id, relay_parent).await?; + //TODO: error handling let downward_messages = - relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent).await?; + relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent).await.ok()?; let horizontal_messages = relay_chain_interface .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) - .await?; + .await + .ok()?; Some(ParachainInherentData { downward_messages, From 5e03777b1dcc47d28bb0da4a841649dfd569e51d Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 17 Jan 2022 17:21:53 +0100 Subject: [PATCH 20/31] Fix return type of proof method --- client/relay-chain-network/src/lib.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs index 4f619575e28..69993eb4a82 100644 --- a/client/relay-chain-network/src/lib.rs +++ b/client/relay-chain-network/src/lib.rs @@ -115,7 +115,7 @@ impl RelayChainRPCClient { &self, storage_keys: Vec, at: Option, - ) -> Result>, RelayChainError> { + ) -> Result, RelayChainError> { let params = rpc_params!(storage_keys, at); self.request("state_getReadProof", params).await } @@ -145,7 +145,7 @@ impl RelayChainRPCClient { &self, hash: Option, ) -> Result, RelayChainError> { - let params = hash.map(|hash| rpc_params!(hash)).flatten(); + let params = rpc_params!(hash); self.request("chain_getHeader", params).await } @@ -427,13 +427,11 @@ impl RelayChainInterface for RelayChainNetwork { let result = self.rpc_client.state_get_read_proof(storage_keys, Some(*hash)).await; - result.map(|value| { - value.map(|read_proof| { - let bytes: Vec> = - read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); + result.map(|read_proof| { + let bytes: Vec> = + read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); - StorageProof::new(bytes.to_vec()) - }) + Some(StorageProof::new(bytes.to_vec())) }) } From d916d694a21dc066dba0d95ded1d1dca55f8bed1 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 17 Jan 2022 18:14:57 +0100 Subject: [PATCH 21/31] Improve error handling of new methods --- Cargo.lock | 266 ++----------- client/network/src/lib.rs | 17 +- client/pov-recovery/src/lib.rs | 22 +- client/relay-chain-interface/Cargo.toml | 1 - client/relay-chain-interface/src/lib.rs | 8 +- client/relay-chain-network/Cargo.toml | 37 -- client/relay-chain-network/src/lib.rs | 486 ------------------------ test/service/Cargo.toml | 1 - test/service/src/lib.rs | 3 - 9 files changed, 50 insertions(+), 791 deletions(-) delete mode 100644 client/relay-chain-network/Cargo.toml delete mode 100644 client/relay-chain-network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index e7f5199d1b7..37568ce3beb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1399,7 +1399,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1a816186fa68d9e426e3cb4ae4dff1fcd8e4a2c34b781bf7a822574a0d0aac8" dependencies = [ - "sct 0.6.1", + "sct", ] [[package]] @@ -1864,7 +1864,6 @@ dependencies = [ "cumulus-primitives-core", "derive_more", "futures 0.3.19", - "jsonrpsee-core", "parking_lot 0.11.2", "polkadot-overseer", "sc-client-api", @@ -1906,38 +1905,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "cumulus-relay-chain-network" -version = "0.1.0" -dependencies = [ - "async-trait", - "cumulus-primitives-core", - "cumulus-relay-chain-interface", - "futures 0.3.19", - "futures-timer", - "jsonrpsee 0.7.0", - "parity-scale-codec", - "parking_lot 0.11.2", - "polkadot-client", - "polkadot-service", - "sc-client-api", - "sc-consensus-babe", - "sc-network", - "sc-rpc-api", - "sc-service", - "sc-telemetry", - "sc-tracing", - "sp-api", - "sp-blockchain", - "sp-consensus", - "sp-core", - "sp-runtime", - "sp-state-machine", - "sp-storage", - "tracing", - "url 2.2.2", -] - [[package]] name = "cumulus-test-client" version = "0.1.0" @@ -2033,7 +2000,6 @@ dependencies = [ "cumulus-primitives-core", "cumulus-primitives-parachain-inherent", "cumulus-relay-chain-local", - "cumulus-relay-chain-network", "cumulus-test-relay-validation-worker-provider", "cumulus-test-runtime", "frame-system", @@ -2915,8 +2881,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a1387e07917c711fb4ee4f48ea0adb04a3c9739e53ef85bf43ae1edc2937a8b" dependencies = [ "futures-io", - "rustls 0.19.1", - "webpki 0.21.4", + "rustls", + "webpki", ] [[package]] @@ -3301,27 +3267,11 @@ dependencies = [ "futures-util", "hyper", "log", - "rustls 0.19.1", - "rustls-native-certs 0.5.0", - "tokio", - "tokio-rustls 0.22.0", - "webpki 0.21.4", -] - -[[package]] -name = "hyper-rustls" -version = "0.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" -dependencies = [ - "http", - "hyper", - "log", - "rustls 0.20.2", - "rustls-native-certs 0.6.1", + "rustls", + "rustls-native-certs", "tokio", - "tokio-rustls 0.23.2", - "webpki-roots 0.22.1", + "tokio-rustls", + "webpki", ] [[package]] @@ -3677,81 +3627,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373a33d987866ccfe1af4bc11b089dce941764313f9fd8b7cf13fcb51b72dc5" dependencies = [ "jsonrpsee-proc-macros", - "jsonrpsee-types 0.4.1", + "jsonrpsee-types", "jsonrpsee-utils", - "jsonrpsee-ws-client 0.4.1", -] - -[[package]] -name = "jsonrpsee" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726b6cb76e568aefc4cc127fdb39cb9d92c176f4df0385eaf8053f770351719c" -dependencies = [ - "jsonrpsee-core", - "jsonrpsee-http-client", - "jsonrpsee-types 0.7.0", - "jsonrpsee-ws-client 0.7.0", -] - -[[package]] -name = "jsonrpsee-client-transport" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bc39096d2bd470ecbd5ed96c8464e2b2c2ef7ec6f8cb9611604255608624773" -dependencies = [ - "futures 0.3.19", - "http", - "jsonrpsee-core", - "jsonrpsee-types 0.7.0", - "pin-project 1.0.10", - "soketto", - "thiserror", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "jsonrpsee-core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b863e5e86a11bfaf46bb3ab5aba184671bd62058e8e3ab741c3395904c7afbf3" -dependencies = [ - "anyhow", - "arrayvec 0.7.2", - "async-trait", - "beef", - "futures-channel", - "futures-util", - "hyper", - "jsonrpsee-types 0.7.0", - "rustc-hash", - "serde", - "serde_json", - "soketto", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "jsonrpsee-http-client" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ca9f9028b3a9cd3c7c5b876f037def9368c6ba6498fd2d3162bdbece1d0ef9" -dependencies = [ - "async-trait", - "hyper", - "hyper-rustls 0.23.0", - "jsonrpsee-core", - "jsonrpsee-types 0.7.0", - "rustc-hash", - "serde", - "serde_json", - "thiserror", - "tokio", - "tracing", + "jsonrpsee-ws-client", ] [[package]] @@ -3786,20 +3664,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "jsonrpsee-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e169725e476234f3f96079fb9d8a6d00226db602d3fa056f044994239a490d78" -dependencies = [ - "anyhow", - "beef", - "serde", - "serde_json", - "thiserror", - "tracing", -] - [[package]] name = "jsonrpsee-utils" version = "0.4.1" @@ -3808,7 +3672,7 @@ checksum = "0109c4f972058f3b1925b73a17210aff7b63b65967264d0045d15ee88fe84f0c" dependencies = [ "arrayvec 0.7.2", "beef", - "jsonrpsee-types 0.4.1", + "jsonrpsee-types", ] [[package]] @@ -3822,30 +3686,19 @@ dependencies = [ "fnv", "futures 0.3.19", "http", - "jsonrpsee-types 0.4.1", + "jsonrpsee-types", "log", "pin-project 1.0.10", - "rustls-native-certs 0.5.0", + "rustls-native-certs", "serde", "serde_json", "soketto", "thiserror", "tokio", - "tokio-rustls 0.22.0", + "tokio-rustls", "tokio-util", ] -[[package]] -name = "jsonrpsee-ws-client" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c97f67449d58b8d90ad57986d12dacab8fd594759ff64eb5e6b6e84e470db977" -dependencies = [ - "jsonrpsee-client-transport", - "jsonrpsee-core", - "jsonrpsee-types 0.7.0", -] - [[package]] name = "keccak" version = "0.1.0" @@ -4510,7 +4363,7 @@ dependencies = [ "rw-stream-sink", "soketto", "url 2.2.2", - "webpki-roots 0.21.1", + "webpki-roots", ] [[package]] @@ -8607,7 +8460,7 @@ version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#fb24fda76d613305ebb2e5728c75362c94b64aa1" dependencies = [ "env_logger 0.9.0", - "jsonrpsee 0.4.1", + "jsonrpsee", "log", "parity-scale-codec", "serde", @@ -8887,20 +8740,8 @@ dependencies = [ "base64", "log", "ring", - "sct 0.6.1", - "webpki 0.21.4", -] - -[[package]] -name = "rustls" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" -dependencies = [ - "log", - "ring", - "sct 0.7.0", - "webpki 0.22.0", + "sct", + "webpki", ] [[package]] @@ -8910,32 +8751,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092" dependencies = [ "openssl-probe", - "rustls 0.19.1", - "schannel", - "security-framework", -] - -[[package]] -name = "rustls-native-certs" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca9ebdfa27d3fc180e42879037b5338ab1c040c06affd00d8338598e7800943" -dependencies = [ - "openssl-probe", - "rustls-pemfile", + "rustls", "schannel", "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" -dependencies = [ - "base64", -] - [[package]] name = "rustversion" version = "1.0.5" @@ -9594,7 +9414,7 @@ dependencies = [ "futures-timer", "hex", "hyper", - "hyper-rustls 0.22.1", + "hyper-rustls", "num_cpus", "once_cell", "parity-scale-codec", @@ -9995,16 +9815,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "secrecy" version = "0.8.0" @@ -11733,20 +11543,9 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "rustls 0.19.1", + "rustls", "tokio", - "webpki 0.21.4", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" -dependencies = [ - "rustls 0.20.2", - "tokio", - "webpki 0.22.0", + "webpki", ] [[package]] @@ -11952,7 +11751,7 @@ name = "try-runtime-cli" version = "0.10.0-dev" source = "git+https://github.com/paritytech/substrate?branch=master#fb24fda76d613305ebb2e5728c75362c94b64aa1" dependencies = [ - "jsonrpsee 0.4.1", + "jsonrpsee", "log", "parity-scale-codec", "remote-externalities", @@ -12505,32 +12304,13 @@ dependencies = [ "untrusted", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "webpki-roots" version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "webpki 0.21.4", -] - -[[package]] -name = "webpki-roots" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c475786c6f47219345717a043a37ec04cb4bc185e28853adcc4fa0a947eba630" -dependencies = [ - "webpki 0.22.0", + "webpki", ] [[package]] diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index dc2aeef183e..154a41dad58 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -290,8 +290,10 @@ where async move { // Check if block is equal or higher than best (this requires a justification) - // TODO: error handling - let relay_chain_best_hash = relay_chain_interface.best_block_hash().await.expect(""); + let relay_chain_best_hash = relay_chain_interface + .best_block_hash() + .await + .map_err(|e| Box::new(e) as Box<_>)?; let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); let block_number = header.number(); @@ -343,8 +345,15 @@ where let block_announce_validator = self.clone(); async move { - // TODO: Error handling - if relay_chain_interface.is_major_syncing().await.expect("") { + let relay_chain_is_syncing = relay_chain_interface + .is_major_syncing() + .await + .map_err(|e| { + tracing::error!(target: LOG_TARGET, "Unable to determine sync status. {}", e) + }) + .unwrap_or(false); + + if relay_chain_is_syncing { return Ok(Validation::Success { is_new_best: false }) } diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 6aec6a5b30d..7151dba8337 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -57,7 +57,7 @@ use polkadot_primitives::v1::{ }; use cumulus_primitives_core::ParachainBlockData; -use cumulus_relay_chain_interface::RelayChainInterface; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; use codec::Decode; use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt}; @@ -363,9 +363,14 @@ where let mut imported_blocks = self.parachain_client.import_notification_stream().fuse(); let mut finalized_blocks = self.parachain_client.finality_notification_stream().fuse(); let pending_candidates = - pending_candidates(self.relay_chain_interface.clone(), self.para_id) - .await - .fuse(); + match pending_candidates(self.relay_chain_interface.clone(), self.para_id).await { + Ok(pending_candidate_stream) => pending_candidate_stream.fuse(), + Err(err) => { + tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve pending candidate stream."); + return + }, + }; + futures::pin_mut!(pending_candidates); loop { @@ -422,10 +427,9 @@ where async fn pending_candidates( relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, -) -> impl Stream { - // TODO: error handling - let stream = relay_chain_client.import_notification_stream().await.expect("should work"); - stream.filter_map(move |n| { +) -> Result, RelayChainError> { + let stream = relay_chain_client.import_notification_stream().await?; + Ok(stream.filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); async move { let block_id = BlockId::hash(n.hash()); @@ -444,5 +448,5 @@ async fn pending_candidates( .ok() .flatten() } - }) + })) } diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 6b7a8788152..0b7dac2f4b3 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -20,4 +20,3 @@ futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" derive_more = "0.99.2" async-trait = "0.1.52" -jsonrpsee-core = "0.7.0" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 5457330fbf5..bece95cef8d 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -29,7 +29,6 @@ use sc_client_api::{blockchain::BlockStatus, StorageProof}; use futures::Stream; use async_trait::async_trait; -use jsonrpsee_core::Error as JsonRPSeeError; use sp_api::ApiError; use sp_state_machine::StorageValue; @@ -52,16 +51,11 @@ pub enum RelayChainError { _1 )] WaitBlockchainError(PHash, sp_blockchain::Error), - #[display( - fmt = "Error occures while calling relay chain method '{}' over the network: {:?}", - _0, - _1 - )] - NetworkError(String, String), #[display(fmt = "Blockchain returned an error: {:?}", _0)] BlockchainError(String), StateMachineError(String), } +impl std::error::Error for RelayChainError {} impl From for RelayChainError { fn from(error: ApiError) -> Self { diff --git a/client/relay-chain-network/Cargo.toml b/client/relay-chain-network/Cargo.toml deleted file mode 100644 index dbcc23d4a90..00000000000 --- a/client/relay-chain-network/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -authors = ["Parity Technologies "] -name = "cumulus-relay-chain-network" -version = "0.1.0" -edition = "2021" - - -[dependencies] -polkadot-client = { git = "https://github.com/paritytech/polkadot", branch = "master" } -polkadot-service = { git = "https://github.com/paritytech/polkadot", branch = "master" } - -cumulus-primitives-core = { path = "../../primitives/core" } -cumulus-relay-chain-interface = { path = "../relay-chain-interface" } - -sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-consensus-babe = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-telemetry = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-tracing = { git = "https://github.com/paritytech/substrate", branch = "master" } -sp-storage = { git = "https://github.com/paritytech/substrate", branch = "master" } -sc-rpc-api = { git = "https://github.com/paritytech/substrate", branch = "master" } - -futures = { version = "0.3.1", features = ["compat"] } -futures-timer = "3.0.2" -parity-scale-codec = "2.3.1" -parking_lot = "0.11.1" -jsonrpsee = {version = "0.7.0", features = ["client"]} -tracing = "0.1.25" -async-trait = "0.1.52" -url = "2.2.2" diff --git a/client/relay-chain-network/src/lib.rs b/client/relay-chain-network/src/lib.rs deleted file mode 100644 index 69993eb4a82..00000000000 --- a/client/relay-chain-network/src/lib.rs +++ /dev/null @@ -1,486 +0,0 @@ -// Copyright 2021 Parity Technologies (UK) Ltd. -// This file is part of Cumulus. - -// Cumulus 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. - -// Cumulus 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 Cumulus. If not, see . - -use std::pin::Pin; - -use async_trait::async_trait; -use core::time::Duration; -use cumulus_primitives_core::{ - relay_chain::{ - v1::{CommittedCandidateReceipt, OccupiedCoreAssumption, SessionIndex, ValidatorId}, - Block as PBlock, BlockId, Hash as PHash, Header as PHeader, InboundHrmpMessage, - }, - InboundDownwardMessage, ParaId, PersistedValidationData, -}; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; -use futures::{FutureExt, Stream, StreamExt}; -use jsonrpsee::{ - core::{ - client::{Client as JsonRPCClient, ClientT, Subscription, SubscriptionClientT}, - Error as JsonRPSeeError, - }, - rpc_params, - types::ParamsSer, - ws_client::WsClientBuilder, -}; -use parity_scale_codec::{Decode, Encode}; -use polkadot_service::Handle; -use sc_client_api::{blockchain::BlockStatus, StorageData, StorageProof}; -use sc_rpc_api::{state::ReadProof, system::Health}; -use sp_core::sp_std::collections::btree_map::BTreeMap; -use sp_runtime::{generic::SignedBlock, DeserializeOwned}; -use sp_state_machine::StorageValue; -use sp_storage::StorageKey; -use std::sync::Arc; - -pub use url::Url; - -const LOG_TARGET: &str = "relay-chain-network"; -const TIMEOUT_IN_SECONDS: u64 = 6; - -#[derive(Clone)] -struct RelayChainRPCClient { - ws_client: Arc, -} - -/// Client that calls RPC endpoints and deserializes call results -impl RelayChainRPCClient { - /// Call a runtime function via rpc - async fn call_remote_runtime_function( - &self, - method_name: &str, - block_id: &BlockId, - payload: Option>, - ) -> Result { - let payload_bytes = payload.map_or(sp_core::Bytes(Vec::new()), sp_core::Bytes); - let params = rpc_params! { - method_name, - payload_bytes, - block_id - }; - self.request("state_call", params) - .await - .map_err(|err| RelayChainError::NetworkError(method_name.to_string(), err.to_string())) - } - - async fn subscribe<'a, R>( - &self, - sub_name: &'a str, - unsub_name: &'a str, - params: Option>, - ) -> Result, RelayChainError> - where - R: DeserializeOwned, - { - tracing::trace!(target: LOG_TARGET, "Subscribing to stream: {}", sub_name); - self.ws_client - .subscribe::(sub_name, params, unsub_name) - .await - .map_err(|err| RelayChainError::NetworkError(sub_name.to_string(), err.to_string())) - } - - async fn request<'a, R>( - &self, - method: &'a str, - params: Option>, - ) -> Result - where - R: DeserializeOwned, - { - tracing::trace!(target: LOG_TARGET, "Calling rpc endpoint: {}", method); - self.ws_client - .request(method, params) - .await - .map_err(|err| RelayChainError::NetworkError(method.to_string(), err.to_string())) - } - - async fn system_health(&self) -> Result { - self.request("system_health", None).await - } - - async fn state_get_read_proof( - &self, - storage_keys: Vec, - at: Option, - ) -> Result, RelayChainError> { - let params = rpc_params!(storage_keys, at); - self.request("state_getReadProof", params).await - } - - async fn state_get_storage( - &self, - storage_key: StorageKey, - at: Option, - ) -> Result, RelayChainError> { - let params = rpc_params!(storage_key, at); - self.request("state_getStorage", params).await - } - - async fn chain_get_block( - &self, - at: Option, - ) -> Result>, RelayChainError> { - let params = rpc_params!(at); - self.request("chain_getBlock", params).await - } - - async fn chain_get_head(&self) -> Result { - self.request("chain_getHead", None).await - } - - async fn chain_get_header( - &self, - hash: Option, - ) -> Result, RelayChainError> { - let params = rpc_params!(hash); - self.request("chain_getHeader", params).await - } - - async fn parachain_host_candidate_pending_availability( - &self, - at: &BlockId, - para_id: ParaId, - ) -> Result, RelayChainError> { - let response_bytes = self - .call_remote_runtime_function( - "ParachainHost_candidate_pending_availability", - at, - Some(para_id.encode()), - ) - .await?; - - Ok(Option::>::decode(&mut &*response_bytes.0) - .expect("should deserialize")) - } - - async fn parachain_host_session_index_for_child( - &self, - at: &BlockId, - ) -> Result { - let response_bytes = self - .call_remote_runtime_function("ParachainHost_session_index_for_child", at, None) - .await?; - - Ok(SessionIndex::decode(&mut &*response_bytes.0).expect("should deserialize")) - } - - async fn parachain_host_validators( - &self, - at: &BlockId, - ) -> Result, RelayChainError> { - let response_bytes = - self.call_remote_runtime_function("ParachainHost_validators", at, None).await?; - - Ok(Vec::::decode(&mut &*response_bytes.0).expect("should deserialize")) - } - - async fn parachain_host_persisted_validation_data( - &self, - block_id: &BlockId, - para_id: ParaId, - occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, RelayChainError> { - let response_bytes = self - .call_remote_runtime_function( - "ParachainHost_persisted_validation_data", - block_id, - Some((para_id, occupied_core_assumption).encode()), - ) - .await?; - - Ok(Option::::decode(&mut &*response_bytes.0) - .expect("should deserialize")) - } - - async fn parachain_host_inbound_hrmp_channels_contents( - &self, - para_id: ParaId, - at: &BlockId, - ) -> Result>, RelayChainError> { - let response_bytes = self - .call_remote_runtime_function( - "ParachainHost_inbound_hrmp_channels_contents", - &at, - Some(para_id.encode()), - ) - .await?; - - Ok(BTreeMap::>::decode(&mut &*response_bytes.0) - .expect("should deserialize")) - } - - async fn parachain_host_dmq_contents( - &self, - para_id: ParaId, - at: &BlockId, - ) -> Result, RelayChainError> { - let response_bytes = self - .call_remote_runtime_function("ParachainHost_dmq_contents", &at, Some(para_id.encode())) - .await?; - - Ok(Vec::::decode(&mut &*response_bytes.0) - .expect("should deserialize")) - } - - async fn subscribe_all_heads(&self) -> Result, RelayChainError> { - self.subscribe::("chain_subscribeAllHeads", "chain_unsubscribeAllHeads", None) - .await - } - - async fn subscribe_new_best_heads(&self) -> Result, RelayChainError> { - self.subscribe::("chain_subscribeNewHeads", "chain_unsubscribeNewHeads", None) - .await - } - - async fn subscribe_finalized_heads(&self) -> Result, RelayChainError> { - self.subscribe::( - "chain_subscribeFinalizedHeads", - "chain_unsubscribeFinalizedHeads", - None, - ) - .await - } -} - -/// RelayChainNetwork is used to interact with a full node that is running locally -/// in the same process. -#[derive(Clone)] -pub struct RelayChainNetwork { - rpc_client: RelayChainRPCClient, -} - -impl RelayChainNetwork { - pub async fn new(url: Url) -> Self { - let ws_client = WsClientBuilder::default() - .build(url.as_str()) - .await - .expect("Should be able to initialize websocket client."); - - Self { rpc_client: RelayChainRPCClient { ws_client: Arc::new(ws_client) } } - } -} - -#[async_trait] -impl RelayChainInterface for RelayChainNetwork { - async fn retrieve_dmq_contents( - &self, - para_id: ParaId, - relay_parent: PHash, - ) -> RelayChainResult> { - let block_id = BlockId::hash(relay_parent); - let response = self.rpc_client.parachain_host_dmq_contents(para_id, &block_id).await; - - response - } - - async fn retrieve_all_inbound_hrmp_channel_contents( - &self, - para_id: ParaId, - relay_parent: PHash, - ) -> RelayChainResult>> { - let block_id = BlockId::hash(relay_parent); - let response = self - .rpc_client - .parachain_host_inbound_hrmp_channels_contents(para_id, &block_id) - .await; - - response - } - - async fn persisted_validation_data( - &self, - block_id: &BlockId, - para_id: ParaId, - occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, RelayChainError> { - let response = self - .rpc_client - .parachain_host_persisted_validation_data(block_id, para_id, occupied_core_assumption) - .await; - - response - } - - async fn candidate_pending_availability( - &self, - block_id: &BlockId, - para_id: ParaId, - ) -> Result, RelayChainError> { - let response = self - .rpc_client - .parachain_host_candidate_pending_availability(block_id, para_id) - .await; - - response - } - - async fn session_index_for_child( - &self, - block_id: &BlockId, - ) -> Result { - let response = self.rpc_client.parachain_host_session_index_for_child(block_id).await; - - response - } - - async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { - let response = self.rpc_client.parachain_host_validators(block_id).await; - - response - } - - async fn import_notification_stream( - &self, - ) -> RelayChainResult + Send>>> { - let imported_headers_stream = self.rpc_client.subscribe_all_heads().await?; - Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { - item.map_err(|err| { - tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) - }) - .ok() - }))) - } - - async fn finality_notification_stream( - &self, - ) -> RelayChainResult + Send>>> { - let imported_headers_stream = self - .rpc_client - .subscribe_finalized_heads() - .await - .expect("Should be able to subscribe"); - - Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { - item.map_err(|err| { - tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) - }) - .ok() - }))) - } - - async fn best_block_hash(&self) -> RelayChainResult { - let response = self.rpc_client.chain_get_head().await; - response - } - - async fn block_status(&self, block_id: BlockId) -> Result { - let hash = match block_id { - sp_api::BlockId::Hash(hash) => hash, - sp_api::BlockId::Number(_) => todo!(), - }; - - let response = self.rpc_client.chain_get_block(Some(hash.clone())).await; - match response { - Ok(Some(_)) => Ok(BlockStatus::InChain), - _ => Ok(BlockStatus::Unknown), - } - } - - async fn is_major_syncing(&self) -> RelayChainResult { - self.rpc_client.system_health().await.map(|h| h.is_syncing) - } - - fn overseer_handle(&self) -> RelayChainResult> { - todo!("overseer_handle"); - } - - async fn get_storage_by_key( - &self, - block_id: &BlockId, - key: &[u8], - ) -> Result, RelayChainError> { - let storage_key = StorageKey(key.to_vec()); - let hash = match block_id { - sp_api::BlockId::Hash(hash) => hash, - sp_api::BlockId::Number(_) => todo!(), - }; - - let response = self.rpc_client.state_get_storage(storage_key, Some(*hash)).await; - response.map(|v| v.map(|sv| sv.0)) - } - - async fn prove_read( - &self, - block_id: &BlockId, - relevant_keys: &Vec>, - ) -> RelayChainResult> { - let cloned = relevant_keys.clone(); - let storage_keys: Vec = cloned.into_iter().map(StorageKey).collect(); - - let hash = match block_id { - sp_api::BlockId::Hash(hash) => hash, - sp_api::BlockId::Number(_) => todo!(), - }; - - let result = self.rpc_client.state_get_read_proof(storage_keys, Some(*hash)).await; - - result.map(|read_proof| { - let bytes: Vec> = - read_proof.proof.into_iter().map(|bytes| (*bytes).to_vec()).collect(); - - Some(StorageProof::new(bytes.to_vec())) - }) - } - - /// Wait for a given relay chain block - /// - /// The hash of the block to wait for is passed. We wait for the block to arrive or return after a timeout. - /// - /// Implementation: - /// 1. Register a listener to all new blocks. - /// 2. Check if the block is already in chain. If yes, succeed early. - /// 3. Wait for the block to be imported via subscription. - /// 4. If timeout is reached, we return an error. - async fn wait_for_block(&self, wait_for_hash: PHash) -> Result<(), RelayChainError> { - let mut head_stream = self.rpc_client.subscribe_all_heads().await?; - - let block_header = self.rpc_client.chain_get_header(Some(wait_for_hash)).await; - if block_header.ok().is_some() { - return Ok(()) - } - - let mut timeout = futures_timer::Delay::new(Duration::from_secs(TIMEOUT_IN_SECONDS)).fuse(); - - loop { - futures::select! { - _ = timeout => return Err(RelayChainError::WaitTimeout(wait_for_hash)), - evt = head_stream.next().fuse() => match evt { - Some(Ok(evt)) if evt.hash() == wait_for_hash => return Ok(()), - // Not the event we waited on. - Some(_) => continue, - None => return Err(RelayChainError::ImportListenerClosed(wait_for_hash)), - } - } - } - } - - async fn new_best_notification_stream( - &self, - ) -> RelayChainResult + Send>>> { - let imported_headers_stream = self - .rpc_client - .subscribe_new_best_heads() - .await - .expect("Should be able to subscribe"); - - Ok(Box::pin(imported_headers_stream.filter_map(|item| async move { - item.map_err(|err| { - tracing::error!(target: LOG_TARGET, "Error occured in stream: {}", err) - }) - .ok() - }))) - } -} diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index 489a7a36bb5..bacc606a760 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -52,7 +52,6 @@ cumulus-primitives-core = { path = "../../primitives/core" } cumulus-primitives-parachain-inherent = { path = "../../primitives/parachain-inherent" } cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } -cumulus-relay-chain-network = { path = "../../client/relay-chain-network" } cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } url = "2.2.2" diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index d43e5786e22..1fa529909ee 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -30,7 +30,6 @@ use cumulus_client_service::{ }; use cumulus_primitives_core::ParaId; use cumulus_relay_chain_local::RelayChainLocal; -use cumulus_relay_chain_network::RelayChainNetwork; use cumulus_test_runtime::{Hash, Header, NodeBlock as Block, RuntimeApi}; use parking_lot::Mutex; @@ -220,8 +219,6 @@ where let client = params.client.clone(); let backend = params.backend.clone(); - let relay_chain_url = url::Url::parse("http://localhost:9333").expect("should be valid url"); - // let relay_chain_interface = Arc::new(RelayChainNetwork::new(relay_chain_url)); let relay_chain_interface = Arc::new(RelayChainLocal::new( relay_chain_full_node.client.clone(), relay_chain_full_node.backend.clone(), From ee60f314409b5288e9ffe2dd6b9f03ba7309e031 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Jan 2022 11:40:54 +0100 Subject: [PATCH 22/31] Improve error handling and move logging outside of interface --- .../common/src/parachain_consensus.rs | 48 +++++++++----- client/consensus/common/src/tests.rs | 10 +-- client/consensus/relay-chain/src/lib.rs | 2 +- client/network/src/tests.rs | 4 +- client/relay-chain-interface/src/lib.rs | 8 ++- client/relay-chain-local/src/lib.rs | 66 ++++--------------- client/service/src/lib.rs | 2 - pallets/parachain-system/src/lib.rs | 2 +- .../parachain-inherent/src/client_side.rs | 33 ++++++++-- 9 files changed, 87 insertions(+), 88 deletions(-) diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index d0c9c031e07..b7e5196cf76 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see . use async_trait::async_trait; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, }; @@ -34,6 +34,8 @@ use futures::{select, FutureExt, Stream, StreamExt}; use std::{pin::Pin, sync::Arc}; +const LOG_TARGET: &str = "cumulus-consensus"; + /// Helper for the relay chain client. This is expected to be a lightweight handle like an `Arc`. #[async_trait] pub trait RelaychainClient: Clone + 'static { @@ -44,10 +46,10 @@ pub trait RelaychainClient: Clone + 'static { type HeadStream: Stream> + Send + Unpin; /// Get a stream of new best heads for the given parachain. - async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream; + async fn new_best_heads(&self, para_id: ParaId) -> RelayChainResult; /// Get a stream of finalized heads for the given parachain. - async fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream; + async fn finalized_heads(&self, para_id: ParaId) -> RelayChainResult; /// Returns the parachain head for the given `para_id` at the given block id. async fn parachain_head_at( @@ -68,7 +70,13 @@ where R: RelaychainClient, B: Backend, { - let mut finalized_heads = relay_chain.finalized_heads(para_id).await; + let mut finalized_heads = match relay_chain.finalized_heads(para_id).await { + Ok(finalized_heads_stream) => finalized_heads_stream, + Err(err) => { + tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve finalized heads stream."); + return + }, + }; loop { let finalized_head = if let Some(h) = finalized_heads.next().await { @@ -167,7 +175,14 @@ async fn follow_new_best( R: RelaychainClient, B: Backend, { - let mut new_best_heads = relay_chain.new_best_heads(para_id).await.fuse(); + let mut new_best_heads = match relay_chain.new_best_heads(para_id).await { + Ok(best_heads_stream) => best_heads_stream.fuse(), + Err(err) => { + tracing::error!(target: LOG_TARGET, error = ?err, "Unable to retrieve best heads stream."); + return + }, + }; + let mut imported_blocks = parachain.import_notification_stream().fuse(); // The unset best header of the parachain. Will be `Some(_)` when we have imported a relay chain // block before the parachain block it included. In this case we need to wait for this block to @@ -379,13 +394,12 @@ where type HeadStream = Pin> + Send>>; - async fn new_best_heads(&self, para_id: ParaId) -> Self::HeadStream { + async fn new_best_heads(&self, para_id: ParaId) -> RelayChainResult { let relay_chain = self.clone(); - //TODO: Error handling - self.new_best_notification_stream() - .await - .expect("") + let new_best_notification_stream = self + .new_best_notification_stream() + .await? .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { @@ -396,15 +410,16 @@ where .flatten() } }) - .boxed() + .boxed(); + Ok(new_best_notification_stream) } - async fn finalized_heads(&self, para_id: ParaId) -> Self::HeadStream { + async fn finalized_heads(&self, para_id: ParaId) -> RelayChainResult { let relay_chain = self.clone(); - self.finality_notification_stream() - .await - .expect("") + let finality_notification_stream = self + .finality_notification_stream() + .await? .filter_map(move |n| { let relay_chain = relay_chain.clone(); async move { @@ -415,7 +430,8 @@ where .flatten() } }) - .boxed() + .boxed(); + Ok(finality_notification_stream) } async fn parachain_head_at( diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index 48db6fbd4a2..54ffaf4a0ff 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -18,7 +18,7 @@ use crate::*; use async_trait::async_trait; use codec::Encode; -use cumulus_relay_chain_interface::RelayChainError; +use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; use cumulus_test_client::{ runtime::{Block, Header}, Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, @@ -74,7 +74,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { type HeadStream = Box> + Send + Unpin>; - async fn new_best_heads(&self, _: ParaId) -> Self::HeadStream { + async fn new_best_heads(&self, _: ParaId) -> RelayChainResult { let stream = self .inner .lock() @@ -83,10 +83,10 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { .take() .expect("Should only be called once"); - Box::new(stream.map(|v| v.encode())) + Ok(Box::new(stream.map(|v| v.encode()))) } - async fn finalized_heads(&self, _: ParaId) -> Self::HeadStream { + async fn finalized_heads(&self, _: ParaId) -> RelayChainResult { let stream = self .inner .lock() @@ -95,7 +95,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { .take() .expect("Should only be called once"); - Box::new(stream.map(|v| v.encode())) + Ok(Box::new(stream.map(|v| v.encode()))) } async fn parachain_head_at( diff --git a/client/consensus/relay-chain/src/lib.rs b/client/consensus/relay-chain/src/lib.rs index 7ab3ef28619..69a92175da1 100644 --- a/client/consensus/relay-chain/src/lib.rs +++ b/client/consensus/relay-chain/src/lib.rs @@ -176,7 +176,7 @@ where .propose( inherent_data, Default::default(), - //TODO: Fix this. + // TODO: Fix this. Duration::from_millis(500), // Set the block limit to 50% of the maximum PoV size. // diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 76106f2105e..5c1370bf35f 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -91,7 +91,7 @@ impl RelayChainInterface for DummyRelayChainInterface { self.relay_backend .blockchain() .status(block_id) - .map_err(|err| RelayChainError::BlockchainError(err.to_string())) + .map_err(RelayChainError::BlockchainError) } async fn best_block_hash(&self) -> RelayChainResult { @@ -206,7 +206,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &polkadot_service::BlockId, _: &Vec>, - ) -> Result, RelayChainError> { + ) -> Result { unimplemented!("Not needed for test") } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index bece95cef8d..7786a9bb5fa 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -52,8 +52,10 @@ pub enum RelayChainError { )] WaitBlockchainError(PHash, sp_blockchain::Error), #[display(fmt = "Blockchain returned an error: {:?}", _0)] - BlockchainError(String), + BlockchainError(sp_blockchain::Error), StateMachineError(String), + #[display(fmt = "Unspecified error occured: {:?}", _0)] + GenericError(String), } impl std::error::Error for RelayChainError {} @@ -160,7 +162,7 @@ pub trait RelayChainInterface: Send + Sync { &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, RelayChainError>; + ) -> Result; } #[async_trait] @@ -254,7 +256,7 @@ where &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> RelayChainResult> { + ) -> RelayChainResult { (**self).prove_read(block_id, relevant_keys).await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 15c021e99a2..c3598401c93 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -42,7 +42,6 @@ use sp_consensus::SyncOracle; use sp_core::{sp_std::collections::btree_map::BTreeMap, Pair}; use sp_state_machine::{Backend as StateBackend, StorageValue}; -const LOG_TARGET: &str = "relay-chain-local"; /// The timeout in seconds after that the waiting for a block should be aborted. const TIMEOUT_IN_SECONDS: u64 = 6; @@ -100,15 +99,7 @@ where sp_core::ExecutionContext::Importing, para_id, ) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - error = ?e, - "An error occured during requesting the downward messages.", - ); - RelayChainError::ApiError(e) - }) + .map_err(RelayChainError::ApiError) } async fn retrieve_all_inbound_hrmp_channel_contents( @@ -123,15 +114,7 @@ where sp_core::ExecutionContext::Importing, para_id, ) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?relay_parent, - error = ?e, - "An error occured during requesting the inbound HRMP messages.", - ); - RelayChainError::ApiError(e) - }) + .map_err(RelayChainError::ApiError) } async fn persisted_validation_data( @@ -202,7 +185,7 @@ where self.backend .blockchain() .status(block_id) - .map_err(|err| RelayChainError::BlockchainError(err.to_string())) + .map_err(RelayChainError::BlockchainError) } async fn is_major_syncing(&self) -> RelayChainResult { @@ -219,45 +202,20 @@ where block_id: &BlockId, key: &[u8], ) -> Result, RelayChainError> { - let state = self - .backend - .state_at(*block_id) - .map_err(|err| RelayChainError::BlockchainError(err.to_string()))?; - state.storage(key).map_err(RelayChainError::BlockchainError) + let state = self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; + state.storage(key).map_err(RelayChainError::GenericError) } async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result, RelayChainError> { - let state_backend = self - .backend - .state_at(*block_id) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?block_id, - error = ?e, - "Cannot obtain the state of the relay chain.", - ); - }) - .ok(); - - match state_backend { - Some(state) => sp_state_machine::prove_read(state, relevant_keys) - .map_err(|e| { - tracing::error!( - target: LOG_TARGET, - relay_parent = ?block_id, - error = ?e, - "Failed to collect required relay chain state storage proof.", - ); - RelayChainError::StateMachineError(e.to_string()) - }) - .map(Some), - None => Ok(None), - } + ) -> Result { + let state_backend = + self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; + + sp_state_machine::prove_read(state_backend, relevant_keys) + .map_err(|e| RelayChainError::StateMachineError(e.to_string())) } /// Wait for a given relay chain block in an async way. @@ -337,7 +295,7 @@ where let block_id = BlockId::Hash(hash); match backend.blockchain().status(block_id) { Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain), - Err(err) => return Err(RelayChainError::BlockchainError(err.to_string())), + Err(err) => return Err(RelayChainError::BlockchainError(err)), _ => {}, } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 6920e7120c2..cee9d0c0443 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -107,7 +107,6 @@ where .spawn_essential_handle() .spawn("cumulus-consensus", None, consensus); - //TODO: error handling let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( relay_chain_interface .overseer_handle() @@ -125,7 +124,6 @@ where .spawn_essential_handle() .spawn("cumulus-pov-recovery", None, pov_recovery.run()); - //TODO: error handling cumulus_client_collator::start_collator(cumulus_client_collator::StartCollatorParams { runtime_api: client.clone(), block_status, diff --git a/pallets/parachain-system/src/lib.rs b/pallets/parachain-system/src/lib.rs index 795f6e29aa9..eaeed7eac26 100644 --- a/pallets/parachain-system/src/lib.rs +++ b/pallets/parachain-system/src/lib.rs @@ -603,7 +603,7 @@ pub mod pallet { #[pallet::genesis_build] impl GenesisBuild for GenesisConfig { fn build(&self) { - //TODO: Remove after https://github.com/paritytech/cumulus/issues/479 + // TODO: Remove after https://github.com/paritytech/cumulus/issues/479 sp_io::storage::set(b":c", &[]); } } diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index 1ca72c3135d..5f2ac24586f 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -113,7 +113,15 @@ async fn collect_relay_storage_proof( relay_chain_interface .prove_read(&relay_parent_block_id, &relevant_keys) .await - .ok()? + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?relay_parent_block_id, + error = ?e, + "Cannot obtain read proof from relay chain.", + ); + }) + .ok() } impl ParachainInherentData { @@ -129,12 +137,29 @@ impl ParachainInherentData { let relay_chain_state = collect_relay_storage_proof(&relay_chain_interface, para_id, relay_parent).await?; - //TODO: error handling - let downward_messages = - relay_chain_interface.retrieve_dmq_contents(para_id, relay_parent).await.ok()?; + let downward_messages = relay_chain_interface + .retrieve_dmq_contents(para_id, relay_parent) + .await + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + error = ?e, + "An error occured during requesting the downward messages.", + ); + }) + .ok()?; let horizontal_messages = relay_chain_interface .retrieve_all_inbound_hrmp_channel_contents(para_id, relay_parent) .await + .map_err(|e| { + tracing::error!( + target: LOG_TARGET, + relay_parent = ?relay_parent, + error = ?e, + "An error occured during requesting the inbound HRMP messages.", + ); + }) .ok()?; Some(ParachainInherentData { From 0a1dd449f8c27a61f65d5ef7a56ce05ac6f137c0 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Jan 2022 12:20:51 +0100 Subject: [PATCH 23/31] Clean up --- .../common/src/parachain_consensus.rs | 6 +-- client/consensus/common/src/tests.rs | 2 +- client/network/src/tests.rs | 16 +++---- client/pov-recovery/src/lib.rs | 4 +- client/relay-chain-interface/src/lib.rs | 48 ++++++++----------- client/relay-chain-local/src/lib.rs | 21 ++++---- 6 files changed, 44 insertions(+), 53 deletions(-) diff --git a/client/consensus/common/src/parachain_consensus.rs b/client/consensus/common/src/parachain_consensus.rs index b7e5196cf76..6328681fd9f 100644 --- a/client/consensus/common/src/parachain_consensus.rs +++ b/client/consensus/common/src/parachain_consensus.rs @@ -15,7 +15,7 @@ // along with Cumulus. If not, see . use async_trait::async_trait; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface, RelayChainResult}; +use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult}; use sc_client_api::{ Backend, BlockBackend, BlockImportNotification, BlockchainEvents, Finalizer, UsageProvider, }; @@ -56,7 +56,7 @@ pub trait RelaychainClient: Clone + 'static { &self, at: &BlockId, para_id: ParaId, - ) -> Result>, RelayChainError>; + ) -> RelayChainResult>>; } /// Follow the finalized head of the given parachain. @@ -438,7 +438,7 @@ where &self, at: &BlockId, para_id: ParaId, - ) -> Result>, RelayChainError> { + ) -> RelayChainResult>> { self.persisted_validation_data(at, para_id, OccupiedCoreAssumption::TimedOut) .await .map(|s| s.map(|s| s.parent_head.0)) diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index 54ffaf4a0ff..8a234c4b06a 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -102,7 +102,7 @@ impl crate::parachain_consensus::RelaychainClient for Relaychain { &self, _: &BlockId, _: ParaId, - ) -> Result>, RelayChainError> { + ) -> RelayChainResult>> { unimplemented!("Not required for tests") } } diff --git a/client/network/src/tests.rs b/client/network/src/tests.rs index 5c1370bf35f..bd52fc0b93b 100644 --- a/client/network/src/tests.rs +++ b/client/network/src/tests.rs @@ -80,14 +80,14 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn validators( &self, _: &cumulus_primitives_core::relay_chain::BlockId, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { Ok(self.data.lock().validators.clone()) } async fn block_status( &self, block_id: cumulus_primitives_core::relay_chain::BlockId, - ) -> Result { + ) -> RelayChainResult { self.relay_backend .blockchain() .status(block_id) @@ -119,7 +119,7 @@ impl RelayChainInterface for DummyRelayChainInterface { _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, _: OccupiedCoreAssumption, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { Ok(Some(PersistedValidationData { parent_head: HeadData(default_header().encode()), ..Default::default() @@ -130,7 +130,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &cumulus_primitives_core::relay_chain::BlockId, _: ParaId, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { if self.data.lock().has_pending_availability { Ok(Some(CommittedCandidateReceipt { descriptor: CandidateDescriptor { @@ -162,7 +162,7 @@ impl RelayChainInterface for DummyRelayChainInterface { async fn session_index_for_child( &self, _: &cumulus_primitives_core::relay_chain::BlockId, - ) -> Result { + ) -> RelayChainResult { Ok(0) } @@ -198,7 +198,7 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &polkadot_service::BlockId, _: &[u8], - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { unimplemented!("Not needed for test") } @@ -206,11 +206,11 @@ impl RelayChainInterface for DummyRelayChainInterface { &self, _: &polkadot_service::BlockId, _: &Vec>, - ) -> Result { + ) -> RelayChainResult { unimplemented!("Not needed for test") } - async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { + async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> { let mut listener = match check_block_in_chain( self.relay_backend.clone(), self.relay_client.clone(), diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 7151dba8337..66d51644e1c 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -57,7 +57,7 @@ use polkadot_primitives::v1::{ }; use cumulus_primitives_core::ParachainBlockData; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainInterface}; +use cumulus_relay_chain_interface::{RelayChainInterface, RelayChainResult}; use codec::Decode; use futures::{select, stream::FuturesUnordered, Future, FutureExt, Stream, StreamExt}; @@ -427,7 +427,7 @@ where async fn pending_candidates( relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, -) -> Result, RelayChainError> { +) -> RelayChainResult> { let stream = relay_chain_client.import_notification_stream().await?; Ok(stream.filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 7786a9bb5fa..5503cd4819d 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -73,15 +73,15 @@ pub trait RelayChainInterface: Send + Sync { &self, block_id: &BlockId, key: &[u8], - ) -> Result, RelayChainError>; + ) -> RelayChainResult>; /// Fetch a vector of current validators. - async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError>; + async fn validators(&self, block_id: &BlockId) -> RelayChainResult>; /// Get the status of a given block. - async fn block_status(&self, block_id: BlockId) -> Result; + async fn block_status(&self, block_id: BlockId) -> RelayChainResult; - async fn best_block_hash(&self) -> Result; + async fn best_block_hash(&self) -> RelayChainResult; /// Returns the whole contents of the downward message queue for the parachain we are collating /// for. @@ -91,7 +91,7 @@ pub trait RelayChainInterface: Send + Sync { &self, para_id: ParaId, relay_parent: PHash, - ) -> Result, RelayChainError>; + ) -> RelayChainResult>; /// Returns channels contents for each inbound HRMP channel addressed to the parachain we are /// collating for. @@ -101,7 +101,7 @@ pub trait RelayChainInterface: Send + Sync { &self, para_id: ParaId, relay_parent: PHash, - ) -> Result>, RelayChainError>; + ) -> RelayChainResult>>; /// Yields the persisted validation data for the given `ParaId` along with an assumption that /// should be used if the para currently occupies a core. @@ -113,7 +113,7 @@ pub trait RelayChainInterface: Send + Sync { block_id: &BlockId, para_id: ParaId, _: OccupiedCoreAssumption, - ) -> Result, RelayChainError>; + ) -> RelayChainResult>; /// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. @@ -121,48 +121,45 @@ pub trait RelayChainInterface: Send + Sync { &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, RelayChainError>; + ) -> RelayChainResult>; /// Returns the session index expected at a child of the block. - async fn session_index_for_child( - &self, - block_id: &BlockId, - ) -> Result; + async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult; /// Get a stream of import block notifications. async fn import_notification_stream( &self, - ) -> Result + Send>>, RelayChainError>; + ) -> RelayChainResult + Send>>>; /// Get a stream of new best block notifications. async fn new_best_notification_stream( &self, - ) -> Result + Send>>, RelayChainError>; + ) -> RelayChainResult + Send>>>; /// Wait for a block with a given hash in the relay chain. /// /// This method returns immediately on error or if the block is already /// reported to be in chain. Otherwise, it waits for the block to arrive. - async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError>; + async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()>; /// Get a stream of finality notifications. async fn finality_notification_stream( &self, - ) -> Result + Send>>, RelayChainError>; + ) -> RelayChainResult + Send>>>; /// Whether the synchronization service is undergoing major sync. /// Returns true if so. - async fn is_major_syncing(&self) -> Result; + async fn is_major_syncing(&self) -> RelayChainResult; /// Get a handle to the overseer. - fn overseer_handle(&self) -> Result, RelayChainError>; + fn overseer_handle(&self) -> RelayChainResult>; /// Generate a storage read proof. async fn prove_read( &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result; + ) -> RelayChainResult; } #[async_trait] @@ -201,18 +198,15 @@ where &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { (**self).candidate_pending_availability(block_id, para_id).await } - async fn session_index_for_child( - &self, - block_id: &BlockId, - ) -> Result { + async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult { (**self).session_index_for_child(block_id).await } - async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { + async fn validators(&self, block_id: &BlockId) -> RelayChainResult> { (**self).validators(block_id).await } @@ -232,7 +226,7 @@ where (**self).best_block_hash().await } - async fn block_status(&self, block_id: BlockId) -> Result { + async fn block_status(&self, block_id: BlockId) -> RelayChainResult { (**self).block_status(block_id).await } @@ -248,7 +242,7 @@ where &self, block_id: &BlockId, key: &[u8], - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { (**self).get_storage_by_key(block_id, key).await } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index c3598401c93..d6cbc4a5bf4 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -122,7 +122,7 @@ where block_id: &BlockId, para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { self.full_client .runtime_api() .persisted_validation_data(block_id, para_id, occupied_core_assumption) @@ -133,24 +133,21 @@ where &self, block_id: &BlockId, para_id: ParaId, - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { self.full_client .runtime_api() .candidate_pending_availability(block_id, para_id) .map_err(RelayChainError::ApiError) } - async fn session_index_for_child( - &self, - block_id: &BlockId, - ) -> Result { + async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult { self.full_client .runtime_api() .session_index_for_child(block_id) .map_err(RelayChainError::ApiError) } - async fn validators(&self, block_id: &BlockId) -> Result, RelayChainError> { + async fn validators(&self, block_id: &BlockId) -> RelayChainResult> { self.full_client .runtime_api() .validators(block_id) @@ -181,7 +178,7 @@ where Ok(self.backend.blockchain().info().best_hash) } - async fn block_status(&self, block_id: BlockId) -> Result { + async fn block_status(&self, block_id: BlockId) -> RelayChainResult { self.backend .blockchain() .status(block_id) @@ -201,7 +198,7 @@ where &self, block_id: &BlockId, key: &[u8], - ) -> Result, RelayChainError> { + ) -> RelayChainResult> { let state = self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; state.storage(key).map_err(RelayChainError::GenericError) } @@ -210,7 +207,7 @@ where &self, block_id: &BlockId, relevant_keys: &Vec>, - ) -> Result { + ) -> RelayChainResult { let state_backend = self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; @@ -235,7 +232,7 @@ where /// /// The timeout is set to 6 seconds. This should be enough time to import the block in the current /// round and if not, the new round of the relay chain already started anyway. - async fn wait_for_block(&self, hash: PHash) -> Result<(), RelayChainError> { + async fn wait_for_block(&self, hash: PHash) -> RelayChainResult<()> { let mut listener = match check_block_in_chain(self.backend.clone(), self.full_client.clone(), hash)? { BlockCheckStatus::InChain => return Ok(()), @@ -286,7 +283,7 @@ pub fn check_block_in_chain( backend: Arc, client: Arc, hash: PHash, -) -> Result +) -> RelayChainResult where Client: BlockchainEvents, { From 68fa0746cc64fefb998d1e0905d5a205f7978b77 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Jan 2022 13:20:15 +0100 Subject: [PATCH 24/31] Remove unwanted changes, clean up --- Cargo.lock | 1 - client/network/Cargo.toml | 2 +- client/pov-recovery/src/lib.rs | 31 +++++++++++++++++-------- client/relay-chain-interface/src/lib.rs | 3 ++- test/service/Cargo.toml | 2 -- 5 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 37568ce3beb..a72808287d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2039,7 +2039,6 @@ dependencies = [ "substrate-test-client", "substrate-test-utils", "tokio", - "url 2.2.2", ] [[package]] diff --git a/client/network/Cargo.toml b/client/network/Cargo.toml index fe988055024..18a4a8c3a07 100644 --- a/client/network/Cargo.toml +++ b/client/network/Cargo.toml @@ -28,8 +28,8 @@ futures = { version = "0.3.1", features = ["compat"] } futures-timer = "3.0.2" tracing = "0.1.22" parking_lot = "0.11.1" -async-trait = "0.1.52" derive_more = "0.99.2" +async-trait = "0.1.52" [dev-dependencies] tokio = { version = "1.10", features = ["macros"] } diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index 66d51644e1c..d19424ad004 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -428,25 +428,36 @@ async fn pending_candidates( relay_chain_client: impl RelayChainInterface + Clone, para_id: ParaId, ) -> RelayChainResult> { - let stream = relay_chain_client.import_notification_stream().await?; - Ok(stream.filter_map(move |n| { + let import_notification_stream = relay_chain_client.import_notification_stream().await?; + + let filtered_stream = import_notification_stream.filter_map(move |n| { let client_for_closure = relay_chain_client.clone(); async move { let block_id = BlockId::hash(n.hash()); - let pending_availability_result = - client_for_closure.candidate_pending_availability(&block_id, para_id).await; - let session_index_result = client_for_closure.session_index_for_child(&block_id).await; - session_index_result - .map(|v| pending_availability_result.ok().flatten().map(|pa| (pa, v))) + let pending_availability_result = client_for_closure + .candidate_pending_availability(&block_id, para_id) + .await .map_err(|e| { tracing::error!( target: LOG_TARGET, error = ?e, - "Failed fetch pending candidates.", + "Failed to fetch pending candidates.", + ) + }); + let session_index_result = + client_for_closure.session_index_for_child(&block_id).await.map_err(|e| { + tracing::error!( + target: LOG_TARGET, + error = ?e, + "Failed to fetch session index.", ) - }) + }); + + session_index_result + .and_then(|v| Ok(pending_availability_result?.map(|pa| (pa, v)))) .ok() .flatten() } - })) + }); + Ok(filtered_stream) } diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 5503cd4819d..0dcadd99617 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -65,7 +65,7 @@ impl From for RelayChainError { } } -/// Should be used for all interaction with the relay chain in cumulus. +/// Trait that provides all necessary methods for interaction between collator and relay chain. #[async_trait] pub trait RelayChainInterface: Send + Sync { /// Fetch a storage item by key. @@ -81,6 +81,7 @@ pub trait RelayChainInterface: Send + Sync { /// Get the status of a given block. async fn block_status(&self, block_id: BlockId) -> RelayChainResult; + /// Get the hash of the current best block. async fn best_block_hash(&self) -> RelayChainResult; /// Returns the whole contents of the downward message queue for the parachain we are collating diff --git a/test/service/Cargo.toml b/test/service/Cargo.toml index bacc606a760..02537138848 100644 --- a/test/service/Cargo.toml +++ b/test/service/Cargo.toml @@ -54,8 +54,6 @@ cumulus-test-runtime = { path = "../runtime" } cumulus-test-relay-validation-worker-provider = { path = "../relay-validation-worker-provider" } cumulus-relay-chain-local = { path = "../../client/relay-chain-local" } -url = "2.2.2" - criterion = { version = "0.3.5", features = [ "async_tokio" ] } parking_lot = "0.11.1" From 2764ea208dba18fd215e9bcbca8c1e7090be9a4e Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 18 Jan 2022 13:29:40 +0100 Subject: [PATCH 25/31] Remove unused import --- client/consensus/common/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/consensus/common/src/tests.rs b/client/consensus/common/src/tests.rs index 8a234c4b06a..ceb60aa501e 100644 --- a/client/consensus/common/src/tests.rs +++ b/client/consensus/common/src/tests.rs @@ -18,7 +18,7 @@ use crate::*; use async_trait::async_trait; use codec::Encode; -use cumulus_relay_chain_interface::{RelayChainError, RelayChainResult}; +use cumulus_relay_chain_interface::RelayChainResult; use cumulus_test_client::{ runtime::{Block, Header}, Backend, Client, InitBlockBuilder, TestClientBuilder, TestClientBuilderExt, From 3be8d65d31dba56ae420cd2af95fcab45c928c9e Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Wed, 19 Jan 2022 01:29:14 +0100 Subject: [PATCH 26/31] Add format for StatemachineError and remove nused From trait --- client/relay-chain-interface/src/lib.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 0dcadd99617..220e42f1215 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -53,17 +53,13 @@ pub enum RelayChainError { WaitBlockchainError(PHash, sp_blockchain::Error), #[display(fmt = "Blockchain returned an error: {:?}", _0)] BlockchainError(sp_blockchain::Error), + #[display(fmt = "State machine error occured: {:?}", _0)] StateMachineError(String), #[display(fmt = "Unspecified error occured: {:?}", _0)] GenericError(String), } -impl std::error::Error for RelayChainError {} -impl From for RelayChainError { - fn from(error: ApiError) -> Self { - RelayChainError::ApiError(error) - } -} +impl std::error::Error for RelayChainError {} /// Trait that provides all necessary methods for interaction between collator and relay chain. #[async_trait] From 4c9b8ea902d46fa058567cddb6dfee0eb360402d Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 24 Jan 2022 13:16:31 +0100 Subject: [PATCH 27/31] Use 'thiserror' crate to simplify error handling --- Cargo.lock | 1 + client/relay-chain-interface/Cargo.toml | 1 + client/relay-chain-interface/src/lib.rs | 29 ++++-------- client/relay-chain-local/src/lib.rs | 61 ++++++++++--------------- 4 files changed, 35 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a72808287d6..05fe0c508d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1872,6 +1872,7 @@ dependencies = [ "sp-core", "sp-runtime", "sp-state-machine", + "thiserror", ] [[package]] diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 0b7dac2f4b3..bc30c390100 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -20,3 +20,4 @@ futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" derive_more = "0.99.2" async-trait = "0.1.52" +thiserror = "1.0.30" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 220e42f1215..8044bcd0b1f 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -34,33 +34,24 @@ use sp_state_machine::StorageValue; pub type RelayChainResult = Result; -#[derive(Debug, derive_more::Display)] +#[derive(thiserror::Error, Debug)] pub enum RelayChainError { - #[display(fmt = "Error occured while calling relay chain runtime: {:?}", _0)] - ApiError(ApiError), - #[display(fmt = "Timeout while waiting for relay-chain block `{}` to be imported.", _0)] + #[error("Error occured while calling relay chain runtime: {0:?}")] + ApiError(#[from] ApiError), + #[error("Timeout while waiting for relay-chain block `{0}` to be imported.")] WaitTimeout(PHash), - #[display( - fmt = "Import listener closed while waiting for relay-chain block `{}` to be imported.", - _0 - )] + #[error("Import listener closed while waiting for relay-chain block `{0}` to be imported.")] ImportListenerClosed(PHash), - #[display( - fmt = "Blockchain returned an error while waiting for relay-chain block `{}` to be imported: {:?}", - _0, - _1 - )] + #[error("Blockchain returned an error while waiting for relay-chain block `{0}` to be imported: {1:?}")] WaitBlockchainError(PHash, sp_blockchain::Error), - #[display(fmt = "Blockchain returned an error: {:?}", _0)] - BlockchainError(sp_blockchain::Error), - #[display(fmt = "State machine error occured: {:?}", _0)] + #[error("Blockchain returned an error: {0:?}")] + BlockchainError(#[from] sp_blockchain::Error), + #[error("State machine error occured: {0:?}")] StateMachineError(String), - #[display(fmt = "Unspecified error occured: {:?}", _0)] + #[error("Unspecified error occured: {0:?}")] GenericError(String), } -impl std::error::Error for RelayChainError {} - /// Trait that provides all necessary methods for interaction between collator and relay chain. #[async_trait] pub trait RelayChainInterface: Send + Sync { diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index d6cbc4a5bf4..dccc840d82c 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -92,14 +92,11 @@ where para_id: ParaId, relay_parent: PHash, ) -> RelayChainResult> { - self.full_client - .runtime_api() - .dmq_contents_with_context( - &BlockId::hash(relay_parent), - sp_core::ExecutionContext::Importing, - para_id, - ) - .map_err(RelayChainError::ApiError) + Ok(self.full_client.runtime_api().dmq_contents_with_context( + &BlockId::hash(relay_parent), + sp_core::ExecutionContext::Importing, + para_id, + )?) } async fn retrieve_all_inbound_hrmp_channel_contents( @@ -107,14 +104,11 @@ where para_id: ParaId, relay_parent: PHash, ) -> RelayChainResult>> { - self.full_client - .runtime_api() - .inbound_hrmp_channels_contents_with_context( - &BlockId::hash(relay_parent), - sp_core::ExecutionContext::Importing, - para_id, - ) - .map_err(RelayChainError::ApiError) + Ok(self.full_client.runtime_api().inbound_hrmp_channels_contents_with_context( + &BlockId::hash(relay_parent), + sp_core::ExecutionContext::Importing, + para_id, + )?) } async fn persisted_validation_data( @@ -123,10 +117,11 @@ where para_id: ParaId, occupied_core_assumption: OccupiedCoreAssumption, ) -> RelayChainResult> { - self.full_client - .runtime_api() - .persisted_validation_data(block_id, para_id, occupied_core_assumption) - .map_err(RelayChainError::ApiError) + Ok(self.full_client.runtime_api().persisted_validation_data( + block_id, + para_id, + occupied_core_assumption, + )?) } async fn candidate_pending_availability( @@ -134,24 +129,18 @@ where block_id: &BlockId, para_id: ParaId, ) -> RelayChainResult> { - self.full_client + Ok(self + .full_client .runtime_api() - .candidate_pending_availability(block_id, para_id) - .map_err(RelayChainError::ApiError) + .candidate_pending_availability(block_id, para_id)?) } async fn session_index_for_child(&self, block_id: &BlockId) -> RelayChainResult { - self.full_client - .runtime_api() - .session_index_for_child(block_id) - .map_err(RelayChainError::ApiError) + Ok(self.full_client.runtime_api().session_index_for_child(block_id)?) } async fn validators(&self, block_id: &BlockId) -> RelayChainResult> { - self.full_client - .runtime_api() - .validators(block_id) - .map_err(RelayChainError::ApiError) + Ok(self.full_client.runtime_api().validators(block_id)?) } async fn import_notification_stream( @@ -179,10 +168,7 @@ where } async fn block_status(&self, block_id: BlockId) -> RelayChainResult { - self.backend - .blockchain() - .status(block_id) - .map_err(RelayChainError::BlockchainError) + Ok(self.backend.blockchain().status(block_id)?) } async fn is_major_syncing(&self) -> RelayChainResult { @@ -199,7 +185,7 @@ where block_id: &BlockId, key: &[u8], ) -> RelayChainResult> { - let state = self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; + let state = self.backend.state_at(*block_id)?; state.storage(key).map_err(RelayChainError::GenericError) } @@ -208,8 +194,7 @@ where block_id: &BlockId, relevant_keys: &Vec>, ) -> RelayChainResult { - let state_backend = - self.backend.state_at(*block_id).map_err(RelayChainError::BlockchainError)?; + let state_backend = self.backend.state_at(*block_id)?; sp_state_machine::prove_read(state_backend, relevant_keys) .map_err(|e| RelayChainError::StateMachineError(e.to_string())) From f2caf4bc6c497368b56ca530e03d2356eaf3c90e Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Mon, 24 Jan 2022 14:59:32 +0100 Subject: [PATCH 28/31] Expose error for overseer, further simplify error handling --- Cargo.lock | 1 + client/relay-chain-interface/Cargo.toml | 1 + client/relay-chain-interface/src/lib.rs | 2 +- client/relay-chain-local/src/lib.rs | 8 ++------ client/service/src/lib.rs | 17 +++++++---------- parachain-template/node/src/service.rs | 2 +- polkadot-parachains/src/service.rs | 8 ++++---- .../parachain-inherent/src/client_side.rs | 4 ++-- test/service/src/lib.rs | 2 +- 9 files changed, 20 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 05fe0c508d6..1868c36a654 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1867,6 +1867,7 @@ dependencies = [ "parking_lot 0.11.2", "polkadot-overseer", "sc-client-api", + "sc-service", "sp-api", "sp-blockchain", "sp-core", diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index bc30c390100..8a0c0155950 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -15,6 +15,7 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" } sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } +sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } futures = { version = "0.3.1", features = ["compat"] } parking_lot = "0.11.1" diff --git a/client/relay-chain-interface/src/lib.rs b/client/relay-chain-interface/src/lib.rs index 8044bcd0b1f..13b0551b38c 100644 --- a/client/relay-chain-interface/src/lib.rs +++ b/client/relay-chain-interface/src/lib.rs @@ -47,7 +47,7 @@ pub enum RelayChainError { #[error("Blockchain returned an error: {0:?}")] BlockchainError(#[from] sp_blockchain::Error), #[error("State machine error occured: {0:?}")] - StateMachineError(String), + StateMachineError(Box), #[error("Unspecified error occured: {0:?}")] GenericError(String), } diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index dccc840d82c..57535a5bc45 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -197,7 +197,7 @@ where let state_backend = self.backend.state_at(*block_id)?; sp_state_machine::prove_read(state_backend, relevant_keys) - .map_err(|e| RelayChainError::StateMachineError(e.to_string())) + .map_err(RelayChainError::StateMachineError) } /// Wait for a given relay chain block in an async way. @@ -246,11 +246,7 @@ where self.full_client .import_notification_stream() .filter_map(|notification| async move { - if notification.is_new_best { - Some(notification.header) - } else { - None - } + notification.is_new_best.then(|| notification.header) }); Ok(Box::pin(notifications_stream)) } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index cee9d0c0443..11729031ce8 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -107,12 +107,13 @@ where .spawn_essential_handle() .spawn("cumulus-consensus", None, consensus); + let overseer_handle = relay_chain_interface + .overseer_handle() + .map_err(|e| sc_service::Error::Other(e.to_string()))? + .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?; + let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( - relay_chain_interface - .overseer_handle() - .ok() - .flatten() - .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, + overseer_handle.clone(), slot_duration, client.clone(), import_queue, @@ -128,11 +129,7 @@ where runtime_api: client.clone(), block_status, announce_block, - overseer_handle: relay_chain_interface - .overseer_handle() - .ok() - .flatten() - .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?, + overseer_handle, spawner, para_id, key: collator_key, diff --git a/parachain-template/node/src/service.rs b/parachain-template/node/src/service.rs index 951fba0afed..f30ac3fcc2a 100644 --- a/parachain-template/node/src/service.rs +++ b/parachain-template/node/src/service.rs @@ -437,7 +437,7 @@ pub async fn start_parachain_node( let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_interface.clone(), + &relay_chain_interface, &validation_data, id, ).await; diff --git a/polkadot-parachains/src/service.rs b/polkadot-parachains/src/service.rs index 8ce6c1aed4e..248b9fdd9a9 100644 --- a/polkadot-parachains/src/service.rs +++ b/polkadot-parachains/src/service.rs @@ -732,7 +732,7 @@ pub async fn start_rococo_parachain_node( let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_interface.clone(), + &relay_chain_interface, &validation_data, id, ).await; @@ -870,7 +870,7 @@ where let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_interface.clone(), + &relay_chain_interface, &validation_data, id, ).await; @@ -1144,7 +1144,7 @@ where let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_for_aura.clone(), + &relay_chain_for_aura, &validation_data, id, ).await; @@ -1204,7 +1204,7 @@ where let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_interface.clone(), + &relay_chain_interface, &validation_data, id, ).await; diff --git a/primitives/parachain-inherent/src/client_side.rs b/primitives/parachain-inherent/src/client_side.rs index 5f2ac24586f..b14c2257654 100644 --- a/primitives/parachain-inherent/src/client_side.rs +++ b/primitives/parachain-inherent/src/client_side.rs @@ -130,12 +130,12 @@ impl ParachainInherentData { /// Returns `None` if the creation failed. pub async fn create_at( relay_parent: PHash, - relay_chain_interface: impl RelayChainInterface, + relay_chain_interface: &impl RelayChainInterface, validation_data: &PersistedValidationData, para_id: ParaId, ) -> Option { let relay_chain_state = - collect_relay_storage_proof(&relay_chain_interface, para_id, relay_parent).await?; + collect_relay_storage_proof(relay_chain_interface, para_id, relay_parent).await?; let downward_messages = relay_chain_interface .retrieve_dmq_contents(para_id, relay_parent) diff --git a/test/service/src/lib.rs b/test/service/src/lib.rs index 1fa529909ee..b8fb297f14b 100644 --- a/test/service/src/lib.rs +++ b/test/service/src/lib.rs @@ -293,7 +293,7 @@ where let parachain_inherent = cumulus_primitives_parachain_inherent::ParachainInherentData::create_at( relay_parent, - relay_chain_interface, + &relay_chain_interface, &validation_data, para_id, ).await; From 4e827a792bca0cf0335d3c7201b4e31085e92ddf Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 25 Jan 2022 16:58:05 +0100 Subject: [PATCH 29/31] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Köcher --- client/relay-chain-interface/Cargo.toml | 2 +- client/relay-chain-local/src/lib.rs | 5 ++--- client/service/src/lib.rs | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/relay-chain-interface/Cargo.toml b/client/relay-chain-interface/Cargo.toml index 8a0c0155950..b76ebcc3137 100644 --- a/client/relay-chain-interface/Cargo.toml +++ b/client/relay-chain-interface/Cargo.toml @@ -17,7 +17,7 @@ sp-state-machine = { git = "https://github.com/paritytech/substrate", branch = " sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" } sc-service = { git = "https://github.com/paritytech/substrate", branch = "master" } -futures = { version = "0.3.1", features = ["compat"] } +futures = "0.3.1" parking_lot = "0.11.1" derive_more = "0.99.2" async-trait = "0.1.52" diff --git a/client/relay-chain-local/src/lib.rs b/client/relay-chain-local/src/lib.rs index 57535a5bc45..903a8ff3c66 100644 --- a/client/relay-chain-local/src/lib.rs +++ b/client/relay-chain-local/src/lib.rs @@ -271,9 +271,8 @@ where let _lock = backend.get_import_lock().read(); let block_id = BlockId::Hash(hash); - match backend.blockchain().status(block_id) { - Ok(BlockStatus::InChain) => return Ok(BlockCheckStatus::InChain), - Err(err) => return Err(RelayChainError::BlockchainError(err)), + match backend.blockchain().status(block_id)? { + BlockStatus::InChain => return Ok(BlockCheckStatus::InChain), _ => {}, } diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index b078a99e6d0..08cd8584f22 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -109,7 +109,7 @@ where let overseer_handle = relay_chain_interface .overseer_handle() - .map_err(|e| sc_service::Error::Other(e.to_string()))? + .map_err(|e| sc_service::Error::Application(Box::new(e)))? .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?; let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( @@ -195,7 +195,7 @@ where let overseer_handle = relay_chain_interface .overseer_handle() - .map_err(|e| sc_service::Error::Other(e.to_string()))? + .map_err(|e| sc_service::Error::Application(Box::new(e)))? .ok_or_else(|| "Polkadot full node did not provide an `OverseerHandle`!")?; let pov_recovery = cumulus_client_pov_recovery::PoVRecovery::new( From 254ff9301f515ee8eaa70508e0b1bf2c68578564 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 25 Jan 2022 16:16:41 +0000 Subject: [PATCH 30/31] Improve readability in pov-recovery --- client/pov-recovery/src/lib.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/client/pov-recovery/src/lib.rs b/client/pov-recovery/src/lib.rs index cade83aa27d..d5d1a19b1d9 100644 --- a/client/pov-recovery/src/lib.rs +++ b/client/pov-recovery/src/lib.rs @@ -471,10 +471,11 @@ async fn pending_candidates( ) }); - session_index_result - .and_then(|v| Ok(pending_availability_result?.map(|pa| (pa, v)))) - .ok() - .flatten() + if let Ok(Some(candidate)) = pending_availability_result { + session_index_result.map(|session_index| (candidate, session_index)).ok() + } else { + None + } } }); Ok(filtered_stream) From 53d10eb587fffeece2749a4d2be3b7b340df7044 Mon Sep 17 00:00:00 2001 From: Sebastian Kunert Date: Tue, 25 Jan 2022 16:34:30 +0000 Subject: [PATCH 31/31] Make handle_block_announce_data async --- client/network/src/lib.rs | 58 ++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 31 deletions(-) diff --git a/client/network/src/lib.rs b/client/network/src/lib.rs index 154a41dad58..2010803d384 100644 --- a/client/network/src/lib.rs +++ b/client/network/src/lib.rs @@ -281,49 +281,45 @@ where } /// Handle a block announcement with empty data (no statement) attached to it. - fn handle_empty_block_announce_data( + async fn handle_empty_block_announce_data( &self, header: Block::Header, - ) -> impl Future> { + ) -> Result { let relay_chain_interface = self.relay_chain_interface.clone(); let para_id = self.para_id; - async move { - // Check if block is equal or higher than best (this requires a justification) - let relay_chain_best_hash = relay_chain_interface - .best_block_hash() - .await - .map_err(|e| Box::new(e) as Box<_>)?; - let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); - let block_number = header.number(); - - let best_head = - Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id) - .await?; - let known_best_number = best_head.number(); - let backed_block = || async { - Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id) - .await - }; + // Check if block is equal or higher than best (this requires a justification) + let relay_chain_best_hash = relay_chain_interface + .best_block_hash() + .await + .map_err(|e| Box::new(e) as Box<_>)?; + let runtime_api_block_id = BlockId::Hash(relay_chain_best_hash); + let block_number = header.number(); + + let best_head = + Self::included_block(&relay_chain_interface, &runtime_api_block_id, para_id).await?; + let known_best_number = best_head.number(); + let backed_block = || async { + Self::backed_block_hash(&relay_chain_interface, &runtime_api_block_id, para_id).await + }; - if best_head == header { - tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",); + if best_head == header { + tracing::debug!(target: LOG_TARGET, "Announced block matches best block.",); - Ok(Validation::Success { is_new_best: true }) - } else if Some(HeadData(header.encode()).hash()) == backed_block().await? { - tracing::debug!(target: LOG_TARGET, "Announced block matches latest backed block.",); + Ok(Validation::Success { is_new_best: true }) + } else if Some(HeadData(header.encode()).hash()) == backed_block().await? { + tracing::debug!(target: LOG_TARGET, "Announced block matches latest backed block.",); - Ok(Validation::Success { is_new_best: true }) - } else if block_number >= known_best_number { - tracing::debug!( + Ok(Validation::Success { is_new_best: true }) + } else if block_number >= known_best_number { + tracing::debug!( target: LOG_TARGET, "Validation failed because a justification is needed if the block at the top of the chain." ); - Ok(Validation::Failure { disconnect: false }) - } else { - Ok(Validation::Success { is_new_best: false }) - } + Ok(Validation::Failure { disconnect: false }) + } else { + Ok(Validation::Success { is_new_best: false }) } } }