mirror of
https://github.com/pezkuwichain/pwap.git
synced 2026-04-24 16:37:55 +00:00
Rebrand: polkadot → pezkuwi build fixes
- Fixed TypeScript type assertion issues - Updated imports from api-augment/substrate to api-augment/bizinikiwi - Fixed imgConvert.mjs header and imports - Added @ts-expect-error for runtime-converted types - Fixed all @polkadot copyright headers to @pezkuwi
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
//! by opening a pull request to the `pezkuwi-sdk` repository.
|
||||
//!
|
||||
//! - [Pezkuwi NFT Marketplace Tutorial by Pezkuwi Fellow Shawn Tabrizi](https://www.shawntabrizi.com/substrate-collectables-workshop/)
|
||||
//! - [HEZ Code School](https://dotcodeschool.com/)
|
||||
//! - [HEZ Code School](https://pezkuwichain.io/docs/introduction)
|
||||
//! - [Pezkuwi Developers Github Organization](https://github.com/polkadot-developers/)
|
||||
//! - [Pezkuwi Blockchain Academy](https://github.com/pezkuwichain/kurdistan_blockchain-akademy)
|
||||
//! - [Pezkuwi Wiki](https://wiki.network.pezkuwichain.io/)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! # Upgrade Teyrchain for Asynchronous Backing Compatibility
|
||||
//!
|
||||
//! This guide is relevant for cumulus based teyrchain projects started in 2023 or before, whose
|
||||
//! This guide is relevant for pezcumulus based teyrchain projects started in 2023 or before, whose
|
||||
//! backing process is synchronous where parablocks can only be built on the latest Relay Chain
|
||||
//! block. Async Backing allows collators to build parablocks on older Relay Chain blocks and create
|
||||
//! pipelines of multiple pending parablocks. This parallel block generation increases efficiency
|
||||
@@ -53,21 +53,21 @@
|
||||
//! 3. Establish constants `MILLISECS_PER_BLOCK` and `SLOT_DURATION` if not already present in the
|
||||
//! runtime.
|
||||
//! ```ignore
|
||||
//! // `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
|
||||
//! // up by `pallet_aura` to implement `fn slot_duration()`.
|
||||
//! // `SLOT_DURATION` is picked up by `pezpallet_timestamp` which is in turn picked
|
||||
//! // up by `pezpallet_aura` to implement `fn slot_duration()`.
|
||||
//! //
|
||||
//! // Change this to adjust the block time.
|
||||
//! pub const MILLISECS_PER_BLOCK: u64 = 12000;
|
||||
//! pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
|
||||
//! ```
|
||||
//!
|
||||
//! 4. Configure `cumulus_pallet_teyrchain_system` in the runtime.
|
||||
//! 4. Configure `pezcumulus_pezpallet_teyrchain_system` in the runtime.
|
||||
//!
|
||||
//! - Define a `FixedVelocityConsensusHook` using our capacity, velocity, and relay slot duration
|
||||
//! constants. Use this to set the teyrchain system `ConsensusHook` property.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", ConsensusHook)]
|
||||
//! ```ignore
|
||||
//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
//! impl pezcumulus_pezpallet_teyrchain_system::Config for Runtime {
|
||||
//! ..
|
||||
//! type ConsensusHook = ConsensusHook;
|
||||
//! ..
|
||||
@@ -76,21 +76,21 @@
|
||||
//! - Set the teyrchain system property `CheckAssociatedRelayNumber` to
|
||||
//! `RelayNumberMonotonicallyIncreases`
|
||||
//! ```ignore
|
||||
//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
//! impl pezcumulus_pezpallet_teyrchain_system::Config for Runtime {
|
||||
//! ..
|
||||
//! type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
|
||||
//! ..
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! 5. Configure `pallet_aura` in the runtime.
|
||||
//! 5. Configure `pezpallet_aura` in the runtime.
|
||||
//!
|
||||
//! - Set `AllowMultipleBlocksPerSlot` to `false` (don't worry, we will set it to `true` when we
|
||||
//! activate async backing in phase 3).
|
||||
//!
|
||||
//! - Define `pallet_aura::SlotDuration` using our constant `SLOT_DURATION`
|
||||
//! - Define `pezpallet_aura::SlotDuration` using our constant `SLOT_DURATION`
|
||||
//! ```ignore
|
||||
//! impl pallet_aura::Config for Runtime {
|
||||
//! impl pezpallet_aura::Config for Runtime {
|
||||
//! ..
|
||||
//! type AllowMultipleBlocksPerSlot = ConstBool<false>;
|
||||
//! #[cfg(feature = "experimental")]
|
||||
@@ -99,25 +99,25 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! 6. Update `sp_consensus_aura::AuraApi::slot_duration` in `sp_api::impl_runtime_apis` to match
|
||||
//! the constant `SLOT_DURATION`
|
||||
//! 6. Update `pezsp_consensus_aura::AuraApi::slot_duration` in `pezsp_api::impl_runtime_apis` to
|
||||
//! match the constant `SLOT_DURATION`
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/apis.rs", impl_slot_duration)]
|
||||
//!
|
||||
//! 7. Implement the `AuraUnincludedSegmentApi`, which allows the collator client to query its
|
||||
//! runtime to determine whether it should author a block.
|
||||
//!
|
||||
//! - Add the dependency `cumulus-primitives-aura` to the `runtime/Cargo.toml` file for your
|
||||
//! - Add the dependency `pezcumulus-primitives-aura` to the `runtime/Cargo.toml` file for your
|
||||
//! runtime
|
||||
//! ```ignore
|
||||
//! ..
|
||||
//! cumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false }
|
||||
//! pezcumulus-primitives-aura = { path = "../../../../primitives/aura", default-features = false }
|
||||
//! ..
|
||||
//! ```
|
||||
//!
|
||||
//! - In the same file, add `"cumulus-primitives-aura/std",` to the `std` feature.
|
||||
//! - In the same file, add `"pezcumulus-primitives-aura/std",` to the `std` feature.
|
||||
//!
|
||||
//! - Inside the `impl_runtime_apis!` block for your runtime, implement the
|
||||
//! `cumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below.
|
||||
//! `pezcumulus_primitives_aura::AuraUnincludedSegmentApi` as shown below.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/apis.rs", impl_can_build_upon)]
|
||||
//!
|
||||
//! **Note:** With a capacity of 1 we have an effective velocity of ½ even when velocity is
|
||||
@@ -136,13 +136,13 @@
|
||||
//!
|
||||
//! This phase consists of plugging in the new lookahead collator node.
|
||||
//!
|
||||
//! 1. Import `cumulus_primitives_core::ValidationCode` to `node/src/service.rs`.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/node/src/service.rs", cumulus_primitives)]
|
||||
//! 1. Import `pezcumulus_primitives_core::ValidationCode` to `node/src/service.rs`.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/node/src/service.rs", pezcumulus_primitives)]
|
||||
//!
|
||||
//! 2. In `node/src/service.rs`, modify `sc_service::spawn_tasks` to use a clone of `Backend` rather
|
||||
//! than the original
|
||||
//! 2. In `node/src/service.rs`, modify `pezsc_service::spawn_tasks` to use a clone of `Backend`
|
||||
//! rather than the original
|
||||
//! ```ignore
|
||||
//! sc_service::spawn_tasks(sc_service::SpawnTasksParams {
|
||||
//! pezsc_service::spawn_tasks(pezsc_service::SpawnTasksParams {
|
||||
//! ..
|
||||
//! backend: backend.clone(),
|
||||
//! ..
|
||||
@@ -197,7 +197,7 @@
|
||||
//! 6. In `start_consensus()` replace `basic_aura::run` with `aura::run`
|
||||
//! ```ignore
|
||||
//! let fut =
|
||||
//! aura::run::<Block, sp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
|
||||
//! aura::run::<Block, pezsp_consensus_aura::sr25519::AuthorityPair, _, _, _, _, _, _, _, _, _>(
|
||||
//! params,
|
||||
//! );
|
||||
//! task_manager.spawn_essential_handle().spawn("aura", None, fut);
|
||||
@@ -207,7 +207,7 @@
|
||||
//!
|
||||
//! This phase consists of changes to your teyrchain’s runtime that activate async backing feature.
|
||||
//!
|
||||
//! 1. Configure `pallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in
|
||||
//! 1. Configure `pezpallet_aura`, setting `AllowMultipleBlocksPerSlot` to true in
|
||||
//! `runtime/src/lib.rs`.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/configs/mod.rs", aura_config)]
|
||||
//!
|
||||
@@ -224,11 +224,11 @@
|
||||
//! 4. Update `MAXIMUM_BLOCK_WEIGHT` to reflect the increased time available for block production.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", max_block_weight)]
|
||||
//!
|
||||
//! 5. Add a feature flagged alternative for `MinimumPeriod` in `pallet_timestamp`. The type should
|
||||
//! be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION / 2}>`
|
||||
//! without.
|
||||
//! 5. Add a feature flagged alternative for `MinimumPeriod` in `pezpallet_timestamp`. The type
|
||||
//! should be `ConstU64<0>` with the feature flag experimental, and `ConstU64<{SLOT_DURATION /
|
||||
//! 2}>` without.
|
||||
//! ```ignore
|
||||
//! impl pallet_timestamp::Config for Runtime {
|
||||
//! impl pezpallet_timestamp::Config for Runtime {
|
||||
//! ..
|
||||
//! #[cfg(feature = "experimental")]
|
||||
//! type MinimumPeriod = ConstU64<0>;
|
||||
@@ -246,7 +246,7 @@
|
||||
//! actual time not matching up, stalling the teyrchain.
|
||||
//!
|
||||
//! One strategy to deal with this issue is to instead rely on relay chain block numbers for timing.
|
||||
//! Relay block number is kept track of by each teyrchain in `pallet-teyrchain-system` with the
|
||||
//! Relay block number is kept track of by each teyrchain in `pezpallet-teyrchain-system` with the
|
||||
//! storage value `LastRelayChainBlockNumber`. This value can be obtained and used wherever timing
|
||||
//! based on block number is needed.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
//! # Cumulus Enabled Teyrchain
|
||||
@@ -66,7 +66,7 @@
|
||||
//!
|
||||
//! ### UMP signals
|
||||
//!
|
||||
//! UMP signals are now enabled by default in the `teyrchain-system` pallet and are used for
|
||||
//! UMP signals are now enabled by default in the `teyrchain-system` pezpallet and are used for
|
||||
//! elastic scaling. You can find more technical details about UMP signals and their usage for
|
||||
//! elastic scaling
|
||||
//! [here](https://github.com/polkadot-fellows/RFCs/blob/main/text/0103-introduce-core-index-commitment.md).
|
||||
@@ -81,7 +81,7 @@
|
||||
//! /// Build with an offset of 1 behind the relay chain best block.
|
||||
//! const RELAY_PARENT_OFFSET: u32 = 1;
|
||||
//!
|
||||
//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
//! impl pezcumulus_pezpallet_teyrchain_system::Config for Runtime {
|
||||
//! // ...
|
||||
//! type RelayParentOffset = ConstU32<RELAY_PARENT_OFFSET>;
|
||||
//! }
|
||||
@@ -89,7 +89,7 @@
|
||||
//!
|
||||
//! Implement the runtime API to retrieve the offset on the client side.
|
||||
//! ```ignore
|
||||
//! impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
//! impl pezcumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
//! fn relay_parent_offset() -> u32 {
|
||||
//! RELAY_PARENT_OFFSET
|
||||
//! }
|
||||
@@ -117,7 +117,7 @@
|
||||
//! /// Relay chain slot duration, in milliseconds.
|
||||
//! const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
|
||||
//!
|
||||
//! type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
|
||||
//! type ConsensusHook = pezcumulus_pezpallet_aura_ext::FixedVelocityConsensusHook<
|
||||
//! Runtime,
|
||||
//! RELAY_CHAIN_SLOT_DURATION_MILLIS,
|
||||
//! BLOCK_PROCESSING_VELOCITY,
|
||||
@@ -129,9 +129,9 @@
|
||||
//! ### Teyrchain Slot Duration
|
||||
//!
|
||||
//! A common source of confusion is the correct configuration of the `SlotDuration` that is passed
|
||||
//! to `pallet-aura`.
|
||||
//! to `pezpallet-aura`.
|
||||
//! ```ignore
|
||||
//! impl pallet_aura::Config for Runtime {
|
||||
//! impl pezpallet_aura::Config for Runtime {
|
||||
//! // ...
|
||||
//! type SlotDuration = ConstU64<SLOT_DURATION>;
|
||||
//! }
|
||||
|
||||
@@ -44,8 +44,8 @@
|
||||
//! ### Runtime integration
|
||||
//!
|
||||
//! From the runtime side only the
|
||||
//! [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash) needs to be added to the
|
||||
//! list of signed extension:
|
||||
//! [`CheckMetadataHash`](pezframe_metadata_hash_extension::CheckMetadataHash) needs to be added to
|
||||
//! the list of signed extension:
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/src/lib.rs", template_signed_extra)]
|
||||
//!
|
||||
//! > **Note:**
|
||||
@@ -64,19 +64,20 @@
|
||||
//!
|
||||
//! The extension does not work with the native runtime, because the
|
||||
//! `RUNTIME_METADATA_HASH` environment variable is not set when building the
|
||||
//! `frame-metadata-hash-extension` crate.
|
||||
//! `pezframe-metadata-hash-extension` crate.
|
||||
//!
|
||||
//! </div>
|
||||
//!
|
||||
//! ### Enable metadata hash generation
|
||||
//!
|
||||
//! The metadata hash generation needs to be enabled when building the wasm binary. The
|
||||
//! `substrate-wasm-builder` supports this out of the box:
|
||||
//! `bizinikiwi-wasm-builder` supports this out of the box:
|
||||
#![doc = docify::embed!("../../templates/teyrchain/runtime/build.rs", template_enable_metadata_hash)]
|
||||
//!
|
||||
//! > **Note:**
|
||||
//! >
|
||||
//! > The `metadata-hash` feature needs to be enabled for the `substrate-wasm-builder` to enable the
|
||||
//! > The `metadata-hash` feature needs to be enabled for the `bizinikiwi-wasm-builder` to enable
|
||||
//! > the
|
||||
//! > code for being able to generate the metadata hash. It is also recommended to put the metadata
|
||||
//! > hash generation behind a feature in the runtime as shown above. The reason behind is that it
|
||||
//! > adds a lot of code which increases the compile time and the generation itself also increases
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
//!
|
||||
//! This guide will teach you how to enable storage weight reclaiming for a teyrchain. The
|
||||
//! explanations in this guide assume a project structure similar to the one detailed in
|
||||
//! the [substrate documentation](crate::pezkuwi_sdk::substrate#anatomy-of-a-binary-crate). Full
|
||||
//! technical details are available in the original [pull request](https://github.com/paritytech/polkadot-sdk/pull/3002).
|
||||
//! the [bizinikiwi documentation](crate::pezkuwi_sdk::bizinikiwi#anatomy-of-a-binary-crate). Full
|
||||
//! technical details are available in the original [pull request](https://github.com/pezkuwichain/pezkuwi-sdk/issues/257).
|
||||
//!
|
||||
//! # What is PoV reclaim?
|
||||
//! When a teyrchain submits a block to a relay chain like Pezkuwi or Kusama, it sends the block
|
||||
@@ -12,7 +12,7 @@
|
||||
//! validators distribute this PoV among themselves over the network. This distribution is costly
|
||||
//! and limits the size of the storage proof. The storage weight dimension of FRAME weights reflects
|
||||
//! this cost and limits the size of the storage proof. However, the storage weight determined
|
||||
//! during [benchmarking](crate::reference_docs::frame_benchmarking_weight) represents the worst
|
||||
//! during [benchmarking](crate::reference_docs::pezframe_benchmarking_weight) represents the worst
|
||||
//! case. In reality, runtime operations often consume less space in the storage proof. PoV reclaim
|
||||
//! offers a mechanism to reclaim the difference between the benchmarked worst-case and the real
|
||||
//! proof-size consumption.
|
||||
@@ -24,12 +24,12 @@
|
||||
//! To reclaim excess storage weight, a teyrchain runtime needs the
|
||||
//! ability to fetch the size of the storage proof from the node. The reclaim
|
||||
//! mechanism uses the
|
||||
//! [`storage_proof_size`](cumulus_primitives_proof_size_hostfunction::storage_proof_size)
|
||||
//! host function for this purpose. For convenience, cumulus provides
|
||||
//! [`TeyrchainHostFunctions`](cumulus_client_service::TeyrchainHostFunctions), a set of
|
||||
//! host functions typically used by cumulus-based teyrchains. In the binary crate of your
|
||||
//! teyrchain, find the instantiation of the [`WasmExecutor`](sc_executor::WasmExecutor) and set the
|
||||
//! correct generic type.
|
||||
//! [`storage_proof_size`](pezcumulus_primitives_proof_size_hostfunction::storage_proof_size)
|
||||
//! host function for this purpose. For convenience, pezcumulus provides
|
||||
//! [`TeyrchainHostFunctions`](pezcumulus_client_service::TeyrchainHostFunctions), a set of
|
||||
//! host functions typically used by pezcumulus-based teyrchains. In the binary crate of your
|
||||
//! teyrchain, find the instantiation of the [`WasmExecutor`](pezsc_executor::WasmExecutor) and set
|
||||
//! the correct generic type.
|
||||
//!
|
||||
//! This example from the teyrchain-template shows a type definition that includes the correct
|
||||
//! host functions.
|
||||
@@ -46,9 +46,9 @@
|
||||
//! The reclaim mechanism reads the size of the currently recorded storage proof multiple times
|
||||
//! during block authoring and block import. Proof recording during authoring is already enabled on
|
||||
//! teyrchains. You must also ensure that storage proof recording is enabled during block import.
|
||||
//! Find where your node builds the fundamental substrate components by calling
|
||||
//! [`new_full_parts`](sc_service::new_full_parts). Replace this
|
||||
//! with [`new_full_parts_record_import`](sc_service::new_full_parts_record_import) and
|
||||
//! Find where your node builds the fundamental bizinikiwi components by calling
|
||||
//! [`new_full_parts`](pezsc_service::new_full_parts). Replace this
|
||||
//! with [`new_full_parts_record_import`](pezsc_service::new_full_parts_record_import) and
|
||||
//! pass `true` as the last parameter to enable import recording.
|
||||
#![doc = docify::embed!("../../templates/teyrchain/node/src/service.rs", component_instantiation)]
|
||||
//!
|
||||
@@ -62,7 +62,7 @@
|
||||
//!
|
||||
//! In your runtime, you will find a list of TransactionExtensions.
|
||||
//! To enable the reclaiming,
|
||||
//! set [`StorageWeightReclaim`](cumulus_pallet_weight_reclaim::StorageWeightReclaim)
|
||||
//! set [`StorageWeightReclaim`](pezcumulus_pezpallet_weight_reclaim::StorageWeightReclaim)
|
||||
//! as a warpper of that list.
|
||||
//! It is necessary that this extension wraps all the other transaction extensions in order to catch
|
||||
//! the whole PoV size of the transactions.
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
//! latency and reduces throughput, affecting the overall performance of the teyrchain.
|
||||
//!
|
||||
//! # Building on Older Pelay Parents
|
||||
//! Cumulus offers a way to mitigate the occurence of forks. Instead of picking a block at the tip
|
||||
//! of the relay chain to build blocks, the node side can pick a relay chain block that is older. By
|
||||
//! building on 12s old relay chain blocks, forks will already have settled and the teyrchain can
|
||||
//! build fork-free.
|
||||
//! Pezcumulus offers a way to mitigate the occurence of forks. Instead of picking a block at the
|
||||
//! tip of the relay chain to build blocks, the node side can pick a relay chain block that is
|
||||
//! older. By building on 12s old relay chain blocks, forks will already have settled and the
|
||||
//! teyrchain can build fork-free.
|
||||
//!
|
||||
//! ```text
|
||||
//! Without offset:
|
||||
@@ -68,10 +68,10 @@
|
||||
//! ```ignore
|
||||
//! const RELAY_PARENT_OFFSET = 2;
|
||||
//! ```
|
||||
//! 2. Pass this constant to the `teyrchain-system` pallet.
|
||||
//! 2. Pass this constant to the `teyrchain-system` pezpallet.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
//! impl pezcumulus_pezpallet_teyrchain_system::Config for Runtime {
|
||||
//! // Other config items here
|
||||
//! ...
|
||||
//! type RelayParentOffset = ConstU32<RELAY_PARENT_OFFSET>;
|
||||
@@ -80,7 +80,7 @@
|
||||
//! 3. Implement the `RelayParentOffsetApi` runtime API for your runtime.
|
||||
//!
|
||||
//! ```ignore
|
||||
//! impl cumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
//! impl pezcumulus_primitives_core::RelayParentOffsetApi<Block> for Runtime {
|
||||
//! fn relay_parent_offset() -> u32 {
|
||||
//! RELAY_PARENT_OFFSET
|
||||
//! }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//!
|
||||
//! The main user-journey covered by these guides is:
|
||||
//!
|
||||
//! * [`your_first_pallet`], where you learn what a FRAME pallet is, and write your first
|
||||
//! * [`your_first_pallet`], where you learn what a FRAME pezpallet is, and write your first
|
||||
//! application logic.
|
||||
//! * [`your_first_runtime`], where you learn how to compile your pallets into a WASM runtime.
|
||||
//! * [`your_first_node`], where you learn how to run the said runtime in a node.
|
||||
@@ -20,17 +20,17 @@
|
||||
//!
|
||||
//! Other guides are related to other miscellaneous topics and are listed as modules below.
|
||||
|
||||
/// Write your first simple pallet, learning the most most basic features of FRAME along the way.
|
||||
/// Write your first simple pezpallet, learning the most most basic features of FRAME along the way.
|
||||
pub mod your_first_pallet;
|
||||
|
||||
/// Write your first real [runtime](`crate::reference_docs::wasm_meta_protocol`),
|
||||
/// compiling it to [WASM](crate::pezkuwi_sdk::substrate#wasm-build).
|
||||
/// compiling it to [WASM](crate::pezkuwi_sdk::bizinikiwi#wasm-build).
|
||||
pub mod your_first_runtime;
|
||||
|
||||
/// Running the given runtime with a node. No specific consensus mechanism is used at this stage.
|
||||
pub mod your_first_node;
|
||||
|
||||
/// How to enhance a given runtime and node to be cumulus-enabled, run it as a teyrchain
|
||||
/// How to enhance a given runtime and node to be pezcumulus-enabled, run it as a teyrchain
|
||||
/// and connect it to a relay-chain.
|
||||
// pub mod your_first_teyrchain;
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
//! # Pezcumulus Enabled Teyrchain
|
||||
@@ -6,7 +6,7 @@
|
||||
//! other options when it comes to running a node.
|
||||
//!
|
||||
//! [`your_first_runtime`] is a runtime with no consensus related code, and therefore can only be
|
||||
//! executed with a node that also expects no consensus ([`sc_consensus_manual_seal`]).
|
||||
//! executed with a node that also expects no consensus ([`pezsc_consensus_manual_seal`]).
|
||||
//! `pezkuwi-omni-node`'s [`--dev-block-time`] precisely does this.
|
||||
//!
|
||||
//! > All of the following steps are coded as unit tests of this module. Please see `Source` of the
|
||||
@@ -28,7 +28,7 @@
|
||||
//! described in [`crate::guides::your_first_runtime#genesis-configuration`].
|
||||
//!
|
||||
//! ```text
|
||||
//! cargo install staging-chain-spec-builder
|
||||
//! cargo install pezstaging-chain-spec-builder
|
||||
//! ```
|
||||
//!
|
||||
//! > The name of the crate is prefixed with `staging` as the crate name `chain-spec-builder` on
|
||||
@@ -49,7 +49,7 @@
|
||||
//! ### Building Chain Spec
|
||||
//!
|
||||
//! Next, we can generate the corresponding chain-spec file. For this example, we will use the
|
||||
//! `development` (`sp_genesis_config::DEVELOPMENT`) preset.
|
||||
//! `development` (`pezsp_genesis_config::DEVELOPMENT`) preset.
|
||||
//!
|
||||
//! Note that we intend to run this chain-spec with `pezkuwi-omni-node`, which is tailored for
|
||||
//! running teyrchains. This requires the chain-spec to always contain the `para_id` and a
|
||||
@@ -82,7 +82,7 @@
|
||||
//!
|
||||
//! > Note that we always prefer to use `--tmp` for testing, as it will save the chain state to a
|
||||
//! > temporary folder, allowing the chain-to be easily restarted without `purge-chain`. See
|
||||
//! > [`sc_cli::commands::PurgeChainCmd`] and [`sc_cli::commands::RunCmd::tmp`] for more info.
|
||||
//! > [`pezsc_cli::commands::PurgeChainCmd`] and [`pezsc_cli::commands::RunCmd::tmp`] for more info.
|
||||
//!
|
||||
//! This will start the node and import the blocks. Note while using `--dev-block-time`, the node
|
||||
//! will use the testing-specific manual-seal consensus. This is an efficient way to test the
|
||||
@@ -103,9 +103,9 @@
|
||||
mod tests {
|
||||
use assert_cmd::assert::OutputAssertExt;
|
||||
use cmd_lib::*;
|
||||
use pezsc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET};
|
||||
use pezsp_genesis_builder::PresetId;
|
||||
use rand::Rng;
|
||||
use sc_chain_spec::{DEV_RUNTIME_PRESET, LOCAL_TESTNET_RUNTIME_PRESET};
|
||||
use sp_genesis_builder::PresetId;
|
||||
use std::{
|
||||
io::{BufRead, BufReader},
|
||||
path::PathBuf,
|
||||
@@ -182,7 +182,7 @@ mod tests {
|
||||
.arg("build")
|
||||
.arg("--release")
|
||||
.arg("-p")
|
||||
.arg("staging-chain-spec-builder")
|
||||
.arg("pezstaging-chain-spec-builder")
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
@@ -224,7 +224,7 @@ mod tests {
|
||||
block_time: u64,
|
||||
maybe_preset: Option<PresetId>,
|
||||
) {
|
||||
sp_tracing::try_init_simple();
|
||||
pezsp_tracing::try_init_simple();
|
||||
maybe_build_runtimes();
|
||||
maybe_build_chain_spec_builder();
|
||||
maybe_build_omni_node();
|
||||
@@ -332,7 +332,7 @@ mod tests {
|
||||
#[tokio::test]
|
||||
// This is a regresion test so that we still remain compatible with runtimes that use
|
||||
// `para-id` in chain specs, instead of implementing the
|
||||
// `cumulus_primitives_core::GetTeyrchainInfo`.
|
||||
// `pezcumulus_primitives_core::GetTeyrchainInfo`.
|
||||
async fn omni_node_dev_mode_works_without_getteyrchaininfo() {
|
||||
let dev_chain_spec = std::env::current_dir()
|
||||
.unwrap()
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
//! # Currency Pallet
|
||||
//! # Currency Pezpallet
|
||||
//!
|
||||
//! By the end of this guide, you will have written a small FRAME pallet (see
|
||||
//! By the end of this guide, you will have written a small FRAME pezpallet (see
|
||||
//! [`crate::pezkuwi_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency.
|
||||
//! This pallet will:
|
||||
//! This pezpallet will:
|
||||
//!
|
||||
//! 1. Allow anyone to mint new tokens into accounts (which is obviously not a great idea for a real
|
||||
//! system).
|
||||
//! 2. Allow any user that owns tokens to transfer them to others.
|
||||
//! 3. Track the total issuance of all tokens at all times.
|
||||
//!
|
||||
//! > This guide will build a currency pallet from scratch using only the lowest primitives of
|
||||
//! > This guide will build a currency pezpallet from scratch using only the lowest primitives of
|
||||
//! > FRAME, and is mainly intended for education, not *applicability*. For example, almost all
|
||||
//! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing
|
||||
//! > FRAME-based runtimes use various techniques to re-use a currency pezpallet instead of writing
|
||||
//! > one. Further advanced FRAME related topics are discussed in [`crate::reference_docs`].
|
||||
//!
|
||||
//! ## Writing Your First Pallet
|
||||
//! ## Writing Your First Pezpallet
|
||||
//!
|
||||
//! To get started, clone one of the templates mentioned in [`crate::pezkuwi_sdk::templates`]. We
|
||||
//! recommend using the `pezkuwi-sdk-minimal-template`. You might need to change small parts of
|
||||
@@ -33,23 +33,23 @@
|
||||
//!
|
||||
//! The following FRAME topics are covered in this guide:
|
||||
//!
|
||||
//! - [`pallet::storage`]
|
||||
//! - [`pallet::call`]
|
||||
//! - [`pallet::event`]
|
||||
//! - [`pallet::error`]
|
||||
//! - Basics of testing a pallet
|
||||
//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime)
|
||||
//! - [`pezpallet::storage`]
|
||||
//! - [`pezpallet::call`]
|
||||
//! - [`pezpallet::event`]
|
||||
//! - [`pezpallet::error`]
|
||||
//! - Basics of testing a pezpallet
|
||||
//! - [Constructing a runtime](pezframe::runtime::prelude::construct_runtime)
|
||||
//!
|
||||
//! ### Shell Pallet
|
||||
//! ### Shell Pezpallet
|
||||
//!
|
||||
//! Consider the following as a "shell pallet". We continue building the rest of this pallet based
|
||||
//! on this template.
|
||||
//! Consider the following as a "shell pezpallet". We continue building the rest of this pezpallet
|
||||
//! based on this template.
|
||||
//!
|
||||
//! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any
|
||||
//! pallet. Refer to the documentation of each to get an overview of what they do.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", shell_pallet)]
|
||||
//! [`pezpallet::config`] and [`pezpallet::pezpallet`] are both mandatory parts of any
|
||||
//! pezpallet. Refer to the documentation of each to get an overview of what they do.
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", shell_pallet)]
|
||||
//!
|
||||
//! All of the code that follows in this guide should live inside of the `mod pallet`.
|
||||
//! All of the code that follows in this guide should live inside of the `mod pezpallet`.
|
||||
//!
|
||||
//! ### Storage
|
||||
//!
|
||||
@@ -59,117 +59,120 @@
|
||||
//! issuance.
|
||||
//!
|
||||
//! > For the rest of this guide, we will opt for a balance type of `u128`. For the sake of
|
||||
//! > simplicity, we are hardcoding this type. In a real pallet is best practice to define it as a
|
||||
//! > simplicity, we are hardcoding this type. In a real pezpallet is best practice to define it as
|
||||
//! > a
|
||||
//! > generic bounded type in the `Config` trait, and then specify it in the implementation.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balance)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", Balance)]
|
||||
//!
|
||||
//! The definition of these two storage items, based on [`pallet::storage`] details, is as follows:
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", TotalIssuance)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Balances)]
|
||||
//! The definition of these two storage items, based on [`pezpallet::storage`] details, is as
|
||||
//! follows:
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", TotalIssuance)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", Balances)]
|
||||
//!
|
||||
//! ### Dispatchables
|
||||
//!
|
||||
//! Next, we will define the dispatchable functions. As per [`pallet::call`], these will be defined
|
||||
//! as normal `fn`s attached to `struct Pallet`.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_pallet)]
|
||||
//! Next, we will define the dispatchable functions. As per [`pezpallet::call`], these will be
|
||||
//! defined as normal `fn`s attached to `struct Pezpallet`.
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", impl_pallet)]
|
||||
//!
|
||||
//! The logic of these functions is self-explanatory. Instead, we will focus on the FRAME-related
|
||||
//! details:
|
||||
//!
|
||||
//! - Where do `T::AccountId` and `T::RuntimeOrigin` come from? These are both defined in
|
||||
//! [`frame::prelude::frame_system::Config`], therefore we can access them in `T`.
|
||||
//! [`pezframe::prelude::pezframe_system::Config`], therefore we can access them in `T`.
|
||||
//! - What is `ensure_signed`, and what does it do with the aforementioned `T::RuntimeOrigin`? This
|
||||
//! is outside the scope of this guide, and you can learn more about it in the origin reference
|
||||
//! document ([`crate::reference_docs::frame_origin`]). For now, you should only know the
|
||||
//! signature of the function: it takes a generic `T::RuntimeOrigin` and returns a
|
||||
//! `Result<T::AccountId, _>`. So by the end of this function call, we know that this dispatchable
|
||||
//! was signed by `sender`.
|
||||
#![doc = docify::embed!("../../substrate/frame/system/src/lib.rs", ensure_signed)]
|
||||
#![doc = docify::embed!("../../bizinikiwi/pezframe/system/src/lib.rs", ensure_signed)]
|
||||
//!
|
||||
//! - Where does `mutate`, `get` and `insert` and other storage APIs come from? All of them are
|
||||
//! explained in the corresponding `type`, for example, for `Balances::<T>::insert`, you can look
|
||||
//! into [`frame::prelude::StorageMap::insert`].
|
||||
//! into [`pezframe::prelude::StorageMap::insert`].
|
||||
//!
|
||||
//! - The return type of all dispatchable functions is [`frame::prelude::DispatchResult`]:
|
||||
#![doc = docify::embed!("../../substrate/frame/support/src/dispatch.rs", DispatchResult)]
|
||||
//! - The return type of all dispatchable functions is [`pezframe::prelude::DispatchResult`]:
|
||||
#![doc = docify::embed!("../../bizinikiwi/pezframe/support/src/dispatch.rs", DispatchResult)]
|
||||
//!
|
||||
//! Which is more or less a normal Rust `Result`, with a custom [`frame::prelude::DispatchError`] as
|
||||
//! Which is more or less a normal Rust `Result`, with a custom [`pezframe::prelude::DispatchError`] as
|
||||
//! the `Err` variant. We won't cover this error in detail here, but importantly you should know
|
||||
//! that there is an `impl From<&'static string> for DispatchError` provided (see
|
||||
//! [here](`frame::prelude::DispatchError#impl-From<%26str>-for-DispatchError`)). Therefore,
|
||||
//! [here](`pezframe::prelude::DispatchError#impl-From<%26str>-for-DispatchError`)). Therefore,
|
||||
//! we can use basic string literals as our error type and `.into()` them into `DispatchError`.
|
||||
//!
|
||||
//! - Why are all `get` and `mutate` functions returning an `Option`? This is the default behavior
|
||||
//! of FRAME storage APIs. You can learn more about how to override this by looking into
|
||||
//! [`pallet::storage`], and [`frame::prelude::ValueQuery`]/[`frame::prelude::OptionQuery`]
|
||||
//! [`pezpallet::storage`], and [`pezframe::prelude::ValueQuery`]/[`pezframe::prelude::OptionQuery`]
|
||||
//!
|
||||
//! ### Improving Errors
|
||||
//!
|
||||
//! How we handle error in the above snippets is fairly rudimentary. Let's look at how this can be
|
||||
//! improved. First, we can use [`frame::prelude::ensure`] to express the error slightly better.
|
||||
//! improved. First, we can use [`pezframe::prelude::ensure`] to express the error slightly better.
|
||||
//! This macro will call `.into()` under the hood.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", transfer_better)]
|
||||
//!
|
||||
//! Moreover, you will learn in the [Defensive Programming
|
||||
//! section](crate::reference_docs::defensive_programming) that it is always recommended to use
|
||||
//! safe arithmetic operations in your runtime. By using [`frame::traits::CheckedSub`], we can not
|
||||
//! safe arithmetic operations in your runtime. By using [`pezframe::traits::CheckedSub`], we can not
|
||||
//! only take a step in that direction, but also improve the error handing and make it slightly more
|
||||
//! ergonomic.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_better_checked)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", transfer_better_checked)]
|
||||
//!
|
||||
//! This is more or less all the logic that there is in this basic currency pallet!
|
||||
//! This is more or less all the logic that there is in this basic currency pezpallet!
|
||||
//!
|
||||
//! ### Your First (Test) Runtime
|
||||
//!
|
||||
//! The typical testing code of a pallet lives in a module that imports some preludes useful for
|
||||
//! The typical testing code of a pezpallet lives in a module that imports some preludes useful for
|
||||
//! testing, similar to:
|
||||
//!
|
||||
//! ```
|
||||
//! pub mod pallet {
|
||||
//! // snip -- actually pallet code.
|
||||
//! pub mod pezpallet {
|
||||
//! // snip -- actually pezpallet code.
|
||||
//! }
|
||||
//!
|
||||
//! #[cfg(test)]
|
||||
//! mod tests {
|
||||
//! // bring in the testing prelude of frame
|
||||
//! use frame::testing_prelude::*;
|
||||
//! // bring in all pallet items
|
||||
//! use super::pallet::*;
|
||||
//! use pezframe::testing_prelude::*;
|
||||
//! // bring in all pezpallet items
|
||||
//! use super::pezpallet::*;
|
||||
//!
|
||||
//! // snip -- rest of the testing code.
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Next, we create a "test runtime" in order to test our pallet. Recall from
|
||||
//! Next, we create a "test runtime" in order to test our pezpallet. Recall from
|
||||
//! [`crate::pezkuwi_sdk::frame_runtime`] that a runtime is a collection of pallets, expressed
|
||||
//! through [`frame::runtime::prelude::construct_runtime`]. All runtimes also have to include
|
||||
//! [`frame::prelude::frame_system`]. So we expect to see a runtime with two pallet, `frame_system`
|
||||
//! and the one we just wrote.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime)]
|
||||
//! through [`pezframe::runtime::prelude::construct_runtime`]. All runtimes also have to include
|
||||
//! [`pezframe::prelude::pezframe_system`]. So we expect to see a runtime with two pezpallet,
|
||||
//! `pezframe_system` and the one we just wrote.
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", runtime)]
|
||||
//!
|
||||
//! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have
|
||||
//! > [`pezframe::pezpallet_macros::derive_impl`] is a FRAME feature that enables developers to have
|
||||
//! > defaults for associated types.
|
||||
//!
|
||||
//! Recall that within our pallet, (almost) all blocks of code are generic over `<T: Config>`. And,
|
||||
//! because `trait Config: frame_system::Config`, we can get access to all items in `Config` (or
|
||||
//! `frame_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how
|
||||
//! Recall that within our pezpallet, (almost) all blocks of code are generic over `<T: Config>`.
|
||||
//! And, because `trait Config: pezframe_system::Config`, we can get access to all items in `Config`
|
||||
//! (or `pezframe_system::Config`) using `T::NameOfItem`. This is all within the boundaries of how
|
||||
//! Rust traits and generics work. If unfamiliar with this pattern, read
|
||||
//! [`crate::reference_docs::trait_based_programming`] before going further.
|
||||
//!
|
||||
//! Crucially, a typical FRAME runtime contains a `struct Runtime`. The main role of this `struct`
|
||||
//! is to implement the `trait Config` of all pallets. That is, anywhere within your pallet code
|
||||
//! is to implement the `trait Config` of all pallets. That is, anywhere within your pezpallet code
|
||||
//! where you see `<T: Config>` (read: *"some type `T` that implements `Config`"*), in the runtime,
|
||||
//! it can be replaced with `<Runtime>`, because `Runtime` implements `Config` of all pallets, as we
|
||||
//! see above.
|
||||
//!
|
||||
//! Another way to think about this is that within a pallet, a lot of types are "unknown" and, we
|
||||
//! Another way to think about this is that within a pezpallet, a lot of types are "unknown" and, we
|
||||
//! only know that they will be provided at some later point. For example, when you write
|
||||
//! `T::AccountId` (which is short for `<T as frame_system::Config>::AccountId`) in your pallet,
|
||||
//! you are in fact saying "*Some type `AccountId` that will be known later*". That "later" is in
|
||||
//! fact when you specify these types when you implement all `Config` traits for `Runtime`.
|
||||
//! `T::AccountId` (which is short for `<T as pezframe_system::Config>::AccountId`) in your
|
||||
//! pezpallet, you are in fact saying "*Some type `AccountId` that will be known later*". That
|
||||
//! "later" is in fact when you specify these types when you implement all `Config` traits for
|
||||
//! `Runtime`.
|
||||
//!
|
||||
//! As you see above, `frame_system::Config` is setting the `AccountId` to `u64`. Of course, a real
|
||||
//! runtime will not use this type, and instead reside to a proper type like a 32-byte standard
|
||||
//! As you see above, `pezframe_system::Config` is setting the `AccountId` to `u64`. Of course, a
|
||||
//! real runtime will not use this type, and instead reside to a proper type like a 32-byte standard
|
||||
//! public key. This is a HUGE benefit that FRAME developers can tap into: through the framework
|
||||
//! being so generic, different types can always be customized to simple things when needed.
|
||||
//!
|
||||
@@ -178,23 +181,23 @@
|
||||
//!
|
||||
//! ### Your First Test
|
||||
//!
|
||||
//! The above is all you need to execute the dispatchables of your pallet. The last thing you need
|
||||
//! to learn is that all of your pallet testing code should be wrapped in
|
||||
//! [`frame::testing_prelude::TestState`]. This is a type that provides access to an in-memory state
|
||||
//! The above is all you need to execute the dispatchables of your pezpallet. The last thing you
|
||||
//! need to learn is that all of your pezpallet testing code should be wrapped in
|
||||
//! [`pezframe::testing_prelude::TestState`]. This is a type that provides access to an in-memory state
|
||||
//! to be used in our tests.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", first_test)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", first_test)]
|
||||
//!
|
||||
//! In the first test, we simply assert that there is no total issuance, and no balance associated
|
||||
//! with Alice's account. Then, we mint some balance into Alice's, and re-check.
|
||||
//!
|
||||
//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing `<T: Config>`.
|
||||
//! This is why for example you see `Balances::<Runtime>::get(..)`. Finally, notice that the
|
||||
//! dispatchables are simply functions that can be called on top of the `Pallet` struct.
|
||||
//! dispatchables are simply functions that can be called on top of the `Pezpallet` struct.
|
||||
//!
|
||||
//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional
|
||||
//! steps to improve our pallet.
|
||||
//! Congratulations! You have written your first pezpallet and tested it! Next, we learn a few
|
||||
//! optional steps to improve our pezpallet.
|
||||
//!
|
||||
//! ## Improving the Currency Pallet
|
||||
//! ## Improving the Currency Pezpallet
|
||||
//!
|
||||
//! ### Better Test Setup
|
||||
//!
|
||||
@@ -206,16 +209,16 @@
|
||||
//!
|
||||
//! Let's see how we can implement a better test setup using this pattern. First, we define a
|
||||
//! `struct StateBuilder`.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", StateBuilder)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", StateBuilder)]
|
||||
//!
|
||||
//! This struct is meant to contain the same list of accounts and balances that we want to have at
|
||||
//! the beginning of each block. We hardcoded this to `let accounts = vec![(ALICE, 100), (2, 100)];`
|
||||
//! so far. Then, if desired, we attach a default value for this struct.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", default_state_builder)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", default_state_builder)]
|
||||
//!
|
||||
//! Like any other builder pattern, we attach functions to the type to mutate its internal
|
||||
//! properties.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_add)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", impl_state_builder_add)]
|
||||
//!
|
||||
//! Finally --the useful part-- we write our own custom `build_and_execute` function on
|
||||
//! this type. This function will do multiple things:
|
||||
@@ -227,29 +230,29 @@
|
||||
//! after each test. For example, in this test, we do some additional checking about the
|
||||
//! correctness of the `TotalIssuance`. We leave it up to you as an exercise to learn why the
|
||||
//! assertion should always hold, and how it is checked.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", impl_state_builder_build)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", impl_state_builder_build)]
|
||||
//!
|
||||
//! We can write tests that specifically check the initial state, and making sure our `StateBuilder`
|
||||
//! is working exactly as intended.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_works)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", state_builder_add_balance)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", state_builder_works)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", state_builder_add_balance)]
|
||||
//!
|
||||
//! ### More Tests
|
||||
//!
|
||||
//! Now that we have a more ergonomic test setup, let's see how a well written test for transfer and
|
||||
//! mint would look like.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_works)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", mint_works)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", transfer_works)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", mint_works)]
|
||||
//!
|
||||
//! It is always a good idea to build a mental model where you write *at least* one test for each
|
||||
//! "success path" of a dispatchable, and one test for each "failure path", such as:
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_from_non_existent_fails)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", transfer_from_non_existent_fails)]
|
||||
//!
|
||||
//! We leave it up to you to write a test that triggers the `InsufficientBalance` error.
|
||||
//!
|
||||
//! ### Event and Error
|
||||
//!
|
||||
//! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and
|
||||
//! Our pezpallet is mainly missing two parts that are common in most FRAME pallets: Events, and
|
||||
//! Errors. First, let's understand what each is.
|
||||
//!
|
||||
//! - **Error**: The static string-based error scheme we used so far is good for readability, but it
|
||||
@@ -259,10 +262,10 @@
|
||||
//! by one character. FRAME errors are exactly a solution to maintain readability, whilst fixing
|
||||
//! the drawbacks mentioned. In short, we use an enum to represent different variants of our
|
||||
//! error. These variants are then mapped in an efficient way (using only `u8` indices) to
|
||||
//! [`sp_runtime::DispatchError::Module`]. Read more about this in [`pallet::error`].
|
||||
//! [`pezsp_runtime::DispatchError::Module`]. Read more about this in [`pezpallet::error`].
|
||||
//!
|
||||
//! - **Event**: Events are akin to the return type of dispatchables. They are mostly data blobs
|
||||
//! emitted by the runtime to let outside world know what is happening inside the pallet. Since
|
||||
//! emitted by the runtime to let outside world know what is happening inside the pezpallet. Since
|
||||
//! otherwise, the outside world does not have an easy access to the state changes. They should
|
||||
//! represent what happened at the end of a dispatch operation. Therefore, the convention is to
|
||||
//! use passive tense for event names (eg. `SomethingHappened`). This allows other sub-systems or
|
||||
@@ -270,41 +273,41 @@
|
||||
//! needing to re-execute the whole state transition function.
|
||||
//!
|
||||
//! With the explanation out of the way, let's see how these components can be added. Both follow a
|
||||
//! fairly familiar syntax: normal Rust enums, with extra [`pallet::event`] and [`pallet::error`]
|
||||
//! attributes attached.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Event)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", Error)]
|
||||
//! fairly familiar syntax: normal Rust enums, with extra [`pezpallet::event`] and
|
||||
//! [`pezpallet::error`] attributes attached.
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", Event)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", Error)]
|
||||
//!
|
||||
//! One slightly custom part of this is the [`pallet::generate_deposit`] part. Without going into
|
||||
//! too much detail, in order for a pallet to emit events to the rest of the system, it needs to do
|
||||
//! two things:
|
||||
//! One slightly custom part of this is the [`pezpallet::generate_deposit`] part. Without going into
|
||||
//! too much detail, in order for a pezpallet to emit events to the rest of the system, it needs to
|
||||
//! do two things:
|
||||
//!
|
||||
//! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In
|
||||
//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent:
|
||||
//! short, by doing this, the pezpallet is expressing an important bound: `type RuntimeEvent:
|
||||
//! From<Event<Self>>`. Read: a `RuntimeEvent` exists, and it can be created from the local `enum
|
||||
//! Event` of this pallet. This enables the pallet to convert its `Event` into `RuntimeEvent`, and
|
||||
//! store it where needed.
|
||||
//! Event` of this pezpallet. This enables the pezpallet to convert its `Event` into `RuntimeEvent`,
|
||||
//! and store it where needed.
|
||||
//!
|
||||
//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME
|
||||
//! provides a default way of storing events, and this is what [`pallet::generate_deposit`] is
|
||||
//! 2. But, doing this conversion and storing is too much to expect each pezpallet to define. FRAME
|
||||
//! provides a default way of storing events, and this is what [`pezpallet::generate_deposit`] is
|
||||
//! doing.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", config_v2)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", config_v2)]
|
||||
//!
|
||||
//! > These `Runtime*` types are better explained in
|
||||
//! > [`crate::reference_docs::frame_runtime_types`].
|
||||
//!
|
||||
//! Then, we can rewrite the `transfer` dispatchable as such:
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", transfer_v2)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", transfer_v2)]
|
||||
//!
|
||||
//! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime
|
||||
//! setup.
|
||||
#![doc = docify::embed!("./packages/guides/first-pallet/src/lib.rs", runtime_v2)]
|
||||
#![doc = docify::embed!("./packages/guides/first-pezpallet/src/lib.rs", runtime_v2)]
|
||||
//!
|
||||
//! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent =
|
||||
//! RuntimeEvent`) is generated by
|
||||
//! [`construct_runtime`](frame::runtime::prelude::construct_runtime). An interesting way to inspect
|
||||
//! [`construct_runtime`](pezframe::runtime::prelude::construct_runtime). An interesting way to inspect
|
||||
//! this type is to see its definition in rust-docs:
|
||||
//! [`crate::guides::your_first_pallet::pallet_v2::tests::runtime_v2::RuntimeEvent`].
|
||||
//! [`crate::guides::your_first_pallet::pezpallet_v2::tests::runtime_v2::RuntimeEvent`].
|
||||
//!
|
||||
//!
|
||||
//! ## What Next?
|
||||
@@ -315,56 +318,57 @@
|
||||
//! - [`crate::reference_docs::defensive_programming`].
|
||||
//! - [`crate::reference_docs::frame_origin`].
|
||||
//! - [`crate::reference_docs::frame_runtime_types`].
|
||||
//! - The pallet we wrote in this guide was using `dev_mode`, learn more in [`pallet::config`].
|
||||
//! - Learn more about the individual pallet items/macros, such as event and errors and call, in
|
||||
//! [`frame::pallet_macros`].
|
||||
//! - The pezpallet we wrote in this guide was using `dev_mode`, learn more in
|
||||
//! [`pezpallet::config`].
|
||||
//! - Learn more about the individual pezpallet items/macros, such as event and errors and call, in
|
||||
//! [`pezframe::pezpallet_macros`].
|
||||
//!
|
||||
//! [`pallet::storage`]: frame_support::pallet_macros::storage
|
||||
//! [`pallet::call`]: frame_support::pallet_macros::call
|
||||
//! [`pallet::event`]: frame_support::pallet_macros::event
|
||||
//! [`pallet::error`]: frame_support::pallet_macros::error
|
||||
//! [`pallet::pallet`]: frame_support::pallet
|
||||
//! [`pallet::config`]: frame_support::pallet_macros::config
|
||||
//! [`pallet::generate_deposit`]: frame_support::pallet_macros::generate_deposit
|
||||
//! [`pezpallet::storage`]: pezframe_support::pezpallet_macros::storage
|
||||
//! [`pezpallet::call`]: pezframe_support::pezpallet_macros::call
|
||||
//! [`pezpallet::event`]: pezframe_support::pezpallet_macros::event
|
||||
//! [`pezpallet::error`]: pezframe_support::pezpallet_macros::error
|
||||
//! [`pezpallet::pezpallet`]: pezframe_support::pezpallet
|
||||
//! [`pezpallet::config`]: pezframe_support::pezpallet_macros::config
|
||||
//! [`pezpallet::generate_deposit`]: pezframe_support::pezpallet_macros::generate_deposit
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod shell_pallet {
|
||||
use frame::prelude::*;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
}
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame::prelude::*;
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet {
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
pub type Balance = u128;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export]
|
||||
/// Single storage item, of type `Balance`.
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type TotalIssuance<T: Config> = StorageValue<_, Balance>;
|
||||
|
||||
#[docify::export]
|
||||
/// A mapping from `T::AccountId` to `Balance`
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type Balances<T: Config> = StorageMap<_, _, T::AccountId, Balance>;
|
||||
|
||||
#[docify::export(impl_pallet)]
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
/// An unsafe mint that can be called by anyone. Not a great idea.
|
||||
pub fn mint_unsafe(
|
||||
origin: T::RuntimeOrigin,
|
||||
@@ -406,7 +410,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
impl<T: Config> Pallet<T> {
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
#[docify::export]
|
||||
pub fn transfer_better(
|
||||
origin: T::RuntimeOrigin,
|
||||
@@ -442,10 +446,10 @@ pub mod pallet {
|
||||
|
||||
#[cfg(any(test, doc))]
|
||||
pub(crate) mod tests {
|
||||
use crate::guides::your_first_pallet::pallet::*;
|
||||
use crate::guides::your_first_pallet::pezpallet::*;
|
||||
|
||||
#[docify::export(testing_prelude)]
|
||||
use frame::testing_prelude::*;
|
||||
use pezframe::testing_prelude::*;
|
||||
|
||||
pub(crate) const ALICE: u64 = 1;
|
||||
pub(crate) const BOB: u64 = 2;
|
||||
@@ -456,29 +460,29 @@ pub mod pallet {
|
||||
// tests { .. }`
|
||||
mod runtime {
|
||||
use super::*;
|
||||
// we need to reference our `mod pallet` as an identifier to pass to
|
||||
// we need to reference our `mod pezpallet` as an identifier to pass to
|
||||
// `construct_runtime`.
|
||||
// YOU HAVE TO CHANGE THIS LINE BASED ON YOUR TEMPLATE
|
||||
use crate::guides::your_first_pallet::pallet as pallet_currency;
|
||||
use crate::guides::your_first_pallet::pezpallet as pezpallet_currency;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
// ---^^^^^^ This is where `enum Runtime` is defined.
|
||||
System: frame_system,
|
||||
Currency: pallet_currency,
|
||||
System: pezframe_system,
|
||||
Currency: pezpallet_currency,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Runtime>;
|
||||
// within pallet we just said `<T as frame_system::Config>::AccountId`, now we
|
||||
// within pezpallet we just said `<T as pezframe_system::Config>::AccountId`, now we
|
||||
// finally specified it.
|
||||
type AccountId = u64;
|
||||
}
|
||||
|
||||
// our simple pallet has nothing to be configured.
|
||||
impl pallet_currency::Config for Runtime {}
|
||||
// our simple pezpallet has nothing to be configured.
|
||||
impl pezpallet_currency::Config for Runtime {}
|
||||
}
|
||||
|
||||
pub(crate) use runtime::*;
|
||||
@@ -500,7 +504,7 @@ pub mod pallet {
|
||||
|
||||
#[docify::export]
|
||||
pub(crate) struct StateBuilder {
|
||||
balances: Vec<(<Runtime as frame_system::Config>::AccountId, Balance)>,
|
||||
balances: Vec<(<Runtime as pezframe_system::Config>::AccountId, Balance)>,
|
||||
}
|
||||
|
||||
#[docify::export(default_state_builder)]
|
||||
@@ -514,7 +518,7 @@ pub mod pallet {
|
||||
impl StateBuilder {
|
||||
fn add_balance(
|
||||
mut self,
|
||||
who: <Runtime as frame_system::Config>::AccountId,
|
||||
who: <Runtime as pezframe_system::Config>::AccountId,
|
||||
amount: Balance,
|
||||
) -> Self {
|
||||
self.balances.push((who, amount));
|
||||
@@ -554,7 +558,7 @@ pub mod pallet {
|
||||
assert_eq!(TotalIssuance::<Runtime>::get(), None);
|
||||
|
||||
// mint some funds into Alice's account.
|
||||
assert_ok!(Pallet::<Runtime>::mint_unsafe(
|
||||
assert_ok!(Pezpallet::<Runtime>::mint_unsafe(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
ALICE,
|
||||
100
|
||||
@@ -603,14 +607,18 @@ pub mod pallet {
|
||||
fn mint_works() {
|
||||
StateBuilder::default().build_and_execute(|| {
|
||||
// given the initial state, when:
|
||||
assert_ok!(Pallet::<Runtime>::mint_unsafe(RuntimeOrigin::signed(ALICE), BOB, 100));
|
||||
assert_ok!(Pezpallet::<Runtime>::mint_unsafe(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
BOB,
|
||||
100
|
||||
));
|
||||
|
||||
// then:
|
||||
assert_eq!(Balances::<Runtime>::get(&BOB), Some(200));
|
||||
assert_eq!(TotalIssuance::<Runtime>::get(), Some(300));
|
||||
|
||||
// given:
|
||||
assert_ok!(Pallet::<Runtime>::mint_unsafe(
|
||||
assert_ok!(Pezpallet::<Runtime>::mint_unsafe(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
CHARLIE,
|
||||
100
|
||||
@@ -627,7 +635,7 @@ pub mod pallet {
|
||||
fn transfer_works() {
|
||||
StateBuilder::default().build_and_execute(|| {
|
||||
// given the initial state, when:
|
||||
assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
|
||||
assert_ok!(Pezpallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
|
||||
|
||||
// then:
|
||||
assert_eq!(Balances::<Runtime>::get(&ALICE), Some(50));
|
||||
@@ -635,7 +643,7 @@ pub mod pallet {
|
||||
assert_eq!(TotalIssuance::<Runtime>::get(), Some(200));
|
||||
|
||||
// when:
|
||||
assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(BOB), ALICE, 50));
|
||||
assert_ok!(Pezpallet::<Runtime>::transfer(RuntimeOrigin::signed(BOB), ALICE, 50));
|
||||
|
||||
// then:
|
||||
assert_eq!(Balances::<Runtime>::get(&ALICE), Some(100));
|
||||
@@ -650,7 +658,7 @@ pub mod pallet {
|
||||
StateBuilder::default().build_and_execute(|| {
|
||||
// given the initial state, when:
|
||||
assert_err!(
|
||||
Pallet::<Runtime>::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, 10),
|
||||
Pezpallet::<Runtime>::transfer(RuntimeOrigin::signed(CHARLIE), ALICE, 10),
|
||||
"NonExistentAccount"
|
||||
);
|
||||
|
||||
@@ -664,32 +672,32 @@ pub mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_v2 {
|
||||
use super::pallet::Balance;
|
||||
use frame::prelude::*;
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_v2 {
|
||||
use super::pezpallet::Balance;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export(config_v2)]
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// The overarching event type of the runtime.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: From<Event<Self>>
|
||||
+ IsType<<Self as frame_system::Config>::RuntimeEvent>
|
||||
+ IsType<<Self as pezframe_system::Config>::RuntimeEvent>
|
||||
+ TryInto<Event<Self>>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type Balances<T: Config> = StorageMap<_, _, T::AccountId, Balance>;
|
||||
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type TotalIssuance<T: Config> = StorageValue<_, Balance>;
|
||||
|
||||
#[docify::export]
|
||||
#[pallet::error]
|
||||
#[pezpallet::error]
|
||||
pub enum Error<T> {
|
||||
/// Account does not exist.
|
||||
NonExistentAccount,
|
||||
@@ -698,15 +706,15 @@ pub mod pallet_v2 {
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[pallet::event]
|
||||
#[pallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
#[pezpallet::event]
|
||||
#[pezpallet::generate_deposit(pub(super) fn deposit_event)]
|
||||
pub enum Event<T: Config> {
|
||||
/// A transfer succeeded.
|
||||
Transferred { from: T::AccountId, to: T::AccountId, amount: Balance },
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
#[docify::export(transfer_v2)]
|
||||
pub fn transfer(
|
||||
origin: T::RuntimeOrigin,
|
||||
@@ -732,30 +740,30 @@ pub mod pallet_v2 {
|
||||
|
||||
#[cfg(any(test, doc))]
|
||||
pub mod tests {
|
||||
use super::{super::pallet::tests::StateBuilder, *};
|
||||
use frame::testing_prelude::*;
|
||||
use super::{super::pezpallet::tests::StateBuilder, *};
|
||||
use pezframe::testing_prelude::*;
|
||||
const ALICE: u64 = 1;
|
||||
const BOB: u64 = 2;
|
||||
|
||||
#[docify::export]
|
||||
pub mod runtime_v2 {
|
||||
use super::*;
|
||||
use crate::guides::your_first_pallet::pallet_v2 as pallet_currency;
|
||||
use crate::guides::your_first_pallet::pezpallet_v2 as pezpallet_currency;
|
||||
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Currency: pallet_currency,
|
||||
System: pezframe_system,
|
||||
Currency: pezpallet_currency,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Runtime>;
|
||||
type AccountId = u64;
|
||||
}
|
||||
|
||||
impl pallet_currency::Config for Runtime {
|
||||
impl pezpallet_currency::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
}
|
||||
}
|
||||
@@ -771,7 +779,7 @@ pub mod pallet_v2 {
|
||||
System::set_block_number(ALICE);
|
||||
|
||||
// given the initial state, when:
|
||||
assert_ok!(Pallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
|
||||
assert_ok!(Pezpallet::<Runtime>::transfer(RuntimeOrigin::signed(ALICE), BOB, 50));
|
||||
|
||||
// then:
|
||||
assert_eq!(Balances::<Runtime>::get(&ALICE), Some(50));
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
//! # Your first Runtime
|
||||
//!
|
||||
//! This guide will walk you through the steps to add your pallet to a runtime.
|
||||
//! This guide will walk you through the steps to add your pezpallet to a runtime.
|
||||
//!
|
||||
//! The good news is, in [`crate::guides::your_first_pallet`], we have already created a _test_
|
||||
//! runtime that was used for testing, and a real runtime is not that much different!
|
||||
//!
|
||||
//! ## Setup
|
||||
//!
|
||||
//! A runtime shares a few similar setup requirements as with a pallet:
|
||||
//! A runtime shares a few similar setup requirements as with a pezpallet:
|
||||
//!
|
||||
//! * importing [`frame`], [`codec`], and [`scale_info`] crates.
|
||||
//! * following the [`std` feature-gating](crate::pezkuwi_sdk::substrate#wasm-build) pattern.
|
||||
//! * following the [`std` feature-gating](crate::pezkuwi_sdk::bizinikiwi#wasm-build) pattern.
|
||||
//!
|
||||
//! But, more specifically, it also contains:
|
||||
//!
|
||||
//! * a `build.rs` that uses [`substrate_wasm_builder`]. This entails declaring
|
||||
//! * a `build.rs` that uses [`bizinikiwi_wasm_builder`]. This entails declaring
|
||||
//! `[build-dependencies]` in the Cargo manifest file:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! [build-dependencies]
|
||||
//! substrate-wasm-builder = { ... }
|
||||
//! bizinikiwi-wasm-builder = { ... }
|
||||
//! ```
|
||||
//!
|
||||
//! >Note that a runtime must always be one-runtime-per-crate. You cannot define multiple runtimes
|
||||
@@ -30,7 +30,7 @@
|
||||
//! ## Your First Runtime
|
||||
//!
|
||||
//! The first new property of a real runtime that it must define its
|
||||
//! [`frame::runtime::prelude::RuntimeVersion`]:
|
||||
//! [`pezframe::runtime::prelude::RuntimeVersion`]:
|
||||
#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", VERSION)]
|
||||
//!
|
||||
//! The version contains a number of very important fields, such as `spec_version` and `spec_name`
|
||||
@@ -39,7 +39,7 @@
|
||||
//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
//!
|
||||
//! Then, a real runtime also contains the `impl` of all individual pallets' `trait Config` for
|
||||
//! `struct Runtime`, and a [`frame::runtime::prelude::construct_runtime`] macro that amalgamates
|
||||
//! `struct Runtime`, and a [`pezframe::runtime::prelude::construct_runtime`] macro that amalgamates
|
||||
//! them all.
|
||||
//!
|
||||
//! In the case of our example:
|
||||
@@ -49,13 +49,13 @@
|
||||
//! their `Config` need to be implemented for `struct Runtime`:
|
||||
#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", config_impls)]
|
||||
//!
|
||||
//! Notice how we use [`frame::pallet_macros::derive_impl`] to provide "default" configuration items
|
||||
//! for each pallet. Feel free to dive into the definition of each default prelude (eg.
|
||||
//! [`frame::prelude::frame_system::pallet::config_preludes`]) to learn more which types are exactly
|
||||
//! used.
|
||||
//! Notice how we use [`pezframe::pezpallet_macros::derive_impl`] to provide "default" configuration
|
||||
//! items for each pezpallet. Feel free to dive into the definition of each default prelude (eg.
|
||||
//! [`pezframe::prelude::pezframe_system::pezpallet::config_preludes`]) to learn more which types are
|
||||
//! exactly used.
|
||||
//!
|
||||
//! Recall that in test runtime in [`crate::guides::your_first_pallet`], we provided `type AccountId
|
||||
//! = u64` to `frame_system`, while in this case we rely on whatever is provided by
|
||||
//! = u64` to `pezframe_system`, while in this case we rely on whatever is provided by
|
||||
//! [`SolochainDefaultConfig`], which is indeed a "real" 32 byte account id.
|
||||
//!
|
||||
//! Then, a familiar instance of `construct_runtime` amalgamates all of the pallets:
|
||||
@@ -66,12 +66,12 @@
|
||||
//! steps of crafting a runtime are related to achieving exactly this.
|
||||
//!
|
||||
//! First, we define a number of types that eventually lead to the creation of an instance of
|
||||
//! [`frame::runtime::prelude::Executive`]. The executive is a handy FRAME utility that, through
|
||||
//! [`pezframe::runtime::prelude::Executive`]. The executive is a handy FRAME utility that, through
|
||||
//! amalgamating all pallets and further types, implements some of the very very core pieces of the
|
||||
//! runtime logic, such as how blocks are executed and other runtime-api implementations.
|
||||
#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", runtime_types)]
|
||||
//!
|
||||
//! Finally, we use [`frame::runtime::prelude::impl_runtime_apis`] to implement all of the runtime
|
||||
//! Finally, we use [`pezframe::runtime::prelude::impl_runtime_apis`] to implement all of the runtime
|
||||
//! APIs that the runtime wishes to expose. As you will see in the code, most of these runtime API
|
||||
//! implementations are merely forwarding calls to `RuntimeExecutive` which handles the actual
|
||||
//! logic. Given that the implementation block is somewhat large, we won't repeat it here. You can
|
||||
@@ -101,7 +101,7 @@
|
||||
//!
|
||||
//! Once you compile a crate that contains a runtime as above, simply running `cargo build` will
|
||||
//! generate the wasm blobs and place them under `./target/release/wbuild`, as explained
|
||||
//! [here](crate::pezkuwi_sdk::substrate#wasm-build).
|
||||
//! [here](crate::pezkuwi_sdk::bizinikiwi#wasm-build).
|
||||
//!
|
||||
//! ## Genesis Configuration
|
||||
//!
|
||||
@@ -110,8 +110,8 @@
|
||||
//! what is known as a **Chain Specification, or chain spec for short**. A chain spec is the
|
||||
//! primary way to run a new chain.
|
||||
//!
|
||||
//! These APIs are defined in [`sp_genesis_builder`], and are re-exposed as a part of
|
||||
//! [`frame::runtime::apis`]. Therefore, the implementation blocks can be found inside of
|
||||
//! These APIs are defined in [`pezsp_genesis_builder`], and are re-exposed as a part of
|
||||
//! [`pezframe::runtime::apis`]. Therefore, the implementation blocks can be found inside of
|
||||
//! `impl_runtime_apis!` similar to:
|
||||
//!
|
||||
//! ```ignore
|
||||
@@ -136,13 +136,14 @@
|
||||
//! The implementation of these function can naturally vary from one runtime to the other, but the
|
||||
//! overall pattern is common. For the case of this runtime, we do the following:
|
||||
//!
|
||||
//! 1. Expose one non-default preset, namely [`sp_genesis_builder::DEV_RUNTIME_PRESET`]. This means
|
||||
//! our runtime has two "presets" of genesis state in total: `DEV_RUNTIME_PRESET` and `None`.
|
||||
//! 1. Expose one non-default preset, namely [`pezsp_genesis_builder::DEV_RUNTIME_PRESET`]. This
|
||||
//! means our runtime has two "presets" of genesis state in total: `DEV_RUNTIME_PRESET` and
|
||||
//! `None`.
|
||||
#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", preset_names)]
|
||||
//!
|
||||
//! For `build_state` and `get_preset`, we use the helper functions provide by frame:
|
||||
//!
|
||||
//! * [`frame::runtime::prelude::build_state`] and [`frame::runtime::prelude::get_preset`].
|
||||
//! * [`pezframe::runtime::prelude::build_state`] and [`pezframe::runtime::prelude::get_preset`].
|
||||
//!
|
||||
//! Indeed, our runtime needs to specify what its `DEV_RUNTIME_PRESET` genesis state should be like:
|
||||
#![doc = docify::embed!("./packages/guides/first-runtime/src/lib.rs", development_config_genesis)]
|
||||
@@ -164,10 +165,10 @@
|
||||
//! [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
//! 4. Learn more about adding and implementing runtime apis in
|
||||
//! [`crate::reference_docs::custom_runtime_api_rpc`].
|
||||
//! 5. To see a complete example of a runtime+pallet that is similar to this guide, please see
|
||||
//! 5. To see a complete example of a runtime+pezpallet that is similar to this guide, please see
|
||||
//! [`crate::pezkuwi_sdk::templates`].
|
||||
//!
|
||||
//! [`SolochainDefaultConfig`]: struct@frame_system::pallet::config_preludes::SolochainDefaultConfig
|
||||
//! [`SolochainDefaultConfig`]: struct@pezframe_system::pezpallet::config_preludes::SolochainDefaultConfig
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
//! > To achieve this, we often use [`docify`](https://github.com/sam0x17/docify), a nifty invention
|
||||
//! > of `@sam0x17`.
|
||||
//!
|
||||
//! Also see: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/109>.
|
||||
//! Also see: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/255>.
|
||||
//!
|
||||
//! ## Scope
|
||||
//!
|
||||
@@ -63,7 +63,7 @@
|
||||
//!
|
||||
//! > A prime example of this, the list of CLI arguments of a particular binary should not be
|
||||
//! > documented in multiple places across this crate. It should be only be documented in the
|
||||
//! > corresponding crate (e.g. `sc_cli`).
|
||||
//! > corresponding crate (e.g. `pezsc_cli`).
|
||||
//!
|
||||
//! > Moreover, this means that as a contributor, **it is your responsibility to have a grasp over
|
||||
//! > what topics are already covered in this crate, and how you can build on top of the information
|
||||
@@ -72,7 +72,7 @@
|
||||
//! For more details see the [latest documenting
|
||||
//! guidelines](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/docs/contributor/DOCUMENTATION_GUIDELINES.md).
|
||||
//!
|
||||
//! #### Example: Explaining `#[pallet::call]`
|
||||
//! #### Example: Explaining `#[pezpallet::call]`
|
||||
//!
|
||||
//! <details>
|
||||
//! <summary>
|
||||
@@ -82,15 +82,15 @@
|
||||
//!
|
||||
//!
|
||||
//! ```
|
||||
//! #[frame::pallet(dev_mode)]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pallet::call]
|
||||
//! impl<T: Config> Pallet<T> {
|
||||
//! #[pezframe::pezpallet(dev_mode)]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[pezpallet::call]
|
||||
//! impl<T: Config> Pezpallet<T> {
|
||||
//! pub fn a_simple_call(origin: OriginFor<T>, data: u32) -> DispatchResult {
|
||||
//! ensure!(data > 10, "SomeStaticString");
|
||||
//! todo!();
|
||||
@@ -101,13 +101,13 @@
|
||||
//!
|
||||
//! * Before even getting started, what is with all of this `<T: Config>`? We link to
|
||||
//! [`crate::reference_docs::trait_based_programming`].
|
||||
//! * First, the name. Why is this called `pallet::call`? This goes back to `enum Call`, which is
|
||||
//! * First, the name. Why is this called `pezpallet::call`? This goes back to `enum Call`, which is
|
||||
//! explained in [`crate::reference_docs::frame_runtime_types`]. Build on top of this!
|
||||
//! * Then, what is `origin`? Just an account id? [`crate::reference_docs::frame_origin`].
|
||||
//! * Then, what is `DispatchResult`? Why is this called *dispatch*? Probably something that can be
|
||||
//! explained in the documentation of [`frame::prelude::DispatchResult`].
|
||||
//! explained in the documentation of [`pezframe::prelude::DispatchResult`].
|
||||
//! * Why is `"SomeStaticString"` a valid error? Because there is implementation for it that you can
|
||||
//! see [here](frame::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError).
|
||||
//! see [here](pezframe::prelude::DispatchError#impl-From<%26'static+str>-for-DispatchError).
|
||||
//!
|
||||
//!
|
||||
//! All of these are examples of underlying information that a contributor should:
|
||||
@@ -132,7 +132,7 @@
|
||||
//! So long as not deployed in `crates.io`, please notice that all of the information in this crate,
|
||||
//! namely in [`crate::guides`] and such are compatible with the master branch of `pezkuwi-sdk`. A
|
||||
//! few solutions have been proposed to improve this, please see
|
||||
//! [here](https://github.com/pezkuwichain/pezkuwi-sdk/issues/146).
|
||||
//! [here](https://github.com/pezkuwichain/pezkuwi-sdk/issues/289).
|
||||
//!
|
||||
//! ## How to Develop Locally
|
||||
//!
|
||||
@@ -146,6 +146,6 @@
|
||||
//! ```
|
||||
//!
|
||||
//! If even faster build time for docs is needed, you can temporarily remove most of the
|
||||
//! substrate/cumulus dependencies that are only used for linking purposes.
|
||||
//! bizinikiwi/pezcumulus dependencies that are only used for linking purposes.
|
||||
//!
|
||||
//! For more on local development, see [`crate::reference_docs::development_environment_advice`].
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
//! # Bizinikiwi
|
||||
//!
|
||||
//! Bizinikiwi is a Rust framework for building blockchains in a modular and extensible way. While
|
||||
//! in itself un-opinionated, it is the main engine behind the Pezkuwi ecosystem.
|
||||
//!
|
||||
//! ## Overview, Philosophy
|
||||
//!
|
||||
//! Bizinikiwi approaches blockchain development with an acknowledgement of a few self-evident
|
||||
//! truths:
|
||||
//!
|
||||
//! 1. Society and technology evolves.
|
||||
//! 2. Humans are fallible.
|
||||
//!
|
||||
//! This makes the task of designing a correct, safe and long-lasting blockchain system hard.
|
||||
//!
|
||||
//! Nonetheless, in strive towards achieving this goal, Bizinikiwi embraces the following:
|
||||
//!
|
||||
//! 1. Use of **Rust** as a modern and safe programming language, which limits human error through
|
||||
//! various means, most notably memory and type safety.
|
||||
//! 2. Bizinikiwi is written from the ground-up with a *generic, modular and extensible* design.
|
||||
//! This ensures that software components can be easily swapped and upgraded. Examples of this is
|
||||
//! multiple consensus mechanisms provided by Bizinikiwi, as listed below.
|
||||
//! 3. Lastly, the final blockchain system created with the above properties needs to be
|
||||
//! upgradeable. In order to achieve this, Bizinikiwi is designed as a meta-protocol, whereby the
|
||||
//! application logic of the blockchain (called "Runtime") is encoded as a WASM blob, and is
|
||||
//! stored in the state. The rest of the system (called "node") acts as the executor of the WASM
|
||||
//! blob.
|
||||
//!
|
||||
//! In essence, the meta-protocol of all Bizinikiwi based chains is the "Runtime as WASM blob"
|
||||
//! accord. This enables the Runtime to become inherently upgradeable, crucially without [forks](https://en.wikipedia.org/wiki/Fork_(blockchain)). The
|
||||
//! upgrade is merely a matter of the WASM blob being changed in the state, which is, in principle,
|
||||
//! same as updating an account's balance. Learn more about this in detail in
|
||||
//! [`crate::reference_docs::wasm_meta_protocol`].
|
||||
//!
|
||||
//! > A great analogy for bizinikiwi is the following: Bizinikiwi node is a gaming console, and a
|
||||
//! > WASM
|
||||
//! > runtime, possibly created with FRAME is the game being inserted into the console.
|
||||
//!
|
||||
//! [`frame`], Bizinikiwi's default runtime development library, takes the above safety practices
|
||||
//! even further by embracing a declarative programming model whereby correctness is enhanced and
|
||||
//! the system is highly configurable through parameterization. Learn more about this in
|
||||
//! [`crate::reference_docs::trait_based_programming`].
|
||||
//!
|
||||
//! ## How to Get Started
|
||||
//!
|
||||
//! Bizinikiwi offers different options at the spectrum of technical freedom <-> development ease.
|
||||
//!
|
||||
//! * The easiest way to use Bizinikiwi is to use one of the templates (some of which listed at
|
||||
//! [`crate::pezkuwi_sdk::templates`]) and only tweak the parameters of the runtime or node. This
|
||||
//! allows you to launch a blockchain in minutes, but is limited in technical freedom.
|
||||
//! * Next, most developers wish to develop their custom runtime modules, for which the de-facto way
|
||||
//! is [`frame`](crate::pezkuwi_sdk::frame_runtime).
|
||||
//! * Finally, Bizinikiwi is highly configurable at the node side as well, but this is the most
|
||||
//! technically demanding.
|
||||
//!
|
||||
//! > A notable Bizinikiwi-based blockchain that has built both custom FRAME pallets and custom
|
||||
//! > node-side components is <https://github.com/Cardinal-Cryptography/aleph-node>.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_dev.mmd")]
|
||||
//!
|
||||
//! ## Structure
|
||||
//!
|
||||
//! Bizinikiwi contains a large number of crates, therefore it is useful to have an overview of what
|
||||
//! they are, and how they are organized. In broad terms, these crates are divided into three
|
||||
//! categories:
|
||||
//!
|
||||
//! * `sc-*` (short for *Bizinikiwi-client*) crates, located under `./client` folder. These are all
|
||||
//! the crates that lead to the node software. Notable examples are [`pezsc_network`], various
|
||||
//! consensus crates, RPC ([`pezsc_rpc_api`]) and database ([`pezsc_client_db`]), all of which are
|
||||
//! expected to reside in the node side.
|
||||
//! * `sp-*` (short for *bizinikiwi-primitives*) crates, located under `./primitives` folder. These
|
||||
//! are crates that facilitate both the node and the runtime, but are not opinionated about what
|
||||
//! framework is using for building the runtime. Notable examples are [`pezsp_api`] and
|
||||
//! [`pezsp_io`], which form the communication bridge between the node and runtime.
|
||||
//! * `pezpallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates
|
||||
//! related to FRAME. See [`frame`] for more information.
|
||||
//!
|
||||
//! ### WASM Build
|
||||
//!
|
||||
//! Many of the Bizinikiwi crates, such as entire `sp-*`, need to compile to both WASM (when a WASM
|
||||
//! runtime is being generated) and native (for example, when testing). To achieve this, Bizinikiwi
|
||||
//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a
|
||||
//! crate is being built with the standard library, and is built for native. Otherwise, it is built
|
||||
//! for `no_std`.
|
||||
//!
|
||||
//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find
|
||||
//! in any Bizinikiwi-based runtime.
|
||||
//!
|
||||
//! Bizinikiwi-based runtimes use [`bizinikiwi_wasm_builder`] in their `build.rs` to automatically
|
||||
//! build their WASM files as a part of normal build command (e.g. `cargo build`). Once built, the
|
||||
//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}/{runtime_name}.wasm`.
|
||||
//!
|
||||
//! In order to ensure that the WASM build is **deterministic**, the [Bizinikiwi Runtime Toolbox (srtool)](https://github.com/paritytech/srtool) can be used.
|
||||
//!
|
||||
//! ### Anatomy of a Binary Crate
|
||||
//!
|
||||
//! From the above, [`node_cli`]/[`pez_kitchensink_runtime`] and `node-template` are essentially
|
||||
//! blueprints of a Bizinikiwi-based project, as the name of the latter is implying. Each
|
||||
//! Bizinikiwi-based project typically contains the following:
|
||||
//!
|
||||
//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file.
|
||||
//! This file typically contains the [`pezframe::runtime::prelude::construct_runtime`] and
|
||||
//! [`pezframe::runtime::prelude::impl_runtime_apis`] macro calls, which is the final definition of a
|
||||
//! runtime.
|
||||
//!
|
||||
//! * Under `./node`, a `main.rs`, which is the starting point, and a `./service.rs`, which contains
|
||||
//! all the node side components. Skimming this file yields an overview of the networking,
|
||||
//! database, consensus and similar node side components.
|
||||
//!
|
||||
//! > The above two are conventions, not rules.
|
||||
//!
|
||||
//! > See <https://github.com/pezkuwichain/pezkuwi-sdk/issues/241> for an update on how the node side
|
||||
//! > components are being amalgamated.
|
||||
//!
|
||||
//! ## Teyrchain?
|
||||
//!
|
||||
//! As noted above, Bizinikiwi is the main engine behind the Pezkuwi ecosystem. One of the ways
|
||||
//! through which Pezkuwi can be utilized is by building "teyrchains", blockchains that are
|
||||
//! connected to Pezkuwi's shared security.
|
||||
//!
|
||||
//! To build a teyrchain, one could use [Pezcumulus](crate::pezkuwi_sdk::pezcumulus), the library on
|
||||
//! top of Bizinikiwi, empowering any bizinikiwi-based chain to be a Pezkuwi teyrchain.
|
||||
//!
|
||||
//! ## Where To Go Next?
|
||||
//!
|
||||
//! Additional noteworthy crates within bizinikiwi:
|
||||
//!
|
||||
//! - RPC APIs of a Bizinikiwi node: [`pezsc_rpc_api`]/[`pezsc_rpc`]
|
||||
//! - CLI Options of a Bizinikiwi node: [`pezsc_cli`]
|
||||
//! - All of the consensus related crates provided by Bizinikiwi:
|
||||
//! - [`pezsc_consensus_aura`]
|
||||
//! - [`pezsc_consensus_babe`]
|
||||
//! - [`pezsc_consensus_grandpa`]
|
||||
//! - [`pezsc_consensus_beefy`] (TODO: @adrian, add some high level docs <https://github.com/pezkuwichain/pezkuwi-sdk/issues/305>)
|
||||
//! - [`pezsc_consensus_manual_seal`]
|
||||
//! - [`pezsc_consensus_pow`]
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use crate::pezkuwi_sdk;
|
||||
@@ -1,130 +0,0 @@
|
||||
//! # Cumulus
|
||||
//!
|
||||
//! Substrate provides a framework ([FRAME]) through which a blockchain node and runtime can easily
|
||||
//! be created. Cumulus aims to extend the same approach to creation of Pezkuwi teyrchains.
|
||||
//!
|
||||
//! > Cumulus clouds are shaped sort of like dots; together they form a system that is intricate,
|
||||
//! > beautiful and functional.
|
||||
//!
|
||||
//! ## Example: Runtime
|
||||
//!
|
||||
//! A Cumulus-based runtime is fairly similar to other [FRAME]-based runtimes. Most notably, the
|
||||
//! following changes are applied to a normal FRAME-based runtime to make it a Cumulus-based
|
||||
//! runtime:
|
||||
//!
|
||||
//! #### Cumulus Pallets
|
||||
//!
|
||||
//! A teyrchain runtime should use a number of pallets that are provided by Cumulus and Substrate.
|
||||
//! Notably:
|
||||
//!
|
||||
//! - [`frame-system`](frame::prelude::frame_system), like all FRAME-based runtimes.
|
||||
//! - [`cumulus_pallet_teyrchain_system`]
|
||||
//! - [`teyrchain_info`]
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/cumulus.rs", system_pallets)]
|
||||
//!
|
||||
//! Given that all Cumulus-based runtimes use a simple Aura-based consensus mechanism, the following
|
||||
//! pallets also need to be added:
|
||||
//!
|
||||
//! - [`pallet_timestamp`]
|
||||
//! - [`pallet_aura`]
|
||||
//! - [`cumulus_pallet_aura_ext`]
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/cumulus.rs", consensus_pallets)]
|
||||
//!
|
||||
//!
|
||||
//! Finally, a separate macro, similar to
|
||||
//! [`impl_runtime_api`](frame::runtime::prelude::impl_runtime_apis), which creates the default set
|
||||
//! of runtime APIs, will generate the teyrchain runtime's validation runtime API, also known as
|
||||
//! teyrchain validation function (PVF). Without this API, the relay chain is unable to validate
|
||||
//! blocks produced by our teyrchain.
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/cumulus.rs", validate_block)]
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! [FRAME]: crate::pezkuwi_sdk::frame_runtime
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![deny(rustdoc::private_intra_doc_links)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod runtime {
|
||||
pub use frame::{
|
||||
deps::sp_consensus_aura::sr25519::AuthorityId as AuraId, prelude::*,
|
||||
runtime::prelude::*, testing_prelude::*,
|
||||
};
|
||||
|
||||
#[docify::export(CR)]
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
// system-level pallets.
|
||||
System: frame_system,
|
||||
Timestamp: pallet_timestamp,
|
||||
TeyrchainSystem: cumulus_pallet_teyrchain_system,
|
||||
TeyrchainInfo: teyrchain_info,
|
||||
|
||||
// teyrchain consensus support -- mandatory.
|
||||
Aura: pallet_aura,
|
||||
AuraExt: cumulus_pallet_aura_ext,
|
||||
}
|
||||
);
|
||||
|
||||
#[docify::export]
|
||||
mod system_pallets {
|
||||
use super::*;
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
type OnSetCode = cumulus_pallet_teyrchain_system::TeyrchainSetCode<Self>;
|
||||
}
|
||||
|
||||
impl cumulus_pallet_teyrchain_system::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type OnSystemEvent = ();
|
||||
type SelfParaId = teyrchain_info::Pallet<Runtime>;
|
||||
type OutboundXcmpMessageSource = ();
|
||||
type XcmpMessageHandler = ();
|
||||
type ReservedDmpWeight = ();
|
||||
type ReservedXcmpWeight = ();
|
||||
type CheckAssociatedRelayNumber =
|
||||
cumulus_pallet_teyrchain_system::RelayNumberMonotonicallyIncreases;
|
||||
type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook<
|
||||
Runtime,
|
||||
6000, // relay chain block time
|
||||
1,
|
||||
1,
|
||||
>;
|
||||
type WeightInfo = ();
|
||||
type DmpQueue = frame::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>;
|
||||
type RelayParentOffset = ConstU32<0>;
|
||||
}
|
||||
|
||||
impl teyrchain_info::Config for Runtime {}
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
mod consensus_pallets {
|
||||
use super::*;
|
||||
|
||||
impl pallet_aura::Config for Runtime {
|
||||
type AuthorityId = AuraId;
|
||||
type DisabledValidators = ();
|
||||
type MaxAuthorities = ConstU32<100_000>;
|
||||
type AllowMultipleBlocksPerSlot = ConstBool<false>;
|
||||
type SlotDuration = pallet_aura::MinimumPeriodTimesTwo<Self>;
|
||||
}
|
||||
|
||||
#[docify::export(timestamp)]
|
||||
#[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||
impl pallet_timestamp::Config for Runtime {}
|
||||
|
||||
impl cumulus_pallet_aura_ext::Config for Runtime {}
|
||||
}
|
||||
|
||||
#[docify::export(validate_block)]
|
||||
cumulus_pallet_teyrchain_system::register_validate_block! {
|
||||
Runtime = Runtime,
|
||||
BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::<Runtime, Executive>,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,102 +10,104 @@
|
||||
//! \_\/ \_\/ \_\/ \__\/\__\/ \__\/ \__\/ \_____\/
|
||||
//! ```
|
||||
//!
|
||||
//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's
|
||||
//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Bizinikiwi's
|
||||
//! > State Transition Function (Runtime) Framework.
|
||||
//!
|
||||
//! ## Introduction
|
||||
//!
|
||||
//! As described in [`crate::reference_docs::wasm_meta_protocol`], at a high-level Substrate-based
|
||||
//! As described in [`crate::reference_docs::wasm_meta_protocol`], at a high-level Bizinikiwi-based
|
||||
//! blockchains are composed of two parts:
|
||||
//!
|
||||
//! 1. A *runtime* which represents the state transition function (i.e. "Business Logic") of a
|
||||
//! blockchain, and is encoded as a WASM blob.
|
||||
//! 2. A node whose primary purpose is to execute the given runtime.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_simple.mmd")]
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_simple.mmd")]
|
||||
//!
|
||||
//! *FRAME is the Substrate's framework of choice to build a runtime.*
|
||||
//! *FRAME is the Bizinikiwi's framework of choice to build a runtime.*
|
||||
//!
|
||||
//! FRAME is composed of two major components, **pallets** and a **runtime**.
|
||||
//!
|
||||
//! ## Pallets
|
||||
//!
|
||||
//! A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
//! A pezpallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
//! linked to other pallets. In order to be reusable, pallets shipped with FRAME strive to only care
|
||||
//! about its own responsibilities and make as few assumptions about the general runtime as
|
||||
//! possible. A pallet is analogous to a _module_ in the runtime.
|
||||
//! possible. A pezpallet is analogous to a _module_ in the runtime.
|
||||
//!
|
||||
//! A pallet is defined as a `mod pallet` wrapped by the [`frame::pallet`] macro. Within this macro,
|
||||
//! pallet components/parts can be defined. Most notable of these parts are:
|
||||
//! A pezpallet is defined as a `mod pezpallet` wrapped by the [`pezframe::pezpallet`] macro. Within
|
||||
//! this macro, pezpallet components/parts can be defined. Most notable of these parts are:
|
||||
//!
|
||||
//! - [Config](frame::pallet_macros::config), allowing a pallet to make itself configurable and
|
||||
//! generic over types, values and such.
|
||||
//! - [Storage](frame::pallet_macros::storage), allowing a pallet to define onchain storage.
|
||||
//! - [Dispatchable function](frame::pallet_macros::call), allowing a pallet to define extrinsics
|
||||
//! that are callable by end users, from the outer world.
|
||||
//! - [Events](frame::pallet_macros::event), allowing a pallet to emit events.
|
||||
//! - [Errors](frame::pallet_macros::error), allowing a pallet to emit well-formed errors.
|
||||
//! - [Config](pezframe::pezpallet_macros::config), allowing a pezpallet to make itself configurable
|
||||
//! and generic over types, values and such.
|
||||
//! - [Storage](pezframe::pezpallet_macros::storage), allowing a pezpallet to define onchain storage.
|
||||
//! - [Dispatchable function](pezframe::pezpallet_macros::call), allowing a pezpallet to define
|
||||
//! extrinsics that are callable by end users, from the outer world.
|
||||
//! - [Events](pezframe::pezpallet_macros::event), allowing a pezpallet to emit events.
|
||||
//! - [Errors](pezframe::pezpallet_macros::error), allowing a pezpallet to emit well-formed errors.
|
||||
//!
|
||||
//! Some of these pallet components resemble the building blocks of a smart contract. While both
|
||||
//! Some of these pezpallet components resemble the building blocks of a smart contract. While both
|
||||
//! models are programming state transition functions of blockchains, there are crucial differences
|
||||
//! between the two. See [`crate::reference_docs::runtime_vs_smart_contract`] for more.
|
||||
//!
|
||||
//! Most of these components are defined using macros, the full list of which can be found in
|
||||
//! [`frame::pallet_macros`].
|
||||
//! [`pezframe::pezpallet_macros`].
|
||||
//!
|
||||
//! ### Example
|
||||
//!
|
||||
//! The following example showcases a minimal pallet.
|
||||
#![doc = docify::embed!("src/pezkuwi_sdk/frame_runtime.rs", pallet)]
|
||||
//! The following example showcases a minimal pezpallet.
|
||||
#![doc = docify::embed!("src/pezkuwi_sdk/frame_runtime.rs", pezpallet)]
|
||||
//!
|
||||
//! ## Runtime
|
||||
//!
|
||||
//! A runtime is a collection of pallets that are amalgamated together. Each pallet typically has
|
||||
//! A runtime is a collection of pallets that are amalgamated together. Each pezpallet typically has
|
||||
//! some configurations (exposed as a `trait Config`) that needs to be *specified* in the runtime.
|
||||
//! This is done with [`frame::runtime::prelude::construct_runtime`].
|
||||
//! This is done with [`pezframe::runtime::prelude::construct_runtime`].
|
||||
//!
|
||||
//! A (real) runtime that actually wishes to compile to WASM needs to also implement a set of
|
||||
//! runtime-apis. These implementation can be specified using the
|
||||
//! [`frame::runtime::prelude::impl_runtime_apis`] macro.
|
||||
//! [`pezframe::runtime::prelude::impl_runtime_apis`] macro.
|
||||
//!
|
||||
//! ### Example
|
||||
//!
|
||||
//! The following example shows a (test) runtime that is composing the pallet demonstrated above,
|
||||
//! next to the [`frame::prelude::frame_system`] pallet, into a runtime.
|
||||
//! The following example shows a (test) runtime that is composing the pezpallet demonstrated above,
|
||||
//! next to the [`pezframe::prelude::pezframe_system`] pezpallet, into a runtime.
|
||||
#![doc = docify::embed!("src/pezkuwi_sdk/frame_runtime.rs", runtime)]
|
||||
//!
|
||||
//! ## More Examples
|
||||
//!
|
||||
//! You can find more FRAME examples that revolve around specific features at [`pallet_examples`].
|
||||
//! You can find more FRAME examples that revolve around specific features at
|
||||
//! [`pezpallet_examples`].
|
||||
//!
|
||||
//! ## Alternatives 🌈
|
||||
//!
|
||||
//! There is nothing in the Substrate's node side code-base that mandates the use of FRAME. While
|
||||
//! FRAME makes it very simple to write Substrate-based runtimes, it is by no means intended to be
|
||||
//! There is nothing in the Bizinikiwi's node side code-base that mandates the use of FRAME. While
|
||||
//! FRAME makes it very simple to write Bizinikiwi-based runtimes, it is by no means intended to be
|
||||
//! the only one. At the end of the day, any WASM blob that exposes the right set of runtime APIs is
|
||||
//! a valid Runtime form the point of view of a Substrate client (see
|
||||
//! a valid Runtime form the point of view of a Bizinikiwi client (see
|
||||
//! [`crate::reference_docs::wasm_meta_protocol`]). Notable examples are:
|
||||
//!
|
||||
//! * writing a runtime in pure Rust, as done in [this template](https://github.com/JoshOrndorff/frameless-node-template).
|
||||
//! * writing a runtime in AssemblyScript, as explored in [this project](https://github.com/LimeChain/subsembly).
|
||||
|
||||
/// A FRAME based pallet. This `mod` is the entry point for everything else. All
|
||||
/// `#[pallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an
|
||||
/// experimental feature to break these parts into different `mod`s. See [`pallet_examples`] for
|
||||
/// A FRAME based pezpallet. This `mod` is the entry point for everything else. All
|
||||
/// `#[pezpallet::xxx]` macros must be defined in this `mod`. Although, frame also provides an
|
||||
/// experimental feature to break these parts into different `mod`s. See [`pezpallet_examples`] for
|
||||
/// more.
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet {
|
||||
use frame::prelude::*;
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet {
|
||||
use pezframe::prelude::*;
|
||||
|
||||
/// The configuration trait of a pallet. Mandatory. Allows a pallet to receive types at a
|
||||
/// later point from the runtime that wishes to contain it. It allows the pallet to be
|
||||
/// The configuration trait of a pezpallet. Mandatory. Allows a pezpallet to receive types at a
|
||||
/// later point from the runtime that wishes to contain it. It allows the pezpallet to be
|
||||
/// parameterized over both types and values.
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// A type that is not known now, but the runtime that will contain this pallet will
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// A type that is not known now, but the runtime that will contain this pezpallet will
|
||||
/// know it later, therefore we define it here as an associated type.
|
||||
#[allow(deprecated)]
|
||||
type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;
|
||||
type RuntimeEvent: IsType<<Self as pezframe_system::Config>::RuntimeEvent>
|
||||
+ From<Event<Self>>;
|
||||
|
||||
/// A parameterize-able value that we receive later via the `Get<_>` trait.
|
||||
type ValueParameter: Get<u32>;
|
||||
@@ -115,25 +117,25 @@ pub mod pallet {
|
||||
const ANOTHER_VALUE_PARAMETER: u32;
|
||||
}
|
||||
|
||||
/// A mandatory struct in each pallet. All functions callable by external users (aka.
|
||||
/// transactions) must be attached to this type (see [`frame::pallet_macros::call`]). For
|
||||
/// A mandatory struct in each pezpallet. All functions callable by external users (aka.
|
||||
/// transactions) must be attached to this type (see [`pezframe::pezpallet_macros::call`]). For
|
||||
/// convenience, internal (private) functions can also be attached to this type.
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(PhantomData<T>);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(PhantomData<T>);
|
||||
|
||||
/// The events that this pallet can emit.
|
||||
#[pallet::event]
|
||||
/// The events that this pezpallet can emit.
|
||||
#[pezpallet::event]
|
||||
pub enum Event<T: Config> {}
|
||||
|
||||
/// A storage item that this pallet contains. This will be part of the state root trie
|
||||
/// A storage item that this pezpallet contains. This will be part of the state root trie
|
||||
/// of the blockchain.
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type Value<T> = StorageValue<Value = u32>;
|
||||
|
||||
/// All *dispatchable* call functions (aka. transactions) are attached to `Pallet` in a
|
||||
/// All *dispatchable* call functions (aka. transactions) are attached to `Pezpallet` in a
|
||||
/// `impl` block.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
/// This will be callable by external users, and has two u32s as a parameter.
|
||||
pub fn some_dispatchable(
|
||||
_origin: OriginFor<T>,
|
||||
@@ -145,29 +147,29 @@ pub mod pallet {
|
||||
}
|
||||
}
|
||||
|
||||
/// A simple runtime that contains the above pallet and `frame_system`, the mandatory pallet of
|
||||
/// all runtimes. This runtime is for testing, but it shares a lot of similarities with a *real*
|
||||
/// runtime.
|
||||
/// A simple runtime that contains the above pezpallet and `pezframe_system`, the mandatory
|
||||
/// pezpallet of all runtimes. This runtime is for testing, but it shares a lot of similarities with
|
||||
/// a *real* runtime.
|
||||
#[docify::export]
|
||||
pub mod runtime {
|
||||
use super::pallet as pallet_example;
|
||||
use frame::{prelude::*, testing_prelude::*};
|
||||
use super::pezpallet as pezpallet_example;
|
||||
use pezframe::{prelude::*, testing_prelude::*};
|
||||
|
||||
// The major macro that amalgamates pallets into `enum Runtime`
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
System: frame_system,
|
||||
Example: pallet_example,
|
||||
System: pezframe_system,
|
||||
Example: pezpallet_example,
|
||||
}
|
||||
);
|
||||
|
||||
// These `impl` blocks specify the parameters of each pallet's `trait Config`.
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
// These `impl` blocks specify the parameters of each pezpallet's `trait Config`.
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
impl pallet_example::Config for Runtime {
|
||||
impl pezpallet_example::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type ValueParameter = ConstU32<42>;
|
||||
const ANOTHER_VALUE_PARAMETER: u32 = 42;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
//! start building on the [Pezkuwi network](https://pezkuwichain.io/), a scalable, multi-chain
|
||||
//! blockchain platform that enables different blockchains to securely interoperate.
|
||||
//!
|
||||
//! [](https://exchange.pezkuwichain.app/)
|
||||
//! [](https://exchange.pezkuwichain.app/)
|
||||
//!
|
||||
//! [](https://github.com/Awsmdot/awesome-dot)
|
||||
//! [](https://wiki.network.pezkuwichain.io/)
|
||||
@@ -20,56 +20,56 @@
|
||||
//! See:
|
||||
//!
|
||||
//! * [`pezkuwi`], to understand what is Pezkuwi as a development platform.
|
||||
//! * [`substrate`], for an overview of what Substrate as the main blockchain framework of Pezkuwi
|
||||
//! * [`bizinikiwi`], for an overview of what Bizinikiwi as the main blockchain framework of Pezkuwi
|
||||
//! SDK.
|
||||
//! * [`frame`], to learn about how to write blockchain applications aka. "App Chains".
|
||||
//! * Continue with the [`pezkuwi_sdk_docs`'s "getting started"](crate#getting-started).
|
||||
//!
|
||||
//! ## Components
|
||||
//!
|
||||
//! #### Substrate
|
||||
//! #### Bizinikiwi
|
||||
//!
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/LICENSE-APACHE2)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/bizinikiwi/LICENSE-APACHE2)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate)
|
||||
//! Repo](https://img.shields.io/badge/github-bizinikiwi-2324CC85)](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/bizinikiwi)
|
||||
//!
|
||||
//! [`substrate`] is the base blockchain framework used to power the Pezkuwi SDK. It is a full
|
||||
//! [`bizinikiwi`] is the base blockchain framework used to power the Pezkuwi SDK. It is a full
|
||||
//! toolkit to create sovereign blockchains, including but not limited to those which connect to
|
||||
//! Pezkuwi as teyrchains.
|
||||
//!
|
||||
//! #### FRAME
|
||||
//!
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/LICENSE-APACHE2)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/bizinikiwi/LICENSE-APACHE2)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/substrate/frame)
|
||||
//! Repo](https://img.shields.io/badge/github-frame-2324CC85)](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/bizinikiwi/pezframe)
|
||||
//!
|
||||
//! [`frame`] is the framework used to create Substrate-based application logic, aka. runtimes.
|
||||
//! [`frame`] is the framework used to create Bizinikiwi-based application logic, aka. runtimes.
|
||||
//! Learn more about the distinction of a runtime and node in
|
||||
//! [`reference_docs::wasm_meta_protocol`].
|
||||
//!
|
||||
//! #### Cumulus
|
||||
//! #### Pezcumulus
|
||||
//!
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/cumulus/LICENSE)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezcumulus/LICENSE)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/cumulus)
|
||||
//! Repo](https://img.shields.io/badge/github-pezcumulus-white)](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezcumulus)
|
||||
//!
|
||||
//! [`cumulus`] transforms FRAME-based runtimes into Pezkuwi-compatible teyrchain runtimes, and
|
||||
//! Substrate-based nodes into Pezkuwi/Teyrchain-compatible nodes.
|
||||
//! [`pezcumulus`] transforms FRAME-based runtimes into Pezkuwi-compatible teyrchain runtimes, and
|
||||
//! Bizinikiwi-based nodes into Pezkuwi/Teyrchain-compatible nodes.
|
||||
//!
|
||||
//! #### XCM
|
||||
//!
|
||||
//! [](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezkuwi/LICENSE)
|
||||
//! [](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/xcm)
|
||||
//! Repo](https://img.shields.io/badge/github-XCM-e6007a?logo=polkadot)](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezkuwi/xcm)
|
||||
//!
|
||||
//! [`xcm`], short for "cross consensus message", is the primary format that is used for
|
||||
//! communication between teyrchains, but is intended to be extensible to other use cases as well.
|
||||
//!
|
||||
//! #### Pezkuwi
|
||||
//!
|
||||
//! [](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE)
|
||||
//! [](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezkuwi/LICENSE)
|
||||
//! [](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot)
|
||||
//! Repo](https://img.shields.io/badge/github-polkadot-e6007a?logo=polkadot)](https://github.com/pezkuwichain/pezkuwi-sdk/blob/master/pezkuwi)
|
||||
//!
|
||||
//! [`pezkuwi`] is an implementation of a Pezkuwi node in Rust, by `@paritytech`. The Pezkuwi
|
||||
//! runtimes are located under the
|
||||
@@ -89,35 +89,35 @@
|
||||
//! `benchmark` subcommand that does the same.
|
||||
//! * [`chain_spec_builder`]: Utility to build chain-specs Nodes typically contain a `build-spec`
|
||||
//! subcommand that does the same.
|
||||
//! * [`subkey`]: Substrate's key management utility.
|
||||
//! * [`substrate-node`](node_cli) is an extensive substrate node that contains the superset of all
|
||||
//! runtime and node side features. The corresponding runtime, called [`kitchensink_runtime`]
|
||||
//! contains all of the modules that are provided with `FRAME`. This node and runtime is only used
|
||||
//! for testing and demonstration.
|
||||
//! * [`pez_subkey`]: Bizinikiwi's key management utility.
|
||||
//! * [`bizinikiwi-node`](node_cli) is an extensive bizinikiwi node that contains the superset of
|
||||
//! all runtime and node side features. The corresponding runtime, called
|
||||
//! [`pez_kitchensink_runtime`] contains all of the modules that are provided with `FRAME`. This
|
||||
//! node and runtime is only used for testing and demonstration.
|
||||
//!
|
||||
//! ### Summary
|
||||
//!
|
||||
//! The following diagram summarizes how some of the components of Pezkuwi SDK work together:
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/pezkuwi_sdk_substrate.mmd")]
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/pezkuwi_sdk_bizinikiwi.mmd")]
|
||||
//!
|
||||
//! A Substrate-based chain is a blockchain composed of a runtime and a node. As noted above, the
|
||||
//! A Bizinikiwi-based chain is a blockchain composed of a runtime and a node. As noted above, the
|
||||
//! runtime is the application logic of the blockchain, and the node is everything else.
|
||||
//! See [`reference_docs::wasm_meta_protocol`] for an in-depth explanation of this. The
|
||||
//! former is built with [`frame`], and the latter is built with rest of Substrate.
|
||||
//! former is built with [`frame`], and the latter is built with rest of Bizinikiwi.
|
||||
//!
|
||||
//! > You can think of a Substrate-based chain as a white-labeled blockchain.
|
||||
//! > You can think of a Bizinikiwi-based chain as a white-labeled blockchain.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/pezkuwi_sdk_pezkuwi.mmd")]
|
||||
//! Pezkuwi is itself a Substrate-based chain, composed of the exact same two components. It has
|
||||
//! Pezkuwi is itself a Bizinikiwi-based chain, composed of the exact same two components. It has
|
||||
//! specialized logic in both the node and the runtime side, but it is not "special" in any way.
|
||||
//!
|
||||
//! A teyrchain is a "special" Substrate-based chain, whereby both the node and the runtime
|
||||
//! components have became "Pezkuwi-aware" using Cumulus.
|
||||
//! A teyrchain is a "special" Bizinikiwi-based chain, whereby both the node and the runtime
|
||||
//! components have became "Pezkuwi-aware" using Pezcumulus.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/pezkuwi_sdk_teyrchain.mmd")]
|
||||
//!
|
||||
//! ## Notable Upstream Crates
|
||||
//!
|
||||
//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec)
|
||||
//! - [`parity-db`](https://github.com/paritytech/parity-db)
|
||||
//! - [`parity-scale-codec`](https://github.com/pezkuwichain/parity-scale-codec)
|
||||
//! - [`parity-db`](https://github.com/pezkuwichain/parity-db)
|
||||
//! - [`trie`](https://github.com/paritytech/trie)
|
||||
//! - [`parity-common`](https://github.com/paritytech/parity-common)
|
||||
//!
|
||||
@@ -131,27 +131,27 @@
|
||||
//! * [Starknet's Madara Sequencer](https://github.com/keep-starknet-strange/madara)
|
||||
//! * [Polymesh](https://polymesh.network/)
|
||||
//!
|
||||
//! [`substrate`]: crate::pezkuwi_sdk::substrate
|
||||
//! [`bizinikiwi`]: crate::pezkuwi_sdk::bizinikiwi
|
||||
//! [`frame`]: crate::pezkuwi_sdk::frame_runtime
|
||||
//! [`cumulus`]: crate::pezkuwi_sdk::cumulus
|
||||
//! [`pezcumulus`]: crate::pezkuwi_sdk::pezcumulus
|
||||
//! [`pezkuwi`]: crate::pezkuwi_sdk::pezkuwi
|
||||
//! [`xcm`]: crate::pezkuwi_sdk::xcm
|
||||
//! [`frame-omni-bencher`]: https://crates.io/crates/frame-omni-bencher
|
||||
//! [`pezkuwi-teyrchain-bin`]: https://crates.io/crates/polkadot-parachain-bin
|
||||
//! [`pezkuwi-omni-node`]: https://crates.io/crates/polkadot-omni-node
|
||||
|
||||
/// Learn about Cumulus, the framework that transforms [`substrate`]-based chains into
|
||||
/// [`pezkuwi`]-enabled teyrchains.
|
||||
pub mod cumulus;
|
||||
/// Learn about FRAME, the framework used to build Substrate runtimes.
|
||||
/// Learn about Bizinikiwi, the main blockchain framework used in the Pezkuwi ecosystem.
|
||||
pub mod bizinikiwi;
|
||||
/// Learn about FRAME, the framework used to build Bizinikiwi runtimes.
|
||||
pub mod frame_runtime;
|
||||
/// Learn about Pezcumulus, the framework that transforms [`bizinikiwi`]-based chains into
|
||||
/// [`pezkuwi`]-enabled teyrchains.
|
||||
pub mod pezcumulus;
|
||||
/// Learn about Pezkuwi as a platform.
|
||||
pub mod pezkuwi;
|
||||
/// Learn about different ways through which smart contracts can be utilized on top of Substrate,
|
||||
/// Learn about different ways through which smart contracts can be utilized on top of Bizinikiwi,
|
||||
/// and in the Pezkuwi ecosystem.
|
||||
pub mod smart_contracts;
|
||||
/// Learn about Substrate, the main blockchain framework used in the Pezkuwi ecosystem.
|
||||
pub mod substrate;
|
||||
/// Index of all the templates that can act as first scaffold for a new project.
|
||||
pub mod templates;
|
||||
/// Learn about XCM, the de-facto communication language between different consensus systems.
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
//! # Pezcumulus
|
||||
//!
|
||||
//! Bizinikiwi provides a framework ([FRAME]) through which a blockchain node and runtime can easily
|
||||
//! be created. Pezcumulus aims to extend the same approach to creation of Pezkuwi teyrchains.
|
||||
//!
|
||||
//! > Pezcumulus clouds are shaped sort of like dots; together they form a system that is intricate,
|
||||
//! > beautiful and functional.
|
||||
//!
|
||||
//! ## Example: Runtime
|
||||
//!
|
||||
//! A Pezcumulus-based runtime is fairly similar to other [FRAME]-based runtimes. Most notably, the
|
||||
//! following changes are applied to a normal FRAME-based runtime to make it a Pezcumulus-based
|
||||
//! runtime:
|
||||
//!
|
||||
//! #### Pezcumulus Pallets
|
||||
//!
|
||||
//! A teyrchain runtime should use a number of pallets that are provided by Pezcumulus and
|
||||
//! Bizinikiwi. Notably:
|
||||
//!
|
||||
//! - [`pezframe-system`](pezframe::prelude::pezframe_system), like all FRAME-based runtimes.
|
||||
//! - [`pezcumulus_pezpallet_teyrchain_system`]
|
||||
//! - [`teyrchain_info`]
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/pezcumulus.rs", system_pallets)]
|
||||
//!
|
||||
//! Given that all Pezcumulus-based runtimes use a simple Aura-based consensus mechanism, the
|
||||
//! following pallets also need to be added:
|
||||
//!
|
||||
//! - [`pezpallet_timestamp`]
|
||||
//! - [`pezpallet_aura`]
|
||||
//! - [`pezcumulus_pezpallet_aura_ext`]
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/pezcumulus.rs", consensus_pallets)]
|
||||
//!
|
||||
//!
|
||||
//! Finally, a separate macro, similar to
|
||||
//! [`impl_runtime_api`](pezframe::runtime::prelude::impl_runtime_apis), which creates the default set
|
||||
//! of runtime APIs, will generate the teyrchain runtime's validation runtime API, also known as
|
||||
//! teyrchain validation function (PVF). Without this API, the relay chain is unable to validate
|
||||
//! blocks produced by our teyrchain.
|
||||
#![doc = docify::embed!("./src/pezkuwi_sdk/pezcumulus.rs", validate_block)]
|
||||
//!
|
||||
//! ---
|
||||
//!
|
||||
//! [FRAME]: crate::pezkuwi_sdk::frame_runtime
|
||||
|
||||
#![deny(rustdoc::broken_intra_doc_links)]
|
||||
#![deny(rustdoc::private_intra_doc_links)]
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
mod runtime {
|
||||
pub use pezframe::{
|
||||
deps::pezsp_consensus_aura::sr25519::AuthorityId as AuraId, prelude::*,
|
||||
runtime::prelude::*, testing_prelude::*,
|
||||
};
|
||||
|
||||
#[docify::export(CR)]
|
||||
construct_runtime!(
|
||||
pub enum Runtime {
|
||||
// system-level pallets.
|
||||
System: pezframe_system,
|
||||
Timestamp: pezpallet_timestamp,
|
||||
TeyrchainSystem: pezcumulus_pezpallet_teyrchain_system,
|
||||
TeyrchainInfo: teyrchain_info,
|
||||
|
||||
// teyrchain consensus support -- mandatory.
|
||||
Aura: pezpallet_aura,
|
||||
AuraExt: pezcumulus_pezpallet_aura_ext,
|
||||
}
|
||||
);
|
||||
|
||||
#[docify::export]
|
||||
mod system_pallets {
|
||||
use super::*;
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
type OnSetCode = pezcumulus_pezpallet_teyrchain_system::TeyrchainSetCode<Self>;
|
||||
}
|
||||
|
||||
impl pezcumulus_pezpallet_teyrchain_system::Config for Runtime {
|
||||
type RuntimeEvent = RuntimeEvent;
|
||||
type OnSystemEvent = ();
|
||||
type SelfParaId = teyrchain_info::Pezpallet<Runtime>;
|
||||
type OutboundXcmpMessageSource = ();
|
||||
type XcmpMessageHandler = ();
|
||||
type ReservedDmpWeight = ();
|
||||
type ReservedXcmpWeight = ();
|
||||
type CheckAssociatedRelayNumber =
|
||||
pezcumulus_pezpallet_teyrchain_system::RelayNumberMonotonicallyIncreases;
|
||||
type ConsensusHook = pezcumulus_pezpallet_aura_ext::FixedVelocityConsensusHook<
|
||||
Runtime,
|
||||
6000, // relay chain block time
|
||||
1,
|
||||
1,
|
||||
>;
|
||||
type WeightInfo = ();
|
||||
type DmpQueue = pezframe::traits::EnqueueWithOrigin<(), pezsp_core::ConstU8<0>>;
|
||||
type RelayParentOffset = ConstU32<0>;
|
||||
}
|
||||
|
||||
impl teyrchain_info::Config for Runtime {}
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
mod consensus_pallets {
|
||||
use super::*;
|
||||
|
||||
impl pezpallet_aura::Config for Runtime {
|
||||
type AuthorityId = AuraId;
|
||||
type DisabledValidators = ();
|
||||
type MaxAuthorities = ConstU32<100_000>;
|
||||
type AllowMultipleBlocksPerSlot = ConstBool<false>;
|
||||
type SlotDuration = pezpallet_aura::MinimumPeriodTimesTwo<Self>;
|
||||
}
|
||||
|
||||
#[docify::export(timestamp)]
|
||||
#[derive_impl(pezpallet_timestamp::config_preludes::TestDefaultConfig)]
|
||||
impl pezpallet_timestamp::Config for Runtime {}
|
||||
|
||||
impl pezcumulus_pezpallet_aura_ext::Config for Runtime {}
|
||||
}
|
||||
|
||||
#[docify::export(validate_block)]
|
||||
pezcumulus_pezpallet_teyrchain_system::register_validate_block! {
|
||||
Runtime = Runtime,
|
||||
BlockExecutor = pezcumulus_pezpallet_aura_ext::BlockExecutor::<Runtime, Executive>,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,8 @@
|
||||
//! security as the Relay Chain.
|
||||
//! Learn about this process called [Approval Checking](https://pezkuwichain.io/blog/polkadot-v1-0-sharding-and-economic-security#approval-checking-and-finality).
|
||||
//! * A framework to build blockchains: In order to materialize the ecosystem of teyrchains, an easy
|
||||
//! blockchain framework must exist. This is [Substrate](crate::pezkuwi_sdk::substrate),
|
||||
//! [FRAME](crate::pezkuwi_sdk::frame_runtime) and [Cumulus](crate::pezkuwi_sdk::cumulus).
|
||||
//! blockchain framework must exist. This is [Bizinikiwi](crate::pezkuwi_sdk::bizinikiwi),
|
||||
//! [FRAME](crate::pezkuwi_sdk::frame_runtime) and [Pezcumulus](crate::pezkuwi_sdk::pezcumulus).
|
||||
//! * A communication language between blockchains: In order for these blockchains to communicate,
|
||||
//! they need a shared language. [XCM](crate::pezkuwi_sdk::xcm) is one such language, and the one
|
||||
//! that is most endorsed in the Pezkuwi ecosystem.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! # Smart Contracts
|
||||
//!
|
||||
//! TODO: @cmichi <https://github.com/pezkuwichain/pezkuwi-sdk/issues/161>
|
||||
//! TODO: @cmichi <https://github.com/pezkuwichain/pezkuwi-sdk/issues/304>
|
||||
//!
|
||||
//! - WASM and EVM based, pallet-contracts and pallet-evm.
|
||||
//! - WASM and EVM based, pezpallet-contracts and pezpallet-evm.
|
||||
//! - single-daap-chain, transition from ink! to FRAME.
|
||||
//! - Link to `use.ink`
|
||||
//! - Link to [`crate::reference_docs::runtime_vs_smart_contract`].
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
//! # Substrate
|
||||
//!
|
||||
//! Substrate is a Rust framework for building blockchains in a modular and extensible way. While in
|
||||
//! itself un-opinionated, it is the main engine behind the Pezkuwi ecosystem.
|
||||
//!
|
||||
//! ## Overview, Philosophy
|
||||
//!
|
||||
//! Substrate approaches blockchain development with an acknowledgement of a few self-evident
|
||||
//! truths:
|
||||
//!
|
||||
//! 1. Society and technology evolves.
|
||||
//! 2. Humans are fallible.
|
||||
//!
|
||||
//! This makes the task of designing a correct, safe and long-lasting blockchain system hard.
|
||||
//!
|
||||
//! Nonetheless, in strive towards achieving this goal, Substrate embraces the following:
|
||||
//!
|
||||
//! 1. Use of **Rust** as a modern and safe programming language, which limits human error through
|
||||
//! various means, most notably memory and type safety.
|
||||
//! 2. Substrate is written from the ground-up with a *generic, modular and extensible* design. This
|
||||
//! ensures that software components can be easily swapped and upgraded. Examples of this is
|
||||
//! multiple consensus mechanisms provided by Substrate, as listed below.
|
||||
//! 3. Lastly, the final blockchain system created with the above properties needs to be
|
||||
//! upgradeable. In order to achieve this, Substrate is designed as a meta-protocol, whereby the
|
||||
//! application logic of the blockchain (called "Runtime") is encoded as a WASM blob, and is
|
||||
//! stored in the state. The rest of the system (called "node") acts as the executor of the WASM
|
||||
//! blob.
|
||||
//!
|
||||
//! In essence, the meta-protocol of all Substrate based chains is the "Runtime as WASM blob"
|
||||
//! accord. This enables the Runtime to become inherently upgradeable, crucially without [forks](https://en.wikipedia.org/wiki/Fork_(blockchain)). The
|
||||
//! upgrade is merely a matter of the WASM blob being changed in the state, which is, in principle,
|
||||
//! same as updating an account's balance. Learn more about this in detail in
|
||||
//! [`crate::reference_docs::wasm_meta_protocol`].
|
||||
//!
|
||||
//! > A great analogy for substrate is the following: Substrate node is a gaming console, and a WASM
|
||||
//! > runtime, possibly created with FRAME is the game being inserted into the console.
|
||||
//!
|
||||
//! [`frame`], Substrate's default runtime development library, takes the above safety practices
|
||||
//! even further by embracing a declarative programming model whereby correctness is enhanced and
|
||||
//! the system is highly configurable through parameterization. Learn more about this in
|
||||
//! [`crate::reference_docs::trait_based_programming`].
|
||||
//!
|
||||
//! ## How to Get Started
|
||||
//!
|
||||
//! Substrate offers different options at the spectrum of technical freedom <-> development ease.
|
||||
//!
|
||||
//! * The easiest way to use Substrate is to use one of the templates (some of which listed at
|
||||
//! [`crate::pezkuwi_sdk::templates`]) and only tweak the parameters of the runtime or node. This
|
||||
//! allows you to launch a blockchain in minutes, but is limited in technical freedom.
|
||||
//! * Next, most developers wish to develop their custom runtime modules, for which the de-facto way
|
||||
//! is [`frame`](crate::pezkuwi_sdk::frame_runtime).
|
||||
//! * Finally, Substrate is highly configurable at the node side as well, but this is the most
|
||||
//! technically demanding.
|
||||
//!
|
||||
//! > A notable Substrate-based blockchain that has built both custom FRAME pallets and custom
|
||||
//! > node-side components is <https://github.com/Cardinal-Cryptography/aleph-node>.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_dev.mmd")]
|
||||
//!
|
||||
//! ## Structure
|
||||
//!
|
||||
//! Substrate contains a large number of crates, therefore it is useful to have an overview of what
|
||||
//! they are, and how they are organized. In broad terms, these crates are divided into three
|
||||
//! categories:
|
||||
//!
|
||||
//! * `sc-*` (short for *Substrate-client*) crates, located under `./client` folder. These are all
|
||||
//! the crates that lead to the node software. Notable examples are [`sc_network`], various
|
||||
//! consensus crates, RPC ([`sc_rpc_api`]) and database ([`sc_client_db`]), all of which are
|
||||
//! expected to reside in the node side.
|
||||
//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These
|
||||
//! are crates that facilitate both the node and the runtime, but are not opinionated about what
|
||||
//! framework is using for building the runtime. Notable examples are [`sp_api`] and [`sp_io`],
|
||||
//! which form the communication bridge between the node and runtime.
|
||||
//! * `pallet-*` and `frame-*` crates, located under `./frame` folder. These are the crates related
|
||||
//! to FRAME. See [`frame`] for more information.
|
||||
//!
|
||||
//! ### WASM Build
|
||||
//!
|
||||
//! Many of the Substrate crates, such as entire `sp-*`, need to compile to both WASM (when a WASM
|
||||
//! runtime is being generated) and native (for example, when testing). To achieve this, Substrate
|
||||
//! follows the convention of the Rust community, and uses a `feature = "std"` to signify that a
|
||||
//! crate is being built with the standard library, and is built for native. Otherwise, it is built
|
||||
//! for `no_std`.
|
||||
//!
|
||||
//! This can be summarized in `#![cfg_attr(not(feature = "std"), no_std)]`, which you can often find
|
||||
//! in any Substrate-based runtime.
|
||||
//!
|
||||
//! Substrate-based runtimes use [`substrate_wasm_builder`] in their `build.rs` to automatically
|
||||
//! build their WASM files as a part of normal build command (e.g. `cargo build`). Once built, the
|
||||
//! wasm file is placed in `./target/{debug|release}/wbuild/{runtime_name}/{runtime_name}.wasm`.
|
||||
//!
|
||||
//! In order to ensure that the WASM build is **deterministic**, the [Substrate Runtime Toolbox (srtool)](https://github.com/paritytech/srtool) can be used.
|
||||
//!
|
||||
//! ### Anatomy of a Binary Crate
|
||||
//!
|
||||
//! From the above, [`node_cli`]/[`kitchensink_runtime`] and `node-template` are essentially
|
||||
//! blueprints of a Substrate-based project, as the name of the latter is implying. Each
|
||||
//! Substrate-based project typically contains the following:
|
||||
//!
|
||||
//! * Under `./runtime`, a `./runtime/src/lib.rs` which is the top level runtime amalgamator file.
|
||||
//! This file typically contains the [`frame::runtime::prelude::construct_runtime`] and
|
||||
//! [`frame::runtime::prelude::impl_runtime_apis`] macro calls, which is the final definition of a
|
||||
//! runtime.
|
||||
//!
|
||||
//! * Under `./node`, a `main.rs`, which is the starting point, and a `./service.rs`, which contains
|
||||
//! all the node side components. Skimming this file yields an overview of the networking,
|
||||
//! database, consensus and similar node side components.
|
||||
//!
|
||||
//! > The above two are conventions, not rules.
|
||||
//!
|
||||
//! > See <https://github.com/pezkuwichain/pezkuwi-sdk/issues/94> for an update on how the node side
|
||||
//! > components are being amalgamated.
|
||||
//!
|
||||
//! ## Teyrchain?
|
||||
//!
|
||||
//! As noted above, Substrate is the main engine behind the Pezkuwi ecosystem. One of the ways
|
||||
//! through which Pezkuwi can be utilized is by building "teyrchains", blockchains that are
|
||||
//! connected to Pezkuwi's shared security.
|
||||
//!
|
||||
//! To build a teyrchain, one could use [Cumulus](crate::pezkuwi_sdk::cumulus), the library on
|
||||
//! top of Substrate, empowering any substrate-based chain to be a Pezkuwi teyrchain.
|
||||
//!
|
||||
//! ## Where To Go Next?
|
||||
//!
|
||||
//! Additional noteworthy crates within substrate:
|
||||
//!
|
||||
//! - RPC APIs of a Substrate node: [`sc_rpc_api`]/[`sc_rpc`]
|
||||
//! - CLI Options of a Substrate node: [`sc_cli`]
|
||||
//! - All of the consensus related crates provided by Substrate:
|
||||
//! - [`sc_consensus_aura`]
|
||||
//! - [`sc_consensus_babe`]
|
||||
//! - [`sc_consensus_grandpa`]
|
||||
//! - [`sc_consensus_beefy`] (TODO: @adrian, add some high level docs <https://github.com/pezkuwichain/pezkuwi-sdk/issues/162>)
|
||||
//! - [`sc_consensus_manual_seal`]
|
||||
//! - [`sc_consensus_pow`]
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use crate::pezkuwi_sdk;
|
||||
@@ -9,11 +9,11 @@
|
||||
//!
|
||||
//! The following templates are maintained as a part of the `pezkuwi-sdk` repository:
|
||||
//!
|
||||
//! - [`minimal-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25): A minimal
|
||||
//! - [`minimal-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/195): A minimal
|
||||
//! template that contains the least amount of features to be a functioning blockchain. Suitable
|
||||
//! for learning and testing.
|
||||
//! - [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25): Formerly known
|
||||
//! as "substrate-node-template", is a white-labeled substrate-based blockchain (aka. solochain)
|
||||
//! - [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/195): Formerly known
|
||||
//! as "bizinikiwi-node-template", is a white-labeled bizinikiwi-based blockchain (aka. solochain)
|
||||
//! that contains moderate features, such as a basic consensus engine and some FRAME pallets. This
|
||||
//! template can act as a good starting point for those who want to launch a solochain.
|
||||
//! - [`teyrchain-template`](https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template):
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//!
|
||||
//! ## Overview
|
||||
//!
|
||||
//! XCM is a standard, specification of which lives in the [xcm format repo](https://github.com/paritytech/xcm-format).
|
||||
//! XCM is a standard, specification of which lives in the [xcm format repo](https://github.com/polkadot-fellows/xcm-format).
|
||||
//! It's agnostic both in programming language and blockchain platform, which means it could be used
|
||||
//! in Rust in Pezkuwi, or in Go or C++ in any other platform like Cosmos or Ethereum.
|
||||
//!
|
||||
@@ -30,15 +30,15 @@
|
||||
//!
|
||||
//! ## Implementation
|
||||
//!
|
||||
//! A ready-to-use Rust implementation lives in the [pezkuwi-sdk repo](https://github.com/paritytech/polkadot-sdk/tree/master/polkadot/xcm),
|
||||
//! A ready-to-use Rust implementation lives in the [pezkuwi-sdk repo](https://github.com/pezkuwichain/pezkuwi-sdk/tree/main/pezkuwi/xcm),
|
||||
//! but will be moved to its own repo in the future.
|
||||
//!
|
||||
//! Its main components are:
|
||||
//! - [`xcm`](::xcm): The definition of the basic types and instructions.
|
||||
//! - [`xcm_executor`]: An implementation of the virtual machine to execute instructions.
|
||||
//! - [`pallet_xcm`]: A FRAME pallet for interacting with the executor.
|
||||
//! - [`pezpallet_xcm`]: A FRAME pezpallet for interacting with the executor.
|
||||
//! - [`xcm_builder`]: A collection of types to configure the executor.
|
||||
//! - [`xcm_simulator`]: A playground for trying out different XCM programs and executor
|
||||
//! - [`xcm_pez_simulator`]: A playground for trying out different XCM programs and executor
|
||||
//! configurations.
|
||||
//!
|
||||
//! ## Example
|
||||
@@ -49,7 +49,7 @@
|
||||
//!
|
||||
//! ## Get started
|
||||
//!
|
||||
//! To learn how it works and to get started, go to the [XCM docs](xcm_docs).
|
||||
//! To learn how it works and to get started, go to the [XCM docs](xcm_pez_docs).
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! # State Transition Function
|
||||
//!
|
||||
//! This document briefly explains how in the context of Substrate-based blockchains, we view the
|
||||
//! This document briefly explains how in the context of Bizinikiwi-based blockchains, we view the
|
||||
//! blockchain as a **decentralized state transition function**.
|
||||
//!
|
||||
//! Recall that a blockchain's main purpose is to help a permissionless set of entities to agree on
|
||||
@@ -14,7 +14,7 @@
|
||||
//! function*.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/stf_simple.mmd")]
|
||||
//!
|
||||
//! In Substrate-based blockchains, the state transition function is called the *Runtime*. This is
|
||||
//! In Bizinikiwi-based blockchains, the state transition function is called the *Runtime*. This is
|
||||
//! explained further in [`crate::reference_docs::wasm_meta_protocol`].
|
||||
//!
|
||||
//! With this in mind, we can paint a complete picture of a blockchain as a state machine:
|
||||
|
||||
@@ -10,52 +10,54 @@
|
||||
//! interact with the runtime in order to build the genesis state.
|
||||
//!
|
||||
//! For more information on chain specification and its properties, refer to
|
||||
//! [`sc_chain_spec#from-initial-state-to-raw-genesis`].
|
||||
//! [`pezsc_chain_spec#from-initial-state-to-raw-genesis`].
|
||||
//!
|
||||
//! The initial genesis state can be provided in the following formats:
|
||||
//! - full
|
||||
//! - patch
|
||||
//! - raw
|
||||
//!
|
||||
//! Each of the formats is explained in [_chain-spec-format_][`sc_chain_spec#chain-spec-formats`].
|
||||
//! Each of the formats is explained in
|
||||
//! [_chain-spec-format_][`pezsc_chain_spec#chain-spec-formats`].
|
||||
//!
|
||||
//!
|
||||
//! # `GenesisConfig` for `pallet`
|
||||
//! # `GenesisConfig` for `pezpallet`
|
||||
//!
|
||||
//! Every frame pallet may have its initial state which is defined by the `GenesisConfig` internal
|
||||
//! struct. It is a regular Rust struct, annotated with the [`pallet::genesis_config`] attribute.
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pallet_bar_GenesisConfig)]
|
||||
//! Every frame pezpallet may have its initial state which is defined by the `GenesisConfig`
|
||||
//! internal struct. It is a regular Rust struct, annotated with the [`pezpallet::genesis_config`]
|
||||
//! attribute.
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pezpallet_bar_GenesisConfig)]
|
||||
//!
|
||||
//! The struct shall be defined within the pallet `mod`, as in the following code:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pallet_bar)]
|
||||
//! The struct shall be defined within the pezpallet `mod`, as in the following code:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pezpallet_bar)]
|
||||
//!
|
||||
//! The initial state conveyed in the `GenesisConfig` struct is transformed into state storage
|
||||
//! items by means of the [`BuildGenesisConfig`] trait, which shall be implemented for the pallet's
|
||||
//! `GenesisConfig` struct. The [`pallet::genesis_build`] attribute shall be attached to the `impl`
|
||||
//! block:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pallet_bar_build)]
|
||||
//! items by means of the [`BuildGenesisConfig`] trait, which shall be implemented for the
|
||||
//! pezpallet's `GenesisConfig` struct. The [`pezpallet::genesis_build`] attribute shall be attached
|
||||
//! to the `impl` block:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pezpallet_bar_build)]
|
||||
//!
|
||||
//! `GenesisConfig` may also contain more complicated types, including nested structs or enums, as
|
||||
//! in the example for `pallet_foo`:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pallet_foo_GenesisConfig)]
|
||||
//! in the example for `pezpallet_foo`:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pezpallet_foo_GenesisConfig)]
|
||||
//!
|
||||
//! Note that [`serde`] attributes can be used to control how the data
|
||||
//! structures are stored into JSON. In the following example, the [`sp_core::bytes`] function is
|
||||
//! structures are stored into JSON. In the following example, the [`pezsp_core::bytes`] function is
|
||||
//! used to serialize the `values` field.
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", SomeFooData2)]
|
||||
//!
|
||||
//! Please note that fields of `GenesisConfig` may not be directly mapped to storage items. In the
|
||||
//! following example, the initial struct fields are used to compute (sum) the value that will be
|
||||
//! stored in the state as `ProcessedEnumValue`:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pallet_foo_build)]
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/pallets.rs", pezpallet_foo_build)]
|
||||
//!
|
||||
//! # `GenesisConfig` for `runtimes`
|
||||
//!
|
||||
//! The runtime genesis config struct consists of configs for every pallet. For the [_demonstration
|
||||
//! runtime_][`chain_spec_guide_runtime`] used in this guide, it consists of `SystemConfig`,
|
||||
//! `BarConfig`, and `FooConfig`. This structure was automatically generated by a macro and it can
|
||||
//! be sneak-peeked here: [`RuntimeGenesisConfig`]. For further reading on generated runtime
|
||||
//! types, refer to [`frame_runtime_types`].
|
||||
//! The runtime genesis config struct consists of configs for every pezpallet. For the
|
||||
//! [_demonstration runtime_][`pez_chain_spec_guide_runtime`] used in this guide, it consists of
|
||||
//! `SystemConfig`, `BarConfig`, and `FooConfig`. This structure was automatically generated by a
|
||||
//! macro and it can be sneak-peeked here: [`RuntimeGenesisConfig`]. For further reading on
|
||||
//! generated runtime types, refer to [`frame_runtime_types`].
|
||||
//!
|
||||
//! The macro automatically adds an attribute that renames all the fields to [`camelCase`]. It is a
|
||||
//! good practice to add it to nested structures too, to have the naming of the JSON keys consistent
|
||||
@@ -80,16 +82,16 @@
|
||||
//! ## Implementing `GenesisBuilder` for runtime
|
||||
//!
|
||||
//! The runtime exposes a dedicated runtime API for interacting with its genesis config:
|
||||
//! [`sp_genesis_builder::GenesisBuilder`]. The implementation shall be provided within
|
||||
//! the [`sp_api::impl_runtime_apis`] macro, typically making use of some helpers provided:
|
||||
//! [`pezsp_genesis_builder::GenesisBuilder`]. The implementation shall be provided within
|
||||
//! the [`pezsp_api::impl_runtime_apis`] macro, typically making use of some helpers provided:
|
||||
//! [`build_state`], [`get_preset`].
|
||||
//! A typical implementation of [`sp_genesis_builder::GenesisBuilder`] looks as follows:
|
||||
//! A typical implementation of [`pezsp_genesis_builder::GenesisBuilder`] looks as follows:
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/runtime.rs", runtime_impl)]
|
||||
//!
|
||||
//! Please note that two functions are customized: `preset_names` and `get_preset`. The first one
|
||||
//! just provides a `Vec` of the names of supported presets, while the latter delegates the call
|
||||
//! to a function that maps the name to an actual preset:
|
||||
//! [`chain_spec_guide_runtime::presets::get_builtin_preset`]
|
||||
//! [`pez_chain_spec_guide_runtime::presets::get_builtin_preset`]
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/src/presets.rs", get_builtin_preset)]
|
||||
//!
|
||||
//! ## Genesis state presets for runtime
|
||||
@@ -150,27 +152,27 @@
|
||||
//! recommended for production chains.
|
||||
//!
|
||||
//! For a detailed description of how the raw format is built, please refer to
|
||||
//! [_chain-spec-raw-genesis_][`sc_chain_spec#from-initial-state-to-raw-genesis`]. Plain and
|
||||
//! [_chain-spec-raw-genesis_][`pezsc_chain_spec#from-initial-state-to-raw-genesis`]. Plain and
|
||||
//! corresponding raw examples of chain-spec are given in
|
||||
//! [_chain-spec-examples_][`sc_chain_spec#json-chain-specification-example`].
|
||||
//! [_chain-spec-examples_][`pezsc_chain_spec#json-chain-specification-example`].
|
||||
//! The [`chain_spec_builder`] util supports building the raw storage.
|
||||
//!
|
||||
//! # Interacting with the tool
|
||||
//!
|
||||
//! The [`chain_spec_builder`] util allows interaction with the runtime in order to list or display
|
||||
//! presets and build the chain specification file. It is possible to use the tool with the
|
||||
//! [_demonstration runtime_][`chain_spec_guide_runtime`]. To build the required packages, just run
|
||||
//! the following command:
|
||||
//! [_demonstration runtime_][`pez_chain_spec_guide_runtime`]. To build the required packages, just
|
||||
//! run the following command:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! cargo build -p staging-chain-spec-builder -p chain-spec-guide-runtime --release
|
||||
//! cargo build -p pezstaging-chain-spec-builder -p pez-chain-spec-guide-runtime --release
|
||||
//! ```
|
||||
//!
|
||||
//! The `chain-spec-builder` util can also be installed with `cargo install`:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! cargo install staging-chain-spec-builder
|
||||
//! cargo build -p chain-spec-guide-runtime --release
|
||||
//! cargo install pezstaging-chain-spec-builder
|
||||
//! cargo build -p pez-chain-spec-guide-runtime --release
|
||||
//! ```
|
||||
//! Here are some examples in the form of rust tests:
|
||||
//! ## Listing available preset names:
|
||||
@@ -183,18 +185,18 @@
|
||||
#![doc = docify::embed!("./src/reference_docs/chain_spec_runtime/tests/chain_spec_builder_tests.rs", cmd_generate_para_chain_spec)]
|
||||
//!
|
||||
//! [`RuntimeGenesisConfig`]:
|
||||
//! chain_spec_guide_runtime::runtime::RuntimeGenesisConfig
|
||||
//! pez_chain_spec_guide_runtime::runtime::RuntimeGenesisConfig
|
||||
//! [`FooStruct`]:
|
||||
//! chain_spec_guide_runtime::pallets::FooStruct
|
||||
//! [`impl_runtime_apis`]: frame::runtime::prelude::impl_runtime_apis
|
||||
//! [`build_state`]: frame_support::genesis_builder_helper::build_state
|
||||
//! [`get_preset`]: frame_support::genesis_builder_helper::get_preset
|
||||
//! [`pallet::genesis_build`]: frame_support::pallet_macros::genesis_build
|
||||
//! [`pallet::genesis_config`]: frame_support::pallet_macros::genesis_config
|
||||
//! [`build_struct_json_patch`]: frame_support::build_struct_json_patch
|
||||
//! [`BuildGenesisConfig`]: frame_support::traits::BuildGenesisConfig
|
||||
//! pez_chain_spec_guide_runtime::pallets::FooStruct
|
||||
//! [`impl_runtime_apis`]: pezframe::runtime::prelude::impl_runtime_apis
|
||||
//! [`build_state`]: pezframe_support::genesis_builder_helper::build_state
|
||||
//! [`get_preset`]: pezframe_support::genesis_builder_helper::get_preset
|
||||
//! [`pezpallet::genesis_build`]: pezframe_support::pezpallet_macros::genesis_build
|
||||
//! [`pezpallet::genesis_config`]: pezframe_support::pezpallet_macros::genesis_config
|
||||
//! [`build_struct_json_patch`]: pezframe_support::build_struct_json_patch
|
||||
//! [`BuildGenesisConfig`]: pezframe_support::traits::BuildGenesisConfig
|
||||
//! [`serde`]: https://serde.rs/field-attrs.html
|
||||
//! [`get_storage_for_patch`]: sc_chain_spec::GenesisConfigBuilderRuntimeCaller::get_storage_for_patch
|
||||
//! [`GenesisBuilder::get_preset`]: sp_genesis_builder::GenesisBuilder::get_preset
|
||||
//! [`get_storage_for_patch`]: pezsc_chain_spec::GenesisConfigBuilderRuntimeCaller::get_storage_for_patch
|
||||
//! [`GenesisBuilder::get_preset`]: pezsp_genesis_builder::GenesisBuilder::get_preset
|
||||
//! [`deny_unknown_fields`]: https://serde.rs/container-attrs.html#deny_unknown_fields
|
||||
//! [`camelCase`]: https://serde.rs/container-attrs.html#rename_all
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "chain-spec-guide-runtime"
|
||||
name = "pez-chain-spec-guide-runtime"
|
||||
description = "A minimal runtime for chain spec guide"
|
||||
version = "0.0.0"
|
||||
license = "MIT-0"
|
||||
@@ -8,57 +8,77 @@ homepage.workspace = true
|
||||
repository.workspace = true
|
||||
edition.workspace = true
|
||||
publish = false
|
||||
documentation.workspace = true
|
||||
|
||||
[dependencies]
|
||||
codec = { workspace = true }
|
||||
docify = { workspace = true }
|
||||
frame-support = { workspace = true }
|
||||
pezframe-support = { workspace = true }
|
||||
pezframe-system = { workspace = true }
|
||||
scale-info = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
|
||||
# this is a frame-based runtime, thus importing `frame` with runtime feature enabled.
|
||||
frame = { features = ["experimental", "runtime"], workspace = true }
|
||||
pezframe = { features = ["experimental", "runtime"], workspace = true }
|
||||
|
||||
# genesis builder that allows us to interact with runtime genesis config
|
||||
sp-application-crypto = { features = ["serde"], workspace = true }
|
||||
sp-core = { workspace = true }
|
||||
sp-genesis-builder = { workspace = true }
|
||||
sp-keyring = { workspace = true }
|
||||
sp-runtime = { features = ["serde"], workspace = true }
|
||||
pezsp-api = { workspace = true }
|
||||
pezsp-application-crypto = { features = ["serde"], workspace = true }
|
||||
pezsp-core = { workspace = true }
|
||||
pezsp-genesis-builder = { workspace = true }
|
||||
pezsp-keyring = { workspace = true }
|
||||
pezsp-runtime = { features = ["serde"], workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cmd_lib = { workspace = true }
|
||||
sc-chain-spec = { workspace = true, default-features = true }
|
||||
pezsc-chain-spec = { workspace = true, default-features = true }
|
||||
|
||||
[build-dependencies]
|
||||
substrate-wasm-builder = { optional = true, workspace = true, default-features = true }
|
||||
bizinikiwi-wasm-builder = { optional = true, workspace = true, default-features = true }
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = [
|
||||
"bizinikiwi-wasm-builder",
|
||||
"bizinikiwi-wasm-builder?/std",
|
||||
"codec/std",
|
||||
"pezframe-support/std",
|
||||
"pezframe-system/std",
|
||||
"pezframe/std",
|
||||
"pezsc-chain-spec/std",
|
||||
"pezsp-api/std",
|
||||
"pezsp-application-crypto/std",
|
||||
"pezsp-core/std",
|
||||
"pezsp-genesis-builder/std",
|
||||
"pezsp-keyring/std",
|
||||
"pezsp-runtime/std",
|
||||
"scale-info/std",
|
||||
|
||||
"frame-support/std",
|
||||
"frame/std",
|
||||
|
||||
"sp-application-crypto/std",
|
||||
"sp-core/std",
|
||||
"sp-genesis-builder/std",
|
||||
"sp-keyring/std",
|
||||
"sp-runtime/std",
|
||||
|
||||
"serde/std",
|
||||
"serde_json/std",
|
||||
"substrate-wasm-builder",
|
||||
]
|
||||
runtime-benchmarks = [
|
||||
"frame-support/runtime-benchmarks",
|
||||
"frame/runtime-benchmarks",
|
||||
"sc-chain-spec/runtime-benchmarks",
|
||||
"sp-genesis-builder/runtime-benchmarks",
|
||||
"sp-keyring/runtime-benchmarks",
|
||||
"sp-runtime/runtime-benchmarks",
|
||||
"substrate-wasm-builder?/runtime-benchmarks",
|
||||
"bizinikiwi-wasm-builder?/runtime-benchmarks",
|
||||
"pezframe-support/runtime-benchmarks",
|
||||
"pezframe-system/runtime-benchmarks",
|
||||
"pezframe/runtime-benchmarks",
|
||||
"pezsc-chain-spec/runtime-benchmarks",
|
||||
"pezsp-api/runtime-benchmarks",
|
||||
"pezsp-application-crypto/runtime-benchmarks",
|
||||
"pezsp-genesis-builder/runtime-benchmarks",
|
||||
"pezsp-keyring/runtime-benchmarks",
|
||||
"pezsp-runtime/runtime-benchmarks",
|
||||
]
|
||||
try-runtime = [
|
||||
"pezframe-support/try-runtime",
|
||||
"pezframe-system/try-runtime",
|
||||
"pezframe/try-runtime",
|
||||
"pezsc-chain-spec/try-runtime",
|
||||
"pezsp-api/try-runtime",
|
||||
"pezsp-genesis-builder/try-runtime",
|
||||
"pezsp-keyring/try-runtime",
|
||||
"pezsp-runtime/try-runtime",
|
||||
]
|
||||
serde = []
|
||||
experimental = []
|
||||
tuples-96 = []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of Substrate.
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,6 +18,6 @@
|
||||
fn main() {
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
substrate_wasm_builder::WasmBuilder::build_using_defaults();
|
||||
bizinikiwi_wasm_builder::WasmBuilder::build_using_defaults();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of Substrate.
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of Substrate.
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -18,32 +18,32 @@
|
||||
//! Pallets for the chain-spec demo runtime.
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use frame::prelude::*;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_bar {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_bar {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub(super) type InitialAccount<T: Config> = StorageValue<Value = T::AccountId>;
|
||||
|
||||
/// Simple `GenesisConfig`.
|
||||
#[pallet::genesis_config]
|
||||
#[pezpallet::genesis_config]
|
||||
#[derive(DefaultNoBound)]
|
||||
#[docify::export(pallet_bar_GenesisConfig)]
|
||||
#[docify::export(pezpallet_bar_GenesisConfig)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub initial_account: Option<T::AccountId>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
#[docify::export(pallet_bar_build)]
|
||||
#[pezpallet::genesis_build]
|
||||
#[docify::export(pezpallet_bar_build)]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
/// The storage building function that presents a direct mapping of the initial config
|
||||
/// values to the storage items.
|
||||
@@ -80,7 +80,7 @@ pub struct SomeFooData1 {
|
||||
#[docify::export]
|
||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||
pub struct SomeFooData2 {
|
||||
#[serde(default, with = "sp_core::bytes")]
|
||||
#[serde(default, with = "pezsp_core::bytes")]
|
||||
pub values: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -94,24 +94,24 @@ pub enum FooEnum {
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_foo {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_foo {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type ProcessedEnumValue<T> = StorageValue<Value = u64>;
|
||||
#[pallet::storage]
|
||||
#[pezpallet::storage]
|
||||
pub type SomeInteger<T> = StorageValue<Value = u32>;
|
||||
|
||||
/// The more sophisticated structure for conveying initial state.
|
||||
#[docify::export(pallet_foo_GenesisConfig)]
|
||||
#[pallet::genesis_config]
|
||||
#[docify::export(pezpallet_foo_GenesisConfig)]
|
||||
#[pezpallet::genesis_config]
|
||||
#[derive(DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub some_integer: u32,
|
||||
@@ -121,8 +121,8 @@ pub mod pallet_foo {
|
||||
pub _phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
#[docify::export(pallet_foo_build)]
|
||||
#[pezpallet::genesis_build]
|
||||
#[docify::export(pezpallet_foo_build)]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
/// The build method that indirectly maps an initial config values into the storage items.
|
||||
fn build(&self) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of Substrate.
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -22,10 +22,10 @@ use crate::{
|
||||
runtime::{BarConfig, FooConfig, RuntimeGenesisConfig},
|
||||
};
|
||||
use alloc::vec;
|
||||
use frame_support::build_struct_json_patch;
|
||||
use pezframe_support::build_struct_json_patch;
|
||||
use pezsp_application_crypto::Ss58Codec;
|
||||
use pezsp_keyring::Sr25519Keyring;
|
||||
use serde_json::{json, to_string, Value};
|
||||
use sp_application_crypto::Ss58Codec;
|
||||
use sp_keyring::Sr25519Keyring;
|
||||
|
||||
/// A demo preset with strings only.
|
||||
pub const PRESET_1: &str = "preset_1";
|
||||
@@ -120,7 +120,7 @@ fn preset_invalid() -> Value {
|
||||
///
|
||||
/// If no preset with given `id` exits `None` is returned.
|
||||
#[docify::export]
|
||||
pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option<alloc::vec::Vec<u8>> {
|
||||
pub fn get_builtin_preset(id: &pezsp_genesis_builder::PresetId) -> Option<alloc::vec::Vec<u8>> {
|
||||
let preset = match id.as_ref() {
|
||||
PRESET_1 => preset_1(),
|
||||
PRESET_2 => preset_2(),
|
||||
@@ -140,7 +140,7 @@ pub fn get_builtin_preset(id: &sp_genesis_builder::PresetId) -> Option<alloc::ve
|
||||
#[test]
|
||||
#[docify::export]
|
||||
fn check_presets() {
|
||||
let builder = sc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
|
||||
let builder = pezsc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
|
||||
crate::WASM_BINARY.expect("wasm binary shall exists"),
|
||||
);
|
||||
assert!(builder.get_storage_for_named_preset(Some(&PRESET_1.to_string())).is_ok());
|
||||
@@ -152,7 +152,7 @@ fn check_presets() {
|
||||
#[test]
|
||||
#[docify::export]
|
||||
fn invalid_preset_works() {
|
||||
let builder = sc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
|
||||
let builder = pezsc_chain_spec::GenesisConfigBuilderRuntimeCaller::<()>::new(
|
||||
crate::WASM_BINARY.expect("wasm binary shall exists"),
|
||||
);
|
||||
// Even though a preset contains invalid_key, conversion to raw storage does not fail. This is
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of Substrate.
|
||||
// This file is part of Bizinikiwi.
|
||||
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -22,25 +22,24 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
|
||||
|
||||
use crate::{
|
||||
pallets::{pallet_bar, pallet_foo},
|
||||
pallets::{pezpallet_bar, pezpallet_foo},
|
||||
presets::*,
|
||||
};
|
||||
use alloc::{vec, vec::Vec};
|
||||
use frame::{
|
||||
deps::frame_support::{
|
||||
genesis_builder_helper::{build_state, get_preset},
|
||||
runtime,
|
||||
},
|
||||
use pezframe::{
|
||||
deps::pezframe_support::genesis_builder_helper::{build_state, get_preset},
|
||||
prelude::*,
|
||||
runtime::{apis, prelude::*},
|
||||
runtime::prelude::*,
|
||||
};
|
||||
use sp_genesis_builder::PresetId;
|
||||
use pezsp_api::impl_runtime_apis;
|
||||
use pezsp_genesis_builder::PresetId;
|
||||
use pezsp_runtime::traits::Block as BlockT;
|
||||
|
||||
/// 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"),
|
||||
spec_name: alloc::borrow::Cow::Borrowed("pez-minimal-template-runtime"),
|
||||
impl_name: alloc::borrow::Cow::Borrowed("pez-minimal-template-runtime"),
|
||||
authoring_version: 1,
|
||||
spec_version: 0,
|
||||
impl_version: 1,
|
||||
@@ -53,7 +52,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
||||
type SignedExtra = ();
|
||||
|
||||
// Composes the runtime by adding all the used pallets and deriving necessary types.
|
||||
#[runtime]
|
||||
#[frame_construct_runtime]
|
||||
mod runtime {
|
||||
/// The main runtime type.
|
||||
#[runtime::runtime]
|
||||
@@ -67,48 +66,48 @@ mod runtime {
|
||||
)]
|
||||
pub struct Runtime;
|
||||
|
||||
/// Mandatory system pallet that should always be included in a FRAME runtime.
|
||||
#[runtime::pallet_index(0)]
|
||||
pub type System = frame_system;
|
||||
/// Mandatory system pezpallet that should always be included in a FRAME runtime.
|
||||
#[runtime::pezpallet_index(0)]
|
||||
pub type System = pezframe_system::Pezpallet<Runtime>;
|
||||
|
||||
/// Sample pallet 1
|
||||
#[runtime::pallet_index(1)]
|
||||
pub type Bar = pallet_bar;
|
||||
/// Sample pezpallet 1
|
||||
#[runtime::pezpallet_index(1)]
|
||||
pub type Bar = pezpallet_bar::Pezpallet<Runtime>;
|
||||
|
||||
/// Sample pallet 2
|
||||
#[runtime::pallet_index(2)]
|
||||
pub type Foo = pallet_foo;
|
||||
/// Sample pezpallet 2
|
||||
#[runtime::pezpallet_index(2)]
|
||||
pub type Foo = pezpallet_foo::Pezpallet<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 {
|
||||
/// Implements the types required for the system pezpallet.
|
||||
#[derive_impl(pezframe_system::config_preludes::SolochainDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = Block;
|
||||
type Version = Version;
|
||||
}
|
||||
|
||||
impl pallet_bar::Config for Runtime {}
|
||||
impl pallet_foo::Config for Runtime {}
|
||||
impl pezpallet_bar::Config for Runtime {}
|
||||
impl pezpallet_foo::Config for Runtime {}
|
||||
|
||||
type Block = frame::runtime::types_common::BlockOf<Runtime, SignedExtra>;
|
||||
type Header = HeaderFor<Runtime>;
|
||||
type Block = pezframe::runtime::types_common::BlockOf<Runtime, SignedExtra>;
|
||||
type _Header = HeaderFor<Runtime>;
|
||||
|
||||
#[docify::export(runtime_impl)]
|
||||
impl_runtime_apis! {
|
||||
impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
|
||||
fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
|
||||
impl pezsp_genesis_builder::GenesisBuilder<Block> for Runtime {
|
||||
fn build_state(config: Vec<u8>) -> pezsp_genesis_builder::Result {
|
||||
build_state::<RuntimeGenesisConfig>(config)
|
||||
}
|
||||
|
||||
fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
|
||||
fn get_preset(id: &Option<pezsp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
|
||||
get_preset::<RuntimeGenesisConfig>(id, get_builtin_preset)
|
||||
}
|
||||
|
||||
fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
|
||||
fn preset_names() -> Vec<pezsp_genesis_builder::PresetId> {
|
||||
vec![
|
||||
PresetId::from(PRESET_1),
|
||||
PresetId::from(PRESET_2),
|
||||
@@ -119,9 +118,9 @@ impl_runtime_apis! {
|
||||
}
|
||||
}
|
||||
|
||||
impl apis::Core<Block> for Runtime {
|
||||
impl pezsp_api::Core<Block> for Runtime {
|
||||
fn version() -> RuntimeVersion { VERSION }
|
||||
fn execute_block(_: <Block as frame::traits::Block>::LazyBlock) { }
|
||||
fn initialize_block(_: &Header) -> ExtrinsicInclusionMode { ExtrinsicInclusionMode::default() }
|
||||
fn execute_block(_: <Block as BlockT>::LazyBlock) { }
|
||||
fn initialize_block(_: &<Block as BlockT>::Header) -> ExtrinsicInclusionMode { ExtrinsicInclusionMode::default() }
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -3,8 +3,8 @@ use serde_json::{json, Value};
|
||||
use std::str;
|
||||
|
||||
fn wasm_file_path() -> &'static str {
|
||||
chain_spec_guide_runtime::runtime::WASM_BINARY_PATH
|
||||
.expect("chain_spec_guide_runtime wasm should exist. qed")
|
||||
pez_chain_spec_guide_runtime::runtime::WASM_BINARY_PATH
|
||||
.expect("pez_chain_spec_guide_runtime wasm should exist. qed")
|
||||
}
|
||||
|
||||
const CHAIN_SPEC_BUILDER_PATH: &str = "../../../../../target/release/chain-spec-builder";
|
||||
@@ -24,7 +24,7 @@ macro_rules! bash(
|
||||
|
||||
fn get_chain_spec_builder_path() -> &'static str {
|
||||
run_cmd!(
|
||||
cargo build --release -p staging-chain-spec-builder --bin chain-spec-builder
|
||||
cargo build --release -p pezstaging-chain-spec-builder --bin chain-spec-builder
|
||||
)
|
||||
.expect("Failed to execute command");
|
||||
CHAIN_SPEC_BUILDER_PATH
|
||||
@@ -189,7 +189,7 @@ fn generate_para_chain_spec() {
|
||||
#[docify::export_content]
|
||||
fn preset_4_json() {
|
||||
assert_eq!(
|
||||
chain_spec_guide_runtime::presets::preset_4(),
|
||||
pez_chain_spec_guide_runtime::presets::preset_4(),
|
||||
json!({
|
||||
"foo": {
|
||||
"someEnum": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! # Substrate CLI
|
||||
//! # Bizinikiwi CLI
|
||||
//!
|
||||
//! Let's see some examples of typical CLI arguments used when setting up and running a
|
||||
//! Substrate-based blockchain. We use the [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/25)
|
||||
//! Bizinikiwi-based blockchain. We use the [`solochain-template`](https://github.com/pezkuwichain/pezkuwi-sdk/issues/195)
|
||||
//! on these examples.
|
||||
//!
|
||||
//! #### Checking the available CLI arguments
|
||||
@@ -10,7 +10,7 @@
|
||||
//! ```
|
||||
//! - `--help`: Displays the available CLI arguments.
|
||||
//!
|
||||
//! #### Starting a Local Substrate Node in Development Mode
|
||||
//! #### Starting a Local Bizinikiwi Node in Development Mode
|
||||
//! ```bash
|
||||
//! ./target/release/node-template \
|
||||
//! --dev
|
||||
@@ -97,8 +97,8 @@
|
||||
//! ---
|
||||
//!
|
||||
//! > If you are interested in learning how to extend the CLI with your custom arguments, you can
|
||||
//! > check out the [Customize your Substrate chain CLI](https://www.youtube.com/watch?v=IVifko1fqjw)
|
||||
//! > check out the [Customize your Bizinikiwi chain CLI](https://www.youtube.com/watch?v=IVifko1fqjw)
|
||||
//! > seminar.
|
||||
//! > Please note that the seminar is based on an older version of Substrate, and [Clap](https://docs.rs/clap/latest/clap/)
|
||||
//! > Please note that the seminar is based on an older version of Bizinikiwi, and [Clap](https://docs.rs/clap/latest/clap/)
|
||||
//! > is now used instead of [StructOpt](https://docs.rs/structopt/latest/structopt/) for parsing
|
||||
//! > CLI arguments.
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
//! ## Finding Host Functions
|
||||
//!
|
||||
//! To declare a set of functions as host functions, you need to use the `#[runtime_interface]`
|
||||
//! ([`sp_runtime_interface`]) attribute macro. The most notable set of host functions are those
|
||||
//! that allow the runtime to access the chain state, namely [`sp_io::storage`]. Some other notable
|
||||
//! host functions are also defined in [`sp_io`].
|
||||
//! ([`pezsp_runtime_interface`]) attribute macro. The most notable set of host functions are those
|
||||
//! that allow the runtime to access the chain state, namely [`pezsp_io::storage`]. Some other
|
||||
//! notable host functions are also defined in [`pezsp_io`].
|
||||
//!
|
||||
//! ## Adding New Host Functions
|
||||
//!
|
||||
@@ -20,8 +20,8 @@
|
||||
//! access to the boilerplate of building your node.
|
||||
//!
|
||||
//! A group of host functions can always be grouped to gether as a tuple:
|
||||
#![doc = docify::embed!("../../substrate/primitives/io/src/lib.rs", SubstrateHostFunctions)]
|
||||
#![doc = docify::embed!("../../bizinikiwi/primitives/io/src/lib.rs", BizinikiwiHostFunctions)]
|
||||
//!
|
||||
//! The host functions are attached to the node side's [`sc_executor::WasmExecutor`]. For example in
|
||||
//! the minimal template, the setup looks as follows:
|
||||
//! The host functions are attached to the node side's [`pezsc_executor::WasmExecutor`]. For example
|
||||
//! in the minimal template, the setup looks as follows:
|
||||
#![doc = docify::embed!("../../templates/minimal/node/src/service.rs", FullClient)]
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//! ## Background
|
||||
//!
|
||||
//! Pezkuwi-SDK offers the ability to query and subscribe storages directly. However what it does
|
||||
//! not have is [view functions](https://github.com/pezkuwichain/pezkuwi-sdk/issues/101). This is an
|
||||
//! not have is [view functions](https://github.com/pezkuwichain/pezkuwi-sdk/issues/247). This is an
|
||||
//! essential feature to avoid duplicated logic between runtime and the client SDK. Custom RPC was
|
||||
//! used as a solution. It allow the RPC node to expose new RPCs that clients can be used to query
|
||||
//! computed properties.
|
||||
@@ -31,7 +31,7 @@
|
||||
//!
|
||||
//! ## Alternatives
|
||||
//!
|
||||
//! Generally, [`sc_rpc::state::StateBackend::call`] aka. `state_call` should be used instead of
|
||||
//! Generally, [`pezsc_rpc::state::StateBackend::call`] aka. `state_call` should be used instead of
|
||||
//! custom RPC.
|
||||
//!
|
||||
//! Usually, each custom RPC comes with a corresponding runtime API which implements the business
|
||||
@@ -52,9 +52,9 @@
|
||||
//!
|
||||
//! For example, let's take a look at the process through which the account nonce can be queried
|
||||
//! through an RPC. First, a new runtime-api needs to be declared:
|
||||
#![doc = docify::embed!("../../substrate/frame/system/rpc/runtime-api/src/lib.rs", AccountNonceApi)]
|
||||
#![doc = docify::embed!("../../bizinikiwi/pezframe/system/rpc/runtime-api/src/lib.rs", AccountNonceApi)]
|
||||
//!
|
||||
//! This API is implemented at the runtime level, always inside [`sp_api::impl_runtime_apis!`].
|
||||
//! This API is implemented at the runtime level, always inside [`pezsp_api::impl_runtime_apis!`].
|
||||
//!
|
||||
//! As noted, this is already enough to make this API usable via `state_call`.
|
||||
//!
|
||||
@@ -62,7 +62,7 @@
|
||||
//!
|
||||
//! Should you wish to implement the legacy approach of exposing this runtime-api as a custom
|
||||
//! RPC-api, then a custom RPC server has to be defined.
|
||||
#![doc = docify::embed!("../../substrate/utils/frame/rpc/system/src/lib.rs", SystemApi)]
|
||||
#![doc = docify::embed!("../../bizinikiwi/utils/pezframe/rpc/system/src/lib.rs", SystemApi)]
|
||||
//!
|
||||
//! ## Add a new RPC to the node (Legacy)
|
||||
//!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -24,14 +24,14 @@
|
||||
//!
|
||||
//! ## General Overview
|
||||
//!
|
||||
//! When developing within the context of the Substrate runtime, there is one golden rule:
|
||||
//! When developing within the context of the Bizinikiwi runtime, there is one golden rule:
|
||||
//!
|
||||
//! ***DO NOT PANIC***. There are some exceptions, but generally, this is the default precedent.
|
||||
//!
|
||||
//! > It’s important to differentiate between the runtime and node. The runtime refers to the core
|
||||
//! > business logic of a Substrate-based chain, whereas the node refers to the outer client, which
|
||||
//! > business logic of a Bizinikiwi-based chain, whereas the node refers to the outer client, which
|
||||
//! > deals with telemetry and gossip from other nodes. For more information, read about
|
||||
//! > [Substrate's node
|
||||
//! > [Bizinikiwi's node
|
||||
//! > architecture](crate::reference_docs::wasm_meta_protocol#node-vs-runtime). It’s also important
|
||||
//! > to note that the criticality of the node is slightly lesser
|
||||
//! > than that of the runtime, which is why you may see `unwrap()` or other “non-defensive”
|
||||
@@ -70,18 +70,18 @@
|
||||
//!
|
||||
//! ### Defensive Traits
|
||||
//!
|
||||
//! The [`Defensive`](frame::traits::Defensive) trait provides a number of functions, all of which
|
||||
//! The [`Defensive`](pezframe::traits::Defensive) trait provides a number of functions, all of which
|
||||
//! provide an alternative to 'vanilla' Rust functions, e.g.:
|
||||
//!
|
||||
//! - [`defensive_unwrap_or()`](frame::traits::Defensive::defensive_unwrap_or) instead of
|
||||
//! - [`defensive_unwrap_or()`](pezframe::traits::Defensive::defensive_unwrap_or) instead of
|
||||
//! `unwrap_or()`
|
||||
//! - [`defensive_ok_or()`](frame::traits::DefensiveOption::defensive_ok_or) instead of `ok_or()`
|
||||
//! - [`defensive_ok_or()`](pezframe::traits::DefensiveOption::defensive_ok_or) instead of `ok_or()`
|
||||
//!
|
||||
//! Defensive methods use [`debug_assertions`](https://doc.rust-lang.org/reference/conditional-compilation.html#debug_assertions), which panic in development, but in
|
||||
//! production/release, they will merely log an error (i.e., `log::error`).
|
||||
//!
|
||||
//! The [`Defensive`](frame::traits::Defensive) trait and its various implementations can be found
|
||||
//! [here](frame::traits::Defensive).
|
||||
//! The [`Defensive`](pezframe::traits::Defensive) trait and its various implementations can be found
|
||||
//! [here](pezframe::traits::Defensive).
|
||||
//!
|
||||
//! ## Integer Overflow
|
||||
//!
|
||||
@@ -110,11 +110,11 @@
|
||||
//! unexpected consequences like a user balance over or underflowing.
|
||||
//!
|
||||
//! Fortunately, there are ways to both represent and handle these scenarios depending on our
|
||||
//! specific use case natively built into Rust and libraries like [`sp_arithmetic`].
|
||||
//! specific use case natively built into Rust and libraries like [`pezsp_arithmetic`].
|
||||
//!
|
||||
//! ## Infallible Arithmetic
|
||||
//!
|
||||
//! Both Rust and Substrate provide safe ways to deal with numbers and alternatives to floating
|
||||
//! Both Rust and Bizinikiwi provide safe ways to deal with numbers and alternatives to floating
|
||||
//! point arithmetic.
|
||||
//!
|
||||
//! Known scenarios that could be fallible should be avoided: i.e., avoiding the possibility of
|
||||
@@ -124,8 +124,9 @@
|
||||
//! A developer should use fixed-point instead of floating-point arithmetic to mitigate the
|
||||
//! potential for inaccuracy, rounding errors, or other unexpected behavior.
|
||||
//!
|
||||
//! - [Fixed point types](sp_arithmetic::fixed_point) and their associated usage can be found here.
|
||||
//! - [PerThing](sp_arithmetic::per_things) and its associated types can be found here.
|
||||
//! - [Fixed point types](pezsp_arithmetic::fixed_point) and their associated usage can be found
|
||||
//! here.
|
||||
//! - [PerThing](pezsp_arithmetic::per_things) and its associated types can be found here.
|
||||
//!
|
||||
//! Using floating point number types (i.e. f32, f64) in the runtime should be avoided, as a single non-deterministic result could cause chaos for blockchain consensus along with the issues above. For more on the specifics of the peculiarities of floating point calculations, [watch this video by the Computerphile](https://www.youtube.com/watch?v=PZRI1IfStY0).
|
||||
//!
|
||||
@@ -187,15 +188,15 @@
|
||||
//! to avoid introducing the notion of any potential-panic or wrapping behavior.
|
||||
//!
|
||||
//! There is also a series of defensive alternatives via
|
||||
//! [`DefensiveSaturating`](frame::traits::DefensiveSaturating), which introduces the same behavior
|
||||
//! of the [`Defensive`](frame::traits::Defensive) trait, only with saturating, mathematical
|
||||
//! [`DefensiveSaturating`](pezframe::traits::DefensiveSaturating), which introduces the same behavior
|
||||
//! of the [`Defensive`](pezframe::traits::Defensive) trait, only with saturating, mathematical
|
||||
//! operations:
|
||||
#![doc = docify::embed!(
|
||||
"./src/reference_docs/defensive_programming.rs",
|
||||
saturated_defensive_example
|
||||
)]
|
||||
//!
|
||||
//! ### Mathematical Operations in Substrate Development - Further Context
|
||||
//! ### Mathematical Operations in Bizinikiwi Development - Further Context
|
||||
//!
|
||||
//! As a recap, we covered the following concepts:
|
||||
//!
|
||||
@@ -214,9 +215,9 @@
|
||||
//!
|
||||
//! #### Bob's Overflowed Balance
|
||||
//!
|
||||
//! **Bob's** balance exceeds the `Balance` type on the `EduChain`. Because the pallet developer did
|
||||
//! not handle the calculation to add to Bob's balance with any regard to this overflow, **Bob's**
|
||||
//! balance is now essentially `0`, the operation **wrapped**.
|
||||
//! **Bob's** balance exceeds the `Balance` type on the `EduChain`. Because the pezpallet developer
|
||||
//! did not handle the calculation to add to Bob's balance with any regard to this overflow,
|
||||
//! **Bob's** balance is now essentially `0`, the operation **wrapped**.
|
||||
//!
|
||||
//! <details>
|
||||
//! <summary><b>Solution: Saturating or Checked</b></summary>
|
||||
@@ -247,7 +248,7 @@
|
||||
//!
|
||||
//! A `u8` parameter, called `proposals_count`, represents the type for counting the number of
|
||||
//! proposals on-chain. Every time a new proposal is added to the system, this number increases.
|
||||
//! With the proposal pallet's high usage, it has reached `u8::MAX`’s limit of 255, causing
|
||||
//! With the proposal pezpallet's high usage, it has reached `u8::MAX`’s limit of 255, causing
|
||||
//! `proposals_count` to go to 0. Unfortunately, this results in new proposals overwriting old ones,
|
||||
//! effectively erasing any notion of past proposals!
|
||||
//!
|
||||
@@ -267,17 +268,17 @@
|
||||
//! From the above, we can clearly see the problematic nature of seemingly simple operations in the
|
||||
//! runtime, and care should be given to ensure a defensive approach is taken.
|
||||
//!
|
||||
//! ### Edge cases of `panic!`-able instances in Substrate
|
||||
//! ### Edge cases of `panic!`-able instances in Bizinikiwi
|
||||
//!
|
||||
//! As you traverse through the codebase (particularly in `substrate/frame`, where the majority of
|
||||
//! As you traverse through the codebase (particularly in `bizinikiwi/frame`, where the majority of
|
||||
//! runtime code lives), you may notice that there (only a few!) occurrences where `panic!` is used
|
||||
//! explicitly. This is used when the runtime should stall, rather than keep running, as that is
|
||||
//! considered safer. Particularly when it comes to mission-critical components, such as block
|
||||
//! authoring, consensus, or other protocol-level dependencies, going through with an action may
|
||||
//! actually cause harm to the network, and thus stalling would be the better option.
|
||||
//!
|
||||
//! Take the example of the BABE pallet ([`pallet_babe`]), which doesn't allow for a validator to
|
||||
//! participate if it is disabled (see: [`frame::traits::DisabledValidators`]):
|
||||
//! Take the example of the BABE pezpallet ([`pezpallet_babe`]), which doesn't allow for a validator
|
||||
//! to participate if it is disabled (see: [`pezframe::traits::DisabledValidators`]):
|
||||
//!
|
||||
//! ```ignore
|
||||
//! if T::DisabledValidators::is_disabled(authority_index) {
|
||||
@@ -358,7 +359,7 @@ mod fake_runtime_types {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use frame::traits::DefensiveSaturating;
|
||||
use pezframe::traits::DefensiveSaturating;
|
||||
#[docify::export]
|
||||
#[test]
|
||||
fn checked_add_example() {
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
//!
|
||||
//! The WASM binary is usually not needed, especially when running `check` or `test`. To skip the
|
||||
//! WASM build, set the `SKIP_WASM_BUILD` environment variable to `1`. For example:
|
||||
//! `SKIP_WASM_BUILD=1 cargo check -p frame-support`.
|
||||
//! `SKIP_WASM_BUILD=1 cargo check -p pezframe-support`.
|
||||
//!
|
||||
//! ### Cargo Remote
|
||||
//!
|
||||
|
||||
@@ -4,21 +4,21 @@
|
||||
//! of a blockchain via the [_state transition
|
||||
//! function_][crate::reference_docs::blockchain_state_machines].
|
||||
//!
|
||||
//! Substrate is configurable enough that extrinsics can take any format. In practice, runtimes
|
||||
//! tend to use our [`sp_runtime::generic::UncheckedExtrinsic`] type to represent extrinsics,
|
||||
//! Bizinikiwi is configurable enough that extrinsics can take any format. In practice, runtimes
|
||||
//! tend to use our [`pezsp_runtime::generic::UncheckedExtrinsic`] type to represent extrinsics,
|
||||
//! because it's generic enough to cater for most (if not all) use cases. In Pezkuwi, this is
|
||||
//! configured [here](https://github.com/polkadot-fellows/runtimes/blob/94b2798b69ba6779764e20a50f056e48db78ebef/relay/polkadot/src/lib.rs#L1478)
|
||||
//! at the time of writing.
|
||||
//!
|
||||
//! What follows is a description of how extrinsics based on this
|
||||
//! [`sp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are
|
||||
//! [`pezsp_runtime::generic::UncheckedExtrinsic`] type are encoded into bytes. Specifically, we are
|
||||
//! looking at how extrinsics with a format version of 5 are encoded. This version is itself a part
|
||||
//! of the payload, and if it changes, it indicates that something about the encoding may have
|
||||
//! changed.
|
||||
//!
|
||||
//! # Encoding an Extrinsic
|
||||
//!
|
||||
//! At a high level, all extrinsics compatible with [`sp_runtime::generic::UncheckedExtrinsic`]
|
||||
//! At a high level, all extrinsics compatible with [`pezsp_runtime::generic::UncheckedExtrinsic`]
|
||||
//! are formed from concatenating some details together, as in the following pseudo-code:
|
||||
//!
|
||||
//! ```text
|
||||
@@ -30,14 +30,14 @@
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! For clarity, the actual implementation in Substrate looks like this:
|
||||
#![doc = docify::embed!("../../substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs", unchecked_extrinsic_encode_impl)]
|
||||
//! For clarity, the actual implementation in Bizinikiwi looks like this:
|
||||
#![doc = docify::embed!("../../bizinikiwi/primitives/runtime/src/generic/unchecked_extrinsic.rs", unchecked_extrinsic_encode_impl)]
|
||||
//!
|
||||
//! Let's look at how each of these details is constructed:
|
||||
//!
|
||||
//! ## compact_encoded_length
|
||||
//!
|
||||
//! This is a [SCALE compact encoded][frame::deps::codec::Compact] integer which is equal to the
|
||||
//! This is a [SCALE compact encoded][pezframe::deps::codec::Compact] integer which is equal to the
|
||||
//! length, in bytes, of the rest of the extrinsic details.
|
||||
//!
|
||||
//! To obtain this value, we must encode and concatenate together the rest of the extrinsic details
|
||||
@@ -90,25 +90,26 @@
|
||||
//!
|
||||
//! #### from_address
|
||||
//!
|
||||
//! This is the [SCALE encoded][frame::deps::codec] address of the sender of the extrinsic. The
|
||||
//! address is the first generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], and so
|
||||
//! This is the [SCALE encoded][pezframe::deps::codec] address of the sender of the extrinsic. The
|
||||
//! address is the first generic parameter of [`pezsp_runtime::generic::UncheckedExtrinsic`], and so
|
||||
//! can vary from chain to chain.
|
||||
//!
|
||||
//! The address type used on the Pezkuwi relay chain is [`sp_runtime::MultiAddress<AccountId32>`],
|
||||
//! where `AccountId32` is defined [here][`sp_core::crypto::AccountId32`]. When constructing a
|
||||
//! signed extrinsic to be submitted to a Pezkuwi node, you'll always use the
|
||||
//! [`sp_runtime::MultiAddress::Id`] variant to wrap your `AccountId32`.
|
||||
//! The address type used on the Pezkuwi relay chain is
|
||||
//! [`pezsp_runtime::MultiAddress<AccountId32>`], where `AccountId32` is defined
|
||||
//! [here][`pezsp_core::crypto::AccountId32`]. When constructing a signed extrinsic to be submitted
|
||||
//! to a Pezkuwi node, you'll always use the [`pezsp_runtime::MultiAddress::Id`] variant to wrap
|
||||
//! your `AccountId32`.
|
||||
//!
|
||||
//! #### signature
|
||||
//!
|
||||
//! This is the [SCALE encoded][frame::deps::codec] signature. The signature type is configured via
|
||||
//! the third generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`], which determines the
|
||||
//! shape of the signature and signing algorithm that should be used.
|
||||
//! This is the [SCALE encoded][pezframe::deps::codec] signature. The signature type is configured via
|
||||
//! the third generic parameter of [`pezsp_runtime::generic::UncheckedExtrinsic`], which determines
|
||||
//! the shape of the signature and signing algorithm that should be used.
|
||||
//!
|
||||
//! The signature is obtained by signing the _signed payload_ bytes (see below on how this is
|
||||
//! constructed) using the private key associated with the address and correct algorithm.
|
||||
//!
|
||||
//! The signature type used on the Pezkuwi relay chain is [`sp_runtime::MultiSignature`]; the
|
||||
//! The signature type used on the Pezkuwi relay chain is [`pezsp_runtime::MultiSignature`]; the
|
||||
//! variants there are the types of signature that can be provided.
|
||||
//!
|
||||
//! ### General extrinsics
|
||||
@@ -120,12 +121,12 @@
|
||||
//!
|
||||
//! ### transaction_extensions_extra
|
||||
//!
|
||||
//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing first a
|
||||
//! This is the concatenation of the [SCALE encoded][pezframe::deps::codec] bytes representing first a
|
||||
//! single byte describing the extension version (this is bumped whenever a change occurs in the
|
||||
//! transaction extension pipeline) followed by the bytes of each of the [_transaction
|
||||
//! extensions_][sp_runtime::traits::TransactionExtension], and are configured by the fourth generic
|
||||
//! parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about transaction
|
||||
//! extensions [here][crate::reference_docs::transaction_extensions].
|
||||
//! extensions_][pezsp_runtime::traits::TransactionExtension], and are configured by the fourth
|
||||
//! generic parameter of [`pezsp_runtime::generic::UncheckedExtrinsic`]. Learn more about
|
||||
//! transaction extensions [here][crate::reference_docs::transaction_extensions].
|
||||
//!
|
||||
//! When it comes to constructing an extrinsic, each transaction extension has two things that we
|
||||
//! are interested in here:
|
||||
@@ -141,22 +142,22 @@
|
||||
//! configuration. At the time of writing, Pezkuwi configures them
|
||||
//! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25).
|
||||
//! Some of the common transaction extensions are defined
|
||||
//! [here][frame::deps::frame_system#transaction-extensions].
|
||||
//! [here][pezframe::deps::pezframe_system#transaction-extensions].
|
||||
//!
|
||||
//! Information about exactly which transaction extensions are present on a chain and in what order
|
||||
//! is also a part of the metadata for the chain. For V15 metadata, it can be [found
|
||||
//! here][frame::deps::frame_support::__private::metadata::v15::ExtrinsicMetadata].
|
||||
//! here][pezframe::deps::pezframe_support::__private::metadata::v15::ExtrinsicMetadata].
|
||||
//!
|
||||
//! ## call_data
|
||||
//!
|
||||
//! This is the main payload of the extrinsic, which is used to determine how the chain's state is
|
||||
//! altered. This is defined by the second generic parameter of
|
||||
//! [`sp_runtime::generic::UncheckedExtrinsic`].
|
||||
//! [`pezsp_runtime::generic::UncheckedExtrinsic`].
|
||||
//!
|
||||
//! A call can be anything that implements [`Encode`][frame::deps::codec::Encode]. In FRAME-based
|
||||
//! A call can be anything that implements [`Encode`][pezframe::deps::codec::Encode]. In FRAME-based
|
||||
//! runtimes, a call is represented as an enum of enums, where the outer enum represents the FRAME
|
||||
//! pallet being called, and the inner enum represents the call being made within that pallet, and
|
||||
//! any arguments to it. Read more about the call enum
|
||||
//! pezpallet being called, and the inner enum represents the call being made within that pezpallet,
|
||||
//! and any arguments to it. Read more about the call enum
|
||||
//! [here][crate::reference_docs::frame_runtime_types].
|
||||
//!
|
||||
//! FRAME `Call` enums are automatically generated, and end up looking something like this:
|
||||
@@ -166,23 +167,23 @@
|
||||
//!
|
||||
//! ```text
|
||||
//! call_data = concat(
|
||||
//! pallet_index,
|
||||
//! pezpallet_index,
|
||||
//! call_index,
|
||||
//! call_args
|
||||
//! )
|
||||
//! ```
|
||||
//!
|
||||
//! - `pallet_index` is a single byte denoting the index of the pallet that we are calling into, and
|
||||
//! is what the tag of the outermost enum will encode to.
|
||||
//! - `call_index` is a single byte denoting the index of the call that we are making the pallet,
|
||||
//! - `pezpallet_index` is a single byte denoting the index of the pezpallet that we are calling
|
||||
//! into, and is what the tag of the outermost enum will encode to.
|
||||
//! - `call_index` is a single byte denoting the index of the call that we are making the pezpallet,
|
||||
//! and is what the tag of the inner enum will encode to.
|
||||
//! - `call_args` are the SCALE encoded bytes for each of the arguments that the call expects, and
|
||||
//! are typically provided as values to the inner enum.
|
||||
//!
|
||||
//! Information about the pallets that exist for a chain (including their indexes), the calls
|
||||
//! available in each pallet (including their indexes), and the arguments required for each call can
|
||||
//! be found in the metadata for the chain. For V15 metadata, this information [is
|
||||
//! here][frame::deps::frame_support::__private::metadata::v15::PalletMetadata].
|
||||
//! available in each pezpallet (including their indexes), and the arguments required for each call
|
||||
//! can be found in the metadata for the chain. For V15 metadata, this information [is
|
||||
//! here][pezframe::deps::pezframe_support::__private::metadata::v15::PalletMetadata].
|
||||
//!
|
||||
//! # The Signed Payload Format
|
||||
//!
|
||||
@@ -202,13 +203,13 @@
|
||||
//!
|
||||
//! The bytes representing `call_data` and `transaction_extensions_extra` can be obtained as
|
||||
//! descibed above. `transaction_extensions_implicit` is constructed by SCALE encoding the
|
||||
//! ["implicit" data][sp_runtime::traits::TransactionExtension::Implicit] for each transaction
|
||||
//! ["implicit" data][pezsp_runtime::traits::TransactionExtension::Implicit] for each transaction
|
||||
//! extension that the chain is using, in order.
|
||||
//!
|
||||
//! Once we've concatenated those together, we hash the result using a Blake2 256bit hasher.
|
||||
//!
|
||||
//! The [`sp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload for
|
||||
//! us, given `call_data` and a tuple of transaction extensions.
|
||||
//! The [`pezsp_runtime::generic::SignedPayload`] type takes care of assembling the correct payload
|
||||
//! for us, given `call_data` and a tuple of transaction extensions.
|
||||
//!
|
||||
//! # The General Transaction Format
|
||||
//!
|
||||
@@ -216,22 +217,22 @@
|
||||
//! extrinsic, such as a traditionally signed transaction. Instead, general transactions should have
|
||||
//! one or more extensions in the transaction extension pipeline that auhtorize origins in some way,
|
||||
//! one of which could be the traditional signature check that happens for all signed transactions
|
||||
//! in the [Checkable](sp_runtime::traits::Checkable) implementation of
|
||||
//! [UncheckedExtrinsic](sp_runtime::generic::UncheckedExtrinsic). Therefore, it is up to each
|
||||
//! in the [Checkable](pezsp_runtime::traits::Checkable) implementation of
|
||||
//! [UncheckedExtrinsic](pezsp_runtime::generic::UncheckedExtrinsic). Therefore, it is up to each
|
||||
//! extension to define the format of the payload it will try to check and authorize the right
|
||||
//! origin type. For an example, look into the [authorization example pallet
|
||||
//! extensions](pallet_example_authorization_tx_extension::extensions)
|
||||
//! origin type. For an example, look into the [authorization example pezpallet
|
||||
//! extensions](pezpallet_example_authorization_tx_extension::extensions)
|
||||
//!
|
||||
//! # Example Encoding
|
||||
//!
|
||||
//! Using [`sp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic as
|
||||
//! follows:
|
||||
//! Using [`pezsp_runtime::generic::UncheckedExtrinsic`], we can construct and encode an extrinsic
|
||||
//! as follows:
|
||||
#![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", encoding_example)]
|
||||
|
||||
#[docify::export]
|
||||
pub mod call_data {
|
||||
use codec::{Decode, Encode};
|
||||
use sp_runtime::{traits::Dispatchable, DispatchResultWithInfo};
|
||||
use pezsp_runtime::{traits::Dispatchable, DispatchResultWithInfo};
|
||||
|
||||
// The outer enum composes calls within
|
||||
// different pallets together. We have two
|
||||
@@ -245,7 +246,7 @@ pub mod call_data {
|
||||
}
|
||||
|
||||
// An inner enum represents the calls within
|
||||
// a specific pallet. "PalletA" has one call,
|
||||
// a specific pezpallet. "PalletA" has one call,
|
||||
// "Foo".
|
||||
#[derive(Encode, Decode, Clone)]
|
||||
pub enum PalletACall {
|
||||
@@ -275,9 +276,9 @@ pub mod encoding_example {
|
||||
use super::call_data::{Call, PalletACall};
|
||||
use crate::reference_docs::transaction_extensions::transaction_extensions_example;
|
||||
use codec::Encode;
|
||||
use sp_core::crypto::AccountId32;
|
||||
use sp_keyring::sr25519::Keyring;
|
||||
use sp_runtime::{
|
||||
use pezsp_core::crypto::AccountId32;
|
||||
use pezsp_keyring::sr25519::Keyring;
|
||||
use pezsp_runtime::{
|
||||
generic::{SignedPayload, UncheckedExtrinsic},
|
||||
MultiAddress, MultiSignature,
|
||||
};
|
||||
|
||||
@@ -17,17 +17,17 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! within the pallet, if you want to use the standard `println!`, it needs to be wrapped in
|
||||
//! [`sp_std::if_std`]. Of course, this means that this print code is only available to you in the
|
||||
//! `std` compiler flag, and never present in a wasm build.
|
||||
//! within the pezpallet, if you want to use the standard `println!`, it needs to be wrapped in
|
||||
//! [`pezsp_std::if_std`]. Of course, this means that this print code is only available to you in
|
||||
//! the `std` compiler flag, and never present in a wasm build.
|
||||
//!
|
||||
//! ```
|
||||
//! // somewhere in your pallet. This is not a real pallet code.
|
||||
//! mod pallet {
|
||||
//! struct Pallet;
|
||||
//! impl Pallet {
|
||||
//! // somewhere in your pezpallet. This is not a real pezpallet code.
|
||||
//! mod pezpallet {
|
||||
//! struct Pezpallet;
|
||||
//! impl Pezpallet {
|
||||
//! fn print() {
|
||||
//! sp_std::if_std! {
|
||||
//! pezsp_std::if_std! {
|
||||
//! println!("Hello, world!");
|
||||
//! }
|
||||
//! }
|
||||
@@ -42,9 +42,9 @@
|
||||
//! 1. `log-level`, signifying how important it is.
|
||||
//! 2. `log-target`, signifying to which component it belongs.
|
||||
//!
|
||||
//! Add log statements to your pallet as such:
|
||||
//! Add log statements to your pezpallet as such:
|
||||
//!
|
||||
//! You can add the log crate to the `Cargo.toml` of the pallet.
|
||||
//! You can add the log crate to the `Cargo.toml` of the pezpallet.
|
||||
//!
|
||||
//! ```text
|
||||
//! #[dependencies]
|
||||
@@ -57,49 +57,49 @@
|
||||
//! ]
|
||||
//! ```
|
||||
//!
|
||||
//! More conveniently, the `frame` umbrella crate re-exports the log crate as [`frame::log`].
|
||||
//! More conveniently, the `frame` umbrella crate re-exports the log crate as [`pezframe::log`].
|
||||
//!
|
||||
//! Then, the pallet can use this crate to emit log statements. In this statement, we use the info
|
||||
//! level, and the target is `pallet-example`.
|
||||
//! Then, the pezpallet can use this crate to emit log statements. In this statement, we use the
|
||||
//! info level, and the target is `pezpallet-example`.
|
||||
//!
|
||||
//! ```
|
||||
//! mod pallet {
|
||||
//! struct Pallet;
|
||||
//! mod pezpallet {
|
||||
//! struct Pezpallet;
|
||||
//!
|
||||
//! impl Pallet {
|
||||
//! impl Pezpallet {
|
||||
//! fn logs() {
|
||||
//! frame::log::info!(target: "pallet-example", "Hello, world!");
|
||||
//! pezframe::log::info!(target: "pezpallet-example", "Hello, world!");
|
||||
//! }
|
||||
//! }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! This will in itself just emit the log messages, **but unless if captured by a logger, they will
|
||||
//! not go anywhere**. [`sp_api`] provides a handy function to enable the runtime logging:
|
||||
//! not go anywhere**. [`pezsp_api`] provides a handy function to enable the runtime logging:
|
||||
//!
|
||||
//! ```
|
||||
//! // in your test
|
||||
//! fn it_also_prints() {
|
||||
//! sp_api::init_runtime_logger();
|
||||
//! // call into your pallet, and now it will print `log` statements.
|
||||
//! pezsp_api::init_runtime_logger();
|
||||
//! // call into your pezpallet, and now it will print `log` statements.
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Alternatively, you can use [`sp_tracing::try_init_simple`].
|
||||
//! Alternatively, you can use [`pezsp_tracing::try_init_simple`].
|
||||
//!
|
||||
//! `info`, `error` and `warn` logs are printed by default, but if you want lower level logs to also
|
||||
//! be printed, you must to add the following compiler flag:
|
||||
//!
|
||||
//! ```text
|
||||
//! RUST_LOG=pallet-example=trace cargo test
|
||||
//! RUST_LOG=pezpallet-example=trace cargo test
|
||||
//! ```
|
||||
//!
|
||||
//! ## Enabling Logs in Production
|
||||
//!
|
||||
//! All logs from the runtime are emitted by default, but there is a feature flag in [`sp_api`],
|
||||
//! All logs from the runtime are emitted by default, but there is a feature flag in [`pezsp_api`],
|
||||
//! called `disable-logging`, that can be used to disable all logs in the runtime. This is useful
|
||||
//! for production chains to reduce the size and overhead of the wasm runtime.
|
||||
#![doc = docify::embed!("../../substrate/primitives/api/src/lib.rs", init_runtime_logger)]
|
||||
#![doc = docify::embed!("../../bizinikiwi/primitives/api/src/lib.rs", init_runtime_logger)]
|
||||
//!
|
||||
//! Similar to the above, the proper `RUST_LOG` must also be passed to your compiler flag when
|
||||
//! compiling the runtime.
|
||||
@@ -107,7 +107,7 @@
|
||||
//! ## Log Target Prefixing
|
||||
//!
|
||||
//! Many [`crate::pezkuwi_sdk::frame_runtime`] pallets emit logs with log target `runtime::<name of
|
||||
//! pallet>`, for example `runtime::system`. This then allows one to run a node with a wasm blob
|
||||
//! pezpallet>`, for example `runtime::system`. This then allows one to run a node with a wasm blob
|
||||
//! compiled with `LOG_TARGET=runtime=debug`, which enables the log target of all pallets who's log
|
||||
//! target starts with `runtime`.
|
||||
//!
|
||||
@@ -115,8 +115,8 @@
|
||||
//!
|
||||
//! Under the hood, logging is another instance of host functions under the hood (as defined in
|
||||
//! [`crate::reference_docs::wasm_meta_protocol`]). The runtime uses a set of host functions under
|
||||
//! [`sp_io::logging`] and [`sp_io::misc`] to emit all logs and prints. You typically do not need to
|
||||
//! use these APIs directly.
|
||||
//! [`pezsp_io::logging`] and [`pezsp_io::misc`] to emit all logs and prints. You typically do not
|
||||
//! need to use these APIs directly.
|
||||
//!
|
||||
//! ## Using Logging in Production
|
||||
//!
|
||||
@@ -124,12 +124,12 @@
|
||||
//! and can lead to consensus issues. This is because with the introduction of
|
||||
//! [`crate::guides::enable_pov_reclaim`], the node side code will track the storage changes, and
|
||||
//! tries to update the onchain record of the `proof_size` weight used (stored in
|
||||
//! [`frame_system::BlockWeight`]) after the block is executed.
|
||||
//! [`pezframe_system::BlockWeight`]) after the block is executed.
|
||||
//!
|
||||
//! If one node has a different log level enabled than the rest of the network, and the extra logs
|
||||
//! impose additional storage reads, then the amount of `proof_size` weight reclaimed into
|
||||
//! [`frame_system::BlockWeight`] will be different, causing a state root mismatch, which is
|
||||
//! typically a fatal error emitted from [`frame_executive`].
|
||||
//! [`pezframe_system::BlockWeight`] will be different, causing a state root mismatch, which is
|
||||
//! typically a fatal error emitted from [`pezframe_executive`].
|
||||
//!
|
||||
//! This also can also happen in a teyrchain context, and cause discrepancies between the relay
|
||||
//! chain and the teyrchain, when execution the Teyrchain Validation Function (PVF) on the relay
|
||||
@@ -151,5 +151,5 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Please read [this issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/155) for one
|
||||
//! Please read [this issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/298) for one
|
||||
//! instance of the consensus issues caused by this mistake.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//! # Offchain Workers
|
||||
//!
|
||||
//! This reference document explains how offchain workers work in Substrate and FRAME. The main
|
||||
//! This reference document explains how offchain workers work in Bizinikiwi and FRAME. The main
|
||||
//! focus is upon FRAME's implementation of this functionality. Nonetheless, offchain workers are a
|
||||
//! Substrate-provided feature and can be used with possible alternatives to [`frame`] as well.
|
||||
//! Bizinikiwi-provided feature and can be used with possible alternatives to [`frame`] as well.
|
||||
//!
|
||||
//! Offchain workers are a commonly misunderstood topic, therefore we explain them bottom-up,
|
||||
//! starting at the fundamentals and then describing the developer interface.
|
||||
@@ -11,11 +11,11 @@
|
||||
//!
|
||||
//! Recall from [`crate::reference_docs::wasm_meta_protocol`] that the node and the runtime
|
||||
//! communicate with one another via host functions and runtime APIs. Many of these interactions
|
||||
//! contribute to the actual state transition of the blockchain. For example [`sp_api::Core`] is the
|
||||
//! main runtime API that is called to execute new blocks.
|
||||
//! contribute to the actual state transition of the blockchain. For example [`pezsp_api::Core`] is
|
||||
//! the main runtime API that is called to execute new blocks.
|
||||
//!
|
||||
//! Offchain workers are in principle not different in any way: It is a runtime API exposed by the
|
||||
//! wasm blob ([`sp_offchain::OffchainWorkerApi`]), and the node software calls into it when it
|
||||
//! wasm blob ([`pezsp_offchain::OffchainWorkerApi`]), and the node software calls into it when it
|
||||
//! deems fit. But, crucially, this API call is different in that:
|
||||
//!
|
||||
//! 1. It can have no impact on the state ie. it is _OFF (the) CHAIN_. If any state is altered
|
||||
@@ -25,7 +25,7 @@
|
||||
//!
|
||||
//! > The main way through which an offchain worker can interact with the state is by submitting an
|
||||
//! > extrinsic to the chain. This is the ONLY way to alter the state from an offchain worker.
|
||||
//! > [`pallet_example_offchain_worker`] provides an example of this.
|
||||
//! > [`pezpallet_example_offchain_worker`] provides an example of this.
|
||||
//!
|
||||
//!
|
||||
//! Given the "Off Chain" nature of this API, it is important to remember that calling this API is
|
||||
@@ -33,16 +33,16 @@
|
||||
//! the execution of your blockchain because no state is altered no matter the execution of the
|
||||
//! offchain worker API.
|
||||
//!
|
||||
//! Substrate's CLI allows some degree of configuration about this, allowing node operators to
|
||||
//! Bizinikiwi's CLI allows some degree of configuration about this, allowing node operators to
|
||||
//! specify when they want to run the offchain worker API. See
|
||||
//! [`sc_cli::RunCmd::offchain_worker_params`].
|
||||
//! [`pezsc_cli::RunCmd::offchain_worker_params`].
|
||||
//!
|
||||
//! ## Nondeterministic Execution
|
||||
//!
|
||||
//! Needless to say, given the above description, the code in your offchain worker API can be
|
||||
//! nondeterministic, as it is not part of the blockchain's STF, so it can be executed at unknown
|
||||
//! times, by unknown nodes, and has no impact on the state. This is why an HTTP
|
||||
//! ([`sp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because
|
||||
//! ([`pezsp_runtime::offchain::http`]) API is readily provided to the offchain worker APIs. Because
|
||||
//! there is no need for determinism in this context.
|
||||
//!
|
||||
//! > A common mistake here is for novice developers to see this HTTP API, and imagine that
|
||||
@@ -54,22 +54,22 @@
|
||||
//! ## FRAME's API
|
||||
//!
|
||||
//! [`frame`] provides a simple API through which pallets can define offchain worker functions. This
|
||||
//! is part of [`frame::traits::Hooks`], which is implemented as a part of
|
||||
//! [`frame::pallet_macros::hooks`].
|
||||
//! is part of [`pezframe::traits::Hooks`], which is implemented as a part of
|
||||
//! [`pezframe::pezpallet_macros::hooks`].
|
||||
//!
|
||||
//! ```
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! use frame::prelude::*;
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! use pezframe::prelude::*;
|
||||
//!
|
||||
//! #[pallet::config]
|
||||
//! pub trait Config: frame_system::Config {}
|
||||
//! #[pezpallet::config]
|
||||
//! pub trait Config: pezframe_system::Config {}
|
||||
//!
|
||||
//! #[pallet::pallet]
|
||||
//! pub struct Pallet<T>(_);
|
||||
//! #[pezpallet::pezpallet]
|
||||
//! pub struct Pezpallet<T>(_);
|
||||
//!
|
||||
//! #[pallet::hooks]
|
||||
//! impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
//! #[pezpallet::hooks]
|
||||
//! impl<T: Config> Hooks<BlockNumberFor<T>> for Pezpallet<T> {
|
||||
//! fn offchain_worker(block_number: BlockNumberFor<T>) {
|
||||
//! // ...
|
||||
//! }
|
||||
@@ -77,10 +77,10 @@
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Additionally, [`sp_runtime::offchain`] provides a set of utilities that can be used to moderate
|
||||
//! the execution of offchain workers.
|
||||
//! Additionally, [`pezsp_runtime::offchain`] provides a set of utilities that can be used to
|
||||
//! moderate the execution of offchain workers.
|
||||
//!
|
||||
//! ## Think Twice: Why Use Substrate's Offchain Workers?
|
||||
//! ## Think Twice: Why Use Bizinikiwi's Offchain Workers?
|
||||
//!
|
||||
//! Consider the fact that in principle, an offchain worker code written using the above API is no
|
||||
//! different than an equivalent written with an _actual offchain interaction library_, such as
|
||||
@@ -88,16 +88,16 @@
|
||||
//!
|
||||
//! They can both read from the state, and have no means of updating the state, other than the route
|
||||
//! of submitting an extrinsic to the chain. Therefore, it is worth thinking twice before embedding
|
||||
//! a logic as a part of Substrate's offchain worker API. Does it have to be there? Can it not be a
|
||||
//! a logic as a part of Bizinikiwi's offchain worker API. Does it have to be there? Can it not be a
|
||||
//! simple, actual offchain application that lives outside of the chain's WASM blob?
|
||||
//!
|
||||
//! Some of the reasons why you might want to do the opposite, and actually embed an offchain worker
|
||||
//! API into the WASM blob are:
|
||||
//!
|
||||
//! * Accessing the state is easier within the `offchain_worker` function, as it is already a part
|
||||
//! of the runtime, and [`frame::pallet_macros::storage`] provides all the tools needed to read
|
||||
//! of the runtime, and [`pezframe::pezpallet_macros::storage`] provides all the tools needed to read
|
||||
//! the state. Other client libraries might provide varying degrees of capability here.
|
||||
//! * It will be updated in synchrony with the runtime. A Substrate's offchain application is part
|
||||
//! * It will be updated in synchrony with the runtime. A Bizinikiwi's offchain application is part
|
||||
//! of the same WASM blob, and is therefore guaranteed to be up to date.
|
||||
//!
|
||||
//! For example, imagine you have modified a storage item to have a new type. This will possibly
|
||||
@@ -111,4 +111,4 @@
|
||||
//!
|
||||
//! - <https://forum.polkadot.network/t/offchain-workers-design-assumptions-vulnerabilities/2548>
|
||||
//! - <https://exchange.pezkuwichain.app/questions/11058/how-can-i-create-ocw-that-wont-activates-every-block-but-will-activates-only-w/11060#11060>
|
||||
//! - [Offchain worker example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/substrate/frame/examples/offchain-worker)
|
||||
//! - [Offchain worker example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/master/bizinikiwi/pezframe/examples/offchain-worker)
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
//!
|
||||
//! FRAME's origin abstractions allow you to convey meanings far beyond just an account-id being the
|
||||
//! caller of an extrinsic. Nonetheless, an account-id having signed an extrinsic is one of the
|
||||
//! meanings that an origin can convey. This is the commonly used [`frame_system::ensure_signed`],
|
||||
//! where the return value happens to be an account-id.
|
||||
//! meanings that an origin can convey. This is the commonly used
|
||||
//! [`pezframe_system::ensure_signed`], where the return value happens to be an account-id.
|
||||
//!
|
||||
//! Instead, let's establish the following as the correct definition of an origin:
|
||||
//!
|
||||
@@ -21,8 +21,8 @@
|
||||
//! example:
|
||||
//!
|
||||
//! * If the majority of token holders agreed upon this. This is more or less what the
|
||||
//! [`pallet_democracy`] does under the hood ([reference](https://github.com/pezkuwichain/pezkuwi-sdk/blob/edd95b3749754d2ed0c5738588e872c87be91624/substrate/frame/democracy/src/lib.rs#L1603-L1633)).
|
||||
//! * If a specific ratio of an instance of [`pallet_collective`]/DAO agrees upon this.
|
||||
//! [`pezpallet_democracy`] does under the hood ([reference](https://github.com/pezkuwichain/pezkuwi-sdk/blob/edd95b3749754d2ed0c5738588e872c87be91624/bizinikiwi/pezframe/democracy/src/lib.rs#L1603-L1633)).
|
||||
//! * If a specific ratio of an instance of [`pezpallet_collective`]/DAO agrees upon this.
|
||||
//! * If another consensus system, for example a bridged network or a teyrchain, agrees upon this.
|
||||
//! * If the majority of validator/authority set agrees upon this[^1].
|
||||
//! * If caller holds a particular NFT.
|
||||
@@ -31,88 +31,89 @@
|
||||
//!
|
||||
//! ## Context
|
||||
//!
|
||||
//! First, let's look at where the `origin` type is encountered in a typical pallet. The `origin:
|
||||
//! First, let's look at where the `origin` type is encountered in a typical pezpallet. The `origin:
|
||||
//! OriginFor<T>` has to be the first argument of any given callable extrinsic in FRAME:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", call_simple)]
|
||||
//!
|
||||
//! Typically, the code of an extrinsic starts with an origin check, such as
|
||||
//! [`frame_system::ensure_signed`].
|
||||
//! [`pezframe_system::ensure_signed`].
|
||||
//!
|
||||
//! Note that [`OriginFor`](frame_system::pallet_prelude::OriginFor) is merely a shorthand for
|
||||
//! [`frame_system::Config::RuntimeOrigin`]. Given the name prefix `Runtime`, we can learn that
|
||||
//! Note that [`OriginFor`](pezframe_system::pezpallet_prelude::OriginFor) is merely a shorthand for
|
||||
//! [`pezframe_system::Config::RuntimeOrigin`]. Given the name prefix `Runtime`, we can learn that
|
||||
//! `RuntimeOrigin` is similar to `RuntimeCall` and others, a runtime composite enum that is
|
||||
//! amalgamated at the runtime level. Read [`crate::reference_docs::frame_runtime_types`] to
|
||||
//! familiarize yourself with these types.
|
||||
//!
|
||||
//! To understand this better, we will next create a pallet with a custom origin, which will add a
|
||||
//! new variant to `RuntimeOrigin`.
|
||||
//! To understand this better, we will next create a pezpallet with a custom origin, which will add
|
||||
//! a new variant to `RuntimeOrigin`.
|
||||
//!
|
||||
//! ## Adding Custom Pallet Origin to the Runtime
|
||||
//! ## Adding Custom Pezpallet Origin to the Runtime
|
||||
//!
|
||||
//! For example, given a pallet that defines the following custom origin:
|
||||
//! For example, given a pezpallet that defines the following custom origin:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin)]
|
||||
//!
|
||||
//! And a runtime with the following pallets:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", runtime_exp)]
|
||||
//!
|
||||
//! The type [`crate::reference_docs::frame_origin::runtime_for_origin::RuntimeOrigin`] is expanded.
|
||||
//! This `RuntimeOrigin` contains a variant for the [`frame_system::RawOrigin`] and the custom
|
||||
//! origin of the pallet.
|
||||
//! This `RuntimeOrigin` contains a variant for the [`pezframe_system::RawOrigin`] and the custom
|
||||
//! origin of the pezpallet.
|
||||
//!
|
||||
//! > Notice how the [`frame_system::ensure_signed`] is nothing more than a `match` statement. If
|
||||
//! > Notice how the [`pezframe_system::ensure_signed`] is nothing more than a `match` statement. If
|
||||
//! > you want to know where the actual origin of an extrinsic is set (and the signature
|
||||
//! > verification happens, if any), see
|
||||
//! > [`sp_runtime::generic::CheckedExtrinsic#trait-implementations`], specifically
|
||||
//! > [`sp_runtime::traits::Applyable`]'s implementation.
|
||||
//! > [`pezsp_runtime::generic::CheckedExtrinsic#trait-implementations`], specifically
|
||||
//! > [`pezsp_runtime::traits::Applyable`]'s implementation.
|
||||
//!
|
||||
//! ## Asserting on a Custom Internal Origin
|
||||
//!
|
||||
//! In order to assert on a custom origin that is defined within your pallet, we need a way to first
|
||||
//! convert the `<T as frame_system::Config>::RuntimeOrigin` into the local `enum Origin` of the
|
||||
//! current pallet. This is a common process that is explained in
|
||||
//! In order to assert on a custom origin that is defined within your pezpallet, we need a way to
|
||||
//! first convert the `<T as pezframe_system::Config>::RuntimeOrigin` into the local `enum Origin`
|
||||
//! of the current pezpallet. This is a common process that is explained in
|
||||
//! [`crate::reference_docs::frame_runtime_types#
|
||||
//! adding-further-constraints-to-runtime-composite-enums`].
|
||||
//!
|
||||
//! We use the same process here to express that `RuntimeOrigin` has a number of additional bounds,
|
||||
//! as follows.
|
||||
//!
|
||||
//! 1. Defining a custom `RuntimeOrigin` with further bounds in the pallet.
|
||||
//! 1. Defining a custom `RuntimeOrigin` with further bounds in the pezpallet.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin_bound)]
|
||||
//!
|
||||
//! 2. Using it in the pallet.
|
||||
//! 2. Using it in the pezpallet.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", custom_origin_usage)]
|
||||
//!
|
||||
//! ## Asserting on a Custom External Origin
|
||||
//!
|
||||
//! Very often, a pallet wants to have a parameterized origin that is **NOT** defined within the
|
||||
//! pallet. In other words, a pallet wants to delegate an origin check to something that is
|
||||
//! Very often, a pezpallet wants to have a parameterized origin that is **NOT** defined within the
|
||||
//! pezpallet. In other words, a pezpallet wants to delegate an origin check to something that is
|
||||
//! specified later at the runtime level. Like many other parameterizations in FRAME, this implies
|
||||
//! adding a new associated type to `trait Config`.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_def)]
|
||||
//!
|
||||
//! Then, within the pallet, we can simply use this "unknown" origin check type:
|
||||
//! Then, within the pezpallet, we can simply use this "unknown" origin check type:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_usage)]
|
||||
//!
|
||||
//! Finally, at the runtime, any implementation of [`frame::traits::EnsureOrigin`] can be passed.
|
||||
//! Finally, at the runtime, any implementation of [`pezframe::traits::EnsureOrigin`] can be passed.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_origin.rs", external_origin_provide)]
|
||||
//!
|
||||
//! Indeed, some of these implementations of [`frame::traits::EnsureOrigin`] are similar to the ones
|
||||
//! that we know about: [`frame::runtime::prelude::EnsureSigned`],
|
||||
//! [`frame::runtime::prelude::EnsureSignedBy`], [`frame::runtime::prelude::EnsureRoot`],
|
||||
//! [`frame::runtime::prelude::EnsureNone`], etc. But, there are also many more that are not known
|
||||
//! Indeed, some of these implementations of [`pezframe::traits::EnsureOrigin`] are similar to the ones
|
||||
//! that we know about: [`pezframe::runtime::prelude::EnsureSigned`],
|
||||
//! [`pezframe::runtime::prelude::EnsureSignedBy`], [`pezframe::runtime::prelude::EnsureRoot`],
|
||||
//! [`pezframe::runtime::prelude::EnsureNone`], etc. But, there are also many more that are not known
|
||||
//! to us, and are defined in other pallets.
|
||||
//!
|
||||
//! For example, [`pallet_collective`] defines [`pallet_collective::EnsureMember`] and
|
||||
//! [`pallet_collective::EnsureProportionMoreThan`] and many more, which is exactly what we alluded
|
||||
//! to earlier in this document.
|
||||
//! For example, [`pezpallet_collective`] defines [`pezpallet_collective::EnsureMember`] and
|
||||
//! [`pezpallet_collective::EnsureProportionMoreThan`] and many more, which is exactly what we
|
||||
//! alluded to earlier in this document.
|
||||
//!
|
||||
//! Make sure to check the full list of [implementors of
|
||||
//! `EnsureOrigin`](frame::traits::EnsureOrigin#implementors) for more inspiration.
|
||||
//! `EnsureOrigin`](pezframe::traits::EnsureOrigin#implementors) for more inspiration.
|
||||
//!
|
||||
//! ## Obtaining Abstract Origins
|
||||
//!
|
||||
//! So far we have learned that FRAME pallets can assert on custom and abstract origin types,
|
||||
//! whether they are defined within the pallet or not. But how can we obtain these abstract origins?
|
||||
//! whether they are defined within the pezpallet or not. But how can we obtain these abstract
|
||||
//! origins?
|
||||
//!
|
||||
//! > All extrinsics that come from the outer world can generally only be obtained as either
|
||||
//! > `signed` or `none` origin.
|
||||
@@ -125,24 +126,24 @@
|
||||
//! - [Gavin Wood's speech about FRAME features at Protocol Berg 2023.](https://youtu.be/j7b8Upipmeg?si=83_XUgYuJxMwWX4g&t=195)
|
||||
//! - [A related StackExchange question.](https://exchange.pezkuwichain.app/questions/10992/how-do-you-find-the-public-key-for-the-medium-spender-track-origin)
|
||||
//!
|
||||
//! [^1]: Inherents are essentially unsigned extrinsics that need an [`frame_system::ensure_none`]
|
||||
//! [^1]: Inherents are essentially unsigned extrinsics that need an [`pezframe_system::ensure_none`]
|
||||
//! origin check, and through the virtue of being an inherent, are agreed upon by all validators.
|
||||
|
||||
use frame::prelude::*;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_for_origin {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_for_origin {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(call_simple)]
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn do_something(_origin: OriginFor<T>) -> DispatchResult {
|
||||
// ^^^^^^^^^^^^^^^^^^^^^
|
||||
todo!();
|
||||
@@ -150,23 +151,23 @@ pub mod pallet_for_origin {
|
||||
}
|
||||
}
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_with_custom_origin {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_with_custom_origin {
|
||||
use super::*;
|
||||
|
||||
#[docify::export(custom_origin_bound)]
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
type RuntimeOrigin: From<<Self as frame_system::Config>::RuntimeOrigin>
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
type RuntimeOrigin: From<<Self as pezframe_system::Config>::RuntimeOrigin>
|
||||
+ Into<Result<Origin, <Self as Config>::RuntimeOrigin>>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(custom_origin)]
|
||||
/// A dummy custom origin.
|
||||
#[pallet::origin]
|
||||
#[pezpallet::origin]
|
||||
#[derive(
|
||||
PartialEq,
|
||||
Eq,
|
||||
@@ -186,13 +187,13 @@ pub mod pallet_with_custom_origin {
|
||||
}
|
||||
|
||||
#[docify::export(custom_origin_usage)]
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn only_validators(origin: OriginFor<T>) -> DispatchResult {
|
||||
// first, we convert from `<T as frame_system::Config>::RuntimeOrigin` to `<T as
|
||||
// first, we convert from `<T as pezframe_system::Config>::RuntimeOrigin` to `<T as
|
||||
// Config>::RuntimeOrigin`
|
||||
let local_runtime_origin = <<T as Config>::RuntimeOrigin as From<
|
||||
<T as frame_system::Config>::RuntimeOrigin,
|
||||
<T as pezframe_system::Config>::RuntimeOrigin,
|
||||
>>::from(origin);
|
||||
// then we convert to `origin`, if possible
|
||||
let local_origin =
|
||||
@@ -204,42 +205,42 @@ pub mod pallet_with_custom_origin {
|
||||
}
|
||||
|
||||
pub mod runtime_for_origin {
|
||||
use super::pallet_with_custom_origin;
|
||||
use frame::{runtime::prelude::*, testing_prelude::*};
|
||||
use super::pezpallet_with_custom_origin;
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
#[docify::export(runtime_exp)]
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: frame_system,
|
||||
PalletWithCustomOrigin: pallet_with_custom_origin,
|
||||
System: pezframe_system,
|
||||
PalletWithCustomOrigin: pezpallet_with_custom_origin,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
impl pallet_with_custom_origin::Config for Runtime {
|
||||
impl pezpallet_with_custom_origin::Config for Runtime {
|
||||
type RuntimeOrigin = RuntimeOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_with_external_origin {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_with_external_origin {
|
||||
use super::*;
|
||||
#[docify::export(external_origin_def)]
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
type ExternalOrigin: EnsureOrigin<Self::RuntimeOrigin>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(external_origin_usage)]
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn externally_checked_ext(origin: OriginFor<T>) -> DispatchResult {
|
||||
T::ExternalOrigin::ensure_origin(origin)?;
|
||||
todo!();
|
||||
@@ -249,22 +250,22 @@ pub mod pallet_with_external_origin {
|
||||
|
||||
pub mod runtime_for_external_origin {
|
||||
use super::*;
|
||||
use frame::{runtime::prelude::*, testing_prelude::*};
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: frame_system,
|
||||
PalletWithExternalOrigin: pallet_with_external_origin,
|
||||
System: pezframe_system,
|
||||
PalletWithExternalOrigin: pezpallet_with_external_origin,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
#[docify::export(external_origin_provide)]
|
||||
impl pallet_with_external_origin::Config for Runtime {
|
||||
type ExternalOrigin = EnsureSigned<<Self as frame_system::Config>::AccountId>;
|
||||
impl pezpallet_with_external_origin::Config for Runtime {
|
||||
type ExternalOrigin = EnsureSigned<<Self as pezframe_system::Config>::AccountId>;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
//! # FRAME Pallet Coupling
|
||||
//! # FRAME Pezpallet Coupling
|
||||
//!
|
||||
//! This reference document explains how FRAME pallets can be combined to interact together.
|
||||
//!
|
||||
//! It is suggested to re-read [`crate::pezkuwi_sdk::frame_runtime`], notably the information
|
||||
//! around [`frame::pallet_macros::config`]. Recall that:
|
||||
//! around [`pezframe::pezpallet_macros::config`]. Recall that:
|
||||
//!
|
||||
//! > Configuration trait of a pallet: It allows a pallet to receive types at a later
|
||||
//! > point from the runtime that wishes to contain it. It allows the pallet to be parameterized
|
||||
//! > Configuration trait of a pezpallet: It allows a pezpallet to receive types at a later
|
||||
//! > point from the runtime that wishes to contain it. It allows the pezpallet to be parameterized
|
||||
//! > over both types and values.
|
||||
//!
|
||||
//! ## Context, Background
|
||||
//!
|
||||
//! FRAME pallets, as per described in [`crate::pezkuwi_sdk::frame_runtime`] are:
|
||||
//!
|
||||
//! > A pallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
//! > A pezpallet is a unit of encapsulated logic. It has a clearly defined responsibility and can
|
||||
//! > be
|
||||
//! linked to other pallets.
|
||||
//!
|
||||
//! That is to say:
|
||||
//!
|
||||
//! * *encapsulated*: Ideally, a FRAME pallet contains encapsulated logic which has clear
|
||||
//! boundaries. It is generally a bad idea to build a single monolithic pallet that does multiple
|
||||
//! things, such as handling currencies, identities and staking all at the same time.
|
||||
//! * *encapsulated*: Ideally, a FRAME pezpallet contains encapsulated logic which has clear
|
||||
//! boundaries. It is generally a bad idea to build a single monolithic pezpallet that does
|
||||
//! multiple things, such as handling currencies, identities and staking all at the same time.
|
||||
//! * *linked to other pallets*: But, adhering extensively to the above also hinders the ability to
|
||||
//! write useful applications. Pallets often need to work with each other, communicate and use
|
||||
//! each other's functionalities.
|
||||
//!
|
||||
//! The broad principle that allows pallets to be linked together is the same way through which a
|
||||
//! pallet uses its `Config` trait to receive types and values from the runtime that contains it.
|
||||
//! pezpallet uses its `Config` trait to receive types and values from the runtime that contains it.
|
||||
//!
|
||||
//! There are generally two ways to achieve this:
|
||||
//!
|
||||
@@ -63,52 +64,52 @@
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! Consider the following example, in which `pallet-foo` needs another pallet to provide the block
|
||||
//! author to it, and `pallet-author` which has access to this information.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_foo)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author)]
|
||||
//! Consider the following example, in which `pezpallet-foo` needs another pezpallet to provide the
|
||||
//! block author to it, and `pezpallet-author` which has access to this information.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pezpallet_foo)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pezpallet_author)]
|
||||
//!
|
||||
//! ### Tight Coupling Pallets
|
||||
//!
|
||||
//! To tightly couple `pallet-foo` and `pallet-author`, we use Rust's supertrait system. When a
|
||||
//! pallet makes its own `trait Config` be bounded by another pallet's `trait Config`, it is
|
||||
//! To tightly couple `pezpallet-foo` and `pezpallet-author`, we use Rust's supertrait system. When
|
||||
//! a pezpallet makes its own `trait Config` be bounded by another pezpallet's `trait Config`, it is
|
||||
//! expressing two things:
|
||||
//!
|
||||
//! 1. That it can only exist in a runtime if the other pallet is also present.
|
||||
//! 2. That it can use the other pallet's functionality.
|
||||
//! 1. That it can only exist in a runtime if the other pezpallet is also present.
|
||||
//! 2. That it can use the other pezpallet's functionality.
|
||||
//!
|
||||
//! `pallet-foo`'s `Config` would then look like:
|
||||
//! `pezpallet-foo`'s `Config` would then look like:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_config)]
|
||||
//!
|
||||
//! And `pallet-foo` can use the method exposed by `pallet_author::Pallet` directly:
|
||||
//! And `pezpallet-foo` can use the method exposed by `pezpallet_author::Pezpallet` directly:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", tight_usage)]
|
||||
//!
|
||||
//!
|
||||
//! ### Loosely Coupling Pallets
|
||||
//!
|
||||
//! If `pallet-foo` wants to *not* rely on `pallet-author` directly, it can leverage its
|
||||
//! If `pezpallet-foo` wants to *not* rely on `pezpallet-author` directly, it can leverage its
|
||||
//! `Config`'s associated types. First, we need a trait to express the functionality that
|
||||
//! `pallet-foo` wants to obtain:
|
||||
//! `pezpallet-foo` wants to obtain:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", AuthorProvider)]
|
||||
//!
|
||||
//! > We sometimes refer to such traits that help two pallets interact as "glue traits".
|
||||
//!
|
||||
//! Next, `pallet-foo` states that it needs this trait to be provided to it, at the runtime level,
|
||||
//! via an associated type:
|
||||
//! Next, `pezpallet-foo` states that it needs this trait to be provided to it, at the runtime
|
||||
//! level, via an associated type:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_config)]
|
||||
//!
|
||||
//! Then, `pallet-foo` can use this trait to obtain the block author, without knowing where it comes
|
||||
//! from:
|
||||
//! Then, `pezpallet-foo` can use this trait to obtain the block author, without knowing where it
|
||||
//! comes from:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", loose_usage)]
|
||||
//!
|
||||
//! Then, if `pallet-author` implements this glue-trait:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pallet_author_provider)]
|
||||
//! Then, if `pezpallet-author` implements this glue-trait:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", pezpallet_author_provider)]
|
||||
//!
|
||||
//! And upon the creation of the runtime, the two pallets are linked together as such:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pallet_coupling.rs", runtime_author_provider)]
|
||||
//!
|
||||
//! Crucially, when using loose coupling, we gain the flexibility of providing different
|
||||
//! implementations of `AuthorProvider`, such that different users of a `pallet-foo` can use
|
||||
//! implementations of `AuthorProvider`, such that different users of a `pezpallet-foo` can use
|
||||
//! different ones, without any code change being needed. For example, in the code snippets of this
|
||||
//! module, you can find [`OtherAuthorProvider`], which is an alternative implementation of
|
||||
//! [`AuthorProvider`].
|
||||
@@ -120,11 +121,11 @@
|
||||
//!
|
||||
//! ## Frame System
|
||||
//!
|
||||
//! With the above information in context, we can conclude that **`frame_system` is a special pallet
|
||||
//! that is tightly coupled with every other pallet**. This is because it provides the fundamental
|
||||
//! system functionality that every pallet needs, such as some types like
|
||||
//! [`frame::prelude::frame_system::Config::AccountId`],
|
||||
//! [`frame::prelude::frame_system::Config::Hash`], and some functionality such as block number,
|
||||
//! With the above information in context, we can conclude that **`pezframe_system` is a special
|
||||
//! pezpallet that is tightly coupled with every other pezpallet**. This is because it provides the
|
||||
//! fundamental system functionality that every pezpallet needs, such as some types like
|
||||
//! [`pezframe::prelude::pezframe_system::Config::AccountId`],
|
||||
//! [`pezframe::prelude::pezframe_system::Config::Hash`], and some functionality such as block number,
|
||||
//! etc.
|
||||
//!
|
||||
//! ## Recap
|
||||
@@ -132,43 +133,44 @@
|
||||
//! To recap, consider the following rules of thumb:
|
||||
//!
|
||||
//! * In all cases, try and break down big pallets apart with clear boundaries of responsibility. In
|
||||
//! general, it is easier to argue about multiple pallet if they only communicate together via a
|
||||
//! known trait, rather than having access to all of each others public items, such as storage and
|
||||
//! dispatchables.
|
||||
//! general, it is easier to argue about multiple pezpallet if they only communicate together via
|
||||
//! a known trait, rather than having access to all of each others public items, such as storage
|
||||
//! and dispatchables.
|
||||
//! * If a group of pallets is meant to work together, but is not foreseen to be generalized, or
|
||||
//! used by others, consider tightly coupling pallets, *if it simplifies the development*.
|
||||
//! * If a pallet needs a functionality provided by another pallet, but multiple implementations can
|
||||
//! be foreseen, consider loosely coupling pallets.
|
||||
//! * If a pezpallet needs a functionality provided by another pezpallet, but multiple
|
||||
//! implementations can be foreseen, consider loosely coupling pallets.
|
||||
//!
|
||||
//! For example, all pallets in `pezkuwi-sdk` that needed to work with currencies could have been
|
||||
//! tightly coupled with [`pallet_balances`]. But, `pezkuwi-sdk` also provides [`pallet_assets`]
|
||||
//! (and more implementations by the community), therefore all pallets use traits to loosely couple
|
||||
//! with balances or assets pallet. More on this in [`crate::reference_docs::frame_tokens`].
|
||||
//! tightly coupled with [`pezpallet_balances`]. But, `pezkuwi-sdk` also provides
|
||||
//! [`pezpallet_assets`] (and more implementations by the community), therefore all pallets use
|
||||
//! traits to loosely couple with balances or assets pezpallet. More on this in
|
||||
//! [`crate::reference_docs::frame_tokens`].
|
||||
//!
|
||||
//! ## Further References
|
||||
//!
|
||||
//! - <https://www.youtube.com/watch?v=0eNGZpNkJk4>
|
||||
//! - <https://exchange.pezkuwichain.app/questions/922/pallet-loose-couplingtight-coupling-and-missing-traits>
|
||||
//! - <https://exchange.pezkuwichain.app/questions/922/pezpallet-loose-couplingtight-coupling-and-missing-traits>
|
||||
//!
|
||||
//! [`AuthorProvider`]: crate::reference_docs::frame_pallet_coupling::AuthorProvider
|
||||
//! [`OtherAuthorProvider`]: crate::reference_docs::frame_pallet_coupling::OtherAuthorProvider
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
use frame::prelude::*;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet]
|
||||
pub mod pallet_foo {
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn do_stuff_with_author() {
|
||||
// needs block author here
|
||||
}
|
||||
@@ -176,41 +178,42 @@ pub mod pallet_foo {
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet]
|
||||
pub mod pallet_author {
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_author {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
impl<T: Config> Pallet<T> {
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn author() -> T::AccountId {
|
||||
todo!("somehow has access to the block author and can return it here")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[frame::pallet]
|
||||
pub mod pallet_foo_tight {
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo_tight {
|
||||
use super::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(tight_config)]
|
||||
/// This pallet can only live in a runtime that has both `frame_system` and `pallet_author`.
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config + pallet_author::Config {}
|
||||
/// This pezpallet can only live in a runtime that has both `pezframe_system` and
|
||||
/// `pezpallet_author`.
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config + pezpallet_author::Config {}
|
||||
|
||||
#[docify::export(tight_usage)]
|
||||
impl<T: Config> Pallet<T> {
|
||||
// anywhere in `pallet-foo`, we can call into `pallet-author` directly, namely because
|
||||
// `T: pallet_author::Config`
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
// anywhere in `pezpallet-foo`, we can call into `pezpallet-author` directly, namely because
|
||||
// `T: pezpallet_author::Config`
|
||||
fn do_stuff_with_author() {
|
||||
let _ = pallet_author::Pallet::<T>::author();
|
||||
let _ = pezpallet_author::Pezpallet::<T>::author();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,33 +224,33 @@ pub trait AuthorProvider<AccountId> {
|
||||
fn author() -> AccountId;
|
||||
}
|
||||
|
||||
#[frame::pallet]
|
||||
pub mod pallet_foo_loose {
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo_loose {
|
||||
use super::*;
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(loose_config)]
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// This pallet relies on the existence of something that implements [`AuthorProvider`],
|
||||
/// which may or may not be `pallet-author`.
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// This pezpallet relies on the existence of something that implements [`AuthorProvider`],
|
||||
/// which may or may not be `pezpallet-author`.
|
||||
type AuthorProvider: AuthorProvider<Self::AccountId>;
|
||||
}
|
||||
|
||||
#[docify::export(loose_usage)]
|
||||
impl<T: Config> Pallet<T> {
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn do_stuff_with_author() {
|
||||
let _ = T::AuthorProvider::author();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export(pallet_author_provider)]
|
||||
impl<T: pallet_author::Config> AuthorProvider<T::AccountId> for pallet_author::Pallet<T> {
|
||||
#[docify::export(pezpallet_author_provider)]
|
||||
impl<T: pezpallet_author::Config> AuthorProvider<T::AccountId> for pezpallet_author::Pezpallet<T> {
|
||||
fn author() -> T::AccountId {
|
||||
pallet_author::Pallet::<T>::author()
|
||||
pezpallet_author::Pezpallet::<T>::author()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,27 +272,27 @@ impl<AccountId> AuthorProvider<AccountId> for () {
|
||||
|
||||
pub mod runtime {
|
||||
use super::*;
|
||||
use cumulus_pallet_aura_ext::pallet;
|
||||
use frame::{runtime::prelude::*, testing_prelude::*};
|
||||
use pezcumulus_pezpallet_aura_ext::pezpallet;
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: frame_system,
|
||||
PalletFoo: pallet_foo_loose,
|
||||
PalletAuthor: pallet_author,
|
||||
System: pezframe_system,
|
||||
PalletFoo: pezpallet_foo_loose,
|
||||
PalletAuthor: pezpallet_author,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
impl pallet_author::Config for Runtime {}
|
||||
impl pezpallet_author::Config for Runtime {}
|
||||
|
||||
#[docify::export(runtime_author_provider)]
|
||||
impl pallet_foo_loose::Config for Runtime {
|
||||
type AuthorProvider = pallet_author::Pallet<Runtime>;
|
||||
impl pezpallet_foo_loose::Config for Runtime {
|
||||
type AuthorProvider = pezpallet_author::Pezpallet<Runtime>;
|
||||
// which is also equivalent to
|
||||
// type AuthorProvider = PalletAuthor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
//! # FRAME Pezpallet Coupling
|
||||
//!
|
||||
//! This reference document explains how FRAME pezpallets can be combined to interact together.
|
||||
//!
|
||||
//! It is suggested to re-read [`crate::pezkuwi_sdk::frame_runtime`], notably the information
|
||||
//! around [`pezframe::pezpallet_macros::config`]. Recall that:
|
||||
//!
|
||||
//! > Configuration trait of a pezpallet: It allows a pezpallet to receive types at a later
|
||||
//! > point from the runtime that wishes to contain it. It allows the pezpallet to be parameterized
|
||||
//! > over both types and values.
|
||||
//!
|
||||
//! ## Context, Background
|
||||
//!
|
||||
//! FRAME pezpallets, as per described in [`crate::pezkuwi_sdk::frame_runtime`] are:
|
||||
//!
|
||||
//! > A pezpallet is a unit of encapsulated logic. It has a clearly defined responsibility and can be
|
||||
//! linked to other pezpallets.
|
||||
//!
|
||||
//! That is to say:
|
||||
//!
|
||||
//! * *encapsulated*: Ideally, a FRAME pezpallet contains encapsulated logic which has clear
|
||||
//! boundaries. It is generally a bad idea to build a single monolithic pezpallet that does multiple
|
||||
//! things, such as handling currencies, identities and staking all at the same time.
|
||||
//! * *linked to other pezpallets*: But, adhering extensively to the above also hinders the ability to
|
||||
//! write useful applications. Pezpallets often need to work with each other, communicate and use
|
||||
//! each other's functionalities.
|
||||
//!
|
||||
//! The broad principle that allows pezpallets to be linked together is the same way through which a
|
||||
//! pezpallet uses its `Config` trait to receive types and values from the runtime that contains it.
|
||||
//!
|
||||
//! There are generally two ways to achieve this:
|
||||
//!
|
||||
//! 1. Tight coupling pezpallets.
|
||||
//! 2. Loose coupling pezpallets.
|
||||
//!
|
||||
//! To explain the difference between the two, consider two pezpallets, `A` and `B`. In both cases, `A`
|
||||
//! wants to use some functionality exposed by `B`.
|
||||
//!
|
||||
//! When tightly coupling pezpallets, `A` can only exist in a runtime if `B` is also present in the
|
||||
//! same runtime. That is, `A` is expressing that can only work if `B` is present.
|
||||
//!
|
||||
//! This translates to the following Rust code:
|
||||
//!
|
||||
//! ```
|
||||
//! trait Pezpallet_B_Config {}
|
||||
//! trait Pezpallet_A_Config: Pezpallet_B_Config {}
|
||||
//! ```
|
||||
//!
|
||||
//! Contrary, when pezpallets are loosely coupled, `A` expresses that some functionality, expressed via
|
||||
//! a trait `F`, needs to be fulfilled. This trait is then implemented by `B`, and the two pezpallets
|
||||
//! are linked together at the runtime level. This means that `A` only relies on the implementation
|
||||
//! of `F`, which may be `B`, or another implementation of `F`.
|
||||
//!
|
||||
//! This translates to the following Rust code:
|
||||
//!
|
||||
//! ```
|
||||
//! trait F {}
|
||||
//! trait Pezpallet_A_Config {
|
||||
//! type F: F;
|
||||
//! }
|
||||
//! // Pezpallet_B will implement and fulfill `F`.
|
||||
//! ```
|
||||
//!
|
||||
//! ## Example
|
||||
//!
|
||||
//! Consider the following example, in which `pezpallet-foo` needs another pezpallet to provide the block
|
||||
//! author to it, and `pezpallet-author` which has access to this information.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", pezpallet_foo)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", pezpallet_author)]
|
||||
//!
|
||||
//! ### Tight Coupling Pezpallets
|
||||
//!
|
||||
//! To tightly couple `pezpallet-foo` and `pezpallet-author`, we use Rust's supertrait system. When a
|
||||
//! pezpallet makes its own `trait Config` be bounded by another pezpallet's `trait Config`, it is
|
||||
//! expressing two things:
|
||||
//!
|
||||
//! 1. That it can only exist in a runtime if the other pezpallet is also present.
|
||||
//! 2. That it can use the other pezpallet's functionality.
|
||||
//!
|
||||
//! `pezpallet-foo`'s `Config` would then look like:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", tight_config)]
|
||||
//!
|
||||
//! And `pezpallet-foo` can use the method exposed by `pezpallet_author::Pezpallet` directly:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", tight_usage)]
|
||||
//!
|
||||
//!
|
||||
//! ### Loosely Coupling Pezpallets
|
||||
//!
|
||||
//! If `pezpallet-foo` wants to *not* rely on `pezpallet-author` directly, it can leverage its
|
||||
//! `Config`'s associated types. First, we need a trait to express the functionality that
|
||||
//! `pezpallet-foo` wants to obtain:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", AuthorProvider)]
|
||||
//!
|
||||
//! > We sometimes refer to such traits that help two pezpallets interact as "glue traits".
|
||||
//!
|
||||
//! Next, `pezpallet-foo` states that it needs this trait to be provided to it, at the runtime level,
|
||||
//! via an associated type:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", loose_config)]
|
||||
//!
|
||||
//! Then, `pezpallet-foo` can use this trait to obtain the block author, without knowing where it comes
|
||||
//! from:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", loose_usage)]
|
||||
//!
|
||||
//! Then, if `pezpallet-author` implements this glue-trait:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", pezpallet_author_provider)]
|
||||
//!
|
||||
//! And upon the creation of the runtime, the two pezpallets are linked together as such:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", runtime_author_provider)]
|
||||
//!
|
||||
//! Crucially, when using loose coupling, we gain the flexibility of providing different
|
||||
//! implementations of `AuthorProvider`, such that different users of a `pezpallet-foo` can use
|
||||
//! different ones, without any code change being needed. For example, in the code snippets of this
|
||||
//! module, you can find [`OtherAuthorProvider`], which is an alternative implementation of
|
||||
//! [`AuthorProvider`].
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", other_author_provider)]
|
||||
//!
|
||||
//! A common pattern in pezkuwi-sdk is to provide an implementation of such glu traits for the unit
|
||||
//! type as a "default/test behavior".
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_pezpallet_coupling.rs", unit_author_provider)]
|
||||
//!
|
||||
//! ## Frame System
|
||||
//!
|
||||
//! With the above information in context, we can conclude that **`pezframe_system` is a special pezpallet
|
||||
//! that is tightly coupled with every other pezpallet**. This is because it provides the fundamental
|
||||
//! system functionality that every pezpallet needs, such as some types like
|
||||
//! [`pezframe::prelude::pezframe_system::Config::AccountId`],
|
||||
//! [`pezframe::prelude::pezframe_system::Config::Hash`], and some functionality such as block number,
|
||||
//! etc.
|
||||
//!
|
||||
//! ## Recap
|
||||
//!
|
||||
//! To recap, consider the following rules of thumb:
|
||||
//!
|
||||
//! * In all cases, try and break down big pezpallets apart with clear boundaries of responsibility. In
|
||||
//! general, it is easier to argue about multiple pezpallet if they only communicate together via a
|
||||
//! known trait, rather than having access to all of each others public items, such as storage and
|
||||
//! dispatchables.
|
||||
//! * If a group of pezpallets is meant to work together, but is not foreseen to be generalized, or
|
||||
//! used by others, consider tightly coupling pezpallets, *if it simplifies the development*.
|
||||
//! * If a pezpallet needs a functionality provided by another pezpallet, but multiple implementations can
|
||||
//! be foreseen, consider loosely coupling pezpallets.
|
||||
//!
|
||||
//! For example, all pezpallets in `pezkuwi-sdk` that needed to work with currencies could have been
|
||||
//! tightly coupled with [`pezpallet_balances`]. But, `pezkuwi-sdk` also provides [`pezpallet_assets`]
|
||||
//! (and more implementations by the community), therefore all pezpallets use traits to loosely couple
|
||||
//! with balances or assets pezpallet. More on this in [`crate::reference_docs::frame_tokens`].
|
||||
//!
|
||||
//! ## Further References
|
||||
//!
|
||||
//! - <https://www.youtube.com/watch?v=0eNGZpNkJk4>
|
||||
//! - <https://exchange.pezkuwichain.app/questions/922/pezpallet-loose-couplingtight-coupling-and-missing-traits>
|
||||
//!
|
||||
//! [`AuthorProvider`]: crate::reference_docs::frame_pezpallet_coupling::AuthorProvider
|
||||
//! [`OtherAuthorProvider`]: crate::reference_docs::frame_pezpallet_coupling::OtherAuthorProvider
|
||||
|
||||
#![allow(unused)]
|
||||
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo {
|
||||
use super::*;
|
||||
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn do_stuff_with_author() {
|
||||
// needs block author here
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_author {
|
||||
use super::*;
|
||||
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn author() -> T::AccountId {
|
||||
todo!("somehow has access to the block author and can return it here")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo_tight {
|
||||
use super::*;
|
||||
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(tight_config)]
|
||||
/// This pezpallet can only live in a runtime that has both `pezframe_system` and `pezpallet_author`.
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config + pezpallet_author::Config {}
|
||||
|
||||
#[docify::export(tight_usage)]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
// anywhere in `pezpallet-foo`, we can call into `pezpallet-author` directly, namely because
|
||||
// `T: pezpallet_author::Config`
|
||||
fn do_stuff_with_author() {
|
||||
let _ = pezpallet_author::Pezpallet::<T>::author();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
/// Abstraction over "something that can provide the block author".
|
||||
pub trait AuthorProvider<AccountId> {
|
||||
fn author() -> AccountId;
|
||||
}
|
||||
|
||||
#[pezframe::pezpallet]
|
||||
pub mod pezpallet_foo_loose {
|
||||
use super::*;
|
||||
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[docify::export(loose_config)]
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
/// This pezpallet relies on the existence of something that implements [`AuthorProvider`],
|
||||
/// which may or may not be `pezpallet-author`.
|
||||
type AuthorProvider: AuthorProvider<Self::AccountId>;
|
||||
}
|
||||
|
||||
#[docify::export(loose_usage)]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn do_stuff_with_author() {
|
||||
let _ = T::AuthorProvider::author();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export(pezpallet_author_provider)]
|
||||
impl<T: pezpallet_author::Config> AuthorProvider<T::AccountId> for pezpallet_author::Pezpallet<T> {
|
||||
fn author() -> T::AccountId {
|
||||
pezpallet_author::Pezpallet::<T>::author()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OtherAuthorProvider;
|
||||
|
||||
#[docify::export(other_author_provider)]
|
||||
impl<AccountId> AuthorProvider<AccountId> for OtherAuthorProvider {
|
||||
fn author() -> AccountId {
|
||||
todo!("somehow get the block author here")
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export(unit_author_provider)]
|
||||
impl<AccountId> AuthorProvider<AccountId> for () {
|
||||
fn author() -> AccountId {
|
||||
todo!("somehow get the block author here")
|
||||
}
|
||||
}
|
||||
|
||||
pub mod runtime {
|
||||
use super::*;
|
||||
use pezcumulus_pezpallet_aura_ext::pezpallet;
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: pezframe_system,
|
||||
PezpalletFoo: pezpallet_foo_loose,
|
||||
PezpalletAuthor: pezpallet_author,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
impl pezpallet_author::Config for Runtime {}
|
||||
|
||||
#[docify::export(runtime_author_provider)]
|
||||
impl pezpallet_foo_loose::Config for Runtime {
|
||||
type AuthorProvider = pezpallet_author::Pezpallet<Runtime>;
|
||||
// which is also equivalent to
|
||||
// type AuthorProvider = PezpalletAuthor;
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
//!
|
||||
//! > As of now, many of these important types are generated within the internals of
|
||||
//! > [`construct_runtime`], and there is no easy way for you to visually know they exist.
|
||||
//! > [#pezkuwi-sdk#1378](https://github.com/paritytech/polkadot-sdk/pull/1378) is meant to
|
||||
//! > [#pezkuwi-sdk#1378](https://github.com/pezkuwichain/pezkuwi-sdk/issues/251) is meant to
|
||||
//! > significantly improve this. Exploring the rust-docs of a runtime, such as [`runtime`] which is
|
||||
//! > defined in this module is as of now the best way to learn about these types.
|
||||
//!
|
||||
@@ -13,7 +13,7 @@
|
||||
//!
|
||||
//! Many types within a FRAME runtime follow the following structure:
|
||||
//!
|
||||
//! * Each individual pallet defines a type, for example `Foo`.
|
||||
//! * Each individual pezpallet defines a type, for example `Foo`.
|
||||
//! * At the runtime level, these types are amalgamated into a single type, for example
|
||||
//! `RuntimeFoo`.
|
||||
//!
|
||||
@@ -29,24 +29,24 @@
|
||||
//!
|
||||
//! ### Example
|
||||
//!
|
||||
//! We provide the following two pallets: [`pallet_foo`] and [`pallet_bar`]. Each define a
|
||||
//! We provide the following two pallets: [`pezpallet_foo`] and [`pezpallet_bar`]. Each define a
|
||||
//! dispatchable, and `Foo` also defines a custom origin. Lastly, `Bar` defines an additional
|
||||
//! `GenesisConfig`.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_foo)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_bar)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pezpallet_foo)]
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pezpallet_bar)]
|
||||
//!
|
||||
//! Let's explore how each of these affect the [`RuntimeCall`], [`RuntimeOrigin`] and
|
||||
//! [`RuntimeGenesisConfig`] generated in [`runtime`] respectively.
|
||||
//!
|
||||
//! As observed, [`RuntimeCall`] has 3 variants, one for each pallet and one for `frame_system`. If
|
||||
//! you explore further, you will soon realize that each variant is merely a pointer to the `Call`
|
||||
//! type in each pallet, for example [`pallet_foo::Call`].
|
||||
//! As observed, [`RuntimeCall`] has 3 variants, one for each pezpallet and one for
|
||||
//! `pezframe_system`. If you explore further, you will soon realize that each variant is merely a
|
||||
//! pointer to the `Call` type in each pezpallet, for example [`pezpallet_foo::Call`].
|
||||
//!
|
||||
//! [`RuntimeOrigin`]'s [`OriginCaller`] has two variants, one for system, and one for `pallet_foo`
|
||||
//! which utilized [`frame::pallet_macros::origin`].
|
||||
//! [`RuntimeOrigin`]'s [`OriginCaller`] has two variants, one for system, and one for
|
||||
//! `pezpallet_foo` which utilized [`pezframe::pezpallet_macros::origin`].
|
||||
//!
|
||||
//! Finally, [`RuntimeGenesisConfig`] is composed of `frame_system` and a variant for `pallet_bar`'s
|
||||
//! [`pallet_bar::GenesisConfig`].
|
||||
//! Finally, [`RuntimeGenesisConfig`] is composed of `pezframe_system` and a variant for
|
||||
//! `pezpallet_bar`'s [`pezpallet_bar::GenesisConfig`].
|
||||
//!
|
||||
//! You can find other composite enums by scanning [`runtime`] for other types who's name starts
|
||||
//! with `Runtime`. Some of the more noteworthy ones are:
|
||||
@@ -57,77 +57,78 @@
|
||||
//!
|
||||
//! ### Adding Further Constraints to Runtime Composite Enums
|
||||
//!
|
||||
//! This section explores a common scenario where a pallet has access to one of these runtime
|
||||
//! This section explores a common scenario where a pezpallet has access to one of these runtime
|
||||
//! composite enums, but it wishes to further specify it by adding more trait bounds to it.
|
||||
//!
|
||||
//! Let's take the example of `RuntimeCall`. This is an associated type in
|
||||
//! [`frame_system::Config::RuntimeCall`], and all pallets have access to this type, because they
|
||||
//! have access to [`frame_system::Config`]. Finally, this type is meant to be set to outer call of
|
||||
//! the entire runtime.
|
||||
//! [`pezframe_system::Config::RuntimeCall`], and all pallets have access to this type, because they
|
||||
//! have access to [`pezframe_system::Config`]. Finally, this type is meant to be set to outer call
|
||||
//! of the entire runtime.
|
||||
//!
|
||||
//! But, let's not forget that this is information that *we know*, and the Rust compiler does not.
|
||||
//! All that the rust compiler knows about this type is *ONLY* what the trait bounds of
|
||||
//! [`frame_system::Config::RuntimeCall`] are specifying:
|
||||
#![doc = docify::embed!("../../substrate/frame/system/src/lib.rs", system_runtime_call)]
|
||||
//! [`pezframe_system::Config::RuntimeCall`] are specifying:
|
||||
#![doc = docify::embed!("../../bizinikiwi/pezframe/system/src/lib.rs", system_runtime_call)]
|
||||
//!
|
||||
//! So, when at a given pallet, one accesses `<T as frame_system::Config>::RuntimeCall`, the type is
|
||||
//! extremely opaque from the perspective of the Rust compiler.
|
||||
//! So, when at a given pezpallet, one accesses `<T as pezframe_system::Config>::RuntimeCall`, the
|
||||
//! type is extremely opaque from the perspective of the Rust compiler.
|
||||
//!
|
||||
//! How can a pallet access the `RuntimeCall` type with further constraints? For example, each
|
||||
//! pallet has its own `enum Call`, and knows that its local `Call` is a part of `RuntimeCall`,
|
||||
//! How can a pezpallet access the `RuntimeCall` type with further constraints? For example, each
|
||||
//! pezpallet has its own `enum Call`, and knows that its local `Call` is a part of `RuntimeCall`,
|
||||
//! therefore there should be a `impl From<Call<_>> for RuntimeCall`.
|
||||
//!
|
||||
//! The only way to express this using Rust's associated types is for the pallet to **define its own
|
||||
//! associated type `RuntimeCall`, and further specify what it thinks `RuntimeCall` should be**.
|
||||
//! The only way to express this using Rust's associated types is for the pezpallet to **define its
|
||||
//! own associated type `RuntimeCall`, and further specify what it thinks `RuntimeCall` should be**.
|
||||
//!
|
||||
//! In this case, we will want to assert the existence of [`frame::traits::IsSubType`], which is
|
||||
//! In this case, we will want to assert the existence of [`pezframe::traits::IsSubType`], which is
|
||||
//! very similar to [`TryFrom`].
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", custom_runtime_call)]
|
||||
//!
|
||||
//! And indeed, at the runtime level, this associated type would be the same `RuntimeCall` that is
|
||||
//! passed to `frame_system`.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pallet_with_specific_runtime_call_impl)]
|
||||
//! passed to `pezframe_system`.
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", pezpallet_with_specific_runtime_call_impl)]
|
||||
//!
|
||||
//! > In other words, the degree of specificity that [`frame_system::Config::RuntimeCall`] has is
|
||||
//! > not enough for the pallet to work with. Therefore, the pallet has to define its own associated
|
||||
//! > In other words, the degree of specificity that [`pezframe_system::Config::RuntimeCall`] has is
|
||||
//! > not enough for the pezpallet to work with. Therefore, the pezpallet has to define its own
|
||||
//! > associated
|
||||
//! > type representing `RuntimeCall`.
|
||||
//!
|
||||
//! Another way to look at this is:
|
||||
//!
|
||||
//! `pallet_with_specific_runtime_call::Config::RuntimeCall` and `frame_system::Config::RuntimeCall`
|
||||
//! are two different representations of the same concrete type that is only known when the runtime
|
||||
//! is being constructed.
|
||||
//! `pezpallet_with_specific_runtime_call::Config::RuntimeCall` and
|
||||
//! `pezframe_system::Config::RuntimeCall` are two different representations of the same concrete
|
||||
//! type that is only known when the runtime is being constructed.
|
||||
//!
|
||||
//! Now, within this pallet, this new `RuntimeCall` can be used, and it can use its new trait
|
||||
//! bounds, such as being [`frame::traits::IsSubType`]:
|
||||
//! Now, within this pezpallet, this new `RuntimeCall` can be used, and it can use its new trait
|
||||
//! bounds, such as being [`pezframe::traits::IsSubType`]:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", custom_runtime_call_usages)]
|
||||
//!
|
||||
//! > Once Rust's "_Associated Type Bounds RFC_" is usable, this syntax can be used to
|
||||
//! > simplify the above scenario. See [this](https://github.com/pezkuwichain/pezkuwi-sdk/issues/133)
|
||||
//! > simplify the above scenario. See [this](https://github.com/pezkuwichain/pezkuwi-sdk/issues/278)
|
||||
//! > issue for more information.
|
||||
//!
|
||||
//! ### Asserting Equality of Multiple Runtime Composite Enums
|
||||
//!
|
||||
//! Recall that in the above example, `<T as Config>::RuntimeCall` and `<T as
|
||||
//! frame_system::Config>::RuntimeCall` are expected to be equal types, but at the compile-time we
|
||||
//! have to represent them with two different associated types with different bounds. Would it not
|
||||
//! be cool if we had a test to make sure they actually resolve to the same concrete type once the
|
||||
//! runtime is constructed? The following snippet exactly does that:
|
||||
//! pezframe_system::Config>::RuntimeCall` are expected to be equal types, but at the compile-time
|
||||
//! we have to represent them with two different associated types with different bounds. Would it
|
||||
//! not be cool if we had a test to make sure they actually resolve to the same concrete type once
|
||||
//! the runtime is constructed? The following snippet exactly does that:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_runtime_types.rs", assert_equality)]
|
||||
//!
|
||||
//! We leave it to the reader to further explore what [`frame::traits::Hooks::integrity_test`] is,
|
||||
//! We leave it to the reader to further explore what [`pezframe::traits::Hooks::integrity_test`] is,
|
||||
//! and what [`core::any::TypeId`] is. Another way to assert this is using
|
||||
//! [`frame::traits::IsType`].
|
||||
//! [`pezframe::traits::IsType`].
|
||||
//!
|
||||
//! ## Type Aliases
|
||||
//!
|
||||
//! A number of type aliases are generated by the `construct_runtime` which are also noteworthy:
|
||||
//!
|
||||
//! * [`runtime::PalletFoo`] is an alias to [`pallet_foo::Pallet`]. Same for `PalletBar`, and
|
||||
//! * [`runtime::PalletFoo`] is an alias to [`pezpallet_foo::Pezpallet`]. Same for `PalletBar`, and
|
||||
//! `System`
|
||||
//! * [`runtime::AllPalletsWithSystem`] is an alias for a tuple of all of the above. This type is
|
||||
//! important to FRAME internals such as `executive`, as it implements traits such as
|
||||
//! [`frame::traits::Hooks`].
|
||||
//! [`pezframe::traits::Hooks`].
|
||||
//!
|
||||
//! ## Further Details
|
||||
//!
|
||||
@@ -139,15 +140,15 @@
|
||||
//! * See the corresponding lecture in the [PBA Lectures](https://www.youtube.com/watch?v=OCBC1pMYPoc&list=PL-w_i5kwVqbni1Ch2j_RwTIXiB-bwnYqq&index=11).
|
||||
//!
|
||||
//!
|
||||
//! [`construct_runtime`]: frame::runtime::prelude::construct_runtime
|
||||
//! [`construct_runtime`]: pezframe::runtime::prelude::construct_runtime
|
||||
//! [`runtime::PalletFoo`]: crate::reference_docs::frame_runtime_types::runtime::PalletFoo
|
||||
//! [`runtime::AllPalletsWithSystem`]: crate::reference_docs::frame_runtime_types::runtime::AllPalletsWithSystem
|
||||
//! [`runtime`]: crate::reference_docs::frame_runtime_types::runtime
|
||||
//! [`pallet_foo`]: crate::reference_docs::frame_runtime_types::pallet_foo
|
||||
//! [`pallet_foo::Call`]: crate::reference_docs::frame_runtime_types::pallet_foo::Call
|
||||
//! [`pallet_foo::Pallet`]: crate::reference_docs::frame_runtime_types::pallet_foo::Pallet
|
||||
//! [`pallet_bar`]: crate::reference_docs::frame_runtime_types::pallet_bar
|
||||
//! [`pallet_bar::GenesisConfig`]: crate::reference_docs::frame_runtime_types::pallet_bar::GenesisConfig
|
||||
//! [`pezpallet_foo`]: crate::reference_docs::frame_runtime_types::pezpallet_foo
|
||||
//! [`pezpallet_foo::Call`]: crate::reference_docs::frame_runtime_types::pezpallet_foo::Call
|
||||
//! [`pezpallet_foo::Pezpallet`]: crate::reference_docs::frame_runtime_types::pezpallet_foo::Pezpallet
|
||||
//! [`pezpallet_bar`]: crate::reference_docs::frame_runtime_types::pezpallet_bar
|
||||
//! [`pezpallet_bar::GenesisConfig`]: crate::reference_docs::frame_runtime_types::pezpallet_bar::GenesisConfig
|
||||
//! [`RuntimeEvent`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeEvent
|
||||
//! [`RuntimeGenesisConfig`]:
|
||||
//! crate::reference_docs::frame_runtime_types::runtime::RuntimeGenesisConfig
|
||||
@@ -157,17 +158,17 @@
|
||||
//! [`RuntimeCall`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeCall
|
||||
//! [`RuntimeHoldReason`]: crate::reference_docs::frame_runtime_types::runtime::RuntimeHoldReason
|
||||
|
||||
use frame::prelude::*;
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_foo {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_foo {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::origin]
|
||||
#[pezpallet::origin]
|
||||
#[derive(
|
||||
PartialEq,
|
||||
Eq,
|
||||
@@ -184,11 +185,11 @@ pub mod pallet_foo {
|
||||
B,
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn foo(_origin: OriginFor<T>) -> DispatchResult {
|
||||
todo!();
|
||||
}
|
||||
@@ -200,29 +201,29 @@ pub mod pallet_foo {
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_bar {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_bar {
|
||||
use super::*;
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {}
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::genesis_config]
|
||||
#[pezpallet::genesis_config]
|
||||
#[derive(DefaultNoBound)]
|
||||
pub struct GenesisConfig<T: Config> {
|
||||
pub initial_account: Option<T::AccountId>,
|
||||
}
|
||||
|
||||
#[pallet::genesis_build]
|
||||
#[pezpallet::genesis_build]
|
||||
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
|
||||
fn build(&self) {}
|
||||
}
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn bar(_origin: OriginFor<T>) -> DispatchResult {
|
||||
todo!();
|
||||
}
|
||||
@@ -230,90 +231,90 @@ pub mod pallet_bar {
|
||||
}
|
||||
|
||||
pub mod runtime {
|
||||
use super::{pallet_bar, pallet_foo};
|
||||
use frame::{runtime::prelude::*, testing_prelude::*};
|
||||
use super::{pezpallet_bar, pezpallet_foo};
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
#[docify::export(runtime_exp)]
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: frame_system,
|
||||
PalletFoo: pallet_foo,
|
||||
PalletBar: pallet_bar,
|
||||
System: pezframe_system,
|
||||
PalletFoo: pezpallet_foo,
|
||||
PalletBar: pezpallet_bar,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
impl pallet_foo::Config for Runtime {}
|
||||
impl pallet_bar::Config for Runtime {}
|
||||
impl pezpallet_foo::Config for Runtime {}
|
||||
impl pezpallet_bar::Config for Runtime {}
|
||||
}
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
pub mod pallet_with_specific_runtime_call {
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
pub mod pezpallet_with_specific_runtime_call {
|
||||
use super::*;
|
||||
use frame::traits::IsSubType;
|
||||
use pezframe::traits::IsSubType;
|
||||
|
||||
#[docify::export(custom_runtime_call)]
|
||||
/// A pallet that wants to further narrow down what `RuntimeCall` is.
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
/// A pezpallet that wants to further narrow down what `RuntimeCall` is.
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
type RuntimeCall: IsSubType<Call<Self>>;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
// note that this pallet needs some `call` to have a `enum Call`.
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
// note that this pezpallet needs some `call` to have a `enum Call`.
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
pub fn foo(_origin: OriginFor<T>) -> DispatchResult {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export(custom_runtime_call_usages)]
|
||||
impl<T: Config> Pallet<T> {
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn _do_something_useful_with_runtime_call(call: <T as Config>::RuntimeCall) {
|
||||
// check if the runtime call given is of this pallet's variant.
|
||||
// check if the runtime call given is of this pezpallet's variant.
|
||||
let _maybe_my_call: Option<&Call<T>> = call.is_sub_type();
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
#[docify::export(assert_equality)]
|
||||
#[pallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
|
||||
#[pezpallet::hooks]
|
||||
impl<T: Config> Hooks<BlockNumberFor<T>> for Pezpallet<T> {
|
||||
fn integrity_test() {
|
||||
use core::any::TypeId;
|
||||
assert_eq!(
|
||||
TypeId::of::<<T as Config>::RuntimeCall>(),
|
||||
TypeId::of::<<T as frame_system::Config>::RuntimeCall>()
|
||||
TypeId::of::<<T as pezframe_system::Config>::RuntimeCall>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod runtime_with_specific_runtime_call {
|
||||
use super::pallet_with_specific_runtime_call;
|
||||
use frame::{runtime::prelude::*, testing_prelude::*};
|
||||
use super::pezpallet_with_specific_runtime_call;
|
||||
use pezframe::{runtime::prelude::*, testing_prelude::*};
|
||||
|
||||
construct_runtime!(
|
||||
pub struct Runtime {
|
||||
System: frame_system,
|
||||
PalletWithSpecificRuntimeCall: pallet_with_specific_runtime_call,
|
||||
System: pezframe_system,
|
||||
PalletWithSpecificRuntimeCall: pezpallet_with_specific_runtime_call,
|
||||
}
|
||||
);
|
||||
|
||||
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
|
||||
impl frame_system::Config for Runtime {
|
||||
#[derive_impl(pezframe_system::config_preludes::TestDefaultConfig)]
|
||||
impl pezframe_system::Config for Runtime {
|
||||
type Block = MockBlock<Self>;
|
||||
}
|
||||
|
||||
#[docify::export(pallet_with_specific_runtime_call_impl)]
|
||||
impl pallet_with_specific_runtime_call::Config for Runtime {
|
||||
#[docify::export(pezpallet_with_specific_runtime_call_impl)]
|
||||
impl pezpallet_with_specific_runtime_call::Config for Runtime {
|
||||
// an implementation of `IsSubType` is provided by `construct_runtime`.
|
||||
type RuntimeCall = RuntimeCall;
|
||||
}
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
//! 1. on-chain state,
|
||||
//! 2. a state transition function.
|
||||
//!
|
||||
//! In Substrate-based blockchains, state transition functions are referred to as
|
||||
//! In Bizinikiwi-based blockchains, state transition functions are referred to as
|
||||
//! [runtimes](https://docs.pezkuwichain.io/sdk/master/polkadot_sdk_docs/reference_docs/blockchain_state_machines/index.html).
|
||||
//!
|
||||
//! Traditionally, before Substrate, upgrading state transition functions required node
|
||||
//! Traditionally, before Bizinikiwi, upgrading state transition functions required node
|
||||
//! operators to download new software and restart their nodes in a process called
|
||||
//! [forking](https://en.wikipedia.org/wiki/Fork_(blockchain)).
|
||||
//!
|
||||
//! Substrate-based blockchains do not require forking, and instead upgrade runtimes
|
||||
//! Bizinikiwi-based blockchains do not require forking, and instead upgrade runtimes
|
||||
//! in a process called "Runtime Upgrades".
|
||||
//!
|
||||
//! Forkless runtime upgrades are a defining feature of the Substrate framework. Updating the
|
||||
//! Forkless runtime upgrades are a defining feature of the Bizinikiwi framework. Updating the
|
||||
//! runtime logic without forking the code base enables your blockchain to seamlessly evolve
|
||||
//! over time in a deterministic, rules-based manner. It also removes ambiguity for node operators
|
||||
//! and other participants in the network about what is the canonical runtime.
|
||||
@@ -24,26 +24,26 @@
|
||||
//!
|
||||
//! ## Performing a Runtime Upgrade
|
||||
//!
|
||||
//! To upgrade a runtime, an [`Origin`](frame_system::RawOrigin) with the necessary permissions
|
||||
//! To upgrade a runtime, an [`Origin`](pezframe_system::RawOrigin) with the necessary permissions
|
||||
//! (usually via governance) changes the `:code` storage. Usually, this is performed via a call to
|
||||
//! [`set_code`] (or [`set_code_without_checks`]) with the desired new runtime blob, scheduled
|
||||
//! using [`pallet_scheduler`].
|
||||
//! using [`pezpallet_scheduler`].
|
||||
//!
|
||||
//! Prior to building the new runtime, don't forget to update the
|
||||
//! [`RuntimeVersion`](sp_version::RuntimeVersion).
|
||||
//! [`RuntimeVersion`](pezsp_version::RuntimeVersion).
|
||||
//!
|
||||
//! # Migrations
|
||||
//!
|
||||
//! It is often desirable to define logic to execute immediately after runtime upgrades (see
|
||||
//! [this diagram](frame::traits::Hooks)).
|
||||
//! [this diagram](pezframe::traits::Hooks)).
|
||||
//!
|
||||
//! Self-contained pieces of logic that execute after a runtime upgrade are called "Migrations".
|
||||
//!
|
||||
//! The typical use case of a migration is to 'migrate' pallet storage from one layout to another,
|
||||
//! for example when the encoding of a storage item is changed. However, they can also execute
|
||||
//! arbitrary logic such as:
|
||||
//! The typical use case of a migration is to 'migrate' pezpallet storage from one layout to
|
||||
//! another, for example when the encoding of a storage item is changed. However, they can also
|
||||
//! execute arbitrary logic such as:
|
||||
//!
|
||||
//! - Calling arbitrary pallet methods.
|
||||
//! - Calling arbitrary pezpallet methods.
|
||||
//! - Mutating arbitrary on-chain state.
|
||||
//! - Cleaning up some old storage items that are no longer needed.
|
||||
//!
|
||||
@@ -54,22 +54,22 @@
|
||||
//! - Are suitable for migrations which are guaranteed to not exceed the block weight.
|
||||
//! - Are simply implementations of [`OnRuntimeUpgrade`].
|
||||
//!
|
||||
//! To learn best practices for writing single block pallet storage migrations, see the
|
||||
//! [Single Block Migration Example Pallet](pallet_example_single_block_migrations).
|
||||
//! To learn best practices for writing single block pezpallet storage migrations, see the
|
||||
//! [Single Block Migration Example Pezpallet](pezpallet_example_single_block_migrations).
|
||||
//!
|
||||
//! ### Scheduling the Single Block Migrations to Run Next Runtime Upgrade
|
||||
//!
|
||||
//! Schedule migrations to run next runtime upgrade passing them as a parameter to your
|
||||
//! [`Config`](frame_system) pallet:
|
||||
//! [`Config`](pezframe_system) pezpallet:
|
||||
//!
|
||||
//! ```ignore
|
||||
//! /// Tuple of migrations (structs that implement `OnRuntimeUpgrade`)
|
||||
//! type Migrations = (
|
||||
//! pallet_example_storage_migration::migrations::v1::versioned::MigrateV0ToV1,
|
||||
//! pezpallet_example_storage_migration::migrations::v1::versioned::MigrateV0ToV1,
|
||||
//! MyCustomMigration,
|
||||
//! // ...more migrations here
|
||||
//! );
|
||||
//! impl frame_system::Config for Runtime {
|
||||
//! impl pezframe_system::Config for Runtime {
|
||||
//! type SingleBlockMigrations = Migrations;
|
||||
//! }
|
||||
//! ```
|
||||
@@ -114,7 +114,7 @@
|
||||
//!
|
||||
//! ### Other useful tools
|
||||
//!
|
||||
//! [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) is another tool in the Substrate
|
||||
//! [`Chopsticks`](https://github.com/AcalaNetwork/chopsticks) is another tool in the Bizinikiwi
|
||||
//! ecosystem which developers may find useful to use in addition to `try-runtime-cli` when testing
|
||||
//! their single block migrations.
|
||||
//!
|
||||
@@ -125,10 +125,10 @@
|
||||
//! Suitable for migrations which could use arbitrary amounts of block weight.
|
||||
//!
|
||||
//! See the
|
||||
//! [multi-block-migrations example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/0d7d2177807ec6b3094f4491a45b0bc0d74d3c8b/substrate/frame/examples/multi-block-migrations)
|
||||
//! [multi-block-migrations example](https://github.com/pezkuwichain/pezkuwi-sdk/tree/0d7d2177807ec6b3094f4491a45b0bc0d74d3c8b/bizinikiwi/pezframe/examples/multi-block-migrations)
|
||||
//! for reference.
|
||||
//!
|
||||
//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade
|
||||
//! [`StorageVersion`]: frame_support::traits::StorageVersion
|
||||
//! [`set_code`]: frame_system::Call::set_code
|
||||
//! [`set_code_without_checks`]: frame_system::Call::set_code_without_checks
|
||||
//! [`OnRuntimeUpgrade`]: pezframe_support::traits::OnRuntimeUpgrade
|
||||
//! [`StorageVersion`]: pezframe_support::traits::StorageVersion
|
||||
//! [`set_code`]: pezframe_system::Call::set_code
|
||||
//! [`set_code_without_checks`]: pezframe_system::Call::set_code_without_checks
|
||||
|
||||
@@ -8,70 +8,70 @@
|
||||
//! Let's begin by starting to store a `NewType` in a storage item:
|
||||
//!
|
||||
//! ```compile_fail
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! pub struct NewType(u32);
|
||||
//
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T> = StorageValue<_, NewType>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! This raises a number of compiler errors, like:
|
||||
//! ```text
|
||||
//! the trait `MaxEncodedLen` is not implemented for `NewType`, which is required by
|
||||
//! `frame::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
|
||||
//! `pezframe::prelude::StorageValue<_GeneratedPrefixForStorageSomething<T>, NewType>:
|
||||
//! StorageInfoTrait`
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! This implies the following set of traits that need to be derived for a type to be stored in
|
||||
//! `frame` storage:
|
||||
//! ```rust
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
//! pub struct NewType(u32);
|
||||
//!
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T> = StorageValue<_, NewType>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! Next, let's look at how this will differ if we are to store a type that is derived from `T` in
|
||||
//! storage, such as [`frame::prelude::BlockNumberFor`]:
|
||||
//! storage, such as [`pezframe::prelude::BlockNumberFor`]:
|
||||
//! ```compile_fail
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
//!
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! Surprisingly, this will also raise a number of errors, like:
|
||||
//! ```text
|
||||
//! the trait `TypeInfo` is not implemented for `T`, which is required
|
||||
//! by`frame_support::pallet_prelude::StorageValue<pallet_2::_GeneratedPrefixForStorageSomething<T>,
|
||||
//! pallet_2::NewType<T>>:StorageEntryMetadataBuilder
|
||||
//! by`pezframe_support::pezpallet_prelude::StorageValue<pezpallet_2::_GeneratedPrefixForStorageSomething<T>,
|
||||
//! pezpallet_2::NewType<T>>:StorageEntryMetadataBuilder
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! Why is that? The underlying reason is that the `TypeInfo` `derive` macro will only work for
|
||||
//! `NewType` if all of `NewType`'s generics also implement `TypeInfo`. This is not the case for `T`
|
||||
//! in the example above.
|
||||
@@ -84,42 +84,42 @@
|
||||
//! attribute to `NewType`. This additional macro will instruct the `derive` to skip the bound on
|
||||
//! `T`.
|
||||
//! ```rust
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo)]
|
||||
//! #[scale_info(skip_type_params(T))]
|
||||
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
//!
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, NewType<T>>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Next, let's say we wish to store `NewType` as [`frame::prelude::ValueQuery`], which means it
|
||||
//!
|
||||
//! Next, let's say we wish to store `NewType` as [`pezframe::prelude::ValueQuery`], which means it
|
||||
//! must also implement `Default`. This should be as simple as adding `derive(Default)` to it,
|
||||
//! right?
|
||||
//! ```compile_fail
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[derive(codec::Encode, codec::Decode, codec::MaxEncodedLen, scale_info::TypeInfo, Default)]
|
||||
//! #[scale_info(skip_type_params(T))]
|
||||
//! pub struct NewType<T: Config>(BlockNumberFor<T>);
|
||||
//!
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! Under the hood, the expansion of the `derive(Default)` will suffer from the same restriction as
|
||||
//! before: it will only work if `T: Default`, and `T` is not `Default`. Note that this is an
|
||||
//! expected issue: `T` is merely a wrapper of many other types, such as `BlockNumberFor<T>`.
|
||||
@@ -129,26 +129,26 @@
|
||||
//! To fix this, frame provides a set of macros that are analogous to normal rust derive macros, but
|
||||
//! work nicely on top of structs that are generic over `T: Config`. These macros are:
|
||||
//!
|
||||
//! - [`frame::prelude::DefaultNoBound`]
|
||||
//! - [`frame::prelude::DebugNoBound`]
|
||||
//! - [`frame::prelude::PartialEqNoBound`]
|
||||
//! - [`frame::prelude::EqNoBound`]
|
||||
//! - [`frame::prelude::CloneNoBound`]
|
||||
//! - [`frame::prelude::PartialOrdNoBound`]
|
||||
//! - [`frame::prelude::OrdNoBound`]
|
||||
//! - [`pezframe::prelude::DefaultNoBound`]
|
||||
//! - [`pezframe::prelude::DebugNoBound`]
|
||||
//! - [`pezframe::prelude::PartialEqNoBound`]
|
||||
//! - [`pezframe::prelude::EqNoBound`]
|
||||
//! - [`pezframe::prelude::CloneNoBound`]
|
||||
//! - [`pezframe::prelude::PartialOrdNoBound`]
|
||||
//! - [`pezframe::prelude::OrdNoBound`]
|
||||
//!
|
||||
//! The above traits are almost certainly needed for your tests - to print your type, assert equality
|
||||
//! or clone it.
|
||||
//!
|
||||
//! We can fix the following example by using [`frame::prelude::DefaultNoBound`].
|
||||
//! We can fix the following example by using [`pezframe::prelude::DefaultNoBound`].
|
||||
//! ```rust
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! # use frame::prelude::*;
|
||||
//! # #[pallet::config]
|
||||
//! # pub trait Config: frame_system::Config {}
|
||||
//! # #[pallet::pallet]
|
||||
//! # pub struct Pallet<T>(_);
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! # use pezframe::prelude::*;
|
||||
//! # #[pezpallet::config]
|
||||
//! # pub trait Config: pezframe_system::Config {}
|
||||
//! # #[pezpallet::pezpallet]
|
||||
//! # pub struct Pezpallet<T>(_);
|
||||
//! #[derive(
|
||||
//! codec::Encode,
|
||||
//! codec::Decode,
|
||||
@@ -159,44 +159,44 @@
|
||||
//! #[scale_info(skip_type_params(T))]
|
||||
//! pub struct NewType<T:Config>(BlockNumberFor<T>);
|
||||
//!
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, NewType<T>, ValueQuery>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! Finally, if a custom type that is provided through `Config` is to be stored in the storage, it
|
||||
//! is subject to the same trait requirements. The following does not work:
|
||||
//! ```compile_fail
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! use frame::prelude::*;
|
||||
//! #[pallet::config]
|
||||
//! pub trait Config: frame_system::Config {
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! use pezframe::prelude::*;
|
||||
//! #[pezpallet::config]
|
||||
//! pub trait Config: pezframe_system::Config {
|
||||
//! type CustomType;
|
||||
//! }
|
||||
//! #[pallet::pallet]
|
||||
//! pub struct Pallet<T>(_);
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::pezpallet]
|
||||
//! pub struct Pezpallet<T>(_);
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//!
|
||||
//! But adding the right trait bounds will fix it.
|
||||
//! ```rust
|
||||
//! #[frame::pallet]
|
||||
//! pub mod pallet {
|
||||
//! use frame::prelude::*;
|
||||
//! #[pallet::config]
|
||||
//! pub trait Config: frame_system::Config {
|
||||
//! #[pezframe::pezpallet]
|
||||
//! pub mod pezpallet {
|
||||
//! use pezframe::prelude::*;
|
||||
//! #[pezpallet::config]
|
||||
//! pub trait Config: pezframe_system::Config {
|
||||
//! type CustomType: codec::FullCodec
|
||||
//! + codec::MaxEncodedLen
|
||||
//! + scale_info::TypeInfo
|
||||
//! + Debug
|
||||
//! + Default;
|
||||
//! }
|
||||
//! #[pallet::pallet]
|
||||
//! pub struct Pallet<T>(_);
|
||||
//! #[pallet::storage]
|
||||
//! #[pezpallet::pezpallet]
|
||||
//! pub struct Pezpallet<T>(_);
|
||||
//! #[pezpallet::storage]
|
||||
//! pub type Something<T: Config> = StorageValue<_, T::CustomType>;
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// This file is part of pezkuwi-sdk.
|
||||
//
|
||||
// Copyright (C) Parity Technologies (UK) Ltd.
|
||||
// Copyright (C) Parity Technologies (UK) Ltd. and Dijital Kurdistan Tech Institute
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -30,13 +30,13 @@
|
||||
//!
|
||||
//! ## Getting Started
|
||||
//!
|
||||
//! The most ubiquitous way to add a token to a FRAME runtime is [`pallet_balances`]. Read
|
||||
//! The most ubiquitous way to add a token to a FRAME runtime is [`pezpallet_balances`]. Read
|
||||
//! more about pallets [here](crate::pezkuwi_sdk::frame_runtime#pallets).
|
||||
//!
|
||||
//! You may then write custom pallets that interact with [`pallet_balances`]. The fastest way to
|
||||
//! You may then write custom pallets that interact with [`pezpallet_balances`]. The fastest way to
|
||||
//! get started with that is by
|
||||
//! [tightly coupling](crate::reference_docs::frame_pallet_coupling#tight-coupling-pallets) your
|
||||
//! custom pallet to [`pallet_balances`].
|
||||
//! custom pezpallet to [`pezpallet_balances`].
|
||||
//!
|
||||
//! However, to keep pallets flexible and modular, it is often preferred to
|
||||
//! [loosely couple](crate::reference_docs::frame_pallet_coupling#loosely--coupling-pallets).
|
||||
@@ -50,80 +50,81 @@
|
||||
//! trait implementations.
|
||||
//!
|
||||
//! **Traits** define common interfaces that types of tokens should implement. For example, the
|
||||
//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) trait specifies an interface
|
||||
//! for *inspecting* token state such as the total issuance of the token, the balance of individual
|
||||
//! accounts, etc.
|
||||
//! [`fungible::Inspect`](`pezframe_support::traits::fungible::Inspect`) trait specifies an
|
||||
//! interface for *inspecting* token state such as the total issuance of the token, the balance of
|
||||
//! individual accounts, etc.
|
||||
//!
|
||||
//! **Trait implementations** are concrete implementations of these traits. For example, one of the
|
||||
//! many traits [`pallet_balances`] implements is
|
||||
//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`)[^1]. It provides the concrete
|
||||
//! way of inspecting the total issuance, balance of accounts, etc. There can be many
|
||||
//! many traits [`pezpallet_balances`] implements is
|
||||
//! [`fungible::Inspect`](`pezframe_support::traits::fungible::Inspect`)[^1]. It provides the
|
||||
//! concrete way of inspecting the total issuance, balance of accounts, etc. There can be many
|
||||
//! implementations of the same traits.
|
||||
//!
|
||||
//! [^1]: Rust Advanced Tip: The knowledge that [`pallet_balances`] implements
|
||||
//! [`fungible::Inspect`](`frame_support::traits::fungible::Inspect`) is not some arcane knowledge
|
||||
//! that you have to know by heart or memorize. One can simply look at the list of the implementors
|
||||
//! of any trait in the Rust Doc to find all implementors (e.g.
|
||||
//! [Mutate trait implementors](https://docs.pezkuwichain.io/sdk/master/frame_support/traits/tokens/fungible/trait.Mutate.html#implementors)),
|
||||
//! [^1]: Rust Advanced Tip: The knowledge that [`pezpallet_balances`] implements
|
||||
//! [`fungible::Inspect`](`pezframe_support::traits::fungible::Inspect`) is not some arcane
|
||||
//! knowledge that you have to know by heart or memorize. One can simply look at the list of the
|
||||
//! implementors of any trait in the Rust Doc to find all implementors (e.g.
|
||||
//! [Mutate trait implementors](https://docs.pezkuwichain.io/sdk/master/pezframe_support/traits/tokens/fungible/trait.Mutate.html#implementors)),
|
||||
//! or use the `rust-analyzer`'s `Implementations` action.
|
||||
//!
|
||||
//! The distinction between traits and trait implementations is helpful because it allows pallets
|
||||
//! and other logic to be generic over their dependencies, avoiding tight coupling.
|
||||
//!
|
||||
//! To illustrate this with an example let's consider [`pallet_preimage`]. This pallet takes a
|
||||
//! To illustrate this with an example let's consider [`pezpallet_preimage`]. This pezpallet takes a
|
||||
//! deposit in exchange for storing a preimage for later use. A naive implementation of the
|
||||
//! pallet may use [`pallet_balances`] in a tightly coupled manner, directly calling methods
|
||||
//! on the pallet to reserve and unreserve deposits. This approach works well,
|
||||
//! until someone has a use case requiring that an asset from a different pallet such as
|
||||
//! [`pallet_assets`] is used for the deposit. Rather than tightly coupling [`pallet_preimage`] to
|
||||
//! [`pallet_balances`], [`pallet_assets`], and every other token-handling pallet, a user
|
||||
//! could possibly specify that [`pallet_preimage`] does not specify a concrete pallet as a
|
||||
//! dependency, but instead accepts any dependency which implements the
|
||||
//! [`currency::ReservableCurrency`](`frame_support::traits::tokens::currency::ReservableCurrency`)
|
||||
//! trait, namely via its [`Config::Currency`](`pallet_preimage::pallet::Config::Currency`)
|
||||
//! associated type. This allows [`pallet_preimage`] to support any arbitrary pallet implementing
|
||||
//! this trait, without needing any knowledge of what those pallets may be or requiring changes to
|
||||
//! support new pallets which may be written in the future.
|
||||
//! pezpallet may use [`pezpallet_balances`] in a tightly coupled manner, directly calling methods
|
||||
//! on the pezpallet to reserve and unreserve deposits. This approach works well,
|
||||
//! until someone has a use case requiring that an asset from a different pezpallet such as
|
||||
//! [`pezpallet_assets`] is used for the deposit. Rather than tightly coupling
|
||||
//! [`pezpallet_preimage`] to [`pezpallet_balances`], [`pezpallet_assets`], and every other
|
||||
//! token-handling pezpallet, a user could possibly specify that [`pezpallet_preimage`] does not
|
||||
//! specify a concrete pezpallet as a dependency, but instead accepts any dependency which
|
||||
//! implements the
|
||||
//! [`currency::ReservableCurrency`](`pezframe_support::traits::tokens::currency::ReservableCurrency`)
|
||||
//! trait, namely via its [`Config::Currency`](`pezpallet_preimage::pezpallet::Config::Currency`)
|
||||
//! associated type. This allows [`pezpallet_preimage`] to support any arbitrary pezpallet
|
||||
//! implementing this trait, without needing any knowledge of what those pallets may be or requiring
|
||||
//! changes to support new pallets which may be written in the future.
|
||||
//!
|
||||
//! Read more about coupling, and the benefits of loose coupling
|
||||
//! [here](crate::reference_docs::frame_pallet_coupling).
|
||||
//!
|
||||
//! ## Fungible Token Traits in FRAME
|
||||
//!
|
||||
//! The [`fungible`](`frame_support::traits::fungible`) crate contains the latest set of FRAME
|
||||
//! The [`fungible`](`pezframe_support::traits::fungible`) crate contains the latest set of FRAME
|
||||
//! fungible token traits, and is recommended to use for all new logic requiring a fungible token.
|
||||
//! See the crate documentation for more info about these fungible traits.
|
||||
//!
|
||||
//! [`fungibles`](`frame_support::traits::fungibles`) provides very similar functionality to
|
||||
//! [`fungible`](`frame_support::traits::fungible`), except it supports managing multiple tokens.
|
||||
//! [`fungibles`](`pezframe_support::traits::fungibles`) provides very similar functionality to
|
||||
//! [`fungible`](`pezframe_support::traits::fungible`), except it supports managing multiple tokens.
|
||||
//!
|
||||
//! You may notice the trait [`Currency`](`frame_support::traits::Currency`) with similar
|
||||
//! You may notice the trait [`Currency`](`pezframe_support::traits::Currency`) with similar
|
||||
//! functionality is also used in the codebase, however this trait is deprecated and existing logic
|
||||
//! is in the process of being migrated to [`fungible`](`frame_support::traits::fungible`) ([tracking issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/102)).
|
||||
//! is in the process of being migrated to [`fungible`](`pezframe_support::traits::fungible`) ([tracking issue](https://github.com/pezkuwichain/pezkuwi-sdk/issues/248)).
|
||||
//!
|
||||
//! ## Fungible Token Trait Implementations in FRAME
|
||||
//!
|
||||
//! [`pallet_balances`] implements [`fungible`](`frame_support::traits::fungible`), and is the most
|
||||
//! commonly used fungible implementation in FRAME. Most of the time, it's used for managing the
|
||||
//! native token of the blockchain network it's used in.
|
||||
//! [`pezpallet_balances`] implements [`fungible`](`pezframe_support::traits::fungible`), and is the
|
||||
//! most commonly used fungible implementation in FRAME. Most of the time, it's used for managing
|
||||
//! the native token of the blockchain network it's used in.
|
||||
//!
|
||||
//! [`pallet_assets`] implements [`fungibles`](`frame_support::traits::fungibles`), and is another
|
||||
//! popular fungible token implementation. It supports the creation and management of multiple
|
||||
//! assets in a single crate, making it a good choice when a network requires more assets in
|
||||
//! addition to its native token.
|
||||
//! [`pezpallet_assets`] implements [`fungibles`](`pezframe_support::traits::fungibles`), and is
|
||||
//! another popular fungible token implementation. It supports the creation and management of
|
||||
//! multiple assets in a single crate, making it a good choice when a network requires more assets
|
||||
//! in addition to its native token.
|
||||
//!
|
||||
//! ## Non-Fungible Tokens in FRAME
|
||||
//!
|
||||
//! [`pallet_nfts`] is recommended to use for all NFT use cases in FRAME.
|
||||
//! See the crate documentation for more info about this pallet.
|
||||
//! [`pezpallet_nfts`] is recommended to use for all NFT use cases in FRAME.
|
||||
//! See the crate documentation for more info about this pezpallet.
|
||||
//!
|
||||
//! [`pallet_uniques`] is deprecated and should not be used.
|
||||
//! [`pezpallet_uniques`] is deprecated and should not be used.
|
||||
//!
|
||||
//!
|
||||
//! # What Next?
|
||||
//!
|
||||
//! - If you are interested in implementing a single fungible token, continue reading the
|
||||
//! [`fungible`](`frame_support::traits::fungible`) and [`pallet_balances`] docs.
|
||||
//! [`fungible`](`pezframe_support::traits::fungible`) and [`pezpallet_balances`] docs.
|
||||
//! - If you are interested in implementing a set of fungible tokens, continue reading the
|
||||
//! [`fungibles`](`frame_support::traits::fungibles`) trait and [`pallet_assets`] docs.
|
||||
//! - If you are interested in implementing an NFT, continue reading the [`pallet_nfts`] docs.
|
||||
//! [`fungibles`](`pezframe_support::traits::fungibles`) trait and [`pezpallet_assets`] docs.
|
||||
//! - If you are interested in implementing an NFT, continue reading the [`pezpallet_nfts`] docs.
|
||||
|
||||
@@ -66,14 +66,14 @@
|
||||
//! included into a block and leads to some action. This includes user-initiated transactions as
|
||||
//! well as inherents which are placed into the block by the block-builder.
|
||||
//!
|
||||
//! #### Pallet
|
||||
//! #### Pezpallet
|
||||
//!
|
||||
//! Similar to software modules in traditional programming, [FRAME](frame) pallets in Substrate are
|
||||
//! Similar to software modules in traditional programming, [FRAME](frame) pallets in Bizinikiwi are
|
||||
//! modular components that encapsulate distinct functionalities or business logic. Just as
|
||||
//! libraries or modules are used to build and extend the capabilities of a software application,
|
||||
//! pallets are the foundational building blocks for constructing a blockchain's runtime with frame.
|
||||
//! They enable the creation of customizable and upgradeable networks, offering a composable
|
||||
//! framework for a Substrate-based blockchain. Each pallet can be thought of as a plug-and-play
|
||||
//! framework for a Bizinikiwi-based blockchain. Each pezpallet can be thought of as a plug-and-play
|
||||
//! module, enhancing the blockchain's functionality in a cohesive and integrated manner.
|
||||
//!
|
||||
//! #### Full Node
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! # Metadata
|
||||
//!
|
||||
//! The existence of metadata in pezkuwi-sdk goes back to the (forkless) upgrade-ability of all
|
||||
//! Substrate-based blockchains, which is achieved through
|
||||
//! Bizinikiwi-based blockchains, which is achieved through
|
||||
//! [`crate::reference_docs::wasm_meta_protocol`]. You can learn more about the details of how to
|
||||
//! deal with these upgrades in [`crate::reference_docs::frame_runtime_upgrades_and_migrations`].
|
||||
//!
|
||||
@@ -9,9 +9,9 @@
|
||||
//! it is hard to know the types internal to the runtime, specifically in light of the fact that
|
||||
//! they can change at any point in time.
|
||||
//!
|
||||
//! This is why all Substrate-based runtimes must expose a [`sp_api::Metadata`] api, which mandates
|
||||
//! the runtime to return a description of itself. The return type of this api is `Vec<u8>`, meaning
|
||||
//! that it is up to the runtime developer to decide on the format of this.
|
||||
//! This is why all Bizinikiwi-based runtimes must expose a [`pezsp_api::Metadata`] api, which
|
||||
//! mandates the runtime to return a description of itself. The return type of this api is
|
||||
//! `Vec<u8>`, meaning that it is up to the runtime developer to decide on the format of this.
|
||||
//!
|
||||
//! All [`crate::pezkuwi_sdk::frame_runtime`] based runtimes expose a specific metadata language,
|
||||
//! maintained in <https://github.com/paritytech/frame-metadata> which is adopted in the Pezkuwi
|
||||
|
||||
@@ -20,17 +20,17 @@
|
||||
//! We call this class of documents "reference documents". Our goal should be to minimize the number
|
||||
//! of "reference" docs, as they incur maintenance burden.
|
||||
|
||||
/// Learn how Substrate and FRAME use traits and associated types to make modules generic in a
|
||||
/// Learn how Bizinikiwi and FRAME use traits and associated types to make modules generic in a
|
||||
/// type-safe manner.
|
||||
pub mod trait_based_programming;
|
||||
|
||||
/// Learn about the way Substrate and FRAME view their blockchains as state machines.
|
||||
/// Learn about the way Bizinikiwi and FRAME view their blockchains as state machines.
|
||||
pub mod blockchain_state_machines;
|
||||
|
||||
/// The glossary.
|
||||
pub mod glossary;
|
||||
|
||||
/// Learn about the WASM meta-protocol of all Substrate-based chains.
|
||||
/// Learn about the WASM meta-protocol of all Bizinikiwi-based chains.
|
||||
pub mod wasm_meta_protocol;
|
||||
|
||||
/// Learn about the differences between smart contracts and a FRAME-based runtime. They are both
|
||||
@@ -60,8 +60,8 @@ pub mod defensive_programming;
|
||||
/// `RuntimeCall`.
|
||||
pub mod frame_runtime_types;
|
||||
|
||||
/// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to
|
||||
/// control usage and sybil attacks.
|
||||
/// Learn about how to make a pezpallet/runtime that is fee-less and instead uses another mechanism
|
||||
/// to control usage and sybil attacks.
|
||||
pub mod fee_less_runtime;
|
||||
|
||||
/// Learn about metadata, the main means through which an upgradeable runtime communicates its
|
||||
@@ -71,14 +71,14 @@ pub mod metadata;
|
||||
/// Learn about how to add custom host functions to the node.
|
||||
pub mod custom_host_functions;
|
||||
|
||||
/// Learn about how frame-system handles `account-ids`, nonces, consumers and providers.
|
||||
pub mod frame_system_accounts;
|
||||
/// Learn about how pezframe-system handles `account-ids`, nonces, consumers and providers.
|
||||
pub mod pezframe_system_accounts;
|
||||
|
||||
/// Advice for configuring your development environment for Substrate development.
|
||||
/// Advice for configuring your development environment for Bizinikiwi development.
|
||||
pub mod development_environment_advice;
|
||||
|
||||
/// Learn about benchmarking and weight.
|
||||
pub mod frame_benchmarking_weight;
|
||||
pub mod pezframe_benchmarking_weight;
|
||||
|
||||
/// Learn about the token-related logic in FRAME and how to apply it to your use case.
|
||||
pub mod frame_tokens;
|
||||
@@ -86,7 +86,7 @@ pub mod frame_tokens;
|
||||
/// Learn about chain specification file and the genesis state of the blockchain.
|
||||
pub mod chain_spec_genesis;
|
||||
|
||||
/// Learn about Substrate's CLI, and how it can be extended.
|
||||
/// Learn about Bizinikiwi's CLI, and how it can be extended.
|
||||
pub mod cli;
|
||||
|
||||
/// Learn about Runtime Upgrades and best practices for writing Migrations.
|
||||
@@ -112,5 +112,5 @@ pub mod custom_runtime_api_rpc;
|
||||
/// The [`pezkuwi-omni-node`](https://crates.io/crates/polkadot-omni-node) and its related binaries.
|
||||
pub mod omni_node;
|
||||
|
||||
/// Learn about the state in Substrate.
|
||||
/// Learn about the state in Bizinikiwi.
|
||||
pub mod state;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
//! # (Omni) Node
|
||||
//!
|
||||
//! This reference doc elaborates on what a Pezkuwi-SDK/Substrate node software is, and what
|
||||
//! This reference doc elaborates on what a Pezkuwi-SDK/Bizinikiwi node software is, and what
|
||||
//! various ways exist to run one.
|
||||
//!
|
||||
//! The node software, as denoted in [`crate::reference_docs::wasm_meta_protocol`], is everything in
|
||||
//! a blockchain other than the WASM runtime. It contains common components such as the database,
|
||||
//! networking, RPC server and consensus. Substrate-based nodes are native binaries that are
|
||||
//! networking, RPC server and consensus. Bizinikiwi-based nodes are native binaries that are
|
||||
//! compiled down from the Rust source code. The `node` folder in any of the [`templates`] are
|
||||
//! examples of this source.
|
||||
//!
|
||||
@@ -30,7 +30,7 @@
|
||||
//!
|
||||
//! > The notorious `service.rs` in any node template is a good example of this.
|
||||
//!
|
||||
//! A [trend](https://github.com/pezkuwichain/pezkuwi-sdk/issues/97) has already been undergoing in
|
||||
//! A [trend](https://github.com/pezkuwichain/pezkuwi-sdk/issues/243) has already been undergoing in
|
||||
//! order to de-couple the node and the runtime for a long time. The north star of this effort is
|
||||
//! twofold :
|
||||
//!
|
||||
@@ -42,7 +42,7 @@
|
||||
//! is the latter.
|
||||
//!
|
||||
//! > Note: The OmniNodes are mainly focused on the development needs of **Pezkuwi
|
||||
//! > teyrchains ONLY**, not (Substrate) solo-chains. For the time being, solo-chains are not
|
||||
//! > teyrchains ONLY**, not (Bizinikiwi) solo-chains. For the time being, solo-chains are not
|
||||
//! > supported by the OmniNodes. This might change in the future.
|
||||
//!
|
||||
//! ## Types of Nodes
|
||||
@@ -95,7 +95,7 @@
|
||||
//! * [`crate::guides::your_first_runtime`]
|
||||
//! * If need be, the weights of the runtime need to be updated using `frame-omni-bencher`.
|
||||
//! References:
|
||||
//! * [`crate::reference_docs::frame_benchmarking_weight`]
|
||||
//! * [`crate::reference_docs::pezframe_benchmarking_weight`]
|
||||
//! * Next, [`chain-spec-builder`] is used to generate a `chain_spec.json`, either for development,
|
||||
//! or for production. References:
|
||||
//! * [`crate::reference_docs::chain_spec_genesis`]
|
||||
@@ -115,21 +115,21 @@
|
||||
//!
|
||||
//! ### Consensus Engine
|
||||
//!
|
||||
//! In any given substrate-based chain, both the node and the runtime will have their own
|
||||
//! In any given bizinikiwi-based chain, both the node and the runtime will have their own
|
||||
//! opinion/information about what consensus engine is going to be used.
|
||||
//!
|
||||
//! In practice, the majority of the implementation of any consensus engine is in the node side, but
|
||||
//! the runtime also typically needs to expose a custom runtime-api to enable the particular
|
||||
//! consensus engine to work, and that particular runtime-api is implemented by a pallet
|
||||
//! consensus engine to work, and that particular runtime-api is implemented by a pezpallet
|
||||
//! corresponding to that consensus engine.
|
||||
//!
|
||||
//! For example, taking a snippet from [`solochain_template_runtime`], the runtime has to provide
|
||||
//! this additional runtime-api (compared to [`minimal_template_runtime`]), if the node software is
|
||||
//! configured to use the Aura consensus engine:
|
||||
//! For example, taking a snippet from [`pez_solochain_template_runtime`], the runtime has to
|
||||
//! provide this additional runtime-api (compared to [`pez_minimal_template_runtime`]), if the node
|
||||
//! software is configured to use the Aura consensus engine:
|
||||
//!
|
||||
//! ```text
|
||||
//! impl sp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
||||
//! fn slot_duration() -> sp_consensus_aura::SlotDuration {
|
||||
//! impl pezsp_consensus_aura::AuraApi<Block, AuraId> for Runtime {
|
||||
//! fn slot_duration() -> pezsp_consensus_aura::SlotDuration {
|
||||
//! ...
|
||||
//! }
|
||||
//! fn authorities() -> Vec<AuraId> {
|
||||
@@ -145,17 +145,17 @@
|
||||
//!
|
||||
//! For block authoring, there are a number of options:
|
||||
//!
|
||||
//! * [`sc_consensus_manual_seal`]: Useful for testing, where any node can produce a block at any
|
||||
//! * [`pezsc_consensus_manual_seal`]: Useful for testing, where any node can produce a block at any
|
||||
//! time. This is often combined with a fixed interval at which a block is produced.
|
||||
//! * [`sc_consensus_aura`]/[`pallet_aura`]: A simple round-robin block authoring mechanism.
|
||||
//! * [`sc_consensus_babe`]/[`pallet_babe`]: A more advanced block authoring mechanism, capable of
|
||||
//! anonymizing the next block author.
|
||||
//! * [`sc_consensus_pow`]: Proof of Work block authoring.
|
||||
//! * [`pezsc_consensus_aura`]/[`pezpallet_aura`]: A simple round-robin block authoring mechanism.
|
||||
//! * [`pezsc_consensus_babe`]/[`pezpallet_babe`]: A more advanced block authoring mechanism,
|
||||
//! capable of anonymizing the next block author.
|
||||
//! * [`pezsc_consensus_pow`]: Proof of Work block authoring.
|
||||
//!
|
||||
//! For finality, there is one main option shipped with pezkuwi-sdk:
|
||||
//!
|
||||
//! * [`sc_consensus_grandpa`]/[`pallet_grandpa`]: A finality gadget that uses a voting mechanism to
|
||||
//! decide when a block
|
||||
//! * [`pezsc_consensus_grandpa`]/[`pezpallet_grandpa`]: A finality gadget that uses a voting
|
||||
//! mechanism to decide when a block
|
||||
//!
|
||||
//! **The most important lesson here is that the node and the runtime must have matching consensus
|
||||
//! components.**
|
||||
@@ -171,10 +171,10 @@
|
||||
//! scaling). [`pezkuwi_omni_node_lib::cli::Cli::experimental_use_slot_based`] for fixed factor
|
||||
//! scaling (a step
|
||||
//! * Ability to run any runtime with [`--dev-block-time`] flag. This uses
|
||||
//! [`sc_consensus_manual_seal`] under the hood, and has no restrictions on the runtime's
|
||||
//! [`pezsc_consensus_manual_seal`] under the hood, and has no restrictions on the runtime's
|
||||
//! consensus.
|
||||
//!
|
||||
//! [This](https://github.com/pezkuwichain/pezkuwi-sdk/issues/143) future improvement to OmniNode
|
||||
//! [This](https://github.com/pezkuwichain/pezkuwi-sdk/issues/286) future improvement to OmniNode
|
||||
//! aims to make such checks automatic.
|
||||
//!
|
||||
//! ### Runtime conventions
|
||||
@@ -185,17 +185,17 @@
|
||||
//! failure.
|
||||
//!
|
||||
//! The list of checks may evolve in the future and for now only few rules are implemented:
|
||||
//! * runtimes must define a type for [`cumulus-pallet-teyrchain-system`], which is recommended to
|
||||
//! be named as `TeyrchainSystem`.
|
||||
//! * runtimes must define a type for [`frame-system`] pallet, which is recommended to be named as
|
||||
//! `System`. The configured [`block number`] here will be used by Omni Node to configure AURA
|
||||
//! accordingly.
|
||||
//! * runtimes must define a type for [`pezcumulus-pezpallet-teyrchain-system`], which is
|
||||
//! recommended to be named as `TeyrchainSystem`.
|
||||
//! * runtimes must define a type for [`pezframe-system`] pezpallet, which is recommended to be
|
||||
//! named as `System`. The configured [`block number`] here will be used by Omni Node to configure
|
||||
//! AURA accordingly.
|
||||
//!
|
||||
//! [`templates`]: crate::pezkuwi_sdk::templates
|
||||
//! [`teyrchain-template`]: https://github.com/pezkuwichain/pezkuwi-sdk-teyrchain-template
|
||||
//! [`--dev-block-time`]: pezkuwi_omni_node_lib::cli::Cli::dev_block_time
|
||||
//! [`pezkuwi-omni-node`]: https://crates.io/crates/polkadot-omni-node
|
||||
//! [`chain-spec-builder`]: https://crates.io/crates/staging-chain-spec-builder
|
||||
//! [`cumulus-pallet-teyrchain-system`]: https://docs.rs/cumulus-pallet-parachain-system/latest/cumulus_pallet_parachain_system/
|
||||
//! [`frame-system`]: https://docs.rs/frame-system/latest/frame_system/
|
||||
//! [`chain-spec-builder`]: https://crates.io/crates/pezstaging-chain-spec-builder
|
||||
//! [`pezcumulus-pezpallet-teyrchain-system`]: https://docs.rs/cumulus-pallet-parachain-system/latest/cumulus_pallet_parachain_system/
|
||||
//! [`pezframe-system`]: https://docs.rs/frame-system/latest/frame_system/
|
||||
//! [`block number`]: https://docs.rs/frame-system/latest/frame_system/pallet/storage_types/struct.Number.html
|
||||
|
||||
+26
-26
@@ -47,13 +47,13 @@
|
||||
//! the 20ms. In a benchmarked environment, it can examine the transactions for their upper bound,
|
||||
//! and include the ones that are known to fit based on the worst case.
|
||||
//!
|
||||
//! The benchmarking code can be written as a part of FRAME pallet, using the macros provided in
|
||||
//! [`frame_benchmarking`]. See any of the existing pallets in `pezkuwi-sdk`, or the pallets in our
|
||||
//! [`crate::pezkuwi_sdk::templates`] for examples.
|
||||
//! The benchmarking code can be written as a part of FRAME pezpallet, using the macros provided in
|
||||
//! [`pezframe_benchmarking`]. See any of the existing pallets in `pezkuwi-sdk`, or the pallets in
|
||||
//! our [`crate::pezkuwi_sdk::templates`] for examples.
|
||||
//!
|
||||
//! ## Weight
|
||||
//!
|
||||
//! Finally, [`sp_weights::Weight`] is the output of the benchmarking process. It is a
|
||||
//! Finally, [`pezsp_weights::Weight`] is the output of the benchmarking process. It is a
|
||||
//! two-dimensional data structure that demonstrates the resources consumed by a given block of
|
||||
//! code (for example, a transaction). The two dimensions are:
|
||||
//!
|
||||
@@ -67,29 +67,29 @@
|
||||
//! it captures the worst case execution of any block of code.
|
||||
//!
|
||||
//! Consider:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer)]
|
||||
#![doc = docify::embed!("./src/reference_docs/pezframe_benchmarking_weight.rs", simple_transfer)]
|
||||
//!
|
||||
//! If this block of code is to be benchmarked, then the benchmarking code must be written such that
|
||||
//! it captures the worst case.
|
||||
//!
|
||||
//! ## Gluing Pallet Benchmarking with Runtime
|
||||
//! ## Gluing Pezpallet Benchmarking with Runtime
|
||||
//!
|
||||
//! FRAME pallets are mandated to provide their own benchmarking code. Runtimes contain the
|
||||
//! boilerplate needed to run these benchmarking (see [Running Benchmarks
|
||||
//! below](#running-benchmarks)). The outcome of running these benchmarks are meant to be fed back
|
||||
//! into the pallet via a conventional `trait WeightInfo` on `Config`:
|
||||
#![doc = docify::embed!("src/reference_docs/frame_benchmarking_weight.rs", WeightInfo)]
|
||||
//! into the pezpallet via a conventional `trait WeightInfo` on `Config`:
|
||||
#![doc = docify::embed!("src/reference_docs/pezframe_benchmarking_weight.rs", WeightInfo)]
|
||||
//!
|
||||
//! Then, individual functions of this trait are the final values that we assigned to the
|
||||
//! [`frame::pallet_macros::weight`] attribute:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer_2)]
|
||||
//! [`pezframe::pezpallet_macros::weight`] attribute:
|
||||
#![doc = docify::embed!("./src/reference_docs/pezframe_benchmarking_weight.rs", simple_transfer_2)]
|
||||
//!
|
||||
//! ## Manual Refund
|
||||
//!
|
||||
//! Back to the assumption of writing benchmarks for worst case: Sometimes, the pre-dispatch weight
|
||||
//! significantly differ from the post-dispatch actual weight consumed. This can be expressed with
|
||||
//! the following FRAME syntax:
|
||||
#![doc = docify::embed!("./src/reference_docs/frame_benchmarking_weight.rs", simple_transfer_3)]
|
||||
#![doc = docify::embed!("./src/reference_docs/pezframe_benchmarking_weight.rs", simple_transfer_3)]
|
||||
//!
|
||||
//! ## Running Benchmarks
|
||||
//!
|
||||
@@ -114,7 +114,7 @@
|
||||
//!
|
||||
//! Pezkuwi-SDK runtimes use a more performant VM, namely WASM, which does not have metering. In
|
||||
//! return they have to be benchmarked to provide an upper bound on the resources they consume. This
|
||||
//! upper bound is represented as [`sp_weights::Weight`].
|
||||
//! upper bound is represented as [`pezsp_weights::Weight`].
|
||||
//!
|
||||
//! ## Future: PolkaVM
|
||||
//!
|
||||
@@ -130,28 +130,28 @@
|
||||
//! [PolkaVM]: https://github.com/koute/polkavm
|
||||
//! [JAM]: https://graypaper.com
|
||||
|
||||
#[frame::pallet(dev_mode)]
|
||||
#[pezframe::pezpallet(dev_mode)]
|
||||
#[allow(unused_variables, unreachable_code, unused, clippy::diverging_sub_expression)]
|
||||
pub mod pallet {
|
||||
use frame::prelude::*;
|
||||
pub mod pezpallet {
|
||||
use pezframe::prelude::*;
|
||||
|
||||
#[docify::export]
|
||||
pub trait WeightInfo {
|
||||
fn simple_transfer() -> Weight;
|
||||
}
|
||||
|
||||
#[pallet::config]
|
||||
pub trait Config: frame_system::Config {
|
||||
#[pezpallet::config]
|
||||
pub trait Config: pezframe_system::Config {
|
||||
type WeightInfo: WeightInfo;
|
||||
}
|
||||
|
||||
#[pallet::pallet]
|
||||
pub struct Pallet<T>(_);
|
||||
#[pezpallet::pezpallet]
|
||||
pub struct Pezpallet<T>(_);
|
||||
|
||||
#[pallet::call]
|
||||
impl<T: Config> Pallet<T> {
|
||||
#[pezpallet::call]
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
#[docify::export]
|
||||
#[pallet::weight(10_000)]
|
||||
#[pezpallet::weight(10_000)]
|
||||
pub fn simple_transfer(
|
||||
origin: OriginFor<T>,
|
||||
destination: T::AccountId,
|
||||
@@ -167,7 +167,7 @@ pub mod pallet {
|
||||
}
|
||||
|
||||
#[docify::export]
|
||||
#[pallet::weight(T::WeightInfo::simple_transfer())]
|
||||
#[pezpallet::weight(T::WeightInfo::simple_transfer())]
|
||||
pub fn simple_transfer_2(
|
||||
origin: OriginFor<T>,
|
||||
destination: T::AccountId,
|
||||
@@ -184,7 +184,7 @@ pub mod pallet {
|
||||
|
||||
#[docify::export]
|
||||
// This is the worst-case, pre-dispatch weight.
|
||||
#[pallet::weight(T::WeightInfo::simple_transfer())]
|
||||
#[pezpallet::weight(T::WeightInfo::simple_transfer())]
|
||||
pub fn simple_transfer_3(
|
||||
origin: OriginFor<T>,
|
||||
destination: T::AccountId,
|
||||
@@ -195,14 +195,14 @@ pub mod pallet {
|
||||
if destination_exists {
|
||||
// simpler code path
|
||||
// Note that need for .into(), to convert `()` to `PostDispatchInfo`
|
||||
// See: https://docs.pezkuwichain.io/sdk/master/frame_support/dispatch/struct.PostDispatchInfo.html#impl-From%3C()%3E-for-PostDispatchInfo
|
||||
// See: https://docs.pezkuwichain.io/sdk/master/pezframe_support/dispatch/struct.PostDispatchInfo.html#impl-From%3C()%3E-for-PostDispatchInfo
|
||||
Ok(().into())
|
||||
} else {
|
||||
// more complex code path
|
||||
let actual_weight =
|
||||
todo!("this can likely come from another benchmark that is NOT the worst case");
|
||||
let pays_fee = todo!("You can set this to `Pays::Yes` or `Pays::No` to change if this transaction should pay fees");
|
||||
Ok(frame::deps::frame_support::dispatch::PostDispatchInfo {
|
||||
Ok(pezframe::deps::pezframe_support::dispatch::PostDispatchInfo {
|
||||
actual_weight: Some(actual_weight),
|
||||
pays_fee,
|
||||
})
|
||||
+3
-3
@@ -2,9 +2,9 @@
|
||||
//!
|
||||
//! 🚧 Work In Progress 🚧
|
||||
//!
|
||||
//! How `frame_system` handles accountIds. Nonce. Consumers and Providers, reference counting.
|
||||
//! How `pezframe_system` handles accountIds. Nonce. Consumers and Providers, reference counting.
|
||||
|
||||
// - poorly understood topics, needs one great article to rul them all.
|
||||
// - https://github.com/paritytech/substrate/issues/14425
|
||||
// - https://github.com/paritytech/substrate/pull/12951
|
||||
// - https://github.com/pezkuwichain/pezkuwi-sdk/issues/17
|
||||
// - https://github.com/pezkuwichain/pezkuwi-sdk/issues/40
|
||||
// - https://exchange.pezkuwichain.app/questions/263/what-is-the-meaning-of-the-account-provider-sufficients-and-consumer
|
||||
@@ -3,7 +3,7 @@
|
||||
//! *TL;DR*: If you need to create a *Blockchain*, then write a runtime. If you need to create a
|
||||
//! *DApp*, then write a Smart Contract.
|
||||
//!
|
||||
//! This is a comparative analysis of Substrate-based Runtimes and Smart Contracts, highlighting
|
||||
//! This is a comparative analysis of Bizinikiwi-based Runtimes and Smart Contracts, highlighting
|
||||
//! their main differences. Our aim is to equip you with a clear understanding of how these two
|
||||
//! methods of deploying on-chain logic diverge in their design, usage, and implications.
|
||||
//!
|
||||
@@ -12,21 +12,21 @@
|
||||
//! decentralized applications. Understanding their differences is crucial in choosing the right
|
||||
//! approach for a specific solution.
|
||||
//!
|
||||
//! ## Substrate
|
||||
//! Substrate is a modular framework that enables the creation of purpose-specific blockchains. In
|
||||
//! ## Bizinikiwi
|
||||
//! Bizinikiwi is a modular framework that enables the creation of purpose-specific blockchains. In
|
||||
//! the Pezkuwi ecosystem you can find two distinct approaches for on-chain code execution:
|
||||
//! [Runtime Development](#runtime-in-substrate) and [Smart Contracts](#smart-contracts).
|
||||
//! [Runtime Development](#runtime-in-bizinikiwi) and [Smart Contracts](#smart-contracts).
|
||||
//!
|
||||
//! #### Smart Contracts in Substrate
|
||||
//! #### Smart Contracts in Bizinikiwi
|
||||
//! Smart Contracts are autonomous, programmable constructs deployed on the blockchain.
|
||||
//! In [FRAME](frame), Smart Contracts infrastructure is implemented by the
|
||||
//! [`pallet_contracts`] for WASM-based contracts or the
|
||||
//! [`pallet_evm`](https://github.com/polkadot-evm/frontier/tree/master/frame/evm) for EVM-compatible contracts. These pallets
|
||||
//! enable Smart Contract developers to build applications and systems on top of a Substrate-based
|
||||
//! [`pezpallet_contracts`] for WASM-based contracts or the
|
||||
//! [`pezpallet_evm`](https://github.com/polkadot-evm/frontier/tree/master/frame/evm) for EVM-compatible contracts. These pallets
|
||||
//! enable Smart Contract developers to build applications and systems on top of a Bizinikiwi-based
|
||||
//! blockchain.
|
||||
//!
|
||||
//! #### Runtime in Substrate
|
||||
//! The Runtime is the state transition function of a Substrate-based blockchain. It defines the
|
||||
//! #### Runtime in Bizinikiwi
|
||||
//! The Runtime is the state transition function of a Bizinikiwi-based blockchain. It defines the
|
||||
//! rules for processing transactions and blocks, essentially governing the behavior and
|
||||
//! capabilities of a blockchain.
|
||||
//!
|
||||
@@ -35,7 +35,7 @@
|
||||
//! | Aspect | Runtime | Smart Contracts |
|
||||
//! |-----------------------|-------------------------------------------------------------------------|----------------------------------------------------------------------|
|
||||
//! | **Design Philosophy** | Core logic of a blockchain, allowing broad and deep customization. | Designed for DApps deployed on the blockchain runtime. |
|
||||
//! | **Development Complexity** | Requires in-depth knowledge of Rust and Substrate. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). |
|
||||
//! | **Development Complexity** | Requires in-depth knowledge of Rust and Bizinikiwi. Suitable for complex blockchain architectures. | Easier to develop with knowledge of Smart Contract languages like Solidity or [ink!](https://use.ink/). |
|
||||
//! | **Upgradeability and Flexibility** | Offers comprehensive upgradeability with migration logic and on-chain governance, allowing modifications to the entire blockchain logic without hard forks. | Less flexible in upgrade migrations but offers more straightforward deployment and iteration. |
|
||||
//! | **Performance and Efficiency** | More efficient, optimized for specific needs of the blockchain. | Can be less efficient due to its generic nature (e.g. the overhead of a virtual machine). |
|
||||
//! | **Security Considerations** | Security flaws can affect the entire blockchain. | Security risks usually localized to the individual contract. |
|
||||
@@ -70,8 +70,8 @@
|
||||
//! differing purposes and technical requirements.
|
||||
//!
|
||||
//! #### Runtime Development Complexity
|
||||
//! - **In-depth Knowledge Requirements**: Developing a Runtime in Substrate requires a
|
||||
//! comprehensive understanding of Rust, Substrate's framework, and blockchain principles.
|
||||
//! - **In-depth Knowledge Requirements**: Developing a Runtime in Bizinikiwi requires a
|
||||
//! comprehensive understanding of Rust, Bizinikiwi's framework, and blockchain principles.
|
||||
//! - **Complex Blockchain Architectures**: Runtime development is suitable for creating complex
|
||||
//! blockchain architectures. Developers must consider aspects like security, scalability, and
|
||||
//! network efficiency.
|
||||
@@ -108,7 +108,7 @@
|
||||
//! - **Deployment and Iteration**: Smart Contracts, by nature, are designed for more
|
||||
//! straightforward deployment and iteration. Developers can quickly deploy contracts.
|
||||
//! - **Contract Code Updates**: Once deployed, although typically immutable, Smart Contracts can be
|
||||
//! upgraded, but lack of migration logic. The [`pallet_contracts`]
|
||||
//! upgraded, but lack of migration logic. The [`pezpallet_contracts`]
|
||||
//! allows for contracts to be upgraded by exposing the `set_code` dispatchable. More details on this
|
||||
//! can be found in [Ink! documentation on upgradeable contracts](https://use.ink/basics/upgradeable-contracts).
|
||||
//! - **Isolated Impact**: Upgrades or changes to a smart contract generally impact only that
|
||||
@@ -123,7 +123,7 @@
|
||||
//! and optimized for specific needs, while Smart Contracts are more generic and less efficient.
|
||||
//!
|
||||
//! #### Runtime Performance and Efficiency
|
||||
//! - **Optimized for Specific Needs**: Runtime modules in Substrate are tailored to meet the
|
||||
//! - **Optimized for Specific Needs**: Runtime modules in Bizinikiwi are tailored to meet the
|
||||
//! specific needs of the blockchain. They are integrated directly into the blockchain's core,
|
||||
//! allowing them to operate with high efficiency and minimal overhead.
|
||||
//! - **Direct Access to Blockchain State**: Runtime has direct access to the blockchain's state.
|
||||
@@ -181,12 +181,12 @@
|
||||
//! #### Weighing
|
||||
//! In FRAME-based Runtimes, operations are *weighed*. This means that each operation in the Runtime
|
||||
//! has a fixed upper cost, known in advance, determined through
|
||||
//! [benchmarking](crate::reference_docs::frame_benchmarking_weight). Weighing is practical here
|
||||
//! [benchmarking](crate::reference_docs::pezframe_benchmarking_weight). Weighing is practical here
|
||||
//! because:
|
||||
//!
|
||||
//! - *Predictability*: Runtime operations are part of the blockchain's core logic, which is static
|
||||
//! until an upgrade occurs. This predictability allows for precise
|
||||
//! [benchmarking](crate::reference_docs::frame_benchmarking_weight).
|
||||
//! [benchmarking](crate::reference_docs::pezframe_benchmarking_weight).
|
||||
//! - *Prevention of Abuse*: By having a fixed upper cost that corresponds to the worst-case
|
||||
//! complexity scenario of its execution (and a mechanism to refund unused weight), it becomes
|
||||
//! infeasible for an attacker to create transactions that could unpredictably consume excessive
|
||||
|
||||
@@ -9,4 +9,4 @@
|
||||
//! The key-value pairs in the state are represented as byte sequences. The node
|
||||
//! doesn't know how to interpret most the key-value pairs. However, there exist some
|
||||
//! special keys and its values that are known to the node, the so-called
|
||||
//! [`well-known-keys`](sp_storage::well_known_keys).
|
||||
//! [`well-known-keys`](pezsp_storage::well_known_keys).
|
||||
|
||||
@@ -7,29 +7,29 @@
|
||||
//! The rest of this document assumes familiarity with the
|
||||
//! [Rust book's Advanced Traits](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html)
|
||||
//! section.
|
||||
//! Moreover, we use the [`frame::traits::Get`].
|
||||
//! Moreover, we use the [`pezframe::traits::Get`].
|
||||
//!
|
||||
//! First, imagine we are writing a FRAME pallet. We represent this pallet with a `struct Pallet`,
|
||||
//! and this pallet wants to implement the functionalities of that pallet, for example a simple
|
||||
//! `transfer` function. For the sake of education, we are interested in having a `MinTransfer`
|
||||
//! amount, expressed as a [`frame::traits::Get`], which will dictate what is the minimum amount
|
||||
//! that can be transferred.
|
||||
//! First, imagine we are writing a FRAME pezpallet. We represent this pezpallet with a `struct
|
||||
//! Pezpallet`, and this pezpallet wants to implement the functionalities of that pezpallet, for
|
||||
//! example a simple `transfer` function. For the sake of education, we are interested in having a
|
||||
//! `MinTransfer` amount, expressed as a [`pezframe::traits::Get`], which will dictate what is the
|
||||
//! minimum amount that can be transferred.
|
||||
//!
|
||||
//! We can foremost write this as simple as the following snippet:
|
||||
#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", basic)]
|
||||
//!
|
||||
//!
|
||||
//! In this example, we use arbitrary choices for `AccountId`, `Balance` and the `MinTransfer` type.
|
||||
//! This works great for **one team's purposes** but we have to remember that Substrate and FRAME
|
||||
//! This works great for **one team's purposes** but we have to remember that Bizinikiwi and FRAME
|
||||
//! are written as generic frameworks, intended to be highly configurable.
|
||||
//!
|
||||
//! In a broad sense, there are two avenues in exposing configurability:
|
||||
//!
|
||||
//! 1. For *values* that need to be generic, for example `MinTransfer`, we attach them to the
|
||||
//! `Pallet` struct as fields:
|
||||
//! `Pezpallet` struct as fields:
|
||||
//!
|
||||
//! ```
|
||||
//! struct Pallet {
|
||||
//! struct Pezpallet {
|
||||
//! min_transfer: u128,
|
||||
//! }
|
||||
//! ```
|
||||
@@ -38,23 +38,23 @@
|
||||
//! as:
|
||||
//!
|
||||
//! ```
|
||||
//! struct Pallet<AccountId> {
|
||||
//! struct Pezpallet<AccountId> {
|
||||
//! min_transfer: u128,
|
||||
//! _marker: std::marker::PhantomData<AccountId>,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Substrate and FRAME, for various reasons (performance, correctness, type safety) has opted to
|
||||
//! Bizinikiwi and FRAME, for various reasons (performance, correctness, type safety) has opted to
|
||||
//! use *types* to declare both *values* and *types* as generic. This is the essence of why the
|
||||
//! `Get` trait exists.
|
||||
//!
|
||||
//! This would bring us to the second iteration of the pallet, which would look like:
|
||||
//! This would bring us to the second iteration of the pezpallet, which would look like:
|
||||
#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", generic)]
|
||||
//!
|
||||
//! In this example, we managed to make all 3 of our types generic. Taking the example of the
|
||||
//! `AccountId`, one should read the above as following:
|
||||
//!
|
||||
//! > The `Pallet` does not know what type `AccountId` concretely is, but it knows that it is
|
||||
//! > The `Pezpallet` does not know what type `AccountId` concretely is, but it knows that it is
|
||||
//! > something that adheres to being `From<[u8; 32]>`.
|
||||
//!
|
||||
//! This method would work, but it suffers from two downsides:
|
||||
@@ -72,7 +72,7 @@
|
||||
//!
|
||||
//! > Interestingly, one downside of associated types is that declaring defaults on them is not
|
||||
//! > stable yet. In the meantime, we have built our own custom mechanics around declaring defaults
|
||||
//! for associated types, see [`pallet_default_config_example`].
|
||||
//! for associated types, see [`pezpallet_default_config_example`].
|
||||
//!
|
||||
//! The last iteration of our code would look like this:
|
||||
#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", trait_based)]
|
||||
@@ -84,7 +84,7 @@
|
||||
//! having individual `trait Configs` declare a shared `trait SystemConfig` as their
|
||||
//! [supertrait](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html).
|
||||
#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", with_system)]
|
||||
//! In FRAME, this shared supertrait is [`frame::prelude::frame_system`].
|
||||
//! In FRAME, this shared supertrait is [`pezframe::prelude::pezframe_system`].
|
||||
//!
|
||||
//! Notice how this made no difference in the syntax of the rest of the code. `T::AccountId` is
|
||||
//! still a valid type, since `T` implements `Config` and `Config` implies `SystemConfig`, which
|
||||
@@ -103,27 +103,27 @@
|
||||
//! length of fully qualified syntax is a common pattern in FRAME.
|
||||
//!
|
||||
//! The above example is almost identical to the well-known (and somewhat notorious) `type
|
||||
//! BalanceOf` that is often used in the context of [`frame::traits::fungible`].
|
||||
#![doc = docify::embed!("../../substrate/frame/fast-unstake/src/types.rs", BalanceOf)]
|
||||
//! BalanceOf` that is often used in the context of [`pezframe::traits::fungible`].
|
||||
#![doc = docify::embed!("../../bizinikiwi/pezframe/fast-unstake/src/types.rs", BalanceOf)]
|
||||
//!
|
||||
//! ## Additional Resources
|
||||
//!
|
||||
//! - <https://github.com/paritytech/substrate/issues/13836>
|
||||
//! - [Substrate Seminar - Traits and Generic Types](https://www.youtube.com/watch?v=6cp10jVWNl4)
|
||||
//! - <https://github.com/pezkuwichain/pezkuwi-sdk/issues/326>
|
||||
//! - [Bizinikiwi Seminar - Traits and Generic Types](https://www.youtube.com/watch?v=6cp10jVWNl4)
|
||||
//! - <https://exchange.pezkuwichain.app/questions/2228/type-casting-to-trait-t-as-config>
|
||||
#![allow(unused)]
|
||||
|
||||
use frame::traits::Get;
|
||||
use pezframe::traits::Get;
|
||||
|
||||
#[docify::export]
|
||||
mod basic {
|
||||
struct Pallet;
|
||||
struct Pezpallet;
|
||||
|
||||
type AccountId = frame::deps::sp_runtime::AccountId32;
|
||||
type AccountId = pezframe::deps::pezsp_runtime::AccountId32;
|
||||
type Balance = u128;
|
||||
type MinTransfer = frame::traits::ConstU128<10>;
|
||||
type MinTransfer = pezframe::traits::ConstU128<10>;
|
||||
|
||||
impl Pallet {
|
||||
impl Pezpallet {
|
||||
fn transfer(_from: AccountId, _to: AccountId, _amount: Balance) {
|
||||
todo!()
|
||||
}
|
||||
@@ -134,14 +134,14 @@ mod basic {
|
||||
mod generic {
|
||||
use super::*;
|
||||
|
||||
struct Pallet<AccountId, Balance, MinTransfer> {
|
||||
struct Pezpallet<AccountId, Balance, MinTransfer> {
|
||||
_marker: std::marker::PhantomData<(AccountId, Balance, MinTransfer)>,
|
||||
}
|
||||
|
||||
impl<AccountId, Balance, MinTransfer> Pallet<AccountId, Balance, MinTransfer>
|
||||
impl<AccountId, Balance, MinTransfer> Pezpallet<AccountId, Balance, MinTransfer>
|
||||
where
|
||||
Balance: frame::traits::AtLeast32BitUnsigned,
|
||||
MinTransfer: frame::traits::Get<Balance>,
|
||||
Balance: pezframe::traits::AtLeast32BitUnsigned,
|
||||
MinTransfer: pezframe::traits::Get<Balance>,
|
||||
AccountId: From<[u8; 32]>,
|
||||
{
|
||||
fn transfer(_from: AccountId, _to: AccountId, amount: Balance) {
|
||||
@@ -157,12 +157,12 @@ mod trait_based {
|
||||
|
||||
trait Config {
|
||||
type AccountId: From<[u8; 32]>;
|
||||
type Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
type MinTransfer: frame::traits::Get<Self::Balance>;
|
||||
type Balance: pezframe::traits::AtLeast32BitUnsigned;
|
||||
type MinTransfer: pezframe::traits::Get<Self::Balance>;
|
||||
}
|
||||
|
||||
struct Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pallet<T> {
|
||||
struct Pezpallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) {
|
||||
assert!(amount >= T::MinTransfer::get());
|
||||
unimplemented!();
|
||||
@@ -179,12 +179,12 @@ mod with_system {
|
||||
}
|
||||
|
||||
pub trait Config: SystemConfig {
|
||||
type Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
type MinTransfer: frame::traits::Get<Self::Balance>;
|
||||
type Balance: pezframe::traits::AtLeast32BitUnsigned;
|
||||
type MinTransfer: pezframe::traits::Get<Self::Balance>;
|
||||
}
|
||||
|
||||
pub struct Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pallet<T> {
|
||||
pub struct Pezpallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) {
|
||||
assert!(amount >= T::MinTransfer::get());
|
||||
unimplemented!();
|
||||
@@ -205,7 +205,7 @@ mod fully_qualified_complicated {
|
||||
use super::with_system::*;
|
||||
|
||||
trait CurrencyTrait {
|
||||
type Balance: frame::traits::AtLeast32BitUnsigned;
|
||||
type Balance: pezframe::traits::AtLeast32BitUnsigned;
|
||||
fn more_stuff() {}
|
||||
}
|
||||
|
||||
@@ -213,8 +213,8 @@ mod fully_qualified_complicated {
|
||||
type Currency: CurrencyTrait;
|
||||
}
|
||||
|
||||
struct Pallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pallet<T> {
|
||||
struct Pezpallet<T: Config>(std::marker::PhantomData<T>);
|
||||
impl<T: Config> Pezpallet<T> {
|
||||
fn transfer(
|
||||
_from: T::AccountId,
|
||||
_to: T::AccountId,
|
||||
|
||||
@@ -5,53 +5,54 @@
|
||||
//!
|
||||
//! FRAME by default already provides the following transaction extensions:
|
||||
//!
|
||||
//! - [`CheckGenesis`](frame_system::CheckGenesis): Ensures that a transaction was sent for the same
|
||||
//! network. Determined based on genesis.
|
||||
//! - [`CheckGenesis`](pezframe_system::CheckGenesis): Ensures that a transaction was sent for the
|
||||
//! same network. Determined based on genesis.
|
||||
//!
|
||||
//! - [`CheckMortality`](frame_system::CheckMortality): Extends a transaction with a configurable
|
||||
//! - [`CheckMortality`](pezframe_system::CheckMortality): Extends a transaction with a configurable
|
||||
//! mortality.
|
||||
//!
|
||||
//! - [`CheckNonZeroSender`](frame_system::CheckNonZeroSender): Ensures that the sender of a
|
||||
//! - [`CheckNonZeroSender`](pezframe_system::CheckNonZeroSender): Ensures that the sender of a
|
||||
//! transaction is not the *all zero account* (all bytes of the accountid are zero).
|
||||
//!
|
||||
//! - [`CheckNonce`](frame_system::CheckNonce): Extends a transaction with a nonce to prevent replay
|
||||
//! of transactions and to provide ordering of transactions.
|
||||
//! - [`CheckNonce`](pezframe_system::CheckNonce): Extends a transaction with a nonce to prevent
|
||||
//! replay of transactions and to provide ordering of transactions.
|
||||
//!
|
||||
//! - [`CheckSpecVersion`](frame_system::CheckSpecVersion): Ensures that a transaction was built for
|
||||
//! the currently active runtime.
|
||||
//! - [`CheckSpecVersion`](pezframe_system::CheckSpecVersion): Ensures that a transaction was built
|
||||
//! for the currently active runtime.
|
||||
//!
|
||||
//! - [`CheckTxVersion`](frame_system::CheckTxVersion): Ensures that the transaction signer used the
|
||||
//! correct encoding of the call.
|
||||
//! - [`CheckTxVersion`](pezframe_system::CheckTxVersion): Ensures that the transaction signer used
|
||||
//! the correct encoding of the call.
|
||||
//!
|
||||
//! - [`CheckWeight`](frame_system::CheckWeight): Ensures that the transaction fits into the block
|
||||
//! before dispatching it.
|
||||
//! - [`CheckWeight`](pezframe_system::CheckWeight): Ensures that the transaction fits into the
|
||||
//! block before dispatching it.
|
||||
//!
|
||||
//! - [`ChargeTransactionPayment`](pallet_transaction_payment::ChargeTransactionPayment): Charges
|
||||
//! - [`ChargeTransactionPayment`](pezpallet_transaction_payment::ChargeTransactionPayment): Charges
|
||||
//! transaction fees from the signer based on the weight of the call using the native token.
|
||||
//!
|
||||
//! - [`ChargeAssetTxPayment`](pallet_asset_tx_payment::ChargeAssetTxPayment): Charges transaction
|
||||
//! fees from the signer based on the weight of the call using any supported asset (including the
|
||||
//! native token).
|
||||
//! - [`ChargeAssetTxPayment`](pezpallet_asset_tx_payment::ChargeAssetTxPayment): Charges
|
||||
//! transaction fees from the signer based on the weight of the call using any supported asset
|
||||
//! (including the native token).
|
||||
//!
|
||||
//! - [`ChargeAssetTxPayment`(using
|
||||
//! conversion)](pallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction
|
||||
//! conversion)](pezpallet_asset_conversion_tx_payment::ChargeAssetTxPayment): Charges transaction
|
||||
//! fees from the signer based on the weight of the call using any supported asset (including the
|
||||
//! native token). The asset is converted to the native token using a pool.
|
||||
//!
|
||||
//! - [`SkipCheckIfFeeless`](pallet_skip_feeless_payment::SkipCheckIfFeeless): Allows transactions
|
||||
//! to be processed without paying any fee. This requires that the `call` that should be
|
||||
//! dispatched is augmented with the [`feeless_if`](frame_support::pallet_macros::feeless_if)
|
||||
//! attribute.
|
||||
//! - [`SkipCheckIfFeeless`](pezpallet_skip_feeless_payment::SkipCheckIfFeeless): Allows
|
||||
//! transactions to be processed without paying any fee. This requires that the `call` that should
|
||||
//! be dispatched is augmented with the
|
||||
//! [`feeless_if`](pezframe_support::pezpallet_macros::feeless_if) attribute.
|
||||
//!
|
||||
//! - [`CheckMetadataHash`](frame_metadata_hash_extension::CheckMetadataHash): Extends transactions
|
||||
//! to include the so-called metadata hash. This is required by chains to support the generic
|
||||
//! Ledger application and other similar offline wallets.
|
||||
//! - [`CheckMetadataHash`](pezframe_metadata_hash_extension::CheckMetadataHash): Extends
|
||||
//! transactions to include the so-called metadata hash. This is required by chains to support the
|
||||
//! generic Ledger application and other similar offline wallets.
|
||||
//!
|
||||
//! - [`WeightReclaim`](frame_system::WeightReclaim): A transaction extension for the relay chain
|
||||
//! - [`WeightReclaim`](pezframe_system::WeightReclaim): A transaction extension for the relay chain
|
||||
//! that reclaims unused weight after executing a transaction.
|
||||
//!
|
||||
//! - [`StorageWeightReclaim`](cumulus_pallet_weight_reclaim::StorageWeightReclaim): A transaction
|
||||
//! extension for teyrchains that reclaims unused storage weight after executing a transaction.
|
||||
//! - [`StorageWeightReclaim`](pezcumulus_pezpallet_weight_reclaim::StorageWeightReclaim): A
|
||||
//! transaction extension for teyrchains that reclaims unused storage weight after executing a
|
||||
//! transaction.
|
||||
//!
|
||||
//! For more information about these extensions, follow the link to the type documentation.
|
||||
//!
|
||||
@@ -63,12 +64,12 @@
|
||||
#[docify::export]
|
||||
pub mod transaction_extensions_example {
|
||||
use codec::{Decode, DecodeWithMemTracking, Encode};
|
||||
use scale_info::TypeInfo;
|
||||
use sp_runtime::{
|
||||
use pezsp_runtime::{
|
||||
impl_tx_ext_default,
|
||||
traits::{Dispatchable, TransactionExtension},
|
||||
transaction_validity::TransactionValidityError,
|
||||
};
|
||||
use scale_info::TypeInfo;
|
||||
|
||||
// This doesn't actually check anything, but simply allows
|
||||
// some arbitrary `u32` to be added to the extrinsic payload
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
//! crate in the repo, with `default-features = false`.
|
||||
//!
|
||||
//! For more fine-grained control, additionally, each crate can be enabled selectively. The umbrella
|
||||
//! exposes one feature per dependency. For example, if you only want to use the `frame-support`
|
||||
//! crate, you can enable the `frame-support` feature.
|
||||
//! exposes one feature per dependency. For example, if you only want to use the `pezframe-support`
|
||||
//! crate, you can enable the `pezframe-support` feature.
|
||||
//!
|
||||
//! The umbrella exposes a few more general features:
|
||||
//! - `tuples-96`: Needs to be enabled for runtimes that have more than 64 pallets.
|
||||
@@ -43,7 +43,8 @@
|
||||
//!
|
||||
//! ## Usage
|
||||
//!
|
||||
//! > Note: You can see a live example in the `staging-node-cli` and `kitchensink-runtime` crates.
|
||||
//! > Note: You can see a live example in the `pezstaging-node-cli` and `pez-kitchensink-runtime`
|
||||
//! > crates.
|
||||
//!
|
||||
//! The umbrella crate can be added to your runtime crate like this:
|
||||
//!
|
||||
@@ -70,10 +71,10 @@
|
||||
//!
|
||||
//! mod foo {
|
||||
//! // This does sadly not compile:
|
||||
//! frame_support::parameter_types! { }
|
||||
//! pezframe_support::parameter_types! { }
|
||||
//!
|
||||
//! // Instead, we need to do this (or add an equivalent `use` statement):
|
||||
//! pezkuwi_sdk::frame_support::parameter_types! { }
|
||||
//! pezkuwi_sdk::pezframe_support::parameter_types! { }
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! # WASM Meta Protocol
|
||||
//!
|
||||
//! All Substrate based chains adhere to a unique architectural design novel to the Pezkuwi
|
||||
//! All Bizinikiwi based chains adhere to a unique architectural design novel to the Pezkuwi
|
||||
//! ecosystem. We refer to this design as the "**WASM Meta Protocol**".
|
||||
//!
|
||||
//! Consider the fact that a traditional blockchain software is usually a monolithic artifact.
|
||||
@@ -12,12 +12,12 @@
|
||||
//! Moreover, the idea of "storing code in the state" is explored in the context of smart contracts
|
||||
//! platforms, but has not been expanded further.
|
||||
//!
|
||||
//! Substrate mixes these two ideas together, and takes the novel approach of storing the
|
||||
//! Bizinikiwi mixes these two ideas together, and takes the novel approach of storing the
|
||||
//! blockchain's main "state transition function" in the main blockchain state, in the same fashion
|
||||
//! that a smart contract platform stores the code of individual contracts in its state. As noted in
|
||||
//! [`crate::reference_docs::blockchain_state_machines`], this state transition function is called
|
||||
//! the **Runtime**, and WASM is chosen as the bytecode. The Runtime is stored under a special key
|
||||
//! in the state (see [`sp_core::storage::well_known_keys`]) and can be updated as a part of the
|
||||
//! in the state (see [`pezsp_core::storage::well_known_keys`]) and can be updated as a part of the
|
||||
//! state transition function's execution, just like a user's account balance can be updated.
|
||||
//!
|
||||
//! > Note that while we drew an analogy between smart contracts and runtimes in the above, there
|
||||
@@ -28,24 +28,24 @@
|
||||
//! [**Node**](crate::reference_docs::glossary#node), and is a normal binary that is compiled from
|
||||
//! Rust to different hardware targets.
|
||||
//!
|
||||
//! This design enables all Substrate-based chains to be fork-less-ly upgradeable, because the
|
||||
//! This design enables all Bizinikiwi-based chains to be fork-less-ly upgradeable, because the
|
||||
//! Runtime can be updated on the fly, within the execution of a block, and the node is (for the
|
||||
//! most part) oblivious to the change that is happening.
|
||||
//!
|
||||
//! Therefore, the high-level architecture of a any Substrate-based chain can be demonstrated as
|
||||
//! Therefore, the high-level architecture of a any Bizinikiwi-based chain can be demonstrated as
|
||||
//! follows:
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_simple.mmd")]
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_simple.mmd")]
|
||||
//!
|
||||
//! The node and the runtime need to communicate. This is done through two concepts:
|
||||
//!
|
||||
//! 1. **Host functions**: a way for the (WASM) runtime to talk to the node. All host functions are
|
||||
//! defined in [`sp_io`]. For example, [`sp_io::storage`] are the set of host functions that
|
||||
//! allow the runtime to read and write data to the on-chain state.
|
||||
//! defined in [`pezsp_io`]. For example, [`pezsp_io::storage`] are the set of host functions
|
||||
//! that allow the runtime to read and write data to the on-chain state.
|
||||
//! 2. **Runtime APIs**: a way for the node to talk to the WASM runtime. Runtime APIs are defined
|
||||
//! using macros and utilities in [`sp_api`]. For example, [`sp_api::Core`] is the most
|
||||
//! using macros and utilities in [`pezsp_api`]. For example, [`pezsp_api::Core`] is the most
|
||||
//! fundamental runtime API that any blockchain must implement in order to be able to (re)
|
||||
//! execute blocks.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_client_runtime.mmd")]
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_client_runtime.mmd")]
|
||||
//!
|
||||
//! A runtime must have a set of runtime APIs in order to have any meaningful blockchain
|
||||
//! functionality, but it can also expose more APIs. See
|
||||
@@ -78,12 +78,12 @@
|
||||
//! > The consensus is to your runtime what HTTP is to a web-application. It is the underlying
|
||||
//! > engine that enables trustless execution of the runtime in a distributed manner whilst
|
||||
//! > maintaining a canonical outcome of that execution.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_with_frame.mmd")]
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_with_frame.mmd")]
|
||||
//!
|
||||
//! ## State
|
||||
//!
|
||||
//! From the previous sections, we know that the database component is part of the node, not the
|
||||
//! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime
|
||||
//! runtime. We also hinted that a set of host functions ([`pezsp_io::storage`]) are how the runtime
|
||||
//! issues commands to the node to read/write to the state. Let's dive deeper into this.
|
||||
//!
|
||||
//! The state of the blockchain, what we seek to come to consensus about, is indeed *kept* in the
|
||||
@@ -92,7 +92,7 @@
|
||||
//! 1. Can update the state.
|
||||
//! 2. Can fully interpret the state.
|
||||
//!
|
||||
//! In fact, [`sp_core::storage::well_known_keys`] are the only state keys that the node side is
|
||||
//! In fact, [`pezsp_core::storage::well_known_keys`] are the only state keys that the node side is
|
||||
//! aware of. The rest of the state, including what logic the runtime has, what balance each user
|
||||
//! has and such, are all only comprehensible to the runtime.
|
||||
#![doc = simple_mermaid::mermaid!("../../../mermaid/state.mmd")]
|
||||
@@ -102,7 +102,7 @@
|
||||
//! (e.g. if it is a number of a vector). Contrary, the runtime knows both the meaning of their
|
||||
//! keys, and the type of the values.
|
||||
//!
|
||||
//! This opaque-ness is the fundamental reason why Substrate-based chains can fork-less-ly upgrade:
|
||||
//! This opaque-ness is the fundamental reason why Bizinikiwi-based chains can fork-less-ly upgrade:
|
||||
//! because the node side code is kept oblivious to all of the details of the state transition
|
||||
//! function. Therefore, the state transition function can freely upgrade without the node needing
|
||||
//! to know.
|
||||
@@ -115,10 +115,10 @@
|
||||
//! infrastructure of native code. However, neither of the two arguments strongly hold and the
|
||||
//! native runtime is being fully removed from the node-sdk.
|
||||
//!
|
||||
//! See: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/97>
|
||||
//! See: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/243>
|
||||
//!
|
||||
//! > Also, note that the flags [`sc_cli::ExecutionStrategy::Native`] is already a noop and all
|
||||
//! > chains built with Substrate only use WASM execution.
|
||||
//! > Also, note that the flags [`pezsc_cli::ExecutionStrategy::Native`] is already a noop and all
|
||||
//! > chains built with Bizinikiwi only use WASM execution.
|
||||
//!
|
||||
//! ### Runtime Versions
|
||||
//!
|
||||
@@ -126,18 +126,18 @@
|
||||
//! obviously, only uses the native runtime if it is the same code as with the wasm blob stored
|
||||
//! onchain. Else, nodes who run the native runtime will come to a different state transition. How
|
||||
//! do nodes determine if two runtimes are the same? Through the very important
|
||||
//! [`sp_version::RuntimeVersion`]. All runtimes expose their version via a runtime api
|
||||
//! ([`sp_api::Core::version`]) that returns this struct. The node software, or other applications,
|
||||
//! inspect this struct to examine the identity of a runtime, and to determine if two runtimes are
|
||||
//! the same. Namely, [`sp_version::RuntimeVersion::spec_version`] is the main key that implies two
|
||||
//! runtimes are the same.
|
||||
//! [`pezsp_version::RuntimeVersion`]. All runtimes expose their version via a runtime api
|
||||
//! ([`pezsp_api::Core::version`]) that returns this struct. The node software, or other
|
||||
//! applications, inspect this struct to examine the identity of a runtime, and to determine if two
|
||||
//! runtimes are the same. Namely, [`pezsp_version::RuntimeVersion::spec_version`] is the main key
|
||||
//! that implies two runtimes are the same.
|
||||
//!
|
||||
//! Therefore, it is utmost important to make sure before any runtime upgrade, the spec version is
|
||||
//! updated.
|
||||
//!
|
||||
//! ## Example: Block Execution.
|
||||
//!
|
||||
//! As a final example to recap, let's look at how Substrate-based nodes execute blocks. Blocks are
|
||||
//! As a final example to recap, let's look at how Bizinikiwi-based nodes execute blocks. Blocks are
|
||||
//! received in the node side software as opaque blobs and in the networking layer.
|
||||
//!
|
||||
//! At some point, based on the consensus algorithm's rules, the node decides to import (aka.
|
||||
@@ -146,10 +146,10 @@
|
||||
//! * First, the node will fetch the state of the parent hash of the block that wishes to be
|
||||
//! imported.
|
||||
//! * The runtime is fetched from this state, and placed into a WASM execution environment.
|
||||
//! * The [`sp_api::Core::execute_block`] runtime API is called and the block is passed in as an
|
||||
//! * The [`pezsp_api::Core::execute_block`] runtime API is called and the block is passed in as an
|
||||
//! argument.
|
||||
//! * The runtime will then execute the block, and update the state accordingly. Any state update is
|
||||
//! issued via the [`sp_io::storage`] host functions.
|
||||
//! issued via the [`pezsp_io::storage`] host functions.
|
||||
//! * Both the runtime and node will check the state-root of the state after the block execution to
|
||||
//! match the one claimed in the block header.
|
||||
//!
|
||||
|
||||
Reference in New Issue
Block a user