feat: initialize Kurdistan SDK - independent fork of Polkadot SDK

This commit is contained in:
2025-12-13 15:44:15 +03:00
commit e4778b4576
6838 changed files with 1847450 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
target/
Dockerfile
.dockerignore
+28
View File
@@ -0,0 +1,28 @@
FROM docker.io/paritytech/ci-unified:latest as builder
WORKDIR /polkadot
COPY . /polkadot
RUN cargo fetch
RUN cargo build --workspace --locked --release
FROM docker.io/parity/base-bin:latest
COPY --from=builder /polkadot/target/release/minimal-template-node /usr/local/bin
USER root
RUN useradd -m -u 1001 -U -s /bin/sh -d /polkadot polkadot && \
mkdir -p /data /polkadot/.local/share && \
chown -R polkadot:polkadot /data && \
ln -s /data /polkadot/.local/share/polkadot && \
# unclutter and minimize the attack surface
rm -rf /usr/bin /usr/sbin && \
# check if executable works in this container
/usr/local/bin/minimal-template-node --version
USER polkadot
EXPOSE 30333 9933 9944 9615
VOLUME ["/data"]
ENTRYPOINT ["/usr/local/bin/minimal-template-node"]
+24
View File
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
+149
View File
@@ -0,0 +1,149 @@
<div align="center">
# Pezkuwi SDK's Minimal Template
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/PezkuwiChain_Logo_Horizontal_Pink_White.png#gh-dark-mode-only"/>
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/PezkuwiChain_Logo_Horizontal_Pink_Black.png#gh-light-mode-only"/>
> This is a minimal template for creating a blockchain based on Pezkuwi SDK.
>
> This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
</div>
## Table of Contents
- [Intro](#intro)
- [Template Structure](#template-structure)
- [Getting Started](#getting-started)
- [Starting a Minimal Template Chain](#starting-a-minimal-template-chain)
- [Minimal Template Node](#minimal-template-node)
- [Zombienet with Minimal Template Node](#zombienet-with-minimal-template-node)
- [Connect with the PezkuwiChain-JS Apps Front-End](#connect-with-the-pezkuwi-js-apps-front-end)
- [Takeaways](#takeaways)
- [Contributing](#contributing)
- [Getting Help](#getting-help)
## Intro
- 🤏 This template is a minimal (in terms of complexity and the number of components)
template for building a blockchain node.
- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
such as a [Balances pallet](https://docs.pezkuwichain.io/sdk/master/pallet_balances/index.html).
- 👤 The template has no consensus configured - it is best for experimenting with a single node network.
## Template Structure
A Pezkuwi SDK based project such as this one consists of:
- 🧮 the [Runtime](./runtime/README.md) - the core logic of the blockchain.
- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
- 💿 a [Node](./node/README.md) - the binary application (which is not part of the cargo default-members list and is not
compiled unless building the entire workspace).
## Getting Started
- 🦀 The template is using the Rust language.
- 👉 Check the
[Rust installation instructions](https://www.rust-lang.org/tools/install) for your system.
- 🛠️ Depending on your operating system and Rust version, there might be additional
packages required to compile this template - please take note of the Rust compiler output.
Fetch minimal template code.
```sh
git clone https://github.com/pezkuwichain/pezkuwi-sdk/issues/25.git minimal-template
cd minimal-template
```
## Starting a Minimal Template Chain
### Minimal Template Node
#### Build both node & runtime
```sh
cargo build --workspace --release
```
🐳 Alternatively, build the docker image which builds all the workspace members,
and has as entry point the node binary:
```sh
docker build . -t pezkuwi-sdk-minimal-template
```
#### Start the `minimal-template-node`
The `minimal-template-node` has dependency on the `minimal-template-runtime`. It will use
the `minimal_template_runtime::WASM_BINARY` constant (which holds the WASM blob as a byte
array) for chain spec building, while starting.
```sh
<target/release/path/to/minimal-template-node> --tmp --consensus manual-seal-3000
# or via docker
docker run --rm pezkuwi-sdk-minimal-template
```
#### Zombienet with `minimal-template-node`
For this one we just need to have `zombienet` installed and run:
```sh
zombienet --provider native spawn zombienet-multi-node.toml
```
### Connect with the PezkuwiChain-JS Apps Front-End
- 🌐 You can interact with your local node using the
hosted version of the [PezkuwiChain/Substrate
Portal](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9944).
- 🪐 A hosted version is also
available on [IPFS](https://dotapps.io/).
- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
[`pezkuwi-js/apps`](https://github.com/polkadot-js/apps) repository.
### Takeaways
Previously minimal template's development chains:
- ❌ Started in a multi-node setup will produce forks because minimal lacks consensus.
- 🧹 Do not persist the state.
- 💰 Are pre-configured with a genesis state that includes several pre-funded development accounts.
- 🧑‍⚖️ One development account (`ALICE`) is used as `sudo` accounts.
## Contributing
- 🔄 This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
- ➡️ Any pull requests should be directed to this [source](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/minimal).
- 😇 Please refer to the monorepo's
[contribution guidelines](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and
[Code of Conduct](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
## Getting Help
- 🧑‍🏫 To learn about PezkuwiChain in general, [docs.PezkuwiChain.com](https://docs.pezkuwichain.app/) website is a good starting point.
- 🧑‍🔧 For technical introduction, [here](https://github.com/pezkuwichain/pezkuwi-sdk#-documentation) are
the Pezkuwi SDK documentation resources.
- 👥 Additionally, there are [GitHub issues](https://github.com/pezkuwichain/pezkuwi-sdk/issues) and
[Substrate StackExchange](https://pezkuwichain.app/community/).
- 👥You can also reach out on the [Official PezkuwiChain discord server](https://polkadot-discord.w3f.tools/)
- 🧑Reach out on [Telegram](https://t.me/substratedevs) for more questions and discussions
File diff suppressed because one or more lines are too long
+38
View File
@@ -0,0 +1,38 @@
[package]
name = "minimal-template-node"
description = "A minimal Substrate-based Substrate node, ready for hacking."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
build = "build.rs"
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
clap = { features = ["derive"], workspace = true }
docify = { workspace = true }
futures = { features = ["thread-pool"], workspace = true }
futures-timer = { workspace = true }
jsonrpsee = { features = ["server"], workspace = true }
minimal-template-runtime = { workspace = true }
pezkuwi-sdk = { workspace = true, features = ["experimental", "node"] }
[build-dependencies]
pezkuwi-sdk = { workspace = true, features = ["substrate-build-script-utils"] }
[features]
default = ["std"]
std = ["minimal-template-runtime/std", "pezkuwi-sdk/std"]
runtime-benchmarks = [
"minimal-template-runtime/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
]
+18
View File
@@ -0,0 +1,18 @@
# Node
️ A node - in PezkuwiChain - is a binary executable, whose primary purpose is to execute the [runtime](../runtime/README.md).
🔗 It communicates with other nodes in the network, and aims for
[consensus](https://docs.pezkuwichain.app/polkadot-protocol/architecture/polkadot-chain/pos-consensus/) among them.
⚙️ It acts as a remote procedure call (RPC) server, allowing interaction with the blockchain.
👉 Learn more about the architecture, and a difference between a node and a runtime
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/wasm_meta_protocol/index.html).
👇 Here are the most important files in this node template:
- [`chain_spec.rs`](./src/chain_spec.rs): A chain specification is a source code file that defines the chain's
initial (genesis) state.
- [`service.rs`](./src/service.rs): This file defines the node implementation.
It's a place to configure consensus-related topics. In favor of minimalism, this template has no consensus configured.
+23
View File
@@ -0,0 +1,23 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use pezkuwi_sdk::substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
fn main() {
generate_cargo_keys();
rerun_if_git_head_changed();
}
+42
View File
@@ -0,0 +1,42 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use minimal_template_runtime::WASM_BINARY;
use pezkuwi_sdk::{
sc_service::{ChainType, Properties},
*,
};
/// This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec;
fn props() -> Properties {
let mut properties = Properties::new();
properties.insert("tokenDecimals".to_string(), 0.into());
properties.insert("tokenSymbol".to_string(), "MINI".into());
properties
}
pub fn development_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(WASM_BINARY.expect("Development wasm not available"), Default::default())
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
.with_properties(props())
.build())
}
+92
View File
@@ -0,0 +1,92 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use pezkuwi_sdk::*;
#[derive(Debug, Clone)]
pub enum Consensus {
ManualSeal(u64),
InstantSeal,
None,
}
impl std::str::FromStr for Consensus {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(if s == "instant-seal" {
Consensus::InstantSeal
} else if let Some(block_time) = s.strip_prefix("manual-seal-") {
Consensus::ManualSeal(block_time.parse().map_err(|_| "invalid block time")?)
} else if s.to_lowercase() == "none" {
Consensus::None
} else {
return Err("incorrect consensus identifier".into());
})
}
}
#[derive(Debug, clap::Parser)]
pub struct Cli {
#[command(subcommand)]
pub subcommand: Option<Subcommand>,
#[clap(long, default_value = "manual-seal-3000")]
pub consensus: Consensus,
#[clap(flatten)]
pub run: sc_cli::RunCmd,
}
#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
/// Key management cli utilities
#[command(subcommand)]
Key(sc_cli::KeySubcommand),
/// Build a chain specification.
/// DEPRECATED: `build-spec` command will be removed after 1/04/2026. Use `export-chain-spec`
/// command instead.
#[deprecated(
note = "build-spec command will be removed after 1/04/2026. Use export-chain-spec command instead"
)]
BuildSpec(sc_cli::BuildSpecCmd),
/// Export the chain specification.
ExportChainSpec(sc_cli::ExportChainSpecCmd),
/// 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),
/// Remove the whole chain.
PurgeChain(sc_cli::PurgeChainCmd),
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),
/// Db meta columns information.
ChainInfo(sc_cli::ChainInfoCmd),
}
+137
View File
@@ -0,0 +1,137 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{
chain_spec,
cli::{Cli, Subcommand},
service,
};
use pezkuwi_sdk::{sc_cli::SubstrateCli, sc_service::PartialComponents, *};
impl SubstrateCli for Cli {
fn impl_name() -> String {
"Substrate Node".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
env!("CARGO_PKG_DESCRIPTION").into()
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"support.anonymous.an".into()
}
fn copyright_start_year() -> i32 {
2017
}
fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_chain_spec()?),
path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
}
/// Parse and run command line arguments
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
match &cli.subcommand {
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
#[allow(deprecated)]
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)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::ExportChainSpec(cmd)) => {
let chain_spec = cli.load_spec(&cmd.chain)?;
cmd.run(chain_spec)
},
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
Ok((cmd.run(client, config.database), task_manager))
})
},
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
Ok((cmd.run(client, config.chain_spec), task_manager))
})
},
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.database))
},
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, backend, .. } =
service::new_partial(&config)?;
Ok((cmd.run(client, backend, None), task_manager))
})
},
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
cmd.run::<minimal_template_runtime::interface::OpaqueBlock>(&config)
})
},
None => {
let runner = cli.create_runner(&cli.run)?;
runner.run_node_until_exit(|config| async move {
match config.network.network_backend {
sc_network::config::NetworkBackendType::Libp2p =>
service::new_full::<sc_network::NetworkWorker<_, _>>(config, cli.consensus)
.map_err(sc_cli::Error::Service),
sc_network::config::NetworkBackendType::Litep2p => service::new_full::<
sc_network::Litep2pNetworkBackend,
>(config, cli.consensus)
.map_err(sc_cli::Error::Service),
}
})
},
}
}
+21
View File
@@ -0,0 +1,21 @@
// This file is part of Pezkuwi Sdk.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod chain_spec;
pub(crate) mod cli;
pub mod rpc;
pub mod service;
+29
View File
@@ -0,0 +1,29 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Substrate Node Template CLI library.
#![warn(missing_docs)]
mod chain_spec;
mod cli;
mod command;
mod rpc;
mod service;
fn main() -> pezkuwi_sdk::sc_cli::Result<()> {
command::run()
}
+66
View File
@@ -0,0 +1,66 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! 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 jsonrpsee::RpcModule;
use minimal_template_runtime::interface::{AccountId, Nonce, OpaqueBlock};
use pezkuwi_sdk::{
sc_transaction_pool_api::TransactionPool,
sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata},
*,
};
use std::sync::Arc;
/// Full client dependencies.
pub struct FullDeps<C, P> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
}
#[docify::export]
/// Instantiate all full RPC extensions.
pub fn create_full<C, P>(
deps: FullDeps<C, P>,
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
where
C: Send
+ Sync
+ 'static
+ sp_api::ProvideRuntimeApi<OpaqueBlock>
+ HeaderBackend<OpaqueBlock>
+ HeaderMetadata<OpaqueBlock, Error = BlockChainError>
+ 'static,
C::Api: sp_block_builder::BlockBuilder<OpaqueBlock>,
C::Api: substrate_frame_rpc_system::AccountNonceApi<OpaqueBlock, AccountId, Nonce>,
P: TransactionPool + 'static,
{
use pezkuwi_sdk::substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcModule::new(());
let FullDeps { client, pool } = deps;
module.merge(System::new(client.clone(), pool.clone()).into_rpc())?;
Ok(module)
}
+269
View File
@@ -0,0 +1,269 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::cli::Consensus;
use futures::FutureExt;
use minimal_template_runtime::{interface::OpaqueBlock as Block, RuntimeApi};
use pezkuwi_sdk::{
sc_client_api::backend::Backend,
sc_executor::WasmExecutor,
sc_service::{error::Error as ServiceError, Configuration, TaskManager},
sc_telemetry::{Telemetry, TelemetryWorker},
sc_transaction_pool_api::OffchainTransactionPoolFactory,
sp_runtime::traits::Block as BlockT,
*,
};
use std::sync::Arc;
type HostFunctions = sp_io::SubstrateHostFunctions;
#[docify::export]
pub(crate) type FullClient =
sc_service::TFullClient<Block, RuntimeApi, WasmExecutor<HostFunctions>>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
/// Assembly of PartialComponents (enough to run chain ops subcommands)
pub type Service = sc_service::PartialComponents<
FullClient,
FullBackend,
FullSelectChain,
sc_consensus::DefaultImportQueue<Block>,
sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
Option<Telemetry>,
>;
pub fn new_partial(config: &Configuration) -> Result<Service, ServiceError> {
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 executor = sc_service::new_wasm_executor(&config.executor);
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 = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
let select_chain = sc_consensus::LongestChain::new(backend.clone());
let transaction_pool = Arc::from(
sc_transaction_pool::Builder::new(
task_manager.spawn_essential_handle(),
client.clone(),
config.role.is_authority().into(),
)
.with_options(config.transaction_pool.clone())
.with_prometheus(config.prometheus_registry())
.build(),
);
let import_queue = sc_consensus_manual_seal::import_queue(
Box::new(client.clone()),
&task_manager.spawn_essential_handle(),
config.prometheus_registry(),
);
Ok(sc_service::PartialComponents {
client,
backend,
task_manager,
import_queue,
keystore_container,
select_chain,
transaction_pool,
other: (telemetry),
})
}
/// Builds a new service for a full client.
pub fn new_full<Network: sc_network::NetworkBackend<Block, <Block as BlockT>::Hash>>(
config: Configuration,
consensus: Consensus,
) -> Result<TaskManager, ServiceError> {
let sc_service::PartialComponents {
client,
backend,
mut task_manager,
import_queue,
keystore_container,
select_chain,
transaction_pool,
other: mut telemetry,
} = new_partial(&config)?;
let net_config = sc_network::config::FullNetworkConfiguration::<
Block,
<Block as BlockT>::Hash,
Network,
>::new(
&config.network,
config.prometheus_config.as_ref().map(|cfg| cfg.registry.clone()),
);
let metrics = Network::register_notification_metrics(
config.prometheus_config.as_ref().map(|cfg| &cfg.registry),
);
let (network, system_rpc_tx, tx_handler_controller, sync_service) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
net_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
block_announce_validator_builder: None,
warp_sync_config: None,
block_relay: None,
metrics,
})?;
if config.offchain_worker.enabled {
let offchain_workers =
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
runtime_api_provider: client.clone(),
is_validator: config.role.is_authority(),
keystore: Some(keystore_container.keystore()),
offchain_db: backend.offchain_storage(),
transaction_pool: Some(OffchainTransactionPoolFactory::new(
transaction_pool.clone(),
)),
network_provider: Arc::new(network.clone()),
enable_http_requests: true,
custom_extensions: |_| vec![],
})?;
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-worker",
offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
);
}
let rpc_extensions_builder = {
let client = client.clone();
let pool = transaction_pool.clone();
Box::new(move |_| {
let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() };
crate::rpc::create_full(deps).map_err(Into::into)
})
};
let prometheus_registry = config.prometheus_registry().cloned();
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
network,
client: client.clone(),
keystore: keystore_container.keystore(),
task_manager: &mut task_manager,
transaction_pool: transaction_pool.clone(),
rpc_builder: rpc_extensions_builder,
backend,
system_rpc_tx,
tx_handler_controller,
sync_service,
config,
telemetry: telemetry.as_mut(),
tracing_execute_block: None,
})?;
let proposer = sc_basic_authorship::ProposerFactory::new(
task_manager.spawn_handle(),
client.clone(),
transaction_pool.clone(),
prometheus_registry.as_ref(),
telemetry.as_ref().map(|x| x.handle()),
);
match consensus {
Consensus::InstantSeal => {
let params = sc_consensus_manual_seal::InstantSealParams {
block_import: client.clone(),
env: proposer,
client,
pool: transaction_pool,
select_chain,
consensus_data_provider: None,
create_inherent_data_providers: move |_, ()| async move {
Ok(sp_timestamp::InherentDataProvider::from_system_time())
},
};
let authorship_future = sc_consensus_manual_seal::run_instant_seal(params);
task_manager.spawn_essential_handle().spawn_blocking(
"instant-seal",
None,
authorship_future,
);
},
Consensus::ManualSeal(block_time) => {
let (mut sink, commands_stream) = futures::channel::mpsc::channel(1024);
task_manager.spawn_handle().spawn("block_authoring", None, async move {
loop {
futures_timer::Delay::new(std::time::Duration::from_millis(block_time)).await;
sink.try_send(sc_consensus_manual_seal::EngineCommand::SealNewBlock {
create_empty: true,
finalize: true,
parent_hash: None,
sender: None,
})
.unwrap();
}
});
let params = sc_consensus_manual_seal::ManualSealParams {
block_import: client.clone(),
env: proposer,
client,
pool: transaction_pool,
select_chain,
commands_stream: Box::pin(commands_stream),
consensus_data_provider: None,
create_inherent_data_providers: move |_, ()| async move {
Ok(sp_timestamp::InherentDataProvider::from_system_time())
},
};
let authorship_future = sc_consensus_manual_seal::run_manual_seal(params);
task_manager.spawn_essential_handle().spawn_blocking(
"manual-seal",
None,
authorship_future,
);
},
_ => {},
}
Ok(task_manager)
}
+13
View File
@@ -0,0 +1,13 @@
# Pallets
️ A pallet is a unit of encapsulated logic, with a clearly defined responsibility. A pallet is analogous to a
module in the runtime.
💁 In this template, there is a simple custom pallet based on the FRAME framework.
👉 Learn more about FRAME
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
🧑‍🏫 Please refer to
[this guide](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html)
to learn how to write a basic pallet.
@@ -0,0 +1,29 @@
[package]
name = "pallet-minimal-template"
description = "A minimal pallet built with FRAME, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { features = ["derive"], workspace = true }
pezkuwi-sdk = { workspace = true, default-features = false, features = [
"experimental",
"runtime",
] }
scale-info = { features = ["derive"], workspace = true }
[features]
default = ["std"]
std = ["codec/std", "pezkuwi-sdk/std", "scale-info/std"]
runtime-benchmarks = ["pezkuwi-sdk/runtime-benchmarks"]
@@ -0,0 +1,26 @@
//! A shell pallet built with [`frame`].
//!
//! To get started with this pallet, try implementing the guide in
//! <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html>
#![cfg_attr(not(feature = "std"), no_std)]
use frame::prelude::*;
use pezkuwi_sdk::pezkuwi_sdk_frame as frame;
// Re-export all pallet parts, this is needed to properly import the pallet into the runtime.
pub use pallet::*;
#[frame::pallet]
pub mod pallet {
use super::*;
#[pallet::config]
pub trait Config: pezkuwi_sdk::frame_system::Config {}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::storage]
pub type Value<T> = StorageValue<Value = u32>;
}
+50
View File
@@ -0,0 +1,50 @@
[package]
name = "minimal-template-runtime"
description = "A solochain runtime template built with Substrate, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[lints]
workspace = true
[dependencies]
codec = { workspace = true }
pezkuwi-sdk = { workspace = true, features = [
"pallet-balances",
"pallet-sudo",
"pallet-timestamp",
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"runtime",
] }
scale-info = { workspace = true }
serde_json = { workspace = true, default-features = false, features = [
"alloc",
] }
# local pallet templates
pallet-minimal-template = { workspace = true }
[build-dependencies]
pezkuwi-sdk = { optional = true, workspace = true, features = [
"substrate-wasm-builder",
] }
[features]
default = ["std"]
std = [
"codec/std",
"pallet-minimal-template/std",
"pezkuwi-sdk/std",
"scale-info/std",
"serde_json/std",
]
runtime-benchmarks = [
"pallet-minimal-template/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
]
+10
View File
@@ -0,0 +1,10 @@
# Runtime
️ The runtime (in other words, a state transition function), refers to the core logic of the blockchain that is
responsible for validating blocks and executing the state changes they define.
💁 The runtime in this template is constructed using ready-made FRAME pallets that ship with
[Pezkuwi SDK](https://github.com/pezkuwichain/pezkuwi-sdk), and a [template for a custom pallet](../pallets/README.md).
👉 Learn more about FRAME
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
+23
View File
@@ -0,0 +1,23 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
fn main() {
#[cfg(feature = "std")]
{
pezkuwi_sdk::substrate_wasm_builder::WasmBuilder::build_using_defaults();
}
}
+351
View File
@@ -0,0 +1,351 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! A minimal runtime that includes the template [`pallet`](`pallet_minimal_template`).
#![cfg_attr(not(feature = "std"), no_std)]
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
extern crate alloc;
use alloc::vec::Vec;
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use pezkuwi_sdk::{
pezkuwi_sdk_frame::{
self as frame,
deps::sp_genesis_builder,
runtime::{apis, prelude::*},
},
*,
};
/// Provides getters for genesis configuration presets.
pub mod genesis_config_presets {
use super::*;
use crate::{
interface::{Balance, MinimumBalance},
sp_keyring::Sr25519Keyring,
BalancesConfig, RuntimeGenesisConfig, SudoConfig,
};
use alloc::{vec, vec::Vec};
use serde_json::Value;
/// Returns a development genesis config preset.
pub fn development_config_genesis() -> Value {
let endowment = <MinimumBalance as Get<Balance>>::get().max(1) * 1000;
frame_support::build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: Sr25519Keyring::iter()
.map(|a| (a.to_account_id(), endowment))
.collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(Sr25519Keyring::Alice.to_account_id()) },
})
}
/// Get the set of the available genesis config presets.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
let patch = match id.as_ref() {
sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET)]
}
}
/// The runtime version.
#[runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"),
impl_name: alloc::borrow::Cow::Borrowed("minimal-template-runtime"),
authoring_version: 1,
spec_version: 0,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,
system_version: 1,
};
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
/// The transaction extensions that are added to the runtime.
type TxExtension = (
// Authorize calls that validate themselves.
frame_system::AuthorizeCall<Runtime>,
// Checks that the sender is not the zero address.
frame_system::CheckNonZeroSender<Runtime>,
// Checks that the runtime version is correct.
frame_system::CheckSpecVersion<Runtime>,
// Checks that the transaction version is correct.
frame_system::CheckTxVersion<Runtime>,
// Checks that the genesis hash is correct.
frame_system::CheckGenesis<Runtime>,
// Checks that the era is valid.
frame_system::CheckEra<Runtime>,
// Checks that the nonce is valid.
frame_system::CheckNonce<Runtime>,
// Checks that the weight is valid.
frame_system::CheckWeight<Runtime>,
// Ensures that the sender has enough funds to pay for the transaction
// and deducts the fee from the sender's account.
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
// Reclaim the unused weight from the block using post dispatch information.
// It must be last in the pipeline in order to catch the refund in previous transaction
// extensions
frame_system::WeightReclaim<Runtime>,
);
// Composes the runtime by adding all the used pallets and deriving necessary types.
#[frame_construct_runtime]
mod runtime {
/// The main runtime type.
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
/// Mandatory system pallet that should always be included in a FRAME runtime.
#[runtime::pallet_index(0)]
pub type System = frame_system::Pallet<Runtime>;
/// Provides a way for consensus systems to set and check the onchain time.
#[runtime::pallet_index(1)]
pub type Timestamp = pallet_timestamp::Pallet<Runtime>;
/// Provides the ability to keep track of balances.
#[runtime::pallet_index(2)]
pub type Balances = pallet_balances::Pallet<Runtime>;
/// Provides a way to execute privileged functions.
#[runtime::pallet_index(3)]
pub type Sudo = pallet_sudo::Pallet<Runtime>;
/// Provides the ability to charge for extrinsic execution.
#[runtime::pallet_index(4)]
pub type TransactionPayment = pallet_transaction_payment::Pallet<Runtime>;
/// A minimal pallet template.
#[runtime::pallet_index(5)]
pub type Template = pallet_minimal_template::Pallet<Runtime>;
}
parameter_types! {
pub const Version: RuntimeVersion = VERSION;
}
/// Implements the types required for the system pallet.
#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
impl frame_system::Config for Runtime {
type Block = Block;
type Version = Version;
// Use the account data from the balances pallet
type AccountData = pallet_balances::AccountData<<Runtime as pallet_balances::Config>::Balance>;
}
// Implements the types required for the balances pallet.
#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
impl pallet_balances::Config for Runtime {
type AccountStore = System;
}
// Implements the types required for the sudo pallet.
#[derive_impl(pallet_sudo::config_preludes::TestDefaultConfig)]
impl pallet_sudo::Config for Runtime {}
// Implements the types required for the sudo pallet.
#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
impl pallet_timestamp::Config for Runtime {}
// Implements the types required for the transaction payment pallet.
#[derive_impl(pallet_transaction_payment::config_preludes::TestDefaultConfig)]
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter<Balances, ()>;
// Setting fee as independent of the weight of the extrinsic for demo purposes
type WeightToFee = NoFee<<Self as pallet_balances::Config>::Balance>;
// Setting fee as fixed for any length of the call data for demo purposes
type LengthToFee = FixedFee<1, <Self as pallet_balances::Config>::Balance>;
}
// Implements the types required for the template pallet.
impl pallet_minimal_template::Config for Runtime {}
type Block = frame::runtime::types_common::BlockOf<Runtime, TxExtension>;
type Header = HeaderFor<Runtime>;
type RuntimeExecutive =
Executive<Runtime, Block, frame_system::ChainContext<Runtime>, Runtime, AllPalletsWithSystem>;
impl_runtime_apis! {
impl apis::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn execute_block(block: <Block as frame::traits::Block>::LazyBlock) {
RuntimeExecutive::execute_block(block)
}
fn initialize_block(header: &Header) -> ExtrinsicInclusionMode {
RuntimeExecutive::initialize_block(header)
}
}
impl apis::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
OpaqueMetadata::new(Runtime::metadata().into())
}
fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
Runtime::metadata_at_version(version)
}
fn metadata_versions() -> Vec<u32> {
Runtime::metadata_versions()
}
}
impl apis::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(extrinsic: ExtrinsicFor<Runtime>) -> ApplyExtrinsicResult {
RuntimeExecutive::apply_extrinsic(extrinsic)
}
fn finalize_block() -> HeaderFor<Runtime> {
RuntimeExecutive::finalize_block()
}
fn inherent_extrinsics(data: InherentData) -> Vec<ExtrinsicFor<Runtime>> {
data.create_extrinsics()
}
fn check_inherents(
block: <Block as frame::traits::Block>::LazyBlock,
data: InherentData,
) -> CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl apis::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
tx: ExtrinsicFor<Runtime>,
block_hash: <Runtime as frame_system::Config>::Hash,
) -> TransactionValidity {
RuntimeExecutive::validate_transaction(source, tx, block_hash)
}
}
impl apis::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &HeaderFor<Runtime>) {
RuntimeExecutive::offchain_worker(header)
}
}
impl apis::SessionKeys<Block> for Runtime {
fn generate_session_keys(_seed: Option<Vec<u8>>) -> Vec<u8> {
Default::default()
}
fn decode_session_keys(
_encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, apis::KeyTypeId)>> {
Default::default()
}
}
impl apis::AccountNonceApi<Block, interface::AccountId, interface::Nonce> for Runtime {
fn account_nonce(account: interface::AccountId) -> interface::Nonce {
System::account_nonce(account)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<
Block,
interface::Balance,
> for Runtime {
fn query_info(uxt: ExtrinsicFor<Runtime>, len: u32) -> RuntimeDispatchInfo<interface::Balance> {
TransactionPayment::query_info(uxt, len)
}
fn query_fee_details(uxt: ExtrinsicFor<Runtime>, len: u32) -> FeeDetails<interface::Balance> {
TransactionPayment::query_fee_details(uxt, len)
}
fn query_weight_to_fee(weight: Weight) -> interface::Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> interface::Balance {
TransactionPayment::length_to_fee(length)
}
}
impl apis::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
build_state::<RuntimeGenesisConfig>(config)
}
fn get_preset(id: &Option<PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, self::genesis_config_presets::get_preset)
}
fn preset_names() -> Vec<PresetId> {
self::genesis_config_presets::preset_names()
}
}
}
/// Some re-exports that the node side code needs to know. Some are useful in this context as well.
///
/// Other types should preferably be private.
// TODO: this should be standardized in some way, see:
// https://github.com/paritytech/substrate/issues/10579#issuecomment-1600537558
pub mod interface {
use super::Runtime;
use pezkuwi_sdk::{pezkuwi_sdk_frame as frame, *};
pub type Block = super::Block;
pub use frame::runtime::types_common::OpaqueBlock;
pub type AccountId = <Runtime as frame_system::Config>::AccountId;
pub type Nonce = <Runtime as frame_system::Config>::Nonce;
pub type Hash = <Runtime as frame_system::Config>::Hash;
pub type Balance = <Runtime as pallet_balances::Config>::Balance;
pub type MinimumBalance = <Runtime as pallet_balances::Config>::ExistentialDeposit;
}
+30
View File
@@ -0,0 +1,30 @@
# The setup bellow allows only one node to produce
# blocks and the rest will follow.
[relaychain]
chain = "dev"
default_command = "minimal-template-node"
[[relaychain.nodes]]
name = "alice"
args = ["--consensus manual-seal-3000"]
validator = true
ws_port = 9944
[[relaychain.nodes]]
name = "bob"
args = ["--consensus None"]
validator = true
ws_port = 9955
[[relaychain.nodes]]
name = "charlie"
args = ["--consensus None"]
validator = true
ws_port = 9966
[[relaychain.nodes]]
name = "dave"
args = ["--consensus None"]
validator = true
ws_port = 9977
+3
View File
@@ -0,0 +1,3 @@
target/
Dockerfile
.dockerignore
+28
View File
@@ -0,0 +1,28 @@
FROM docker.io/paritytech/ci-unified:latest as builder
WORKDIR /polkadot
COPY . /polkadot
RUN cargo fetch
RUN cargo build --locked --release
FROM docker.io/parity/base-bin:latest
COPY --from=builder /polkadot/target/release/solochain-template-node /usr/local/bin
USER root
RUN useradd -m -u 1001 -U -s /bin/sh -d /polkadot polkadot && \
mkdir -p /data /polkadot/.local/share && \
chown -R polkadot:polkadot /data && \
ln -s /data /polkadot/.local/share/polkadot && \
# unclutter and minimize the attack surface
rm -rf /usr/bin /usr/sbin && \
# check if executable works in this container
/usr/local/bin/solochain-template-node --version
USER polkadot
EXPOSE 30333 9933 9944 9615
VOLUME ["/data"]
ENTRYPOINT ["/usr/local/bin/solochain-template-node"]
+24
View File
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
+232
View File
@@ -0,0 +1,232 @@
# Substrate Node Template
A fresh [Substrate](https://substrate.pezkuwichain.app/) node, ready for hacking :rocket:
A standalone version of this template is available for each release of PezkuwiChain
in the [Substrate Developer Hub Teyrchain
Template](https://github.com/substrate-developer-hub/substrate-node-template/)
repository. The teyrchain template is generated directly at each PezkuwiChain
release branch from the [Solochain Template in
Substrate](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/solochain)
upstream
It is usually best to use the stand-alone version to start a new project. All
bugs, suggestions, and feature requests should be made upstream in the
[Substrate](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/substrate)
repository.
## Getting Started
Depending on your operating system and Rust version, there might be additional
packages required to compile this template. Check the
[Install](https://docs.pezkuwichain.io/install/) instructions for your platform for
the most common dependencies. Alternatively, you can use one of the [alternative
installation](#alternatives-installations) options.
Fetch solochain template code:
```sh
git clone https://github.com/pezkuwichain/pezkuwi-sdk/issues/25.git solochain-template
cd solochain-template
```
### Build
🔨 Use the following command to build the node without launching it:
```sh
cargo build --release
```
### Embedded Docs
After you build the project, you can use the following command to explore its
parameters and subcommands:
```sh
./target/release/solochain-template-node -h
```
You can generate and view the [Rust
Docs](https://doc.rust-lang.org/cargo/commands/cargo-doc.html) for this template
with this command:
```sh
cargo +nightly doc --open
```
### Single-Node Development Chain
The following command starts a single-node development chain that doesn't
persist state:
```sh
./target/release/solochain-template-node --dev
```
To purge the development chain's state, run the following command:
```sh
./target/release/solochain-template-node purge-chain --dev
```
To start the development chain with detailed logging, run the following command:
```sh
RUST_BACKTRACE=1 ./target/release/solochain-template-node -ldebug --dev
```
Development chains:
- Maintain state in a `tmp` folder while the node is running.
- Use the **Alice** and **Bob** accounts as default validator authorities.
- Use the **Alice** account as the default `sudo` account.
- Are preconfigured with a genesis state (`/node/src/chain_spec.rs`) that
includes several pre-funded development accounts.
To persist chain state between runs, specify a base path by running a command
similar to the following:
```sh
// Create a folder to use as the db base path
$ mkdir my-chain-state
// Use of that folder to store the chain state
$ ./target/release/solochain-template-node --dev --base-path ./my-chain-state/
// Check the folder structure created inside the base path after running the chain
$ ls ./my-chain-state
chains
$ ls ./my-chain-state/chains/
dev
$ ls ./my-chain-state/chains/dev
db keystore network
```
### Connect with PezkuwiChain-JS Apps Front-End
After you start the node template locally, you can interact with it using the
hosted version of the [PezkuwiChain/Substrate
Portal](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9944)
front-end by connecting to the local node endpoint. A hosted version is also
available on [IPFS](https://dotapps.io/). You can
also find the source code and instructions for hosting your own instance in the
[`pezkuwi-js/apps`](https://github.com/polkadot-js/apps) repository.
### Multi-Node Local Testnet
If you want to see the multi-node consensus algorithm in action, see [Simulate a
network](https://docs.pezkuwichain.io/tutorials/build-a-blockchain/simulate-network/).
## Template Structure
A Substrate project such as this consists of a number of components that are
spread across a few directories.
### Node
A blockchain node is an application that allows users to participate in a
blockchain network. Substrate-based blockchain nodes expose a number of
capabilities:
- Networking: Substrate nodes use the [`libp2p`](https://libp2p.io/) networking
stack to allow the nodes in the network to communicate with one another.
- Consensus: Blockchains must have a way to come to
[consensus](https://docs.pezkuwichain.io/fundamentals/consensus/) on the state of
the network. Substrate makes it possible to supply custom consensus engines
and also ships with several consensus mechanisms that have been built on top
of [Web3 Foundation
research](https://research.web3.foundation/PezkuwiChain/protocols/NPoS).
- RPC Server: A remote procedure call (RPC) server is used to interact with
Substrate nodes.
There are several files in the `node` directory. Take special note of the
following:
- [`chain_spec.rs`](./node/src/chain_spec.rs): A [chain
specification](https://docs.pezkuwichain.io/build/chain-spec/) is a source code
file that defines a Substrate chain's initial (genesis) state. Chain
specifications are useful for development and testing, and critical when
architecting the launch of a production chain. Take note of the
`development_config` and `testnet_genesis` functions. These functions are
used to define the genesis state for the local development chain
configuration. These functions identify some [well-known
accounts](https://docs.pezkuwichain.io/reference/command-line-tools/subkey/) and
use them to configure the blockchain's initial state.
- [`service.rs`](./node/src/service.rs): This file defines the node
implementation. Take note of the libraries that this file imports and the
names of the functions it invokes. In particular, there are references to
consensus-related topics, such as the [block finalization and
forks](https://docs.pezkuwichain.io/fundamentals/consensus/#finalization-and-forks)
and other [consensus
mechanisms](https://docs.pezkuwichain.io/fundamentals/consensus/#default-consensus-models)
such as Aura for block authoring and GRANDPA for finality.
### Runtime
In Substrate, the terms "runtime" and "state transition function" are analogous.
Both terms refer to the core logic of the blockchain that is responsible for
validating blocks and executing the state changes they define. The Substrate
project in this repository uses
[FRAME](https://docs.pezkuwichain.io/learn/runtime-development/#frame) to construct
a blockchain runtime. FRAME allows runtime developers to declare domain-specific
logic in modules called "pallets". At the heart of FRAME is a helpful [macro
language](https://docs.pezkuwichain.io/reference/frame-macros/) that makes it easy
to create pallets and flexibly compose them to create blockchains that can
address [a variety of needs](https://substrate.pezkuwichain.app/ecosystem/projects/).
Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this
template and note the following:
- This file configures several pallets to include in the runtime. Each pallet
configuration is defined by a code block that begins with `impl
$PALLET_NAME::Config for Runtime`.
- The pallets are composed into a single runtime by way of the
[#[runtime]](https://docs.pezkuwichain.io/sdk/master/frame_support/attr.runtime.html)
macro, which is part of the [core FRAME pallet
library](https://docs.pezkuwichain.io/reference/frame-pallets/#system-pallets).
### Pallets
The runtime in this project is constructed using many FRAME pallets that ship
with [the Substrate
repository](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/substrate/frame) and a
template pallet that is [defined in the
`pallets`](./pallets/template/src/lib.rs) directory.
A FRAME pallet is comprised of a number of blockchain primitives, including:
- Storage: FRAME defines a rich set of powerful [storage
abstractions](https://docs.pezkuwichain.io/build/runtime-storage/) that makes it
easy to use Substrate's efficient key-value database to manage the evolving
state of a blockchain.
- Dispatchables: FRAME pallets define special types of functions that can be
invoked (dispatched) from outside of the runtime in order to update its state.
- Events: Substrate uses
[events](https://docs.pezkuwichain.io/build/events-and-errors/) to notify users
of significant state changes.
- Errors: When a dispatchable fails, it returns an error.
Each pallet has its own `Config` trait which serves as a configuration interface
to generically define the types and parameters it depends on.
## Alternatives Installations
Instead of installing dependencies and building this source directly, consider
the following alternatives.
### Nix
Install [nix](https://nixos.org/) and
[nix-direnv](https://github.com/nix-community/nix-direnv) for a fully
plug-and-play experience for setting up the development environment. To get all
the correct dependencies, activate direnv `direnv allow`.
### Docker
Please follow the [Substrate Docker instructions
here](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/docker/README.md) to
build the Docker container with the Substrate Node Template binary.
+218
View File
@@ -0,0 +1,218 @@
# Installation
This guide is for reference only, please check the latest information on getting started with Substrate [here](https://docs.pezkuwichain.io/main-docs/install/).
This page will guide you through the **2 steps** needed to prepare a computer for **Substrate** development. Since
Substrate is built with [the Rust programming language](https://www.rust-lang.org/), the first thing you will need to do
is prepare the computer for Rust development - these steps will vary based on the computer's operating system. Once Rust
is configured, you will use its toolchains to interact with Rust projects; the commands for Rust's toolchains will be
the same for all supported, Unix-based operating systems.
## Build dependencies
Substrate development is easiest on Unix-based operating systems like macOS or Linux. The examples in the [Substrate
Docs](https://github.com/pezkuwichain/docs.pezkuwichain.io) use Unix-style terminals to demonstrate how to interact with Substrate from the command
line.
### Ubuntu/Debian
Use a terminal shell to execute the following commands:
```bash
sudo apt update
# May prompt for location information
sudo apt install -y git clang curl libssl-dev llvm libudev-dev
```
### Arch Linux
Run these commands from a terminal:
```bash
pacman -Syu --needed --noconfirm curl git clang
```
### Fedora
Run these commands from a terminal:
```bash
sudo dnf update
sudo dnf install clang curl git openssl-devel
```
### OpenSUSE
Run these commands from a terminal:
```bash
sudo zypper install clang curl git openssl-devel llvm-devel libudev-devel
```
### macOS
> **Apple M1 ARM** If you have an Apple M1 ARM system on a chip, make sure that you have Apple Rosetta 2 installed
> through `softwareupdate --install-rosetta`. This is only needed to run the `protoc` tool during the build. The build
> itself and the target binaries would remain native.
Open the Terminal application and execute the following commands:
```bash
# Install Homebrew if necessary https://brew.sh/
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
# Make sure Homebrew is up-to-date, install openssl
brew update
brew install openssl
```
### Windows
**_PLEASE NOTE:_** Native Windows development of Substrate is _not_ very well supported! It is _highly_
recommended to use [Windows Subsystem Linux](https://docs.microsoft.com/en-us/windows/wsl/install-win10)
(WSL) and follow the instructions for [Ubuntu/Debian](#ubuntudebian).
Please refer to the separate
[guide for native Windows development](https://docs.pezkuwichain.io/main-docs/install/windows/).
## Rust developer environment
This guide uses <https://rustup.rs> installer and the `rustup` tool to manage the Rust toolchain. First install and
configure `rustup`:
```bash
# Install
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Configure
source ~/.cargo/env
```
Configure the Rust toolchain to default to the latest stable version, add nightly and the nightly wasm target:
```bash
rustup default stable
rustup update
rustup update nightly
rustup target add wasm32-unknown-unknown --toolchain nightly
```
## Test your set-up
Now the best way to ensure that you have successfully prepared a computer for Substrate development is to follow the
steps in [our first Substrate tutorial](https://docs.pezkuwichain.io/tutorials/v3/create-your-first-substrate-chain/).
## Troubleshooting Substrate builds
Sometimes you can't get the Substrate node template to compile out of the box. Here are some tips to help you work
through that.
### Rust configuration check
To see what Rust toolchain you are presently using, run:
```bash
rustup show
```
This will show something like this (Ubuntu example) output:
```text
Default host: x86_64-unknown-linux-gnu
rustup home: /home/user/.rustup
installed toolchains
--------------------
stable-x86_64-unknown-linux-gnu (default)
nightly-2020-10-06-x86_64-unknown-linux-gnu
nightly-x86_64-unknown-linux-gnu
installed targets for active toolchain
--------------------------------------
wasm32-unknown-unknown
x86_64-unknown-linux-gnu
active toolchain
----------------
stable-x86_64-unknown-linux-gnu (default)
rustc 1.50.0 (cb75ad5db 2021-02-10)
```
As you can see above, the default toolchain is stable, and the `nightly-x86_64-unknown-linux-gnu` toolchain as well as
its `wasm32-unknown-unknown` target is installed. You also see that `nightly-2020-10-06-x86_64-unknown-linux-gnu` is
installed, but is not used unless explicitly defined as illustrated in the [specify your nightly
version](#specifying-nightly-version) section.
### WebAssembly compilation
Substrate uses [WebAssembly](https://webassembly.org) (Wasm) to produce portable blockchain runtimes. You will need to
configure your Rust compiler to use [`nightly` builds](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) to
allow you to compile Substrate runtime code to the Wasm target.
> There are upstream issues in Rust that need to be resolved before all of Substrate can use the stable Rust toolchain.
> [This is our tracking issue](https://github.com/paritytech/substrate/issues/1252) if you're curious as to why and how
> this will be resolved.
#### Latest nightly for Substrate `master`
Developers who are building Substrate _itself_ should always use the latest bug-free versions of Rust stable and
nightly. This is because the Substrate codebase follows the tip of Rust nightly, which means that changes in Substrate
often depend on upstream changes in the Rust nightly compiler. To ensure your Rust compiler is always up to date, you
should run:
```bash
rustup update
rustup update nightly
rustup target add wasm32-unknown-unknown --toolchain nightly
```
> NOTE: It may be necessary to occasionally rerun `rustup update` if a change in the upstream Substrate codebase depends
> on a new feature of the Rust compiler. When you do this, both your nightly and stable toolchains will be pulled to the
> most recent release, and for nightly, it is generally _not_ expected to compile WASM without error (although it very
> often does). Be sure to [specify your nightly version](#specifying-nightly-version) if you get WASM build errors from
> `rustup` and [downgrade nightly as needed](#downgrading-rust-nightly).
#### Rust nightly toolchain
If you want to guarantee that your build works on your computer as you update Rust and other dependencies, you should
use a specific Rust nightly version that is known to be compatible with the version of Substrate they are using; this
version will vary from project to project and different projects may use different mechanisms to communicate this
version to developers. For instance, the Pezkuwi client specifies this information in its [release
notes](https://github.com/pezkuwichain/pezkuwi-sdk/releases).
```bash
# Specify the specific nightly toolchain in the date below:
rustup install nightly-<yyyy-MM-dd>
```
#### Wasm toolchain
Now, configure the nightly version to work with the Wasm compilation target:
```bash
rustup target add wasm32-unknown-unknown --toolchain nightly-<yyyy-MM-dd>
```
### Specifying nightly version
Use the `WASM_BUILD_TOOLCHAIN` environment variable to specify the Rust nightly version a Substrate project should use
for Wasm compilation:
```bash
WASM_BUILD_TOOLCHAIN=nightly-<yyyy-MM-dd> cargo build --release
```
> Note that this only builds _the runtime_ with the specified nightly. The rest of project will be compiled with **your
> default toolchain**, i.e. the latest installed stable toolchain.
### Downgrading Rust nightly
If your computer is configured to use the latest Rust nightly and you would like to downgrade to a specific nightly
version, follow these steps:
```bash
rustup uninstall nightly
rustup install nightly-<yyyy-MM-dd>
rustup target add wasm32-unknown-unknown --toolchain nightly-<yyyy-MM-dd>
```
+9
View File
@@ -0,0 +1,9 @@
# Env setup
Special files for setting up an environment to work with the template:
- `rust-toolchain.toml` when working with `rustup`.
- `flake.nix` when working with `nix`.
These files will be copied by the installer script to the main directory. They are
put into this special directory to not interfere with the normal CI.
+43
View File
@@ -0,0 +1,43 @@
{
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1678901627,
"narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1679262748,
"narHash": "sha256-DQCrrAFrkxijC6haUzOC5ZoFqpcv/tg2WxnyW3np1Cc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "60c1d71f2ba4c80178ec84523c2ca0801522e0a6",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}
+22
View File
@@ -0,0 +1,22 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils, ... }: flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
devShells.default = pkgs.mkShell {
packages = with pkgs; [
rustup
clang
protobuf
];
LIBCLANG_PATH = "${pkgs.libclang.lib}/lib";
};
});
}
@@ -0,0 +1,14 @@
[toolchain]
channel = "stable"
components = [
"cargo",
"clippy",
"rust-analyzer",
"rust-src",
"rust-std",
"rustc",
"rustc-dev",
"rustfmt",
]
targets = ["wasm32-unknown-unknown"]
profile = "minimal"
+111
View File
@@ -0,0 +1,111 @@
[package]
name = "solochain-template-node"
description = "A solochain node template built with Substrate, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
build = "build.rs"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lints]
workspace = true
[dependencies]
clap = { features = ["derive"], workspace = true }
futures = { features = ["thread-pool"], workspace = true }
jsonrpsee = { features = ["server"], workspace = true }
# substrate client
sc-basic-authorship = { workspace = true, default-features = true }
sc-cli = { workspace = true, default-features = true }
sc-client-api = { workspace = true, default-features = true }
sc-consensus = { workspace = true, default-features = true }
sc-consensus-aura = { workspace = true, default-features = true }
sc-consensus-grandpa = { workspace = true, default-features = true }
sc-executor = { workspace = true, default-features = true }
sc-network = { workspace = true, default-features = true }
sc-offchain = { workspace = true, default-features = true }
sc-service = { workspace = true, default-features = true }
sc-telemetry = { workspace = true, default-features = true }
sc-transaction-pool = { workspace = true, default-features = true }
sc-transaction-pool-api = { workspace = true, default-features = true }
sp-consensus-aura = { workspace = true, default-features = true }
sp-core = { workspace = true, default-features = true }
sp-genesis-builder = { workspace = true, default-features = true }
# substrate primitives
sp-api = { workspace = true, default-features = true }
sp-block-builder = { workspace = true, default-features = true }
sp-blockchain = { workspace = true, default-features = true }
sp-inherents = { workspace = true, default-features = true }
sp-io = { workspace = true, default-features = true }
sp-keyring = { workspace = true, default-features = true }
sp-runtime = { workspace = true, default-features = true }
sp-timestamp = { workspace = true, default-features = true }
# frame and pallets
frame-metadata-hash-extension = { workspace = true, default-features = true }
frame-system = { workspace = true, default-features = true }
pallet-transaction-payment = { workspace = true, default-features = true }
pallet-transaction-payment-rpc = { workspace = true, default-features = true }
substrate-frame-rpc-system = { workspace = true, default-features = true }
# These dependencies are used for runtime benchmarking
frame-benchmarking-cli = { workspace = true, default-features = true }
# Local Dependencies
solochain-template-runtime = { workspace = true }
[build-dependencies]
substrate-build-script-utils = { workspace = true, default-features = true }
[features]
default = ["std"]
std = ["solochain-template-runtime/std"]
# Dependencies that are only required if runtime benchmarking should be build.
runtime-benchmarks = [
"frame-benchmarking-cli/runtime-benchmarks",
"frame-metadata-hash-extension/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-transaction-payment-rpc/runtime-benchmarks",
"pallet-transaction-payment/runtime-benchmarks",
"sc-basic-authorship/runtime-benchmarks",
"sc-cli/runtime-benchmarks",
"sc-client-api/runtime-benchmarks",
"sc-consensus-aura/runtime-benchmarks",
"sc-consensus-grandpa/runtime-benchmarks",
"sc-consensus/runtime-benchmarks",
"sc-executor/runtime-benchmarks",
"sc-network/runtime-benchmarks",
"sc-offchain/runtime-benchmarks",
"sc-service/runtime-benchmarks",
"sc-transaction-pool-api/runtime-benchmarks",
"sc-transaction-pool/runtime-benchmarks",
"solochain-template-runtime/runtime-benchmarks",
"sp-api/runtime-benchmarks",
"sp-block-builder/runtime-benchmarks",
"sp-blockchain/runtime-benchmarks",
"sp-consensus-aura/runtime-benchmarks",
"sp-genesis-builder/runtime-benchmarks",
"sp-inherents/runtime-benchmarks",
"sp-io/runtime-benchmarks",
"sp-keyring/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"sp-timestamp/runtime-benchmarks",
"substrate-frame-rpc-system/runtime-benchmarks",
]
# Enable features that allow the runtime to be tried and debugged. Name might be subject to change
# in the near future.
try-runtime = [
"frame-system/try-runtime",
"pallet-transaction-payment/try-runtime",
"solochain-template-runtime/try-runtime",
"sp-runtime/try-runtime",
]
+7
View File
@@ -0,0 +1,7 @@
use substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
fn main() {
generate_cargo_keys();
rerun_if_git_head_changed();
}
@@ -0,0 +1,167 @@
//! Setup code for [`super::command`] which would otherwise bloat that module.
//!
//! Should only be used for benchmarking as it may break in other contexts.
use crate::service::FullClient;
use runtime::{AccountId, Balance, BalancesCall, SystemCall};
use sc_cli::Result;
use sc_client_api::BlockBackend;
use solochain_template_runtime as runtime;
use sp_core::{Encode, Pair};
use sp_inherents::{InherentData, InherentDataProvider};
use sp_keyring::Sr25519Keyring;
use sp_runtime::{OpaqueExtrinsic, SaturatedConversion};
use std::{sync::Arc, time::Duration};
/// Generates extrinsics for the `benchmark overhead` command.
///
/// Note: Should only be used for benchmarking.
pub struct RemarkBuilder {
client: Arc<FullClient>,
}
impl RemarkBuilder {
/// Creates a new [`Self`] from the given client.
pub fn new(client: Arc<FullClient>) -> Self {
Self { client }
}
}
impl frame_benchmarking_cli::ExtrinsicBuilder for RemarkBuilder {
fn pallet(&self) -> &str {
"system"
}
fn extrinsic(&self) -> &str {
"remark"
}
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
self.client.as_ref(),
acc,
SystemCall::remark { remark: vec![] }.into(),
nonce,
)
.into();
Ok(extrinsic)
}
}
/// Generates `Balances::TransferKeepAlive` extrinsics for the benchmarks.
///
/// Note: Should only be used for benchmarking.
pub struct TransferKeepAliveBuilder {
client: Arc<FullClient>,
dest: AccountId,
value: Balance,
}
impl TransferKeepAliveBuilder {
/// Creates a new [`Self`] from the given client.
pub fn new(client: Arc<FullClient>, dest: AccountId, value: Balance) -> Self {
Self { client, dest, value }
}
}
impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder {
fn pallet(&self) -> &str {
"balances"
}
fn extrinsic(&self) -> &str {
"transfer_keep_alive"
}
fn build(&self, nonce: u32) -> std::result::Result<OpaqueExtrinsic, &'static str> {
let acc = Sr25519Keyring::Bob.pair();
let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic(
self.client.as_ref(),
acc,
BalancesCall::transfer_keep_alive { dest: self.dest.clone().into(), value: self.value }
.into(),
nonce,
)
.into();
Ok(extrinsic)
}
}
/// Create a transaction using the given `call`.
///
/// Note: Should only be used for benchmarking.
pub fn create_benchmark_extrinsic(
client: &FullClient,
sender: sp_core::sr25519::Pair,
call: runtime::RuntimeCall,
nonce: u32,
) -> runtime::UncheckedExtrinsic {
let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
let best_hash = client.chain_info().best_hash;
let best_block = client.chain_info().best_number;
let period = runtime::configs::BlockHashCount::get()
.checked_next_power_of_two()
.map(|c| c / 2)
.unwrap_or(2) as u64;
let tx_ext: runtime::TxExtension = (
frame_system::AuthorizeCall::<runtime::Runtime>::new(),
frame_system::CheckNonZeroSender::<runtime::Runtime>::new(),
frame_system::CheckSpecVersion::<runtime::Runtime>::new(),
frame_system::CheckTxVersion::<runtime::Runtime>::new(),
frame_system::CheckGenesis::<runtime::Runtime>::new(),
frame_system::CheckEra::<runtime::Runtime>::from(sp_runtime::generic::Era::mortal(
period,
best_block.saturated_into(),
)),
frame_system::CheckNonce::<runtime::Runtime>::from(nonce),
frame_system::CheckWeight::<runtime::Runtime>::new(),
pallet_transaction_payment::ChargeTransactionPayment::<runtime::Runtime>::from(0),
frame_metadata_hash_extension::CheckMetadataHash::<runtime::Runtime>::new(false),
frame_system::WeightReclaim::<runtime::Runtime>::new(),
);
let raw_payload = runtime::SignedPayload::from_raw(
call.clone(),
tx_ext.clone(),
(
(),
(),
runtime::VERSION.spec_version,
runtime::VERSION.transaction_version,
genesis_hash,
best_hash,
(),
(),
(),
None,
(),
),
);
let signature = raw_payload.using_encoded(|e| sender.sign(e));
runtime::UncheckedExtrinsic::new_signed(
call,
sp_runtime::AccountId32::from(sender.public()).into(),
runtime::Signature::Sr25519(signature),
tx_ext,
)
}
/// Generates inherent data for the `benchmark overhead` command.
///
/// Note: Should only be used for benchmarking.
pub fn inherent_benchmark_data() -> Result<InherentData> {
let mut inherent_data = InherentData::new();
let d = Duration::from_millis(0);
let timestamp = sp_timestamp::InherentDataProvider::new(d.into());
futures::executor::block_on(timestamp.provide_inherent_data(&mut inherent_data))
.map_err(|e| format!("creating inherent data: {e:?}"))?;
Ok(inherent_data)
}
@@ -0,0 +1,29 @@
use sc_service::ChainType;
use solochain_template_runtime::WASM_BINARY;
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec;
pub fn development_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
None,
)
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
.build())
}
pub fn local_chain_spec() -> Result<ChainSpec, String> {
Ok(ChainSpec::builder(
WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?,
None,
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_preset_name(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET)
.build())
}
+52
View File
@@ -0,0 +1,52 @@
#[derive(Debug, clap::Parser)]
pub struct Cli {
#[command(subcommand)]
pub subcommand: Option<Subcommand>,
#[clap(flatten)]
pub run: sc_cli::RunCmd,
}
#[derive(Debug, clap::Subcommand)]
#[allow(clippy::large_enum_variant)]
pub enum Subcommand {
/// Key management cli utilities
#[command(subcommand)]
Key(sc_cli::KeySubcommand),
/// Build a chain specification.
/// DEPRECATED: `build-spec` command will be removed after 1/04/2026. Use `export-chain-spec`
/// command instead.
#[deprecated(
note = "build-spec command will be removed after 1/04/2026. Use export-chain-spec command instead"
)]
BuildSpec(sc_cli::BuildSpecCmd),
/// Export the chain specification.
ExportChainSpec(sc_cli::ExportChainSpecCmd),
/// 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),
/// Remove the whole chain.
PurgeChain(sc_cli::PurgeChainCmd),
/// Revert the chain to a previous state.
Revert(sc_cli::RevertCmd),
/// Sub-commands concerned with benchmarking.
#[command(subcommand)]
Benchmark(frame_benchmarking_cli::BenchmarkCmd),
/// Db meta columns information.
ChainInfo(sc_cli::ChainInfoCmd),
}
+202
View File
@@ -0,0 +1,202 @@
use crate::{
benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder},
chain_spec,
cli::{Cli, Subcommand},
service,
};
use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE};
use sc_cli::SubstrateCli;
use sc_service::PartialComponents;
use solochain_template_runtime::{Block, EXISTENTIAL_DEPOSIT};
use sp_keyring::Sr25519Keyring;
impl SubstrateCli for Cli {
fn impl_name() -> String {
"Substrate Node".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
env!("CARGO_PKG_DESCRIPTION").into()
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"support.anonymous.an".into()
}
fn copyright_start_year() -> i32 {
2017
}
fn load_spec(&self, id: &str) -> Result<Box<dyn sc_service::ChainSpec>, String> {
Ok(match id {
"dev" => Box::new(chain_spec::development_chain_spec()?),
"" | "local" => Box::new(chain_spec::local_chain_spec()?),
path =>
Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
}
/// Parse and run command line arguments
pub fn run() -> sc_cli::Result<()> {
let cli = Cli::from_args();
match &cli.subcommand {
Some(Subcommand::Key(cmd)) => cmd.run(&cli),
#[allow(deprecated)]
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)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::ExportChainSpec(cmd)) => {
let chain_spec = cli.load_spec(&cmd.chain)?;
cmd.run(chain_spec)
},
Some(Subcommand::ExportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
Ok((cmd.run(client, config.database), task_manager))
})
},
Some(Subcommand::ExportState(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, .. } = service::new_partial(&config)?;
Ok((cmd.run(client, config.chain_spec), task_manager))
})
},
Some(Subcommand::ImportBlocks(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, import_queue, .. } =
service::new_partial(&config)?;
Ok((cmd.run(client, import_queue), task_manager))
})
},
Some(Subcommand::PurgeChain(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run(config.database))
},
Some(Subcommand::Revert(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.async_run(|config| {
let PartialComponents { client, task_manager, backend, .. } =
service::new_partial(&config)?;
let aux_revert = Box::new(|client, _, blocks| {
sc_consensus_grandpa::revert(client, blocks)?;
Ok(())
});
Ok((cmd.run(client, backend, Some(aux_revert)), task_manager))
})
},
Some(Subcommand::Benchmark(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| {
// This switch needs to be in the client, since the client decides
// which sub-commands it wants to support.
match cmd {
BenchmarkCmd::Pallet(cmd) => {
if !cfg!(feature = "runtime-benchmarks") {
return Err(
"Runtime benchmarking wasn't enabled when building the node. \
You can enable it with `--features runtime-benchmarks`."
.into(),
);
}
cmd.run_with_spec::<sp_runtime::traits::HashingFor<Block>, ()>(Some(
config.chain_spec,
))
},
BenchmarkCmd::Block(cmd) => {
let PartialComponents { client, .. } = service::new_partial(&config)?;
cmd.run(client)
},
#[cfg(not(feature = "runtime-benchmarks"))]
BenchmarkCmd::Storage(_) => Err(
"Storage benchmarking can be enabled with `--features runtime-benchmarks`."
.into(),
),
#[cfg(feature = "runtime-benchmarks")]
BenchmarkCmd::Storage(cmd) => {
let PartialComponents { client, backend, .. } =
service::new_partial(&config)?;
let db = backend.expose_db();
let storage = backend.expose_storage();
let shared_cache = backend.expose_shared_trie_cache();
cmd.run(config, client, db, storage, shared_cache)
},
BenchmarkCmd::Overhead(cmd) => {
let PartialComponents { client, .. } = service::new_partial(&config)?;
let ext_builder = RemarkBuilder::new(client.clone());
cmd.run(
config.chain_spec.name().into(),
client,
inherent_benchmark_data()?,
Vec::new(),
&ext_builder,
false,
)
},
BenchmarkCmd::Extrinsic(cmd) => {
let PartialComponents { client, .. } = service::new_partial(&config)?;
// Register the *Remark* and *TKA* builders.
let ext_factory = ExtrinsicFactory(vec![
Box::new(RemarkBuilder::new(client.clone())),
Box::new(TransferKeepAliveBuilder::new(
client.clone(),
Sr25519Keyring::Alice.to_account_id(),
EXISTENTIAL_DEPOSIT,
)),
]);
cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory)
},
BenchmarkCmd::Machine(cmd) =>
cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()),
}
})
},
Some(Subcommand::ChainInfo(cmd)) => {
let runner = cli.create_runner(cmd)?;
runner.sync_run(|config| cmd.run::<Block>(&config))
},
None => {
let runner = cli.create_runner(&cli.run)?;
runner.run_node_until_exit(|config| async move {
match config.network.network_backend {
sc_network::config::NetworkBackendType::Libp2p => service::new_full::<
sc_network::NetworkWorker<
solochain_template_runtime::opaque::Block,
<solochain_template_runtime::opaque::Block as sp_runtime::traits::Block>::Hash,
>,
>(config)
.map_err(sc_cli::Error::Service),
sc_network::config::NetworkBackendType::Litep2p =>
service::new_full::<sc_network::Litep2pNetworkBackend>(config)
.map_err(sc_cli::Error::Service),
}
})
},
}
}
+13
View File
@@ -0,0 +1,13 @@
//! Substrate Node Template CLI library.
#![warn(missing_docs)]
mod benchmarking;
mod chain_spec;
mod cli;
mod command;
mod rpc;
mod service;
fn main() -> sc_cli::Result<()> {
command::run()
}
+60
View File
@@ -0,0 +1,60 @@
//! 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 jsonrpsee::RpcModule;
use sc_transaction_pool_api::TransactionPool;
use solochain_template_runtime::{opaque::Block, AccountId, Balance, Nonce};
use sp_api::ProvideRuntimeApi;
use sp_block_builder::BlockBuilder;
use sp_blockchain::{Error as BlockChainError, HeaderBackend, HeaderMetadata};
/// Full client dependencies.
pub struct FullDeps<C, P> {
/// The client instance to use.
pub client: Arc<C>,
/// Transaction pool instance.
pub pool: Arc<P>,
}
/// Instantiate all full RPC extensions.
pub fn create_full<C, P>(
deps: FullDeps<C, P>,
) -> Result<RpcModule<()>, Box<dyn std::error::Error + Send + Sync>>
where
C: ProvideRuntimeApi<Block>,
C: HeaderBackend<Block> + HeaderMetadata<Block, Error = BlockChainError> + 'static,
C: Send + Sync + 'static,
C::Api: substrate_frame_rpc_system::AccountNonceApi<Block, AccountId, Nonce>,
C::Api: pallet_transaction_payment_rpc::TransactionPaymentRuntimeApi<Block, Balance>,
C::Api: BlockBuilder<Block>,
P: TransactionPool + 'static,
{
use pallet_transaction_payment_rpc::{TransactionPayment, TransactionPaymentApiServer};
use substrate_frame_rpc_system::{System, SystemApiServer};
let mut module = RpcModule::new(());
let FullDeps { client, pool } = deps;
module.merge(System::new(client.clone(), pool).into_rpc())?;
module.merge(TransactionPayment::new(client).into_rpc())?;
// Extend this RPC with a custom API by using the following syntax.
// `YourRpcStruct` should have a reference to a client, which is needed
// to call into the runtime.
// `module.merge(YourRpcTrait::into_rpc(YourRpcStruct::new(ReferenceToClient, ...)))?;`
// You probably want to enable the `rpc v2 chainSpec` API as well
//
// let chain_name = chain_spec.name().to_string();
// let genesis_hash = client.block_hash(0).ok().flatten().expect("Genesis block exists; qed");
// let properties = chain_spec.properties();
// module.merge(ChainSpec::new(chain_name, genesis_hash, properties).into_rpc())?;
Ok(module)
}
+334
View File
@@ -0,0 +1,334 @@
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
use futures::FutureExt;
use sc_client_api::{Backend, BlockBackend};
use sc_consensus_aura::{ImportQueueParams, SlotProportion, StartAuraParams};
use sc_consensus_grandpa::SharedVoterState;
use sc_service::{error::Error as ServiceError, Configuration, TaskManager, WarpSyncConfig};
use sc_telemetry::{Telemetry, TelemetryWorker};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use solochain_template_runtime::{self, apis::RuntimeApi, opaque::Block};
use sp_consensus_aura::sr25519::AuthorityPair as AuraPair;
use std::{sync::Arc, time::Duration};
pub(crate) type FullClient = sc_service::TFullClient<
Block,
RuntimeApi,
sc_executor::WasmExecutor<sp_io::SubstrateHostFunctions>,
>;
type FullBackend = sc_service::TFullBackend<Block>;
type FullSelectChain = sc_consensus::LongestChain<FullBackend, Block>;
/// The minimum period of blocks on which justifications will be
/// imported and generated.
const GRANDPA_JUSTIFICATION_PERIOD: u32 = 512;
pub type Service = sc_service::PartialComponents<
FullClient,
FullBackend,
FullSelectChain,
sc_consensus::DefaultImportQueue<Block>,
sc_transaction_pool::TransactionPoolHandle<Block, FullClient>,
(
sc_consensus_grandpa::GrandpaBlockImport<FullBackend, Block, FullClient, FullSelectChain>,
sc_consensus_grandpa::LinkHalf<Block, FullClient, FullSelectChain>,
Option<Telemetry>,
),
>;
pub fn new_partial(config: &Configuration) -> Result<Service, ServiceError> {
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 executor = sc_service::new_wasm_executor::<sp_io::SubstrateHostFunctions>(&config.executor);
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 = telemetry.map(|(worker, telemetry)| {
task_manager.spawn_handle().spawn("telemetry", None, worker.run());
telemetry
});
let select_chain = sc_consensus::LongestChain::new(backend.clone());
let transaction_pool = Arc::from(
sc_transaction_pool::Builder::new(
task_manager.spawn_essential_handle(),
client.clone(),
config.role.is_authority().into(),
)
.with_options(config.transaction_pool.clone())
.with_prometheus(config.prometheus_registry())
.build(),
);
let (grandpa_block_import, grandpa_link) = sc_consensus_grandpa::block_import(
client.clone(),
GRANDPA_JUSTIFICATION_PERIOD,
&client,
select_chain.clone(),
telemetry.as_ref().map(|x| x.handle()),
)?;
let cidp_client = client.clone();
let import_queue =
sc_consensus_aura::import_queue::<AuraPair, _, _, _, _, _>(ImportQueueParams {
block_import: grandpa_block_import.clone(),
justification_import: Some(Box::new(grandpa_block_import.clone())),
client: client.clone(),
create_inherent_data_providers: move |parent_hash, _| {
let cidp_client = cidp_client.clone();
async move {
let slot_duration = sc_consensus_aura::standalone::slot_duration_at(
&*cidp_client,
parent_hash,
)?;
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
Ok((slot, timestamp))
}
},
spawner: &task_manager.spawn_essential_handle(),
registry: config.prometheus_registry(),
check_for_equivocation: Default::default(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
compatibility_mode: Default::default(),
})?;
Ok(sc_service::PartialComponents {
client,
backend,
task_manager,
import_queue,
keystore_container,
select_chain,
transaction_pool,
other: (grandpa_block_import, grandpa_link, telemetry),
})
}
/// Builds a new service for a full client.
pub fn new_full<
N: sc_network::NetworkBackend<Block, <Block as sp_runtime::traits::Block>::Hash>,
>(
config: Configuration,
) -> Result<TaskManager, ServiceError> {
let sc_service::PartialComponents {
client,
backend,
mut task_manager,
import_queue,
keystore_container,
select_chain,
transaction_pool,
other: (block_import, grandpa_link, mut telemetry),
} = new_partial(&config)?;
let mut net_config = sc_network::config::FullNetworkConfiguration::<
Block,
<Block as sp_runtime::traits::Block>::Hash,
N,
>::new(&config.network, config.prometheus_registry().cloned());
let metrics = N::register_notification_metrics(config.prometheus_registry());
let peer_store_handle = net_config.peer_store_handle();
let grandpa_protocol_name = sc_consensus_grandpa::protocol_standard_name(
&client.block_hash(0).ok().flatten().expect("Genesis block exists; qed"),
&config.chain_spec,
);
let (grandpa_protocol_config, grandpa_notification_service) =
sc_consensus_grandpa::grandpa_peers_set_config::<_, N>(
grandpa_protocol_name.clone(),
metrics.clone(),
peer_store_handle,
);
net_config.add_notification_protocol(grandpa_protocol_config);
let warp_sync = Arc::new(sc_consensus_grandpa::warp_proof::NetworkProvider::new(
backend.clone(),
grandpa_link.shared_authority_set().clone(),
Vec::default(),
));
let (network, system_rpc_tx, tx_handler_controller, sync_service) =
sc_service::build_network(sc_service::BuildNetworkParams {
config: &config,
net_config,
client: client.clone(),
transaction_pool: transaction_pool.clone(),
spawn_handle: task_manager.spawn_handle(),
import_queue,
block_announce_validator_builder: None,
warp_sync_config: Some(WarpSyncConfig::WithProvider(warp_sync)),
block_relay: None,
metrics,
})?;
if config.offchain_worker.enabled {
let offchain_workers =
sc_offchain::OffchainWorkers::new(sc_offchain::OffchainWorkerOptions {
runtime_api_provider: client.clone(),
is_validator: config.role.is_authority(),
keystore: Some(keystore_container.keystore()),
offchain_db: backend.offchain_storage(),
transaction_pool: Some(OffchainTransactionPoolFactory::new(
transaction_pool.clone(),
)),
network_provider: Arc::new(network.clone()),
enable_http_requests: true,
custom_extensions: |_| vec![],
})?;
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-worker",
offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
);
}
let role = config.role;
let force_authoring = config.force_authoring;
let backoff_authoring_blocks: Option<()> = None;
let name = config.network.node_name.clone();
let enable_grandpa = !config.disable_grandpa;
let prometheus_registry = config.prometheus_registry().cloned();
let rpc_extensions_builder = {
let client = client.clone();
let pool = transaction_pool.clone();
Box::new(move |_| {
let deps = crate::rpc::FullDeps { client: client.clone(), pool: pool.clone() };
crate::rpc::create_full(deps).map_err(Into::into)
})
};
let _rpc_handlers = sc_service::spawn_tasks(sc_service::SpawnTasksParams {
network: Arc::new(network.clone()),
client: client.clone(),
keystore: keystore_container.keystore(),
task_manager: &mut task_manager,
transaction_pool: transaction_pool.clone(),
rpc_builder: rpc_extensions_builder,
backend,
system_rpc_tx,
tx_handler_controller,
sync_service: sync_service.clone(),
config,
telemetry: telemetry.as_mut(),
tracing_execute_block: None,
})?;
if role.is_authority() {
let proposer_factory = sc_basic_authorship::ProposerFactory::new(
task_manager.spawn_handle(),
client.clone(),
transaction_pool.clone(),
prometheus_registry.as_ref(),
telemetry.as_ref().map(|x| x.handle()),
);
let slot_duration = sc_consensus_aura::slot_duration(&*client)?;
let aura = sc_consensus_aura::start_aura::<AuraPair, _, _, _, _, _, _, _, _, _, _>(
StartAuraParams {
slot_duration,
client,
select_chain,
block_import,
proposer_factory,
create_inherent_data_providers: move |_, ()| async move {
let timestamp = sp_timestamp::InherentDataProvider::from_system_time();
let slot =
sp_consensus_aura::inherents::InherentDataProvider::from_timestamp_and_slot_duration(
*timestamp,
slot_duration,
);
Ok((slot, timestamp))
},
force_authoring,
backoff_authoring_blocks,
keystore: keystore_container.keystore(),
sync_oracle: sync_service.clone(),
justification_sync_link: sync_service.clone(),
block_proposal_slot_portion: SlotProportion::new(2f32 / 3f32),
max_block_proposal_slot_portion: None,
telemetry: telemetry.as_ref().map(|x| x.handle()),
compatibility_mode: Default::default(),
},
)?;
// the AURA authoring task is considered essential, i.e. if it
// fails we take down the service with it.
task_manager
.spawn_essential_handle()
.spawn_blocking("aura", Some("block-authoring"), aura);
}
if enable_grandpa {
// if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below.
let keystore = if role.is_authority() { Some(keystore_container.keystore()) } else { None };
let grandpa_config = sc_consensus_grandpa::Config {
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
justification_generation_period: GRANDPA_JUSTIFICATION_PERIOD,
name: Some(name),
observer_enabled: false,
keystore,
local_role: role,
telemetry: telemetry.as_ref().map(|x| x.handle()),
protocol_name: grandpa_protocol_name,
};
// start the full GRANDPA voter
// NOTE: non-authorities could run the GRANDPA observer protocol, but at
// this point the full voter should provide better guarantees of block
// and vote data availability than the observer. The observer has not
// been tested extensively yet and having most nodes in a network run it
// could lead to finality stalls.
let grandpa_config = sc_consensus_grandpa::GrandpaParams {
config: grandpa_config,
link: grandpa_link,
network,
sync: Arc::new(sync_service),
notification_service: grandpa_notification_service,
voting_rule: sc_consensus_grandpa::VotingRulesBuilder::default().build(),
prometheus_registry,
shared_voter_state: SharedVoterState::empty(),
telemetry: telemetry.as_ref().map(|x| x.handle()),
offchain_tx_pool_factory: OffchainTransactionPoolFactory::new(transaction_pool),
};
// the GRANDPA voter task is considered infallible, i.e.
// if it fails we take down the service with it.
task_manager.spawn_essential_handle().spawn_blocking(
"grandpa-voter",
None,
sc_consensus_grandpa::run_grandpa_voter(grandpa_config)?,
);
}
Ok(task_manager)
}
@@ -0,0 +1,55 @@
[package]
name = "pallet-template"
description = "FRAME pallet template for defining custom runtime logic."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lints]
workspace = true
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
# frame deps
frame-benchmarking = { optional = true, workspace = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
[dev-dependencies]
sp-core = { workspace = true, default-features = true }
sp-io = { workspace = true, default-features = true }
sp-runtime = { workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-io/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"sp-runtime/try-runtime",
]
@@ -0,0 +1 @@
License: MIT-0
@@ -0,0 +1,35 @@
//! Benchmarking setup for pallet-template
use super::*;
#[allow(unused)]
use crate::Pallet as Template;
use frame_benchmarking::v2::*;
use frame_system::RawOrigin;
#[benchmarks]
mod benchmarks {
use super::*;
#[benchmark]
fn do_something() {
let value = 100u32;
let caller: T::AccountId = whitelisted_caller();
#[extrinsic_call]
do_something(RawOrigin::Signed(caller), value);
assert_eq!(Something::<T>::get(), Some(value));
}
#[benchmark]
fn cause_error() {
Something::<T>::put(100u32);
let caller: T::AccountId = whitelisted_caller();
#[extrinsic_call]
cause_error(RawOrigin::Signed(caller));
assert_eq!(Something::<T>::get(), Some(101u32));
}
impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
}
@@ -0,0 +1,203 @@
//! # Template Pallet
//!
//! A pallet with minimal functionality to help developers understand the essential components of
//! writing a FRAME pallet. It is typically used in beginner tutorials or in Substrate template
//! nodes as a starting point for creating a new pallet and **not meant to be used in production**.
//!
//! ## Overview
//!
//! This template pallet contains basic examples of:
//! - declaring a storage item that stores a single `u32` value
//! - declaring and using events
//! - declaring and using errors
//! - a dispatchable function that allows a user to set a new value to storage and emits an event
//! upon success
//! - another dispatchable function that causes a custom error to be thrown
//!
//! Each pallet section is annotated with an attribute using the `#[pallet::...]` procedural macro.
//! This macro generates the necessary code for a pallet to be aggregated into a FRAME runtime.
//!
//! Learn more about FRAME macros [here](https://docs.pezkuwichain.io/reference/frame-macros/).
//!
//! ### Pallet Sections
//!
//! The pallet sections in this template are:
//!
//! - A **configuration trait** that defines the types and parameters which the pallet depends on
//! (denoted by the `#[pallet::config]` attribute). See: [`Config`].
//! - A **means to store pallet-specific data** (denoted by the `#[pallet::storage]` attribute).
//! See: [`storage_types`].
//! - A **declaration of the events** this pallet emits (denoted by the `#[pallet::event]`
//! attribute). See: [`Event`].
//! - A **declaration of the errors** that this pallet can throw (denoted by the `#[pallet::error]`
//! attribute). See: [`Error`].
//! - A **set of dispatchable functions** that define the pallet's functionality (denoted by the
//! `#[pallet::call]` attribute). See: [`dispatchables`].
//!
//! Run `cargo doc --package pallet-template --open` to view this pallet's documentation.
// We make sure this pallet uses `no_std` for compiling to Wasm.
#![cfg_attr(not(feature = "std"), no_std)]
// Re-export pallet items so that they can be accessed from the crate namespace.
pub use pallet::*;
// FRAME pallets require their own "mock runtimes" to be able to run unit tests. This module
// contains a mock runtime specific for testing this pallet's functionality.
#[cfg(test)]
mod mock;
// This module contains the unit tests for this pallet.
// Learn about pallet unit testing here: https://docs.pezkuwichain.io/test/unit-testing/
#[cfg(test)]
mod tests;
// Every callable function or "dispatchable" a pallet exposes must have weight values that correctly
// estimate a dispatchable's execution time. The benchmarking module is used to calculate weights
// for each dispatchable and generates this pallet's weight.rs file. Learn more about benchmarking here: https://docs.pezkuwichain.io/test/benchmark/
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
pub mod weights;
pub use weights::*;
// All pallet logic is defined in its own module and must be annotated by the `pallet` attribute.
#[frame_support::pallet]
pub mod pallet {
// Import various useful types required by all FRAME pallets.
use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
// The `Pallet` struct serves as a placeholder to implement traits, methods and dispatchables
// (`Call`s) in this pallet.
#[pallet::pallet]
pub struct Pallet<T>(_);
/// The pallet's configuration trait.
///
/// All our types and constants a pallet depends on must be declared here.
/// These types are defined generically and made concrete when the pallet is declared in the
/// `runtime/src/lib.rs` file of your chain.
#[pallet::config]
pub trait Config: frame_system::Config {
/// The overarching runtime event type.
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// A type representing the weights required by the dispatchables of this pallet.
type WeightInfo: WeightInfo;
}
/// A storage item for this pallet.
///
/// In this template, we are declaring a storage item called `Something` that stores a single
/// `u32` value. Learn more about runtime storage here: <https://docs.pezkuwichain.io/build/runtime-storage/>
#[pallet::storage]
pub type Something<T> = StorageValue<_, u32>;
/// Events that functions in this pallet can emit.
///
/// Events are a simple means of indicating to the outside world (such as dApps, chain explorers
/// or other users) that some notable update in the runtime has occurred. In a FRAME pallet, the
/// documentation for each event field and its parameters is added to a node's metadata so it
/// can be used by external interfaces or tools.
///
/// The `generate_deposit` macro generates a function on `Pallet` called `deposit_event` which
/// will convert the event type of your pallet into `RuntimeEvent` (declared in the pallet's
/// [`Config`] trait) and deposit it using [`frame_system::Pallet::deposit_event`].
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// A user has successfully set a new value.
SomethingStored {
/// The new value set.
something: u32,
/// The account who set the new value.
who: T::AccountId,
},
}
/// Errors that can be returned by this pallet.
///
/// Errors tell users that something went wrong so it's important that their naming is
/// informative. Similar to events, error documentation is added to a node's metadata so it's
/// equally important that they have helpful documentation associated with them.
///
/// This type of runtime error can be up to 4 bytes in size should you want to return additional
/// information.
#[pallet::error]
pub enum Error<T> {
/// The value retrieved was `None` as no value was previously set.
NoneValue,
/// There was an attempt to increment the value in storage over `u32::MAX`.
StorageOverflow,
}
/// The pallet's dispatchable functions ([`Call`]s).
///
/// Dispatchable functions allows users to interact with the pallet and invoke state changes.
/// These functions materialize as "extrinsics", which are often compared to transactions.
/// They must always return a `DispatchResult` and be annotated with a weight and call index.
///
/// The [`call_index`] macro is used to explicitly
/// define an index for calls in the [`Call`] enum. This is useful for pallets that may
/// introduce new dispatchables over time. If the order of a dispatchable changes, its index
/// will also change which will break backwards compatibility.
///
/// The [`weight`] macro is used to assign a weight to each call.
#[pallet::call]
impl<T: Config> Pallet<T> {
/// An example dispatchable that takes a single u32 value as a parameter, writes the value
/// to storage and emits an event.
///
/// It checks that the _origin_ for this call is _Signed_ and returns a dispatch
/// error if it isn't. Learn more about origins here: <https://docs.pezkuwichain.io/build/origins/>
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::do_something())]
pub fn do_something(origin: OriginFor<T>, something: u32) -> DispatchResult {
// Check that the extrinsic was signed and get the signer.
let who = ensure_signed(origin)?;
// Update storage.
Something::<T>::put(something);
// Emit an event.
Self::deposit_event(Event::SomethingStored { something, who });
// Return a successful `DispatchResult`
Ok(())
}
/// An example dispatchable that may throw a custom error.
///
/// It checks that the caller is a signed origin and reads the current value from the
/// `Something` storage item. If a current value exists, it is incremented by 1 and then
/// written back to storage.
///
/// ## Errors
///
/// The function will return an error under the following conditions:
///
/// - If no value has been set ([`Error::NoneValue`])
/// - If incrementing the value in storage causes an arithmetic overflow
/// ([`Error::StorageOverflow`])
#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::cause_error())]
pub fn cause_error(origin: OriginFor<T>) -> DispatchResult {
let _who = ensure_signed(origin)?;
// Read a value from storage.
match Something::<T>::get() {
// Return an error if the value has not been set.
None => Err(Error::<T>::NoneValue.into()),
Some(old) => {
// Increment the value read from storage. This will cause an error in the event
// of overflow.
let new = old.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
// Update the value in storage with the incremented result.
Something::<T>::put(new);
Ok(())
},
}
}
}
}
@@ -0,0 +1,46 @@
use crate as pallet_template;
use frame_support::derive_impl;
use sp_runtime::BuildStorage;
type Block = frame_system::mocking::MockBlock<Test>;
#[frame_support::runtime]
mod runtime {
// The main runtime
#[runtime::runtime]
// Runtime Types to be generated
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Test;
#[runtime::pallet_index(0)]
pub type System = frame_system::Pallet<Test>;
#[runtime::pallet_index(1)]
pub type Template = pallet_template::Pallet<Test>;
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Block = Block;
}
impl pallet_template::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
}
// Build genesis storage according to the mock runtime.
pub fn new_test_ext() -> sp_io::TestExternalities {
frame_system::GenesisConfig::<Test>::default().build_storage().unwrap().into()
}
@@ -0,0 +1,24 @@
use crate::{mock::*, Error, Event, Something};
use frame_support::{assert_noop, assert_ok};
#[test]
fn it_works_for_default_value() {
new_test_ext().execute_with(|| {
// Go past genesis block so events get deposited
System::set_block_number(1);
// Dispatch a signed extrinsic.
assert_ok!(Template::do_something(RuntimeOrigin::signed(1), 42));
// Read pallet storage and assert an expected result.
assert_eq!(Something::<Test>::get(), Some(42));
// Assert that the correct event was deposited
System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into());
});
}
#[test]
fn correct_error_for_none_value() {
new_test_ext().execute_with(|| {
// Ensure the expected error is thrown when no value is present.
assert_noop!(Template::cause_error(RuntimeOrigin::signed(1)), Error::<Test>::NoneValue);
});
}
@@ -0,0 +1,90 @@
//! Autogenerated weights for pallet_template
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `<UNKNOWN>`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ../../target/release/node-template
// benchmark
// pallet
// --chain
// dev
// --pallet
// pallet_template
// --extrinsic
// *
// --steps=50
// --repeat=20
// --wasm-execution=compiled
// --output
// pallets/template/src/weights.rs
// --template
// ../../.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}};
use core::marker::PhantomData;
/// Weight functions needed for pallet_template.
pub trait WeightInfo {
fn do_something() -> Weight;
fn cause_error() -> Weight;
}
/// Weights for pallet_template using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: Template Something (r:0 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn do_something() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 8_000_000 picoseconds.
Weight::from_parts(9_000_000, 0)
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: Template Something (r:1 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn cause_error() -> Weight {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1489`
// Minimum execution time: 6_000_000 picoseconds.
Weight::from_parts(6_000_000, 1489)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: Template Something (r:0 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn do_something() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 8_000_000 picoseconds.
Weight::from_parts(9_000_000, 0)
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: Template Something (r:1 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn cause_error() -> Weight {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1489`
// Minimum execution time: 6_000_000 picoseconds.
Weight::from_parts(6_000_000, 1489)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
+165
View File
@@ -0,0 +1,165 @@
[package]
name = "solochain-template-runtime"
description = "A solochain runtime template built with Substrate, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lints]
workspace = true
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive", "serde"], workspace = true }
serde_json = { workspace = true, default-features = false, features = [
"alloc",
] }
# frame
frame-executive = { workspace = true }
frame-metadata-hash-extension = { workspace = true }
frame-support = { features = ["experimental"], workspace = true }
frame-system = { workspace = true }
frame-try-runtime = { optional = true, workspace = true }
# frame pallets
pallet-aura = { workspace = true }
pallet-balances = { workspace = true }
pallet-grandpa = { workspace = true }
pallet-sudo = { workspace = true }
pallet-timestamp = { workspace = true }
pallet-transaction-payment = { workspace = true }
# primitives
sp-api = { workspace = true }
sp-block-builder = { workspace = true }
sp-consensus-aura = { features = ["serde"], workspace = true }
sp-consensus-grandpa = { features = ["serde"], workspace = true }
sp-core = { features = ["serde"], workspace = true }
sp-genesis-builder = { workspace = true }
sp-inherents = { workspace = true }
sp-keyring = { workspace = true }
sp-offchain = { workspace = true }
sp-runtime = { features = ["serde"], workspace = true }
sp-session = { workspace = true }
sp-storage = { workspace = true }
sp-transaction-pool = { workspace = true }
sp-version = { features = ["serde"], workspace = true }
# RPC related
frame-system-rpc-runtime-api = { workspace = true }
pallet-transaction-payment-rpc-runtime-api = { workspace = true }
# Used for runtime benchmarking
frame-benchmarking = { optional = true, workspace = true }
frame-system-benchmarking = { optional = true, workspace = true }
# The pallet in this template.
pallet-template = { workspace = true }
[build-dependencies]
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-executive/std",
"frame-metadata-hash-extension/std",
"frame-support/std",
"frame-system-benchmarking?/std",
"frame-system-rpc-runtime-api/std",
"frame-system/std",
"frame-try-runtime?/std",
"pallet-aura/std",
"pallet-balances/std",
"pallet-grandpa/std",
"pallet-sudo/std",
"pallet-template/std",
"pallet-timestamp/std",
"pallet-transaction-payment-rpc-runtime-api/std",
"pallet-transaction-payment/std",
"scale-info/std",
"serde_json/std",
"sp-api/std",
"sp-block-builder/std",
"sp-consensus-aura/std",
"sp-consensus-grandpa/std",
"sp-core/std",
"sp-genesis-builder/std",
"sp-inherents/std",
"sp-keyring/std",
"sp-offchain/std",
"sp-runtime/std",
"sp-session/std",
"sp-storage/std",
"sp-transaction-pool/std",
"sp-version/std",
"substrate-wasm-builder",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-executive/runtime-benchmarks",
"frame-metadata-hash-extension/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system-benchmarking/runtime-benchmarks",
"frame-system-rpc-runtime-api/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"frame-try-runtime?/runtime-benchmarks",
"pallet-aura/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-grandpa/runtime-benchmarks",
"pallet-sudo/runtime-benchmarks",
"pallet-template/runtime-benchmarks",
"pallet-timestamp/runtime-benchmarks",
"pallet-transaction-payment-rpc-runtime-api/runtime-benchmarks",
"pallet-transaction-payment/runtime-benchmarks",
"sp-api/runtime-benchmarks",
"sp-block-builder/runtime-benchmarks",
"sp-consensus-aura/runtime-benchmarks",
"sp-consensus-grandpa/runtime-benchmarks",
"sp-genesis-builder/runtime-benchmarks",
"sp-inherents/runtime-benchmarks",
"sp-keyring/runtime-benchmarks",
"sp-offchain/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"sp-session/runtime-benchmarks",
"sp-transaction-pool/runtime-benchmarks",
"sp-version/runtime-benchmarks",
"substrate-wasm-builder?/runtime-benchmarks",
]
try-runtime = [
"frame-executive/try-runtime",
"frame-support/try-runtime",
"frame-system/try-runtime",
"frame-try-runtime/try-runtime",
"pallet-aura/try-runtime",
"pallet-balances/try-runtime",
"pallet-grandpa/try-runtime",
"pallet-sudo/try-runtime",
"pallet-template/try-runtime",
"pallet-timestamp/try-runtime",
"pallet-transaction-payment/try-runtime",
"sp-runtime/try-runtime",
]
# Enable the metadata hash generation.
#
# This is hidden behind a feature because it increases the compile time.
# The wasm binary needs to be compiled twice, once to fetch the metadata,
# generate the metadata hash and then a second time with the
# `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash`
# extension.
metadata-hash = ["substrate-wasm-builder/metadata-hash"]
# A convenience feature for enabling things when doing a build
# for an on-chain release.
on-chain-release-build = ["metadata-hash", "sp-api/disable-logging"]
+16
View File
@@ -0,0 +1,16 @@
#[cfg(all(feature = "std", feature = "metadata-hash"))]
fn main() {
substrate_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("UNIT", 12)
.build();
}
#[cfg(all(feature = "std", not(feature = "metadata-hash")))]
fn main() {
substrate_wasm_builder::WasmBuilder::build_using_defaults();
}
/// The wasm builder is deactivated when compiling
/// this crate for wasm to speed up the compilation.
#[cfg(not(feature = "std"))]
fn main() {}
+304
View File
@@ -0,0 +1,304 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
// External crates imports
use alloc::vec::Vec;
use frame_support::{
genesis_builder_helper::{build_state, get_preset},
weights::Weight,
};
use pallet_grandpa::AuthorityId as GrandpaId;
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
traits::{Block as BlockT, NumberFor},
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult,
};
use sp_version::RuntimeVersion;
// Local module imports
use super::{
AccountId, Aura, Balance, Block, Executive, Grandpa, InherentDataExt, Nonce, Runtime,
RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TransactionPayment, VERSION,
};
impl_runtime_apis! {
impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn execute_block(block: <Block as BlockT>::LazyBlock) {
Executive::execute_block(block);
}
fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
Executive::initialize_block(header)
}
}
impl sp_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
OpaqueMetadata::new(Runtime::metadata().into())
}
fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
Runtime::metadata_at_version(version)
}
fn metadata_versions() -> Vec<u32> {
Runtime::metadata_versions()
}
}
impl frame_support::view_functions::runtime_api::RuntimeViewFunction<Block> for Runtime {
fn execute_view_function(id: frame_support::view_functions::ViewFunctionId, input: Vec<u8>) -> Result<Vec<u8>, frame_support::view_functions::ViewFunctionDispatchError> {
Runtime::execute_view_function(id, input)
}
}
impl sp_block_builder::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
Executive::apply_extrinsic(extrinsic)
}
fn finalize_block() -> <Block as BlockT>::Header {
Executive::finalize_block()
}
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics()
}
fn check_inherents(
block: <Block as BlockT>::LazyBlock,
data: sp_inherents::InherentData,
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
tx: <Block as BlockT>::Extrinsic,
block_hash: <Block as BlockT>::Hash,
) -> TransactionValidity {
Executive::validate_transaction(source, tx, block_hash)
}
}
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &<Block as BlockT>::Header) {
Executive::offchain_worker(header)
}
}
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(Aura::slot_duration())
}
fn authorities() -> Vec<AuraId> {
pallet_aura::Authorities::<Runtime>::get().into_inner()
}
}
impl sp_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
SessionKeys::generate(seed)
}
fn decode_session_keys(
encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
SessionKeys::decode_into_raw_public_keys(&encoded)
}
}
impl sp_consensus_grandpa::GrandpaApi<Block> for Runtime {
fn grandpa_authorities() -> sp_consensus_grandpa::AuthorityList {
Grandpa::grandpa_authorities()
}
fn current_set_id() -> sp_consensus_grandpa::SetId {
Grandpa::current_set_id()
}
fn submit_report_equivocation_unsigned_extrinsic(
_equivocation_proof: sp_consensus_grandpa::EquivocationProof<
<Block as BlockT>::Hash,
NumberFor<Block>,
>,
_key_owner_proof: sp_consensus_grandpa::OpaqueKeyOwnershipProof,
) -> Option<()> {
None
}
fn generate_key_ownership_proof(
_set_id: sp_consensus_grandpa::SetId,
_authority_id: GrandpaId,
) -> Option<sp_consensus_grandpa::OpaqueKeyOwnershipProof> {
// NOTE: this is the only implementation possible since we've
// defined our key owner proof type as a bottom type (i.e. a type
// with no values).
None
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
fn account_nonce(account: AccountId) -> Nonce {
System::account_nonce(account)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
fn query_info(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_info(uxt, len)
}
fn query_fee_details(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_fee_details(uxt, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
for Runtime
{
fn query_call_info(
call: RuntimeCall,
len: u32,
) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_call_info(call, len)
}
fn query_call_fee_details(
call: RuntimeCall,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_call_fee_details(call, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
#[cfg(feature = "runtime-benchmarks")]
impl frame_benchmarking::Benchmark<Block> for Runtime {
fn benchmark_metadata(extra: bool) -> (
Vec<frame_benchmarking::BenchmarkList>,
Vec<frame_support::traits::StorageInfo>,
) {
use frame_benchmarking::{baseline, BenchmarkList};
use frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench;
use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench;
use baseline::Pallet as BaselineBench;
use super::*;
let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra);
let storage_info = AllPalletsWithSystem::storage_info();
(list, storage_info)
}
#[allow(non_local_definitions)]
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
use frame_benchmarking::{baseline, BenchmarkBatch};
use sp_storage::TrackedStorageKey;
use frame_system_benchmarking::Pallet as SystemBench;
use frame_system_benchmarking::extensions::Pallet as SystemExtensionsBench;
use baseline::Pallet as BaselineBench;
use super::*;
impl frame_system_benchmarking::Config for Runtime {}
impl baseline::Config for Runtime {}
use frame_support::traits::WhitelistedStorageKeys;
let whitelist: Vec<TrackedStorageKey> = AllPalletsWithSystem::whitelisted_storage_keys();
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
add_benchmarks!(params, batches);
Ok(batches)
}
}
#[cfg(feature = "try-runtime")]
impl frame_try_runtime::TryRuntime<Block> for Runtime {
fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here. If any of the pre/post migration checks fail, we shall stop
// right here and right now.
let weight = Executive::try_runtime_upgrade(checks).unwrap();
(weight, super::configs::RuntimeBlockWeights::get().max_block)
}
fn execute_block(
block: <Block as BlockT>::LazyBlock,
state_root_check: bool,
signature_check: bool,
select: frame_try_runtime::TryStateSelect
) -> Weight {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here.
Executive::try_execute_block(block, state_root_check, signature_check, select).expect("execute-block failed")
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
build_state::<RuntimeGenesisConfig>(config)
}
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset)
}
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
crate::genesis_config_presets::preset_names()
}
}
}
@@ -0,0 +1,34 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
frame_benchmarking::define_benchmarks!(
[frame_benchmarking, BaselineBench::<Runtime>]
[frame_system, SystemBench::<Runtime>]
[frame_system_extensions, SystemExtensionsBench::<Runtime>]
[pallet_balances, Balances]
[pallet_timestamp, Timestamp]
[pallet_sudo, Sudo]
[pallet_template, Template]
);
@@ -0,0 +1,171 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
// Substrate and Pezkuwi dependencies
use frame_support::{
derive_impl, parameter_types,
traits::{ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, VariantCountOf},
weights::{
constants::{RocksDbWeight, WEIGHT_REF_TIME_PER_SECOND},
IdentityFee, Weight,
},
};
use frame_system::limits::{BlockLength, BlockWeights};
use pallet_transaction_payment::{ConstFeeMultiplier, FungibleAdapter, Multiplier};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_runtime::{traits::One, Perbill};
use sp_version::RuntimeVersion;
// Local module imports
use super::{
AccountId, Aura, Balance, Balances, Block, BlockNumber, Hash, Nonce, PalletInfo, Runtime,
RuntimeCall, RuntimeEvent, RuntimeFreezeReason, RuntimeHoldReason, RuntimeOrigin, RuntimeTask,
System, EXISTENTIAL_DEPOSIT, SLOT_DURATION, VERSION,
};
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
parameter_types! {
pub const BlockHashCount: BlockNumber = 2400;
pub const Version: RuntimeVersion = VERSION;
/// We allow for 2 seconds of compute with a 6 second average block time.
pub RuntimeBlockWeights: BlockWeights = BlockWeights::with_sensible_defaults(
Weight::from_parts(2u64 * WEIGHT_REF_TIME_PER_SECOND, u64::MAX),
NORMAL_DISPATCH_RATIO,
);
pub RuntimeBlockLength: BlockLength = BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
pub const SS58Prefix: u8 = 42;
}
/// All migrations of the runtime, aside from the ones declared in the pallets.
///
/// This can be a tuple of types, each implementing `OnRuntimeUpgrade`.
#[allow(unused_parens)]
type SingleBlockMigrations = ();
/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from
/// [`SoloChainDefaultConfig`](`struct@frame_system::config_preludes::SolochainDefaultConfig`),
/// but overridden as needed.
#[derive_impl(frame_system::config_preludes::SolochainDefaultConfig)]
impl frame_system::Config for Runtime {
/// The block type for the runtime.
type Block = Block;
/// Block & extrinsics weights: base values and limits.
type BlockWeights = RuntimeBlockWeights;
/// The maximum length of a block (in bytes).
type BlockLength = RuntimeBlockLength;
/// The identifier used to distinguish between accounts.
type AccountId = AccountId;
/// The type for storing how many extrinsics an account has signed.
type Nonce = Nonce;
/// The type for hashing blocks and tries.
type Hash = Hash;
/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
type BlockHashCount = BlockHashCount;
/// The weight of database operations that the runtime can invoke.
type DbWeight = RocksDbWeight;
/// Version of the runtime.
type Version = Version;
/// The data to be stored in an account.
type AccountData = pallet_balances::AccountData<Balance>;
/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
type SS58Prefix = SS58Prefix;
type MaxConsumers = frame_support::traits::ConstU32<16>;
type SingleBlockMigrations = SingleBlockMigrations;
}
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
type DisabledValidators = ();
type MaxAuthorities = ConstU32<32>;
type AllowMultipleBlocksPerSlot = ConstBool<false>;
type SlotDuration = pallet_aura::MinimumPeriodTimesTwo<Runtime>;
}
impl pallet_grandpa::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
type MaxAuthorities = ConstU32<32>;
type MaxNominators = ConstU32<0>;
type MaxSetIdSessionEntries = ConstU64<0>;
type KeyOwnerProof = sp_core::Void;
type EquivocationReportSystem = ();
}
impl pallet_timestamp::Config for Runtime {
/// A timestamp: milliseconds since the unix epoch.
type Moment = u64;
type OnTimestampSet = Aura;
type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
type WeightInfo = ();
}
impl pallet_balances::Config for Runtime {
type MaxLocks = ConstU32<50>;
type MaxReserves = ();
type ReserveIdentifier = [u8; 8];
/// The type for recording an account's balance.
type Balance = Balance;
/// The ubiquitous event type.
type RuntimeEvent = RuntimeEvent;
type DustRemoval = ();
type ExistentialDeposit = ConstU128<EXISTENTIAL_DEPOSIT>;
type AccountStore = System;
type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
type FreezeIdentifier = RuntimeFreezeReason;
type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
type RuntimeHoldReason = RuntimeHoldReason;
type RuntimeFreezeReason = RuntimeFreezeReason;
type DoneSlashHandler = ();
}
parameter_types! {
pub FeeMultiplier: Multiplier = Multiplier::one();
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = FungibleAdapter<Balances, ()>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ConstFeeMultiplier<FeeMultiplier>;
type WeightInfo = pallet_transaction_payment::weights::SubstrateWeight<Runtime>;
}
impl pallet_sudo::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = pallet_sudo::weights::SubstrateWeight<Runtime>;
}
/// Configure the pallet-template in pallets/template.
impl pallet_template::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = pallet_template::weights::SubstrateWeight<Runtime>;
}
@@ -0,0 +1,109 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::{AccountId, BalancesConfig, RuntimeGenesisConfig, SudoConfig};
use alloc::{vec, vec::Vec};
use frame_support::build_struct_json_patch;
use serde_json::Value;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_consensus_grandpa::AuthorityId as GrandpaId;
use sp_genesis_builder::{self, PresetId};
use sp_keyring::Sr25519Keyring;
// Returns the genesis config presets populated with given parameters.
fn testnet_genesis(
initial_authorities: Vec<(AuraId, GrandpaId)>,
endowed_accounts: Vec<AccountId>,
root: AccountId,
) -> Value {
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, 1u128 << 60))
.collect::<Vec<_>>(),
},
aura: pallet_aura::GenesisConfig {
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect::<Vec<_>>(),
},
grandpa: pallet_grandpa::GenesisConfig {
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect::<Vec<_>>(),
},
sudo: SudoConfig { key: Some(root) },
})
}
/// Return the development genesis config.
pub fn development_config_genesis() -> Value {
testnet_genesis(
vec![(
sp_keyring::Sr25519Keyring::Alice.public().into(),
sp_keyring::Ed25519Keyring::Alice.public().into(),
)],
vec![
Sr25519Keyring::Alice.to_account_id(),
Sr25519Keyring::Bob.to_account_id(),
Sr25519Keyring::AliceStash.to_account_id(),
Sr25519Keyring::BobStash.to_account_id(),
],
sp_keyring::Sr25519Keyring::Alice.to_account_id(),
)
}
/// Return the local genesis config preset.
pub fn local_config_genesis() -> Value {
testnet_genesis(
vec![
(
sp_keyring::Sr25519Keyring::Alice.public().into(),
sp_keyring::Ed25519Keyring::Alice.public().into(),
),
(
sp_keyring::Sr25519Keyring::Bob.public().into(),
sp_keyring::Ed25519Keyring::Bob.public().into(),
),
],
Sr25519Keyring::iter()
.filter(|v| v != &Sr25519Keyring::One && v != &Sr25519Keyring::Two)
.map(|v| v.to_account_id())
.collect::<Vec<_>>(),
Sr25519Keyring::Alice.to_account_id(),
)
}
/// Provides the JSON representation of predefined genesis config for given `id`.
pub fn get_preset(id: &PresetId) -> Option<Vec<u8>> {
let patch = match id.as_ref() {
sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(),
sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => local_config_genesis(),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![
PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET),
PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET),
]
}
+222
View File
@@ -0,0 +1,222 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub mod apis;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarks;
pub mod configs;
extern crate alloc;
use alloc::vec::Vec;
use sp_runtime::{
generic, impl_opaque_keys,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiAddress, MultiSignature,
};
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
pub use frame_system::Call as SystemCall;
pub use pallet_balances::Call as BalancesCall;
pub use pallet_timestamp::Call as TimestampCall;
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;
pub mod genesis_config_presets;
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
/// to even the core data structures.
pub mod opaque {
use super::*;
use sp_runtime::{
generic,
traits::{BlakeTwo256, Hash as HashT},
};
pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
/// Opaque block header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Opaque block type.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Opaque block identifier type.
pub type BlockId = generic::BlockId<Block>;
/// Opaque block hash type.
pub type Hash = <BlakeTwo256 as HashT>::Output;
}
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
pub grandpa: Grandpa,
}
}
// To learn more about runtime versioning, see:
// https://docs.pezkuwichain.io/main-docs/build/upgrade#runtime-versioning
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: alloc::borrow::Cow::Borrowed("solochain-template-runtime"),
impl_name: alloc::borrow::Cow::Borrowed("solochain-template-runtime"),
authoring_version: 1,
// The version of the runtime specification. A full node will not attempt to use its native
// runtime in substitute for the on-chain Wasm runtime unless all of `spec_name`,
// `spec_version`, and `authoring_version` are the same between Wasm and native.
// This value is set to 100 to notify Pezkuwi-JS App (https://pezkuwichain.io) to use
// the compatible custom types.
spec_version: 100,
impl_version: 1,
apis: apis::RUNTIME_API_VERSIONS,
transaction_version: 1,
system_version: 1,
};
mod block_times {
/// This determines the average expected block time that we are targeting. Blocks will be
/// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by
/// `pallet_timestamp` which is in turn picked up by `pallet_aura` to implement `fn
/// slot_duration()`.
///
/// Change this to adjust the block time.
pub const MILLI_SECS_PER_BLOCK: u64 = 6000;
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
// Attempting to do so will brick block production.
pub const SLOT_DURATION: u64 = MILLI_SECS_PER_BLOCK;
}
pub use block_times::*;
// Time is measured by number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLI_SECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
pub const BLOCK_HASH_COUNT: BlockNumber = 2400;
// Unit = the base number of indivisible units for balances
pub const UNIT: Balance = 1_000_000_000_000;
pub const MILLI_UNIT: Balance = 1_000_000_000;
pub const MICRO_UNIT: Balance = 1_000_000;
/// Existential deposit.
pub const EXISTENTIAL_DEPOSIT: Balance = MILLI_UNIT;
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
/// Balance of an account.
pub type Balance = u128;
/// Index of a transaction in the chain.
pub type Nonce = u32;
/// A hash of some data used by the chain.
pub type Hash = sp_core::H256;
/// An index to a block.
pub type BlockNumber = u32;
/// The address format for describing accounts.
pub type Address = MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The `TransactionExtension` to the basic transaction logic.
pub type TxExtension = (
frame_system::AuthorizeCall<Runtime>,
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
frame_system::WeightReclaim<Runtime>,
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
/// The payload being signed in transactions.
pub type SignedPayload = generic::SignedPayload<RuntimeCall, TxExtension>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
>;
// Create the runtime by composing the FRAME pallets that were previously configured.
#[frame_support::runtime]
mod runtime {
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
#[runtime::pallet_index(0)]
pub type System = frame_system;
#[runtime::pallet_index(1)]
pub type Timestamp = pallet_timestamp;
#[runtime::pallet_index(2)]
pub type Aura = pallet_aura;
#[runtime::pallet_index(3)]
pub type Grandpa = pallet_grandpa;
#[runtime::pallet_index(4)]
pub type Balances = pallet_balances;
#[runtime::pallet_index(5)]
pub type TransactionPayment = pallet_transaction_payment;
#[runtime::pallet_index(6)]
pub type Sudo = pallet_sudo;
// Include the custom logic from the pallet-template in the runtime.
#[runtime::pallet_index(7)]
pub type Template = pallet_template;
}
+3
View File
@@ -0,0 +1,3 @@
target/
Dockerfile
.dockerignore
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "teyrchain-template"
description = "A teyrchain-template helper crate to keep documentation in sync with the template's components."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[dependencies]
docify = { workspace = true }
[features]
generate-readme = []
+28
View File
@@ -0,0 +1,28 @@
FROM docker.io/paritytech/ci-unified:latest as builder
WORKDIR /polkadot
COPY . /polkadot
RUN cargo fetch
RUN cargo build --workspace --locked --profile production
FROM docker.io/parity/base-bin:latest
COPY --from=builder /polkadot/target/production/parachain-template-node /usr/local/bin
USER root
RUN useradd -m -u 1001 -U -s /bin/sh -d /polkadot polkadot && \
mkdir -p /data /polkadot/.local/share && \
chown -R polkadot:polkadot /data && \
ln -s /data /polkadot/.local/share/polkadot && \
# unclutter and minimize the attack surface
rm -rf /usr/bin /usr/sbin && \
# check if executable works in this container
/usr/local/bin/parachain-template-node --version
USER polkadot
EXPOSE 30333 9933 9944 9615
VOLUME ["/data"]
ENTRYPOINT ["/usr/local/bin/parachain-template-node"]
+24
View File
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
+268
View File
@@ -0,0 +1,268 @@
<div align="center">
# Pezkuwi SDK's Teyrchain Template
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/Polkadot_Logo_Horizontal_Pink_White.png#gh-dark-mode-only"/>
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/Polkadot_Logo_Horizontal_Pink_Black.png#gh-light-mode-only"/>
> This is a template for creating a [teyrchain](https://wiki.network.pezkuwichain.io/docs/learn-parachains) based on Pezkuwi SDK.
>
> This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
</div>
## Table of Contents
- [Intro](#intro)
- [Template Structure](#template-structure)
- [Getting Started](#getting-started)
- [Starting a Development Chain](#starting-a-development-chain)
- [Omni Node](#omni-node-prerequisites)
- [Zombienet setup with Omni Node](#zombienet-setup-with-omni-node)
- [Teyrchain Template Node](#teyrchain-template-node)
- [Connect with the Pezkuwi-JS Apps Front-End](#connect-with-the-pezkuwi-js-apps-front-end)
- [Takeaways](#takeaways)
- [Runtime development](#runtime-development)
- [Contributing](#contributing)
- [Getting Help](#getting-help)
## Intro
- ⏫ This template provides a starting point to build a [teyrchain](https://wiki.network.pezkuwichain.io/docs/learn-parachains).
- ☁️ It is based on the
[Cumulus](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/cumulus/index.html) framework.
- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
such as a [Balances pallet](https://docs.pezkuwichain.io/sdk/master/pallet_balances/index.html).
- 👉 Learn more about teyrchains [here](https://wiki.network.pezkuwichain.io/docs/learn-parachains)
## Template Structure
A Pezkuwi SDK based project such as this one consists of:
- 🧮 the [Runtime](./runtime/README.md) - the core logic of the teyrchain.
- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
- 💿 a [Node](./node/README.md) - the binary application, not part of the project default-members list and not compiled unless
building the project with `--workspace` flag, which builds all workspace members, and is an alternative to
[Omni Node](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html).
## Getting Started
- 🦀 The template is using the Rust language.
- 👉 Check the
[Rust installation instructions](https://www.rust-lang.org/tools/install) for your system.
- 🛠️ Depending on your operating system and Rust version, there might be additional
packages required to compile this template - please take note of the Rust compiler output.
Fetch teyrchain template code:
```sh
git clone https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template.git teyrchain-template
cd teyrchain-template
```
## Starting a Development Chain
The teyrchain template relies on a hardcoded teyrchain id which is defined in the runtime code
and referenced throughout the contents of this file as `{{TEYRCHAIN_ID}}`. Please replace
any command or file referencing this placeholder with the value of the `TEYRCHAIN_ID` constant:
<!-- docify::embed!("runtime/src/genesis_config_presets.rs", TEYRCHAIN_ID)-->
### Omni Node Prerequisites
[Omni Node](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can
be used to run the teyrchain template's runtime. `pezkuwi-omni-node` binary crate usage is described at a high-level
[on crates.io](https://crates.io/crates/polkadot-omni-node).
#### Install `pezkuwi-omni-node`
```sh
cargo install pezkuwi-omni-node
```
> For more advanced options, please see the installation section at [`crates.io/omni-node`](https://crates.io/crates/polkadot-omni-node).
#### Build `teyrchain-template-runtime`
```sh
cargo build --profile production
```
#### Install `staging-chain-spec-builder`
```sh
cargo install staging-chain-spec-builder
```
> For more advanced options, please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder).
#### Use `chain-spec-builder` to generate the `chain_spec.json` file
```sh
chain-spec-builder create --relay-chain "pezkuwichain-local" --runtime \
target/release/wbuild/teyrchain-template-runtime/teyrchain_template_runtime.wasm named-preset development
```
**Note**: the `relay-chain` flag is required by Omni Node. The `relay-chain` value is set in accordance
with the relay chain ID where this instantiation of teyrchain-template will connect to.
#### Run Omni Node
Start Omni Node with the generated chain spec. We'll start it in development mode (without a relay chain config), producing
and finalizing blocks based on manual seal, configured below to seal a block with each second.
```bash
pezkuwi-omni-node --chain <path/to/chain_spec.json> --dev --dev-block-time 1000
```
However, such a setup is not close to what would run in production, and for that we need to setup a local
relay chain network that will help with the block finalization. In this guide we'll setup a local relay chain
as well. We'll not do it manually, by starting one node at a time, but we'll use [zombienet](https://paritytech.github.io/zombienet/intro.html).
Follow through the next section for more details on how to do it.
### Zombienet setup with Omni Node
Assuming we continue from the last step of the previous section, we have a chain spec and we need to setup a relay chain.
We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), and
`zombienet-omni-node.toml` contains the network specification we want to start.
#### Relay chain prerequisites
Download the `pezkuwi` (and the accompanying `pezkuwi-prepare-worker` and `pezkuwi-execute-worker`) binaries from
[Pezkuwi SDK releases](https://github.com/pezkuwichain/pezkuwi-sdk/releases). Then expose them on `PATH` like so:
```sh
export PATH="$PATH:<path/to/binaries>"
```
#### Update `zombienet-omni-node.toml` with a valid chain spec path
To simplify the process of using the teyrchain-template with zombienet and Omni Node, we've added a pre-configured
development chain spec (dev_chain_spec.json) to the teyrchain template. The zombienet-omni-node.toml file of this
template points to it, but you can update it to an updated chain spec generated on your machine. To generate a
chain spec refer to [staging-chain-spec-builder](https://crates.io/crates/staging-chain-spec-builder)
Then make the changes in the network specification like so:
```toml
# ...
[[teyrchains]]
id = "<TEYRCHAIN_ID>"
chain_spec_path = "<TO BE UPDATED WITH A VALID PATH>"
# ...
```
#### Start the network
```sh
zombienet --provider native spawn zombienet-omni-node.toml
```
### Teyrchain Template Node
As mentioned in the `Template Structure` section, the `node` crate is optionally compiled and it is an alternative
to `Omni Node`. Similarly, it requires setting up a relay chain, and we'll use `zombienet` once more.
#### Install the `teyrchain-template-node`
```sh
cargo install --path node --locked
```
#### Setup and start the network
For setup, please consider the instructions for `zombienet` installation [here](https://paritytech.github.io/zombienet/install.html#installation)
and [relay chain prerequisites](#relay-chain-prerequisites).
We're left just with starting the network:
```sh
zombienet --provider native spawn zombienet.toml
```
### Connect with the Pezkuwi-JS Apps Front-End
- 🌐 You can interact with your local node using the
hosted version of the Pezkuwi/Substrate Portal:
[relay chain](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9944)
and [teyrchain](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9988).
- 🪐 A hosted version is also
available on [IPFS](https://dotapps.io/).
- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
[`pezkuwi-js/apps`](https://github.com/polkadot-js/apps) repository.
### Takeaways
Development teyrchains:
- 🔗 Connect to relay chains, and we showcased how to connect to a local one.
- 🧹 Do not persist the state.
- 💰 Are preconfigured with a genesis state that includes several prefunded development accounts.
- 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts.
## Runtime development
We recommend using [`chopsticks`](https://github.com/AcalaNetwork/chopsticks) when the focus is more on the runtime
development and `OmniNode` is enough as is.
### Install chopsticks
To use `chopsticks`, please install the latest version according to the installation [guide](https://github.com/AcalaNetwork/chopsticks?tab=readme-ov-file#install).
### Build a raw chain spec
Build the `teyrchain-template-runtime` as mentioned before in this guide and use `chain-spec-builder`
again but this time by passing `--raw-storage` flag:
```sh
chain-spec-builder create --raw-storage --relay-chain "pezkuwichain-local" --runtime \
target/release/wbuild/teyrchain-template-runtime/teyrchain_template_runtime.wasm named-preset development
```
### Start `chopsticks` with the chain spec
```sh
npx @acala-network/chopsticks@latest --chain-spec <path/to/chain_spec.json>
```
### Alternatives
`OmniNode` can be still used for runtime development if using the `--dev` flag, while `teyrchain-template-node` doesn't
support it at this moment. It can still be used to test a runtime in a full setup where it is started alongside a
relay chain network (see [Teyrchain Template node](#teyrchain-template-node) setup).
## Contributing
- 🔄 This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
- ➡️ Any pull requests should be directed to this [source](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/teyrchain).
- 😇 Please refer to the monorepo's
[contribution guidelines](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and
[Code of Conduct](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
## Getting Help
- 🧑‍🏫 To learn about Pezkuwi in general, [docs.Pezkuwi.com](https://docs.pezkuwichain.io/) website is a good starting point.
- 🧑‍🔧 For technical introduction, [here](https://github.com/pezkuwichain/pezkuwi-sdk#-documentation) are
the Pezkuwi SDK documentation resources.
- 👥 Additionally, there are [GitHub issues](https://github.com/pezkuwichain/pezkuwi-sdk/issues) and
[Substrate StackExchange](https://exchange.pezkuwichain.app/).
- 👥You can also reach out on the [Official Pezkuwi discord server](https://polkadot-discord.w3f.tools/)
- 🧑Reach out on [Telegram](https://t.me/substratedevs) for more questions and discussions
+270
View File
@@ -0,0 +1,270 @@
<div align="center">
# Pezkuwi SDK's Teyrchain Template
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/Polkadot_Logo_Horizontal_Pink_White.png#gh-dark-mode-only"/>
<img height="70px" alt="Pezkuwi SDK Logo" src="https://github.com/pezkuwichain/pezkuwi-sdk/raw/master/docs/images/Polkadot_Logo_Horizontal_Pink_Black.png#gh-light-mode-only"/>
> This is a template for creating a [teyrchain](https://wiki.network.pezkuwichain.io/docs/learn-parachains) based on Pezkuwi SDK.
>
> This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
</div>
## Table of Contents
- [Intro](#intro)
- [Template Structure](#template-structure)
- [Getting Started](#getting-started)
- [Starting a Development Chain](#starting-a-development-chain)
- [Omni Node](#omni-node-prerequisites)
- [Zombienet setup with Omni Node](#zombienet-setup-with-omni-node)
- [Teyrchain Template Node](#teyrchain-template-node)
- [Connect with the Pezkuwi-JS Apps Front-End](#connect-with-the-pezkuwi-js-apps-front-end)
- [Takeaways](#takeaways)
- [Runtime development](#runtime-development)
- [Contributing](#contributing)
- [Getting Help](#getting-help)
## Intro
- ⏫ This template provides a starting point to build a [teyrchain](https://wiki.network.pezkuwichain.io/docs/learn-parachains).
- ☁️ It is based on the
[Cumulus](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/cumulus/index.html) framework.
- 🔧 Its runtime is configured with a single custom pallet as a starting point, and a handful of ready-made pallets
such as a [Balances pallet](https://docs.pezkuwichain.io/sdk/master/pallet_balances/index.html).
- 👉 Learn more about teyrchains [here](https://wiki.network.pezkuwichain.io/docs/learn-parachains)
## Template Structure
A Pezkuwi SDK based project such as this one consists of:
- 🧮 the [Runtime](./runtime/README.md) - the core logic of the teyrchain.
- 🎨 the [Pallets](./pallets/README.md) - from which the runtime is constructed.
- 💿 a [Node](./node/README.md) - the binary application, not part of the project default-members list and not compiled unless
building the project with `--workspace` flag, which builds all workspace members, and is an alternative to
[Omni Node](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html).
## Getting Started
- 🦀 The template is using the Rust language.
- 👉 Check the
[Rust installation instructions](https://www.rust-lang.org/tools/install) for your system.
- 🛠️ Depending on your operating system and Rust version, there might be additional
packages required to compile this template - please take note of the Rust compiler output.
Fetch teyrchain template code:
```sh
git clone https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template.git teyrchain-template
cd teyrchain-template
```
## Starting a Development Chain
The teyrchain template relies on a hardcoded teyrchain id which is defined in the runtime code
and referenced throughout the contents of this file as `{{TEYRCHAIN_ID}}`. Please replace
any command or file referencing this placeholder with the value of the `TEYRCHAIN_ID` constant:
```rust,ignore
pub const TEYRCHAIN_ID: u32 = 1000;
```
### Omni Node Prerequisites
[Omni Node](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/omni_node/index.html) can
be used to run the teyrchain template's runtime. `pezkuwi-omni-node` binary crate usage is described at a high-level
[on crates.io](https://crates.io/crates/polkadot-omni-node).
#### Install `pezkuwi-omni-node`
```sh
cargo install pezkuwi-omni-node
```
> For more advanced options, please see the installation section at [`crates.io/omni-node`](https://crates.io/crates/polkadot-omni-node).
#### Build `teyrchain-template-runtime`
```sh
cargo build --profile production
```
#### Install `staging-chain-spec-builder`
```sh
cargo install staging-chain-spec-builder
```
> For more advanced options, please see the installation section at [`crates.io/staging-chain-spec-builder`](https://crates.io/crates/staging-chain-spec-builder).
#### Use `chain-spec-builder` to generate the `chain_spec.json` file
```sh
chain-spec-builder create --relay-chain "pezkuwichain-local" --runtime \
target/release/wbuild/teyrchain-template-runtime/teyrchain_template_runtime.wasm named-preset development
```
**Note**: the `relay-chain` flag is required by Omni Node. The `relay-chain` value is set in accordance
with the relay chain ID where this instantiation of teyrchain-template will connect to.
#### Run Omni Node
Start Omni Node with the generated chain spec. We'll start it in development mode (without a relay chain config), producing
and finalizing blocks based on manual seal, configured below to seal a block with each second.
```bash
pezkuwi-omni-node --chain <path/to/chain_spec.json> --dev --dev-block-time 1000
```
However, such a setup is not close to what would run in production, and for that we need to setup a local
relay chain network that will help with the block finalization. In this guide we'll setup a local relay chain
as well. We'll not do it manually, by starting one node at a time, but we'll use [zombienet](https://paritytech.github.io/zombienet/intro.html).
Follow through the next section for more details on how to do it.
### Zombienet setup with Omni Node
Assuming we continue from the last step of the previous section, we have a chain spec and we need to setup a relay chain.
We can install `zombienet` as described [here](https://paritytech.github.io/zombienet/install.html#installation), and
`zombienet-omni-node.toml` contains the network specification we want to start.
#### Relay chain prerequisites
Download the `pezkuwi` (and the accompanying `pezkuwi-prepare-worker` and `pezkuwi-execute-worker`) binaries from
[Pezkuwi SDK releases](https://github.com/pezkuwichain/pezkuwi-sdk/releases). Then expose them on `PATH` like so:
```sh
export PATH="$PATH:<path/to/binaries>"
```
#### Update `zombienet-omni-node.toml` with a valid chain spec path
To simplify the process of using the teyrchain-template with zombienet and Omni Node, we've added a pre-configured
development chain spec (dev_chain_spec.json) to the teyrchain template. The zombienet-omni-node.toml file of this
template points to it, but you can update it to an updated chain spec generated on your machine. To generate a
chain spec refer to [staging-chain-spec-builder](https://crates.io/crates/staging-chain-spec-builder)
Then make the changes in the network specification like so:
```toml
# ...
[[teyrchains]]
id = "<TEYRCHAIN_ID>"
chain_spec_path = "<TO BE UPDATED WITH A VALID PATH>"
# ...
```
#### Start the network
```sh
zombienet --provider native spawn zombienet-omni-node.toml
```
### Teyrchain Template Node
As mentioned in the `Template Structure` section, the `node` crate is optionally compiled and it is an alternative
to `Omni Node`. Similarly, it requires setting up a relay chain, and we'll use `zombienet` once more.
#### Install the `teyrchain-template-node`
```sh
cargo install --path node --locked
```
#### Setup and start the network
For setup, please consider the instructions for `zombienet` installation [here](https://paritytech.github.io/zombienet/install.html#installation)
and [relay chain prerequisites](#relay-chain-prerequisites).
We're left just with starting the network:
```sh
zombienet --provider native spawn zombienet.toml
```
### Connect with the Pezkuwi-JS Apps Front-End
- 🌐 You can interact with your local node using the
hosted version of the Pezkuwi/Substrate Portal:
[relay chain](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9944)
and [teyrchain](https://pezkuwichain.io/#/explorer?rpc=ws://localhost:9988).
- 🪐 A hosted version is also
available on [IPFS](https://dotapps.io/).
- 🧑‍🔧 You can also find the source code and instructions for hosting your own instance in the
[`pezkuwi-js/apps`](https://github.com/polkadot-js/apps) repository.
### Takeaways
Development teyrchains:
- 🔗 Connect to relay chains, and we showcased how to connect to a local one.
- 🧹 Do not persist the state.
- 💰 Are preconfigured with a genesis state that includes several prefunded development accounts.
- 🧑‍⚖️ Development accounts are used as validators, collators, and `sudo` accounts.
## Runtime development
We recommend using [`chopsticks`](https://github.com/AcalaNetwork/chopsticks) when the focus is more on the runtime
development and `OmniNode` is enough as is.
### Install chopsticks
To use `chopsticks`, please install the latest version according to the installation [guide](https://github.com/AcalaNetwork/chopsticks?tab=readme-ov-file#install).
### Build a raw chain spec
Build the `teyrchain-template-runtime` as mentioned before in this guide and use `chain-spec-builder`
again but this time by passing `--raw-storage` flag:
```sh
chain-spec-builder create --raw-storage --relay-chain "pezkuwichain-local" --runtime \
target/release/wbuild/teyrchain-template-runtime/teyrchain_template_runtime.wasm named-preset development
```
### Start `chopsticks` with the chain spec
```sh
npx @acala-network/chopsticks@latest --chain-spec <path/to/chain_spec.json>
```
### Alternatives
`OmniNode` can be still used for runtime development if using the `--dev` flag, while `teyrchain-template-node` doesn't
support it at this moment. It can still be used to test a runtime in a full setup where it is started alongside a
relay chain network (see [Teyrchain Template node](#teyrchain-template-node) setup).
## Contributing
- 🔄 This template is automatically updated after releases in the main [Pezkuwi SDK monorepo](https://github.com/pezkuwichain/pezkuwi-sdk).
- ➡️ Any pull requests should be directed to this [source](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/templates/teyrchain).
- 😇 Please refer to the monorepo's
[contribution guidelines](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CONTRIBUTING.md) and
[Code of Conduct](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/CODE_OF_CONDUCT.md).
## Getting Help
- 🧑‍🏫 To learn about Pezkuwi in general, [docs.Pezkuwi.com](https://docs.pezkuwichain.io/) website is a good starting point.
- 🧑‍🔧 For technical introduction, [here](https://github.com/pezkuwichain/pezkuwi-sdk#-documentation) are
the Pezkuwi SDK documentation resources.
- 👥 Additionally, there are [GitHub issues](https://github.com/pezkuwichain/pezkuwi-sdk/issues) and
[Substrate StackExchange](https://exchange.pezkuwichain.app/).
- 👥You can also reach out on the [Official Pezkuwi discord server](https://polkadot-discord.w3f.tools/)
- 🧑Reach out on [Telegram](https://t.me/substratedevs) for more questions and discussions
File diff suppressed because one or more lines are too long
+46
View File
@@ -0,0 +1,46 @@
[package]
name = "teyrchain-template-node"
description = "A teyrchain node template built with Substrate and Cumulus, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
build = "build.rs"
[lints]
workspace = true
[dependencies]
clap = { features = ["derive"], workspace = true }
codec = { workspace = true, default-features = true }
color-print = { workspace = true }
docify = { workspace = true }
futures = { workspace = true }
jsonrpsee = { features = ["server"], workspace = true }
log = { workspace = true, default-features = true }
serde = { features = ["derive"], workspace = true, default-features = true }
pezkuwi-sdk = { workspace = true, features = ["node", "pezkuwi-primitives"] }
teyrchain-template-runtime = { workspace = true }
# Substrate
prometheus-endpoint = { workspace = true, default-features = true }
[build-dependencies]
pezkuwi-sdk = { workspace = true, features = ["substrate-build-script-utils"] }
[features]
default = ["std"]
std = ["log/std", "pezkuwi-sdk/std", "teyrchain-template-runtime/std"]
runtime-benchmarks = [
"pezkuwi-sdk/runtime-benchmarks",
"teyrchain-template-runtime/runtime-benchmarks",
]
try-runtime = [
"pezkuwi-sdk/try-runtime",
"teyrchain-template-runtime/try-runtime",
]
+18
View File
@@ -0,0 +1,18 @@
# Node
️ A node - in PezkuwiChain - is a binary executable, whose primary purpose is to execute the [runtime](../runtime/README.md).
🔗 It communicates with other nodes in the network, and aims for
[consensus](https://wiki.network.pezkuwichain.io/docs/learn-consensus) among them.
⚙️ It acts as a remote procedure call (RPC) server, allowing interaction with the blockchain.
👉 Learn more about the architecture, and the difference between a node and a runtime
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/wasm_meta_protocol/index.html).
👇 Here are the most important files in this node template:
- [`chain_spec.rs`](./src/chain_spec.rs): A chain specification is a source code file that defines the chain's
initial (genesis) state.
- [`service.rs`](./src/service.rs): This file defines the node implementation.
It's a place to configure consensus-related topics.
+7
View File
@@ -0,0 +1,7 @@
use pezkuwi_sdk::substrate_build_script_utils::{generate_cargo_keys, rerun_if_git_head_changed};
fn main() {
generate_cargo_keys();
rerun_if_git_head_changed();
}
@@ -0,0 +1,65 @@
use pezkuwi_sdk::*;
use sc_chain_spec::{ChainSpecExtension, ChainSpecGroup};
use sc_service::ChainType;
use serde::{Deserialize, Serialize};
use teyrchain_template_runtime as runtime;
/// Specialized `ChainSpec` for the normal teyrchain runtime.
pub type ChainSpec = sc_service::GenericChainSpec<Extensions>;
/// The relay chain that you want to configure this teyrchain to connect to.
pub const RELAY_CHAIN: &str = "pezkuwichain-local";
/// The extensions for the [`ChainSpec`].
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ChainSpecGroup, ChainSpecExtension)]
pub struct Extensions {
/// The relay chain of the Teyrchain.
#[serde(alias = "relayChain", alias = "RelayChain")]
pub relay_chain: String,
}
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())
}
}
pub fn development_chain_spec() -> 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(
runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: RELAY_CHAIN.into() },
)
.with_name("Development")
.with_id("dev")
.with_chain_type(ChainType::Development)
.with_genesis_config_preset_name(sp_genesis_builder::DEV_RUNTIME_PRESET)
.with_properties(properties)
.build()
}
pub fn local_chain_spec() -> 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(
runtime::WASM_BINARY.expect("WASM binary was not built, please build it!"),
Extensions { relay_chain: RELAY_CHAIN.into() },
)
.with_name("Local Testnet")
.with_id("local_testnet")
.with_chain_type(ChainType::Local)
.with_genesis_config_preset_name(sc_chain_spec::LOCAL_TESTNET_RUNTIME_PRESET)
.with_protocol_id("template-local")
.with_properties(properties)
.build()
}
+120
View File
@@ -0,0 +1,120 @@
use pezkuwi_sdk::*;
use std::path::PathBuf;
/// Sub-commands supported by the collator.
#[allow(clippy::large_enum_variant)]
#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
/// Build a chain specification.
/// DEPRECATED: `build-spec` command will be removed after 1/04/2026. Use `export-chain-spec`
/// command instead.
#[deprecated(
note = "build-spec command will be removed after 1/04/2026. Use export-chain-spec command instead"
)]
BuildSpec(sc_cli::BuildSpecCmd),
/// Export the chain specification.
ExportChainSpec(sc_cli::ExportChainSpecCmd),
/// 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 teyrchain.
///
/// Head data is the encoded block header.
#[command(alias = "export-genesis-state")]
ExportGenesisHead(cumulus_client_cli::ExportGenesisHeadCommand),
/// Export the genesis wasm of the teyrchain.
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),
}
const AFTER_HELP_EXAMPLE: &str = color_print::cstr!(
r#"<bold><underline>Examples:</></>
<bold>teyrchain-template-node build-spec --disable-default-bootnode > plain-teyrchain-chainspec.json</>
Export a chainspec for a local testnet in json format.
<bold>teyrchain-template-node --chain plain-teyrchain-chainspec.json --tmp -- --chain pezkuwichain-local</>
Launch a full node with chain specification loaded from plain-teyrchain-chainspec.json.
<bold>teyrchain-template-node</>
Launch a full node with default teyrchain <italic>local-testnet</> and relay chain <italic>pezkuwichain-local</>.
<bold>teyrchain-template-node --collator</>
Launch a collator with default teyrchain <italic>local-testnet</> and relay chain <italic>pezkuwichain-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: pezkuwi_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("pezkuwi");
Self {
base_path: Some(base_path),
chain_id,
base: clap::Parser::parse_from(relay_chain_args),
}
}
}
+383
View File
@@ -0,0 +1,383 @@
use pezkuwi_sdk::*;
use cumulus_client_service::storage_proof_size::HostFunctions as ReclaimHostFunctions;
use frame_benchmarking_cli::{BenchmarkCmd, SUBSTRATE_REFERENCE_HARDWARE};
use log::info;
use sc_cli::{
ChainSpec, CliConfiguration, DefaultConfigurationValues, ImportParams, KeystoreParams,
NetworkParams, Result, RpcEndpoint, SharedParams, SubstrateCli,
};
use sc_service::config::{BasePath, PrometheusConfig};
use teyrchain_template_runtime::Block;
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_chain_spec()),
"template-pezkuwichain" => Box::new(chain_spec::local_chain_spec()),
"" | "local" => Box::new(chain_spec::local_chain_spec()),
path => Box::new(chain_spec::ChainSpec::from_json_file(std::path::PathBuf::from(path))?),
})
}
impl SubstrateCli for Cli {
fn impl_name() -> String {
"Teyrchain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
format!(
"Teyrchain Collator Template\n\nThe command-line arguments provided first will be \
passed to the teyrchain node, while the arguments provided after -- will be passed \
to the relay chain node.\n\n\
{} <teyrchain-args> -- <relay-chain-args>",
Self::executable_name()
)
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/pezkuwichain/pezkuwi-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 {
"Teyrchain Collator Template".into()
}
fn impl_version() -> String {
env!("SUBSTRATE_CLI_IMPL_VERSION").into()
}
fn description() -> String {
format!(
"Teyrchain Collator Template\n\nThe command-line arguments provided first will be \
passed to the teyrchain node, while the arguments provided after -- will be passed \
to the relay chain node.\n\n\
{} <teyrchain-args> -- <relay-chain-args>",
Self::executable_name()
)
}
fn author() -> String {
env!("CARGO_PKG_AUTHORS").into()
}
fn support_url() -> String {
"https://github.com/pezkuwichain/pezkuwi-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> {
pezkuwi_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 {
#[allow(deprecated)]
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::ExportChainSpec(cmd)) => {
let chain_spec = cli.load_spec(&cmd.chain)?;
cmd.run(chain_spec)
},
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 pezkuwi_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
);
let pezkuwi_config = SubstrateCli::create_configuration(
&pezkuwi_cli,
&pezkuwi_cli,
config.tokio_handle.clone(),
)
.map_err(|err| format!("Relay chain argument error: {err}"))?;
cmd.run(config, pezkuwi_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_with_spec::<sp_runtime::traits::HashingFor<Block>, ReclaimHostFunctions>(Some(config.chain_spec)))
} 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();
let shared_cache = partials.backend.expose_shared_trie_cache();
cmd.run(config, partials.client.clone(), db, storage, shared_cache)
}),
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()),
}
},
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(|| {
config.database.path().map(|database_path| {
let _ = std::fs::create_dir_all(database_path);
sc_sysinfo::gather_hwbench(
Some(database_path),
&SUBSTRATE_REFERENCE_HARDWARE,
)
})
})
.flatten();
let pezkuwi_cli = RelayChainCli::new(
&config,
[RelayChainCli::executable_name()].iter().chain(cli.relay_chain_args.iter()),
);
let tokio_handle = config.tokio_handle.clone();
let pezkuwi_config =
SubstrateCli::create_configuration(&pezkuwi_cli, &pezkuwi_cli, tokio_handle)
.map_err(|err| format!("Relay chain argument error: {err}"))?;
info!("Is collating: {}", if config.role.is_authority() { "yes" } else { "no" });
crate::service::start_teyrchain_node(
config,
pezkuwi_config,
collator_options,
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<Vec<RpcEndpoint>>> {
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) -> Result<()>
where
F: FnOnce(&mut sc_cli::LoggerBuilder),
{
unreachable!("PezkuwiCli 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()
}
}
+15
View File
@@ -0,0 +1,15 @@
//! Substrate Teyrchain Node Template CLI
#![warn(missing_docs)]
use pezkuwi_sdk::*;
mod chain_spec;
mod cli;
mod command;
mod rpc;
mod service;
fn main() -> sc_cli::Result<()> {
command::run()
}
+55
View File
@@ -0,0 +1,55 @@
//! 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 teyrchain_template_runtime::{opaque::Block, AccountId, Balance, Nonce};
use pezkuwi_sdk::*;
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>,
}
/// 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>
+ 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 } = deps;
module.merge(System::new(client.clone(), pool).into_rpc())?;
module.merge(TransactionPayment::new(client).into_rpc())?;
Ok(module)
}
+448
View File
@@ -0,0 +1,448 @@
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
// std
use std::{sync::Arc, time::Duration};
// Local Runtime Types
use teyrchain_template_runtime::{
apis::RuntimeApi,
opaque::{Block, Hash},
};
use codec::Encode;
use pezkuwi_sdk::{cumulus_client_service::TeyrchainTracingExecuteBlock, *};
// Cumulus Imports
use cumulus_client_bootnodes::{start_bootnode_tasks, StartBootnodeTasksParams};
use cumulus_client_cli::CollatorOptions;
use cumulus_client_collator::service::CollatorService;
#[docify::export(lookahead_collator)]
use cumulus_client_consensus_aura::collators::lookahead::{self as aura, Params as AuraParams};
use cumulus_client_consensus_common::TeyrchainBlockImport as TTeyrchainBlockImport;
use cumulus_client_service::{
build_network, build_relay_chain_interface, prepare_node_config, start_relay_chain_tasks,
BuildNetworkParams, CollatorSybilResistance, DARecoveryProfile, StartRelayChainTasksParams,
TeyrchainHostFunctions,
};
#[docify::export(cumulus_primitives)]
use cumulus_primitives_core::{
relay_chain::{CollatorPair, ValidationCode},
GetTeyrchainInfo, ParaId,
};
use cumulus_relay_chain_interface::{OverseerHandle, RelayChainInterface};
// Substrate Imports
use frame_benchmarking_cli::SUBSTRATE_REFERENCE_HARDWARE;
use pezkuwi_sdk::sc_network::PeerId;
use prometheus_endpoint::Registry;
use sc_client_api::Backend;
use sc_consensus::ImportQueue;
use sc_executor::{HeapAllocStrategy, WasmExecutor, DEFAULT_HEAP_ALLOC_STRATEGY};
use sc_network::{NetworkBackend, NetworkBlock};
use sc_service::{Configuration, PartialComponents, TFullBackend, TFullClient, TaskManager};
use sc_telemetry::{Telemetry, TelemetryHandle, TelemetryWorker, TelemetryWorkerHandle};
use sc_transaction_pool_api::OffchainTransactionPoolFactory;
use sp_api::ProvideRuntimeApi;
use sp_keystore::KeystorePtr;
#[docify::export(wasm_executor)]
type TeyrchainExecutor = WasmExecutor<TeyrchainHostFunctions>;
type TeyrchainClient = TFullClient<Block, RuntimeApi, TeyrchainExecutor>;
type TeyrchainBackend = TFullBackend<Block>;
type TeyrchainBlockImport = TTeyrchainBlockImport<Block, Arc<TeyrchainClient>, TeyrchainBackend>;
/// Assembly of PartialComponents (enough to run chain ops subcommands)
pub type Service = PartialComponents<
TeyrchainClient,
TeyrchainBackend,
(),
sc_consensus::DefaultImportQueue<Block>,
sc_transaction_pool::TransactionPoolHandle<Block, TeyrchainClient>,
(TeyrchainBlockImport, Option<Telemetry>, Option<TelemetryWorkerHandle>),
>;
/// 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.
#[docify::export(component_instantiation)]
pub fn new_partial(config: &Configuration) -> Result<Service, 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
.executor
.default_heap_pages
.map_or(DEFAULT_HEAP_ALLOC_STRATEGY, |h| HeapAllocStrategy::Static { extra_pages: h as _ });
let executor = TeyrchainExecutor::builder()
.with_execution_method(config.executor.wasm_method)
.with_onchain_heap_alloc_strategy(heap_pages)
.with_offchain_heap_alloc_strategy(heap_pages)
.with_max_runtime_instances(config.executor.max_runtime_instances)
.with_runtime_cache_size(config.executor.runtime_cache_size)
.build();
let (client, backend, keystore_container, task_manager) =
sc_service::new_full_parts_record_import::<Block, RuntimeApi, _>(
config,
telemetry.as_ref().map(|(_, telemetry)| telemetry.handle()),
executor,
true,
)?;
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 = Arc::from(
sc_transaction_pool::Builder::new(
task_manager.spawn_essential_handle(),
client.clone(),
config.role.is_authority().into(),
)
.with_options(config.transaction_pool.clone())
.with_prometheus(config.prometheus_registry())
.build(),
);
let block_import = TeyrchainBlockImport::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),
})
}
/// Build the import queue for the teyrchain runtime.
fn build_import_queue(
client: Arc<TeyrchainClient>,
block_import: TeyrchainBlockImport,
config: &Configuration,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
) -> sc_consensus::DefaultImportQueue<Block> {
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)
},
&task_manager.spawn_essential_handle(),
config.prometheus_registry(),
telemetry,
)
}
#[allow(clippy::too_many_arguments)]
fn start_consensus(
client: Arc<TeyrchainClient>,
backend: Arc<TeyrchainBackend>,
block_import: TeyrchainBlockImport,
prometheus_registry: Option<&Registry>,
telemetry: Option<TelemetryHandle>,
task_manager: &TaskManager,
relay_chain_interface: Arc<dyn RelayChainInterface>,
transaction_pool: Arc<sc_transaction_pool::TransactionPoolHandle<Block, TeyrchainClient>>,
keystore: KeystorePtr,
relay_chain_slot_duration: Duration,
para_id: ParaId,
collator_key: CollatorPair,
collator_peer_id: PeerId,
overseer_handle: OverseerHandle,
announce_block: Arc<dyn Fn(Hash, Option<Vec<u8>>) + Send + Sync>,
) -> Result<(), sc_service::Error> {
let proposer = sc_basic_authorship::ProposerFactory::with_proof_recording(
task_manager.spawn_handle(),
client.clone(),
transaction_pool,
prometheus_registry,
telemetry.clone(),
);
let collator_service = CollatorService::new(
client.clone(),
Arc::new(task_manager.spawn_handle()),
announce_block,
client.clone(),
);
let params = AuraParams {
create_inherent_data_providers: move |_, ()| async move { Ok(()) },
block_import,
para_client: client.clone(),
para_backend: backend,
relay_client: relay_chain_interface,
code_hash_provider: move |block_hash| {
client.code_at(block_hash).ok().map(|c| ValidationCode::from(c).hash())
},
keystore,
collator_key,
collator_peer_id,
para_id,
overseer_handle,
relay_chain_slot_duration,
proposer,
collator_service,
authoring_duration: Duration::from_millis(2000),
reinitialize: false,
max_pov_percentage: None,
};
let fut = aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _>(
params,
);
task_manager.spawn_essential_handle().spawn("aura", None, fut);
Ok(())
}
/// Start a node with the given teyrchain `Configuration` and relay chain `Configuration`.
#[sc_tracing::logging::prefix_logs_with("Teyrchain")]
pub async fn start_teyrchain_node(
teyrchain_config: Configuration,
pezkuwi_config: Configuration,
collator_options: CollatorOptions,
hwbench: Option<sc_sysinfo::HwBench>,
) -> sc_service::error::Result<(TaskManager, Arc<TeyrchainClient>)> {
let teyrchain_config = prepare_node_config(teyrchain_config);
let params = new_partial(&teyrchain_config)?;
let (block_import, mut telemetry, telemetry_worker_handle) = params.other;
let prometheus_registry = teyrchain_config.prometheus_registry().cloned();
let net_config = sc_network::config::FullNetworkConfiguration::<
_,
_,
sc_network::NetworkWorker<Block, Hash>,
>::new(&teyrchain_config.network, prometheus_registry.clone());
let client = params.client.clone();
let backend = params.backend.clone();
let mut task_manager = params.task_manager;
let relay_chain_fork_id = pezkuwi_config.chain_spec.fork_id().map(ToString::to_string);
let teyrchain_fork_id = teyrchain_config.chain_spec.fork_id().map(ToString::to_string);
let advertise_non_global_ips = teyrchain_config.network.allow_non_globals_in_dht;
let teyrchain_public_addresses = teyrchain_config.network.public_addresses.clone();
let (relay_chain_interface, collator_key, relay_chain_network, paranode_rx) =
build_relay_chain_interface(
pezkuwi_config,
&teyrchain_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 = teyrchain_config.role.is_authority();
let transaction_pool = params.transaction_pool.clone();
let import_queue_service = params.import_queue.service();
// Take teyrchain id from runtime.
let best_hash = client.chain_info().best_hash;
let para_id = client
.runtime_api()
.teyrchain_id(best_hash)
.map_err(|_| "Failed to retrieve teyrchain id from runtime. Make sure you implement `cumulus_primitives_core::GetParachaiNidentity` runtime API.")?;
// NOTE: because we use Aura here explicitly, we can use `CollatorSybilResistance::Resistant`
// when starting the network.
let (network, system_rpc_tx, tx_handler_controller, sync_service) =
build_network(BuildNetworkParams {
teyrchain_config: &teyrchain_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
metrics: sc_network::NetworkWorker::<Block, Hash>::register_notification_metrics(
teyrchain_config.prometheus_config.as_ref().map(|config| &config.registry),
),
})
.await?;
let collator_peer_id = network.local_peer_id();
if teyrchain_config.offchain_worker.enabled {
use futures::FutureExt;
let offchain_workers =
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: Arc::new(network.clone()),
is_validator: teyrchain_config.role.is_authority(),
enable_http_requests: false,
custom_extensions: move |_| vec![],
})?;
task_manager.spawn_handle().spawn(
"offchain-workers-runner",
"offchain-work",
offchain_workers.run(client.clone(), task_manager.spawn_handle()).boxed(),
);
}
let rpc_builder = {
let client = client.clone();
let transaction_pool = transaction_pool.clone();
Box::new(move |_| {
let deps =
crate::rpc::FullDeps { client: client.clone(), pool: transaction_pool.clone() };
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: teyrchain_config,
keystore: params.keystore_container.keystore(),
backend: backend.clone(),
network: network.clone(),
sync_service: sync_service.clone(),
system_rpc_tx,
tx_handler_controller,
telemetry: telemetry.as_mut(),
tracing_execute_block: Some(Arc::new(TeyrchainTracingExecuteBlock::new(client.clone()))),
})?;
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, false) {
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(),
prometheus_registry: prometheus_registry.as_ref(),
})?;
start_bootnode_tasks(StartBootnodeTasksParams {
embedded_dht_bootnode: collator_options.embedded_dht_bootnode,
dht_bootnode_discovery: collator_options.dht_bootnode_discovery,
para_id,
task_manager: &mut task_manager,
relay_chain_interface: relay_chain_interface.clone(),
relay_chain_fork_id,
relay_chain_network,
request_receiver: paranode_rx,
teyrchain_network: network,
advertise_non_global_ips,
teyrchain_genesis_hash: client.chain_info().genesis_hash.encode(),
teyrchain_fork_id,
teyrchain_public_addresses,
});
if validator {
start_consensus(
client.clone(),
backend,
block_import,
prometheus_registry.as_ref(),
telemetry.as_ref().map(|t| t.handle()),
&task_manager,
relay_chain_interface,
transaction_pool,
params.keystore_container.keystore(),
relay_chain_slot_duration,
para_id,
collator_key.expect("Command line arguments do not allow this. qed"),
collator_peer_id,
overseer_handle,
announce_block,
)?;
}
Ok((task_manager, client))
}
+13
View File
@@ -0,0 +1,13 @@
# Pallets
️ A pallet is a unit of encapsulated logic, with a clearly defined responsibility. A pallet is analogous to a
module in the runtime.
💁 In this template, there is a simple custom pallet based on the FRAME framework.
👉 Learn more about FRAME
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
🧑‍🏫 Please refer to
[this guide](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html)
to learn how to write a basic pallet.
@@ -0,0 +1,31 @@
[package]
name = "pallet-teyrchain-template"
description = "FRAME pallet template for defining custom runtime logic."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[lints]
workspace = true
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[dependencies]
codec = { features = ["derive"], workspace = true }
scale-info = { features = ["derive"], workspace = true }
frame = { workspace = true, default-features = false, features = [
"experimental",
"runtime",
] }
[features]
default = ["std"]
runtime-benchmarks = ["frame/runtime-benchmarks"]
std = ["codec/std", "frame/std", "scale-info/std"]
try-runtime = ["frame/try-runtime"]
@@ -0,0 +1,33 @@
//! Benchmarking setup for pallet-template
use super::*;
use frame::{deps::frame_benchmarking::v2::*, prelude::*};
#[benchmarks]
mod benchmarks {
use super::*;
#[cfg(test)]
use crate::pallet::Pallet as Template;
use frame_system::RawOrigin;
#[benchmark]
fn do_something() {
let caller: T::AccountId = whitelisted_caller();
#[extrinsic_call]
do_something(RawOrigin::Signed(caller), 100);
assert_eq!(Something::<T>::get().map(|v| v.block_number), Some(100u32.into()));
}
#[benchmark]
fn cause_error() {
Something::<T>::put(CompositeStruct { block_number: 100u32.into() });
let caller: T::AccountId = whitelisted_caller();
#[extrinsic_call]
cause_error(RawOrigin::Signed(caller));
assert_eq!(Something::<T>::get().map(|v| v.block_number), Some(101u32.into()));
}
impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test);
}
@@ -0,0 +1,183 @@
//! # Template Pallet
//!
//! A pallet with minimal functionality to help developers understand the essential components of
//! writing a FRAME pallet. It is typically used in beginner tutorials or in Pezkuwi SDK template
//! as a starting point for creating a new pallet and **not meant to be used in production**.
//!
//! ## Overview
//!
//! This template pallet contains basic examples of:
//! - declaring a storage item that stores a single block-number
//! - declaring and using events
//! - declaring and using errors
//! - a dispatchable function that allows a user to set a new value to storage and emits an event
//! upon success
//! - another dispatchable function that causes a custom error to be thrown
//!
//! Each pallet section is annotated with an attribute using the `#[pallet::...]` procedural macro.
//! This macro generates the necessary code for a pallet to be aggregated into a FRAME runtime.
//!
//! To get started with pallet development, consider using this tutorial:
//!
//! <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html>
//!
//! And reading the main documentation of the `frame` crate:
//!
//! <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html>
//!
//! And looking at the frame [`kitchen-sink`](https://docs.pezkuwichain.io/sdk/master/pallet_example_kitchensink/index.html)
//! pallet, a showcase of all pallet macros.
//!
//! ### Pallet Sections
//!
//! The pallet sections in this template are:
//!
//! - A **configuration trait** that defines the types and parameters which the pallet depends on
//! (denoted by the `#[pallet::config]` attribute). See: [`Config`].
//! - A **means to store pallet-specific data** (denoted by the `#[pallet::storage]` attribute).
//! See: [`storage_types`].
//! - A **declaration of the events** this pallet emits (denoted by the `#[pallet::event]`
//! attribute). See: [`Event`].
//! - A **declaration of the errors** that this pallet can throw (denoted by the `#[pallet::error]`
//! attribute). See: [`Error`].
//! - A **set of dispatchable functions** that define the pallet's functionality (denoted by the
//! `#[pallet::call]` attribute). See: [`dispatchables`].
//!
//! Run `cargo doc --package pallet-template --open` to view this pallet's documentation.
#![cfg_attr(not(feature = "std"), no_std)]
pub use pallet::*;
#[cfg(test)]
mod mock;
#[cfg(test)]
mod tests;
pub mod weights;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html>
// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html>
//
// To see a full list of `pallet` macros and their use cases, see:
// <https://docs.pezkuwichain.io/sdk/master/pallet_example_kitchensink/index.html>
// <https://docs.pezkuwichain.io/sdk/master/frame_support/pallet_macros/index.html>
#[frame::pallet]
pub mod pallet {
use frame::prelude::*;
/// Configure the pallet by specifying the parameters and types on which it depends.
#[pallet::config]
pub trait Config: frame_system::Config {
#[allow(deprecated)]
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// A type representing the weights required by the dispatchables of this pallet.
type WeightInfo: crate::weights::WeightInfo;
}
#[pallet::pallet]
pub struct Pallet<T>(_);
/// A struct to store a single block-number. Has all the right derives to store it in storage.
/// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/frame_storage_derives/index.html>
#[derive(
Encode, Decode, MaxEncodedLen, TypeInfo, CloneNoBound, PartialEqNoBound, DefaultNoBound,
)]
#[scale_info(skip_type_params(T))]
pub struct CompositeStruct<T: Config> {
/// A block number.
pub(crate) block_number: BlockNumberFor<T>,
}
/// The pallet's storage items.
/// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html#storage>
/// <https://docs.pezkuwichain.io/sdk/master/frame_support/pallet_macros/attr.storage.html>
#[pallet::storage]
pub type Something<T: Config> = StorageValue<_, CompositeStruct<T>>;
/// Pallets use events to inform users when important changes are made.
/// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html#event-and-error>
#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
pub enum Event<T: Config> {
/// We usually use passive tense for events.
SomethingStored { block_number: BlockNumberFor<T>, who: T::AccountId },
}
/// Errors inform users that something went wrong.
/// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html#event-and-error>
#[pallet::error]
pub enum Error<T> {
/// Error names should be descriptive.
NoneValue,
/// Errors should have helpful documentation associated with them.
StorageOverflow,
}
#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
/// Dispatchable functions allows users to interact with the pallet and invoke state changes.
/// These functions materialize as "extrinsics", which are often compared to transactions.
/// Dispatchable functions must be annotated with a weight and must return a DispatchResult.
/// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/guides/your_first_pallet/index.html#dispatchables>
#[pallet::call]
impl<T: Config> Pallet<T> {
/// An example dispatchable that takes a singles value as a parameter, writes the value to
/// storage and emits an event. This function must be dispatched by a signed extrinsic.
#[pallet::call_index(0)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().writes(1))]
pub fn do_something(origin: OriginFor<T>, bn: u32) -> DispatchResultWithPostInfo {
// Check that the extrinsic was signed and get the signer.
// This function will return an error if the extrinsic is not signed.
// <https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/frame_origin/index.html>
let who = ensure_signed(origin)?;
// Convert the u32 into a block number. This is possible because the set of trait bounds
// defined in [`frame_system::Config::BlockNumber`].
let block_number: BlockNumberFor<T> = bn.into();
// Update storage.
<Something<T>>::put(CompositeStruct { block_number });
// Emit an event.
Self::deposit_event(Event::SomethingStored { block_number, who });
// Return a successful [`DispatchResultWithPostInfo`] or [`DispatchResult`].
Ok(().into())
}
/// An example dispatchable that may throw a custom error.
#[pallet::call_index(1)]
#[pallet::weight(Weight::from_parts(10_000, 0) + T::DbWeight::get().reads_writes(1,1))]
pub fn cause_error(origin: OriginFor<T>) -> DispatchResultWithPostInfo {
let _who = ensure_signed(origin)?;
// Read a value from storage.
match <Something<T>>::get() {
// Return an error if the value has not been set.
None => Err(Error::<T>::NoneValue)?,
Some(mut old) => {
// Increment the value read from storage; will error in the event of overflow.
old.block_number = old
.block_number
.checked_add(&One::one())
// ^^ equivalent is to:
// .checked_add(&1u32.into())
// both of which build a `One` instance for the type `BlockNumber`.
.ok_or(Error::<T>::StorageOverflow)?;
// Update the value in storage with the incremented result.
<Something<T>>::put(old);
// Explore how you can rewrite this using
// [`frame_support::storage::StorageValue::mutate`].
Ok(().into())
},
}
}
}
}
@@ -0,0 +1,48 @@
use frame::{
deps::{frame_support::weights::constants::RocksDbWeight, frame_system::GenesisConfig},
prelude::*,
runtime::prelude::*,
testing_prelude::*,
};
// Configure a mock runtime to test the pallet.
#[frame_construct_runtime]
mod test_runtime {
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Test;
#[runtime::pallet_index(0)]
pub type System = frame_system;
#[runtime::pallet_index(1)]
pub type Template = crate;
}
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Nonce = u64;
type Block = MockBlock<Test>;
type BlockHashCount = ConstU64<250>;
type DbWeight = RocksDbWeight;
}
impl crate::Config for Test {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
}
// Build genesis storage according to the mock runtime.
pub fn new_test_ext() -> TestState {
GenesisConfig::<Test>::default().build_storage().unwrap().into()
}
@@ -0,0 +1,20 @@
use crate::{mock::*, Error, Something};
use frame::testing_prelude::*;
#[test]
fn it_works_for_default_value() {
new_test_ext().execute_with(|| {
// Dispatch a signed extrinsic.
assert_ok!(Template::do_something(RuntimeOrigin::signed(1), 42));
// Read pallet storage and assert an expected result.
assert_eq!(Something::<Test>::get().map(|v| v.block_number), Some(42));
});
}
#[test]
fn correct_error_for_none_value() {
new_test_ext().execute_with(|| {
// Ensure the expected error is thrown when no value is present.
assert_noop!(Template::cause_error(RuntimeOrigin::signed(1)), Error::<Test>::NoneValue);
});
}
@@ -0,0 +1,96 @@
//! Autogenerated weights for pallet_template
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev
//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `_`, CPU: `<UNKNOWN>`
//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024
// Executed Command:
// ../../target/release/node-template
// benchmark
// pallet
// --chain
// dev
// --pallet
// pallet_template
// --extrinsic
// *
// --steps=50
// --repeat=20
// --wasm-execution=compiled
// --output
// pallets/template/src/weights.rs
// --template
// ../../.maintain/frame-weight-template.hbs
#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]
use frame::{deps::frame_support::weights::constants::RocksDbWeight, prelude::*};
use core::marker::PhantomData;
/// Weight functions needed for pallet_template.
pub trait WeightInfo {
fn do_something() -> Weight;
fn cause_error() -> Weight;
}
/// Weights for pallet_template using the Substrate node and recommended hardware.
#[cfg_attr(
not(feature = "std"),
deprecated(
note = "SubstrateWeight is auto-generated and should not be used in production. Replace it with runtime benchmarked weights."
)
)]
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: Template Something (r:0 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn do_something() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 8_000_000 picoseconds.
Weight::from_parts(9_000_000, 0)
.saturating_add(T::DbWeight::get().writes(1_u64))
}
/// Storage: Template Something (r:1 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn cause_error() -> Weight {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1489`
// Minimum execution time: 6_000_000 picoseconds.
Weight::from_parts(6_000_000, 1489)
.saturating_add(T::DbWeight::get().reads(1_u64))
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}
// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: Template Something (r:0 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn do_something() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 8_000_000 picoseconds.
Weight::from_parts(9_000_000, 0)
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
/// Storage: Template Something (r:1 w:1)
/// Proof: Template Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)
fn cause_error() -> Weight {
// Proof Size summary in bytes:
// Measured: `32`
// Estimated: `1489`
// Minimum execution time: 6_000_000 picoseconds.
Weight::from_parts(6_000_000, 1489)
.saturating_add(RocksDbWeight::get().reads(1_u64))
.saturating_add(RocksDbWeight::get().writes(1_u64))
}
}
+108
View File
@@ -0,0 +1,108 @@
[package]
name = "teyrchain-template-runtime"
description = "A teyrchain runtime template built with Substrate and Cumulus, part of Pezkuwi Sdk."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
[lints]
workspace = true
[dependencies]
codec = { features = ["derive"], workspace = true }
docify = { workspace = true }
hex-literal = { optional = true, workspace = true, default-features = true }
log = { workspace = true }
scale-info = { features = ["derive"], workspace = true }
serde_json = { workspace = true, default-features = false, features = [
"alloc",
] }
smallvec = { workspace = true, default-features = true }
# Local
pallet-teyrchain-template = { workspace = true }
pezkuwi-sdk = { workspace = true, default-features = false, features = [
"pallet-aura",
"pallet-authorship",
"pallet-balances",
"pallet-message-queue",
"pallet-session",
"pallet-sudo",
"pallet-timestamp",
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"pallet-xcm",
"pezkuwi-runtime-common",
"pezkuwi-teyrchain-primitives",
"staging-xcm",
"staging-xcm-builder",
"staging-xcm-executor",
"cumulus-pallet-aura-ext",
"cumulus-pallet-session-benchmarking",
"cumulus-pallet-weight-reclaim",
"cumulus-pallet-xcm",
"cumulus-pallet-xcmp-queue",
"cumulus-primitives-aura",
"cumulus-primitives-core",
"cumulus-primitives-utility",
"pallet-collator-selection",
"staging-teyrchain-info",
"teyrchains-common",
"runtime",
] }
# Cumulus
cumulus-pallet-teyrchain-system = { workspace = true }
[build-dependencies]
docify = { workspace = true }
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
[features]
default = ["std"]
std = [
"codec/std",
"cumulus-pallet-teyrchain-system/std",
"log/std",
"pallet-teyrchain-template/std",
"pezkuwi-sdk/std",
"scale-info/std",
"serde_json/std",
"substrate-wasm-builder",
]
runtime-benchmarks = [
"cumulus-pallet-teyrchain-system/runtime-benchmarks",
"hex-literal",
"pallet-teyrchain-template/runtime-benchmarks",
"pezkuwi-sdk/runtime-benchmarks",
"substrate-wasm-builder?/runtime-benchmarks",
]
try-runtime = [
"cumulus-pallet-teyrchain-system/try-runtime",
"pallet-teyrchain-template/try-runtime",
"pezkuwi-sdk/try-runtime",
]
# Enable the metadata hash generation.
#
# This is hidden behind a feature because it increases the compile time.
# The wasm binary needs to be compiled twice, once to fetch the metadata,
# generate the metadata hash and then a second time with the
# `RUNTIME_METADATA_HASH` environment variable set for the `CheckMetadataHash`
# extension.
metadata-hash = ["substrate-wasm-builder/metadata-hash"]
# A convenience feature for enabling things when doing a build
# for an on-chain release.
on-chain-release-build = ["metadata-hash"]
+10
View File
@@ -0,0 +1,10 @@
# Runtime
️ The runtime (in other words, a state transition function), refers to the core logic of the teyrchain that is
responsible for validating blocks and executing the state changes they define.
💁 The runtime in this template is constructed using ready-made FRAME pallets that ship with
[Pezkuwi SDK](https://github.com/pezkuwichain/pezkuwi-sdk), and a [template for a custom pallet](../pallets/README.md).
👉 Learn more about FRAME
[here](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/polkadot_sdk/frame_runtime/index.html).
+17
View File
@@ -0,0 +1,17 @@
#[cfg(all(feature = "std", feature = "metadata-hash"))]
#[docify::export(template_enable_metadata_hash)]
fn main() {
substrate_wasm_builder::WasmBuilder::init_with_defaults()
.enable_metadata_hash("UNIT", 12)
.build();
}
#[cfg(all(feature = "std", not(feature = "metadata-hash")))]
fn main() {
substrate_wasm_builder::WasmBuilder::build_using_defaults();
}
/// The wasm builder is deactivated when compiling
/// this crate for wasm to speed up the compilation.
#[cfg(not(feature = "std"))]
fn main() {}
+328
View File
@@ -0,0 +1,328 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
// External crates imports
use alloc::vec::Vec;
use pezkuwi_sdk::{staging_teyrchain_info as teyrchain_info, *};
use cumulus_primitives_core::ParaId;
use frame_support::{
genesis_builder_helper::{build_state, get_preset},
weights::Weight,
};
use pallet_aura::Authorities;
use sp_api::impl_runtime_apis;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{crypto::KeyTypeId, OpaqueMetadata};
use sp_runtime::{
traits::Block as BlockT,
transaction_validity::{TransactionSource, TransactionValidity},
ApplyExtrinsicResult,
};
use sp_version::RuntimeVersion;
// Local module imports
use super::{
AccountId, Balance, Block, ConsensusHook, Executive, InherentDataExt, Nonce, Runtime,
RuntimeCall, RuntimeGenesisConfig, SessionKeys, System, TeyrchainSystem, TransactionPayment,
SLOT_DURATION, VERSION,
};
// we move some impls outside so we can easily use them with `docify`.
impl Runtime {
#[docify::export]
fn impl_slot_duration() -> sp_consensus_aura::SlotDuration {
sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION)
}
#[docify::export]
fn impl_can_build_upon(
included_hash: <Block as BlockT>::Hash,
slot: cumulus_primitives_aura::Slot,
) -> bool {
ConsensusHook::can_build_upon(included_hash, slot)
}
}
impl_runtime_apis! {
impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> sp_consensus_aura::SlotDuration {
Runtime::impl_slot_duration()
}
fn authorities() -> Vec<AuraId> {
Authorities::<Runtime>::get().into_inner()
}
}
impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
fn relay_parent_offset() -> u32 {
0
}
}
impl cumulus_primitives_aura::AuraUnincludedSegmentApi<Block> for Runtime {
fn can_build_upon(
included_hash: <Block as BlockT>::Hash,
slot: cumulus_primitives_aura::Slot,
) -> bool {
Runtime::impl_can_build_upon(included_hash, slot)
}
}
impl sp_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
fn execute_block(block: <Block as BlockT>::LazyBlock) {
Executive::execute_block(block)
}
fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
Executive::initialize_block(header)
}
}
impl sp_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
OpaqueMetadata::new(Runtime::metadata().into())
}
fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
Runtime::metadata_at_version(version)
}
fn metadata_versions() -> Vec<u32> {
Runtime::metadata_versions()
}
}
impl frame_support::view_functions::runtime_api::RuntimeViewFunction<Block> for Runtime {
fn execute_view_function(id: frame_support::view_functions::ViewFunctionId, input: Vec<u8>) -> Result<Vec<u8>, frame_support::view_functions::ViewFunctionDispatchError> {
Runtime::execute_view_function(id, input)
}
}
impl sp_block_builder::BlockBuilder<Block> for Runtime {
fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
Executive::apply_extrinsic(extrinsic)
}
fn finalize_block() -> <Block as BlockT>::Header {
Executive::finalize_block()
}
fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
data.create_extrinsics()
}
fn check_inherents(
block: <Block as BlockT>::LazyBlock,
data: sp_inherents::InherentData,
) -> sp_inherents::CheckInherentsResult {
data.check_extrinsics(&block)
}
}
impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(
source: TransactionSource,
tx: <Block as BlockT>::Extrinsic,
block_hash: <Block as BlockT>::Hash,
) -> TransactionValidity {
Executive::validate_transaction(source, tx, block_hash)
}
}
impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(header: &<Block as BlockT>::Header) {
Executive::offchain_worker(header)
}
}
impl sp_session::SessionKeys<Block> for Runtime {
fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
SessionKeys::generate(seed)
}
fn decode_session_keys(
encoded: Vec<u8>,
) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
SessionKeys::decode_into_raw_public_keys(&encoded)
}
}
impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce> for Runtime {
fn account_nonce(account: AccountId) -> Nonce {
System::account_nonce(account)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance> for Runtime {
fn query_info(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_info(uxt, len)
}
fn query_fee_details(
uxt: <Block as BlockT>::Extrinsic,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_fee_details(uxt, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentCallApi<Block, Balance, RuntimeCall>
for Runtime
{
fn query_call_info(
call: RuntimeCall,
len: u32,
) -> pallet_transaction_payment::RuntimeDispatchInfo<Balance> {
TransactionPayment::query_call_info(call, len)
}
fn query_call_fee_details(
call: RuntimeCall,
len: u32,
) -> pallet_transaction_payment::FeeDetails<Balance> {
TransactionPayment::query_call_fee_details(call, len)
}
fn query_weight_to_fee(weight: Weight) -> Balance {
TransactionPayment::weight_to_fee(weight)
}
fn query_length_to_fee(length: u32) -> Balance {
TransactionPayment::length_to_fee(length)
}
}
impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
TeyrchainSystem::collect_collation_info(header)
}
}
#[cfg(feature = "try-runtime")]
impl frame_try_runtime::TryRuntime<Block> for Runtime {
fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
use super::configs::RuntimeBlockWeights;
let weight = Executive::try_runtime_upgrade(checks).unwrap();
(weight, RuntimeBlockWeights::get().max_block)
}
fn execute_block(
block: <Block as BlockT>::LazyBlock,
state_root_check: bool,
signature_check: bool,
select: frame_try_runtime::TryStateSelect,
) -> Weight {
// NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
// have a backtrace here.
Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
}
}
#[cfg(feature = "runtime-benchmarks")]
impl frame_benchmarking::Benchmark<Block> for Runtime {
fn benchmark_metadata(extra: bool) -> (
Vec<frame_benchmarking::BenchmarkList>,
Vec<pezkuwi_sdk::frame_support::traits::StorageInfo>,
) {
use frame_benchmarking::BenchmarkList;
use pezkuwi_sdk::frame_support::traits::StorageInfoTrait;
use frame_system_benchmarking::Pallet as SystemBench;
use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
use super::*;
let mut list = Vec::<BenchmarkList>::new();
list_benchmarks!(list, extra);
let storage_info = AllPalletsWithSystem::storage_info();
(list, storage_info)
}
#[allow(non_local_definitions)]
fn dispatch_benchmark(
config: frame_benchmarking::BenchmarkConfig
) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
use frame_benchmarking::{BenchmarkError, BenchmarkBatch};
use super::*;
use frame_system_benchmarking::Pallet as SystemBench;
impl frame_system_benchmarking::Config for Runtime {
fn setup_set_code_requirements(code: &Vec<u8>) -> Result<(), BenchmarkError> {
TeyrchainSystem::initialize_for_set_code_benchmark(code.len() as u32);
Ok(())
}
fn verify_set_code() {
System::assert_last_event(cumulus_pallet_teyrchain_system::Event::<Runtime>::ValidationFunctionStored.into());
}
}
use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
impl cumulus_pallet_session_benchmarking::Config for Runtime {}
use pezkuwi_sdk::frame_support::traits::WhitelistedStorageKeys;
let whitelist = AllPalletsWithSystem::whitelisted_storage_keys();
let mut batches = Vec::<BenchmarkBatch>::new();
let params = (&config, &whitelist);
add_benchmarks!(params, batches);
if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) }
Ok(batches)
}
}
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
build_state::<RuntimeGenesisConfig>(config)
}
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
get_preset::<RuntimeGenesisConfig>(id, crate::genesis_config_presets::get_preset)
}
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
crate::genesis_config_presets::preset_names()
}
}
impl cumulus_primitives_core::GetTeyrchainInfo<Block> for Runtime {
fn teyrchain_id() -> ParaId {
teyrchain_info::Pallet::<Runtime>::teyrchain_id()
}
}
}
@@ -0,0 +1,37 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
pezkuwi_sdk::frame_benchmarking::define_benchmarks!(
[frame_system, SystemBench::<Runtime>]
[pallet_balances, Balances]
[pallet_session, SessionBench::<Runtime>]
[pallet_timestamp, Timestamp]
[pallet_message_queue, MessageQueue]
[pallet_sudo, Sudo]
[pallet_collator_selection, CollatorSelection]
[cumulus_pallet_teyrchain_system, TeyrchainSystem]
[cumulus_pallet_xcmp_queue, XcmpQueue]
[cumulus_pallet_weight_reclaim, WeightReclaim]
);
@@ -0,0 +1,348 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
//
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// For more information, please refer to <http://unlicense.org>
mod xcm_config;
use pezkuwi_sdk::{staging_teyrchain_info as teyrchain_info, staging_xcm as xcm, *};
#[cfg(not(feature = "runtime-benchmarks"))]
use pezkuwi_sdk::{staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor};
// Substrate and Pezkuwi dependencies
use cumulus_pallet_teyrchain_system::RelayNumberMonotonicallyIncreases;
use cumulus_primitives_core::{AggregateMessageOrigin, ParaId};
use frame_support::{
derive_impl,
dispatch::DispatchClass,
parameter_types,
traits::{
ConstBool, ConstU32, ConstU64, ConstU8, EitherOfDiverse, TransformOrigin, VariantCountOf,
},
weights::{ConstantMultiplier, Weight},
PalletId,
};
use frame_system::{
limits::{BlockLength, BlockWeights},
EnsureRoot,
};
use pallet_xcm::{EnsureXcm, IsVoiceOfBody};
use pezkuwi_runtime_common::{
xcm_sender::ExponentialPrice, BlockHashCount, SlowAdjustingFeeUpdate,
};
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_runtime::Perbill;
use sp_version::RuntimeVersion;
use teyrchains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling};
use xcm::latest::prelude::{AssetId, BodyId};
// Local module imports
use super::{
weights::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight},
AccountId, Aura, Balance, Balances, Block, BlockNumber, CollatorSelection, ConsensusHook, Hash,
MessageQueue, Nonce, PalletInfo, Runtime, RuntimeCall, RuntimeEvent, RuntimeFreezeReason,
RuntimeHoldReason, RuntimeOrigin, RuntimeTask, Session, SessionKeys, System, TeyrchainSystem,
WeightToFee, XcmpQueue, AVERAGE_ON_INITIALIZE_RATIO, CENTS, EXISTENTIAL_DEPOSIT, HOURS,
MAXIMUM_BLOCK_WEIGHT, MICRO_UNIT, NORMAL_DISPATCH_RATIO, SLOT_DURATION, VERSION,
};
use xcm_config::{RelayLocation, XcmOriginToTransactDispatchOrigin};
parameter_types! {
pub const Version: RuntimeVersion = VERSION;
// This part is copied from Substrate's `bin/node/runtime/src/lib.rs`.
// The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the
// `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize
// the lazy contract deletion.
pub RuntimeBlockLength: BlockLength =
BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
.base_block(BlockExecutionWeight::get())
.for_class(DispatchClass::all(), |weights| {
weights.base_extrinsic = ExtrinsicBaseWeight::get();
})
.for_class(DispatchClass::Normal, |weights| {
weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
})
.for_class(DispatchClass::Operational, |weights| {
weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
// Operational transactions have some extra reserved space, so that they
// are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
weights.reserved = Some(
MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
);
})
.avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
.build_or_panic();
pub const SS58Prefix: u16 = 42;
}
/// All migrations of the runtime, aside from the ones declared in the pallets.
///
/// This can be a tuple of types, each implementing `OnRuntimeUpgrade`.
#[allow(unused_parens)]
type SingleBlockMigrations = ();
/// The default types are being injected by [`derive_impl`](`frame_support::derive_impl`) from
/// [`TeyrchainDefaultConfig`](`struct@frame_system::config_preludes::TeyrchainDefaultConfig`),
/// but overridden as needed.
#[derive_impl(frame_system::config_preludes::TeyrchainDefaultConfig)]
impl frame_system::Config for Runtime {
/// The identifier used to distinguish between accounts.
type AccountId = AccountId;
/// The index type for storing how many extrinsics an account has signed.
type Nonce = Nonce;
/// The type for hashing blocks and tries.
type Hash = Hash;
/// The block type.
type Block = Block;
/// Maximum number of block number to block hash mappings to keep (oldest pruned first).
type BlockHashCount = BlockHashCount;
/// Runtime version.
type Version = Version;
/// The data to be stored in an account.
type AccountData = pallet_balances::AccountData<Balance>;
/// The weight of database operations that the runtime can invoke.
type DbWeight = RocksDbWeight;
/// Block & extrinsics weights: base values and limits.
type BlockWeights = RuntimeBlockWeights;
/// The maximum length of a block (in bytes).
type BlockLength = RuntimeBlockLength;
/// This is used as an identifier of the chain. 42 is the generic substrate prefix.
type SS58Prefix = SS58Prefix;
/// The action to take on a Runtime Upgrade
type OnSetCode = cumulus_pallet_teyrchain_system::TeyrchainSetCode<Self>;
type MaxConsumers = frame_support::traits::ConstU32<16>;
type SingleBlockMigrations = SingleBlockMigrations;
}
/// Configure the palelt weight reclaim tx.
impl cumulus_pallet_weight_reclaim::Config for Runtime {
type WeightInfo = ();
}
impl pallet_timestamp::Config for Runtime {
/// A timestamp: milliseconds since the unix epoch.
type Moment = u64;
type OnTimestampSet = Aura;
type MinimumPeriod = ConstU64<0>;
type WeightInfo = ();
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Aura>;
type EventHandler = (CollatorSelection,);
}
parameter_types! {
pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
}
impl pallet_balances::Config for Runtime {
type MaxLocks = ConstU32<50>;
/// The type for recording an account's balance.
type Balance = Balance;
/// The ubiquitous event type.
type RuntimeEvent = RuntimeEvent;
type DustRemoval = ();
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = pallet_balances::weights::SubstrateWeight<Runtime>;
type MaxReserves = ConstU32<50>;
type ReserveIdentifier = [u8; 8];
type RuntimeHoldReason = RuntimeHoldReason;
type RuntimeFreezeReason = RuntimeFreezeReason;
type FreezeIdentifier = RuntimeFreezeReason;
type MaxFreezes = VariantCountOf<RuntimeFreezeReason>;
type DoneSlashHandler = ();
}
parameter_types! {
/// Relay Chain `TransactionByteFee` / 10
pub const TransactionByteFee: Balance = 10 * MICRO_UNIT;
}
impl pallet_transaction_payment::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type OnChargeTransaction = pallet_transaction_payment::FungibleAdapter<Balances, ()>;
type WeightToFee = WeightToFee;
type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightInfo = ();
}
impl pallet_sudo::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type RuntimeCall = RuntimeCall;
type WeightInfo = ();
}
parameter_types! {
pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
}
impl cumulus_pallet_teyrchain_system::Config for Runtime {
type WeightInfo = ();
type RuntimeEvent = RuntimeEvent;
type OnSystemEvent = ();
type SelfParaId = teyrchain_info::Pallet<Runtime>;
type OutboundXcmpMessageSource = XcmpQueue;
type DmpQueue = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
type ReservedDmpWeight = ReservedDmpWeight;
type XcmpMessageHandler = XcmpQueue;
type ReservedXcmpWeight = ReservedXcmpWeight;
type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
type ConsensusHook = ConsensusHook;
type RelayParentOffset = ConstU32<0>;
}
impl teyrchain_info::Config for Runtime {}
parameter_types! {
pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block;
}
impl pallet_message_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = ();
#[cfg(feature = "runtime-benchmarks")]
type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
cumulus_primitives_core::AggregateMessageOrigin,
>;
#[cfg(not(feature = "runtime-benchmarks"))]
type MessageProcessor = xcm_builder::ProcessXcmMessage<
AggregateMessageOrigin,
xcm_executor::XcmExecutor<xcm_config::XcmConfig>,
RuntimeCall,
>;
type Size = u32;
// The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
type QueuePausedQuery = NarrowOriginToSibling<XcmpQueue>;
type HeapSize = sp_core::ConstU32<{ 103 * 1024 }>;
type MaxStale = sp_core::ConstU32<8>;
type ServiceWeight = MessageQueueServiceWeight;
type IdleMaxServiceWeight = ();
}
impl cumulus_pallet_aura_ext::Config for Runtime {}
parameter_types! {
/// The asset ID for the asset that we use to pay for message delivery fees.
pub FeeAssetId: AssetId = AssetId(xcm_config::RelayLocation::get());
/// The base fee for the message delivery fees.
pub const ToSiblingBaseDeliveryFee: u128 = CENTS.saturating_mul(3);
pub const ToParentBaseDeliveryFee: u128 = CENTS.saturating_mul(3);
}
/// The price for delivering XCM messages to sibling teyrchains.
pub type PriceForSiblingTeyrchainDelivery =
ExponentialPrice<FeeAssetId, ToSiblingBaseDeliveryFee, TransactionByteFee, XcmpQueue>;
/// The price for delivering XCM messages to relay chain.
pub type PriceForParentDelivery =
ExponentialPrice<FeeAssetId, ToParentBaseDeliveryFee, TransactionByteFee, TeyrchainSystem>;
impl cumulus_pallet_xcmp_queue::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ChannelInfo = TeyrchainSystem;
type VersionWrapper = ();
// Enqueue XCMP messages from siblings for later processing.
type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
type MaxInboundSuspended = sp_core::ConstU32<1_000>;
type MaxActiveOutboundChannels = ConstU32<128>;
type MaxPageSize = ConstU32<{ 1 << 16 }>;
type ControllerOrigin = EnsureRoot<AccountId>;
type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
type WeightInfo = ();
type PriceForSiblingDelivery = PriceForSiblingTeyrchainDelivery;
}
parameter_types! {
pub const Period: u32 = 6 * HOURS;
pub const Offset: u32 = 0;
}
impl pallet_session::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type ValidatorId = <Self as frame_system::Config>::AccountId;
// we don't have stash and controller, thus we don't need the convert as well.
type ValidatorIdOf = pallet_collator_selection::IdentityCollator;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = CollatorSelection;
// Essentially just Aura, but let's be pedantic.
type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
type Keys = SessionKeys;
type DisablingStrategy = ();
type WeightInfo = ();
type Currency = Balances;
type KeyDeposit = ();
}
#[docify::export(aura_config)]
impl pallet_aura::Config for Runtime {
type AuthorityId = AuraId;
type DisabledValidators = ();
type MaxAuthorities = ConstU32<100_000>;
type AllowMultipleBlocksPerSlot = ConstBool<true>;
type SlotDuration = ConstU64<SLOT_DURATION>;
}
parameter_types! {
pub const PotId: PalletId = PalletId(*b"PotStake");
pub const SessionLength: BlockNumber = 6 * HOURS;
// StakingAdmin pluralistic body.
pub const StakingAdminBodyId: BodyId = BodyId::Defense;
}
/// We allow root and the StakingAdmin to execute privileged collator selection operations.
pub type CollatorSelectionUpdateOrigin = EitherOfDiverse<
EnsureRoot<AccountId>,
EnsureXcm<IsVoiceOfBody<RelayLocation, StakingAdminBodyId>>,
>;
impl pallet_collator_selection::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type Currency = Balances;
type UpdateOrigin = CollatorSelectionUpdateOrigin;
type PotId = PotId;
type MaxCandidates = ConstU32<100>;
type MinEligibleCollators = ConstU32<4>;
type MaxInvulnerables = ConstU32<20>;
// should be a multiple of session or things will get inconsistent
type KickThreshold = Period;
type ValidatorId = <Self as frame_system::Config>::AccountId;
type ValidatorIdOf = pallet_collator_selection::IdentityCollator;
type ValidatorRegistration = Session;
type WeightInfo = ();
}
/// Configure the pallet template in pallets/template.
impl pallet_teyrchain_template::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type WeightInfo = pallet_teyrchain_template::weights::SubstrateWeight<Runtime>;
}
@@ -0,0 +1,207 @@
use super::PriceForParentDelivery;
use crate::{
AccountId, AllPalletsWithSystem, Balances, PezkuwiXcm, Runtime, RuntimeCall, RuntimeEvent,
RuntimeOrigin, TeyrchainInfo, TeyrchainSystem, WeightToFee, XcmpQueue,
};
use pezkuwi_sdk::{
staging_xcm as xcm, staging_xcm_builder as xcm_builder, staging_xcm_executor as xcm_executor, *,
};
use frame_support::{
parameter_types,
traits::{ConstU32, Contains, Everything, Nothing},
weights::Weight,
};
use frame_system::EnsureRoot;
use pallet_xcm::XcmPassthrough;
use pezkuwi_runtime_common::impls::ToAuthor;
use pezkuwi_sdk::{
pezkuwi_sdk_frame::traits::Disabled,
staging_xcm_builder::{DenyRecursively, DenyThenTry},
};
use pezkuwi_teyrchain_primitives::primitives::Sibling;
use xcm::latest::prelude::*;
use xcm_builder::{
AccountId32Aliases, AllowExplicitUnpaidExecutionFrom, AllowTopLevelPaidExecutionFrom,
DenyReserveTransferToRelayChain, EnsureXcmOrigin, FixedWeightBounds,
FrameTransactionalProcessor, FungibleAdapter, IsConcrete, NativeAsset, ParentIsPreset,
RelayChainAsNative, SiblingTeyrchainAsNative, SiblingTeyrchainConvertsVia,
SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
TrailingSetTopicAsId, UsingComponents, WithComputedOrigin, WithUniqueTopic,
};
use xcm_executor::XcmExecutor;
parameter_types! {
pub const RelayLocation: Location = Location::parent();
pub const RelayNetwork: Option<NetworkId> = None;
pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
// For the real deployment, it is recommended to set `RelayNetwork` according to the relay chain
// and prepend `UniversalLocation` with `GlobalConsensus(RelayNetwork::get())`.
pub UniversalLocation: InteriorLocation = Teyrchain(TeyrchainInfo::teyrchain_id().into()).into();
}
/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
/// `Transact` in order to determine the dispatch Origin.
pub type LocationToAccountId = (
// The parent (Relay-chain) origin converts to the parent `AccountId`.
ParentIsPreset<AccountId>,
// Sibling teyrchain origins convert to AccountId via the `ParaId::into`.
SiblingTeyrchainConvertsVia<Sibling, AccountId>,
// Straight up local `AccountId32` origins just alias directly to `AccountId`.
AccountId32Aliases<RelayNetwork, AccountId>,
);
/// Means for transacting assets on this chain.
pub type LocalAssetTransactor = FungibleAdapter<
// Use this currency:
Balances,
// Use this currency when it is a fungible asset matching the given location or name:
IsConcrete<RelayLocation>,
// Do a simple punn to convert an AccountId32 Location into a native chain account ID:
LocationToAccountId,
// Our chain's account ID type (we can't get away without mentioning it explicitly):
AccountId,
// We don't track any teleports.
(),
>;
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
/// biases the kind of local `Origin` it will become.
pub type XcmOriginToTransactDispatchOrigin = (
// Sovereign account converter; this attempts to derive an `AccountId` from the origin location
// using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
// foreign chains who want to have a local sovereign account on this chain which they control.
SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
// Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when
// recognized.
RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
// Native converter for sibling Teyrchains; will convert to a `SiblingPara` origin when
// recognized.
SiblingTeyrchainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
// Native signed account converter; this just converts an `AccountId32` origin into a normal
// `RuntimeOrigin::Signed` origin of the same 32-byte value.
SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
// Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
XcmPassthrough<RuntimeOrigin>,
);
parameter_types! {
// One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
pub const MaxInstructions: u32 = 100;
pub const MaxAssetsIntoHolding: u32 = 64;
}
pub struct ParentOrParentsExecutivePlurality;
impl Contains<Location> for ParentOrParentsExecutivePlurality {
fn contains(location: &Location) -> bool {
matches!(location.unpack(), (1, []) | (1, [Plurality { id: BodyId::Executive, .. }]))
}
}
pub type Barrier = TrailingSetTopicAsId<
DenyThenTry<
DenyRecursively<DenyReserveTransferToRelayChain>,
(
TakeWeightCredit,
WithComputedOrigin<
(
AllowTopLevelPaidExecutionFrom<Everything>,
AllowExplicitUnpaidExecutionFrom<ParentOrParentsExecutivePlurality>,
// ^^^ Parent and its exec plurality get free execution
),
UniversalLocation,
ConstU32<8>,
>,
),
>,
>;
pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
type RuntimeCall = RuntimeCall;
type XcmSender = XcmRouter;
type XcmEventEmitter = PezkuwiXcm;
// How to withdraw and deposit an asset.
type AssetTransactor = LocalAssetTransactor;
type OriginConverter = XcmOriginToTransactDispatchOrigin;
type IsReserve = NativeAsset;
type IsTeleporter = (); // Teleporting is disabled.
type UniversalLocation = UniversalLocation;
type Barrier = Barrier;
type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
type Trader =
UsingComponents<WeightToFee, RelayLocation, AccountId, Balances, ToAuthor<Runtime>>;
type ResponseHandler = PezkuwiXcm;
type AssetTrap = PezkuwiXcm;
type AssetClaims = PezkuwiXcm;
type SubscriptionService = PezkuwiXcm;
type PalletInstancesInfo = AllPalletsWithSystem;
type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
type AssetLocker = ();
type AssetExchanger = ();
type FeeManager = ();
type MessageExporter = ();
type UniversalAliases = Nothing;
type CallDispatcher = RuntimeCall;
type SafeCallFilter = Everything;
type Aliasers = Nothing;
type TransactionalProcessor = FrameTransactionalProcessor;
type HrmpNewChannelOpenRequestHandler = ();
type HrmpChannelAcceptedHandler = ();
type HrmpChannelClosingHandler = ();
type XcmRecorder = PezkuwiXcm;
}
/// Converts a local signed origin into an XCM location. Forms the basis for local origins
/// sending/executing XCMs.
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
/// The means for routing XCM messages which are not for local execution into the right message
/// queues.
pub type XcmRouter = WithUniqueTopic<(
// Two routers - use UMP to communicate with the relay chain:
cumulus_primitives_utility::ParentAsUmp<TeyrchainSystem, PezkuwiXcm, PriceForParentDelivery>,
// ..and XCMP to communicate with the sibling chains.
XcmpQueue,
)>;
impl pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmRouter = XcmRouter;
type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
type XcmExecuteFilter = Nothing;
// ^ Disable dispatchable execute on the XCM pallet.
// Needs to be `Everything` for local testing.
type XcmExecutor = XcmExecutor<XcmConfig>;
type XcmTeleportFilter = Everything;
type XcmReserveTransferFilter = Nothing;
type Weigher = FixedWeightBounds<UnitWeightCost, RuntimeCall, MaxInstructions>;
type UniversalLocation = UniversalLocation;
type RuntimeOrigin = RuntimeOrigin;
type RuntimeCall = RuntimeCall;
const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
// ^ Override for AdvertisedXcmVersion default
type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
type Currency = Balances;
type CurrencyMatcher = ();
type TrustedLockers = ();
type SovereignAccountOf = LocationToAccountId;
type MaxLockers = ConstU32<8>;
type WeightInfo = pallet_xcm::TestWeightInfo;
type AdminOrigin = EnsureRoot<AccountId>;
type MaxRemoteLockConsumers = ConstU32<0>;
type RemoteLockConsumerIdentifier = ();
// Aliasing is disabled: xcm_executor::Config::Aliasers is set to `Nothing`.
type AuthorizedAliasConsideration = Disabled;
}
impl cumulus_pallet_xcm::Config for Runtime {
type RuntimeEvent = RuntimeEvent;
type XcmExecutor = XcmExecutor<XcmConfig>;
}
@@ -0,0 +1,112 @@
use crate::{
AccountId, BalancesConfig, CollatorSelectionConfig, PezkuwiXcmConfig, RuntimeGenesisConfig,
SessionConfig, SessionKeys, SudoConfig, TeyrchainInfoConfig, EXISTENTIAL_DEPOSIT,
};
use alloc::{vec, vec::Vec};
use pezkuwi_sdk::{staging_xcm as xcm, *};
use cumulus_primitives_core::ParaId;
use frame_support::build_struct_json_patch;
use serde_json::Value;
use sp_genesis_builder::PresetId;
use sp_keyring::Sr25519Keyring;
use teyrchains_common::AuraId;
/// The default XCM version to set in genesis config.
const SAFE_XCM_VERSION: u32 = xcm::prelude::XCM_VERSION;
/// Teyrchain id used for genesis config presets of teyrchain template.
#[docify::export_content]
pub const TEYRCHAIN_ID: u32 = 1000;
/// 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) -> SessionKeys {
SessionKeys { aura: keys }
}
fn testnet_genesis(
invulnerables: Vec<(AccountId, AuraId)>,
endowed_accounts: Vec<AccountId>,
root: AccountId,
id: ParaId,
) -> Value {
build_struct_json_patch!(RuntimeGenesisConfig {
balances: BalancesConfig {
balances: endowed_accounts
.iter()
.cloned()
.map(|k| (k, 1u128 << 60))
.collect::<Vec<_>>(),
},
teyrchain_info: TeyrchainInfoConfig { teyrchain_id: id },
collator_selection: CollatorSelectionConfig {
invulnerables: invulnerables.iter().cloned().map(|(acc, _)| acc).collect::<Vec<_>>(),
candidacy_bond: EXISTENTIAL_DEPOSIT * 16,
},
session: SessionConfig {
keys: invulnerables
.into_iter()
.map(|(acc, aura)| {
(
acc.clone(), // account id
acc, // validator id
template_session_keys(aura), // session keys
)
})
.collect::<Vec<_>>(),
},
pezkuwi_xcm: PezkuwiXcmConfig { safe_xcm_version: Some(SAFE_XCM_VERSION) },
sudo: SudoConfig { key: Some(root) },
})
}
fn local_testnet_genesis() -> Value {
testnet_genesis(
// initial collators.
vec![
(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()),
(Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()),
],
Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(),
Sr25519Keyring::Alice.to_account_id(),
TEYRCHAIN_ID.into(),
)
}
fn development_config_genesis() -> Value {
testnet_genesis(
// initial collators.
vec![
(Sr25519Keyring::Alice.to_account_id(), Sr25519Keyring::Alice.public().into()),
(Sr25519Keyring::Bob.to_account_id(), Sr25519Keyring::Bob.public().into()),
],
Sr25519Keyring::well_known().map(|k| k.to_account_id()).collect(),
Sr25519Keyring::Alice.to_account_id(),
TEYRCHAIN_ID.into(),
)
}
/// Provides the JSON representation of predefined genesis config for given `id`.
pub fn get_preset(id: &PresetId) -> Option<vec::Vec<u8>> {
let patch = match id.as_ref() {
sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET => local_testnet_genesis(),
sp_genesis_builder::DEV_RUNTIME_PRESET => development_config_genesis(),
_ => return None,
};
Some(
serde_json::to_string(&patch)
.expect("serialization to json is expected to work. qed.")
.into_bytes(),
)
}
/// List of supported presets.
pub fn preset_names() -> Vec<PresetId> {
vec![
PresetId::from(sp_genesis_builder::DEV_RUNTIME_PRESET),
PresetId::from(sp_genesis_builder::LOCAL_TESTNET_RUNTIME_PRESET),
]
}
+317
View File
@@ -0,0 +1,317 @@
#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
#![recursion_limit = "256"]
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
pub mod apis;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarks;
pub mod configs;
mod genesis_config_presets;
mod weights;
extern crate alloc;
use alloc::vec::Vec;
use smallvec::smallvec;
use pezkuwi_sdk::{staging_teyrchain_info as teyrchain_info, *};
use sp_runtime::{
generic, impl_opaque_keys,
traits::{BlakeTwo256, IdentifyAccount, Verify},
MultiSignature,
};
#[cfg(feature = "std")]
use sp_version::NativeVersion;
use sp_version::RuntimeVersion;
use frame_support::weights::{
constants::WEIGHT_REF_TIME_PER_SECOND, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
WeightToFeePolynomial,
};
pub use genesis_config_presets::TEYRCHAIN_ID;
pub use sp_consensus_aura::sr25519::AuthorityId as AuraId;
pub use sp_runtime::{MultiAddress, Perbill, Permill};
use weights::ExtrinsicBaseWeight;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = MultiSignature;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
/// Balance of an account.
pub type Balance = u128;
/// Index of a transaction in the chain.
pub type Nonce = u32;
/// A hash of some data used by the chain.
pub type Hash = sp_core::H256;
/// An index to a block.
pub type BlockNumber = u32;
/// The address format for describing accounts.
pub type Address = MultiAddress<AccountId, ()>;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The extension to the basic transaction logic.
#[docify::export(template_signed_extra)]
pub type TxExtension = cumulus_pallet_weight_reclaim::StorageWeightReclaim<
Runtime,
(
frame_system::AuthorizeCall<Runtime>,
frame_system::CheckNonZeroSender<Runtime>,
frame_system::CheckSpecVersion<Runtime>,
frame_system::CheckTxVersion<Runtime>,
frame_system::CheckGenesis<Runtime>,
frame_system::CheckEra<Runtime>,
frame_system::CheckNonce<Runtime>,
frame_system::CheckWeight<Runtime>,
pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
frame_metadata_hash_extension::CheckMetadataHash<Runtime>,
),
>;
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic =
generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
/// Executive: handles dispatch to the various modules.
pub type Executive = frame_executive::Executive<
Runtime,
Block,
frame_system::ChainContext<Runtime>,
Runtime,
AllPalletsWithSystem,
>;
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
/// node's balance type.
///
/// This should typically create a mapping between the following ranges:
/// - `[0, MAXIMUM_BLOCK_WEIGHT]`
/// - `[Balance::min, Balance::max]`
///
/// Yet, it can be used for any other sort of change to weight-fee. Some examples being:
/// - Setting it to `0` will essentially disable the weight fee.
/// - Setting it to `1` will cause the literal `#[weight = x]` values to be charged.
pub struct WeightToFee;
impl WeightToFeePolynomial for WeightToFee {
type Balance = Balance;
fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
// in Pezkuwichain, extrinsic base weight (smallest non-zero weight) is mapped to 1
// MILLI_UNIT: in our template, we map to 1/10 of that, or 1/10 MILLI_UNIT
let p = MILLI_UNIT / 10;
let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
smallvec![WeightToFeeCoefficient {
degree: 1,
negative: false,
coeff_frac: Perbill::from_rational(p % q, q),
coeff_integer: p / q,
}]
}
}
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
/// to even the core data structures.
pub mod opaque {
use super::*;
pub use pezkuwi_sdk::sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
use pezkuwi_sdk::sp_runtime::{
generic,
traits::{BlakeTwo256, Hash as HashT},
};
/// Opaque block header type.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Opaque block type.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// Opaque block identifier type.
pub type BlockId = generic::BlockId<Block>;
/// Opaque block hash type.
pub type Hash = <BlakeTwo256 as HashT>::Output;
}
impl_opaque_keys! {
pub struct SessionKeys {
pub aura: Aura,
}
}
#[sp_version::runtime_version]
pub const VERSION: RuntimeVersion = RuntimeVersion {
spec_name: alloc::borrow::Cow::Borrowed("teyrchain-template-runtime"),
impl_name: alloc::borrow::Cow::Borrowed("teyrchain-template-runtime"),
authoring_version: 1,
spec_version: 1,
impl_version: 0,
apis: apis::RUNTIME_API_VERSIONS,
transaction_version: 1,
system_version: 1,
};
#[docify::export]
mod block_times {
/// This determines the average expected block time that we are targeting. Blocks will be
/// produced at a minimum duration defined by `SLOT_DURATION`. `SLOT_DURATION` is picked up by
/// `pallet_timestamp` which is in turn picked up by `pallet_aura` to implement `fn
/// slot_duration()`.
///
/// Change this to adjust the block time.
pub const MILLI_SECS_PER_BLOCK: u64 = 6000;
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
// Attempting to do so will brick block production.
pub const SLOT_DURATION: u64 = MILLI_SECS_PER_BLOCK;
}
pub use block_times::*;
// Time is measured by number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLI_SECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
// Unit = the base number of indivisible units for balances
pub const UNIT: Balance = 1_000_000_000_000;
pub const CENTS: Balance = UNIT / 100;
pub const MILLI_UNIT: Balance = 1_000_000_000;
pub const MICRO_UNIT: Balance = 1_000_000;
/// The existential deposit. Set to 1/10 of the Connected Relay Chain.
pub const EXISTENTIAL_DEPOSIT: Balance = MILLI_UNIT;
/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is
/// used to limit the maximal weight of a single extrinsic.
const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by
/// `Operational` extrinsics.
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
#[docify::export(max_block_weight)]
/// We allow for 2 seconds of compute with a 6 second average block time.
const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
);
#[docify::export]
mod async_backing_params {
/// Maximum number of blocks simultaneously accepted by the Runtime, not yet included
/// into the relay chain.
pub(crate) const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
/// How many teyrchain blocks are processed by the relay chain per parent. Limits the
/// number of blocks authored per slot.
pub(crate) const BLOCK_PROCESSING_VELOCITY: u32 = 1;
/// Relay chain slot duration, in milliseconds.
pub(crate) const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
}
pub(crate) use async_backing_params::*;
#[docify::export]
/// Aura consensus hook
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
Runtime,
RELAY_CHAIN_SLOT_DURATION_MILLIS,
BLOCK_PROCESSING_VELOCITY,
UNINCLUDED_SEGMENT_CAPACITY,
>;
/// The version information used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
}
// Create the runtime by composing the FRAME pallets that were previously configured.
#[frame_support::runtime]
mod runtime {
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
#[runtime::pallet_index(0)]
pub type System = frame_system;
#[runtime::pallet_index(1)]
pub type TeyrchainSystem = cumulus_pallet_teyrchain_system;
#[runtime::pallet_index(2)]
pub type Timestamp = pallet_timestamp;
#[runtime::pallet_index(3)]
pub type TeyrchainInfo = teyrchain_info;
#[runtime::pallet_index(4)]
pub type WeightReclaim = cumulus_pallet_weight_reclaim;
// Monetary stuff.
#[runtime::pallet_index(10)]
pub type Balances = pallet_balances;
#[runtime::pallet_index(11)]
pub type TransactionPayment = pallet_transaction_payment;
// Governance
#[runtime::pallet_index(15)]
pub type Sudo = pallet_sudo;
// Collator support. The order of these 4 are important and shall not change.
#[runtime::pallet_index(20)]
pub type Authorship = pallet_authorship;
#[runtime::pallet_index(21)]
pub type CollatorSelection = pallet_collator_selection;
#[runtime::pallet_index(22)]
pub type Session = pallet_session;
#[runtime::pallet_index(23)]
pub type Aura = pallet_aura;
#[runtime::pallet_index(24)]
pub type AuraExt = cumulus_pallet_aura_ext;
// XCM helpers.
#[runtime::pallet_index(30)]
pub type XcmpQueue = cumulus_pallet_xcmp_queue;
#[runtime::pallet_index(31)]
pub type PezkuwiXcm = pallet_xcm;
#[runtime::pallet_index(32)]
pub type CumulusXcm = cumulus_pallet_xcm;
#[runtime::pallet_index(33)]
pub type MessageQueue = pallet_message_queue;
// Template
#[runtime::pallet_index(50)]
pub type TemplatePallet = pallet_teyrchain_template;
}
#[docify::export(register_validate_block)]
cumulus_pallet_teyrchain_system::register_validate_block! {
Runtime = Runtime,
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
}
@@ -0,0 +1,57 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod constants {
use pezkuwi_sdk::*;
use frame_support::{
parameter_types,
weights::{constants, Weight},
};
parameter_types! {
/// Importing a block with 0 Extrinsics.
pub const BlockExecutionWeight: Weight =
Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(5_000_000), 0);
}
#[cfg(test)]
mod test_weights {
use pezkuwi_sdk::*;
use frame_support::weights::constants;
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
let w = super::constants::BlockExecutionWeight::get();
// At least 100 µs.
assert!(
w.ref_time() >= 100u64 * constants::WEIGHT_REF_TIME_PER_MICROS,
"Weight should be at least 100 µs."
);
// At most 50 ms.
assert!(
w.ref_time() <= 50u64 * constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 50 ms."
);
}
}
}
@@ -0,0 +1,57 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod constants {
use pezkuwi_sdk::*;
use frame_support::{
parameter_types,
weights::{constants, Weight},
};
parameter_types! {
/// Executing a NO-OP `System::remarks` Extrinsic.
pub const ExtrinsicBaseWeight: Weight =
Weight::from_parts(constants::WEIGHT_REF_TIME_PER_NANOS.saturating_mul(125_000), 0);
}
#[cfg(test)]
mod test_weights {
use pezkuwi_sdk::*;
use frame_support::weights::constants;
/// Checks that the weight exists and is sane.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
let w = super::constants::ExtrinsicBaseWeight::get();
// At least 10 µs.
assert!(
w.ref_time() >= 10u64 * constants::WEIGHT_REF_TIME_PER_MICROS,
"Weight should be at least 10 µs."
);
// At most 1 ms.
assert!(
w.ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Weight should be at most 1 ms."
);
}
}
}
@@ -0,0 +1,27 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Expose the auto generated weight files.
pub mod block_weights;
pub mod extrinsic_weights;
pub mod paritydb_weights;
pub mod rocksdb_weights;
pub use block_weights::constants::BlockExecutionWeight;
pub use extrinsic_weights::constants::ExtrinsicBaseWeight;
pub use rocksdb_weights::constants::RocksDbWeight;
@@ -0,0 +1,67 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod constants {
use pezkuwi_sdk::*;
use frame_support::{
parameter_types,
weights::{constants, RuntimeDbWeight},
};
parameter_types! {
/// `ParityDB` can be enabled with a feature flag, but is still experimental. These weights
/// are available for brave runtime engineers who may want to try this out as default.
pub const ParityDbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 8_000 * constants::WEIGHT_REF_TIME_PER_NANOS,
write: 50_000 * constants::WEIGHT_REF_TIME_PER_NANOS,
};
}
#[cfg(test)]
mod test_db_weights {
use pezkuwi_sdk::*;
use super::constants::ParityDbWeight as W;
use frame_support::weights::constants;
/// Checks that all weights exist and have sane values.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
// At least 1 µs.
assert!(
W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS,
"Read weight should be at least 1 µs."
);
assert!(
W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS,
"Write weight should be at least 1 µs."
);
// At most 1 ms.
assert!(
W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Read weight should be at most 1 ms."
);
assert!(
W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Write weight should be at most 1 ms."
);
}
}
}
@@ -0,0 +1,67 @@
// This file is part of Substrate.
// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub mod constants {
use pezkuwi_sdk::*;
use frame_support::{
parameter_types,
weights::{constants, RuntimeDbWeight},
};
parameter_types! {
/// By default, Substrate uses `RocksDB`, so this will be the weight used throughout
/// the runtime.
pub const RocksDbWeight: RuntimeDbWeight = RuntimeDbWeight {
read: 25_000 * constants::WEIGHT_REF_TIME_PER_NANOS,
write: 100_000 * constants::WEIGHT_REF_TIME_PER_NANOS,
};
}
#[cfg(test)]
mod test_db_weights {
use pezkuwi_sdk::*;
use super::constants::RocksDbWeight as W;
use frame_support::weights::constants;
/// Checks that all weights exist and have sane values.
// NOTE: If this test fails but you are sure that the generated values are fine,
// you can delete it.
#[test]
fn sane() {
// At least 1 µs.
assert!(
W::get().reads(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS,
"Read weight should be at least 1 µs."
);
assert!(
W::get().writes(1).ref_time() >= constants::WEIGHT_REF_TIME_PER_MICROS,
"Write weight should be at least 1 µs."
);
// At most 1 ms.
assert!(
W::get().reads(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Read weight should be at most 1 ms."
);
assert!(
W::get().writes(1).ref_time() <= constants::WEIGHT_REF_TIME_PER_MILLIS,
"Write weight should be at most 1 ms."
);
}
}
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Cumulus.
// Cumulus is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Cumulus is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Cumulus. If not, see <http://www.gnu.org/licenses/>.
// The teyrchain-template crate helps with keeping the README.md in sync
// with code sections across the components under the template: node,
// pallets & runtime, by using `docify`.
#[cfg(feature = "generate-readme")]
docify::compile_markdown!("README.docify.md", "README.md");
@@ -0,0 +1,22 @@
[relaychain]
default_command = "pezkuwi"
chain = "pezkuwichain-local"
[[relaychain.nodes]]
name = "alice"
validator = true
ws_port = 9944
[[relaychain.nodes]]
name = "bob"
validator = true
ws_port = 9955
[[teyrchains]]
id = 1000
chain_spec_path = "./dev_chain_spec.json"
[teyrchains.collator]
name = "charlie"
ws_port = 9988
command = "pezkuwi-omni-node"
+21
View File
@@ -0,0 +1,21 @@
[relaychain]
default_command = "pezkuwi"
chain = "pezkuwichain-local"
[[relaychain.nodes]]
name = "alice"
validator = true
ws_port = 9944
[[relaychain.nodes]]
name = "bob"
validator = true
ws_port = 9955
[[teyrchains]]
id = 1000
[teyrchains.collator]
name = "charlie"
ws_port = 9988
command = "teyrchain-template-node"
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "template-zombienet-tests"
description = "Zombienet test for templates."
version = "0.0.0"
license = "Unlicense"
authors.workspace = true
homepage.workspace = true
repository.workspace = true
edition.workspace = true
publish = false
[dependencies]
anyhow = { workspace = true }
env_logger = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread"] }
zombienet-sdk = { workspace = true }
[features]
zombienet = []
File diff suppressed because one or more lines are too long
+187
View File
@@ -0,0 +1,187 @@
//! This test is setup to run with the `native` provider and needs these binaries in your PATH
//! `pezkuwi`, `pezkuwi-prepare-worker`, `pezkuwi-execute-worker`, `teyrchain-template-node`.
//! You can follow these steps to compile and export the binaries:
//! `cargo build --release -features fast-runtime --bin pezkuwi --bin pezkuwi-execute-worker --bin
//! pezkuwi-prepare-worker`
//! `cargo build --package teyrchain-template-node --release`
//! `export PATH=<path-to-pezkuwi-sdk-repo>/target/release:$PATH
//!
//! There are also some tests related to omni node which run basaed on pre-generated chain specs,
//! so to be able to run them you would need to generate the right chain spec (just minimal and
//! teyrchain tests supported for now).
//!
//! You can run the following command to generate a minimal chainspec, once the runtime wasm file is
//! compiled:
//!`chain-spec-builder create --relay-chain <relay_chain_id> -r \
//! <path_to_template_wasm_file> named-preset development`
//!
//! Once the files are generated, you must export an environment variable called
//! `CHAIN_SPECS_DIR` which should point to the absolute path of the directory
//! that holds the generated chain spec. The chain specs file names should be
//! `teyrchain_chain_spec.json` for teyrchain
//! templates.
//!
//! To start all tests here we should run:
//! `cargo test -p template-zombienet-tests --features zombienet`
#[cfg(feature = "zombienet")]
mod smoke {
use std::path::PathBuf;
use anyhow::anyhow;
use zombienet_sdk::{NetworkConfig, NetworkConfigBuilder, NetworkConfigExt};
const CHAIN_SPECS_DIR_PATH: &str = "CHAIN_SPECS_DIR";
const TEYRCHAIN_ID: u32 = 1000;
#[inline]
fn expect_env_var(var_name: &str) -> String {
std::env::var(var_name)
.unwrap_or_else(|_| panic!("{CHAIN_SPECS_DIR_PATH} environment variable is set. qed."))
}
#[derive(Default)]
struct NetworkSpec {
relaychain_cmd: &'static str,
relaychain_spec_path: Option<PathBuf>,
// TODO: update the type to something like Option<Vec<Arg>> after
// `zombienet-sdk` exposes `shared::types::Arg`.
relaychain_cmd_args: Option<Vec<(&'static str, &'static str)>>,
para_cmd: Option<&'static str>,
para_chain_spec_path: Option<PathBuf>,
para_cmd_args: Option<Vec<(&'static str, &'static str)>>,
}
fn get_config(network_spec: NetworkSpec) -> Result<NetworkConfig, anyhow::Error> {
let chain =
if network_spec.relaychain_cmd == "pezkuwi" { "pezkuwichain-local" } else { "dev" };
let config = NetworkConfigBuilder::new().with_relaychain(|r| {
let mut r = r.with_chain(chain).with_default_command(network_spec.relaychain_cmd);
if let Some(path) = network_spec.relaychain_spec_path {
r = r.with_chain_spec_path(path);
}
if let Some(args) = network_spec.relaychain_cmd_args {
r = r.with_default_args(args.into_iter().map(|arg| arg.into()).collect());
}
r.with_node(|node| node.with_name("alice"))
.with_node(|node| node.with_name("bob"))
});
let config = if let Some(para_cmd) = network_spec.para_cmd {
config.with_teyrchain(|p| {
let mut p = p.with_id(TEYRCHAIN_ID).with_default_command(para_cmd);
if let Some(args) = network_spec.para_cmd_args {
p = p.with_default_args(args.into_iter().map(|arg| arg.into()).collect());
}
if let Some(path) = network_spec.para_chain_spec_path {
p = p.with_chain_spec_path(path);
}
p.with_collator(|n| n.with_name("collator"))
})
} else {
config
};
config.build().map_err(|e| {
let errs = e.into_iter().map(|e| e.to_string()).collect::<Vec<_>>().join(" ");
anyhow!("config errs: {errs}")
})
}
#[tokio::test(flavor = "multi_thread")]
async fn teyrchain_template_block_production_test() -> Result<(), anyhow::Error> {
let _ = env_logger::try_init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);
let config = get_config(NetworkSpec {
relaychain_cmd: "pezkuwi",
para_cmd: Some("teyrchain-template-node"),
..Default::default()
})?;
let network = config.spawn_native().await?;
// wait 6 blocks of the para
let collator = network.get_node("collator")?;
assert!(collator
.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
.await
.is_ok());
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn solochain_template_block_production_test() -> Result<(), anyhow::Error> {
let _ = env_logger::try_init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);
let config = get_config(NetworkSpec {
relaychain_cmd: "solochain-template-node",
..Default::default()
})?;
let network = config.spawn_native().await?;
// wait 6 blocks
let alice = network.get_node("alice")?;
assert!(alice
.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
.await
.is_ok());
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn minimal_template_block_production_test() -> Result<(), anyhow::Error> {
let _ = env_logger::try_init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);
let config = get_config(NetworkSpec {
relaychain_cmd: "minimal-template-node",
..Default::default()
})?;
let network = config.spawn_native().await?;
// wait 6 blocks
let alice = network.get_node("alice")?;
assert!(alice
.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
.await
.is_ok());
Ok(())
}
#[tokio::test(flavor = "multi_thread")]
async fn omni_node_with_teyrchain_runtime_block_production_test() -> Result<(), anyhow::Error> {
let _ = env_logger::try_init_from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);
let chain_spec_path = expect_env_var(CHAIN_SPECS_DIR_PATH) + "/teyrchain_chain_spec.json";
let config = get_config(NetworkSpec {
relaychain_cmd: "pezkuwi",
para_cmd: Some("pezkuwi-omni-node"),
para_chain_spec_path: Some(PathBuf::from(chain_spec_path)),
..Default::default()
})?;
let network = config.spawn_native().await?;
// wait 6 blocks
let alice = network.get_node("collator")?;
assert!(alice
.wait_metric("block_height{status=\"finalized\"}", |b| b > 5_f64)
.await
.is_ok());
Ok(())
}
}