One node two runtimes (#191)

* One node two runtimes

This enables the rococo-collator to run the normal and the contracts runtime.

* Fix tests
This commit is contained in:
Bastian Köcher
2020-08-11 11:35:54 +02:00
committed by GitHub
parent 3ed6030110
commit 3b71c2a6e2
33 changed files with 1958 additions and 1466 deletions
+81 -17
View File
@@ -15,19 +15,20 @@
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
use cumulus_primitives::ParaId;
use parachain_runtime::{
AccountId, BalancesConfig, GenesisConfig, Signature, SudoConfig, SystemConfig,
ParachainInfoConfig, WASM_BINARY,
};
use hex_literal::hex;
use rococo_parachain_primitives::{AccountId, Signature};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{sr25519, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};
use hex_literal::hex;
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig, Extensions>;
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type ChainSpec = sc_service::GenericChainSpec<parachain_runtime::GenesisConfig, Extensions>;
/// Specialized `ChainSpec` for the contracts parachain runtime.
pub type ContractsChainSpec =
sc_service::GenericChainSpec<parachain_contracts_runtime::GenesisConfig, Extensions>;
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
@@ -99,6 +100,42 @@ pub fn get_chain_spec(id: ParaId) -> ChainSpec {
)
}
pub fn get_contracts_chain_spec(id: ParaId) -> ContractsChainSpec {
ContractsChainSpec::from_genesis(
"Contracts Local Testnet",
"contracts_local_testnet",
ChainType::Local,
move || {
contracts_testnet_genesis(
get_account_id_from_seed::<sr25519::Public>("Alice"),
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
],
id,
)
},
vec![],
None,
None,
None,
Extensions {
relay_chain: "westend-dev".into(),
para_id: id.into(),
},
)
}
pub fn staging_test_net(id: ParaId) -> ChainSpec {
ChainSpec::from_genesis(
"Staging Testnet",
@@ -107,7 +144,9 @@ pub fn staging_test_net(id: ParaId) -> ChainSpec {
move || {
testnet_genesis(
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
vec![hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into()],
vec![
hex!["9ed7705e3c7da027ba0583a22a3212042f7e715d3c168ba14f1424e2bc111d00"].into(),
],
id,
)
},
@@ -126,22 +165,47 @@ fn testnet_genesis(
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> GenesisConfig {
GenesisConfig {
frame_system: Some(SystemConfig {
code: WASM_BINARY.expect("WASM binary was not build, please build it!").to_vec(),
) -> parachain_runtime::GenesisConfig {
parachain_runtime::GenesisConfig {
frame_system: Some(parachain_runtime::SystemConfig {
code: parachain_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
changes_trie_config: Default::default(),
}),
pallet_balances: Some(BalancesConfig {
pallet_balances: Some(parachain_runtime::BalancesConfig {
balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, 1 << 60))
.collect(),
}),
pallet_sudo: Some(SudoConfig { key: root_key }),
parachain_info: Some(ParachainInfoConfig { parachain_id: id }),
// TODO: add contracts genesis for the contracts runtime
// pallet_contracts: Some(parachain_runtime::ContractsConfig { current_schedule: Default::default() }),
pallet_sudo: Some(parachain_runtime::SudoConfig { key: root_key }),
parachain_info: Some(parachain_runtime::ParachainInfoConfig { parachain_id: id }),
}
}
fn contracts_testnet_genesis(
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
id: ParaId,
) -> parachain_contracts_runtime::GenesisConfig {
parachain_contracts_runtime::GenesisConfig {
frame_system: Some(parachain_contracts_runtime::SystemConfig {
code: parachain_contracts_runtime::WASM_BINARY
.expect("WASM binary was not build, please build it!")
.to_vec(),
changes_trie_config: Default::default(),
}),
pallet_balances: Some(parachain_contracts_runtime::BalancesConfig {
balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, 1 << 60))
.collect(),
}),
pallet_sudo: Some(parachain_contracts_runtime::SudoConfig { key: root_key }),
parachain_info: Some(parachain_contracts_runtime::ParachainInfoConfig { parachain_id: id }),
cumulus_pallet_contracts: None,
}
}
+54 -19
View File
@@ -24,8 +24,8 @@ use log::info;
use parachain_runtime::Block;
use polkadot_parachain::primitives::AccountIdConversion;
use sc_cli::{
ChainSpec, CliConfiguration, ImportParams, KeystoreParams, NetworkParams, Result,
RuntimeVersion, SharedParams, SubstrateCli, DefaultConfigurationValues,
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
NetworkParams, Result, RuntimeVersion, SharedParams, SubstrateCli,
};
use sc_service::config::{BasePath, PrometheusConfig};
use sp_core::hexdisplay::HexDisplay;
@@ -77,6 +77,9 @@ impl SubstrateCli for Cli {
"track" => Ok(Box::new(chain_spec::ChainSpec::from_json_bytes(
&include_bytes!("../res/track.json")[..],
)?)),
"contracts" => Ok(Box::new(chain_spec::get_contracts_chain_spec(
self.run.parachain_id.unwrap_or(100).into(),
))),
"" => Ok(Box::new(chain_spec::get_chain_spec(
self.run.parachain_id.unwrap_or(100).into(),
))),
@@ -167,6 +170,10 @@ fn extract_genesis_wasm(chain_spec: &Box<dyn sc_service::ChainSpec>) -> Result<V
.ok_or_else(|| "Could not find wasm file in genesis state!".into())
}
fn use_contracts_runtime(chain_spec: &Box<dyn ChainSpec>) -> bool {
chain_spec.id().starts_with("trick") || chain_spec.id().starts_with("contracts")
}
/// Parse command line arguments into service configuration.
pub fn run() -> Result<()> {
let cli = Cli::from_args();
@@ -175,16 +182,35 @@ pub fn run() -> Result<()> {
Some(Subcommand::Base(subcommand)) => {
let runner = cli.create_runner(subcommand)?;
runner.run_subcommand(subcommand, |mut config| {
let params = crate::service::new_partial(&mut config)?;
if use_contracts_runtime(&runner.config().chain_spec) {
runner.run_subcommand(subcommand, |mut config| {
let params = crate::service::new_partial::<
parachain_contracts_runtime::RuntimeApi,
crate::service::ContractsRuntimeExecutor,
>(&mut config)?;
Ok((
params.client,
params.backend,
params.import_queue,
params.task_manager,
))
})
Ok((
params.client,
params.backend,
params.import_queue,
params.task_manager,
))
})
} else {
runner.run_subcommand(subcommand, |mut config| {
let params = crate::service::new_partial::<
parachain_runtime::RuntimeApi,
crate::service::RuntimeExecutor,
>(&mut config)?;
Ok((
params.client,
params.backend,
params.import_queue,
params.task_manager,
))
})
}
}
Some(Subcommand::ExportGenesisState(params)) => {
sc_cli::init_logger("");
@@ -256,14 +282,23 @@ pub fn run() -> Result<()> {
if cli.run.base.validator { "yes" } else { "no" }
);
crate::service::run_node(
config,
key,
polkadot_config,
id,
cli.run.base.validator,
)
.map(|(x, _)| x)
if use_contracts_runtime(&config.chain_spec) {
crate::service::start_contracts_node(
config,
key,
polkadot_config,
id,
cli.run.base.validator,
)
} else {
crate::service::start_node(
config,
key,
polkadot_config,
id,
cli.run.base.validator,
).map(|r| r.0)
}
})
}
}
@@ -60,7 +60,8 @@ async fn integration_test() {
INTEGRATION_TEST_ALLOWED_TIME
.and_then(|x| x.parse().ok())
.unwrap_or(600),
)).fuse();
))
.fuse();
let t2 = async {
let para_id = ParaId::from(100);
@@ -105,7 +106,7 @@ async fn integration_test() {
let parachain_config =
parachain_config(task_executor.clone(), Charlie, vec![], para_id).unwrap();
let (_service, charlie_client) =
crate::service::run_node(parachain_config, key, polkadot_config, para_id, true)
crate::service::start_node(parachain_config, key, polkadot_config, para_id, true)
.unwrap();
sleep(Duration::from_secs(3)).await;
charlie_client.wait_for_blocks(4).await;
+121 -65
View File
@@ -20,67 +20,74 @@ use cumulus_service::{
prepare_node_config, start_collator, start_full_node, StartCollatorParams, StartFullNodeParams,
};
use polkadot_primitives::v0::CollatorPair;
use rococo_parachain_primitives::Block;
use sc_executor::native_executor_instance;
pub use sc_executor::NativeExecutor;
use sc_informant::OutputFormat;
use sc_service::{Configuration, PartialComponents, Role, TFullBackend, TFullClient, TaskManager};
use sp_api::ConstructRuntimeApi;
use sp_runtime::traits::BlakeTwo256;
use sp_trie::PrefixedMemoryDB;
use std::sync::Arc;
// Our native executor instance.
// Native executor instance.
native_executor_instance!(
pub Executor,
pub RuntimeExecutor,
parachain_runtime::api::dispatch,
parachain_runtime::native_version,
);
// Native executor instance for the contracts runtime.
native_executor_instance!(
pub ContractsRuntimeExecutor,
parachain_contracts_runtime::api::dispatch,
parachain_contracts_runtime::native_version,
);
/// Starts a `ServiceBuilder` for a full service.
///
/// Use this macro if you don't actually need the full service, but just the builder in order to
/// be able to perform chain operations.
pub fn new_partial(
pub fn new_partial<RuntimeApi, Executor>(
config: &mut Configuration,
) -> Result<
PartialComponents<
TFullClient<
parachain_runtime::opaque::Block,
parachain_runtime::RuntimeApi,
crate::service::Executor,
>,
TFullBackend<parachain_runtime::opaque::Block>,
TFullClient<Block, RuntimeApi, Executor>,
TFullBackend<Block>,
(),
sp_consensus::import_queue::BasicQueue<
parachain_runtime::opaque::Block,
PrefixedMemoryDB<BlakeTwo256>,
>,
sc_transaction_pool::FullPool<
parachain_runtime::opaque::Block,
TFullClient<
parachain_runtime::opaque::Block,
parachain_runtime::RuntimeApi,
crate::service::Executor,
>,
>,
sp_consensus::import_queue::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
sc_transaction_pool::FullPool<Block, TFullClient<Block, RuntimeApi, Executor>>,
(),
>,
sc_service::Error,
> {
>
where
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, Executor>>
+ Send
+ Sync
+ 'static,
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::Metadata<Block>
+ sp_session::SessionKeys<Block>
+ sp_api::ApiExt<
Block,
Error = sp_blockchain::Error,
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
> + sp_offchain::OffchainWorkerApi<Block>
+ sp_block_builder::BlockBuilder<Block>,
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
Executor: sc_executor::NativeExecutionDispatch + 'static,
{
let inherent_data_providers = sp_inherents::InherentDataProviders::new();
let (client, backend, keystore, task_manager) = sc_service::new_full_parts::<
parachain_runtime::opaque::Block,
parachain_runtime::RuntimeApi,
crate::service::Executor,
>(&config)?;
let (client, backend, keystore, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, Executor>(&config)?;
let client = Arc::new(client);
//let select_chain = sc_consensus::LongestChain::new(backend.clone());
let registry = config.prometheus_registry();
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(),
//std::sync::Arc::new(pool_api),
config.prometheus_registry(),
task_manager.spawn_handle(),
client.clone(),
@@ -109,25 +116,39 @@ pub fn new_partial(
Ok(params)
}
/// Run a node with the given parachain `Configuration` and relay chain `Configuration`
/// Start a node with the given parachain `Configuration` and relay chain `Configuration`.
///
/// This function blocks until done.
pub fn run_node(
/// This is the actual implementation that is abstract over the executor and the runtime api.
fn start_node_impl<RuntimeApi, Executor, RB>(
parachain_config: Configuration,
collator_key: Arc<CollatorPair>,
mut polkadot_config: polkadot_collator::Configuration,
id: polkadot_primitives::v0::Id,
validator: bool,
) -> sc_service::error::Result<(
TaskManager,
Arc<
TFullClient<
parachain_runtime::opaque::Block,
parachain_runtime::RuntimeApi,
crate::service::Executor,
>,
>,
)> {
rpc_ext_builder: RB,
) -> sc_service::error::Result<(TaskManager, Arc<TFullClient<Block, RuntimeApi, Executor>>)>
where
RuntimeApi: ConstructRuntimeApi<Block, TFullClient<Block, RuntimeApi, Executor>>
+ Send
+ Sync
+ 'static,
RuntimeApi::RuntimeApi: sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block>
+ sp_api::Metadata<Block>
+ sp_session::SessionKeys<Block>
+ sp_api::ApiExt<
Block,
Error = sp_blockchain::Error,
StateBackend = sc_client_api::StateBackendFor<TFullBackend<Block>, Block>,
> + sp_offchain::OffchainWorkerApi<Block>
+ sp_block_builder::BlockBuilder<Block>,
sc_client_api::StateBackendFor<TFullBackend<Block>, Block>: sp_api::StateBackend<BlakeTwo256>,
Executor: sc_executor::NativeExecutionDispatch + 'static,
RB: Fn(
Arc<TFullClient<Block, RuntimeApi, Executor>>,
) -> jsonrpc_core::IoHandler<sc_rpc::Metadata>
+ Send
+ 'static,
{
if matches!(parachain_config.role, Role::Light) {
return Err("Light client not supported!".into());
}
@@ -143,7 +164,7 @@ pub fn run_node(
prefix: format!("[{}] ", Color::Blue.bold().paint("Relaychain")),
};
let params = new_partial(&mut parachain_config)?;
let params = new_partial::<RuntimeApi, Executor>(&mut parachain_config)?;
params
.inherent_data_providers
.register_provider(sp_timestamp::InherentDataProvider)
@@ -163,32 +184,21 @@ pub fn run_node(
let import_queue = params.import_queue;
let (network, network_status_sinks, system_rpc_tx, start_network) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &parachain_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: None,
block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)),
finality_proof_request_builder: None,
finality_proof_provider: None,
config: &parachain_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
on_demand: None,
block_announce_validator_builder: Some(Box::new(block_announce_validator_builder)),
finality_proof_request_builder: None,
finality_proof_provider: None,
})?;
let rpc_extensions_builder = {
let _client = client.clone();
let client = client.clone();
Box::new(move |_deny_unsafe| {
let io = jsonrpc_core::IoHandler::default();
// TODO: add this rpc when running the contracts runtime
/*
use pallet_contracts_rpc::{Contracts, ContractsApi};
io.extend_with(
ContractsApi::to_delegate(Contracts::new(client.clone()))
);
*/
io
})
Box::new(move |_deny_unsafe| rpc_ext_builder(client.clone()))
};
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
@@ -249,3 +259,49 @@ pub fn run_node(
Ok((task_manager, client))
}
/// Start a normal parachain node.
pub fn start_node(
parachain_config: Configuration,
collator_key: Arc<CollatorPair>,
polkadot_config: polkadot_collator::Configuration,
id: polkadot_primitives::v0::Id,
validator: bool,
) -> sc_service::error::Result<(
TaskManager,
Arc<TFullClient<Block, parachain_runtime::RuntimeApi, RuntimeExecutor>>,
)> {
start_node_impl::<parachain_runtime::RuntimeApi, RuntimeExecutor, _>(
parachain_config,
collator_key,
polkadot_config,
id,
validator,
|_| Default::default(),
)
}
/// Start a contracts parachain node.
pub fn start_contracts_node(
parachain_config: Configuration,
collator_key: Arc<CollatorPair>,
polkadot_config: polkadot_collator::Configuration,
id: polkadot_primitives::v0::Id,
validator: bool,
) -> sc_service::error::Result<TaskManager> {
start_node_impl::<parachain_contracts_runtime::RuntimeApi, ContractsRuntimeExecutor, _>(
parachain_config,
collator_key,
polkadot_config,
id,
validator,
|client| {
let mut io = jsonrpc_core::IoHandler::default();
use cumulus_pallet_contracts_rpc::{Contracts, ContractsApi};
io.extend_with(ContractsApi::to_delegate(Contracts::new(client)));
io
},
)
.map(|r| r.0)
}