Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ where

/// Helper function to build the genesis storage using given json patch and code
fn build_genesis_storage(patch: serde_json::Value, code: &[u8]) -> Storage {
let mut storage = GenesisConfigBuilderRuntimeCaller::new(code)
let mut storage = <GenesisConfigBuilderRuntimeCaller>::new(code)
.get_storage_for_patch(patch)
.unwrap();
storage
Expand Down
3 changes: 2 additions & 1 deletion substrate/bin/utils/chain-spec-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ pub fn generate_chain_spec_for_runtime(cmd: &RuntimeCmd) -> Result<String, Strin
)?)
},
GenesisBuildAction::Default(DefaultCmd { ref default_config_path }) => {
let caller = GenesisConfigBuilderRuntimeCaller::new(&code[..]);
let caller: GenesisConfigBuilderRuntimeCaller =
GenesisConfigBuilderRuntimeCaller::new(&code[..]);
let default_config = caller
.get_default_config()
.map_err(|e| format!("getting default config from runtime should work: {e}"))?;
Expand Down
84 changes: 56 additions & 28 deletions substrate/client/chain-spec/src/chain_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
//! Substrate chain configurations.
#![warn(missing_docs)]
use crate::{
extension::GetExtension, ChainType, GenesisConfigBuilderRuntimeCaller as RuntimeCaller,
Properties, RuntimeGenesis,
extension::GetExtension, genesis_config_builder::HostFunctions, ChainType,
GenesisConfigBuilderRuntimeCaller as RuntimeCaller, Properties, RuntimeGenesis,
};
use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints;
Expand Down Expand Up @@ -122,7 +122,10 @@ impl<G: RuntimeGenesis> GenesisSource<G> {
}
}

impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
impl<G: RuntimeGenesis, E, EHF> BuildStorage for ChainSpec<G, E, EHF>
where
EHF: HostFunctions,
{
fn assimilate_storage(&self, storage: &mut Storage) -> Result<(), String> {
match self.genesis.resolve()? {
#[allow(deprecated)]
Expand Down Expand Up @@ -158,7 +161,7 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
json_blob: RuntimeGenesisConfigJson::Config(config),
code,
}) => {
RuntimeCaller::new(&code[..])
RuntimeCaller::<(sp_io::SubstrateHostFunctions, EHF)>::new(&code[..])
.get_storage_for_config(config)?
.assimilate_storage(storage)?;
storage
Expand All @@ -169,7 +172,7 @@ impl<G: RuntimeGenesis, E> BuildStorage for ChainSpec<G, E> {
json_blob: RuntimeGenesisConfigJson::Patch(patch),
code,
}) => {
RuntimeCaller::new(&code[..])
RuntimeCaller::<(sp_io::SubstrateHostFunctions, EHF)>::new(&code[..])
.get_storage_for_patch(patch)?
.assimilate_storage(storage)?;
storage
Expand Down Expand Up @@ -322,7 +325,7 @@ struct ClientSpec<E> {
pub type NoExtension = Option<()>;

/// Builder for creating [`ChainSpec`] instances.
pub struct ChainSpecBuilder<G, E = NoExtension> {
pub struct ChainSpecBuilder<G, E = NoExtension, EHF = ()> {
code: Vec<u8>,
extensions: E,
name: String,
Expand All @@ -334,10 +337,10 @@ pub struct ChainSpecBuilder<G, E = NoExtension> {
protocol_id: Option<String>,
fork_id: Option<String>,
properties: Option<Properties>,
_genesis: PhantomData<G>,
_genesis: PhantomData<(G, EHF)>,
}

impl<G, E> ChainSpecBuilder<G, E> {
impl<G, E, EHF> ChainSpecBuilder<G, E, EHF> {
/// Creates a new builder instance with no defaults.
pub fn new(code: &[u8], extensions: E) -> Self {
Self {
Expand Down Expand Up @@ -448,23 +451,33 @@ impl<G, E> ChainSpecBuilder<G, E> {
ChainSpec {
client_spec,
genesis: GenesisSource::GenesisBuilderApi(self.genesis_build_action, self.code.into()),
_host_functions: Default::default(),
}
}
}

/// A configuration of a chain. Can be used to build a genesis block.
pub struct ChainSpec<G, E = NoExtension> {
///
/// The chain spec is generic over the native `RuntimeGenesisConfig` struct (`G`). It is also
/// possible to parametrize chain spec over the extended host functions (EHF). It should be use if
/// runtime is using the non-standard host function during genesis state creation.
pub struct ChainSpec<G, E = NoExtension, EHF = ()> {
client_spec: ClientSpec<E>,
genesis: GenesisSource<G>,
_host_functions: PhantomData<EHF>,
}

impl<G, E: Clone> Clone for ChainSpec<G, E> {
impl<G, E: Clone, EHF> Clone for ChainSpec<G, E, EHF> {
fn clone(&self) -> Self {
ChainSpec { client_spec: self.client_spec.clone(), genesis: self.genesis.clone() }
ChainSpec {
client_spec: self.client_spec.clone(),
genesis: self.genesis.clone(),
_host_functions: self._host_functions,
}
}
}

impl<G, E> ChainSpec<G, E> {
impl<G, E, EHF> ChainSpec<G, E, EHF> {
/// A list of bootnode addresses.
pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
&self.client_spec.boot_nodes
Expand Down Expand Up @@ -553,6 +566,7 @@ impl<G, E> ChainSpec<G, E> {
ChainSpec {
client_spec,
genesis: GenesisSource::Factory(Arc::new(constructor), code.into()),
_host_functions: Default::default(),
}
}

Expand All @@ -562,19 +576,23 @@ impl<G, E> ChainSpec<G, E> {
}

/// Provides a `ChainSpec` builder.
pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder<G, E> {
pub fn builder(code: &[u8], extensions: E) -> ChainSpecBuilder<G, E, EHF> {
ChainSpecBuilder::new(code, extensions)
}
}

impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned> ChainSpec<G, E> {
impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned, EHF> ChainSpec<G, E, EHF> {
/// Parse json content into a `ChainSpec`
pub fn from_json_bytes(json: impl Into<Cow<'static, [u8]>>) -> Result<Self, String> {
let json = json.into();
let client_spec = json::from_slice(json.as_ref())
.map_err(|e| format!("Error parsing spec file: {}", e))?;

Ok(ChainSpec { client_spec, genesis: GenesisSource::Binary(json) })
Ok(ChainSpec {
client_spec,
genesis: GenesisSource::Binary(json),
_host_functions: Default::default(),
})
}

/// Parse json file into a `ChainSpec`
Expand All @@ -593,7 +611,11 @@ impl<G: serde::de::DeserializeOwned, E: serde::de::DeserializeOwned> ChainSpec<G
let client_spec =
json::from_slice(&bytes).map_err(|e| format!("Error parsing spec file: {}", e))?;

Ok(ChainSpec { client_spec, genesis: GenesisSource::File(path) })
Ok(ChainSpec {
client_spec,
genesis: GenesisSource::File(path),
_host_functions: Default::default(),
})
}
}

Expand All @@ -608,7 +630,10 @@ struct ChainSpecJsonContainer<G, E> {
genesis: Genesis<G>,
}

impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static, EHF> ChainSpec<G, E, EHF>
where
EHF: HostFunctions,
{
fn json_container(&self, raw: bool) -> Result<ChainSpecJsonContainer<G, E>, String> {
let raw_genesis = match (raw, self.genesis.resolve()?) {
(
Expand All @@ -618,7 +643,8 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
code,
}),
) => {
let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_config(config)?;
let mut storage =
RuntimeCaller::<EHF>::new(&code[..]).get_storage_for_config(config)?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
RawGenesis::from(storage)
},
Expand All @@ -629,7 +655,8 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
code,
}),
) => {
let mut storage = RuntimeCaller::new(&code[..]).get_storage_for_patch(patch)?;
let mut storage =
RuntimeCaller::<EHF>::new(&code[..]).get_storage_for_patch(patch)?;
storage.top.insert(sp_core::storage::well_known_keys::CODE.to_vec(), code);
RawGenesis::from(storage)
},
Expand Down Expand Up @@ -664,10 +691,11 @@ impl<G: RuntimeGenesis, E: serde::Serialize + Clone + 'static> ChainSpec<G, E> {
}
}

impl<G, E> crate::ChainSpec for ChainSpec<G, E>
impl<G, E, EHF> crate::ChainSpec for ChainSpec<G, E, EHF>
where
G: RuntimeGenesis + 'static,
E: GetExtension + serde::Serialize + Clone + Send + Sync + 'static,
EHF: HostFunctions,
{
fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
ChainSpec::boot_nodes(self)
Expand Down Expand Up @@ -953,7 +981,7 @@ mod tests {
#[docify::export]
#[test]
fn build_chain_spec_with_patch_works() {
let output: ChainSpec<()> = ChainSpec::builder(
let output = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand Down Expand Up @@ -986,7 +1014,7 @@ mod tests {
#[docify::export]
#[test]
fn generate_chain_spec_with_patch_works() {
let output: ChainSpec<()> = ChainSpec::builder(
let output = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand Down Expand Up @@ -1033,7 +1061,7 @@ mod tests {
#[test]
fn generate_chain_spec_with_full_config_works() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let output: ChainSpec<()> = ChainSpec::builder(
let output = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand Down Expand Up @@ -1065,7 +1093,7 @@ mod tests {
fn chain_spec_as_json_fails_with_invalid_config() {
let j =
include_str!("../../../test-utils/runtime/res/default_genesis_config_invalid_2.json");
let output: ChainSpec<()> = ChainSpec::builder(
let output = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand All @@ -1083,7 +1111,7 @@ mod tests {

#[test]
fn chain_spec_as_json_fails_with_invalid_patch() {
let output: ChainSpec<()> = ChainSpec::builder(
let output = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand Down Expand Up @@ -1139,7 +1167,7 @@ mod tests {
#[test]
fn update_code_works_with_runtime_genesis_config() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let chain_spec: ChainSpec<()> = ChainSpec::builder(
let chain_spec = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand All @@ -1162,7 +1190,7 @@ mod tests {
#[test]
fn update_code_works_for_raw() {
let j = include_str!("../../../test-utils/runtime/res/default_genesis_config.json");
let chain_spec: ChainSpec<()> = ChainSpec::builder(
let chain_spec = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand All @@ -1184,7 +1212,7 @@ mod tests {

#[test]
fn update_code_works_with_runtime_genesis_patch() {
let chain_spec: ChainSpec<()> = ChainSpec::builder(
let chain_spec = ChainSpec::<()>::builder(
substrate_test_runtime::wasm_binary_unwrap().into(),
Default::default(),
)
Expand Down
20 changes: 11 additions & 9 deletions substrate/client/chain-spec/src/genesis_config_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//! A helper module for calling the GenesisBuilder API from arbitrary runtime wasm blobs.

use codec::{Decode, Encode};
pub use sc_executor::sp_wasm_interface::HostFunctions;
use sc_executor::{error::Result, WasmExecutor};
use serde_json::{from_slice, Value};
use sp_core::{
Expand All @@ -30,29 +31,30 @@ use sp_state_machine::BasicExternalities;
use std::borrow::Cow;

/// A utility that facilitates calling the GenesisBuilder API from the runtime wasm code blob.
pub struct GenesisConfigBuilderRuntimeCaller<'a> {
pub struct GenesisConfigBuilderRuntimeCaller<'a, HF = sp_io::SubstrateHostFunctions> {
code: Cow<'a, [u8]>,
code_hash: Vec<u8>,
executor: WasmExecutor<sp_io::SubstrateHostFunctions>,
executor: WasmExecutor<HF>,
}

impl<'a> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a> {
impl<'a, HF> FetchRuntimeCode for GenesisConfigBuilderRuntimeCaller<'a, HF> {
fn fetch_runtime_code(&self) -> Option<Cow<[u8]>> {
Some(self.code.as_ref().into())
}
}

impl<'a> GenesisConfigBuilderRuntimeCaller<'a> {
impl<'a, HF> GenesisConfigBuilderRuntimeCaller<'a, HF>
where
HF: HostFunctions,
{
/// Creates new instance using the provided code blob.
///
/// This code is later referred to as `runtime`.
pub fn new(code: &'a [u8]) -> Self {
GenesisConfigBuilderRuntimeCaller {
code: code.into(),
code_hash: sp_core::blake2_256(code).to_vec(),
executor: WasmExecutor::<sp_io::SubstrateHostFunctions>::builder()
.with_allow_missing_host_functions(true)
.build(),
executor: WasmExecutor::<HF>::builder().with_allow_missing_host_functions(true).build(),
}
}

Expand Down Expand Up @@ -134,7 +136,7 @@ mod tests {
#[test]
fn get_default_config_works() {
let config =
GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap())
<GenesisConfigBuilderRuntimeCaller>::new(substrate_test_runtime::wasm_binary_unwrap())
.get_default_config()
.unwrap();
let expected = r#"{"system":{},"babe":{"authorities":[],"epochConfig":null},"substrateTest":{"authorities":[]},"balances":{"balances":[]}}"#;
Expand All @@ -156,7 +158,7 @@ mod tests {
});

let storage =
GenesisConfigBuilderRuntimeCaller::new(substrate_test_runtime::wasm_binary_unwrap())
<GenesisConfigBuilderRuntimeCaller>::new(substrate_test_runtime::wasm_binary_unwrap())
.get_storage_for_patch(patch)
.unwrap();

Expand Down