mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-14 01:41:09 +00:00
Decouples light-sync state from chain spec (#9491)
* Decouples light-sync state from chain spec This decouples the light-sync state from chain spec. First, the light-sync state currently only works with BABE+Grandpa, so not all *Substrate* based chains can use this feature. The next problem was also that this pulled the `sc-consensus-babe` and `sc-finality-grandpa` crate into `sc-chain-spec`. If a chain now wants to support the light-sync state, it needs to add the `LightSyncStateExtension` to the chain spec as an extension. This is documented in the crate level docs of `sc-sync-state-rpc`. If this extension is not available, `SyncStateRpc` fails at initialization. * Fix compilation for browser * Fmt
This commit is contained in:
Generated
+3
-4
@@ -4222,6 +4222,7 @@ dependencies = [
|
||||
"sc-rpc",
|
||||
"sc-service",
|
||||
"sc-service-test",
|
||||
"sc-sync-state-rpc",
|
||||
"sc-telemetry",
|
||||
"sc-tracing",
|
||||
"sc-transaction-pool",
|
||||
@@ -7126,14 +7127,10 @@ dependencies = [
|
||||
"impl-trait-for-tuples",
|
||||
"parity-scale-codec",
|
||||
"sc-chain-spec-derive",
|
||||
"sc-consensus-babe",
|
||||
"sc-consensus-epochs",
|
||||
"sc-finality-grandpa",
|
||||
"sc-network",
|
||||
"sc-telemetry",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sp-consensus-babe",
|
||||
"sp-core",
|
||||
"sp-runtime",
|
||||
]
|
||||
@@ -8151,12 +8148,14 @@ dependencies = [
|
||||
"jsonrpc-core",
|
||||
"jsonrpc-core-client",
|
||||
"jsonrpc-derive",
|
||||
"parity-scale-codec",
|
||||
"sc-chain-spec",
|
||||
"sc-client-api",
|
||||
"sc-consensus-babe",
|
||||
"sc-consensus-epochs",
|
||||
"sc-finality-grandpa",
|
||||
"sc-rpc-api",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sp-blockchain",
|
||||
"sp-runtime",
|
||||
|
||||
@@ -203,7 +203,7 @@ pub fn new_full(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
let deps =
|
||||
crate::rpc::FullDeps { client: client.clone(), pool: pool.clone(), deny_unsafe };
|
||||
|
||||
crate::rpc::create_full(deps)
|
||||
Ok(crate::rpc::create_full(deps))
|
||||
})
|
||||
};
|
||||
|
||||
@@ -436,7 +436,7 @@ pub fn new_light(mut config: Configuration) -> Result<TaskManager, ServiceError>
|
||||
transaction_pool,
|
||||
task_manager: &mut task_manager,
|
||||
on_demand: Some(on_demand),
|
||||
rpc_extensions_builder: Box::new(|_, _| ()),
|
||||
rpc_extensions_builder: Box::new(|_, _| Ok(())),
|
||||
config,
|
||||
client,
|
||||
keystore: keystore_container.sync_keystore(),
|
||||
|
||||
@@ -77,6 +77,7 @@ sc-service = { version = "0.10.0-dev", default-features = false, path = "../../.
|
||||
sc-tracing = { version = "4.0.0-dev", path = "../../../client/tracing" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../../../client/telemetry" }
|
||||
sc-authority-discovery = { version = "0.10.0-dev", path = "../../../client/authority-discovery" }
|
||||
sc-sync-state-rpc = { version = "0.10.0-dev", path = "../../../client/sync-state-rpc" }
|
||||
|
||||
# frame dependencies
|
||||
pallet-indices = { version = "4.0.0-dev", path = "../../../frame/indices" }
|
||||
|
||||
@@ -57,6 +57,8 @@ pub struct Extensions {
|
||||
pub fork_blocks: sc_client_api::ForkBlocks<Block>,
|
||||
/// Known bad block hashes.
|
||||
pub bad_blocks: sc_client_api::BadBlocks<Block>,
|
||||
/// The light sync state extension used by the sync-state rpc.
|
||||
pub light_sync_state: sc_sync_state_rpc::LightSyncStateExtension,
|
||||
}
|
||||
|
||||
/// Specialized `ChainSpec`.
|
||||
|
||||
@@ -49,7 +49,10 @@ pub fn new_partial(
|
||||
sc_consensus::DefaultImportQueue<Block, FullClient>,
|
||||
sc_transaction_pool::FullPool<Block, FullClient>,
|
||||
(
|
||||
impl Fn(node_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> node_rpc::IoHandler,
|
||||
impl Fn(
|
||||
node_rpc::DenyUnsafe,
|
||||
sc_rpc::SubscriptionTaskExecutor,
|
||||
) -> Result<node_rpc::IoHandler, sc_service::Error>,
|
||||
(
|
||||
sc_consensus_babe::BabeBlockImport<Block, FullClient, FullGrandpaBlockImport>,
|
||||
grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
|
||||
@@ -180,7 +183,7 @@ pub fn new_partial(
|
||||
},
|
||||
};
|
||||
|
||||
node_rpc::create_full(deps)
|
||||
node_rpc::create_full(deps).map_err(Into::into)
|
||||
};
|
||||
|
||||
(rpc_extensions_builder, rpc_setup)
|
||||
|
||||
@@ -111,7 +111,7 @@ pub type IoHandler = jsonrpc_core::IoHandler<sc_rpc::Metadata>;
|
||||
/// Instantiate all Full RPC extensions.
|
||||
pub fn create_full<C, P, SC, B>(
|
||||
deps: FullDeps<C, P, SC, B>,
|
||||
) -> jsonrpc_core::IoHandler<sc_rpc_api::Metadata>
|
||||
) -> Result<jsonrpc_core::IoHandler<sc_rpc_api::Metadata>, Box<dyn std::error::Error + Send + Sync>>
|
||||
where
|
||||
C: ProvideRuntimeApi<Block>
|
||||
+ HeaderBackend<Block>
|
||||
@@ -178,10 +178,10 @@ where
|
||||
shared_authority_set,
|
||||
shared_epoch_changes,
|
||||
deny_unsafe,
|
||||
),
|
||||
)?,
|
||||
));
|
||||
|
||||
io
|
||||
Ok(io)
|
||||
}
|
||||
|
||||
/// Instantiate all Light RPC extensions.
|
||||
|
||||
@@ -22,7 +22,3 @@ serde_json = "1.0.41"
|
||||
sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
|
||||
sc-telemetry = { version = "4.0.0-dev", path = "../telemetry" }
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
sc-consensus-babe = { version = "0.10.0-dev", path = "../consensus/babe" }
|
||||
sp-consensus-babe = { version = "0.10.0-dev", path = "../../primitives/consensus/babe" }
|
||||
sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" }
|
||||
sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" }
|
||||
|
||||
@@ -65,6 +65,15 @@ pub fn extension_derive(ast: &DeriveInput) -> proc_macro::TokenStream {
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_any_mut(&mut self, t: std::any::TypeId) -> &mut dyn std::any::Any {
|
||||
use std::any::{Any, TypeId};
|
||||
|
||||
match t {
|
||||
#( x if x == TypeId::of::<#field_types>() => &mut self.#field_names ),*,
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -28,10 +28,7 @@ use sp_core::{
|
||||
storage::{ChildInfo, Storage, StorageChild, StorageData, StorageKey},
|
||||
Bytes,
|
||||
};
|
||||
use sp_runtime::{
|
||||
traits::{Block as BlockT, NumberFor},
|
||||
BuildStorage,
|
||||
};
|
||||
use sp_runtime::BuildStorage;
|
||||
use std::{borrow::Cow, collections::HashMap, fs::File, path::PathBuf, sync::Arc};
|
||||
|
||||
enum GenesisSource<G> {
|
||||
@@ -167,7 +164,6 @@ struct ClientSpec<E> {
|
||||
consensus_engine: (),
|
||||
#[serde(skip_serializing)]
|
||||
genesis: serde::de::IgnoredAny,
|
||||
light_sync_state: Option<SerializableLightSyncState>,
|
||||
/// Mapping from `block_hash` to `wasm_code`.
|
||||
///
|
||||
/// The given `wasm_code` will be used to substitute the on-chain wasm code from the given
|
||||
@@ -231,11 +227,16 @@ impl<G, E> ChainSpec<G, E> {
|
||||
self.client_spec.boot_nodes.push(addr)
|
||||
}
|
||||
|
||||
/// Returns a reference to defined chain spec extensions.
|
||||
/// Returns a reference to the defined chain spec extensions.
|
||||
pub fn extensions(&self) -> &E {
|
||||
&self.client_spec.extensions
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the defined chain spec extensions.
|
||||
pub fn extensions_mut(&mut self) -> &mut E {
|
||||
&mut self.client_spec.extensions
|
||||
}
|
||||
|
||||
/// Create hardcoded spec.
|
||||
pub fn from_genesis<F: Fn() -> G + 'static + Send + Sync>(
|
||||
name: &str,
|
||||
@@ -259,7 +260,6 @@ impl<G, E> ChainSpec<G, E> {
|
||||
extensions,
|
||||
consensus_engine: (),
|
||||
genesis: Default::default(),
|
||||
light_sync_state: None,
|
||||
code_substitutes: HashMap::new(),
|
||||
};
|
||||
|
||||
@@ -270,11 +270,6 @@ 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> {
|
||||
@@ -379,6 +374,10 @@ where
|
||||
ChainSpec::extensions(self) as &dyn GetExtension
|
||||
}
|
||||
|
||||
fn extensions_mut(&mut self) -> &mut dyn GetExtension {
|
||||
ChainSpec::extensions_mut(self) as &mut dyn GetExtension
|
||||
}
|
||||
|
||||
fn as_json(&self, raw: bool) -> Result<String, String> {
|
||||
ChainSpec::as_json(self, raw)
|
||||
}
|
||||
@@ -395,10 +394,6 @@ where
|
||||
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)
|
||||
}
|
||||
|
||||
fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>> {
|
||||
self.client_spec
|
||||
.code_substitutes
|
||||
@@ -408,60 +403,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Hardcoded infomation that allows light clients to sync quickly.
|
||||
pub struct LightSyncState<Block: BlockT> {
|
||||
/// The header of the best finalized block.
|
||||
pub finalized_block_header: <Block as BlockT>::Header,
|
||||
/// The epoch changes tree for babe.
|
||||
pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor<Block, sc_consensus_babe::Epoch>,
|
||||
/// 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<<Block as BlockT>::Hash, NumberFor<Block>>,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> LightSyncState<Block> {
|
||||
/// Convert into a `SerializableLightSyncState`.
|
||||
pub fn to_serializable(&self) -> SerializableLightSyncState {
|
||||
use codec::Encode;
|
||||
|
||||
SerializableLightSyncState {
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from a `SerializableLightSyncState`.
|
||||
pub fn from_serializable(
|
||||
serialized: &SerializableLightSyncState,
|
||||
) -> Result<Self, codec::Error> {
|
||||
Ok(Self {
|
||||
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[..],
|
||||
)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
finalized_block_header: StorageData,
|
||||
babe_epoch_changes: StorageData,
|
||||
babe_finalized_block_weight: sp_consensus_babe::BabeBlockWeight,
|
||||
grandpa_authority_set: StorageData,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -126,8 +126,10 @@ pub trait Extension: Serialize + DeserializeOwned + Clone {
|
||||
|
||||
/// Get an extension of specific type.
|
||||
fn get<T: 'static>(&self) -> Option<&T>;
|
||||
/// Get an extension of specific type as refernce to `Any`
|
||||
/// Get an extension of specific type as reference to `Any`.
|
||||
fn get_any(&self, t: TypeId) -> &dyn Any;
|
||||
/// Get an extension of specific type as mutable reference to `Any`.
|
||||
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any;
|
||||
|
||||
/// Get forkable extensions of specific type.
|
||||
fn forks<BlockNumber, T>(&self) -> Option<Forks<BlockNumber, T>>
|
||||
@@ -151,6 +153,9 @@ impl Extension for crate::NoExtension {
|
||||
fn get_any(&self, _t: TypeId) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn get_any_mut(&mut self, _: TypeId) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IsForks {
|
||||
@@ -240,16 +245,26 @@ where
|
||||
type Forks = Self;
|
||||
|
||||
fn get<T: 'static>(&self) -> Option<&T> {
|
||||
match TypeId::of::<T>() {
|
||||
x if x == TypeId::of::<E>() => <dyn Any>::downcast_ref(&self.base),
|
||||
_ => self.base.get(),
|
||||
if TypeId::of::<T>() == TypeId::of::<E>() {
|
||||
<dyn Any>::downcast_ref(&self.base)
|
||||
} else {
|
||||
self.base.get()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_any(&self, t: TypeId) -> &dyn Any {
|
||||
match t {
|
||||
x if x == TypeId::of::<E>() => &self.base,
|
||||
_ => self.base.get_any(t),
|
||||
if t == TypeId::of::<E>() {
|
||||
&self.base
|
||||
} else {
|
||||
self.base.get_any(t)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any {
|
||||
if t == TypeId::of::<E>() {
|
||||
&mut self.base
|
||||
} else {
|
||||
self.base.get_any_mut(t)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,20 +288,31 @@ where
|
||||
pub trait GetExtension {
|
||||
/// Get an extension of specific type.
|
||||
fn get_any(&self, t: TypeId) -> &dyn Any;
|
||||
|
||||
/// Get an extension of specific type with mutable access.
|
||||
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any;
|
||||
}
|
||||
|
||||
impl<E: Extension> GetExtension for E {
|
||||
fn get_any(&self, t: TypeId) -> &dyn Any {
|
||||
Extension::get_any(self, t)
|
||||
}
|
||||
|
||||
fn get_any_mut(&mut self, t: TypeId) -> &mut dyn Any {
|
||||
Extension::get_any_mut(self, t)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function that queries an extension by type from `GetExtension`
|
||||
/// trait object.
|
||||
/// Helper function that queries an extension by type from `GetExtension` trait object.
|
||||
pub fn get_extension<T: 'static>(e: &dyn GetExtension) -> Option<&T> {
|
||||
<dyn Any>::downcast_ref(GetExtension::get_any(e, TypeId::of::<T>()))
|
||||
}
|
||||
|
||||
/// Helper function that queries an extension by type from `GetExtension` trait object.
|
||||
pub fn get_extension_mut<T: 'static>(e: &mut dyn GetExtension) -> Option<&mut T> {
|
||||
<dyn Any>::downcast_mut(GetExtension::get_any_mut(e, TypeId::of::<T>()))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -110,10 +110,10 @@
|
||||
mod chain_spec;
|
||||
mod extension;
|
||||
|
||||
pub use chain_spec::{
|
||||
ChainSpec as GenericChainSpec, LightSyncState, NoExtension, SerializableLightSyncState,
|
||||
pub use chain_spec::{ChainSpec as GenericChainSpec, NoExtension};
|
||||
pub use extension::{
|
||||
get_extension, get_extension_mut, Extension, Fork, Forks, GetExtension, Group,
|
||||
};
|
||||
pub use extension::{get_extension, Extension, Fork, Forks, GetExtension, Group};
|
||||
pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
|
||||
|
||||
use sc_network::config::MultiaddrWithPeerId;
|
||||
@@ -169,8 +169,10 @@ pub trait ChainSpec: BuildStorage + Send + Sync {
|
||||
///
|
||||
/// Returns an empty JSON object if 'properties' not defined in config
|
||||
fn properties(&self) -> Properties;
|
||||
/// Returns a reference to defined chain spec extensions.
|
||||
/// Returns a reference to the defined chain spec extensions.
|
||||
fn extensions(&self) -> &dyn GetExtension;
|
||||
/// Returns a mutable reference to the defined chain spec extensions.
|
||||
fn extensions_mut(&mut self) -> &mut dyn GetExtension;
|
||||
/// Add a bootnode to the list.
|
||||
fn add_boot_node(&mut self, addr: MultiaddrWithPeerId);
|
||||
/// Return spec as JSON.
|
||||
@@ -183,8 +185,6 @@ pub trait ChainSpec: BuildStorage + Send + Sync {
|
||||
///
|
||||
/// 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);
|
||||
/// Returns code substitutes that should be used for the on chain wasm.
|
||||
fn code_substitutes(&self) -> std::collections::HashMap<String, Vec<u8>>;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ pub use sp_consensus_babe::{
|
||||
CompatibleDigestItem, NextConfigDescriptor, NextEpochDescriptor, PreDigest,
|
||||
PrimaryPreDigest, SecondaryPlainPreDigest,
|
||||
},
|
||||
AuthorityId, AuthorityPair, AuthoritySignature, BabeApi, BabeAuthorityWeight,
|
||||
AuthorityId, AuthorityPair, AuthoritySignature, BabeApi, BabeAuthorityWeight, BabeBlockWeight,
|
||||
BabeEpochConfiguration, BabeGenesisConfiguration, ConsensusLog, BABE_ENGINE_ID,
|
||||
VRF_OUTPUT_LENGTH,
|
||||
};
|
||||
|
||||
@@ -80,12 +80,12 @@ pub trait RpcExtensionBuilder {
|
||||
&self,
|
||||
deny: sc_rpc::DenyUnsafe,
|
||||
subscription_executor: sc_rpc::SubscriptionTaskExecutor,
|
||||
) -> Self::Output;
|
||||
) -> Result<Self::Output, Error>;
|
||||
}
|
||||
|
||||
impl<F, R> RpcExtensionBuilder for F
|
||||
where
|
||||
F: Fn(sc_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> R,
|
||||
F: Fn(sc_rpc::DenyUnsafe, sc_rpc::SubscriptionTaskExecutor) -> Result<R, Error>,
|
||||
R: sc_rpc::RpcExtension<sc_rpc::Metadata>,
|
||||
{
|
||||
type Output = R;
|
||||
@@ -94,7 +94,7 @@ where
|
||||
&self,
|
||||
deny: sc_rpc::DenyUnsafe,
|
||||
subscription_executor: sc_rpc::SubscriptionTaskExecutor,
|
||||
) -> Self::Output {
|
||||
) -> Result<Self::Output, Error> {
|
||||
(*self)(deny, subscription_executor)
|
||||
}
|
||||
}
|
||||
@@ -114,8 +114,8 @@ where
|
||||
&self,
|
||||
_deny: sc_rpc::DenyUnsafe,
|
||||
_subscription_executor: sc_rpc::SubscriptionTaskExecutor,
|
||||
) -> Self::Output {
|
||||
self.0.clone()
|
||||
) -> Result<Self::Output, Error> {
|
||||
Ok(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,7 +655,7 @@ where
|
||||
gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics, "inbrowser"),
|
||||
)
|
||||
)?
|
||||
.into(),
|
||||
));
|
||||
|
||||
@@ -742,7 +742,7 @@ fn gen_handler<TBl, TBackend, TExPool, TRpc, TCl>(
|
||||
rpc_extensions_builder: &(dyn RpcExtensionBuilder<Output = TRpc> + Send),
|
||||
offchain_storage: Option<<TBackend as sc_client_api::backend::Backend<TBl>>::OffchainStorage>,
|
||||
system_rpc_tx: TracingUnboundedSender<sc_rpc::system::Request<TBl>>,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>
|
||||
) -> Result<sc_rpc_server::RpcHandler<sc_rpc::Metadata>, Error>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: ProvideRuntimeApi<TBl>
|
||||
@@ -813,7 +813,7 @@ where
|
||||
offchain::OffchainApi::to_delegate(offchain)
|
||||
});
|
||||
|
||||
sc_rpc_server::rpc_handler(
|
||||
Ok(sc_rpc_server::rpc_handler(
|
||||
(
|
||||
state::StateApi::to_delegate(state),
|
||||
state::ChildStateApi::to_delegate(child_state),
|
||||
@@ -821,10 +821,10 @@ where
|
||||
maybe_offchain_rpc,
|
||||
author::AuthorApi::to_delegate(author),
|
||||
system::SystemApi::to_delegate(system),
|
||||
rpc_extensions_builder.build(deny_unsafe, task_executor),
|
||||
rpc_extensions_builder.build(deny_unsafe, task_executor)?,
|
||||
),
|
||||
rpc_middleware,
|
||||
)
|
||||
))
|
||||
}
|
||||
|
||||
/// Parameters to pass into `build_network`.
|
||||
|
||||
@@ -348,28 +348,31 @@ fn start_rpc_servers<
|
||||
H: FnMut(
|
||||
sc_rpc::DenyUnsafe,
|
||||
sc_rpc_server::RpcMiddleware,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
|
||||
) -> Result<sc_rpc_server::RpcHandler<sc_rpc::Metadata>, Error>,
|
||||
>(
|
||||
config: &Configuration,
|
||||
mut gen_handler: H,
|
||||
rpc_metrics: sc_rpc_server::RpcMetrics,
|
||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
|
||||
) -> Result<Box<dyn std::any::Any + Send + Sync>, Error> {
|
||||
fn maybe_start_server<T, F>(
|
||||
address: Option<SocketAddr>,
|
||||
mut start: F,
|
||||
) -> Result<Option<T>, io::Error>
|
||||
) -> Result<Option<T>, Error>
|
||||
where
|
||||
F: FnMut(&SocketAddr) -> Result<T, io::Error>,
|
||||
F: FnMut(&SocketAddr) -> Result<T, Error>,
|
||||
{
|
||||
address
|
||||
.map(|mut address| {
|
||||
start(&address).or_else(|e| match e.kind() {
|
||||
io::ErrorKind::AddrInUse | io::ErrorKind::PermissionDenied => {
|
||||
warn!("Unable to bind RPC server to {}. Trying random port.", address);
|
||||
address.set_port(0);
|
||||
start(&address)
|
||||
start(&address).or_else(|e| match e {
|
||||
Error::Io(e) => match e.kind() {
|
||||
io::ErrorKind::AddrInUse | io::ErrorKind::PermissionDenied => {
|
||||
warn!("Unable to bind RPC server to {}. Trying random port.", address);
|
||||
address.set_port(0);
|
||||
start(&address)
|
||||
},
|
||||
_ => Err(e.into()),
|
||||
},
|
||||
_ => Err(e),
|
||||
e => Err(e),
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
@@ -390,8 +393,9 @@ fn start_rpc_servers<
|
||||
gen_handler(
|
||||
sc_rpc::DenyUnsafe::No,
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ipc"),
|
||||
),
|
||||
)?,
|
||||
)
|
||||
.map_err(Error::from)
|
||||
}),
|
||||
maybe_start_server(config.rpc_http, |address| {
|
||||
sc_rpc_server::start_http(
|
||||
@@ -401,9 +405,10 @@ fn start_rpc_servers<
|
||||
gen_handler(
|
||||
deny_unsafe(&address, &config.rpc_methods),
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "http"),
|
||||
),
|
||||
)?,
|
||||
config.rpc_max_payload,
|
||||
)
|
||||
.map_err(Error::from)
|
||||
})?
|
||||
.map(|s| waiting::HttpServer(Some(s))),
|
||||
maybe_start_server(config.rpc_ws, |address| {
|
||||
@@ -414,9 +419,10 @@ fn start_rpc_servers<
|
||||
gen_handler(
|
||||
deny_unsafe(&address, &config.rpc_methods),
|
||||
sc_rpc_server::RpcMiddleware::new(rpc_metrics.clone(), "ws"),
|
||||
),
|
||||
)?,
|
||||
config.rpc_max_payload,
|
||||
)
|
||||
.map_err(Error::from)
|
||||
})?
|
||||
.map(|s| waiting::WsServer(Some(s))),
|
||||
)))
|
||||
@@ -428,7 +434,7 @@ fn start_rpc_servers<
|
||||
H: FnMut(
|
||||
sc_rpc::DenyUnsafe,
|
||||
sc_rpc_server::RpcMiddleware,
|
||||
) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>,
|
||||
) -> Result<sc_rpc_server::RpcHandler<sc_rpc::Metadata>, Error>,
|
||||
>(
|
||||
_: &Configuration,
|
||||
_: H,
|
||||
|
||||
@@ -24,5 +24,7 @@ sc-consensus-epochs = { version = "0.10.0-dev", path = "../consensus/epochs" }
|
||||
sc-finality-grandpa = { version = "0.10.0-dev", path = "../finality-grandpa" }
|
||||
sc-rpc-api = { version = "0.10.0-dev", path = "../rpc-api" }
|
||||
serde_json = "1.0.58"
|
||||
serde = { version = "1.0.126", features = ["derive"] }
|
||||
sp-blockchain = { version = "4.0.0-dev", path = "../../primitives/blockchain" }
|
||||
sp-runtime = { version = "4.0.0-dev", path = "../../primitives/runtime" }
|
||||
codec = { package = "parity-scale-codec", version = "2.0.0" }
|
||||
|
||||
@@ -17,10 +17,31 @@
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
//! A RPC handler to create sync states for light clients.
|
||||
//!
|
||||
//! Currently only usable with BABE + GRANDPA.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! To use the light sync state, it needs to be added as an extension to the chain spec:
|
||||
//!
|
||||
//! ```
|
||||
//! use sc_sync_state_rpc::LightSyncStateExtension;
|
||||
//!
|
||||
//! #[derive(Default, Clone, serde::Serialize, serde::Deserialize, sc_chain_spec::ChainSpecExtension)]
|
||||
//! #[serde(rename_all = "camelCase")]
|
||||
//! pub struct Extensions {
|
||||
//! light_sync_state: LightSyncStateExtension,
|
||||
//! }
|
||||
//!
|
||||
//! type ChainSpec = sc_chain_spec::GenericChainSpec<(), Extensions>;
|
||||
//! ```
|
||||
//!
|
||||
//! If the [`LightSyncStateExtension`] is not added as an extension to the chain spec,
|
||||
//! the [`SyncStateRpcHandler`] will fail at instantiation.
|
||||
|
||||
#![deny(unused_crate_dependencies)]
|
||||
|
||||
use sc_client_api::StorageData;
|
||||
use sp_blockchain::HeaderBackend;
|
||||
use sp_runtime::{
|
||||
generic::BlockId,
|
||||
@@ -35,17 +56,24 @@ type SharedAuthoritySet<TBl> =
|
||||
type SharedEpochChanges<TBl> =
|
||||
sc_consensus_epochs::SharedEpochChanges<TBl, sc_consensus_babe::Epoch>;
|
||||
|
||||
/// Error type used by this crate.
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
#[allow(missing_docs)]
|
||||
enum Error<Block: BlockT> {
|
||||
pub enum Error<Block: BlockT> {
|
||||
#[error(transparent)]
|
||||
Blockchain(#[from] sp_blockchain::Error),
|
||||
|
||||
#[error("Failed to load the block weight for block {0:?}")]
|
||||
LoadingBlockWeightFailed(<Block as BlockT>::Hash),
|
||||
LoadingBlockWeightFailed(Block::Hash),
|
||||
|
||||
#[error("JsonRpc error: {0}")]
|
||||
JsonRpc(String),
|
||||
|
||||
#[error(
|
||||
"The light sync state extension is not provided by the chain spec. \
|
||||
Read the `sc-sync-state-rpc` crate docs on how to do this!"
|
||||
)]
|
||||
LightSyncStateExtensionNotFound,
|
||||
}
|
||||
|
||||
impl<Block: BlockT> From<Error<Block>> for jsonrpc_core::Error {
|
||||
@@ -58,6 +86,40 @@ impl<Block: BlockT> From<Error<Block>> for jsonrpc_core::Error {
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize the given `val` by encoding it with SCALE codec and serializing it as hex.
|
||||
fn serialize_encoded<S: serde::Serializer, T: codec::Encode>(
|
||||
val: &T,
|
||||
s: S,
|
||||
) -> Result<S::Ok, S::Error> {
|
||||
let encoded = StorageData(val.encode());
|
||||
serde::Serialize::serialize(&encoded, s)
|
||||
}
|
||||
|
||||
/// The light sync state extension.
|
||||
///
|
||||
/// This represents a JSON serialized [`LightSyncState`]. It is required to be added to the
|
||||
/// chain-spec as an extension.
|
||||
pub type LightSyncStateExtension = Option<serde_json::Value>;
|
||||
|
||||
/// Hardcoded infomation that allows light clients to sync quickly.
|
||||
#[derive(serde::Serialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct LightSyncState<Block: BlockT> {
|
||||
/// The header of the best finalized block.
|
||||
#[serde(serialize_with = "serialize_encoded")]
|
||||
pub finalized_block_header: <Block as BlockT>::Header,
|
||||
/// The epoch changes tree for babe.
|
||||
#[serde(serialize_with = "serialize_encoded")]
|
||||
pub babe_epoch_changes: sc_consensus_epochs::EpochChangesFor<Block, sc_consensus_babe::Epoch>,
|
||||
/// The babe weight of the finalized block.
|
||||
pub babe_finalized_block_weight: sc_consensus_babe::BabeBlockWeight,
|
||||
/// The authority set for grandpa.
|
||||
#[serde(serialize_with = "serialize_encoded")]
|
||||
pub grandpa_authority_set:
|
||||
sc_finality_grandpa::AuthoritySet<<Block as BlockT>::Hash, NumberFor<Block>>,
|
||||
}
|
||||
|
||||
/// An api for sync state RPC calls.
|
||||
#[rpc]
|
||||
pub trait SyncStateRpcApi {
|
||||
@@ -67,31 +129,37 @@ pub trait SyncStateRpcApi {
|
||||
}
|
||||
|
||||
/// The handler for sync state RPC calls.
|
||||
pub struct SyncStateRpcHandler<TBl: BlockT, TCl> {
|
||||
pub struct SyncStateRpcHandler<Block: BlockT, Backend> {
|
||||
chain_spec: Box<dyn sc_chain_spec::ChainSpec>,
|
||||
client: Arc<TCl>,
|
||||
shared_authority_set: SharedAuthoritySet<TBl>,
|
||||
shared_epoch_changes: SharedEpochChanges<TBl>,
|
||||
client: Arc<Backend>,
|
||||
shared_authority_set: SharedAuthoritySet<Block>,
|
||||
shared_epoch_changes: SharedEpochChanges<Block>,
|
||||
deny_unsafe: sc_rpc_api::DenyUnsafe,
|
||||
}
|
||||
|
||||
impl<TBl, TCl> SyncStateRpcHandler<TBl, TCl>
|
||||
impl<Block, Backend> SyncStateRpcHandler<Block, Backend>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: HeaderBackend<TBl> + sc_client_api::AuxStore + 'static,
|
||||
Block: BlockT,
|
||||
Backend: HeaderBackend<Block> + sc_client_api::AuxStore + 'static,
|
||||
{
|
||||
/// Create a new handler.
|
||||
pub fn new(
|
||||
chain_spec: Box<dyn sc_chain_spec::ChainSpec>,
|
||||
client: Arc<TCl>,
|
||||
shared_authority_set: SharedAuthoritySet<TBl>,
|
||||
shared_epoch_changes: SharedEpochChanges<TBl>,
|
||||
client: Arc<Backend>,
|
||||
shared_authority_set: SharedAuthoritySet<Block>,
|
||||
shared_epoch_changes: SharedEpochChanges<Block>,
|
||||
deny_unsafe: sc_rpc_api::DenyUnsafe,
|
||||
) -> Self {
|
||||
Self { chain_spec, client, shared_authority_set, shared_epoch_changes, deny_unsafe }
|
||||
) -> Result<Self, Error<Block>> {
|
||||
if sc_chain_spec::get_extension::<LightSyncStateExtension>(chain_spec.extensions())
|
||||
.is_some()
|
||||
{
|
||||
Ok(Self { chain_spec, client, shared_authority_set, shared_epoch_changes, deny_unsafe })
|
||||
} else {
|
||||
Err(Error::<Block>::LightSyncStateExtensionNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
fn build_sync_state(&self) -> Result<sc_chain_spec::LightSyncState<TBl>, Error<TBl>> {
|
||||
fn build_sync_state(&self) -> Result<LightSyncState<Block>, Error<Block>> {
|
||||
let finalized_hash = self.client.info().finalized_hash;
|
||||
let finalized_header = self
|
||||
.client
|
||||
@@ -102,7 +170,7 @@ where
|
||||
sc_consensus_babe::aux_schema::load_block_weight(&*self.client, finalized_hash)?
|
||||
.ok_or_else(|| Error::LoadingBlockWeightFailed(finalized_hash))?;
|
||||
|
||||
Ok(sc_chain_spec::LightSyncState {
|
||||
Ok(LightSyncState {
|
||||
finalized_block_header: finalized_header,
|
||||
babe_epoch_changes: self.shared_epoch_changes.shared_data().clone(),
|
||||
babe_finalized_block_weight: finalized_block_weight,
|
||||
@@ -111,10 +179,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<TBl, TCl> SyncStateRpcApi for SyncStateRpcHandler<TBl, TCl>
|
||||
impl<Block, Backend> SyncStateRpcApi for SyncStateRpcHandler<Block, Backend>
|
||||
where
|
||||
TBl: BlockT,
|
||||
TCl: HeaderBackend<TBl> + sc_client_api::AuxStore + 'static,
|
||||
Block: BlockT,
|
||||
Backend: HeaderBackend<Block> + sc_client_api::AuxStore + 'static,
|
||||
{
|
||||
fn system_gen_sync_spec(&self, raw: bool) -> jsonrpc_core::Result<jsonrpc_core::Value> {
|
||||
if let Err(err) = self.deny_unsafe.check_if_safe() {
|
||||
@@ -123,12 +191,21 @@ where
|
||||
|
||||
let mut chain_spec = self.chain_spec.cloned_box();
|
||||
|
||||
let sync_state = self.build_sync_state().map_err(map_error::<TBl, Error<TBl>>)?;
|
||||
let sync_state = self.build_sync_state().map_err(map_error::<Block, Error<Block>>)?;
|
||||
|
||||
chain_spec.set_light_sync_state(sync_state.to_serializable());
|
||||
let string = chain_spec.as_json(raw).map_err(map_error::<TBl, _>)?;
|
||||
let extension = sc_chain_spec::get_extension_mut::<LightSyncStateExtension>(
|
||||
chain_spec.extensions_mut(),
|
||||
)
|
||||
.ok_or_else(|| {
|
||||
Error::<Block>::JsonRpc("Could not find `LightSyncState` chain-spec extension!".into())
|
||||
})?;
|
||||
|
||||
serde_json::from_str(&string).map_err(|err| map_error::<TBl, _>(err))
|
||||
*extension =
|
||||
Some(serde_json::to_value(&sync_state).map_err(|err| map_error::<Block, _>(err))?);
|
||||
|
||||
let json_string = chain_spec.as_json(raw).map_err(map_error::<Block, _>)?;
|
||||
|
||||
serde_json::from_str(&json_string).map_err(|err| map_error::<Block, _>(err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ where
|
||||
rpc_extensions_builder: Box::new(move |_, _| {
|
||||
let mut io = jsonrpc_core::IoHandler::default();
|
||||
io.extend_with(ManualSealApi::to_delegate(ManualSeal::new(rpc_sink.clone())));
|
||||
io
|
||||
Ok(io)
|
||||
}),
|
||||
remote_blockchain: None,
|
||||
network,
|
||||
|
||||
Reference in New Issue
Block a user