Add a LightSyncState field to the chain spec (#6894)

* Reset code, almost ready for PR

* Improved build_hardcoded_spec

* Fix line widths

* Fix tests

* Fix sc-service-test

* Suggestions from code review

* Rename to LightSyncState

* It's not syncing :^(

* It syncs!

* Remove rpc call

* Convert spaces to tabs

* Moved sc-service things to export_sync_state.rs

* Fix tests

* Wait for syncing with network_status_sinks

* Remove sc-network from node-template

* Apply suggestions from code review

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Various changes, split the flag up into 2 pieces to make testing easier.

* Update client/cli/src/commands/build_spec_cmd.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* Revert a lot of changes

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
Ashley
2020-08-24 10:34:16 +02:00
committed by GitHub
parent b1a8ff1724
commit f009f6c227
10 changed files with 212 additions and 53 deletions
+67 -11
View File
@@ -17,6 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Substrate chain configurations.
#![warn(missing_docs)]
use std::{borrow::Cow, fs::File, path::PathBuf, sync::Arc, collections::HashMap};
use serde::{Serialize, Deserialize};
@@ -26,6 +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;
enum GenesisSource<G> {
File(PathBuf),
@@ -157,6 +159,7 @@ struct ClientSpec<E> {
consensus_engine: (),
#[serde(skip_serializing)]
genesis: serde::de::IgnoredAny,
light_sync_state: Option<SerializableLightSyncState>,
}
/// A type denoting empty extensions.
@@ -245,6 +248,7 @@ impl<G, E> ChainSpec<G, E> {
extensions,
consensus_engine: (),
genesis: Default::default(),
light_sync_state: None,
};
ChainSpec {
@@ -257,6 +261,11 @@ impl<G, E> ChainSpec<G, E> {
fn chain_type(&self) -> ChainType {
self.client_spec.chain_type.clone()
}
/// 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);
}
}
impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
@@ -284,16 +293,15 @@ impl<G, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
}
}
impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
/// Dump to json string.
pub fn as_json(&self, raw: bool) -> Result<String, String> {
#[derive(Serialize, Deserialize)]
struct Container<G, E> {
#[serde(flatten)]
client_spec: ClientSpec<E>,
genesis: Genesis<G>,
#[derive(Serialize, Deserialize)]
struct JsonContainer<G, E> {
#[serde(flatten)]
client_spec: ClientSpec<E>,
genesis: Genesis<G>,
}
};
impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
fn json_container(&self, raw: bool) -> Result<JsonContainer<G, E>, String> {
let genesis = match (raw, self.genesis.resolve()?) {
(true, Genesis::Runtime(g)) => {
let storage = g.build_storage()?;
@@ -313,10 +321,15 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
},
(_, genesis) => genesis,
};
let container = Container {
Ok(JsonContainer {
client_spec: self.client_spec.clone(),
genesis,
};
})
}
/// Dump to json string.
pub fn as_json(&self, raw: bool) -> Result<String, String> {
let container = self.json_container(raw)?;
json::to_string_pretty(&container)
.map_err(|e| format!("Error generating spec json: {}", e))
}
@@ -378,6 +391,49 @@ where
fn set_storage(&mut self, storage: Storage) {
self.genesis = GenesisSource::Storage(storage);
}
fn set_light_sync_state(&mut self, light_sync_state: SerializableLightSyncState) {
ChainSpec::set_light_sync_state(self, light_sync_state)
}
}
/// Hardcoded infomation that allows light clients to sync quickly.
pub struct LightSyncState<Block: BlockT> {
/// The header of the best finalized block.
pub header: <Block as BlockT>::Header,
/// A list of all CHTs in the chain.
pub chts: Vec<<Block as BlockT>::Hash>,
}
impl<Block: BlockT> LightSyncState<Block> {
/// Convert into a `SerializableLightSyncState`.
pub fn to_serializable(&self) -> SerializableLightSyncState {
use codec::Encode;
SerializableLightSyncState {
header: StorageData(self.header.encode()),
chts: self.chts.iter().map(|hash| StorageData(hash.encode())).collect(),
}
}
/// Convert from a `SerializableLightSyncState`.
pub fn from_serializable(serialized: &SerializableLightSyncState) -> Result<Self, codec::Error> {
Ok(Self {
header: codec::Decode::decode(&mut &serialized.header.0[..])?,
chts: serialized.chts.iter()
.map(|cht| codec::Decode::decode(&mut &cht.0[..]))
.collect::<Result<_, _>>()?,
})
}
}
/// The serializable form of `LightSyncState`. Created using `LightSyncState::serialize`.
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
#[serde(deny_unknown_fields)]
pub struct SerializableLightSyncState {
header: StorageData,
chts: Vec<StorageData>,
}
#[cfg(test)]
+5 -1
View File
@@ -108,7 +108,9 @@
mod chain_spec;
mod extension;
pub use chain_spec::{ChainSpec as GenericChainSpec, NoExtension};
pub use chain_spec::{
ChainSpec as GenericChainSpec, NoExtension, LightSyncState, SerializableLightSyncState,
};
pub use extension::{Group, Fork, Forks, Extension, GetExtension, get_extension};
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
pub use sp_chain_spec::{Properties, ChainType};
@@ -155,6 +157,8 @@ pub trait ChainSpec: BuildStorage + Send {
///
/// This will be used as storage at genesis.
fn set_storage(&mut self, storage: Storage);
/// Hardcode infomation to allow light clients to sync quickly into the chain spec.
fn set_light_sync_state(&mut self, light_sync_state: SerializableLightSyncState);
}
impl std::fmt::Debug for dyn ChainSpec {