Transition into monorepo (#180)

* evm template integrated

* workflows modified per template

* workflow fixes
This commit is contained in:
Özgün Özerk
2024-05-17 12:00:25 +03:00
committed by GitHub
parent 9cd76d29f0
commit 1bb2e96501
103 changed files with 20153 additions and 581 deletions
+202
View File
@@ -0,0 +1,202 @@
use cumulus_primitives_core::ParaId;
use parachain_template_runtime::{
constants::currency::EXISTENTIAL_DEPOSIT, AccountId, AuraId, Signature,
};
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use sp_core::{ecdsa, Pair, Public};
use sp_runtime::traits::{IdentifyAccount, Verify};
/// Specialized `ChainSpec` for the normal parachain runtime.
pub type ChainSpec =
sc_service::GenericChainSpec<parachain_template_runtime::RuntimeGenesisConfig, Extensions>;
/// The default XCM version to set in genesis config.
const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION;
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
/// The extensions for the [`ChainSpec`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
#[serde(deny_unknown_fields)]
pub struct Extensions {
/// The relay chain of the Parachain.
pub relay_chain: String,
/// The id of the Parachain.
pub para_id: u32,
}
impl Extensions {
/// Try to get the extension from the given `ChainSpec`.
pub fn try_get(chain_spec: &dyn sc_service::ChainSpec) -> Option<&Self> {
sc_chain_spec::get_extension(chain_spec.extensions())
}
}
type AccountPublic = <Signature as Verify>::Signer;
/// Generate collator keys from seed.
///
/// This function's return type must always match the session keys of the chain
/// in tuple format.
pub fn get_collator_keys_from_seed(seed: &str) -> AuraId {
get_from_seed::<AuraId>(seed)
}
/// Helper function to generate an account ID from seed
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
/// Generate the session keys from individual elements.
///
/// The input must be a tuple of individual keys (a single arg for now since we
/// have just one key).
pub fn template_session_keys(keys: AuraId) -> parachain_template_runtime::SessionKeys {
parachain_template_runtime::SessionKeys { aura: keys }
}
pub fn development_config() -> ChainSpec {
// Give your base currency a unit name and decimal places
let mut properties = sc_chain_spec::Properties::new();
properties.insert("tokenSymbol".into(), "UNIT".into());
properties.insert("tokenDecimals".into(), 12.into());
properties.insert("ss58Format".into(), 42.into());
ChainSpec::builder(
parachain_template_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(),
// You MUST set this to the correct network!
para_id: 1000,
},
)
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_patch(testnet_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<ecdsa::Public>("Alice"),
get_collator_keys_from_seed("Alice"),
),
(get_account_id_from_seed::<ecdsa::Public>("Bob"), get_collator_keys_from_seed("Bob")),
],
vec![
get_account_id_from_seed::<ecdsa::Public>("Alice"),
get_account_id_from_seed::<ecdsa::Public>("Bob"),
get_account_id_from_seed::<ecdsa::Public>("Charlie"),
get_account_id_from_seed::<ecdsa::Public>("Dave"),
get_account_id_from_seed::<ecdsa::Public>("Eve"),
get_account_id_from_seed::<ecdsa::Public>("Ferdie"),
get_account_id_from_seed::<ecdsa::Public>("Alice//stash"),
get_account_id_from_seed::<ecdsa::Public>("Bob//stash"),
get_account_id_from_seed::<ecdsa::Public>("Charlie//stash"),
get_account_id_from_seed::<ecdsa::Public>("Dave//stash"),
get_account_id_from_seed::<ecdsa::Public>("Eve//stash"),
get_account_id_from_seed::<ecdsa::Public>("Ferdie//stash"),
],
get_account_id_from_seed::<ecdsa::Public>("Alice"),
1000.into(),
))
.build()
}
pub fn local_testnet_config() -> ChainSpec {
// Give your base currency a unit name and decimal places
let mut properties = sc_chain_spec::Properties::new();
properties.insert("tokenSymbol".into(), "UNIT".into());
properties.insert("tokenDecimals".into(), 12.into());
properties.insert("ss58Format".into(), 42.into());
#[allow(deprecated)]
ChainSpec::builder(
parachain_template_runtime::WASM_BINARY
.expect("WASM binary was not built, please build it!"),
Extensions {
relay_chain: "rococo-local".into(),
// You MUST set this to the correct network!
para_id: 1000,
},
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_patch(testnet_genesis(
// initial collators.
vec![
(
get_account_id_from_seed::<ecdsa::Public>("Alice"),
get_collator_keys_from_seed("Alice"),
),
(get_account_id_from_seed::<ecdsa::Public>("Bob"), get_collator_keys_from_seed("Bob")),
],
vec![
get_account_id_from_seed::<ecdsa::Public>("Alice"),
get_account_id_from_seed::<ecdsa::Public>("Bob"),
get_account_id_from_seed::<ecdsa::Public>("Charlie"),
get_account_id_from_seed::<ecdsa::Public>("Dave"),
get_account_id_from_seed::<ecdsa::Public>("Eve"),
get_account_id_from_seed::<ecdsa::Public>("Ferdie"),
get_account_id_from_seed::<ecdsa::Public>("Alice//stash"),
get_account_id_from_seed::<ecdsa::Public>("Bob//stash"),
get_account_id_from_seed::<ecdsa::Public>("Charlie//stash"),
get_account_id_from_seed::<ecdsa::Public>("Dave//stash"),
get_account_id_from_seed::<ecdsa::Public>("Eve//stash"),
get_account_id_from_seed::<ecdsa::Public>("Ferdie//stash"),
],
get_account_id_from_seed::<ecdsa::Public>("Alice"),
1000.into(),
))
.with_protocol_id("template-local")
.with_properties(properties)
.build()
}
fn testnet_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
root: AccountId,
id: ParaId,
) -> serde_json::Value {
serde_json::json!({
"balances": {
"balances": endowed_accounts.iter().cloned().map(|k| (k, 1u64 << 60)).collect::<Vec<_>>(),
},
"parachainInfo": {
"parachainId": id,
},
"collatorSelection": {
"invulnerables": invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
"candidacyBond": EXISTENTIAL_DEPOSIT * 16,
},
"session": {
"keys": invulnerables
.into_iter()
.map(|(acc, aura)| {
(
acc, // account id
acc, // validator id
template_session_keys(aura), // session keys
)
})
.collect::<Vec<_>>(),
},
"treasury": {},
"polkadotXcm": {
"safeXcmVersion": Some(SAFE_XCM_VERSION),
},
"sudo": { "key": Some(root) }
})
}
+117
View File
@@ -0,0 +1,117 @@
use std::path::PathBuf;
/// Sub-commands supported by the collator.
#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
/// Build a chain specification.
BuildSpec(sc_cli::BuildSpecCmd),
/// Validate blocks.
CheckBlock(sc_cli::CheckBlockCmd),
/// Export blocks.
ExportBlocks(sc_cli::ExportBlocksCmd),
/// Export the state of a given block into a chain spec.
ExportState(sc_cli::ExportStateCmd),
/// Import blocks.
ImportBlocks(sc_cli::ImportBlocksCmd),
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),
/// Remove the whole chain.
PurgeChain(cumulus_client_cli::PurgeChainCmd),
/// Export the genesis head data of the parachain.
///
/// Head data is the encoded block header.
#[command(alias = "export-genesis-state")]
ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand),
/// Export the genesis wasm of the parachain.
ExportGenesisWasm(cumulus_client_cli::ExportGenesisWasmCommand),
/// Sub-commands concerned with benchmarking.
/// The pallet benchmarking moved to the `pallet` sub-command.
#[command(subcommand)]
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
/// Try-runtime has migrated to a standalone
/// [CLI](<https://github.com/paritytech/try-runtime-cli>). The subcommand exists as a stub and
/// deprecation notice. It will be removed entirely some time after Janurary
/// 2024.
TryRuntime,
}
const AFTER_HELP_EXAMPLE: &str = color_print::cstr!(
r#"<bold><underline>Examples:</></>
<bold>parachain-template-node build-spec --disable-default-bootnode > plain-parachain-chainspec.json</>
Export a chainspec for a local testnet in json format.
<bold>parachain-template-node --chain plain-parachain-chainspec.json --tmp -- --chain rococo-local</>
Launch a full node with chain specification loaded from plain-parachain-chainspec.json.
<bold>parachain-template-node</>
Launch a full node with default parachain <italic>local-testnet</> and relay chain <italic>rococo-local</>.
<bold>parachain-template-node --collator</>
Launch a collator with default parachain <italic>local-testnet</> and relay chain <italic>rococo-local</>.
"#
);
#[derive(Debug, clap::Parser)]
#[command(
propagate_version = true,
args_conflicts_with_subcommands = true,
subcommand_negates_reqs = true
)]
#[clap(after_help = AFTER_HELP_EXAMPLE)]
pub struct Cli {
#[command(subcommand)]
pub subcommand: Option<Subcommand>,
#[command(flatten)]
pub run: cumulus_client_cli::RunCmd,
/// Disable automatic hardware benchmarks.
///
/// By default these benchmarks are automatically ran at startup and measure
/// the CPU speed, the memory bandwidth and the disk speed.
///
/// The results are then printed out in the logs, and also sent as part of
/// telemetry, if telemetry is enabled.
#[arg(long)]
pub no_hardware_benchmarks: bool,
/// Relay chain arguments
#[arg(raw = true)]
pub relay_chain_args: Vec<String>,
}
#[derive(Debug)]
pub struct RelayChainCli {
/// The actual relay chain cli object.
pub base: polkadot_cli::RunCmd,
/// Optional chain id that should be passed to the relay chain.
pub chain_id: Option<String>,
/// The base path that should be used by the relay chain.
pub base_path: Option<PathBuf>,
}
impl RelayChainCli {
/// Parse the relay chain CLI parameters using the para chain
/// `Configuration`.
pub fn new<'a>(
para_config: &sc_service::Configuration,
relay_chain_args: impl Iterator<Item = &'a String>,
) -> Self {
let extension = crate::chain_spec::Extensions::try_get(&*para_config.chain_spec);
let chain_id = extension.map(|e| e.relay_chain.clone());
let base_path = para_config.base_path.path().join("polkadot");
Self {
base_path: Some(base_path),
chain_id,
base: clap::Parser::parse_from(relay_chain_args),
}
}
}
+388
View File
@@ -0,0 +1,388 @@
use std::net::SocketAddr;
use cumulus_primitives_core::ParaId;
use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE};
use log::info;
use parachain_template_runtime::Block;
use sc_cli::{
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
NetworkParams, Result, SharedParams, SubstrateCli,
};
use sc_service::config::{BasePath, PrometheusConfig};
use sp_runtime::traits::AccountIdConversion;
use crate::{
chain_spec,
cli::{Cli, RelayChainCli, Subcommand},
service::new_partial,
};
fn load_spec(id: &str) -> std::result::Result<Box<dyn ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_config()),
"template-rococo" => Box::new(chain_spec::local_testnet_config()),
"" | "local" => Box::new(chain_spec::local_testnet_config()),
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
impl SubstrateCli for Cli {
fn impl_name() -> String {
"Parachain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
format!(
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
passed to the parachain node, while the arguments provided after -- will be passed \
to the relay chain node.\n\n{} <parachain-args> -- <relay-chain-args>",
Self::executable_name()
)
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/paritytech/polkadot-sdk/issues/new".into()
}
fn copyright_start_year() -> i32 {
2020
}
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
load_spec(id)
}
}
impl SubstrateCli for RelayChainCli {
fn impl_name() -> String {
"Parachain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
format!(
"Parachain Collator Template\n\nThe command-line arguments provided first will be \
passed to the parachain node, while the arguments provided after -- will be passed \
to the relay chain node.\n\n{} <parachain-args> -- <relay-chain-args>",
Self::executable_name()
)
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/paritytech/polkadot-sdk/issues/new".into()
}
fn copyright_start_year() -> i32 {
2020
}
fn load_spec(&self, id: &str) -> std::result::Result<Box<dyn sc_service::ChainSpec>, String> {
polkadot_cli::Cli::from_iter([RelayChainCli::executable_name()].iter()).load_spec(id)
}
}
macro_rules! construct_async_run {
(|$components:ident, $cli:ident, $cmd:ident, $config:ident| $( $code:tt )* ) => {{
let runner = $cli.create_runner($cmd)?;
runner.async_run(|$config| {
let $components = new_partial(&$config)?;
let task_manager = $components.task_manager;
{ $( $code )* }.map(|v| (v, task_manager))
})
}}
}
/// Parse command line arguments into service configuration.
pub fn run() -> Result<()> {
let cli = Cli::from_args();
match &cli.subcommand {
Some(Subcommand::BuildSpec(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.chain_spec, config.network))
},
Some(Subcommand::CheckBlock(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
},
Some(Subcommand::ExportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.database))
})
},
Some(Subcommand::ExportState(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, config.chain_spec))
})
},
Some(Subcommand::ImportBlocks(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.import_queue))
})
},
Some(Subcommand::Revert(cmd)) => {
construct_async_run!(|components, cli, cmd, config| {
Ok(cmd.run(components.client, components.backend, None))
})
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
let polkadot_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
);
let polkadot_config = SubstrateCli::create_configuration(
&polkadot_cli,
&polkadot_cli,
config.tokio_handle.clone(),
)
.map_err(|err| format!("Relay chain argument error: {}", err))?;
cmd.run(config, polkadot_config)
})
},
Some(Subcommand::ExportGenesisHead(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
let partials = new_partial(&config)?;
cmd.run(partials.client)
})
},
Some(Subcommand::ExportGenesisWasm(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|_config| {
let spec = cli.load_spec(&cmd.shared_params.chain.clone().unwrap_or_default())?;
cmd.run(&*spec)
})
},
Some(Subcommand::Benchmark(cmd)) => {
let runner = cli.create_runner(cmd)?;
// Switch on the concrete benchmark sub-command-
match cmd {
BenchmarkCmd::Pallet(cmd) =>
if cfg!(feature = "runtime-benchmarks") {
runner.sync_run(|config| cmd.run::<Block, ()>(config))
} else {
Err("Benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
.into())
},
BenchmarkCmd::Block(cmd) => runner.sync_run(|config| {
let partials = new_partial(&config)?;
cmd.run(partials.client)
}),
#[cfg(not(feature = "runtime-benchmarks"))]
BenchmarkCmd::Storage(_) =>
Err(sc_cli::Error::Input(
"Compile with --features=runtime-benchmarks \
to enable storage benchmarks."
.into(),
)),
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => runner.sync_run(|config| {
let partials = new_partial(&config)?;
let db = partials.backend.expose_db();
let storage = partials.backend.expose_storage();
cmd.run(config, partials.client.clone(), db, storage)
}),
BenchmarkCmd::Machine(cmd) =>
runner.sync_run(|config| cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone())),
// NOTE: this allows the Client to leniently implement
// new benchmark commands without requiring a companion MR.
#[allow(unreachable_patterns)]
_ => Err("Benchmarking sub-command unsupported".into()),
}
},
Some(Subcommand::TryRuntime) => Err("The `try-runtime` subcommand has been migrated to a standalone CLI (https://github.com/paritytech/try-runtime-cli). It is no longer being maintained here and will be removed entirely some time after January 2024. Please remove this subcommand from your runtime and use the standalone CLI.".into()),
None => {
let runner = cli.create_runner(&cli.run.normalize())?;
let collator_options = cli.run.collator_options();
runner.run_node_until_exit(|config| async move {
let hwbench = (!cli.no_hardware_benchmarks)
.then_some(config.database.path().map(|database_path| {
let _ = std::fs::create_dir_all(database_path);
sc_sysinfo::gather_hwbench(Some(database_path))
}))
.flatten();
let para_id = chain_spec::Extensions::try_get(&*config.chain_spec)
.map(|e| e.para_id)
.ok_or("Could not find parachain ID in chain-spec.")?;
let polkadot_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
);
let id = ParaId::from(para_id);
let parachain_account =
AccountIdConversion::<polkadot_primitives::AccountId>::into_account_truncating(
&id,
);
let tokio_handle = config.tokio_handle.clone();
let polkadot_config =
SubstrateCli::create_configuration(&polkadot_cli, &polkadot_cli, tokio_handle)
.map_err(|err| format!("Relay chain argument error: {}", err))?;
info!("Parachain Account: {parachain_account}");
info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
crate::service::start_parachain_node(
config,
polkadot_config,
collator_options,
id,
hwbench,
)
.await
.map(|r| r.0)
.map_err(Into::into)
})
},
}
}
impl DefaultConfigurationValues for RelayChainCli {
fn p2p_listen_port() -> u16 {
30334
}
fn rpc_listen_port() -> u16 {
9945
}
fn prometheus_listen_port() -> u16 {
9616
}
}
impl CliConfiguration<Self> for RelayChainCli {
fn shared_params(&self) -> &SharedParams {
self.base.base.shared_params()
}
fn import_params(&self) -> Option<&ImportParams> {
self.base.base.import_params()
}
fn network_params(&self) -> Option<&NetworkParams> {
self.base.base.network_params()
}
fn keystore_params(&self) -> Option<&KeystoreParams> {
self.base.base.keystore_params()
}
fn base_path(&self) -> Result<Option<BasePath>> {
Ok(self.shared_params().base_path()?.or_else(|| self.base_path.clone().map(Into::into)))
}
fn rpc_addr(&self, default_listen_port: u16) -> Result<Option<SocketAddr>> {
self.base.base.rpc_addr(default_listen_port)
}
fn prometheus_config(
&self,
default_listen_port: u16,
chain_spec: &Box<dyn ChainSpec>,
) -> Result<Option<PrometheusConfig>> {
self.base.base.prometheus_config(default_listen_port, chain_spec)
}
fn init<F>(
&self,
_support_url: &String,
_impl_version: &String,
_logger_hook: F,
_config: &sc_service::Configuration,
) -> Result<()>
where
F: FnOnce(&mut sc_cli::LoggerBuilder, &sc_service::Configuration),
{
unreachable!("PolkadotCli is never initialized; qed");
}
fn chain_id(&self, is_dev: bool) -> Result<String> {
let chain_id = self.base.base.chain_id(is_dev)?;
Ok(if chain_id.is_empty() { self.chain_id.clone().unwrap_or_default() } else { chain_id })
}
fn role(&self, is_dev: bool) -> Result<sc_service::Role> {
self.base.base.role(is_dev)
}
fn transaction_pool(&self, is_dev: bool) -> Result<sc_service::config::TransactionPoolOptions> {
self.base.base.transaction_pool(is_dev)
}
fn trie_cache_maximum_size(&self) -> Result<Option<usize>> {
self.base.base.trie_cache_maximum_size()
}
fn rpc_methods(&self) -> Result<sc_service::config::RpcMethods> {
self.base.base.rpc_methods()
}
fn rpc_max_connections(&self) -> Result<u32> {
self.base.base.rpc_max_connections()
}
fn rpc_cors(&self, is_dev: bool) -> Result<Option<Vec<String>>> {
self.base.base.rpc_cors(is_dev)
}
fn default_heap_pages(&self) -> Result<Option<u64>> {
self.base.base.default_heap_pages()
}
fn force_authoring(&self) -> Result<bool> {
self.base.base.force_authoring()
}
fn disable_grandpa(&self) -> Result<bool> {
self.base.base.disable_grandpa()
}
fn max_runtime_instances(&self) -> Result<Option<usize>> {
self.base.base.max_runtime_instances()
}
fn announce_block(&self) -> Result<bool> {
self.base.base.announce_block()
}
fn telemetry_endpoints(
&self,
chain_spec: &Box<dyn ChainSpec>,
) -> Result<Option<sc_telemetry::TelemetryEndpoints>> {
self.base.base.telemetry_endpoints(chain_spec)
}
fn node_name(&self) -> Result<String> {
self.base.base.node_name()
}
}
+14
View File
@@ -0,0 +1,14 @@
//! Substrate Parachain Node Template CLI
#![warn(missing_docs)]
mod chain_spec;
#[macro_use]
mod service;
mod cli;
mod command;
mod rpc;
fn main() -> sc_cli::Result<()> {
command::run()
}
+57
View File
@@ -0,0 +1,57 @@
//! A collection of node-specific RPC methods.
//! Substrate provides the `sc-rpc` crate, which defines the core RPC layer
//! used by Substrate nodes. This file extends those RPC definitions with
//! capabilities that are specific to this project's runtime configuration.
#![warn(missing_docs)]
use std::sync::Arc;
use parachain_template_runtime::{opaque::Block, AccountId, Balance, Nonce};
use sc_client_api::AuxStore;
pub use sc_rpc::DenyUnsafe;
use sc_transaction_pool_api::TransactionPool;
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
/// A type representing all RPC extensions.
pub type RpcExtension = jsonrpsee::RpcModule<()>;
/// Full client dependencies
pub struct FullDeps<C, P> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
/// Whether to deny unsafe calls
pub deny_unsafe: DenyUnsafe,
}
/// Instantiate all RPC extensions.
pub fn create_full<C, P>(
deps: FullDeps<C, P>,
) -> Result<RpcExtension, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>
+ HeaderBackend<Block>
+ AuxStore
+ HeaderMetadata<Block, Error = BlockChainError>
+ Send
+ Sync
+ 'static,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: BlockBuilder<Block>,
P: TransactionPool + Sync + Send + 'static,
{
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcExtension::new(());
let FullDeps { client, pool, deny_unsafe } = deps;
module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?;
module.merge(TransactionPayment::new(client).into_rpc())?;
Ok(module)
}
+471
View File
@@ -0,0 +1,471 @@
//! Service and ServiceFactory implementation. Specialized wrapper over
//! substrate service.
// std
use std::{sync::Arc, time::Duration};
use cumulus_client_cli::CollatorOptions;
// Cumulus Imports
use cumulus_client_collator::service::CollatorService;
use cumulus_client_consensus_common::ParachainBlockImport as TParachainBlockImport;
use cumulus_client_consensus_proposer::Proposer;
use cumulus_client_service::{
build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks,
BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams,
};
#[cfg(feature = "async-backing")]
use cumulus_primitives_core::relay_chain::ValidationCode;
use cumulus_primitives_core::{relay_chain::CollatorPair, ParaId};
use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
// Substrate Imports
use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
// Local Runtime Types
use parachain_template_runtime::{
opaque::{Block, Hash},
RuntimeApi,
};
use sc_client_api::Backend;
use sc_consensus::ImportQueue;
use sc_executor::{
HeapAllocStrategy, NativeElseWasmExecutor, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY,
};
use sc_network::NetworkBlock;
use sc_network_sync::SyncingService;
use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager};
use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use sp_keystore::KeystorePtr;
use substrate_prometheus_endpoint::Registry;
/// Native executor type.
pub struct ParachainNativeExecutor;
impl sc_executor::NativeExecutionDispatch for ParachainNativeExecutor {
type ExtendHostFunctions = frame_benchmarking::benchmarking::HostFunctions;
fn dispatch(method: &str, data: &[u8]) -> Option<Vec<u8>> {
parachain_template_runtime::api::dispatch(method, data)
}
fn native_version() -> sc_executor::NativeVersion {
parachain_template_runtime::native_version()
}
}
type ParachainExecutor = NativeElseWasmExecutor<ParachainNativeExecutor>;
type ParachainClient = TFullClient<Block, RuntimeApi, ParachainExecutor>;
type ParachainBackend = TFullBackend<Block>;
type ParachainBlockImport = TParachainBlockImport<Block, Arc<ParachainClient>, ParachainBackend>;
/// 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(
config: &Configuration,
) -> Result<
PartialComponents<
ParachainClient,
ParachainBackend,
(),
sc_consensus::DefaultImportQueue<Block>,
sc_transaction_pool::FullPool<Block, ParachainClient>,
(ParachainBlockImport, Option<Telemetry>, Option<TelemetryWorkerHandle>),
>,
sc_service::Error,
> {
let telemetry = config
.telemetry_endpoints
.clone()
.filter(|x| !x.is_empty())
.map(|endpoints| -> Result<_, sc_telemetry::Error> {
let worker = TelemetryWorker::new(16)?;
let telemetry = worker.handle().new_telemetry(endpoints);
Ok((worker, telemetry))
})
.transpose()?;
let heap_pages = config
.default_heap_pages
.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ });
let wasm = WasmExecutor::builder()
.with_execution_method(config.wasm_method)
.with_onchain_heap_alloc_strategy(heap_pages)
.with_offchain_heap_alloc_strategy(heap_pages)
.with_max_runtime_instances(config.max_runtime_instances)
.with_runtime_cache_size(config.runtime_cache_size)
.build();
let executor = ParachainExecutor::new_with_wasm_executor(wasm);
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts::<Block, RuntimeApi, _>(
config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
executor,
)?;
let client = Arc::new(client);
let telemetry_worker_handle = telemetry.as_ref().map(|(worker, _)| worker.handle());
let telemetry = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
let transaction_pool = sc_transaction_pool::BasicPool::new_full(
config.transaction_pool.clone(),
config.role.is_authority().into(),
config.prometheus_registry(),
task_manager.spawn_essential_handle(),
client.clone(),
);
let block_import = ParachainBlockImport::new(client.clone(), backend.clone());
let import_queue = build_import_queue(
client.clone(),
block_import.clone(),
config,
telemetry.as_ref().map(|telemetry| telemetry.handle()),
&task_manager,
)?;
Ok(PartialComponents {
backend,
client,
import_queue,
keystore_container,
task_manager,
transaction_pool,
select_chain: (),
other: (block_import, telemetry, telemetry_worker_handle),
})
}
/// Start a node with the given parachain `Configuration` and relay chain
/// `Configuration`.
///
/// This is the actual implementation that is abstract over the executor and the
/// runtime api.
#[sc_tracing::logging::prefix_logs_with("Parachain")]
async fn start_node_impl(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
para_id: ParaId,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)> {
let parachain_config = prepare_node_config(parachain_config);
let params = new_partial(&parachain_config)?;
let (block_import, mut telemetry, telemetry_worker_handle) = params.other;
let net_config = sc_network::config::FullNetworkConfiguration::new(&parachain_config.network);
let client = params.client.clone();
let backend = params.backend.clone();
let mut task_manager = params.task_manager;
let (relay_chain_interface, collator_key) = build_relay_chain_interface(
polkadot_config,
&parachain_config,
telemetry_worker_handle,
&mut task_manager,
collator_options.clone(),
hwbench.clone(),
)
.await
.map_err(|e| sc_service::Error::Application(Box::new(e) as Box<_>))?;
let validator = parachain_config.role.is_authority();
let prometheus_registry = parachain_config.prometheus_registry().cloned();
let transaction_pool = params.transaction_pool.clone();
let import_queue_service = params.import_queue.service();
let (network, system_rpc_tx, tx_handler_controller, start_network, sync_service) =
build_network(BuildNetworkParams {
parachain_config: &parachain_config,
net_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
para_id,
spawn_handle: task_manager.spawn_handle(),
relay_chain_interface: relay_chain_interface.clone(),
import_queue: params.import_queue,
sybil_resistance_level: CollatorSybilResistance::Resistant, // because of Aura
})
.await?;
if parachain_config.offchain_worker.enabled {
use futures::FutureExt;
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-work",
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
runtime_api_provider: client.clone(),
keystore: Some(params.keystore_container.keystore()),
offchain_db: backend.offchain_storage(),
transaction_pool: Some(OffchainTransactionPoolFactory::new(
transaction_pool.clone(),
)),
network_provider: network.clone(),
is_validator: parachain_config.role.is_authority(),
enable_http_requests: false,
custom_extensions: move |_| vec![],
})
.run(client.clone(), task_manager.spawn_handle())
.boxed(),
);
}
let rpc_builder = {
let client = client.clone();
let transaction_pool = transaction_pool.clone();
Box::new(move |deny_unsafe, _| {
let deps = crate::rpc::FullDeps {
client: client.clone(),
pool: transaction_pool.clone(),
deny_unsafe,
};
crate::rpc::create_full(deps).map_err(Into::into)
})
};
sc_service::spawn_tasks(sc_service::SpawnTasksParams {
rpc_builder,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
task_manager: &mut task_manager,
config: parachain_config,
keystore: params.keystore_container.keystore(),
#[cfg(not(feature = "async-backing"))]
backend,
#[cfg(feature = "async-backing")]
backend: backend.clone(),
network: network.clone(),
sync_service: sync_service.clone(),
system_rpc_tx,
tx_handler_controller,
telemetry: telemetry.as_mut(),
})?;
if let Some(hwbench) = hwbench {
sc_sysinfo::print_hwbench(&hwbench);
// Here you can check whether the hardware meets your chains' requirements.
// Putting a link in there and swapping out the requirements for your
// own are probably a good idea. The requirements for a para-chain are
// dictated by its relay-chain.
match SUBSTRATE_REFERENCE_HARDWARE.check_hardware(&hwbench) {
Err(err) if validator => {
log::warn!(
"⚠️ The hardware does not meet the minimal requirements {} for role \
'Authority'.",
err
);
}
_ => {}
}
if let Some(ref mut telemetry) = telemetry {
let telemetry_handle = telemetry.handle();
task_manager.spawn_handle().spawn(
"telemetry_hwbench",
None,
sc_sysinfo::initialize_hwbench_telemetry(telemetry_handle, hwbench),
);
}
}
let announce_block = {
let sync_service = sync_service.clone();
Arc::new(move |hash, data| sync_service.announce_block(hash, data))
};
let relay_chain_slot_duration = Duration::from_secs(6);
let overseer_handle = relay_chain_interface
.overseer_handle()
.map_err(|e| sc_service::Error::Application(Box::new(e)))?;
start_relay_chain_tasks(StartRelayChainTasksParams {
client: client.clone(),
announce_block: announce_block.clone(),
para_id,
relay_chain_interface: relay_chain_interface.clone(),
task_manager: &mut task_manager,
da_recovery_profile: if validator {
DARecoveryProfile::Collator
} else {
DARecoveryProfile::FullNode
},
import_queue: import_queue_service,
relay_chain_slot_duration,
recovery_handle: Box::new(overseer_handle.clone()),
sync_service: sync_service.clone(),
})?;
if validator {
start_consensus(
client.clone(),
#[cfg(feature = "async-backing")]
backend.clone(),
block_import,
prometheus_registry.as_ref(),
telemetry.as_ref().map(|t| t.handle()),
&task_manager,
relay_chain_interface.clone(),
transaction_pool,
sync_service.clone(),
params.keystore_container.keystore(),
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
overseer_handle,
announce_block,
)?;
}
start_network.start_network();
Ok((task_manager, client))
}
/// Build the import queue for the parachain runtime.
fn build_import_queue(
client: Arc<ParachainClient>,
block_import: ParachainBlockImport,
config: &Configuration,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
) -> Result<sc_consensus::DefaultImportQueue<Block>, sc_service::Error> {
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
Ok(cumulus_client_consensus_aura::equivocation_import_queue::fully_verifying_import_queue::<
sp_consensus_aura::sr25519::AuthorityPair,
_,
_,
_,
_,
>(
client,
block_import,
move |_, _| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
Ok(timestamp)
},
slot_duration,
&task_manager.spawn_essential_handle(),
config.prometheus_registry(),
telemetry,
))
}
fn start_consensus(
client: Arc<ParachainClient>,
#[cfg(feature = "async-backing")] backend: Arc<ParachainBackend>,
block_import: ParachainBlockImport,
prometheus_registry: Option<&Registry>,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
relay_chain_interface: Arc<dyn RelayChainInterface>,
transaction_pool: Arc<sc_transaction_pool::FullPool<Block, ParachainClient>>,
sync_oracle: Arc<SyncingService<Block>>,
keystore: KeystorePtr,
relay_chain_slot_duration: Duration,
para_id: ParaId,
collator_key: CollatorPair,
overseer_handle: OverseerHandle,
announce_block: Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error> {
#[cfg(not(feature = "async-backing"))]
use cumulus_client_consensus_aura::collators::basic::{self as basic_aura, Params};
#[cfg(feature = "async-backing")]
use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params};
// NOTE: because we use Aura here explicitly, we can use
// `CollatorSybilResistance::Resistant` when starting the network.
let slot_duration = cumulus_client_consensus_aura::slot_duration(&*client)?;
let proposer_factory = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry,
telemetry.clone(),
);
let proposer = Proposer::new(proposer_factory);
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let params = Params {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
#[cfg(not(feature = "async-backing"))]
para_client: client,
#[cfg(feature = "async-backing")]
para_client: client.clone(),
#[cfg(feature = "async-backing")]
para_backend: backend,
relay_client: relay_chain_interface,
#[cfg(feature = "async-backing")]
code_hash_provider: move |block_hash| {
client.code_at(block_hash).ok().map(ValidationCode).map(|c| c.hash())
},
sync_oracle,
keystore,
collator_key,
para_id,
overseer_handle,
slot_duration,
relay_chain_slot_duration,
proposer,
collator_service,
// Very limited proposal time.
#[cfg(not(feature = "async-backing"))]
authoring_duration: Duration::from_millis(500),
#[cfg(feature = "async-backing")]
authoring_duration: Duration::from_millis(1500),
#[cfg(not(feature = "async-backing"))]
collation_request_receiver: None,
#[cfg(feature = "async-backing")]
reinitialize: false,
};
#[cfg(not(feature = "async-backing"))]
let fut =
basic_aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _>(
params,
);
#[cfg(feature = "async-backing")]
let fut =
aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
params,
);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(())
}
/// Start a parachain node.
pub async fn start_parachain_node(
parachain_config: Configuration,
polkadot_config: Configuration,
collator_options: CollatorOptions,
para_id: ParaId,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<ParachainClient>)> {
start_node_impl(parachain_config, polkadot_config, collator_options, para_id, hwbench).await
}