From d3e8c97f8364cd6c0e18aedff568745416b58bdb Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Wed, 23 Sep 2020 17:06:03 +0200 Subject: [PATCH 01/12] Initial draft --- Cargo.lock | 7 ++++ client/chain-spec/Cargo.toml | 3 ++ client/chain-spec/src/chain_spec.rs | 28 +++++++++++++ client/cli/Cargo.toml | 2 + .../cli/src/commands/build_sync_spec_cmd.rs | 15 ++++++- client/finality-grandpa/src/authorities.rs | 10 ++--- client/finality-grandpa/src/aux_schema.rs | 3 +- client/finality-grandpa/src/lib.rs | 1 + client/service/Cargo.toml | 3 ++ .../service/src/chain_ops/build_sync_spec.rs | 41 +++++++++++++++++-- 10 files changed, 101 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3eeb7c315f4a9..07b3480a7022d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6289,12 +6289,15 @@ dependencies = [ "impl-trait-for-tuples", "parity-scale-codec", "sc-chain-spec-derive", + "sc-consensus-babe", "sc-network", "sc-telemetry", "serde", "serde_json", "sp-chain-spec", + "sp-consensus-slots", "sp-core", + "sp-finality-grandpa", "sp-runtime", ] @@ -6331,6 +6334,7 @@ dependencies = [ "regex", "rpassword", "sc-client-api", + "sc-consensus-babe", "sc-informant", "sc-keystore", "sc-network", @@ -6339,6 +6343,7 @@ dependencies = [ "sc-tracing", "serde", "serde_json", + "sp-api", "sp-application-crypto", "sp-blockchain", "sp-core", @@ -7155,6 +7160,8 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-client-db", + "sc-consensus-babe", + "sc-consensus-epochs", "sc-executor", "sc-finality-grandpa", "sc-informant", diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index a73d809ba2523..57c4083ded7da 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -23,3 +23,6 @@ sp-runtime = { version = "2.0.0", path = "../../primitives/runtime" } sp-chain-spec = { version = "2.0.0", path = "../../primitives/chain-spec" } sc-telemetry = { version = "2.0.0", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "1.3.4" } +sp-consensus-slots = { version = "0.8.0-rc6", path = "../../primitives/consensus/slots" } +sc-consensus-babe = { version = "0.8.0-rc6", path = "../consensus/babe" } +sp-finality-grandpa = { version = "2.0.0-rc6", path = "../../primitives/finality-grandpa" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 1fbf0419e2001..7df218e933a82 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -401,6 +401,11 @@ where pub struct LightSyncState { /// The header of the best finalized block. pub header: ::Header, + pub babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, + pub babe_finalized_block_epoch_information: sc_consensus_babe::Epoch, + pub babe_finalized_next_epoch_transition: sc_consensus_babe::Epoch, + pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, + pub grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, } impl LightSyncState { @@ -410,6 +415,15 @@ impl LightSyncState { SerializableLightSyncState { header: StorageData(self.header.encode()), + babe_finalized_block1_slot_number: self.babe_finalized_block1_slot_number, + babe_finalized_block_epoch_information: + StorageData(self.babe_finalized_block_epoch_information.encode()), + babe_finalized_next_epoch_transition: + StorageData(self.babe_finalized_next_epoch_transition.encode()), + grandpa_finalized_triggered_authorities: + StorageData(self.grandpa_finalized_triggered_authorities.encode()), + grandpa_after_finalized_block_authorities_set_id: + self.grandpa_after_finalized_block_authorities_set_id, } } @@ -417,6 +431,15 @@ impl LightSyncState { pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result { Ok(Self { header: codec::Decode::decode(&mut &serialized.header.0[..])?, + babe_finalized_block1_slot_number: serialized.babe_finalized_block1_slot_number, + babe_finalized_block_epoch_information: + codec::Decode::decode(&mut &serialized.babe_finalized_block_epoch_information.0[..])?, + babe_finalized_next_epoch_transition: + codec::Decode::decode(&mut &serialized.babe_finalized_next_epoch_transition.0[..])?, + grandpa_finalized_triggered_authorities: + codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, + grandpa_after_finalized_block_authorities_set_id: + serialized.grandpa_after_finalized_block_authorities_set_id, }) } } @@ -427,6 +450,11 @@ impl LightSyncState { #[serde(deny_unknown_fields)] pub struct SerializableLightSyncState { header: StorageData, + babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, + babe_finalized_block_epoch_information: StorageData, + babe_finalized_next_epoch_transition: StorageData, + grandpa_finalized_triggered_authorities: StorageData, + grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, } #[cfg(test)] diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index dca91d18c3efc..5d424fc3f527b 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -44,6 +44,8 @@ sp-state-machine = { version = "0.8.0", path = "../../primitives/state-machine" sc-telemetry = { version = "2.0.0", path = "../telemetry" } substrate-prometheus-endpoint = { path = "../../utils/prometheus" , version = "0.8.0"} sp-keyring = { version = "2.0.0", path = "../../primitives/keyring" } +sp-api = { version = "2.0.0", path = "../../primitives/api" } +sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } names = "0.11.0" structopt = "0.3.8" sc-tracing = { version = "2.0.0", path = "../tracing" } diff --git a/client/cli/src/commands/build_sync_spec_cmd.rs b/client/cli/src/commands/build_sync_spec_cmd.rs index 3f1bfce6a3290..2002dc9e78d0d 100644 --- a/client/cli/src/commands/build_sync_spec_cmd.rs +++ b/client/cli/src/commands/build_sync_spec_cmd.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use crate::error; -use crate::params::{SharedParams, NetworkParams}; +use crate::params::{SharedParams, NetworkParams, ImportParams}; use crate::CliConfiguration; use log::info; use sc_network::config::build_multiaddr; @@ -57,6 +57,10 @@ pub struct BuildSyncSpecCmd { #[allow(missing_docs)] #[structopt(flatten)] pub network_params: NetworkParams, + + #[allow(missing_docs)] + #[structopt(flatten)] + pub import_params: ImportParams, } impl BuildSyncSpecCmd { @@ -70,7 +74,10 @@ impl BuildSyncSpecCmd { ) -> error::Result<()> where B: BlockT, - CL: sp_blockchain::HeaderBackend, + CL: sp_blockchain::HeaderBackend + sp_api::ProvideRuntimeApi + + sc_client_api::AuxStore, + >::Api: + sc_consensus_babe::BabeApi, { if self.sync_first { network_status_sinks.status_stream(std::time::Duration::from_secs(1)).filter(|status| { @@ -110,4 +117,8 @@ impl CliConfiguration for BuildSyncSpecCmd { fn network_params(&self) -> Option<&NetworkParams> { Some(&self.network_params) } + + fn import_params(&self) -> Option<&ImportParams> { + Some(&self.import_params) + } } diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 7a064d7a6224b..78dffd37ab016 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -101,11 +101,11 @@ pub(crate) struct Status { /// A set of authorities. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub(crate) struct AuthoritySet { +pub struct AuthoritySet { /// The current active authorities. - pub(crate) current_authorities: AuthorityList, + pub current_authorities: AuthorityList, /// The current set id. - pub(crate) set_id: u64, + pub set_id: u64, /// Tree of pending standard changes across forks. Standard changes are /// enacted on finality and must be enacted (i.e. finalized) in-order across /// a given branch @@ -494,7 +494,7 @@ where /// Kinds of delays for pending changes. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub(crate) enum DelayKind { +pub enum DelayKind { /// Depth in finalized chain. Finalized, /// Depth in best chain. The median last finalized block is calculated at the time the @@ -507,7 +507,7 @@ pub(crate) enum DelayKind { /// This will be applied when the announcing block is at some depth within /// the finalized or unfinalized chain. #[derive(Debug, Clone, Encode, PartialEq)] -pub(crate) struct PendingChange { +pub struct PendingChange { /// The new authorities and weights to apply. pub(crate) next_authorities: AuthorityList, /// How deep in the chain the announcing block must be diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 4ed96d058ac6b..0f5b8d4faebcc 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -433,8 +433,7 @@ pub(crate) fn update_consensus_changes( write_aux(&[(CONSENSUS_CHANGES_KEY, set.encode().as_slice())]) } -#[cfg(test)] -pub(crate) fn load_authorities(backend: &B) +pub fn load_authorities(backend: &B) -> Option> { load_decode::<_, AuthoritySet>(backend, AUTHORITY_SET_KEY) .expect("backend error") diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index a15130942c30f..1de285dbe41fa 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -134,6 +134,7 @@ pub use voting_rule::{ BeforeBestBlockBy, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRulesBuilder }; pub use finality_grandpa::voter::report; +pub use aux_schema::load_authorities; use aux_schema::PersistentData; use environment::{Environment, VoterSetState}; diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index f57a145422c8c..43643f0699e00 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -77,6 +77,9 @@ sc-tracing = { version = "2.0.0", path = "../tracing" } sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } tracing = "0.1.19" parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] } +sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } +sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } +grandpa = { version = "0.8.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } [target.'cfg(not(target_os = "unknown"))'.dependencies] tempfile = "3.1.0" diff --git a/client/service/src/chain_ops/build_sync_spec.rs b/client/service/src/chain_ops/build_sync_spec.rs index 9553ea21a6965..0b61f6295cf0e 100644 --- a/client/service/src/chain_ops/build_sync_spec.rs +++ b/client/service/src/chain_ops/build_sync_spec.rs @@ -15,9 +15,11 @@ // along with Substrate. If not, see . use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::One; use sp_blockchain::HeaderBackend; use std::sync::Arc; use sp_runtime::generic::BlockId; +use sp_api::NumberFor; /// Build a `LightSyncState` from the CHT roots stored in a backend. pub fn build_light_sync_state( @@ -25,12 +27,45 @@ pub fn build_light_sync_state( ) -> Result, sp_blockchain::Error> where TBl: BlockT, - TCl: HeaderBackend, + TCl: HeaderBackend + sp_api::ProvideRuntimeApi + sc_client_api::AuxStore, + >::Api: + sc_consensus_babe::BabeApi, { + let finalized_number = client.info().finalized_number; let finalized_hash = client.info().finalized_hash; - let header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); + let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); + + let babe_config = sc_consensus_babe::Config::get_or_compute(&*client)?; + + let babe_epoch_changes = + sc_consensus_babe::aux_schema::load_epoch_changes::(&*client, &babe_config)?; + + let block1_number = NumberFor::::one(); + let block1_hash = client.hash(block1_number)?.unwrap(); + + let babe_epoch_changes_lock = babe_epoch_changes.lock(); + + let epoch_1 = babe_epoch_changes_lock.epoch(&sc_consensus_epochs::EpochIdentifier { + position: sc_consensus_epochs::EpochIdentifierPosition::Genesis0, + number: block1_number, + hash: block1_hash, + }).unwrap(); + + let finalized_epoch = babe_epoch_changes_lock.epoch(&sc_consensus_epochs::EpochIdentifier { + position: sc_consensus_epochs::EpochIdentifierPosition::Regular, + number: finalized_number, + hash: finalized_hash + }).unwrap().clone(); + + let authorities = + grandpa::load_authorities::<_, ::Hash, NumberFor>(&*client).unwrap(); Ok(sc_chain_spec::LightSyncState { - header + header: finalized_header, + babe_finalized_block1_slot_number: epoch_1.start_slot, + babe_finalized_block_epoch_information: finalized_epoch.clone(), + babe_finalized_next_epoch_transition: finalized_epoch, + grandpa_finalized_triggered_authorities: authorities.current_authorities, + grandpa_after_finalized_block_authorities_set_id: authorities.set_id, }) } From 1eb129752855fec2060b93dcddd5d2de8baf73ec Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 28 Sep 2020 14:00:56 +0200 Subject: [PATCH 02/12] Add an iterator that helps us get most items --- client/chain-spec/src/chain_spec.rs | 34 +++++--- client/service/Cargo.toml | 2 + .../service/src/chain_ops/build_sync_spec.rs | 86 ++++++++++++------- 3 files changed, 77 insertions(+), 45 deletions(-) diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 7df218e933a82..0a87e5de6af12 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -27,7 +27,7 @@ use serde_json as json; use crate::{RuntimeGenesis, ChainType, extension::GetExtension, Properties}; use sc_network::config::MultiaddrWithPeerId; use sc_telemetry::TelemetryEndpoints; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, NumberFor}; enum GenesisSource { File(PathBuf), @@ -264,7 +264,7 @@ impl ChainSpec { /// Hardcode infomation to allow light clients to sync quickly into the chain spec. fn set_light_sync_state(&mut self, light_sync_state: SerializableLightSyncState) { - self.client_spec.light_sync_state = Some(light_sync_state); + self.client_spec.light_sync_state = Some(light_sync_state); } } @@ -400,12 +400,13 @@ where /// Hardcoded infomation that allows light clients to sync quickly. pub struct LightSyncState { /// The header of the best finalized block. - pub header: ::Header, + pub finalized_block_header: ::Header, pub babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, - pub babe_finalized_block_epoch_information: sc_consensus_babe::Epoch, - pub babe_finalized_next_epoch_transition: sc_consensus_babe::Epoch, - pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, + pub babe_finalized_block_epoch_information: sc_consensus_babe::NextEpochDescriptor, + pub babe_finalized_next_epoch_transition: sc_consensus_babe::NextEpochDescriptor, pub grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, + pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, + pub grandpa_finalized_scheduled_change: sp_finality_grandpa::ScheduledChange>, } impl LightSyncState { @@ -414,32 +415,36 @@ impl LightSyncState { use codec::Encode; SerializableLightSyncState { - header: StorageData(self.header.encode()), + finalized_block_header: StorageData(self.finalized_block_header.encode()), babe_finalized_block1_slot_number: self.babe_finalized_block1_slot_number, babe_finalized_block_epoch_information: StorageData(self.babe_finalized_block_epoch_information.encode()), babe_finalized_next_epoch_transition: StorageData(self.babe_finalized_next_epoch_transition.encode()), - grandpa_finalized_triggered_authorities: - StorageData(self.grandpa_finalized_triggered_authorities.encode()), grandpa_after_finalized_block_authorities_set_id: self.grandpa_after_finalized_block_authorities_set_id, + grandpa_finalized_triggered_authorities: + StorageData(self.grandpa_finalized_triggered_authorities.encode()), + grandpa_finalized_scheduled_change: + StorageData(self.grandpa_finalized_scheduled_change.encode()), } } /// Convert from a `SerializableLightSyncState`. pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result { Ok(Self { - header: codec::Decode::decode(&mut &serialized.header.0[..])?, + finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, babe_finalized_block1_slot_number: serialized.babe_finalized_block1_slot_number, babe_finalized_block_epoch_information: codec::Decode::decode(&mut &serialized.babe_finalized_block_epoch_information.0[..])?, babe_finalized_next_epoch_transition: codec::Decode::decode(&mut &serialized.babe_finalized_next_epoch_transition.0[..])?, - grandpa_finalized_triggered_authorities: - codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, grandpa_after_finalized_block_authorities_set_id: serialized.grandpa_after_finalized_block_authorities_set_id, + grandpa_finalized_triggered_authorities: + codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, + grandpa_finalized_scheduled_change: + codec::Decode::decode(&mut &serialized.grandpa_finalized_scheduled_change.0[..])?, }) } } @@ -449,12 +454,13 @@ impl LightSyncState { #[serde(rename_all = "camelCase")] #[serde(deny_unknown_fields)] pub struct SerializableLightSyncState { - header: StorageData, + finalized_block_header: StorageData, babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, babe_finalized_block_epoch_information: StorageData, babe_finalized_next_epoch_transition: StorageData, - grandpa_finalized_triggered_authorities: StorageData, grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, + grandpa_finalized_triggered_authorities: StorageData, + grandpa_finalized_scheduled_change: StorageData, } #[cfg(test)] diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index 43643f0699e00..e7cbde9500c03 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,8 +78,10 @@ sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } tracing = "0.1.19" parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] } sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } +sp-consensus-babe = { version = "0.8.0", path = "../../primitives/consensus/babe" } sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } grandpa = { version = "0.8.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } +grandpa-primitives = { version = "2.0.0", package = "sp-finality-grandpa", path = "../../primitives/finality-grandpa" } [target.'cfg(not(target_os = "unknown"))'.dependencies] tempfile = "3.1.0" diff --git a/client/service/src/chain_ops/build_sync_spec.rs b/client/service/src/chain_ops/build_sync_spec.rs index 0b61f6295cf0e..7ce0e7dfa131c 100644 --- a/client/service/src/chain_ops/build_sync_spec.rs +++ b/client/service/src/chain_ops/build_sync_spec.rs @@ -14,12 +14,38 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use sp_runtime::traits::Block as BlockT; -use sp_runtime::traits::One; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One}; use sp_blockchain::HeaderBackend; use std::sync::Arc; +use sp_runtime::ConsensusEngineId; use sp_runtime::generic::BlockId; -use sp_api::NumberFor; +use sc_client_api::{CallExecutor, ExecutorProvider}; + +fn backwards_consensus_log_iter<'a, TBl, TCl, CL, FN, T>( + client: Arc, mut number: NumberFor, engine_id: &'a ConsensusEngineId, func: FN, +) -> impl Iterator> + 'a + where + TBl: BlockT, + TCl: HeaderBackend + 'a, + CL: codec::Decode, + FN: Fn(CL) -> Option + 'a, +{ + let id = sp_runtime::generic::OpaqueDigestItemId::Consensus(engine_id); + + std::iter::from_fn(move || { + let header = match client.header(BlockId::Number(number)) { + Ok(Some(header)) => header, + Ok(None) => return Some(Some(Err(sp_blockchain::Error::Msg("Missing header".into())))), + Err(err) => return Some(Some(Err(err))), + }; + + let change = header.digest() + .convert_first(|l| l.try_to(id).and_then(&func)); + + number -= NumberFor::::one(); + Some(change.map(Ok)) + }).filter_map(|optional_log_item| optional_log_item) +} /// Build a `LightSyncState` from the CHT roots stored in a backend. pub fn build_light_sync_state( @@ -35,37 +61,35 @@ pub fn build_light_sync_state( let finalized_hash = client.info().finalized_hash; let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); - let babe_config = sc_consensus_babe::Config::get_or_compute(&*client)?; - - let babe_epoch_changes = - sc_consensus_babe::aux_schema::load_epoch_changes::(&*client, &babe_config)?; - - let block1_number = NumberFor::::one(); - let block1_hash = client.hash(block1_number)?.unwrap(); - - let babe_epoch_changes_lock = babe_epoch_changes.lock(); - - let epoch_1 = babe_epoch_changes_lock.epoch(&sc_consensus_epochs::EpochIdentifier { - position: sc_consensus_epochs::EpochIdentifierPosition::Genesis0, - number: block1_number, - hash: block1_hash, - }).unwrap(); + let mut scheduled_changes = backwards_consensus_log_iter( + client.clone(), finalized_number, &grandpa_primitives::GRANDPA_ENGINE_ID, + |log| match log { + grandpa_primitives::ConsensusLog::>::ScheduledChange(change) => Some(change), + grandpa_primitives::ConsensusLog::>::ForcedChange(_, change) => Some(change), + _ => None + } + ); + let future_change = scheduled_changes.next().unwrap()?; + let current_authorities = scheduled_changes.next().unwrap()?.next_authorities; - let finalized_epoch = babe_epoch_changes_lock.epoch(&sc_consensus_epochs::EpochIdentifier { - position: sc_consensus_epochs::EpochIdentifierPosition::Regular, - number: finalized_number, - hash: finalized_hash - }).unwrap().clone(); + let mut babe_epoch_descriptors = backwards_consensus_log_iter( + client.clone(), finalized_number, &sp_consensus_babe::BABE_ENGINE_ID, + |log| match log { + sp_consensus_babe::ConsensusLog::NextEpochData(descriptor)=> Some(descriptor), + _ => None + } + ); - let authorities = - grandpa::load_authorities::<_, ::Hash, NumberFor>(&*client).unwrap(); + let next_desc = babe_epoch_descriptors.next().unwrap()?; + let current_desc = babe_epoch_descriptors.next().unwrap()?; Ok(sc_chain_spec::LightSyncState { - header: finalized_header, - babe_finalized_block1_slot_number: epoch_1.start_slot, - babe_finalized_block_epoch_information: finalized_epoch.clone(), - babe_finalized_next_epoch_transition: finalized_epoch, - grandpa_finalized_triggered_authorities: authorities.current_authorities, - grandpa_after_finalized_block_authorities_set_id: authorities.set_id, + finalized_block_header: finalized_header, + babe_finalized_block1_slot_number: 0, + babe_finalized_block_epoch_information: current_desc, + babe_finalized_next_epoch_transition: next_desc, + grandpa_finalized_triggered_authorities: current_authorities, + grandpa_after_finalized_block_authorities_set_id: 0, + grandpa_finalized_scheduled_change: future_change, }) } From ccfb11da7001af80f4485ed180e70443418afc77 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 28 Sep 2020 14:03:47 +0200 Subject: [PATCH 03/12] Revert changes to grandpa --- client/finality-grandpa/src/authorities.rs | 10 +++++----- client/finality-grandpa/src/aux_schema.rs | 3 ++- client/finality-grandpa/src/lib.rs | 1 - 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 78dffd37ab016..7a064d7a6224b 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -101,11 +101,11 @@ pub(crate) struct Status { /// A set of authorities. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub struct AuthoritySet { +pub(crate) struct AuthoritySet { /// The current active authorities. - pub current_authorities: AuthorityList, + pub(crate) current_authorities: AuthorityList, /// The current set id. - pub set_id: u64, + pub(crate) set_id: u64, /// Tree of pending standard changes across forks. Standard changes are /// enacted on finality and must be enacted (i.e. finalized) in-order across /// a given branch @@ -494,7 +494,7 @@ where /// Kinds of delays for pending changes. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub enum DelayKind { +pub(crate) enum DelayKind { /// Depth in finalized chain. Finalized, /// Depth in best chain. The median last finalized block is calculated at the time the @@ -507,7 +507,7 @@ pub enum DelayKind { /// This will be applied when the announcing block is at some depth within /// the finalized or unfinalized chain. #[derive(Debug, Clone, Encode, PartialEq)] -pub struct PendingChange { +pub(crate) struct PendingChange { /// The new authorities and weights to apply. pub(crate) next_authorities: AuthorityList, /// How deep in the chain the announcing block must be diff --git a/client/finality-grandpa/src/aux_schema.rs b/client/finality-grandpa/src/aux_schema.rs index 0f5b8d4faebcc..4ed96d058ac6b 100644 --- a/client/finality-grandpa/src/aux_schema.rs +++ b/client/finality-grandpa/src/aux_schema.rs @@ -433,7 +433,8 @@ pub(crate) fn update_consensus_changes( write_aux(&[(CONSENSUS_CHANGES_KEY, set.encode().as_slice())]) } -pub fn load_authorities(backend: &B) +#[cfg(test)] +pub(crate) fn load_authorities(backend: &B) -> Option> { load_decode::<_, AuthoritySet>(backend, AUTHORITY_SET_KEY) .expect("backend error") diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 1de285dbe41fa..a15130942c30f 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -134,7 +134,6 @@ pub use voting_rule::{ BeforeBestBlockBy, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRulesBuilder }; pub use finality_grandpa::voter::report; -pub use aux_schema::load_authorities; use aux_schema::PersistentData; use environment::{Environment, VoterSetState}; From 35a580a6c74c11cd97586527a03a738f1183ce6b Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Tue, 29 Sep 2020 15:07:59 +0200 Subject: [PATCH 04/12] Change fields to just be the grandpa authority set and babe epoch changes --- Cargo.lock | 7 +- bin/node/cli/Cargo.toml | 1 + bin/node/cli/src/command.rs | 4 +- bin/node/cli/src/service.rs | 10 ++- client/chain-spec/Cargo.toml | 4 +- client/chain-spec/src/chain_spec.rs | 48 ++++--------- client/cli/Cargo.toml | 3 +- .../cli/src/commands/build_sync_spec_cmd.rs | 11 ++- client/finality-grandpa/src/authorities.rs | 8 +-- client/finality-grandpa/src/lib.rs | 2 +- client/service/Cargo.toml | 2 - .../service/src/chain_ops/build_sync_spec.rs | 67 ++----------------- 12 files changed, 49 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e3c5a33cb5f2..af62203d05225 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6291,14 +6291,14 @@ dependencies = [ "parity-scale-codec", "sc-chain-spec-derive", "sc-consensus-babe", + "sc-consensus-epochs", + "sc-finality-grandpa", "sc-network", "sc-telemetry", "serde", "serde_json", "sp-chain-spec", - "sp-consensus-slots", "sp-core", - "sp-finality-grandpa", "sp-runtime", ] @@ -6336,6 +6336,8 @@ dependencies = [ "rpassword", "sc-client-api", "sc-consensus-babe", + "sc-consensus-epochs", + "sc-finality-grandpa", "sc-informant", "sc-keystore", "sc-network", @@ -6344,7 +6346,6 @@ dependencies = [ "sc-tracing", "serde", "serde_json", - "sp-api", "sp-application-crypto", "sp-blockchain", "sp-core", diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 39df211707eaa..058bc5d51d412 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -74,6 +74,7 @@ sc-service = { version = "0.8.0", default-features = false, path = "../../../cli sc-tracing = { version = "2.0.0", path = "../../../client/tracing" } sc-telemetry = { version = "2.0.0", path = "../../../client/telemetry" } sc-authority-discovery = { version = "0.8.0", path = "../../../client/authority-discovery" } +sc-consensus-epochs = { version = "0.8.0", path = "../../../client/consensus/epochs" } # frame dependencies pallet-indices = { version = "2.0.0", path = "../../../frame/indices" } diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 7b84ff5a0583b..6102c6f782dfb 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -105,10 +105,10 @@ pub fn run() -> Result<()> { runner.async_run(|config| { let chain_spec = config.chain_spec.cloned_box(); let network_config = config.network.clone(); - let NewFullBase { task_manager, client, network_status_sinks, .. } + let NewFullBase { task_manager, client, network_status_sinks, shared_authority_set, shared_epoch_changes, .. } = new_full_base(config, |_, _| ())?; - Ok((cmd.run(chain_spec, network_config, client, network_status_sinks), task_manager)) + Ok((cmd.run(chain_spec, network_config, client, network_status_sinks, shared_authority_set, shared_epoch_changes), task_manager)) }) }, Some(Subcommand::CheckBlock(cmd)) => { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index b15ace6181a8f..c301809e0232d 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -31,7 +31,7 @@ use sc_service::{ }; use sp_inherents::InherentDataProviders; use sc_network::{Event, NetworkService}; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use futures::prelude::*; use sc_client_api::{ExecutorProvider, RemoteBackend}; use sp_core::traits::BareCryptoStorePtr; @@ -164,6 +164,8 @@ pub struct NewFullBase { pub network: Arc::Hash>>, pub network_status_sinks: sc_service::NetworkStatusSinks, pub transaction_pool: Arc>, + pub shared_authority_set: grandpa::SharedAuthoritySet<::Hash, NumberFor>, + pub shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, } /// Creates a full service from the configuration. @@ -228,6 +230,8 @@ pub fn new_full_base( (with_startup_data)(&block_import, &babe_link); + let shared_epoch_changes = babe_link.epoch_changes().clone(); + if let sc_service::config::Role::Authority { .. } = &role { let proposer = sc_basic_authorship::ProposerFactory::new( client.clone(), @@ -306,6 +310,8 @@ pub fn new_full_base( is_authority: role.is_network_authority(), }; + let shared_authority_set = grandpa_link.shared_authority_set().clone(); + if enable_grandpa { // start the full GRANDPA voter // NOTE: non-authorities could run the GRANDPA observer protocol, but at @@ -341,7 +347,7 @@ pub fn new_full_base( network_starter.start_network(); Ok(NewFullBase { task_manager, inherent_data_providers, client, network, network_status_sinks, - transaction_pool, + transaction_pool, shared_authority_set, shared_epoch_changes, }) } diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 57c4083ded7da..9648e26e32270 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -23,6 +23,6 @@ sp-runtime = { version = "2.0.0", path = "../../primitives/runtime" } sp-chain-spec = { version = "2.0.0", path = "../../primitives/chain-spec" } sc-telemetry = { version = "2.0.0", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "1.3.4" } -sp-consensus-slots = { version = "0.8.0-rc6", path = "../../primitives/consensus/slots" } sc-consensus-babe = { version = "0.8.0-rc6", path = "../consensus/babe" } -sp-finality-grandpa = { version = "2.0.0-rc6", path = "../../primitives/finality-grandpa" } +sc-consensus-epochs = { version = "0.8.0-rc6", path = "../consensus/epochs" } +sc-finality-grandpa = { version = "0.8.0-rc6", path = "../finality-grandpa" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 0a87e5de6af12..ae5f64ac1fb38 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -401,12 +401,10 @@ where pub struct LightSyncState { /// The header of the best finalized block. pub finalized_block_header: ::Header, - pub babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, - pub babe_finalized_block_epoch_information: sc_consensus_babe::NextEpochDescriptor, - pub babe_finalized_next_epoch_transition: sc_consensus_babe::NextEpochDescriptor, - pub grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, - pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, - pub grandpa_finalized_scheduled_change: sp_finality_grandpa::ScheduledChange>, + /// The epoch changes tree for babe. + pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor, + /// The authority set for grandpa. + pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<::Hash, NumberFor>, } impl LightSyncState { @@ -416,17 +414,10 @@ impl LightSyncState { SerializableLightSyncState { finalized_block_header: StorageData(self.finalized_block_header.encode()), - babe_finalized_block1_slot_number: self.babe_finalized_block1_slot_number, - babe_finalized_block_epoch_information: - StorageData(self.babe_finalized_block_epoch_information.encode()), - babe_finalized_next_epoch_transition: - StorageData(self.babe_finalized_next_epoch_transition.encode()), - grandpa_after_finalized_block_authorities_set_id: - self.grandpa_after_finalized_block_authorities_set_id, - grandpa_finalized_triggered_authorities: - StorageData(self.grandpa_finalized_triggered_authorities.encode()), - grandpa_finalized_scheduled_change: - StorageData(self.grandpa_finalized_scheduled_change.encode()), + babe_epoch_changes: + StorageData(self.babe_epoch_changes.encode()), + grandpa_authority_set: + StorageData(self.grandpa_authority_set.encode()), } } @@ -434,17 +425,10 @@ impl LightSyncState { pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result { Ok(Self { finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, - babe_finalized_block1_slot_number: serialized.babe_finalized_block1_slot_number, - babe_finalized_block_epoch_information: - codec::Decode::decode(&mut &serialized.babe_finalized_block_epoch_information.0[..])?, - babe_finalized_next_epoch_transition: - codec::Decode::decode(&mut &serialized.babe_finalized_next_epoch_transition.0[..])?, - grandpa_after_finalized_block_authorities_set_id: - serialized.grandpa_after_finalized_block_authorities_set_id, - grandpa_finalized_triggered_authorities: - codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, - grandpa_finalized_scheduled_change: - codec::Decode::decode(&mut &serialized.grandpa_finalized_scheduled_change.0[..])?, + babe_epoch_changes: + codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?, + grandpa_authority_set: + codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?, }) } } @@ -455,12 +439,8 @@ impl LightSyncState { #[serde(deny_unknown_fields)] pub struct SerializableLightSyncState { finalized_block_header: StorageData, - babe_finalized_block1_slot_number: sp_consensus_slots::SlotNumber, - babe_finalized_block_epoch_information: StorageData, - babe_finalized_next_epoch_transition: StorageData, - grandpa_after_finalized_block_authorities_set_id: sp_finality_grandpa::SetId, - grandpa_finalized_triggered_authorities: StorageData, - grandpa_finalized_scheduled_change: StorageData, + babe_epoch_changes: StorageData, + grandpa_authority_set: StorageData, } #[cfg(test)] diff --git a/client/cli/Cargo.toml b/client/cli/Cargo.toml index 5d424fc3f527b..110342aa62946 100644 --- a/client/cli/Cargo.toml +++ b/client/cli/Cargo.toml @@ -44,8 +44,9 @@ sp-state-machine = { version = "0.8.0", path = "../../primitives/state-machine" sc-telemetry = { version = "2.0.0", path = "../telemetry" } substrate-prometheus-endpoint = { path = "../../utils/prometheus" , version = "0.8.0"} sp-keyring = { version = "2.0.0", path = "../../primitives/keyring" } -sp-api = { version = "2.0.0", path = "../../primitives/api" } sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } +sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } +sc-finality-grandpa = { version = "0.8.0", path = "../finality-grandpa" } names = "0.11.0" structopt = "0.3.8" sc-tracing = { version = "2.0.0", path = "../tracing" } diff --git a/client/cli/src/commands/build_sync_spec_cmd.rs b/client/cli/src/commands/build_sync_spec_cmd.rs index 2002dc9e78d0d..df5f005983a05 100644 --- a/client/cli/src/commands/build_sync_spec_cmd.rs +++ b/client/cli/src/commands/build_sync_spec_cmd.rs @@ -25,7 +25,7 @@ use sc_service::{config::{MultiaddrWithPeerId, NetworkConfiguration}, ChainSpec} use structopt::StructOpt; use std::io::Write; use std::sync::Arc; -use sp_runtime::traits::Block as BlockT; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use sc_service::chain_ops::build_light_sync_state; use sc_service::NetworkStatusSinks; use futures::{FutureExt, StreamExt}; @@ -71,13 +71,12 @@ impl BuildSyncSpecCmd { network_config: NetworkConfiguration, client: Arc, network_status_sinks: NetworkStatusSinks, + shared_authority_set: sc_finality_grandpa::SharedAuthoritySet<::Hash, NumberFor>, + shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, ) -> error::Result<()> where B: BlockT, - CL: sp_blockchain::HeaderBackend + sp_api::ProvideRuntimeApi + - sc_client_api::AuxStore, - >::Api: - sc_consensus_babe::BabeApi, + CL: sp_blockchain::HeaderBackend, { if self.sync_first { network_status_sinks.status_stream(std::time::Duration::from_secs(1)).filter(|status| { @@ -85,7 +84,7 @@ impl BuildSyncSpecCmd { }).into_future().map(drop).await; } - let light_sync_state = build_light_sync_state(client)?; + let light_sync_state = build_light_sync_state(client, shared_authority_set, shared_epoch_changes)?; spec.set_light_sync_state(light_sync_state.to_serializable()); info!("Building chain spec"); diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 7a064d7a6224b..9b84c2e979e2a 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -53,7 +53,7 @@ impl Clone for SharedAuthoritySet { impl SharedAuthoritySet { /// Acquire a reference to the inner read-write lock. - pub(crate) fn inner(&self) -> &RwLock> { + pub fn inner(&self) -> &RwLock> { &*self.inner } } @@ -101,7 +101,7 @@ pub(crate) struct Status { /// A set of authorities. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub(crate) struct AuthoritySet { +pub struct AuthoritySet { /// The current active authorities. pub(crate) current_authorities: AuthorityList, /// The current set id. @@ -494,7 +494,7 @@ where /// Kinds of delays for pending changes. #[derive(Debug, Clone, Encode, Decode, PartialEq)] -pub(crate) enum DelayKind { +pub enum DelayKind { /// Depth in finalized chain. Finalized, /// Depth in best chain. The median last finalized block is calculated at the time the @@ -507,7 +507,7 @@ pub(crate) enum DelayKind { /// This will be applied when the announcing block is at some depth within /// the finalized or unfinalized chain. #[derive(Debug, Clone, Encode, PartialEq)] -pub(crate) struct PendingChange { +pub struct PendingChange { /// The new authorities and weights to apply. pub(crate) next_authorities: AuthorityList, /// How deep in the chain the announcing block must be diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index a15130942c30f..ab53de888c82a 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -124,7 +124,7 @@ mod observer; mod until_imported; mod voting_rule; -pub use authorities::SharedAuthoritySet; +pub use authorities::{SharedAuthoritySet, AuthoritySet}; pub use finality_proof::{FinalityProofFragment, FinalityProofProvider, StorageAndProofProvider}; pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream}; pub use import::GrandpaBlockImport; diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index e7cbde9500c03..43643f0699e00 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,10 +78,8 @@ sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } tracing = "0.1.19" parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] } sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } -sp-consensus-babe = { version = "0.8.0", path = "../../primitives/consensus/babe" } sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } grandpa = { version = "0.8.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } -grandpa-primitives = { version = "2.0.0", package = "sp-finality-grandpa", path = "../../primitives/finality-grandpa" } [target.'cfg(not(target_os = "unknown"))'.dependencies] tempfile = "3.1.0" diff --git a/client/service/src/chain_ops/build_sync_spec.rs b/client/service/src/chain_ops/build_sync_spec.rs index 7ce0e7dfa131c..3d77f00ffc2df 100644 --- a/client/service/src/chain_ops/build_sync_spec.rs +++ b/client/service/src/chain_ops/build_sync_spec.rs @@ -14,82 +14,27 @@ // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor, One}; +use sp_runtime::traits::{Block as BlockT, NumberFor}; use sp_blockchain::HeaderBackend; use std::sync::Arc; -use sp_runtime::ConsensusEngineId; use sp_runtime::generic::BlockId; -use sc_client_api::{CallExecutor, ExecutorProvider}; - -fn backwards_consensus_log_iter<'a, TBl, TCl, CL, FN, T>( - client: Arc, mut number: NumberFor, engine_id: &'a ConsensusEngineId, func: FN, -) -> impl Iterator> + 'a - where - TBl: BlockT, - TCl: HeaderBackend + 'a, - CL: codec::Decode, - FN: Fn(CL) -> Option + 'a, -{ - let id = sp_runtime::generic::OpaqueDigestItemId::Consensus(engine_id); - - std::iter::from_fn(move || { - let header = match client.header(BlockId::Number(number)) { - Ok(Some(header)) => header, - Ok(None) => return Some(Some(Err(sp_blockchain::Error::Msg("Missing header".into())))), - Err(err) => return Some(Some(Err(err))), - }; - - let change = header.digest() - .convert_first(|l| l.try_to(id).and_then(&func)); - - number -= NumberFor::::one(); - Some(change.map(Ok)) - }).filter_map(|optional_log_item| optional_log_item) -} /// Build a `LightSyncState` from the CHT roots stored in a backend. pub fn build_light_sync_state( client: Arc, + shared_authority_set: grandpa::SharedAuthoritySet<::Hash, NumberFor>, + shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, ) -> Result, sp_blockchain::Error> where TBl: BlockT, - TCl: HeaderBackend + sp_api::ProvideRuntimeApi + sc_client_api::AuxStore, - >::Api: - sc_consensus_babe::BabeApi, + TCl: HeaderBackend, { - let finalized_number = client.info().finalized_number; let finalized_hash = client.info().finalized_hash; let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); - let mut scheduled_changes = backwards_consensus_log_iter( - client.clone(), finalized_number, &grandpa_primitives::GRANDPA_ENGINE_ID, - |log| match log { - grandpa_primitives::ConsensusLog::>::ScheduledChange(change) => Some(change), - grandpa_primitives::ConsensusLog::>::ForcedChange(_, change) => Some(change), - _ => None - } - ); - let future_change = scheduled_changes.next().unwrap()?; - let current_authorities = scheduled_changes.next().unwrap()?.next_authorities; - - let mut babe_epoch_descriptors = backwards_consensus_log_iter( - client.clone(), finalized_number, &sp_consensus_babe::BABE_ENGINE_ID, - |log| match log { - sp_consensus_babe::ConsensusLog::NextEpochData(descriptor)=> Some(descriptor), - _ => None - } - ); - - let next_desc = babe_epoch_descriptors.next().unwrap()?; - let current_desc = babe_epoch_descriptors.next().unwrap()?; - Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, - babe_finalized_block1_slot_number: 0, - babe_finalized_block_epoch_information: current_desc, - babe_finalized_next_epoch_transition: next_desc, - grandpa_finalized_triggered_authorities: current_authorities, - grandpa_after_finalized_block_authorities_set_id: 0, - grandpa_finalized_scheduled_change: future_change, + babe_epoch_changes: shared_epoch_changes.lock().clone(), + grandpa_authority_set: shared_authority_set.inner().read().clone(), }) } From a8f0966794e01fb70ca67b990bce23bccb500525 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Wed, 30 Sep 2020 13:36:29 +0200 Subject: [PATCH 05/12] Only use the fields we need from the shared authority set --- Cargo.lock | 1 + client/chain-spec/Cargo.toml | 1 + client/chain-spec/src/chain_spec.rs | 25 +++++++++++++------ client/finality-grandpa/src/authorities.rs | 6 ++--- client/finality-grandpa/src/lib.rs | 2 +- .../service/src/chain_ops/build_sync_spec.rs | 8 +++++- 6 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af62203d05225..78842afef831c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6299,6 +6299,7 @@ dependencies = [ "serde_json", "sp-chain-spec", "sp-core", + "sp-finality-grandpa", "sp-runtime", ] diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 9648e26e32270..bda14b3091a4d 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -26,3 +26,4 @@ codec = { package = "parity-scale-codec", version = "1.3.4" } sc-consensus-babe = { version = "0.8.0-rc6", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.8.0-rc6", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.8.0-rc6", path = "../finality-grandpa" } +sp-finality-grandpa = { version = "2.0.0-rc6", path = "../../primitives/finality-grandpa" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index ae5f64ac1fb38..a3d13c6fa6e4b 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -403,8 +403,9 @@ pub struct LightSyncState { pub finalized_block_header: ::Header, /// The epoch changes tree for babe. pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor, - /// The authority set for grandpa. - pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<::Hash, NumberFor>, + pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, + pub grandpa_after_finalized_block_authorities_set_id: u64, + pub grandpa_finalized_scheduled_change: sc_finality_grandpa::PendingChange<::Hash, NumberFor> } impl LightSyncState { @@ -416,8 +417,12 @@ impl LightSyncState { finalized_block_header: StorageData(self.finalized_block_header.encode()), babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()), - grandpa_authority_set: - StorageData(self.grandpa_authority_set.encode()), + grandpa_finalized_triggered_authorities: + StorageData(self.grandpa_finalized_triggered_authorities.encode()), + grandpa_after_finalized_block_authorities_set_id: + self.grandpa_after_finalized_block_authorities_set_id, + grandpa_finalized_scheduled_change: + StorageData(self.grandpa_finalized_scheduled_change.encode()), } } @@ -427,8 +432,12 @@ impl LightSyncState { finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?, - grandpa_authority_set: - codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?, + grandpa_finalized_triggered_authorities: + codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, + grandpa_after_finalized_block_authorities_set_id: + serialized.grandpa_after_finalized_block_authorities_set_id, + grandpa_finalized_scheduled_change: + codec::Decode::decode(&mut &serialized.grandpa_finalized_scheduled_change.0[..])?, }) } } @@ -440,7 +449,9 @@ impl LightSyncState { pub struct SerializableLightSyncState { finalized_block_header: StorageData, babe_epoch_changes: StorageData, - grandpa_authority_set: StorageData, + grandpa_finalized_triggered_authorities: StorageData, + grandpa_after_finalized_block_authorities_set_id: u64, + grandpa_finalized_scheduled_change: StorageData, } #[cfg(test)] diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 9b84c2e979e2a..a6ac739e4f4be 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -103,9 +103,9 @@ pub(crate) struct Status { #[derive(Debug, Clone, Encode, Decode, PartialEq)] pub struct AuthoritySet { /// The current active authorities. - pub(crate) current_authorities: AuthorityList, + pub current_authorities: AuthorityList, /// The current set id. - pub(crate) set_id: u64, + pub set_id: u64, /// Tree of pending standard changes across forks. Standard changes are /// enacted on finality and must be enacted (i.e. finalized) in-order across /// a given branch @@ -314,7 +314,7 @@ where /// Inspect pending changes. Standard pending changes are iterated first, /// and the changes in the tree are traversed in pre-order, afterwards all /// forced changes are iterated. - pub(crate) fn pending_changes(&self) -> impl Iterator> { + pub fn pending_changes(&self) -> impl Iterator> { self.pending_standard_changes.iter().map(|(_, _, c)| c) .chain(self.pending_forced_changes.iter()) } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index ab53de888c82a..7bccc80ea0c6c 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -124,7 +124,7 @@ mod observer; mod until_imported; mod voting_rule; -pub use authorities::{SharedAuthoritySet, AuthoritySet}; +pub use authorities::{SharedAuthoritySet, AuthoritySet, PendingChange}; pub use finality_proof::{FinalityProofFragment, FinalityProofProvider, StorageAndProofProvider}; pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream}; pub use import::GrandpaBlockImport; diff --git a/client/service/src/chain_ops/build_sync_spec.rs b/client/service/src/chain_ops/build_sync_spec.rs index 3d77f00ffc2df..67b7c30967040 100644 --- a/client/service/src/chain_ops/build_sync_spec.rs +++ b/client/service/src/chain_ops/build_sync_spec.rs @@ -32,9 +32,15 @@ pub fn build_light_sync_state( let finalized_hash = client.info().finalized_hash; let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); + let authority_set = shared_authority_set.inner().read(); + + let pending_change = authority_set.pending_changes().next().unwrap(); + Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, babe_epoch_changes: shared_epoch_changes.lock().clone(), - grandpa_authority_set: shared_authority_set.inner().read().clone(), + grandpa_finalized_triggered_authorities: authority_set.current_authorities.clone(), + grandpa_after_finalized_block_authorities_set_id: authority_set.set_id, + grandpa_finalized_scheduled_change: pending_change.clone(), }) } From fdd282f0162d678e063f8047a7842e8d979c7f07 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Tue, 6 Oct 2020 16:50:23 +0200 Subject: [PATCH 06/12] Switch to RPC call --- Cargo.lock | 1 + bin/node-template/node/src/service.rs | 2 + bin/node/cli/Cargo.toml | 1 - bin/node/cli/src/cli.rs | 3 - bin/node/cli/src/command.rs | 13 +- bin/node/cli/src/service.rs | 19 ++- client/chain-spec/src/chain_spec.rs | 11 ++ client/chain-spec/src/lib.rs | 2 + .../cli/src/commands/build_sync_spec_cmd.rs | 123 ------------------ client/cli/src/commands/mod.rs | 2 - client/rpc-api/Cargo.toml | 1 + client/rpc-api/src/system/error.rs | 16 +++ client/rpc-api/src/system/mod.rs | 5 + client/rpc/src/system/mod.rs | 20 ++- client/rpc/src/system/tests.rs | 5 +- client/service/src/builder.rs | 18 ++- client/service/src/chain_ops/mod.rs | 2 - client/service/src/lib.rs | 30 ++++- .../build_sync_spec.rs => sync_state.rs} | 4 +- 19 files changed, 115 insertions(+), 163 deletions(-) delete mode 100644 client/cli/src/commands/build_sync_spec_cmd.rs rename client/service/src/{chain_ops/build_sync_spec.rs => sync_state.rs} (93%) diff --git a/Cargo.lock b/Cargo.lock index 78842afef831c..5831bc12f48bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7100,6 +7100,7 @@ dependencies = [ "parking_lot 0.10.2", "serde", "serde_json", + "sp-blockchain", "sp-chain-spec", "sp-core", "sp-rpc", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 3de31dc61ab51..973b6f9961906 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -101,6 +101,7 @@ pub fn new_full(config: Configuration) -> Result { block_announce_validator_builder: None, finality_proof_request_builder: None, finality_proof_provider: Some(finality_proof_provider.clone()), + sync_state_items: None, })?; if config.offchain_worker.enabled { @@ -273,6 +274,7 @@ pub fn new_light(config: Configuration) -> Result { block_announce_validator_builder: None, finality_proof_request_builder: Some(finality_proof_request_builder), finality_proof_provider: Some(finality_proof_provider), + sync_state_items: None, })?; if config.offchain_worker.enabled { diff --git a/bin/node/cli/Cargo.toml b/bin/node/cli/Cargo.toml index 058bc5d51d412..39df211707eaa 100644 --- a/bin/node/cli/Cargo.toml +++ b/bin/node/cli/Cargo.toml @@ -74,7 +74,6 @@ sc-service = { version = "0.8.0", default-features = false, path = "../../../cli sc-tracing = { version = "2.0.0", path = "../../../client/tracing" } sc-telemetry = { version = "2.0.0", path = "../../../client/telemetry" } sc-authority-discovery = { version = "0.8.0", path = "../../../client/authority-discovery" } -sc-consensus-epochs = { version = "0.8.0", path = "../../../client/consensus/epochs" } # frame dependencies pallet-indices = { version = "2.0.0", path = "../../../frame/indices" } diff --git a/bin/node/cli/src/cli.rs b/bin/node/cli/src/cli.rs index 6e51dae93793f..2130ff1e4b106 100644 --- a/bin/node/cli/src/cli.rs +++ b/bin/node/cli/src/cli.rs @@ -59,9 +59,6 @@ pub enum Subcommand { /// Build a chain specification. BuildSpec(sc_cli::BuildSpecCmd), - /// Build a chain specification with a light client sync state. - BuildSyncSpec(sc_cli::BuildSyncSpecCmd), - /// Validate blocks. CheckBlock(sc_cli::CheckBlockCmd), diff --git a/bin/node/cli/src/command.rs b/bin/node/cli/src/command.rs index 6102c6f782dfb..e75c8b17dfe1a 100644 --- a/bin/node/cli/src/command.rs +++ b/bin/node/cli/src/command.rs @@ -21,7 +21,7 @@ use node_executor::Executor; use node_runtime::{Block, RuntimeApi}; use sc_cli::{Result, SubstrateCli, RuntimeVersion, Role, ChainSpec}; use sc_service::PartialComponents; -use crate::service::{new_partial, new_full_base, NewFullBase}; +use crate::service::new_partial; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -100,17 +100,6 @@ pub fn run() -> Result<()> { let runner = cli.create_runner(cmd)?; runner.sync_run(|config| cmd.run(config.chain_spec, config.network)) }, - Some(Subcommand::BuildSyncSpec(cmd)) => { - let runner = cli.create_runner(cmd)?; - runner.async_run(|config| { - let chain_spec = config.chain_spec.cloned_box(); - let network_config = config.network.clone(); - let NewFullBase { task_manager, client, network_status_sinks, shared_authority_set, shared_epoch_changes, .. } - = new_full_base(config, |_, _| ())?; - - Ok((cmd.run(chain_spec, network_config, client, network_status_sinks, shared_authority_set, shared_epoch_changes), task_manager)) - }) - }, Some(Subcommand::CheckBlock(cmd)) => { let runner = cli.create_runner(cmd)?; runner.async_run(|config| { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index c301809e0232d..fab3fcf81f370 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -31,7 +31,7 @@ use sc_service::{ }; use sp_inherents::InherentDataProviders; use sc_network::{Event, NetworkService}; -use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_runtime::traits::Block as BlockT; use futures::prelude::*; use sc_client_api::{ExecutorProvider, RemoteBackend}; use sp_core::traits::BareCryptoStorePtr; @@ -164,8 +164,6 @@ pub struct NewFullBase { pub network: Arc::Hash>>, pub network_status_sinks: sc_service::NetworkStatusSinks, pub transaction_pool: Arc>, - pub shared_authority_set: grandpa::SharedAuthoritySet<::Hash, NumberFor>, - pub shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, } /// Creates a full service from the configuration. @@ -183,6 +181,9 @@ pub fn new_full_base( } = new_partial(&config)?; let (shared_voter_state, finality_proof_provider) = rpc_setup; + let (block_import, grandpa_link, babe_link) = import_setup; + let shared_authority_set = grandpa_link.shared_authority_set().clone(); + let shared_epoch_changes = babe_link.epoch_changes().clone(); let (network, network_status_sinks, system_rpc_tx, network_starter) = sc_service::build_network(sc_service::BuildNetworkParams { @@ -195,6 +196,9 @@ pub fn new_full_base( block_announce_validator_builder: None, finality_proof_request_builder: None, finality_proof_provider: Some(finality_proof_provider.clone()), + sync_state_items: Some(( + shared_authority_set.clone(), shared_epoch_changes.clone(), + )) })?; if config.offchain_worker.enabled { @@ -226,12 +230,8 @@ pub fn new_full_base( system_rpc_tx, })?; - let (block_import, grandpa_link, babe_link) = import_setup; - (with_startup_data)(&block_import, &babe_link); - let shared_epoch_changes = babe_link.epoch_changes().clone(); - if let sc_service::config::Role::Authority { .. } = &role { let proposer = sc_basic_authorship::ProposerFactory::new( client.clone(), @@ -310,8 +310,6 @@ pub fn new_full_base( is_authority: role.is_network_authority(), }; - let shared_authority_set = grandpa_link.shared_authority_set().clone(); - if enable_grandpa { // start the full GRANDPA voter // NOTE: non-authorities could run the GRANDPA observer protocol, but at @@ -347,7 +345,7 @@ pub fn new_full_base( network_starter.start_network(); Ok(NewFullBase { task_manager, inherent_data_providers, client, network, network_status_sinks, - transaction_pool, shared_authority_set, shared_epoch_changes, + transaction_pool, }) } @@ -421,6 +419,7 @@ pub fn new_light_base(config: Configuration) -> Result<( block_announce_validator_builder: None, finality_proof_request_builder: Some(finality_proof_request_builder), finality_proof_provider: Some(finality_proof_provider), + sync_state_items: None, })?; network_starter.start_network(); diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index a3d13c6fa6e4b..fd052e44bb20d 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -333,6 +333,13 @@ impl ChainSpec { json::to_string_pretty(&container) .map_err(|e| format!("Error generating spec json: {}", e)) } + + /// Dump to json value + pub fn as_json_value(&self, raw: bool) -> Result { + let container = self.json_container(raw)?; + json::to_value(container) + .map_err(|e| format!("Error generating spec json: {}", e)) + } } impl crate::ChainSpec for ChainSpec @@ -380,6 +387,10 @@ where ChainSpec::as_json(self, raw) } + fn as_json_value(&self, raw: bool) -> Result { + ChainSpec::as_json_value(self, raw) + } + fn as_storage_builder(&self) -> &dyn BuildStorage { self } diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index f5afe496f1980..a1802d5b523e3 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -149,6 +149,8 @@ pub trait ChainSpec: BuildStorage + Send { fn add_boot_node(&mut self, addr: MultiaddrWithPeerId); /// Return spec as JSON. fn as_json(&self, raw: bool) -> Result; + /// Return spec as JSON value. + fn as_json_value(&self, raw: bool) -> Result; /// Return StorageBuilder for this spec. fn as_storage_builder(&self) -> &dyn BuildStorage; /// Returns a cloned `Box`. diff --git a/client/cli/src/commands/build_sync_spec_cmd.rs b/client/cli/src/commands/build_sync_spec_cmd.rs deleted file mode 100644 index df5f005983a05..0000000000000 --- a/client/cli/src/commands/build_sync_spec_cmd.rs +++ /dev/null @@ -1,123 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) 2018-2020 Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program 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. - -// This program 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 this program. If not, see . - -use crate::error; -use crate::params::{SharedParams, NetworkParams, ImportParams}; -use crate::CliConfiguration; -use log::info; -use sc_network::config::build_multiaddr; -use sc_service::{config::{MultiaddrWithPeerId, NetworkConfiguration}, ChainSpec}; -use structopt::StructOpt; -use std::io::Write; -use std::sync::Arc; -use sp_runtime::traits::{Block as BlockT, NumberFor}; -use sc_service::chain_ops::build_light_sync_state; -use sc_service::NetworkStatusSinks; -use futures::{FutureExt, StreamExt}; -use futures::future::ready; - -/// The `build-sync-spec` command used to build a chain spec that contains a light client state -/// so that light clients can sync faster. -#[derive(Debug, StructOpt)] -pub struct BuildSyncSpecCmd { - /// Force raw genesis storage output. - #[structopt(long = "raw")] - pub raw: bool, - - /// Sync the chain using a full client first. - #[structopt(long)] - pub sync_first: bool, - - /// Disable adding the default bootnode to the specification. - /// - /// By default the `/ip4/127.0.0.1/tcp/30333/p2p/NODE_PEER_ID` bootnode is added to the - /// specification when no bootnode exists. - #[structopt(long = "disable-default-bootnode")] - pub disable_default_bootnode: bool, - - #[allow(missing_docs)] - #[structopt(flatten)] - pub shared_params: SharedParams, - - #[allow(missing_docs)] - #[structopt(flatten)] - pub network_params: NetworkParams, - - #[allow(missing_docs)] - #[structopt(flatten)] - pub import_params: ImportParams, -} - -impl BuildSyncSpecCmd { - /// Run the build-sync-spec command - pub async fn run( - &self, - mut spec: Box, - network_config: NetworkConfiguration, - client: Arc, - network_status_sinks: NetworkStatusSinks, - shared_authority_set: sc_finality_grandpa::SharedAuthoritySet<::Hash, NumberFor>, - shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, - ) -> error::Result<()> - where - B: BlockT, - CL: sp_blockchain::HeaderBackend, - { - if self.sync_first { - network_status_sinks.status_stream(std::time::Duration::from_secs(1)).filter(|status| { - ready(status.sync_state == sc_network::SyncState::Idle && status.num_sync_peers > 0) - }).into_future().map(drop).await; - } - - let light_sync_state = build_light_sync_state(client, shared_authority_set, shared_epoch_changes)?; - spec.set_light_sync_state(light_sync_state.to_serializable()); - - info!("Building chain spec"); - let raw_output = self.raw; - - if spec.boot_nodes().is_empty() && !self.disable_default_bootnode { - let keys = network_config.node_key.into_keypair()?; - let peer_id = keys.public().into_peer_id(); - let addr = MultiaddrWithPeerId { - multiaddr: build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(30333u16)], - peer_id, - }; - spec.add_boot_node(addr) - } - - let json = sc_service::chain_ops::build_spec(&*spec, raw_output)?; - if std::io::stdout().write_all(json.as_bytes()).is_err() { - let _ = std::io::stderr().write_all(b"Error writing to stdout\n"); - } - Ok(()) - } -} - -impl CliConfiguration for BuildSyncSpecCmd { - fn shared_params(&self) -> &SharedParams { - &self.shared_params - } - - fn network_params(&self) -> Option<&NetworkParams> { - Some(&self.network_params) - } - - fn import_params(&self) -> Option<&ImportParams> { - Some(&self.import_params) - } -} diff --git a/client/cli/src/commands/mod.rs b/client/cli/src/commands/mod.rs index 899abf0c3d437..7b740d1003238 100644 --- a/client/cli/src/commands/mod.rs +++ b/client/cli/src/commands/mod.rs @@ -16,7 +16,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . mod build_spec_cmd; -mod build_sync_spec_cmd; mod check_block_cmd; mod export_blocks_cmd; mod export_state_cmd; @@ -37,7 +36,6 @@ pub mod utils; pub use self::{ build_spec_cmd::BuildSpecCmd, - build_sync_spec_cmd::BuildSyncSpecCmd, check_block_cmd::CheckBlockCmd, export_blocks_cmd::ExportBlocksCmd, export_state_cmd::ExportStateCmd, diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 55eb51d261cdb..97396e4137a2a 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -30,3 +30,4 @@ serde = { version = "1.0.101", features = ["derive"] } serde_json = "1.0.41" sp-transaction-pool = { version = "2.0.0", path = "../../primitives/transaction-pool" } sp-rpc = { version = "2.0.0", path = "../../primitives/rpc" } +sp-blockchain = { version = "2.0.0", path = "../../primitives/blockchain" } diff --git a/client/rpc-api/src/system/error.rs b/client/rpc-api/src/system/error.rs index 4897aa485cbe4..ea163e12de269 100644 --- a/client/rpc-api/src/system/error.rs +++ b/client/rpc-api/src/system/error.rs @@ -32,6 +32,12 @@ pub enum Error { NotHealthy(Health), /// Peer argument is malformatted. MalformattedPeerArg(String), + /// An error that occurred while trying to generate the sync state. + #[display(fmt = "{}. Try syncing the node some more.", _0)] + GenSyncState(sp_blockchain::Error), + /// BuildNetworkParams::sync_state_items has not been set. + #[display(fmt = "BuildNetworkParams::sync_state_items has not been set.")] + MissingSyncStateItems, } impl std::error::Error for Error {} @@ -51,6 +57,16 @@ impl From for rpc::Error { code :rpc::ErrorCode::ServerError(BASE_ERROR + 2), message: e.clone(), data: None, + }, + Error::GenSyncState(_) => rpc::Error { + code :rpc::ErrorCode::ServerError(BASE_ERROR + 3), + message: e.to_string(), + data: None, + }, + Error::MissingSyncStateItems => rpc::Error { + code :rpc::ErrorCode::ServerError(BASE_ERROR + 4), + message: e.to_string(), + data: None, } } } diff --git a/client/rpc-api/src/system/mod.rs b/client/rpc-api/src/system/mod.rs index a7b746ee1b114..a1bea058d965f 100644 --- a/client/rpc-api/src/system/mod.rs +++ b/client/rpc-api/src/system/mod.rs @@ -103,4 +103,9 @@ pub trait SystemApi { /// Returns the roles the node is running as. #[rpc(name = "system_nodeRoles", returns = "Vec")] fn system_node_roles(&self) -> Receiver>; + + /// Returns the json-serialized chainspec running the node, with a sync state. + #[rpc(name = "system_genSyncSpec", returns = "jsonrpc_core::Value")] + fn system_gen_sync_spec(&self, raw: bool) + -> Compat>>; } diff --git a/client/rpc/src/system/mod.rs b/client/rpc/src/system/mod.rs index 4b8abbe144462..74d0f8b798a53 100644 --- a/client/rpc/src/system/mod.rs +++ b/client/rpc/src/system/mod.rs @@ -66,7 +66,9 @@ pub enum Request { /// Must return any potential parse error. NetworkRemoveReservedPeer(String, oneshot::Sender>), /// Must return the node role. - NodeRoles(oneshot::Sender>) + NodeRoles(oneshot::Sender>), + /// Must return either a chain spec with a snc state encoded as a `Value` or an error. + GenSyncSpec(bool, oneshot::Sender>), } impl System { @@ -189,4 +191,20 @@ impl SystemApi::Number> for Sy let _ = self.send_back.unbounded_send(Request::NodeRoles(tx)); Receiver(Compat::new(rx)) } + + fn system_gen_sync_spec(&self, raw: bool) + -> Compat>> + { + bail_if_unsafe!(self.deny_unsafe); + + let (tx, rx) = oneshot::channel(); + let _ = self.send_back.unbounded_send(Request::GenSyncSpec(raw, tx)); + async move { + match rx.await { + Ok(Ok(value)) => Ok(value), + Ok(Err(e)) => Err(rpc::Error::from(e)), + Err(_) => Err(rpc::Error::internal_error()), + } + }.boxed().compat() + } } diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index f16d7da5b1a8b..b5c2b920df123 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -103,7 +103,10 @@ fn api>>(sync: T) -> System { } Request::NodeRoles(sender) => { let _ = sender.send(vec![NodeRole::Authority]); - } + }, + Request::GenSyncSpec(_, _, sender) => { + let _ = sender.send(Ok(serde_json::Value::Null)); + }, }; future::ready(()) diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index 410198af26da3..7a4160b2c3e29 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -25,7 +25,7 @@ use crate::{ config::{Configuration, KeystoreConfig, PrometheusConfig}, }; use sc_client_api::{ - light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider, + light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider, AuxStore, }; use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sc_chain_spec::get_extension; @@ -42,7 +42,7 @@ use sc_network::NetworkService; use parking_lot::RwLock; use sp_runtime::generic::BlockId; use sp_runtime::traits::{ - Block as BlockT, SaturatedConversion, HashFor, Zero, BlockIdTo, + Block as BlockT, SaturatedConversion, HashFor, Zero, BlockIdTo, NumberFor, }; use sp_api::{ProvideRuntimeApi, CallApiAt}; use sc_executor::{NativeExecutor, NativeExecutionDispatch, RuntimeInfo}; @@ -780,6 +780,12 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { pub finality_proof_request_builder: Option>, /// An optional, shared finality proof request provider. pub finality_proof_provider: Option>>, + /// Shared GRANDPA and BABE items that are used to generate sync states to be used by light + /// clients. Only generated on full clients. + pub sync_state_items: Option<( + grandpa::SharedAuthoritySet<::Hash, NumberFor>, + sc_consensus_epochs::SharedEpochChanges, + )> } /// Build the network service, the network status sinks and an RPC sender. @@ -798,12 +804,12 @@ pub fn build_network( TBl: BlockT, TCl: ProvideRuntimeApi + HeaderMetadata + Chain + BlockBackend + BlockIdTo + ProofProvider + - HeaderBackend + BlockchainEvents + 'static, + HeaderBackend + BlockchainEvents + AuxStore + 'static, TExPool: MaintainedTransactionPool::Hash> + 'static, TImpQu: ImportQueue + 'static, { let BuildNetworkParams { - config, client, transaction_pool, spawn_handle, import_queue, on_demand, + config, client, transaction_pool, spawn_handle, import_queue, on_demand, sync_state_items, block_announce_validator_builder, finality_proof_request_builder, finality_proof_provider, } = params; @@ -867,6 +873,10 @@ pub fn build_network( system_rpc_rx, has_bootnodes, config.announce_block, + sync_state_items.map(|(auth_set, epoch_changes)| ( + config.chain_spec.cloned_box(), + auth_set, epoch_changes, + )) ); // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the diff --git a/client/service/src/chain_ops/mod.rs b/client/service/src/chain_ops/mod.rs index e6b2fdfb8e0e6..af6e6f632fc06 100644 --- a/client/service/src/chain_ops/mod.rs +++ b/client/service/src/chain_ops/mod.rs @@ -21,11 +21,9 @@ mod export_blocks; mod export_raw_state; mod import_blocks; mod revert_chain; -mod build_sync_spec; pub use check_block::*; pub use export_blocks::*; pub use export_raw_state::*; pub use import_blocks::*; pub use revert_chain::*; -pub use build_sync_spec::*; diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 39f1dff289a1a..88d2df2296da0 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -32,6 +32,7 @@ mod builder; pub mod client; #[cfg(not(feature = "test-helpers"))] mod client; +mod sync_state; mod task_manager; use std::{io, pin::Pin}; @@ -46,9 +47,11 @@ use sc_network::{NetworkStatus, network_state::NetworkState, PeerId}; use log::{warn, debug, error}; use codec::{Encode, Decode}; use sp_runtime::generic::BlockId; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; use parity_util_mem::MallocSizeOf; use sp_utils::{status_sinks, mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}}; +use sp_blockchain::HeaderBackend; +use sc_client_api::{AuxStore, BlockchainEvents}; pub use self::error::Error; pub use self::builder::{ @@ -80,7 +83,6 @@ pub use sc_tracing::TracingReceiver; pub use task_manager::SpawnTaskHandle; pub use task_manager::TaskManager; pub use sp_consensus::import_queue::ImportQueue; -use sc_client_api::BlockchainEvents; pub use sc_keystore::KeyStorePtr as KeyStore; const DEFAULT_PROTOCOL_ID: &str = "sup"; @@ -200,7 +202,7 @@ pub struct PartialComponents, + C: BlockchainEvents + HeaderBackend + AuxStore, H: sc_network::ExHashT > ( role: Role, @@ -210,6 +212,11 @@ async fn build_network_future< mut rpc_rx: TracingUnboundedReceiver>, should_have_peers: bool, announce_imported_blocks: bool, + sync_state_items: Option<( + Box, + grandpa::SharedAuthoritySet<::Hash, NumberFor>, + sc_consensus_epochs::SharedEpochChanges, + )>, ) { let mut imported_blocks_stream = client.import_notification_stream().fuse(); @@ -323,6 +330,23 @@ async fn build_network_future< }; let _ = sender.send(vec![node_role]); + }, + sc_rpc::system::Request::GenSyncSpec(raw, sender) => { + let result = sync_state_items + .as_ref() + .ok_or(sc_rpc::system::error::Error::MissingSyncStateItems) + .and_then(|(chain_spec, auth_set, epoch_changes)| { + let mut chain_spec = chain_spec.cloned_box(); + + let sync_state = crate::sync_state::build_light_sync_state( + client.clone(), auth_set.clone(), epoch_changes.clone(), + )?; + chain_spec.set_light_sync_state(sync_state.to_serializable()); + chain_spec.as_json_value(raw).map_err(|err| { + sp_blockchain::Error::Msg(err).into() + }) + }); + let _ = sender.send(result); } } } diff --git a/client/service/src/chain_ops/build_sync_spec.rs b/client/service/src/sync_state.rs similarity index 93% rename from client/service/src/chain_ops/build_sync_spec.rs rename to client/service/src/sync_state.rs index 67b7c30967040..fc10c78ec0bc2 100644 --- a/client/service/src/chain_ops/build_sync_spec.rs +++ b/client/service/src/sync_state.rs @@ -34,7 +34,9 @@ pub fn build_light_sync_state( let authority_set = shared_authority_set.inner().read(); - let pending_change = authority_set.pending_changes().next().unwrap(); + let pending_change = authority_set.pending_changes().next().ok_or_else(|| { + "No next pending change in the authority set" + })?; Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, From 7f28aa9eb9dc60219b1a73b1a0261520e1c2fda1 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 9 Oct 2020 13:30:33 +0200 Subject: [PATCH 07/12] Revert "Only use the fields we need from the shared authority set" This reverts commit a8f0966794e01fb70ca67b990bce23bccb500525. --- Cargo.lock | 1 - client/chain-spec/Cargo.toml | 1 - client/chain-spec/src/chain_spec.rs | 25 ++++++---------------- client/finality-grandpa/src/authorities.rs | 6 +++--- client/finality-grandpa/src/lib.rs | 2 +- client/service/src/sync_state.rs | 10 +-------- 6 files changed, 12 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6af5990a97970..acefd543ad8b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6299,7 +6299,6 @@ dependencies = [ "serde_json", "sp-chain-spec", "sp-core", - "sp-finality-grandpa", "sp-runtime", ] diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index bda14b3091a4d..9648e26e32270 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -26,4 +26,3 @@ codec = { package = "parity-scale-codec", version = "1.3.4" } sc-consensus-babe = { version = "0.8.0-rc6", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.8.0-rc6", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.8.0-rc6", path = "../finality-grandpa" } -sp-finality-grandpa = { version = "2.0.0-rc6", path = "../../primitives/finality-grandpa" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index fd052e44bb20d..313022f72ea63 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -414,9 +414,8 @@ pub struct LightSyncState { pub finalized_block_header: ::Header, /// The epoch changes tree for babe. pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor, - pub grandpa_finalized_triggered_authorities: sp_finality_grandpa::AuthorityList, - pub grandpa_after_finalized_block_authorities_set_id: u64, - pub grandpa_finalized_scheduled_change: sc_finality_grandpa::PendingChange<::Hash, NumberFor> + /// The authority set for grandpa. + pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<::Hash, NumberFor>, } impl LightSyncState { @@ -428,12 +427,8 @@ impl LightSyncState { finalized_block_header: StorageData(self.finalized_block_header.encode()), babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()), - grandpa_finalized_triggered_authorities: - StorageData(self.grandpa_finalized_triggered_authorities.encode()), - grandpa_after_finalized_block_authorities_set_id: - self.grandpa_after_finalized_block_authorities_set_id, - grandpa_finalized_scheduled_change: - StorageData(self.grandpa_finalized_scheduled_change.encode()), + grandpa_authority_set: + StorageData(self.grandpa_authority_set.encode()), } } @@ -443,12 +438,8 @@ impl LightSyncState { finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?, - grandpa_finalized_triggered_authorities: - codec::Decode::decode(&mut &serialized.grandpa_finalized_triggered_authorities.0[..])?, - grandpa_after_finalized_block_authorities_set_id: - serialized.grandpa_after_finalized_block_authorities_set_id, - grandpa_finalized_scheduled_change: - codec::Decode::decode(&mut &serialized.grandpa_finalized_scheduled_change.0[..])?, + grandpa_authority_set: + codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?, }) } } @@ -460,9 +451,7 @@ impl LightSyncState { pub struct SerializableLightSyncState { finalized_block_header: StorageData, babe_epoch_changes: StorageData, - grandpa_finalized_triggered_authorities: StorageData, - grandpa_after_finalized_block_authorities_set_id: u64, - grandpa_finalized_scheduled_change: StorageData, + grandpa_authority_set: StorageData, } #[cfg(test)] diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index a6ac739e4f4be..9b84c2e979e2a 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -103,9 +103,9 @@ pub(crate) struct Status { #[derive(Debug, Clone, Encode, Decode, PartialEq)] pub struct AuthoritySet { /// The current active authorities. - pub current_authorities: AuthorityList, + pub(crate) current_authorities: AuthorityList, /// The current set id. - pub set_id: u64, + pub(crate) set_id: u64, /// Tree of pending standard changes across forks. Standard changes are /// enacted on finality and must be enacted (i.e. finalized) in-order across /// a given branch @@ -314,7 +314,7 @@ where /// Inspect pending changes. Standard pending changes are iterated first, /// and the changes in the tree are traversed in pre-order, afterwards all /// forced changes are iterated. - pub fn pending_changes(&self) -> impl Iterator> { + pub(crate) fn pending_changes(&self) -> impl Iterator> { self.pending_standard_changes.iter().map(|(_, _, c)| c) .chain(self.pending_forced_changes.iter()) } diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index 7bccc80ea0c6c..ab53de888c82a 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -124,7 +124,7 @@ mod observer; mod until_imported; mod voting_rule; -pub use authorities::{SharedAuthoritySet, AuthoritySet, PendingChange}; +pub use authorities::{SharedAuthoritySet, AuthoritySet}; pub use finality_proof::{FinalityProofFragment, FinalityProofProvider, StorageAndProofProvider}; pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream}; pub use import::GrandpaBlockImport; diff --git a/client/service/src/sync_state.rs b/client/service/src/sync_state.rs index fc10c78ec0bc2..3d77f00ffc2df 100644 --- a/client/service/src/sync_state.rs +++ b/client/service/src/sync_state.rs @@ -32,17 +32,9 @@ pub fn build_light_sync_state( let finalized_hash = client.info().finalized_hash; let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); - let authority_set = shared_authority_set.inner().read(); - - let pending_change = authority_set.pending_changes().next().ok_or_else(|| { - "No next pending change in the authority set" - })?; - Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, babe_epoch_changes: shared_epoch_changes.lock().clone(), - grandpa_finalized_triggered_authorities: authority_set.current_authorities.clone(), - grandpa_after_finalized_block_authorities_set_id: authority_set.set_id, - grandpa_finalized_scheduled_change: pending_change.clone(), + grandpa_authority_set: shared_authority_set.inner().read().clone(), }) } From 81ac0ab84792f57fb9bbaa2bb40f5208685907fb Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 9 Oct 2020 13:53:38 +0200 Subject: [PATCH 08/12] Add babe_finalized_block_weight from `ashley-improve-sync-state-WIP-loading` --- Cargo.lock | 1 + client/chain-spec/Cargo.toml | 1 + client/chain-spec/src/chain_spec.rs | 7 +++++++ client/consensus/babe/src/aux_schema.rs | 2 +- client/service/src/sync_state.rs | 8 +++++++- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 331d28d2b68e2..f7c7d4f99067a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6323,6 +6323,7 @@ dependencies = [ "serde", "serde_json", "sp-chain-spec", + "sp-consensus-babe", "sp-core", "sp-runtime", ] diff --git a/client/chain-spec/Cargo.toml b/client/chain-spec/Cargo.toml index 9648e26e32270..79f14058aad6d 100644 --- a/client/chain-spec/Cargo.toml +++ b/client/chain-spec/Cargo.toml @@ -24,5 +24,6 @@ sp-chain-spec = { version = "2.0.0", path = "../../primitives/chain-spec" } sc-telemetry = { version = "2.0.0", path = "../telemetry" } codec = { package = "parity-scale-codec", version = "1.3.4" } sc-consensus-babe = { version = "0.8.0-rc6", path = "../consensus/babe" } +sp-consensus-babe = { version = "0.8.0-rc6", path = "../../primitives/consensus/babe" } sc-consensus-epochs = { version = "0.8.0-rc6", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.8.0-rc6", path = "../finality-grandpa" } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 313022f72ea63..5f4fb1808ff36 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -414,6 +414,8 @@ pub struct LightSyncState { pub finalized_block_header: ::Header, /// The epoch changes tree for babe. pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor, + /// The babe weight of the finalized block. + pub babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight, /// The authority set for grandpa. pub grandpa_authority_set: sc_finality_grandpa::AuthoritySet<::Hash, NumberFor>, } @@ -427,6 +429,8 @@ impl LightSyncState { finalized_block_header: StorageData(self.finalized_block_header.encode()), babe_epoch_changes: StorageData(self.babe_epoch_changes.encode()), + babe_finalized_block_weight: + self.babe_finalized_block_weight, grandpa_authority_set: StorageData(self.grandpa_authority_set.encode()), } @@ -438,6 +442,8 @@ impl LightSyncState { finalized_block_header: codec::Decode::decode(&mut &serialized.finalized_block_header.0[..])?, babe_epoch_changes: codec::Decode::decode(&mut &serialized.babe_epoch_changes.0[..])?, + babe_finalized_block_weight: + serialized.babe_finalized_block_weight, grandpa_authority_set: codec::Decode::decode(&mut &serialized.grandpa_authority_set.0[..])?, }) @@ -451,6 +457,7 @@ impl LightSyncState { pub struct SerializableLightSyncState { finalized_block_header: StorageData, babe_epoch_changes: StorageData, + babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight, grandpa_authority_set: StorageData, } diff --git a/client/consensus/babe/src/aux_schema.rs b/client/consensus/babe/src/aux_schema.rs index 74078b4ee7b8a..287121566a417 100644 --- a/client/consensus/babe/src/aux_schema.rs +++ b/client/consensus/babe/src/aux_schema.rs @@ -126,7 +126,7 @@ pub(crate) fn write_block_weight( } /// Load the cumulative chain-weight associated with a block. -pub(crate) fn load_block_weight( +pub fn load_block_weight( backend: &B, block_hash: H, ) -> ClientResult> { diff --git a/client/service/src/sync_state.rs b/client/service/src/sync_state.rs index 3d77f00ffc2df..15c322a326ea2 100644 --- a/client/service/src/sync_state.rs +++ b/client/service/src/sync_state.rs @@ -27,14 +27,20 @@ pub fn build_light_sync_state( ) -> Result, sp_blockchain::Error> where TBl: BlockT, - TCl: HeaderBackend, + TCl: HeaderBackend + sc_client_api::AuxStore, { let finalized_hash = client.info().finalized_hash; let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); + let finalized_block_weight = sc_consensus_babe::aux_schema::load_block_weight( + &*client, + finalized_hash, + )?.unwrap(); + Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, babe_epoch_changes: shared_epoch_changes.lock().clone(), + babe_finalized_block_weight: finalized_block_weight, grandpa_authority_set: shared_authority_set.inner().read().clone(), }) } From 136231b2b6ddd4446f7a081619845c8e435ff94f Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Fri, 9 Oct 2020 14:37:37 +0200 Subject: [PATCH 09/12] Fix rpc test --- client/rpc/src/system/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index b5c2b920df123..fc9e92487625e 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -104,7 +104,7 @@ fn api>>(sync: T) -> System { Request::NodeRoles(sender) => { let _ = sender.send(vec![NodeRole::Authority]); }, - Request::GenSyncSpec(_, _, sender) => { + Request::GenSyncSpec(_, sender) => { let _ = sender.send(Ok(serde_json::Value::Null)); }, }; From d94adf1795ea4343cef94c7081c6a7054fddf09c Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 12 Oct 2020 13:05:17 +0200 Subject: [PATCH 10/12] Move sync state rpc stuff into sc-sync-state-rpc --- Cargo.lock | 22 ++++- Cargo.toml | 1 + bin/node-template/node/src/service.rs | 2 - bin/node/cli/src/service.rs | 11 +-- bin/node/rpc/Cargo.toml | 2 + bin/node/rpc/src/lib.rs | 27 ++++-- client/chain-spec/src/chain_spec.rs | 2 +- client/chain-spec/src/lib.rs | 2 +- client/rpc-api/Cargo.toml | 1 - client/rpc-api/src/system/error.rs | 16 ---- client/rpc-api/src/system/mod.rs | 5 -- client/rpc/src/system/mod.rs | 20 +---- client/rpc/src/system/tests.rs | 5 +- client/service/Cargo.toml | 3 - client/service/src/builder.rs | 18 +--- client/service/src/lib.rs | 30 +------ client/service/src/sync_state.rs | 46 ---------- client/service/test/src/lib.rs | 10 +-- client/sync-state-rpc/Cargo.toml | 26 ++++++ client/sync-state-rpc/src/lib.rs | 118 ++++++++++++++++++++++++++ utils/browser/src/lib.rs | 2 +- 21 files changed, 208 insertions(+), 161 deletions(-) delete mode 100644 client/service/src/sync_state.rs create mode 100644 client/sync-state-rpc/Cargo.toml create mode 100644 client/sync-state-rpc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index f7c7d4f99067a..6833d87a3e771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3826,6 +3826,7 @@ dependencies = [ "node-runtime", "pallet-contracts-rpc", "pallet-transaction-payment-rpc", + "sc-chain-spec", "sc-client-api", "sc-consensus-babe", "sc-consensus-babe-rpc", @@ -3835,6 +3836,7 @@ dependencies = [ "sc-keystore", "sc-rpc", "sc-rpc-api", + "sc-sync-state-rpc", "sp-api", "sp-block-builder", "sp-blockchain", @@ -7136,7 +7138,6 @@ dependencies = [ "parking_lot 0.10.2", "serde", "serde_json", - "sp-blockchain", "sp-chain-spec", "sp-core", "sp-rpc", @@ -7200,8 +7201,6 @@ dependencies = [ "sc-chain-spec", "sc-client-api", "sc-client-db", - "sc-consensus-babe", - "sc-consensus-epochs", "sc-executor", "sc-finality-grandpa", "sc-informant", @@ -7294,6 +7293,23 @@ dependencies = [ "sp-core", ] +[[package]] +name = "sc-sync-state-rpc" +version = "0.8.0" +dependencies = [ + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "sc-chain-spec", + "sc-client-api", + "sc-consensus-babe", + "sc-consensus-epochs", + "sc-finality-grandpa", + "sc-rpc-api", + "sp-blockchain", + "sp-runtime", +] + [[package]] name = "sc-telemetry" version = "2.0.0" diff --git a/Cargo.toml b/Cargo.toml index ecea10cc45582..1d6235c0abcd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,6 +53,7 @@ members = [ "client/service", "client/service/test", "client/state-db", + "client/sync-state-rpc", "client/telemetry", "client/transaction-pool", "client/transaction-pool/graph", diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 6c33fe1398402..8a9e9bfad882a 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -101,7 +101,6 @@ pub fn new_full(config: Configuration) -> Result { block_announce_validator_builder: None, finality_proof_request_builder: None, finality_proof_provider: Some(finality_proof_provider.clone()), - sync_state_items: None, })?; if config.offchain_worker.enabled { @@ -274,7 +273,6 @@ pub fn new_light(config: Configuration) -> Result { block_announce_validator_builder: None, finality_proof_request_builder: Some(finality_proof_request_builder), finality_proof_provider: Some(finality_proof_provider), - sync_state_items: None, })?; if config.offchain_worker.enabled { diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index efc03ef6032bb..adc5fe4fd58ff 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -122,12 +122,14 @@ pub fn new_partial(config: &Configuration) -> Result Result<( block_announce_validator_builder: None, finality_proof_request_builder: Some(finality_proof_request_builder), finality_proof_provider: Some(finality_proof_provider), - sync_state_items: None, })?; network_starter.start_network(); diff --git a/bin/node/rpc/Cargo.toml b/bin/node/rpc/Cargo.toml index 992e863227b49..aef4a82db776a 100644 --- a/bin/node/rpc/Cargo.toml +++ b/bin/node/rpc/Cargo.toml @@ -20,11 +20,13 @@ sc-client-api = { version = "2.0.0", path = "../../../client/api" } sc-consensus-babe = { version = "0.8.0", path = "../../../client/consensus/babe" } sc-consensus-babe-rpc = { version = "0.8.0", path = "../../../client/consensus/babe/rpc" } sc-consensus-epochs = { version = "0.8.0", path = "../../../client/consensus/epochs" } +sc-chain-spec = { version = "2.0.0", path = "../../../client/chain-spec" } sc-finality-grandpa = { version = "0.8.0", path = "../../../client/finality-grandpa" } sc-finality-grandpa-rpc = { version = "0.8.0", path = "../../../client/finality-grandpa/rpc" } sc-keystore = { version = "2.0.0", path = "../../../client/keystore" } sc-rpc-api = { version = "0.8.0", path = "../../../client/rpc-api" } sc-rpc = { version = "2.0.0", path = "../../../client/rpc" } +sc-sync-state-rpc = { version = "0.8.0", path = "../../../client/sync-state-rpc" } sp-api = { version = "2.0.0", path = "../../../primitives/api" } sp-block-builder = { version = "2.0.0", path = "../../../primitives/block-builder" } sp-blockchain = { version = "2.0.0", path = "../../../primitives/blockchain" } diff --git a/bin/node/rpc/src/lib.rs b/bin/node/rpc/src/lib.rs index c11cbee92d62b..1ced3d60ab362 100644 --- a/bin/node/rpc/src/lib.rs +++ b/bin/node/rpc/src/lib.rs @@ -49,6 +49,7 @@ use sp_consensus::SelectChain; use sp_consensus_babe::BabeApi; use sc_rpc::SubscriptionTaskExecutor; use sp_transaction_pool::TransactionPool; +use sc_client_api::AuxStore; /// Light client extra dependencies. pub struct LightDeps { @@ -94,6 +95,8 @@ pub struct FullDeps { pub pool: Arc

, /// The SelectChain Strategy pub select_chain: SC, + /// A copy of the chain spec. + pub chain_spec: Box, /// Whether to deny unsafe calls pub deny_unsafe: DenyUnsafe, /// BABE specific dependencies. @@ -109,9 +112,8 @@ pub type IoHandler = jsonrpc_core::IoHandler; pub fn create_full( deps: FullDeps, ) -> jsonrpc_core::IoHandler where - C: ProvideRuntimeApi, - C: HeaderBackend + HeaderMetadata + 'static, - C: Send + Sync + 'static, + C: ProvideRuntimeApi + HeaderBackend + AuxStore + + HeaderMetadata + Sync + Send + 'static, C::Api: substrate_frame_rpc_system::AccountNonceApi, C::Api: pallet_contracts_rpc::ContractsRuntimeApi, C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi, @@ -131,6 +133,7 @@ pub fn create_full( client, pool, select_chain, + chain_spec, deny_unsafe, babe, grandpa, @@ -164,8 +167,8 @@ pub fn create_full( io.extend_with( sc_consensus_babe_rpc::BabeApi::to_delegate( BabeRpcHandler::new( - client, - shared_epoch_changes, + client.clone(), + shared_epoch_changes.clone(), keystore, babe_config, select_chain, @@ -176,7 +179,7 @@ pub fn create_full( io.extend_with( sc_finality_grandpa_rpc::GrandpaApi::to_delegate( GrandpaRpcHandler::new( - shared_authority_set, + shared_authority_set.clone(), shared_voter_state, justification_stream, subscription_executor, @@ -185,6 +188,18 @@ pub fn create_full( ) ); + io.extend_with( + sc_sync_state_rpc::SyncStateRpcApi::to_delegate( + sc_sync_state_rpc::SyncStateRpcHandler::new( + chain_spec, + client, + shared_authority_set, + shared_epoch_changes, + deny_unsafe, + ) + ) + ); + io } diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index 5f4fb1808ff36..ffac97e285e28 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -345,7 +345,7 @@ impl ChainSpec { impl crate::ChainSpec for ChainSpec where G: RuntimeGenesis + 'static, - E: GetExtension + serde::Serialize + Clone + Send + 'static, + E: GetExtension + serde::Serialize + Clone + Send + Sync + 'static, { fn boot_nodes(&self) -> &[MultiaddrWithPeerId] { ChainSpec::boot_nodes(self) diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index a1802d5b523e3..ba426eef429a0 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -126,7 +126,7 @@ pub trait RuntimeGenesis: Serialize + DeserializeOwned + BuildStorage {} impl RuntimeGenesis for T {} /// Common interface of a chain specification. -pub trait ChainSpec: BuildStorage + Send { +pub trait ChainSpec: BuildStorage + Send + Sync { /// Spec name. fn name(&self) -> &str; /// Spec id. diff --git a/client/rpc-api/Cargo.toml b/client/rpc-api/Cargo.toml index 97396e4137a2a..55eb51d261cdb 100644 --- a/client/rpc-api/Cargo.toml +++ b/client/rpc-api/Cargo.toml @@ -30,4 +30,3 @@ serde = { version = "1.0.101", features = ["derive"] } serde_json = "1.0.41" sp-transaction-pool = { version = "2.0.0", path = "../../primitives/transaction-pool" } sp-rpc = { version = "2.0.0", path = "../../primitives/rpc" } -sp-blockchain = { version = "2.0.0", path = "../../primitives/blockchain" } diff --git a/client/rpc-api/src/system/error.rs b/client/rpc-api/src/system/error.rs index ea163e12de269..4897aa485cbe4 100644 --- a/client/rpc-api/src/system/error.rs +++ b/client/rpc-api/src/system/error.rs @@ -32,12 +32,6 @@ pub enum Error { NotHealthy(Health), /// Peer argument is malformatted. MalformattedPeerArg(String), - /// An error that occurred while trying to generate the sync state. - #[display(fmt = "{}. Try syncing the node some more.", _0)] - GenSyncState(sp_blockchain::Error), - /// BuildNetworkParams::sync_state_items has not been set. - #[display(fmt = "BuildNetworkParams::sync_state_items has not been set.")] - MissingSyncStateItems, } impl std::error::Error for Error {} @@ -57,16 +51,6 @@ impl From for rpc::Error { code :rpc::ErrorCode::ServerError(BASE_ERROR + 2), message: e.clone(), data: None, - }, - Error::GenSyncState(_) => rpc::Error { - code :rpc::ErrorCode::ServerError(BASE_ERROR + 3), - message: e.to_string(), - data: None, - }, - Error::MissingSyncStateItems => rpc::Error { - code :rpc::ErrorCode::ServerError(BASE_ERROR + 4), - message: e.to_string(), - data: None, } } } diff --git a/client/rpc-api/src/system/mod.rs b/client/rpc-api/src/system/mod.rs index a1bea058d965f..a7b746ee1b114 100644 --- a/client/rpc-api/src/system/mod.rs +++ b/client/rpc-api/src/system/mod.rs @@ -103,9 +103,4 @@ pub trait SystemApi { /// Returns the roles the node is running as. #[rpc(name = "system_nodeRoles", returns = "Vec")] fn system_node_roles(&self) -> Receiver>; - - /// Returns the json-serialized chainspec running the node, with a sync state. - #[rpc(name = "system_genSyncSpec", returns = "jsonrpc_core::Value")] - fn system_gen_sync_spec(&self, raw: bool) - -> Compat>>; } diff --git a/client/rpc/src/system/mod.rs b/client/rpc/src/system/mod.rs index 74d0f8b798a53..4b8abbe144462 100644 --- a/client/rpc/src/system/mod.rs +++ b/client/rpc/src/system/mod.rs @@ -66,9 +66,7 @@ pub enum Request { /// Must return any potential parse error. NetworkRemoveReservedPeer(String, oneshot::Sender>), /// Must return the node role. - NodeRoles(oneshot::Sender>), - /// Must return either a chain spec with a snc state encoded as a `Value` or an error. - GenSyncSpec(bool, oneshot::Sender>), + NodeRoles(oneshot::Sender>) } impl System { @@ -191,20 +189,4 @@ impl SystemApi::Number> for Sy let _ = self.send_back.unbounded_send(Request::NodeRoles(tx)); Receiver(Compat::new(rx)) } - - fn system_gen_sync_spec(&self, raw: bool) - -> Compat>> - { - bail_if_unsafe!(self.deny_unsafe); - - let (tx, rx) = oneshot::channel(); - let _ = self.send_back.unbounded_send(Request::GenSyncSpec(raw, tx)); - async move { - match rx.await { - Ok(Ok(value)) => Ok(value), - Ok(Err(e)) => Err(rpc::Error::from(e)), - Err(_) => Err(rpc::Error::internal_error()), - } - }.boxed().compat() - } } diff --git a/client/rpc/src/system/tests.rs b/client/rpc/src/system/tests.rs index fc9e92487625e..f16d7da5b1a8b 100644 --- a/client/rpc/src/system/tests.rs +++ b/client/rpc/src/system/tests.rs @@ -103,10 +103,7 @@ fn api>>(sync: T) -> System { } Request::NodeRoles(sender) => { let _ = sender.send(vec![NodeRole::Authority]); - }, - Request::GenSyncSpec(_, sender) => { - let _ = sender.send(Ok(serde_json::Value::Null)); - }, + } }; future::ready(()) diff --git a/client/service/Cargo.toml b/client/service/Cargo.toml index f186c4a969383..9c0ddbc54c904 100644 --- a/client/service/Cargo.toml +++ b/client/service/Cargo.toml @@ -78,9 +78,6 @@ sc-tracing = { version = "2.0.0", path = "../tracing" } sp-tracing = { version = "2.0.0", path = "../../primitives/tracing" } tracing = "0.1.19" parity-util-mem = { version = "0.7.0", default-features = false, features = ["primitive-types"] } -sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } -sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } -grandpa = { version = "0.8.0", package = "sc-finality-grandpa", path = "../finality-grandpa" } [target.'cfg(not(target_os = "unknown"))'.dependencies] tempfile = "3.1.0" diff --git a/client/service/src/builder.rs b/client/service/src/builder.rs index c027d2317ae8e..0a8111710b30b 100644 --- a/client/service/src/builder.rs +++ b/client/service/src/builder.rs @@ -25,7 +25,7 @@ use crate::{ config::{Configuration, KeystoreConfig, PrometheusConfig}, }; use sc_client_api::{ - light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider, AuxStore, + light::RemoteBlockchain, ForkBlocks, BadBlocks, UsageProvider, ExecutorProvider, }; use sp_utils::mpsc::{tracing_unbounded, TracingUnboundedSender}; use sc_chain_spec::get_extension; @@ -45,7 +45,7 @@ use sc_network::config::{Role, FinalityProofProvider, OnDemand, BoxFinalityProof use sc_network::NetworkService; use sp_runtime::generic::BlockId; use sp_runtime::traits::{ - Block as BlockT, SaturatedConversion, HashFor, Zero, BlockIdTo, NumberFor, + Block as BlockT, SaturatedConversion, HashFor, Zero, BlockIdTo, }; use sp_api::{ProvideRuntimeApi, CallApiAt}; use sc_executor::{NativeExecutor, NativeExecutionDispatch, RuntimeInfo}; @@ -813,12 +813,6 @@ pub struct BuildNetworkParams<'a, TBl: BlockT, TExPool, TImpQu, TCl> { pub finality_proof_request_builder: Option>, /// An optional, shared finality proof request provider. pub finality_proof_provider: Option>>, - /// Shared GRANDPA and BABE items that are used to generate sync states to be used by light - /// clients. Only generated on full clients. - pub sync_state_items: Option<( - grandpa::SharedAuthoritySet<::Hash, NumberFor>, - sc_consensus_epochs::SharedEpochChanges, - )> } /// Build the network service, the network status sinks and an RPC sender. @@ -837,12 +831,12 @@ pub fn build_network( TBl: BlockT, TCl: ProvideRuntimeApi + HeaderMetadata + Chain + BlockBackend + BlockIdTo + ProofProvider + - HeaderBackend + BlockchainEvents + AuxStore + 'static, + HeaderBackend + BlockchainEvents + 'static, TExPool: MaintainedTransactionPool::Hash> + 'static, TImpQu: ImportQueue + 'static, { let BuildNetworkParams { - config, client, transaction_pool, spawn_handle, import_queue, on_demand, sync_state_items, + config, client, transaction_pool, spawn_handle, import_queue, on_demand, block_announce_validator_builder, finality_proof_request_builder, finality_proof_provider, } = params; @@ -906,10 +900,6 @@ pub fn build_network( system_rpc_rx, has_bootnodes, config.announce_block, - sync_state_items.map(|(auth_set, epoch_changes)| ( - config.chain_spec.cloned_box(), - auth_set, epoch_changes, - )) ); // TODO: Normally, one is supposed to pass a list of notifications protocols supported by the diff --git a/client/service/src/lib.rs b/client/service/src/lib.rs index 86741e802e449..1c67d3865f485 100644 --- a/client/service/src/lib.rs +++ b/client/service/src/lib.rs @@ -32,7 +32,6 @@ mod builder; pub mod client; #[cfg(not(feature = "test-helpers"))] mod client; -mod sync_state; mod task_manager; use std::{io, pin::Pin}; @@ -47,11 +46,9 @@ use sc_network::{NetworkStatus, network_state::NetworkState, PeerId}; use log::{warn, debug, error}; use codec::{Encode, Decode}; use sp_runtime::generic::BlockId; -use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor}; +use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use parity_util_mem::MallocSizeOf; use sp_utils::{status_sinks, mpsc::{tracing_unbounded, TracingUnboundedReceiver, TracingUnboundedSender}}; -use sp_blockchain::HeaderBackend; -use sc_client_api::{AuxStore, BlockchainEvents}; pub use self::error::Error; pub use self::builder::{ @@ -83,6 +80,7 @@ pub use sc_tracing::TracingReceiver; pub use task_manager::SpawnTaskHandle; pub use task_manager::TaskManager; pub use sp_consensus::import_queue::ImportQueue; +use sc_client_api::BlockchainEvents; const DEFAULT_PROTOCOL_ID: &str = "sup"; @@ -201,7 +199,7 @@ pub struct PartialComponents + HeaderBackend + AuxStore, + C: BlockchainEvents, H: sc_network::ExHashT > ( role: Role, @@ -211,11 +209,6 @@ async fn build_network_future< mut rpc_rx: TracingUnboundedReceiver>, should_have_peers: bool, announce_imported_blocks: bool, - sync_state_items: Option<( - Box, - grandpa::SharedAuthoritySet<::Hash, NumberFor>, - sc_consensus_epochs::SharedEpochChanges, - )>, ) { let mut imported_blocks_stream = client.import_notification_stream().fuse(); @@ -329,23 +322,6 @@ async fn build_network_future< }; let _ = sender.send(vec![node_role]); - }, - sc_rpc::system::Request::GenSyncSpec(raw, sender) => { - let result = sync_state_items - .as_ref() - .ok_or(sc_rpc::system::error::Error::MissingSyncStateItems) - .and_then(|(chain_spec, auth_set, epoch_changes)| { - let mut chain_spec = chain_spec.cloned_box(); - - let sync_state = crate::sync_state::build_light_sync_state( - client.clone(), auth_set.clone(), epoch_changes.clone(), - )?; - chain_spec.set_light_sync_state(sync_state.to_serializable()); - chain_spec.as_json_value(raw).map_err(|err| { - sp_blockchain::Error::Msg(err).into() - }) - }); - let _ = sender.send(result); } } } diff --git a/client/service/src/sync_state.rs b/client/service/src/sync_state.rs deleted file mode 100644 index 15c322a326ea2..0000000000000 --- a/client/service/src/sync_state.rs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2020 Parity Technologies (UK) Ltd. -// This file is part of Substrate. - -// Substrate 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. - -// Substrate 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 Substrate. If not, see . - -use sp_runtime::traits::{Block as BlockT, NumberFor}; -use sp_blockchain::HeaderBackend; -use std::sync::Arc; -use sp_runtime::generic::BlockId; - -/// Build a `LightSyncState` from the CHT roots stored in a backend. -pub fn build_light_sync_state( - client: Arc, - shared_authority_set: grandpa::SharedAuthoritySet<::Hash, NumberFor>, - shared_epoch_changes: sc_consensus_epochs::SharedEpochChanges, -) -> Result, sp_blockchain::Error> - where - TBl: BlockT, - TCl: HeaderBackend + sc_client_api::AuxStore, -{ - let finalized_hash = client.info().finalized_hash; - let finalized_header = client.header(BlockId::Hash(finalized_hash))?.unwrap(); - - let finalized_block_weight = sc_consensus_babe::aux_schema::load_block_weight( - &*client, - finalized_hash, - )?.unwrap(); - - Ok(sc_chain_spec::LightSyncState { - finalized_block_header: finalized_header, - babe_epoch_changes: shared_epoch_changes.lock().clone(), - babe_finalized_block_weight: finalized_block_weight, - grandpa_authority_set: shared_authority_set.inner().read().clone(), - }) -} diff --git a/client/service/test/src/lib.rs b/client/service/test/src/lib.rs index cfe815f174fac..7c4e28f4ddc4a 100644 --- a/client/service/test/src/lib.rs +++ b/client/service/test/src/lib.rs @@ -194,7 +194,7 @@ where F: Clone + Send + 'static, L: Clone + Send +'static, U: Clone + Send + 'st } } -fn node_config ( +fn node_config ( index: usize, spec: &GenericChainSpec, role: Role, @@ -275,7 +275,7 @@ fn node_config TestNet where F: TestNetNode, L: TestNetNode, - E: ChainSpecExtension + Clone + 'static + Send, + E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, { fn new( @@ -389,7 +389,7 @@ pub fn connectivity( full_builder: Fb, light_builder: Lb, ) where - E: ChainSpecExtension + Clone + 'static + Send, + E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, Fb: Fn(Configuration) -> Result, F: TestNetNode, @@ -509,7 +509,7 @@ pub fn sync( B: FnMut(&F, &mut U), ExF: FnMut(&F, &U) -> ::Extrinsic, U: Clone + Send + 'static, - E: ChainSpecExtension + Clone + 'static + Send, + E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, { const NUM_FULL_NODES: usize = 10; @@ -584,7 +584,7 @@ pub fn consensus( F: TestNetNode, Lb: Fn(Configuration) -> Result, L: TestNetNode, - E: ChainSpecExtension + Clone + 'static + Send, + E: ChainSpecExtension + Clone + 'static + Send + Sync, G: RuntimeGenesis + 'static, { const NUM_FULL_NODES: usize = 10; diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml new file mode 100644 index 0000000000000..819f6ea7eface --- /dev/null +++ b/client/sync-state-rpc/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "sc-sync-state-rpc" +version = "0.8.0" +authors = ["Parity Technologies "] +description = "A RPC handler to create sync states for light clients." +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +readme = "README.md" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +jsonrpc-core = "15.0" +jsonrpc-core-client = "15.0" +jsonrpc-derive = "15.0" +sc-chain-spec = { version = "2.0.0", path = "../chain-spec" } +sc-client-api = { version = "2.0.0", path = "../api" } +sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } +sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } +sc-finality-grandpa = { version = "0.8.0", path = "../finality-grandpa" } +sc-rpc-api = { version = "0.8.0", path = "../rpc-api" } +sp-blockchain = { version = "2.0.0", path = "../../primitives/blockchain" } +sp-runtime = { version = "2.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs new file mode 100644 index 0000000000000..2ad97dd8c7227 --- /dev/null +++ b/client/sync-state-rpc/src/lib.rs @@ -0,0 +1,118 @@ +// Copyright 2020 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate 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. + +// Substrate 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 Substrate. If not, see . + +//! A RPC handler to create sync states for light clients. +//! Currently only usable with BABE + GRANDPA. + +use sp_runtime::traits::{Block as BlockT, NumberFor}; +use sp_blockchain::HeaderBackend; +use std::sync::Arc; +use sp_runtime::generic::BlockId; + +use jsonrpc_derive::rpc; + +type SharedAuthoritySet = + sc_finality_grandpa::SharedAuthoritySet<::Hash, NumberFor>; +type SharedEpochChanges = sc_consensus_epochs::SharedEpochChanges; + +struct Error(sp_blockchain::Error); + +impl From for jsonrpc_core::Error { + fn from(error: Error) -> Self { + jsonrpc_core::Error { + message: error.0.to_string(), + code: jsonrpc_core::ErrorCode::ServerError(1), + data: None, + } + } +} + +/// An api for sync state RPC calls. +#[rpc] +pub trait SyncStateRpcApi { + /// Returns the json-serialized chainspec running the node, with a sync state. + #[rpc(name = "sync_state_genSyncSpec", returns = "jsonrpc_core::Value")] + fn system_gen_sync_spec(&self, raw: bool) + -> jsonrpc_core::Result; +} + +/// The handler for sync state RPC calls. +pub struct SyncStateRpcHandler { + chain_spec: Box, + client: Arc, + shared_authority_set: SharedAuthoritySet, + shared_epoch_changes: SharedEpochChanges, + deny_unsafe: sc_rpc_api::DenyUnsafe, +} + +impl SyncStateRpcHandler + where + TBl: BlockT, + TCl: HeaderBackend + sc_client_api::AuxStore + 'static, +{ + /// Create a new handler. + pub fn new( + chain_spec: Box, + client: Arc, + shared_authority_set: SharedAuthoritySet, + shared_epoch_changes: SharedEpochChanges, + deny_unsafe: sc_rpc_api::DenyUnsafe, + ) -> Self { + Self { + chain_spec, client, shared_authority_set, shared_epoch_changes, deny_unsafe, + } + } + + fn build_sync_state(&self) -> Result, sp_blockchain::Error> { + let finalized_hash = self.client.info().finalized_hash; + let finalized_header = self.client.header(BlockId::Hash(finalized_hash))?.unwrap(); + + let finalized_block_weight = sc_consensus_babe::aux_schema::load_block_weight( + &*self.client, + finalized_hash, + )?.unwrap(); + + Ok(sc_chain_spec::LightSyncState { + finalized_block_header: finalized_header, + babe_epoch_changes: self.shared_epoch_changes.lock().clone(), + babe_finalized_block_weight: finalized_block_weight, + grandpa_authority_set: self.shared_authority_set.inner().read().clone(), + }) + } +} + +impl SyncStateRpcApi for SyncStateRpcHandler + where + TBl: BlockT, + TCl: HeaderBackend + sc_client_api::AuxStore + 'static, +{ + fn system_gen_sync_spec(&self, raw: bool) + -> jsonrpc_core::Result + { + if let Err(err) = self.deny_unsafe.check_if_safe() { + return Err(err.into()); + } + + let mut chain_spec = self.chain_spec.cloned_box(); + + let sync_state = self.build_sync_state().map_err(Error)?; + + chain_spec.set_light_sync_state(sync_state.to_serializable()); + chain_spec.as_json_value(raw).map_err(|err| { + Error(sp_blockchain::Error::Msg(err)).into() + }) + } +} diff --git a/utils/browser/src/lib.rs b/utils/browser/src/lib.rs index ffd0a134be19e..196282ddecab7 100644 --- a/utils/browser/src/lib.rs +++ b/utils/browser/src/lib.rs @@ -41,7 +41,7 @@ pub async fn browser_configuration(chain_spec: GenericChainSpec) -> Result> where G: RuntimeGenesis + 'static, - E: Extension + 'static + Send, + E: Extension + 'static + Send + Sync, { let name = chain_spec.name().to_string(); From 49f1d472668a2a8280dc7fdaa181753f244d50f0 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Mon, 12 Oct 2020 14:51:44 +0200 Subject: [PATCH 11/12] Remove as_json_value and remove unwraps from sc-sync-state-rpc --- Cargo.lock | 5 +++-- client/chain-spec/src/chain_spec.rs | 11 ----------- client/chain-spec/src/lib.rs | 2 -- client/sync-state-rpc/Cargo.toml | 1 + client/sync-state-rpc/src/lib.rs | 20 +++++++++++++++----- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b61ad5d9e5c4f..b10e2074167a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7306,6 +7306,7 @@ dependencies = [ "sc-consensus-epochs", "sc-finality-grandpa", "sc-rpc-api", + "serde_json", "sp-blockchain", "sp-runtime", ] @@ -7596,9 +7597,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" dependencies = [ "itoa", "ryu", diff --git a/client/chain-spec/src/chain_spec.rs b/client/chain-spec/src/chain_spec.rs index ffac97e285e28..39c47e32908df 100644 --- a/client/chain-spec/src/chain_spec.rs +++ b/client/chain-spec/src/chain_spec.rs @@ -333,13 +333,6 @@ impl ChainSpec { json::to_string_pretty(&container) .map_err(|e| format!("Error generating spec json: {}", e)) } - - /// Dump to json value - pub fn as_json_value(&self, raw: bool) -> Result { - let container = self.json_container(raw)?; - json::to_value(container) - .map_err(|e| format!("Error generating spec json: {}", e)) - } } impl crate::ChainSpec for ChainSpec @@ -387,10 +380,6 @@ where ChainSpec::as_json(self, raw) } - fn as_json_value(&self, raw: bool) -> Result { - ChainSpec::as_json_value(self, raw) - } - fn as_storage_builder(&self) -> &dyn BuildStorage { self } diff --git a/client/chain-spec/src/lib.rs b/client/chain-spec/src/lib.rs index ba426eef429a0..94ed93758bb2d 100644 --- a/client/chain-spec/src/lib.rs +++ b/client/chain-spec/src/lib.rs @@ -149,8 +149,6 @@ pub trait ChainSpec: BuildStorage + Send + Sync { fn add_boot_node(&mut self, addr: MultiaddrWithPeerId); /// Return spec as JSON. fn as_json(&self, raw: bool) -> Result; - /// Return spec as JSON value. - fn as_json_value(&self, raw: bool) -> Result; /// Return StorageBuilder for this spec. fn as_storage_builder(&self) -> &dyn BuildStorage; /// Returns a cloned `Box`. diff --git a/client/sync-state-rpc/Cargo.toml b/client/sync-state-rpc/Cargo.toml index 819f6ea7eface..8da372db94ffc 100644 --- a/client/sync-state-rpc/Cargo.toml +++ b/client/sync-state-rpc/Cargo.toml @@ -22,5 +22,6 @@ sc-consensus-babe = { version = "0.8.0", path = "../consensus/babe" } sc-consensus-epochs = { version = "0.8.0", path = "../consensus/epochs" } sc-finality-grandpa = { version = "0.8.0", path = "../finality-grandpa" } sc-rpc-api = { version = "0.8.0", path = "../rpc-api" } +serde_json = "1.0.58" sp-blockchain = { version = "2.0.0", path = "../../primitives/blockchain" } sp-runtime = { version = "2.0.0", path = "../../primitives/runtime" } diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 2ad97dd8c7227..36c34b2f39f80 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -78,12 +78,18 @@ impl SyncStateRpcHandler fn build_sync_state(&self) -> Result, sp_blockchain::Error> { let finalized_hash = self.client.info().finalized_hash; - let finalized_header = self.client.header(BlockId::Hash(finalized_hash))?.unwrap(); + let finalized_header = self.client.header(BlockId::Hash(finalized_hash))? + .ok_or_else(|| sp_blockchain::Error::Msg( + format!("Failed to get the header for block {:?}", finalized_hash) + ))?; let finalized_block_weight = sc_consensus_babe::aux_schema::load_block_weight( &*self.client, finalized_hash, - )?.unwrap(); + )? + .ok_or_else(|| sp_blockchain::Error::Msg( + format!("Failed to load the block weight for block {:?}", finalized_hash) + ))?; Ok(sc_chain_spec::LightSyncState { finalized_block_header: finalized_header, @@ -111,8 +117,12 @@ impl SyncStateRpcApi for SyncStateRpcHandler let sync_state = self.build_sync_state().map_err(Error)?; chain_spec.set_light_sync_state(sync_state.to_serializable()); - chain_spec.as_json_value(raw).map_err(|err| { - Error(sp_blockchain::Error::Msg(err)).into() - }) + let string = chain_spec.as_json(raw).map_err(map_error)?; + + serde_json::from_str(&string).map_err(|err| map_error(err.to_string())) } } + +fn map_error(error: String) -> jsonrpc_core::Error { + Error(sp_blockchain::Error::Msg(error)).into() +} From 750448bafd99caf64676771fe8aa8e3014be3f47 Mon Sep 17 00:00:00 2001 From: Ashley Ruglys Date: Thu, 15 Oct 2020 10:46:13 +0200 Subject: [PATCH 12/12] Add clone_inner to SharedAuthoritySet --- client/finality-grandpa/src/authorities.rs | 7 ++++++- client/sync-state-rpc/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/client/finality-grandpa/src/authorities.rs b/client/finality-grandpa/src/authorities.rs index 9b84c2e979e2a..57c30bc3b25c9 100644 --- a/client/finality-grandpa/src/authorities.rs +++ b/client/finality-grandpa/src/authorities.rs @@ -53,7 +53,7 @@ impl Clone for SharedAuthoritySet { impl SharedAuthoritySet { /// Acquire a reference to the inner read-write lock. - pub fn inner(&self) -> &RwLock> { + pub(crate) fn inner(&self) -> &RwLock> { &*self.inner } } @@ -81,6 +81,11 @@ where N: Add + Ord + Clone + Debug, qed.", ) } + + /// Clone the inner `AuthoritySet`. + pub fn clone_inner(&self) -> AuthoritySet { + self.inner.read().clone() + } } impl From> for SharedAuthoritySet { diff --git a/client/sync-state-rpc/src/lib.rs b/client/sync-state-rpc/src/lib.rs index 36c34b2f39f80..fa433e5e31d2d 100644 --- a/client/sync-state-rpc/src/lib.rs +++ b/client/sync-state-rpc/src/lib.rs @@ -95,7 +95,7 @@ impl SyncStateRpcHandler finalized_block_header: finalized_header, babe_epoch_changes: self.shared_epoch_changes.lock().clone(), babe_finalized_block_weight: finalized_block_weight, - grandpa_authority_set: self.shared_authority_set.inner().read().clone(), + grandpa_authority_set: self.shared_authority_set.clone_inner(), }) } }