From a451f7eef9b5f9e3a53a49400aad6542a163d1ed Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 09:55:26 +0000 Subject: [PATCH 01/66] add developer-hub and all things related --- .github/workflows/docs.yml | 34 + .gitignore | 2 +- Cargo.lock | 60 +- Cargo.toml | 5 +- cumulus/parachain-template/runtime/src/lib.rs | 3 +- .../pallets/collective-content/src/mock.rs | 4 +- .../src/fellowship/migration.rs | 1 - developer-hub/Cargo.toml | 60 ++ developer-hub/headers/toc.html | 47 ++ developer-hub/src/lib.rs | 116 +++ developer-hub/src/polkadot_sdk/cumulus.rs | 133 ++++ .../src/polkadot_sdk/frame_runtime.rs | 122 +++ developer-hub/src/polkadot_sdk/mod.rs | 121 +++ developer-hub/src/polkadot_sdk/polkadot.rs | 13 + .../src/polkadot_sdk/smart_contracts.rs | 1 + developer-hub/src/polkadot_sdk/substrate.rs | 149 ++++ developer-hub/src/polkadot_sdk/templates.rs | 6 + .../reference_docs/blockchain_scalibility.rs | 0 .../blockchain_state_machines.rs | 29 + .../src/reference_docs/extrinsic_encoding.rs | 289 +++++++ .../src/reference_docs/fee_less_runtime.rs | 0 .../reference_docs/frame_composite_enums.rs | 1 + developer-hub/src/reference_docs/glossary.rs | 17 + developer-hub/src/reference_docs/mod.rs | 58 ++ .../origin_account_abstraction.rs | 0 .../runtime_vs_smart_contract.rs | 0 .../safe_defensive_programming.rs | 0 .../src/reference_docs/signed_extensions.rs | 79 ++ .../reference_docs/trait_based_programming.rs | 226 ++++++ .../src/reference_docs/wasm_meta_protocol.rs | 107 +++ .../src/tutorial/currency_simple/mod.rs | 737 ++++++++++++++++++ .../tutorial/currency_simple/with_event.rs | 101 +++ developer-hub/src/tutorial/mod.rs | 8 + docs/mermaid/IA.mmd | 13 + docs/mermaid/extrinsics.mmd | 5 + docs/mermaid/polkadot_sdk.mmd | 26 + docs/mermaid/state.mmd | 16 + docs/mermaid/stf.mmd | 21 + docs/mermaid/stf_simple.mmd | 4 + substrate/Cargo.toml | 28 - substrate/frame/asset-conversion/src/mock.rs | 4 +- substrate/frame/balances/src/tests/mod.rs | 4 +- .../election-provider-multi-phase/src/mock.rs | 6 +- .../frame/examples/kitchensink/src/lib.rs | 5 +- substrate/frame/fast-unstake/src/types.rs | 1 + substrate/frame/src/lib.rs | 38 +- substrate/frame/support/procedural/src/lib.rs | 52 +- .../procedural/src/pallet/parse/call.rs | 47 +- substrate/frame/support/src/dispatch.rs | 3 +- substrate/frame/support/src/lib.rs | 155 +++- substrate/frame/system/Cargo.toml | 2 + substrate/frame/system/src/lib.rs | 30 +- substrate/frame/tx-pause/src/mock.rs | 6 +- substrate/primitives/runtime/Cargo.toml | 3 + .../runtime/src/generic/checked_extrinsic.rs | 8 +- .../src/generic/unchecked_extrinsic.rs | 33 +- substrate/src/lib.rs | 238 ------ 57 files changed, 2870 insertions(+), 407 deletions(-) create mode 100644 .github/workflows/docs.yml create mode 100644 developer-hub/Cargo.toml create mode 100644 developer-hub/headers/toc.html create mode 100644 developer-hub/src/lib.rs create mode 100644 developer-hub/src/polkadot_sdk/cumulus.rs create mode 100644 developer-hub/src/polkadot_sdk/frame_runtime.rs create mode 100644 developer-hub/src/polkadot_sdk/mod.rs create mode 100644 developer-hub/src/polkadot_sdk/polkadot.rs create mode 100644 developer-hub/src/polkadot_sdk/smart_contracts.rs create mode 100644 developer-hub/src/polkadot_sdk/substrate.rs create mode 100644 developer-hub/src/polkadot_sdk/templates.rs create mode 100644 developer-hub/src/reference_docs/blockchain_scalibility.rs create mode 100644 developer-hub/src/reference_docs/blockchain_state_machines.rs create mode 100644 developer-hub/src/reference_docs/extrinsic_encoding.rs create mode 100644 developer-hub/src/reference_docs/fee_less_runtime.rs create mode 100644 developer-hub/src/reference_docs/frame_composite_enums.rs create mode 100644 developer-hub/src/reference_docs/glossary.rs create mode 100644 developer-hub/src/reference_docs/mod.rs create mode 100644 developer-hub/src/reference_docs/origin_account_abstraction.rs create mode 100644 developer-hub/src/reference_docs/runtime_vs_smart_contract.rs create mode 100644 developer-hub/src/reference_docs/safe_defensive_programming.rs create mode 100644 developer-hub/src/reference_docs/signed_extensions.rs create mode 100644 developer-hub/src/reference_docs/trait_based_programming.rs create mode 100644 developer-hub/src/reference_docs/wasm_meta_protocol.rs create mode 100644 developer-hub/src/tutorial/currency_simple/mod.rs create mode 100644 developer-hub/src/tutorial/currency_simple/with_event.rs create mode 100644 developer-hub/src/tutorial/mod.rs create mode 100644 docs/mermaid/IA.mmd create mode 100644 docs/mermaid/extrinsics.mmd create mode 100644 docs/mermaid/polkadot_sdk.mmd create mode 100644 docs/mermaid/state.mmd create mode 100644 docs/mermaid/stf.mmd create mode 100644 docs/mermaid/stf_simple.mmd delete mode 100644 substrate/Cargo.toml delete mode 100644 substrate/src/lib.rs diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000000..7c9404c66c90 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,34 @@ +name: Rust Docs + +on: + push: + branches: [kiz-umbrella-crates] + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + # Setup protoc + - name: Set up Protocol Buffers + uses: arduino/setup-protoc@v1 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rust-docs + target: wasm32-unknown-unknown + + - name: Generate docs + run: cargo doc -p developer-hub -p sp-io -p sp-runtime -p frame -p frame-support --no-deps + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@v4 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages # The branch the action should deploy to. + FOLDER: target/doc # The folder the action should deploy. diff --git a/.gitignore b/.gitignore index 7feea8ada5c5..b475465e167b 100644 --- a/.gitignore +++ b/.gitignore @@ -29,7 +29,7 @@ artifacts bin/node-template/Cargo.lock nohup.out polkadot_argument_parsing -polkadot.* +polkadot pwasm-alloc/Cargo.lock pwasm-libc/Cargo.lock release-artifacts diff --git a/Cargo.lock b/Cargo.lock index c95cc70b0da4..9a00f6214b81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4409,6 +4409,29 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "developer-hub" +version = "0.0.1" +dependencies = [ + "cumulus-pallet-aura-ext", + "cumulus-pallet-parachain-system", + "docify", + "frame", + "pallet-aura", + "pallet-default-config-example", + "pallet-timestamp", + "parachain-info", + "parity-scale-codec", + "scale-info", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?branch=main)", + "sp-api", + "sp-core", + "sp-io", + "sp-keyring", + "sp-runtime", + "substrate-wasm-builder", +] + [[package]] name = "diff" version = "0.1.13" @@ -5209,7 +5232,7 @@ dependencies = [ "pallet-examples", "parity-scale-codec", "scale-info", - "simple-mermaid", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?rev=e48b187bcfd5cc75111acd9d241f1bd36604344b)", "sp-api", "sp-arithmetic", "sp-block-builder", @@ -5569,6 +5592,7 @@ version = "4.0.0-dev" dependencies = [ "cfg-if", "criterion 0.4.0", + "docify", "frame-support", "log", "parity-scale-codec", @@ -11270,9 +11294,9 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" dependencies = [ "arrayvec 0.7.4", "bitvec", @@ -11285,9 +11309,9 @@ dependencies = [ [[package]] name = "parity-scale-codec-derive" -version = "3.6.4" +version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -16576,6 +16600,11 @@ dependencies = [ "wide", ] +[[package]] +name = "simple-mermaid" +version = "0.1.0" +source = "git+https://github.com/kianenigma/simple-mermaid.git?branch=main#e48b187bcfd5cc75111acd9d241f1bd36604344b" + [[package]] name = "simple-mermaid" version = "0.1.0" @@ -17354,6 +17383,7 @@ dependencies = [ name = "sp-runtime" version = "24.0.0" dependencies = [ + "docify", "either", "hash256-std-hasher", "impl-trait-for-tuples", @@ -17364,6 +17394,7 @@ dependencies = [ "scale-info", "serde", "serde_json", + "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?branch=main)", "sp-api", "sp-application-crypto", "sp-arithmetic", @@ -17924,25 +17955,6 @@ dependencies = [ "sc-cli", ] -[[package]] -name = "substrate" -version = "1.0.0" -dependencies = [ - "chain-spec-builder", - "frame-support", - "sc-cli", - "sc-consensus-aura", - "sc-consensus-babe", - "sc-consensus-beefy", - "sc-consensus-grandpa", - "sc-consensus-manual-seal", - "sc-consensus-pow", - "sc-service", - "simple-mermaid", - "sp-runtime", - "subkey", -] - [[package]] name = "substrate-bip39" version = "0.4.4" diff --git a/Cargo.toml b/Cargo.toml index 2c63aabf9352..f8a0c453d5bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ license = "GPL-3.0-only" resolver = "2" members = [ + "developer-hub", "bridges/bin/runtime-common", "bridges/modules/grandpa", "bridges/modules/messages", @@ -181,7 +182,6 @@ members = [ "polkadot/xcm/xcm-simulator/fuzzer", "substrate/bin/minimal/node", "substrate/bin/minimal/runtime", - "substrate", "substrate/bin/node-template/node", "substrate/bin/node-template/pallets/template", "substrate/bin/node-template/runtime", @@ -463,8 +463,7 @@ default-members = [ "polkadot", "substrate/bin/node/cli" ] panic = "unwind" opt-level = 3 -# make sure dev builds with backtrace do -# not slow us down +# make sure dev builds with backtrace do not slow us down [profile.dev.package.backtrace] inherits = "release" diff --git a/cumulus/parachain-template/runtime/src/lib.rs b/cumulus/parachain-template/runtime/src/lib.rs index bfb3e74be9c0..401304184435 100644 --- a/cumulus/parachain-template/runtime/src/lib.rs +++ b/cumulus/parachain-template/runtime/src/lib.rs @@ -488,8 +488,7 @@ impl pallet_parachain_template::Config for Runtime { // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( - pub enum Runtime - { + pub struct Runtime { // System support stuff. System: frame_system = 0, ParachainSystem: cumulus_pallet_parachain_system = 1, diff --git a/cumulus/parachains/pallets/collective-content/src/mock.rs b/cumulus/parachains/pallets/collective-content/src/mock.rs index 2ae5943f332a..350cd421b49d 100644 --- a/cumulus/parachains/pallets/collective-content/src/mock.rs +++ b/cumulus/parachains/pallets/collective-content/src/mock.rs @@ -96,9 +96,7 @@ impl WeightInfo for CCWeightInfo { // Build test environment. pub fn new_test_ext() -> sp_io::TestExternalities { let t = RuntimeGenesisConfig::default().build_storage().unwrap().into(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + sp_io::TestExternalities::new(t) } #[cfg(feature = "runtime-benchmarks")] diff --git a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs index 9350d03a2c9f..ef01ce2de474 100644 --- a/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs +++ b/cumulus/parachains/runtimes/collectives/collectives-polkadot/src/fellowship/migration.rs @@ -238,7 +238,6 @@ pub mod tests { let t = frame_system::GenesisConfig::::default().build_storage().unwrap(); let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); ext.execute_with(|| { assert_eq!(MemberCount::::get(0), 0); Migration::::on_runtime_upgrade(); diff --git a/developer-hub/Cargo.toml b/developer-hub/Cargo.toml new file mode 100644 index 000000000000..304173e7250d --- /dev/null +++ b/developer-hub/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "developer-hub" +description = "The one stop shop for developers of the polakdot-sdk" +license = "GPL-3.0-or-later WITH Classpath-exception-2.0" +homepage = "paritytech.github.io" +repository.workspace = true +authors.workspace = true +edition.workspace = true +# This crate is not publish-able to crates.io for now because of docify. +publish = false +version = "0.0.1" + +[dependencies] +# Needed for all FRAME-based code +parity-scale-codec = { version = "3.0.0", default-features = false } +scale-info = { version = "2.6.0", default-features = false } +frame = { path = "../substrate/frame", features = ["runtime", "experimental"] } + +# How we build docs in rust-docs +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } +docify = "0.2.6" + +# Polkadot SDK docs, typically all should only be scope such that we can link to their doc item. +# node-cli = { path = "../substrate/bin/node/cli" } +# kitchensink-runtime = { path = "../substrate/bin/node/runtime" } +# chain-spec-builder = { path = "../substrate/bin/utils/chain-spec-builder" } +# subkey = { path = "../substrate/bin/utils/subkey" } + +# sc-network = { path = "../substrate/client/network" } +# sc-rpc-api = { path = "../substrate/client/rpc-api" } +# sc-rpc = { path = "../substrate/client/rpc" } +# sc-client-db = { path = "../substrate/client/db" } +# sc-cli = { path = "../substrate/client/cli" } +# sc-consensus-aura = { path = "../substrate/client/consensus/aura" } +# sc-consensus-babe = { path = "../substrate/client/consensus/babe" } +# sc-consensus-grandpa = { path = "../substrate/client/consensus/grandpa" } +# sc-consensus-beefy = { path = "../substrate/client/consensus/beefy" } +# sc-consensus-manual-seal = { path = "../substrate/client/consensus/manual-seal" } +# sc-consensus-pow = { path = "../substrate/client/consensus/pow" } + +sp-io = { path = "../substrate/primitives/io" } +sp-api = { path = "../substrate/primitives/api" } +sp-core = { path = "../substrate/primitives/core" } +sp-keyring = { path = "../substrate/primitives/keyring" } +sp-runtime = { path = "../substrate/primitives/runtime" } + +substrate-wasm-builder = { path = "../substrate/utils/wasm-builder" } + +pallet-default-config-example = { path = "../substrate/frame/examples/default-config" } + +[dev-dependencies] +cumulus-pallet-aura-ext = { path = "../cumulus/pallets/aura-ext" } +cumulus-pallet-parachain-system = { path = "../cumulus/pallets/parachain-system", features = ["parameterized-consensus-hook"] } +parachain-info = { path = "../cumulus/parachains/pallets/parachain-info" } +pallet-aura = { path = "../substrate/frame/aura" } +pallet-timestamp = { path = "../substrate/frame/timestamp" } + +parity-scale-codec = "3.6.5" +scale-info = "2.9.0" + diff --git a/developer-hub/headers/toc.html b/developer-hub/headers/toc.html new file mode 100644 index 000000000000..4520fd29072a --- /dev/null +++ b/developer-hub/headers/toc.html @@ -0,0 +1,47 @@ + + diff --git a/developer-hub/src/lib.rs b/developer-hub/src/lib.rs new file mode 100644 index 000000000000..f8a168813968 --- /dev/null +++ b/developer-hub/src/lib.rs @@ -0,0 +1,116 @@ +//! # Developer Hub +//! +//! The Polkadot SDK Developer Hub. +//! +//! This crate is meant to be a *minimal*, but *always-accurate* source of information for those +//! wishing to build on the Polkadot SDK. +//! +//! ## Getting Started +//! +//! We suggest the following reading sequence: +//! +//! - Start by learning about the structure of the [`polkadot_sdk`] and its context. +//! - Then, head over the [`tutorial`] to get more hand-on practice. +//! - Whilst reading the tutorial, you might find back-links to [`reference_docs`]. +//! - Finally, is the parent website of this crate that hosts the +//! documentation of other related projects. +//! +//! ## Information Architecture +//! +//! This section paints a picture over the information architecture of this crate. In short, the +//! list of modules below is the starting point. Each module has a short description of what it is +//! covering. +//! +//! In a more visual representation, the information architecture of this crate is as follows: +#![doc = simple_mermaid::mermaid!("../../docs/mermaid/IA.mmd")] +//! +//! ## Contribution +//! +//! The following sections cover more detailed information about this crate and how it should be +//! maintained. +//! +//! ### Checklist +//! +//! TODO +//! +//! ### Note on `crates.io` and Publishing +//! +//! TODO: This crate cannot be published for now, and that is fine. We use `paritytech.github.io` as +//! the entry point. +//! TODO: link checker. +//! +//! ### Why Rust Docs? +//! +//! We acknowledge that blockchain based systems, particularly a cutting-edge one like the +//! Polkadot-Sdk is a software artifact that is complex, and rapidly evolving. This makes the task +//! of documenting it externally extremely difficult, especially with regards to making sure it is +//! up-to-date. +//! +//! Consequently, we argue that the best hedge against this is to move as much of the documentation +//! near the source code as possible. This would further incentivizes developers to keep the +//! documentation up-to-date, as the overhead is reduced by making sure everything is in one +//! repository, and everything being in `.rs` files. +//! +//! > This is not say that a more visually appealing version of this crate (for example as an +//! > `md-book`) cannot exist, but it would be the outside the scope of this crate. +//! +//! Moreover, we acknowledge that a major pain-pint of the past has been not only outdated +//! *concepts*, but also *outdated code*. For this, we commit to making sure no code-snippet in this +//! crate is left as `"/`/`/`ignore"`, making sure all code snippets are self-contained, +//! compile-able, and correct at every single revision of the entire repository. This also allows us +//! to have a clear versioning on the entire content of this crate. For every commit of the +//! Polkadot-Sdk, there would be one version of this crate that is guaranteed to be correct. +//! +//! > To achieve this, we often use [`docify`](https://github.com/sam0x17/docify), a nifty invention +//! > of `@sam0x17`. +//! +//! Also see: . +//! +//! ### Scope +//! +//! The above would NOT be unattainable if we don't acknowledge that the scope of this crate MUST be +//! limited, or else its maintenance burden would be infeasible or not worthwhile. In short, future +//! maintainers should always strive to keep the content of this repository as minimal as possible. +//! Some of the following principles are specifically there to be the guidance for this. +//! +//! ## Principles +//! +//! The following guidelines are meant to be the guiding torch of those who contribute to this +//! crate. +//! +//! 1. πŸ”Ί Ground Up: Information should be layed out in the most ground-up fashion. The lowest level +//! (ie. "ground") is Rust-docs. The highest level (ie "up") is "outside of this crate". In +//! between lies [`reference_docs`] and [`tutorial`], from low to high. The point of this +//! principle is to document as much of the information is possible in the lower lever mediums, +//! as it is easier to maintain. Then, use excessive linking to back-link when writing in a more +//! high level. Moreover, lower level mediums are often accessible to more readers. +//! +//! > A prime example of this, the details of the FRAME storage APIs should NOT be explained in a +//! > high level tutorial. They should be explained in the rust-doc of the corresponding type or +//! > macro. +//! +//! 2. 🧘 Less is More: For reasons mentioned [above](#crate::why-rust-docs), the more concise this +//! crate is, the better. +//! 3. √ Don’t Repeat Yourself – DRY: A summary of the above two points. Authors should always +//! strive to avoid any duplicate information. Every concept should ideally be documented in +//! *ONE* place and one place only. This makes the task of maintaining topics significantly +//! easier. +//! +//! > 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 (eg. `sc_cli`). +//! +//! For more details about documenting guidelines, see: +//! +#![warn(rustdoc::broken_intra_doc_links)] +#![warn(rustdoc::private_intra_doc_links)] + +/// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, +/// the tools that are provided as a part of it, and to gain a high level understanding of each. +pub mod polkadot_sdk; +/// Reference documents covering in-depth topics across the Polkadot SDK. It is suggested to read +/// these on-demand, while you are going through the [`tutorial`] or other content. +pub mod reference_docs; +/// The main polkadot-sdk tutorial, targeted toward those who wish to build parachains FRAME and +/// Cumulus. +pub mod tutorial; diff --git a/developer-hub/src/polkadot_sdk/cumulus.rs b/developer-hub/src/polkadot_sdk/cumulus.rs new file mode 100644 index 000000000000..8d90cbe7b224 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/cumulus.rs @@ -0,0 +1,133 @@ +//! # Cumulus +//! +//! Substrate provides a framework through which a blockchain node and runtime can easily be +//! created. Cumulus aims to extend the same approach to creation of Polkadot parachains. +//! +//! > 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 a normal [FRAME]-based runtime. Most notably, the +//! following changes are applied to a normal FRAME-based runtime to make it a cumulus-based +//! runtime: +//! +//! #### Cumulus Pallets +//! +//! A parachain runtime should use a number of pallets that are provided by Cumulus. Notably: +//! +//! - [`frame-system`], like all FRAME-based runtimes. +//! - [`cumulus-pallet-parachain-system`] +//! - [`parachain-info`] +#![doc = docify::embed!("./src/polkadot_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/lib.rs", consensus_pallets)] +//! +//! +//! Finally, a separate macro, similar to `impl_runtime_api`, which create the default set of +//! runtime apis, will generate the parachain runtime's main additional runtime api, also known as +//! PVF. +#![doc = docify::embed!("./src/polkadot_sdk/cumulus.rs", validate_block)] +//! +//! +//! ## Example: Running a node +//! +//! TODO +//! +//! --- +//! +//! +//! [FRAME]: https://paritytech.github.io/polkadot-sdk/master/frame/ +//! [`frame_system`]: https://paritytech.github.io/polkadot-sdk/master/frame_system/ + +#![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 struct Runtime { + // system-level pallets. + System: frame_system, + Timestamp: pallet_timestamp, + ParachainSystem: cumulus_pallet_parachain_system, + ParachainInfo: parachain_info, + + // parachain 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 as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode; + } + + impl cumulus_pallet_parachain_system::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type OnSystemEvent = (); + type SelfParaId = parachain_info::Pallet; + type OutboundXcmpMessageSource = (); + type DmpMessageHandler = (); + type ReservedDmpWeight = (); + type XcmpMessageHandler = (); + type ReservedXcmpWeight = (); + type CheckAssociatedRelayNumber = + cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases; + type ConsensusHook = cumulus_pallet_aura_ext::FixedVelocityConsensusHook< + Runtime, + 6000, // relay chain block time + 1, + 1, + >; + } + + impl parachain_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; + #[cfg(feature = "experimental")] + type SlotDuration = pallet_aura::MinimumPeriodTimesTwo; + } + + #[docify::export(timestamp)] + #[derive_impl(pallet_timestamp::config_preludes::TestDefaultConfig as pallet_timestamp::DefaultConfig)] + impl pallet_timestamp::Config for Runtime {} + + impl cumulus_pallet_aura_ext::Config for Runtime {} + } + + #[docify::export(validate_block)] + cumulus_pallet_parachain_system::register_validate_block! { + Runtime = Runtime, + BlockExecutor = cumulus_pallet_aura_ext::BlockExecutor::, + } + } +} diff --git a/developer-hub/src/polkadot_sdk/frame_runtime.rs b/developer-hub/src/polkadot_sdk/frame_runtime.rs new file mode 100644 index 000000000000..30bff8ad91e7 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/frame_runtime.rs @@ -0,0 +1,122 @@ +//! # FRAME +//! +//! ```co_compile +//! ______ ______ ________ ___ __ __ ______ +//! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ +//! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ +//! \:\/___/\\:(_) ) )_\::(_) \ \\:. \ \\:\/___/\ +//! \:::._\/ \: __ `\ \\:: __ \ \\:.\-/\ \ \\::___\/_ +//! \:\ \ \ \ `\ \ \\:.\ \ \ \\. \ \ \ \\:\____/\ +//! \_\/ \_\/ \_\/ \__\/\__\/ \__\/ \__\/ \_____\/ +//! ``` +//! +//! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's +//! > State Transition Function (Runtime) Framework. +//! +//! ## Introduction +//! +//! recall from [`crate::reference_docs::wasm_meta_protocol`] that at a very high, a substrate-based +//! blockchain is made with it is 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 client whose primary purpose is to execute the given runtime. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_simple.mmd")] +//! +//! *FRAME is the Substrate'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 +//! linked to other pallets. Each pallet should try 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. +//! +//! 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: +//! +//! - [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 aka. Extrinsics](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. +//! +//! Most of these components are defined using macros, the full list of which can be found in +//! [`frame::pallet_macros`] +//! +//! ### Example +//! +//! The following examples showcases a minimal pallet. +#![doc = docify::embed!("src/polkadot_sdk/frame_runtime.rs", pallet)] +//! +//! ## Runtime +//! +//! A runtime is a collection of pallets that are amalgamated together. Each pallet 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`]. +//! +//! 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::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. +#![doc = docify::embed!("src/polkadot_sdk/frame_runtime.rs", runtime)] + +#[cfg(test)] +mod tests { + use frame::prelude::*; + + #[docify::export] + #[frame::pallet(dev_mode)] + pub mod pallet { + use super::*; + + #[pallet::config] + pub trait Config: frame_system::Config { + type RuntimeEvent: IsType<::RuntimeEvent> + + From>; + } + + #[pallet::pallet] + pub struct Pallet(PhantomData); + + #[pallet::event] + pub enum Event {} + + #[pallet::storage] + pub type Value = StorageValue; + + #[pallet::call] + impl Pallet { + pub fn some_dispatchable(_origin: OriginFor) -> DispatchResult { + Ok(()) + } + } + } + + #[docify::export] + pub mod runtime { + use super::pallet as pallet_example; + use frame::{prelude::*, testing_prelude::*}; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + Example: pallet_example, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + } + + impl pallet_example::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + } + } +} diff --git a/developer-hub/src/polkadot_sdk/mod.rs b/developer-hub/src/polkadot_sdk/mod.rs new file mode 100644 index 000000000000..a7b0c687b2da --- /dev/null +++ b/developer-hub/src/polkadot_sdk/mod.rs @@ -0,0 +1,121 @@ +//! # Polkadot SDK +//! +//! The [Polkadot SDK repository](https://github.com/paritytech/polkadot-sdk) provides all the +//! resources needed to start building on the [Polkadot network](https://polkadot.network), a +//! multi-chain blockchain platform that enables different blockchains to interoperate and share +//! information in a secure and scalable way. +//! +//! [![StackExchange](https://img.shields.io/badge/StackExchange-Polkadot%20and%20Substrate-222222?logo=stackexchange)](https://substrate.stackexchange.com/) +//! +//! [![awesomeDot](https://img.shields.io/badge/polkadot-awesome-e6007a?logo=polkadot)](https://github.com/Awsmdot/awesome-dot) +//! [![awesomeDot](https://img.shields.io/badge/polkadot-wiki-e6007a?logo=polkadot)](https://wiki.polkadot.network/) +//! [![awesomeDot](https://img.shields.io/badge/polkadot-forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) +//! +//! [![RFCs](https://img.shields.io/badge/fellowship-RFCs-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/rfcs) +//! [![Runtime](https://img.shields.io/badge/fellowship-runtimes-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/runtimes) +//! [![Manifesto](https://img.shields.io/badge/fellowship-manifesto-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/manifesto) +//! +//! +//! ## Getting Started +//! +//! The primary way to get started with the Polkadot SDK is to start writing a Substrate-based +//! runtime using FRAME. See: +//! +//! 1. [`substrate`], for an overview of what Substrate is. +//! 2. Jump right into [`frame`] to learn about how to write a FRAME-based blockchain runtime. +//! 3. Continue with the [`developer_hub`'s "getting started"](crate#getting-started). +//! +//! ## Structure +//! +//! This repository is a nested +//! [workspace](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html), containing the +//! following major software artifacts: +//! +//! #### Substrate +//! +//! [![Substrate-license](https://img.shields.io/badge/License-GPL3%2FApache2.0-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/LICENSE-APACHE2) +//! [![GitHub Repo](https://img.shields.io/badge/github-substrate-2324CC85)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame) +//! +//! [`substrate`] is the base blockchain framework used to power the Polkadot SDK. It is a full +//! toolkit to create sovereign blockchains, including but not limited to those who connect to +//! Polkadot as parachains. +//! +//! #### FRAME +//! +//! [![Substrate-license](https://img.shields.io/badge/License-Apache2.0-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/LICENSE-APACHE2) +//! [![GitHub Repo](https://img.shields.io/badge/github-frame-2324CC85)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/frame) +//! +//! [`frame`] is the framework used to create Substrate-based runtimes. Learn more +//! +//! #### Cumulus +//! +//! [![Cumulus-license](https://img.shields.io/badge/License-GPL3-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/cumulus/LICENSE) +//! [![GitHub Repo](https://img.shields.io/badge/github-cumulus-white)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/cumulus) +//! +//! [`cumulus`] transforms FRAME-based runtimes into Polkadot-compatible parachain runtimes, and +//! substrate-based client into Polkadot-compatible collators. +//! +//! #### Polkadot +//! +//! [![Polkadot-license](https://img.shields.io/badge/License-GPL3-blue)](https://github.com/paritytech/polkadot-sdk/blob/master/polkadot/LICENSE) +//! [![GitHub Repo](https://img.shields.io/badge/github-polkadot-e6007a?logo=polkadot)](https://github.com/paritytech/polkadot-sdk/blob/master/substrate/polkadot) +//! +//! Recall from [Substrate's architecture](`polkadot_sdk::substrate#architecture`) that any +//! substrate-based chain is composed of two parts: A client, and a runtime. +//! +//! [`polkadot`] is an implementation of a Polkadot client in Rust, by `@paritytech`. The Polkadot +//! runtimes are located under the `fellowship/runtime` repository. +//! +//! > [`polkadot`] contains useful links to further learn about Polkadot, **but is in general not +//! > part of the SDK**, as it is rarely used by developers who wish to build on top of Polkadot. +//! +//! ### Summary +//! +//! The following diagram summarizes how components of the Polkadot-SDK work together: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/polkadot_sdk.mmd")] +//! +//! 1. A Substrate-based chain is a blockchain composed of a "Runtime" and a "Client". As noted +//! above, the "Runtime" is the application logic of the blockchain, and the "Client" 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 Substrate client +//! libraries. +//! 2. Polkadot is itself a Substrate-based chain, composed of the the exact same two components. +//! The Polkadot client code is in [`polkadot`], and the Polkadot runtimes are controlled by the +//! Polkadot Fellowship. +//! 3. A parachain is a "special" Substrate based chain, whereby both the client and the runtime +//! components have became "Polkadot-aware" using Cumulus. +//! +//! ## History +//! +//! Substrate, Polkadot and Cumulus used to each have their own repository, each of which is now +//! archived. For historical context about how they merged into this mono-repo, see: +//! +//! - +//! - +//! +//! [`substrate`]: crate::polkadot_sdk::substrate +//! [`frame`]: crate::polkadot_sdk::frame_runtime +//! [`cumulus`]: crate::polkadot_sdk::cumulus +//! [`polkadot`]: crate::polkadot_sdk::polkadot +//! +//! ## Notable Upstream Crates: +//! +//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) +//! - [`parity-db`](https://github.com/paritytech/parity-db) +//! - [`trie`](https://github.com/paritytech/trie) +//! - [`parity-common`](https://github.com/paritytech/parity-common) + +/// Lean about Cumulus, the framework that transforms [`substrate`]-based chains into +/// [`polkadot`]-enabled parachains. +pub mod cumulus; +/// Learn about FRAME, the framework used to build Substrate runtimes. +pub mod frame_runtime; +/// Learn about Polkadot as a platform. +pub mod polkadot; +/// Learn about different ways through which smart contracts can be utilized on top of Substrate, +/// and in the Polkadot ecosystem. +pub mod smart_contracts; +/// Learn about Substrate, the main blockchain framework used in the Polkadot ecosystem. +pub mod substrate; +/// Index of all the templates that can act as an initial scaffold for a new project. +pub mod templates; diff --git a/developer-hub/src/polkadot_sdk/polkadot.rs b/developer-hub/src/polkadot_sdk/polkadot.rs new file mode 100644 index 000000000000..d6bbcd4d7fea --- /dev/null +++ b/developer-hub/src/polkadot_sdk/polkadot.rs @@ -0,0 +1,13 @@ +//! # Polkadot +//! +//! Implementation of the Polkadot host in Rust. +//! +//! ## Getting Involved +//! +//! [![PolkadotForum](https://img.shields.io/badge/Polkadot_Forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) +//! - RFCs TODO +//! - Polkadot Fellowship TODO +//! - Polkadot Specs +//! - Polkadot Implementor's guide +//! +//! ## What is Polkadot diff --git a/developer-hub/src/polkadot_sdk/smart_contracts.rs b/developer-hub/src/polkadot_sdk/smart_contracts.rs new file mode 100644 index 000000000000..7837baf7a303 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/smart_contracts.rs @@ -0,0 +1 @@ +//! Under Construction diff --git a/developer-hub/src/polkadot_sdk/substrate.rs b/developer-hub/src/polkadot_sdk/substrate.rs new file mode 100644 index 000000000000..65c7b40ba8e5 --- /dev/null +++ b/developer-hub/src/polkadot_sdk/substrate.rs @@ -0,0 +1,149 @@ +//! # 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 Polkadot 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 achieve 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 "Client") 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. 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`]. +//! +//! [`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 Stared +//! +//! While most developer develop using [`crate::polkadot_sdk::frame_runtime`], it is worth noting a +//! few (niche) alternatives: +//! +//! 1.It is entirely possible to craft a substrate-based runtime without FRAME, an example of which +//! can be found [here](https://github.com/JoshOrndorff/frameless-node-template). +//! 2. Substrate's client side code, as mentioned above, is also highly configurable, and many teams +//! embark on customizing the client, for example with a custom consensus algorithm. Notable +//! examples of this are: +//! +//! - +//! - +//! +//! 3. A number of substrate-based templates are listed in [`crate::polkadot_sdk::templates`]. +//! +//! ## Structure +//! +//! Substrate is a massive cargo workspace with hundreds of crates, therefore it is useful to know +//! how to navigate its crates. +//! +//! In broad terms, it is divided into three categories: +//! +//! * `sc-*` (short for *substrate-client*) crates, located under `./client` folder. These are all +//! the client crates. Notable examples are crates such as [`sc_network`], various consensus +//! crates, [`sc_rpc_api`] and [`sc_client_db`], all of which are expected to reside in the client +//! side. +//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These +//! are the traits that glue the client and runtime together, 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 client 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 commandsOnce built, the wasm file is placed in +//! `./target/{debug|release}/wbuild/{runtime_name}.wasm`. +//! +//! ### Binaries +//! +//! Multiple binaries are shipped with substrate, the most important of which are located in the +//! [`./bin`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin) folder. +//! +//! * [`node_cli`] is an extensive substrate node that contains the superset of all runtime and +//! client 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. +//! * [`chain_spec_builder`]: Utility to build more detailed chain-specs for the aforementioned +//! node. Other projects typically contain a `build-spec` subcommand that does the same. +//! * [`node_template`](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/bin/node-template): +//! a template node that contains a minimal set of features and can act as a starting point of a +//! project. +//! * [`subkey`]: Substrate's key management utility. +//! +//! ### 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 point, and a `./service.rs`, which contains all the +//! client side components. Skimming this file yields an overview of the networking, database, +//! consensus and similar client side components. +//! +//! > The above two are conventions, not rules. +//! +//! > See for an update on how the client side +//! > components are being amalgamated. +//! +//! ## Parachain? +//! +//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways +//! through which Polkadot can be utilized is by building "parachains", blockchains that are +//! connected to Polkadot's shared security. +//! +//! To build a parachain, one could use [`crate::polkadot_sdk::cumulus`], the library on top +//! of Substrate, empowering any substrate-based chain to be a Polkadot parachain. +//! +//! ## 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) +//! - [`sc_consensus_manual_seal`] +//! - [`sc_consensus_pow`] + +#[doc(hidden)] +pub use crate::polkadot_sdk; diff --git a/developer-hub/src/polkadot_sdk/templates.rs b/developer-hub/src/polkadot_sdk/templates.rs new file mode 100644 index 000000000000..bd1a2520334f --- /dev/null +++ b/developer-hub/src/polkadot_sdk/templates.rs @@ -0,0 +1,6 @@ +//! # Templates +//! +//! - classic [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) +//! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) +//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) +//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) diff --git a/developer-hub/src/reference_docs/blockchain_scalibility.rs b/developer-hub/src/reference_docs/blockchain_scalibility.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/blockchain_state_machines.rs b/developer-hub/src/reference_docs/blockchain_state_machines.rs new file mode 100644 index 000000000000..fcffe7ee7783 --- /dev/null +++ b/developer-hub/src/reference_docs/blockchain_state_machines.rs @@ -0,0 +1,29 @@ +//! # State Transition Function +//! +//! This document briefly explains how in the context of substrate based blockchains, we view the +//! blockchain as **decentralized state transition function**. +//! +//! Recall that a blockchain's main purpose is to help a permissionless set of entities to agree on +//! a shared data-set, and how it evolves. This is called the **State**, also referred to as +//! "onchain" data, or *Storage* in the context of FRAME. The state is where the account balance of +//! each user is, for example, stored, and there is a canonical version of it that everyone agrees +//! upon. +//! +//! Then, recall that a typical blockchain system will alter its state through execution of blocks. +//! *The component that dictates how this state alteration can happen is called the state transition +//! function*. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/stf_simple.mmd")] +//! +//! In Substrate-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: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/stf.mmd")] +//! +//! In essence, the state of the blockchain at block N is the outcome of applying the state +//! transition function to the the previous state, and the current block as input. This can be +//! mathematically represented as: +//! +//! ```math +//! STF = F(State_N, Block_N) -> State_{N+1} +//! ``` diff --git a/developer-hub/src/reference_docs/extrinsic_encoding.rs b/developer-hub/src/reference_docs/extrinsic_encoding.rs new file mode 100644 index 000000000000..f9c50dc77fa3 --- /dev/null +++ b/developer-hub/src/reference_docs/extrinsic_encoding.rs @@ -0,0 +1,289 @@ +//! # Constructing and Signing Extrinsics +//! +//! Extrinsics are payloads that are stored in blocks which are responsible for altering the state +//! 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, +//! because it's generic enough to cater for most (if not all) use cases. In Polkadot, 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 +//! looking at how extrinsics with a format version of 4 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`] +//! are formed from concatenating some details together, as in the following pseudo-code: +//! +//! ```text +//! extrinsic_bytes = concat( +//! compact_encoded_length, +//! version_and_maybe_signature, +//! call_data +//! ) +//! ``` +//! +//! 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)] +//! +//! 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 +//! 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 +//! first, and then obtain the byte length of these. We can then compact encode that length, and +//! prepend it to the rest of the details. +//! +//! ## version_and_maybe_signature +//! +//! If the extrinsic is _unsigned_, then `version_and_maybe_signature` will be just one byte +//! denoting the _transaction protocol version_, which is 4 (or `0b0000_0100`). +//! +//! If the extrinsic is _signed_ (all extrinsics submitted from users must be signed), then +//! `version_and_maybe_signature` is obtained by concatenating some details together, ie: +//! +//! ```text +//! version_and_maybe_signature = concat( +//! version_and_signed, +//! from_address, +//! signature, +//! signed_extensions_extra, +//! ) +//! ``` +//! +//! Each of the details to be concatenated together is explained below: +//! +//! ### version_and_signed +//! +//! This is one byte, equal to `0x84` or `0b1000_0100` (ie an upper 1 bit to denote that it is +//! signed, and then the transaction version, 4, in the lower bits). +//! +//! ### 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 +//! can vary from chain to chain. +//! +//! The address type used on the Polkadot relay chain is [`sp_runtime::MultiAddress`], +//! where `AccountId32` is defined [here][`sp_core::crypto::AccountId32`]. When constructing a +//! signed extrinsic to be submitted to a Polkadot node, you'll always use the +//! [`sp_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. +//! +//! 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 Polkadot relay chain is [`sp_runtime::MultiSignature`]; the +//! variants there are the types of signature that can be provided. +//! +//! ### signed_extensions_extra +//! +//! This is the concatenation of the [SCALE encoded][frame::deps::codec] bytes representing each of +//! the [_signed extensions_][sp_runtime::traits::SignedExtension], and are configured by the +//! fourth generic parameter of [`sp_runtime::generic::UncheckedExtrinsic`]. Learn more about +//! signed extensions [here][crate::reference_docs::signed_extensions]. +//! +//! When it comes to constructing an extrinsic, each signed extension has two things that we are +//! interested in here: +//! +//! - The actual SCALE encoding of the signed extension type itself; this is what will form our +//! `signed_extensions_extra` bytes. +//! - An `AdditionalSigned` type. This is SCALE encoded into the `signed_extensions_additional` +//! data of the _signed payload_ (see below). +//! +//! Either (or both) of these can encode to zero bytes. +//! +//! Each chain configures the set of signed extensions that it uses in its runtime configuration. +//! At the time of writing, Polkadot configures them +//! [here](https://github.com/polkadot-fellows/runtimes/blob/1dc04eb954eadf8aadb5d83990b89662dbb5a074/relay/polkadot/src/lib.rs#L1432C25-L1432C25). +//! Some of the common signed extensions are defined [here][frame::deps::frame_system#signed-extensions]. +//! +//! Information about exactly which signed 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]. +//! +//! ## call_data +//! +//! This is the main payload of the extrinsic, and is the data that the chain will use to determine +//! how the state of the chain is altered. This is determined by the second generic parameter of +//! [`sp_runtime::generic::UncheckedExtrinsic`]. +//! +//! A call can be anything that implements [`Encode`][frame::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 [here][crate::reference_docs::frame_composite_enums]. +//! +//! FRAME `Call` enums are automatically generated, and end up looking something like this: +//! +#![doc = docify::embed!("./src/reference_docs/extrinsic_encoding.rs", call_data)] +//! +//! In pseudo-code, this `Call` enum encodes equivalently to: +//! +//! ```text +//! call_data = concat( +//! pallet_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, +//! 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]. +//! +//! # The Signed Payload Format +//! +//! All extrinsics submitted to a node from the outside world (also known as _transactions_) need to +//! be _signed_. The data that needs to be signed for some extrinsic is called the _signed payload_, +//! and its shape is described by the following pseudo-code: +//! +//! ```text +//! signed_payload = concat( +//! call_data, +//! signed_extensions_extra, +//! signed_extensions_additional, +//! ) +//! +//! if length(signed_payload) > 256 { +//! signed_payload = blake2_256(signed_payload) +//! } +//! ``` +//! +//! The bytes representing `call_data` and `signed_extensions_extra` can be obtained as descibed +//! above. `signed_extensions_additional` is constructed by SCALE encoding the +//! ["additional signed" data][sp_runtime::traits::SignedExtension::AdditionalSigned] for each +//! signed extension that the chain is using, in order. +//! +//! Once we've concatenated those together, we hash the result if it's greater than 256 bytes in +//! length 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 signed extensions. +//! +//! # Example Encoding +//! +//! Using [`sp_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 parity_scale_codec::{Encode, Decode}; + + // The outer enum composes calls within + // different pallets together. We have two + // pallets, "PalletA" and "PalletB". + #[derive(Encode, Decode)] + pub enum Call { + #[codec(index = 0)] + PalletA(PalletACall), + #[codec(index = 7)] + PalletB(PalletBCall) + } + + // An inner enum represents the calls within + // a specific pallet. "PalletA" has one call, + // "Foo". + #[derive(Encode, Decode)] + pub enum PalletACall { + #[codec(index = 0)] + Foo(String) + } + + #[derive(Encode, Decode)] + pub enum PalletBCall { + #[codec(index = 0)] + Bar(String) + } +} + +#[docify::export] +pub mod encoding_example { + use crate::reference_docs::signed_extensions::signed_extensions_example; + use super::call_data::{ Call, PalletACall }; + use sp_runtime::{MultiAddress, MultiSignature}; + use sp_runtime::generic::{UncheckedExtrinsic, SignedPayload}; + use sp_core::crypto::AccountId32; + use sp_keyring::sr25519::Keyring; + use parity_scale_codec::Encode; + + // Define some signed extensions to use. We'll use a couple of examples + // from the signed extensions reference doc. + type SignedExtensions = ( + signed_extensions_example::AddToPayload, + signed_extensions_example::AddToSignaturePayload, + ); + + // We'll use `UncheckedExtrinsic` to encode our extrinsic for us. We set + // the address and signature type to those used on Polkadot, use our custom + // `Call` type, and use our custom set of `SignedExtensions`. + type Extrinsic = UncheckedExtrinsic< + MultiAddress, + Call, + MultiSignature, + SignedExtensions + >; + + pub fn encode_demo_extrinsic() -> Vec { + // The "from" address will be our Alice dev account. + let from_address = MultiAddress::::Id(Keyring::Alice.to_account_id()); + + // We provide some values for our expected signed extensions. + let signed_extensions = ( + signed_extensions_example::AddToPayload(1), + signed_extensions_example::AddToSignaturePayload + ); + + // Construct our call data: + let call_data = Call::PalletA(PalletACall::Foo("Hello".to_string())); + + // The signed payload. This takes care of encoding the call_data, + // signed_extensions_extra and signed_extensions_additional, and hashing + // the result if it's > 256 bytes: + let signed_payload = SignedPayload::new( + &call_data, + signed_extensions.clone(), + ); + + // Sign the signed payload with our Alice dev account's private key, + // and wrap the signature into the expected type: + let signature = { + let sig = Keyring::Alice.sign(&signed_payload.encode()); + MultiSignature::Sr25519(sig) + }; + + // Now, we can build and encode our extrinsic: + let ext = Extrinsic::new_signed( + call_data, + from_address, + signature, + signed_extensions + ); + + let encoded_ext = ext.encode(); + encoded_ext + } +} diff --git a/developer-hub/src/reference_docs/fee_less_runtime.rs b/developer-hub/src/reference_docs/fee_less_runtime.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/frame_composite_enums.rs b/developer-hub/src/reference_docs/frame_composite_enums.rs new file mode 100644 index 000000000000..6051cd534467 --- /dev/null +++ b/developer-hub/src/reference_docs/frame_composite_enums.rs @@ -0,0 +1 @@ +//! # FRAME Composite Enums diff --git a/developer-hub/src/reference_docs/glossary.rs b/developer-hub/src/reference_docs/glossary.rs new file mode 100644 index 000000000000..76e3692fc97d --- /dev/null +++ b/developer-hub/src/reference_docs/glossary.rs @@ -0,0 +1,17 @@ +//! +//! +//! State: Onchain Data +//! +//! Offchain +//! +//! STF, Runtime: +//! +//! Node, Client, Host: +//! +//! Host Function: +//! +//! Runtime API: +//! +//! Dispatchable, Callable: +//! +//! Extrinsic, Transaction diff --git a/developer-hub/src/reference_docs/mod.rs b/developer-hub/src/reference_docs/mod.rs new file mode 100644 index 000000000000..99f0f2559ecb --- /dev/null +++ b/developer-hub/src/reference_docs/mod.rs @@ -0,0 +1,58 @@ +//! # Polkadot SDK Reference Docs. +//! +//! This is the entry point for all reference documents that enhance one's learning experience in +//! the Polkadot SDK. +//! +//! ## What is a "reference document"? +//! +//! First, see [why we use rust-docs for everything](crate#why-rust-docs) and our documentation +//! [principles](crate#principles). We acknowledge that as much of the crucial information should be +//! embedded in the low level rust-docs. Then, high level scenarios should be covered in +//! [`crate::tutorial`]. Finally, we acknowledge that there is a category of information that is: +//! +//! 1. crucial to know. +//! 2. is too high level to be in the rust-doc of any one `type`, `trait` or `fn`. +//! 3. is too low level to be encompassed in a [`crate::tutorial`]. +//! +//! We can this class of documents "reference documents". Our goal should be to minimize the number +//! of "reference" docs, as they incur maintenance burden. +//! +//! ## Ownership +//! +//! Every page must have an owner or a list of owners, who are responsible for maintaining the page. + +/// Learn how Substrate 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. +pub mod blockchain_state_machines; + +/// The glossary. +pub mod glossary; + +/// Learn about the WASM meta-protocol of all substrate-based chains. +pub mod wasm_meta_protocol; + +/// Learn about the differences between smart contracts and a FRAME-based runtime. They are both +/// "code stored onchain", but how do they differ? +pub mod runtime_vs_smart_contract; + +/// Learn about how extrinsics are encoded to be transmitted to a node and stored in blocks. +pub mod extrinsic_encoding; + +/// Learn about the signed extensions that form a part of extrinsics. +pub mod signed_extensions; + +/// Learn about *"Origin"* A topic in FRAME that enables complex account abstractions to be built. +pub mod origin_account_abstraction; + +/// Learn about how to write safe and defensive code in your FRAME runtime. +pub mod safe_defensive_programming; + +/// Learn about composite enums in FRAME-based runtimes, such as "RuntimeEvent" and "RuntimeCall". +pub mod frame_composite_enums; + +/// Learn about how to make a pallet/runtime that is fee-less and instead uses another mechanism to +/// control usage and sybil attacks. +pub mod fee_less_runtime; diff --git a/developer-hub/src/reference_docs/origin_account_abstraction.rs b/developer-hub/src/reference_docs/origin_account_abstraction.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/runtime_vs_smart_contract.rs b/developer-hub/src/reference_docs/runtime_vs_smart_contract.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/safe_defensive_programming.rs b/developer-hub/src/reference_docs/safe_defensive_programming.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/signed_extensions.rs b/developer-hub/src/reference_docs/signed_extensions.rs new file mode 100644 index 000000000000..b6b46afd3858 --- /dev/null +++ b/developer-hub/src/reference_docs/signed_extensions.rs @@ -0,0 +1,79 @@ +//! Signed extensions are, briefly, a means for different chains to extend the "basic" extrinsic +//! format with custom data that can be checked by the runtime. +//! +//! # Example +//! +//! Defining a couple of very simple signed extensions looks like the following: +#![doc = docify::embed!("./src/reference_docs/signed_extensions.rs", signed_extensions_example)] + +#[docify::export] +pub mod signed_extensions_example { + use parity_scale_codec::{Decode, Encode}; + use scale_info::TypeInfo; + use sp_runtime::traits::SignedExtension; + + // This doesn't actually check anything, but simply allows + // some arbitrary `u32` to be added to the extrinsic payload + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToPayload(pub u32); + + impl SignedExtension for AddToPayload { + const IDENTIFIER: &'static str = "AddToPayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = (); + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(()) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } + + // This is the opposite; nothing will be added to the extrinsic payload, + // but the AdditionalSigned type is `1234u32`, which will be added to the + // payload which will be signed. + #[derive(Debug, Encode, Decode, Clone, Eq, PartialEq, TypeInfo)] + pub struct AddToSignaturePayload; + + impl SignedExtension for AddToSignaturePayload { + const IDENTIFIER: &'static str = "AddToSignaturePayload"; + type AccountId = (); + type Call = (); + type AdditionalSigned = u32; + type Pre = (); + + fn additional_signed( + &self, + ) -> Result< + Self::AdditionalSigned, + sp_runtime::transaction_validity::TransactionValidityError, + > { + Ok(1234) + } + + fn pre_dispatch( + self, + _who: &Self::AccountId, + _call: &Self::Call, + _info: &sp_runtime::traits::DispatchInfoOf, + _len: usize, + ) -> Result { + Ok(()) + } + } +} diff --git a/developer-hub/src/reference_docs/trait_based_programming.rs b/developer-hub/src/reference_docs/trait_based_programming.rs new file mode 100644 index 000000000000..612d23cff1c3 --- /dev/null +++ b/developer-hub/src/reference_docs/trait_based_programming.rs @@ -0,0 +1,226 @@ +//! # Trait-based Programming +//! +//! This documents walks you over a peculiar way of using Rust's `trait` items. This pattern is +//! abundantly used within [`frame`] and is therefore paramount important for a smooth transition +//! into it. +//! +//! The rest of this document assumes familiarity with the Rust book's advance trait section. +//! Moreover, we use the [`frame::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. +//! +//! 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 +//! 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: +//! +//! ``` +//! struct Pallet { +//! min_transfer: u128, +//! } +//! ``` +//! +//! 2. For *types* that need to be generic, we would have to use generic or associated types, such +//! as: +//! +//! ``` +//! struct Pallet { +//! min_transfer: u128, +//! _marker: std::marker::PhantomData, +//! } +//! ``` +//! +//! Substrate 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: +#![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 +//! > something that adheres to being `From<[u8; 32]>`. +//! +//! This method would work, but it suffers from two downsides: +//! +//! 1. It is verbose, each `impl` block would have to reiterate all of the trait bounds. +//! 2. It cannot easily share/inherit generic types. Imagine multiple pallets wanting to be generic +//! over a single `AccountId`. There is no easy way to express that in this model. +//! +//! Finally, this brings us to using traits and associated types on traits to express the above. +//! trait associated types have the benefit of: +//! +//! 1. Being less verbose, as in effect they can *group multiple `type`s together*. +//! 2. Can inherit from one another by declaring super-trait +//! +//! > Interestingly, one of the only 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`]. +//! +//! The last iteration of our code would look like this: +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", trait_based)] +//! +//! Notice how instead of having multiple generics, everything is generic over a single ``, and all types are fetched through `T::Foo`. +//! +//! Finally, imagine all pallets wanting to be generic over `AccountId`. This can be achieved by +//! 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`]. +//! +//! 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` and +//! `SystemConfig` has a `type AccountId`. +//! +//! Note, in some instances one would need to use what is known as the fully-qualified-syntax to +//! access a type to help the Rust compiler disambiguate. +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", fully_qualified)] +//! +//! This syntax can sometimes become more complicated when you are dealing with nested traits. +//! Consider the following example, in which we fetch the `type Balance` from another trait +//! `CurrencyTrait`. +#![doc = docify::embed!("./src/reference_docs/trait_based_programming.rs", fully_qualified_complicated)] +//! +//! Notice the final `type BalanceOf` and how it is defined. Using such aliases to shorten the +//! 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)] +//! +//! ## Additional Resources +//! +//! - +//! - +//! - +#![allow(unused)] + +use frame::traits::Get; + +#[docify::export] +mod basic { + struct Pallet; + + type AccountId = frame::deps::sp_runtime::AccountId32; + type Balance = u128; + type MinTransfer = frame::traits::ConstU128<10>; + + impl Pallet { + fn transfer(_from: AccountId, _to: AccountId, _amount: Balance) { + todo!() + } + } +} + +#[docify::export] +mod generic { + use super::*; + + struct Pallet { + _marker: std::marker::PhantomData<(AccountId, Balance, MinTransfer)>, + } + + impl Pallet + where + Balance: frame::traits::AtLeast32BitUnsigned, + MinTransfer: frame::traits::Get, + AccountId: From<[u8; 32]>, + { + fn transfer(_from: AccountId, _to: AccountId, amount: Balance) { + assert!(amount >= MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod trait_based { + use super::*; + + trait Config { + type AccountId: From<[u8; 32]>; + type Balance: frame::traits::AtLeast32BitUnsigned; + type MinTransfer: frame::traits::Get; + } + + struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) { + assert!(amount >= T::MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod with_system { + use super::*; + + pub trait SystemConfig { + type AccountId: From<[u8; 32]>; + } + + pub trait Config: SystemConfig { + type Balance: frame::traits::AtLeast32BitUnsigned; + type MinTransfer: frame::traits::Get; + } + + pub struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer(_from: T::AccountId, _to: T::AccountId, amount: T::Balance) { + assert!(amount >= T::MinTransfer::get()); + unimplemented!(); + } + } +} + +#[docify::export] +mod fully_qualified { + use super::with_system::*; + + // Simple of using fully qualified syntax. + type AccountIdOf = ::AccountId; +} + +#[docify::export] +mod fully_qualified_complicated { + use super::with_system::*; + + trait CurrencyTrait { + type Balance: frame::traits::AtLeast32BitUnsigned; + fn more_stuff() {} + } + + trait Config: SystemConfig { + type Currency: CurrencyTrait; + } + + struct Pallet(std::marker::PhantomData); + impl Pallet { + fn transfer( + _from: T::AccountId, + _to: T::AccountId, + _amount: <::Currency as CurrencyTrait>::Balance, + ) { + unimplemented!(); + } + } + + /// A common pattern in FRAME. + type BalanceOf = <::Currency as CurrencyTrait>::Balance; +} diff --git a/developer-hub/src/reference_docs/wasm_meta_protocol.rs b/developer-hub/src/reference_docs/wasm_meta_protocol.rs new file mode 100644 index 000000000000..83a7bbf66c15 --- /dev/null +++ b/developer-hub/src/reference_docs/wasm_meta_protocol.rs @@ -0,0 +1,107 @@ +//! # WASM Meta Protocol +//! +//! All Substrate based chains adhere to a unique architectural design novel to the Polkadot +//! ecosystem. We refer to this design as the "WASM Meta Protocol". +//! +//! Consider the fact that a traditional blockchain software is usually a monolith artifact. +//! Upgrading any part of the system implies upgrading the entire system. This has historically led +//! to cumbersome forkful upgrades to be the status quo in the blockchain ecosystem. +//! +//! 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 +//! blockchain's main "state transition function" in the main blockchain state, 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 +//! 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 +//! > are fundamental differences between the two, explained in +//! > [`crate::reference_docs::runtime_vs_smart_contract`]. +//! +//! The rest of the system that is NOT the state transition function is called the **client**, 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 +//! Runtime can be updates on the fly, within the execution of a block, and the client 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 +//! follows: +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_simple.mmd")] +//! +//! The client 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 client. 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. +//! 2. **Runtime APIs**: a way for the client 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 +//! fundamental runtime API that any blockchain must implement in order to be able to (re) +//! execute blocks. +#![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_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 as an example of how to add custom +//! runtime APIs to your FRAME-based runtime. +//! +//! Similarly, for a runtime to be "compatible" with a client, the client must implement the full +//! set of host functions that the runtime at any point in time requires. Given the fact that a +//! runtime can evolve in time, and a blockchain client (typically) wishes to be capable of +//! re-executing all the previous blocks, this means that a client must always maintain support for +//! the old host functions. This also implies that adding a new host function is a big commitment +//! and should be done with care. This is why, for example, adding a new host function to Polkadot +//! always requires an RFC. +//! +//! ## Client vs. Runtime +//! +//! A common question is: what components of the system end up being part of the client, and what +//! components the runtime. +//! +//! Recall from [`crate::reference_docs::blockchain_state_machines`] that the runtime is the state +//! transition function. Anything that needs to influence how your blockchain's state is updated, +//! should be a part of the runtime. For example, the logic around currency, governance, identity or +//! any other application-specific logic that has to do with the state is part of the runtime. +//! +//! Anything that does not have to do with the state-transition function and will only +//! facilitate/enable it is part of the client. For example, the database, networking, and even +//! consensus algorithm are all client-side components. +//! +//! > 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!("../../../docs/mermaid/substrate_with_frame.mmd")] +//! +//! ## State +//! +//! From the previous sections, we know that the a database component is part of the client, not the +//! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime +//! issues commands to the client 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 +//! client side. Nonetheless, the runtime is the only component that: +//! +//! 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 client 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!("../../../docs/mermaid/state.mmd")] +//! +//! In the above diagram, all of the state keys and values are opaque bytes to the client. The +//! client does not know what they mean, and it does not now what is the type of the corresponding +//! value (eg. 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: +//! because the client 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 client needing +//! to know. +//! +//! ## Example: Block Execution. +//! +//! TODO: diff --git a/developer-hub/src/tutorial/currency_simple/mod.rs b/developer-hub/src/tutorial/currency_simple/mod.rs new file mode 100644 index 000000000000..b968a0f8343e --- /dev/null +++ b/developer-hub/src/tutorial/currency_simple/mod.rs @@ -0,0 +1,737 @@ +//! # Currency Pallet +//! +//! By the end of this tutorial, you will write a small FRAME pallet (see +//! [`crate::polkadot_sdk::frame_runtime`]) that is capable of handling a simple crypto-currency. +//! This pallet will: +//! +//! 1. Allow a 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. Tracks of the total issuance of all tokens at all times. +//! +//! > This tutorial will build a currency pallet 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 +//! > one. Further advance FRAME related topics are discussed in [`crate::reference_docs`]. +//! +//! ## Topics Covered +//! +//! The following FRAME topics are covered in this tutorial. See the rust-doc of the associated +//! items to know more. +//! +//! - [Storage](frame::pallet_macros::storage`) +//! - [Call](frame::pallet_macros::call) +//! - [Event](frame::pallet_macros::event) +//! - [Error](frame::pallet_macros::error) +//! - Basics of testing a pallet. +//! - [Constructing a runtime](frame::runtime::construct_runtime) +//! +//! ## Writing Your First Pallet +//! +//! You should have studied the following modules as a prelude to this tutorial: +//! +//! - [`crate::reference_docs::blockchain_state_machines`] +//! - [`crate::reference_docs::trait_based_programming`] +//! - [`crate::polkadot_sdk::frame_runtime`] +//! +//! ### Shell Pallet +//! +//! Consider the following as a "shell pallet". We continue building the rest of this pallet based +//! on this template. +//! +//! [`pallet::config`](frame::pallet_macros::config) and +//! [`pallet::pallet`](frame::pallet_macros::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!("./src/tutorial/currency_simple/mod.rs", shell_pallet)] +//! +//! ### Storage +//! +//! First, we will need to create two onchain storage declarations. +//! +//! One should be a mapping from account-ids to a balance type, and one value that is the total +//! issuance. +// +// For the rest of this tutorial, we will opt for a balance type of u128. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", Balance)] +//! +//! The definition of these two storage items, based on [`frame::pallet_macros::storage`] details, +//! is as follows: +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", TotalIssuance)] +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", Balances)] +//! +//! ### Dispatchables +//! +//! Next, we will define the dispatchable functions. As per [`frame::pallet_macros::call`], these +//! will be defined as normal `fn`s attached to `struct Pallet`. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", impl_pallet)] +//! +//! The logic of the 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`. +//! - What is `ensure_signed`, and what does it do with the aforementioned `T::RuntimeOrigin`? this +//! is outside the scope of this tutorial, and you can learn more about it in the origin reference +//! document ([`crate::reference_docs::origin_account_abstraction`]). For now, you should only +//! know the signature of the function: it takes a generic `T::RuntimeOrigin` and returns a +//! `Result`. So by the end of this function call, we know that this dispatchable +//! was signed by `who`. +#![doc = docify::embed!("../substrate/frame/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::::insert`, you can look +//! into [`frame::prelude::StorageMap::insert`]. +//! +//! - The return type of all dispatchable functions is [`frame::prelude::DispatchResult`]: +#![doc = docify::embed!("../substrate/frame/support/src/dispatch.rs", DispatchResult)] +//! +//! Which is more or less a normal Rust `Result`, with a custom [`frame::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<%26'static+str>-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 +//! [`frame::pallet_macros::storage`], and +//! [`frame::prelude::ValueQuery`]/[`frame::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. +//! This macro will call `.into()` under the hood. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", transfer_better)] +//! +//! Moreover, you will learn elsewhere ([`crate::reference_docs::safe_defensive_programming`]) that +//! it is always recommended to use safe arithmetic operations in your runtime. By using +//! [`frame::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!("./src/tutorial/currency_simple/mod.rs", transfer_better_checked)] +//! +//! This is more or less all the logic that there is this basic currency pallet! +//! +//! ### Your First (Test) Runtime +//! +//! Next, we create a "test runtime" in order to test our pallet. Recall from +//! [`crate::polkadot_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!("./src/tutorial/currency_simple/mod.rs", runtime)] +//! +//! > [`frame::pallet_macros::derive_impl`] is a FRAME feature that enables developers to have +//! > defaults for associated types. +//! +//! Recall that within out pallet, (almost) all blocks of code are generic over ``. 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 Rust +//! traits and generics work. In 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 +//! where you see `` (read: *"some type `T` that implements `Config`"*), in the runtime, +//! it can be replaced with ``, 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 +//! only know that they will be provided at some later point. For example, when you write +//! `T::AccountId` (which is short for ``) 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`. +//! +//! 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 +//! 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. +//! +//! > Imagine how hard it would have been if all tests had to use a real 32-byte account id, as +//! > opposed to just a u64 number πŸ™ˆ. +//! +//! ### 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 +//! to be used in our tests. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", first_test)] +//! +//! In the first test, we simply assert that there is no total issuance, and no balance associated +//! with account `1`. Then, we mint some balance into `1`, and re-check. +//! +//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing ``. +//! This is why for example you see `Balances::::get(..)`. Finally, notice that the +//! dispatchables are simply functions that can be called on top of the `Pallet` struct. +//! +//! TODO: hard to explain exactly `RuntimeOrigin::signed(1)` at this point. +//! +//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional +//! steps to improve our pallet. +//! +//! ## Improving the Currency Pallet +//! +//! ### Better Test Setup +//! +//! Idiomatic FRAME pallets often use Builder pattern to define their initial state. +//! +//! > The Polkadot Blockchain Academy's Rust entrance exam has a +//! > [section](https://github.com/Polkadot-Blockchain-Academy/pba-qualifier-exam/blob/main/src/m_builder.rs) +//! > on this that you can use to learn the Builder Pattern. +//! +//! Let's see how we can implement a better test setup using this pattern. First, we define a +//! `struct StateBuilder`. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.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![(1, 100), (2, 100)];` so +//! far. Then, if desired, we attach a default value for this struct. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", default_state_builder)] +//! +//! Like any other builder pattern, we attach functions to the type to mutate its internal +//! properties. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.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: +//! +//! 1. It would consume `self` to produce our `TestState` based on the properties that we attached +//! to `self`. +//! 2. It would execute any test function that we pass in as closure. +//! 3. A nifty trick, this allows our test setup to have some code that is executed both before and +//! 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!("./src/tutorial/currency_simple/mod.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!("./src/tutorial/currency_simple/mod.rs", state_builder_works)] +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.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!("./src/tutorial/currency_simple/mod.rs", transfer_works)] +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.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!("./src/tutorial/currency_simple/mod.rs", transfer_from_non_existent_fails)] +//! +//! We leave it up to you to write a test that triggers to `InsufficientBalance` error. +//! +//! ### Event and Error +//! +//! TODO: this should be a new tutorial. +//! +//! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and +//! Errors. First, let's understand what each are. +//! +//! - **Error**: The static string-based error scheme we used so far is good for readability, but it +//! has a few drawbacks. These string literals will bloat the final wasm blob, and are relatively +//! heavy to transmit and encode/decode. Moreover, it is easy to mistype then 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 inly `u8` indices) to +//! [`sp_runtime::DispatchError::Module`] Read more about this in [`frame::pallet_macros::error`]. +//! +//! - **Event**: Events are akin to the return type of dispatch-ables. 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 external parties +//! (eg. a light-client, A DApp) to listen to particular events happening, without needing to +//! re-execute the whole state transition function. +//! +//! TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation of +//! event is probably not the best. +//! +//! 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 an extra `#[frame::event/error]` attribute +//! attached. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", Event)] +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", Error)] +//! +//! One slightly custom part of this is the `#[pallet::generate_deposit(pub(super) fn +//! deposit_event)]` 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: +//! +//! 1.Declare a type in its `Config` that refers to the over-arching event type of the runtime. In +//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent: +//! From>`. Read: There exists a `RuntimeEvent`, 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. +//! +//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME +//! provides a default way of storing events, in this is what `pallet::generate_deposit` is doing. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", config_v2)] +//! +//! > These `Runtime*` types are better explained in +//! > [`crate::reference_docs::frame_composite_enums`]. +//! +//! Then, we can rewrite the `transfer` dispatchable as such: +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", transfer_v2)] +//! +//! Then, notice how now we would need to provide this `type RuntimeEvent` in our test runtime +//! setup. +#![doc = docify::embed!("./src/tutorial/currency_simple/mod.rs", runtime_v2)] +//! +//! In this snippet, the actual `RuntimeEvent` type (right hand side of `type RuntimeEvent = +//! RuntimeEvent`) is generated by `construct_runtime`. An interesting way to inspect this type is +//! to see its definition in rust-docs: +//! [`crate::tutorial::currency_simple::pallet_v2::tests::runtime_v2::RuntimeEvent`]. +//! +//! +//! +//! ## What Next? +//! +//! The following topics where used in this tutorial, but not covered in depth. It is suggested to +//! study them subsequently: +//! +//! - [`crate::reference_docs::safe_defensive_programming`]. +//! - [`crate::reference_docs::origin_account_abstraction`]. +//! - [`crate::reference_docs::frame_composite_enums`]. +//! - The pallet we wrote in this tutorial was using `dev_mode`, learn more in +//! [`frame::pallet_macros::config`]. +//! - Learn more about the individual pallet items/macros, such as event and errors and call, in +//! [`frame::pallet_macros`]. + +use frame::prelude::*; + +#[docify::export] +#[frame::pallet(dev_mode)] +pub mod shell_pallet { + use frame::prelude::*; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); +} + +#[frame::pallet(dev_mode)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub type Balance = u128; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export] + /// Single storage item, of type `Balance`. + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + /// A mapping from `T::AccountId` to `Balance` + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[docify::export(impl_pallet)] + #[pallet::call] + impl Pallet { + /// An unsafe mint that can be called by anyone. Not a great idea. + pub fn mint_unsafe( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + // ensure that this is a signed account, but we don't really check `_anyone`. + let _anyone = ensure_signed(origin)?; + + // update the balances map. Notice how all `` remains as ``. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + // update total issuance. + TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); + + Ok(()) + } + + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + if sender_balance < amount { + return Err("InsufficientBalance".into()) + } + let reminder = sender_balance - amount; + + // update sender and dest balances. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Ok(()) + } + } + + #[allow(unused)] + impl Pallet { + #[docify::export] + pub fn transfer_better( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + ensure!(sender_balance >= amount, "InsufficientBalance"); + let reminder = sender_balance - amount; + + // .. snip + Ok(()) + } + + #[docify::export] + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer_better_checked( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + let reminder = sender_balance.checked_sub(amount).ok_or("InsufficientBalance")?; + + // .. snip + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub(crate) mod tests { + use crate::tutorial::currency_simple::pallet::*; + use frame::testing_prelude::*; + + #[docify::export] + mod runtime { + use super::*; + // we need to reference our `mod pallet` as an identifier to pass to + // `construct_runtime`. + use crate::tutorial::currency_simple::pallet as pallet_currency; + + construct_runtime!( + pub struct Runtime { + // ---^^^^^^ This is where `struct Runtime` is defined. + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + // within pallet we just said `::AccountId`, now we + // finally specified it. + type AccountId = u64; + } + + // our simple pallet has nothing to be configured. + impl pallet_currency::Config for Runtime {} + } + + pub(crate) use runtime::*; + + #[allow(unused)] + #[docify::export] + fn new_test_state_basic() -> TestState { + let mut state = TestState::new_empty(); + let accounts = vec![(1, 100), (2, 100)]; + state.execute_with(|| { + for (who, amount) in &accounts { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + state + } + + #[docify::export] + pub(crate) struct StateBuilder { + balances: Vec<(::AccountId, Balance)>, + } + + #[docify::export(default_state_builder)] + impl Default for StateBuilder { + fn default() -> Self { + Self { balances: vec![(1, 100), (2, 100)] } + } + } + + #[docify::export(impl_state_builder_add)] + impl StateBuilder { + fn add_balance( + mut self, + who: ::AccountId, + amount: Balance, + ) -> Self { + self.balances.push((who, amount)); + self + } + } + + #[docify::export(impl_state_builder_build)] + impl StateBuilder { + pub(crate) fn build_and_execute(self, test: impl FnOnce() -> ()) { + let mut ext = TestState::new_empty(); + ext.execute_with(|| { + for (who, amount) in &self.balances { + Balances::::insert(who, amount); + TotalIssuance::::mutate(|b| *b = Some(b.unwrap_or(0) + amount)); + } + }); + + ext.execute_with(test); + + // assertions that must always hold + ext.execute_with(|| { + assert_eq!( + Balances::::iter().map(|(_, x)| x).sum::(), + TotalIssuance::::get().unwrap_or_default() + ); + }) + } + } + + #[docify::export] + #[test] + fn first_test() { + TestState::new_empty().execute_with(|| { + // We expect account 1 to have no funds. + assert_eq!(Balances::::get(&1), None); + assert_eq!(TotalIssuance::::get(), None); + + // mint some funds into 1 + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 1, 100)); + + // re-check the above + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(100)); + }) + } + + #[docify::export] + #[test] + fn state_builder_works() { + StateBuilder::default().build_and_execute(|| { + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn state_builder_add_balance() { + StateBuilder::default().add_balance(3, 42).build_and_execute(|| { + assert_eq!(Balances::::get(&3), Some(42)); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[test] + #[should_panic] + fn state_builder_duplicate_genesis_fails() { + StateBuilder::default() + .add_balance(3, 42) + .add_balance(3, 43) + .build_and_execute(|| { + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(242)); + }) + } + + #[docify::export] + #[test] + fn mint_works() { + StateBuilder::default().build_and_execute(|| { + // given the initial state, when: + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 2, 100)); + + // then: + assert_eq!(Balances::::get(&2), Some(200)); + assert_eq!(TotalIssuance::::get(), Some(300)); + + // given: + assert_ok!(Pallet::::mint_unsafe(RuntimeOrigin::signed(1), 3, 100)); + + // then: + assert_eq!(Balances::::get(&3), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(400)); + }); + } + + #[docify::export] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // given the the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(50)); + assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(2), 1, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + + #[docify::export] + #[test] + fn transfer_from_non_existent_fails() { + StateBuilder::default().build_and_execute(|| { + // given the the initial state, when: + assert_err!( + Pallet::::transfer(RuntimeOrigin::signed(3), 1, 10), + "NonExistentAccount" + ); + + // then nothing has changed. + assert_eq!(Balances::::get(&1), Some(100)); + assert_eq!(Balances::::get(&2), Some(100)); + assert_eq!(Balances::::get(&3), None); + assert_eq!(TotalIssuance::::get(), Some(200)); + }); + } + } +} + +#[frame::pallet(dev_mode)] +pub mod pallet_v2 { + use super::pallet::Balance; + use frame::prelude::*; + + #[docify::export(config_v2)] + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type of the runtime. + type RuntimeEvent: From> + + IsType<::RuntimeEvent> + + TryInto>; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + #[pallet::error] + pub enum Error { + /// Account does not exist. + NonExistentAccount, + /// Account does not have enough balance. + InsufficientBalance, + } + + #[docify::export] + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event { + /// A transfer succeeded. + Transferred { from: T::AccountId, to: T::AccountId, amount: Balance }, + } + + #[pallet::call] + impl Pallet { + #[docify::export(transfer_v2)] + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = + Balances::::get(&sender).ok_or(Error::::NonExistentAccount)?; + let reminder = + sender_balance.checked_sub(amount).ok_or(Error::::InsufficientBalance)?; + + Balances::::mutate(&dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Self::deposit_event(Event::::Transferred { from: sender, to: dest, amount }); + + Ok(()) + } + } + + #[cfg(any(test, doc))] + pub mod tests { + use super::{super::pallet::tests::StateBuilder, *}; + use frame::testing_prelude::*; + + #[docify::export] + pub mod runtime_v2 { + use super::*; + use crate::tutorial::currency_simple::pallet_v2 as pallet_currency; + + construct_runtime!( + pub struct Runtime { + System: frame_system, + Currency: pallet_currency, + } + ); + + #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + impl frame_system::Config for Runtime { + type Block = MockBlock; + type AccountId = u64; + } + + impl pallet_currency::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + } + } + + pub(crate) use runtime_v2::*; + + #[docify::export(transfer_works_v2)] + #[test] + fn transfer_works() { + StateBuilder::default().build_and_execute(|| { + // given the the initial state, when: + assert_ok!(Pallet::::transfer(RuntimeOrigin::signed(1), 2, 50)); + + // then: + assert_eq!(Balances::::get(&1), Some(50)); + assert_eq!(Balances::::get(&2), Some(150)); + assert_eq!(TotalIssuance::::get(), Some(200)); + + // now we can also check that an event has been deposited: + assert_eq!( + System::read_events_for_pallet::>(), + vec![Event::Transferred { from: 1, to: 2, amount: 50 }] + ); + }); + } + } +} diff --git a/developer-hub/src/tutorial/currency_simple/with_event.rs b/developer-hub/src/tutorial/currency_simple/with_event.rs new file mode 100644 index 000000000000..a65aac324f07 --- /dev/null +++ b/developer-hub/src/tutorial/currency_simple/with_event.rs @@ -0,0 +1,101 @@ +#[frame::pallet(dev_mode)] +pub mod pallet { + use frame::prelude::*; + + #[docify::export] + pub type Balance = u128; + + #[pallet::config] + pub trait Config: frame_system::Config {} + + #[pallet::pallet] + pub struct Pallet(_); + + #[docify::export] + /// Single storage item, of type `Balance`. + #[pallet::storage] + pub type TotalIssuance = StorageValue<_, Balance>; + + #[docify::export] + /// A mapping from `T::AccountId` to `Balance` + #[pallet::storage] + pub type Balances = StorageMap<_, _, T::AccountId, Balance>; + + #[docify::export(impl_pallet)] + #[pallet::call] + impl Pallet { + /// An unsafe mint that can be called by anyone. Not a great idea. + pub fn mint_unsafe( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + // ensure that this is a signed account, but we don't really check `_anyone`. + let _anyone = ensure_signed(origin)?; + + // update the balances map. Notice how all `` remains as ``. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + // update total issuance. + TotalIssuance::::mutate(|t| *t = Some(t.unwrap_or(0) + amount)); + + Ok(()) + } + + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + // ensure sender has enough balance, and if so, calculate what is left after `amount`. + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + if sender_balance < amount { + return Err("NotEnoughBalance".into()) + } + let reminder = sender_balance - amount; + + // update sender and dest balances. + Balances::::mutate(dest, |b| *b = Some(b.unwrap_or(0) + amount)); + Balances::::insert(&sender, reminder); + + Ok(()) + } + } + + #[allow(unused)] + impl Pallet { + #[docify::export] + pub fn transfer_better( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + ensure!(sender_balance >= amount, "NotEnoughBalance"); + let reminder = sender_balance - amount; + + // .. snip + Ok(()) + } + + #[docify::export] + /// Transfer `amount` from `origin` to `dest`. + pub fn transfer_better_checked( + origin: T::RuntimeOrigin, + dest: T::AccountId, + amount: Balance, + ) -> DispatchResult { + let sender = ensure_signed(origin)?; + + let sender_balance = Balances::::get(&sender).ok_or("NonExistentAccount")?; + let reminder = sender_balance.checked_sub(amount).ok_or("NotEnoughBalance")?; + + // .. snip + Ok(()) + } + } +} diff --git a/developer-hub/src/tutorial/mod.rs b/developer-hub/src/tutorial/mod.rs new file mode 100644 index 000000000000..cb19a6622f36 --- /dev/null +++ b/developer-hub/src/tutorial/mod.rs @@ -0,0 +1,8 @@ +//! # Polkadot Developer Hub Tutorials +//! +//! This crate contains a collection of tutorials that are foundational to the developers of +//! Polkadot SDK. They common user-journeys that are traversed in the Polkadot ecosystem. + +/// The first tutorial of the Polkadot SDK. Write a simple currency pallet, in which you will learn +/// the basics of FRAME. +pub mod currency_simple; diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd new file mode 100644 index 000000000000..0fd95951931b --- /dev/null +++ b/docs/mermaid/IA.mmd @@ -0,0 +1,13 @@ +flowchart + parity[paritytech.github.io] --> devhub[developer_hub] + + devhub --> polkadot_sdk + devhub --> reference_docs + devhub --> tutorial + + polkadot_sdk --> substrate + polkadot_sdk --> frame + polkadot_sdk --> cumulus + polkadot_sdk --> polkadot + + diff --git a/docs/mermaid/extrinsics.mmd b/docs/mermaid/extrinsics.mmd new file mode 100644 index 000000000000..4afd4ab8f755 --- /dev/null +++ b/docs/mermaid/extrinsics.mmd @@ -0,0 +1,5 @@ +flowchart TD + E(Extrinsic) ---> I(Inherent); + E --> T(Transaction) + T --> ST("Signed (aka. Transaction)") + T --> UT(Unsigned) diff --git a/docs/mermaid/polkadot_sdk.mmd b/docs/mermaid/polkadot_sdk.mmd new file mode 100644 index 000000000000..6a7efa42f110 --- /dev/null +++ b/docs/mermaid/polkadot_sdk.mmd @@ -0,0 +1,26 @@ +flowchart LR + subgraph Parachain[A Polkadot Parachain] + ParachainCollator[Parachain Collator] + ParachainRuntime[Parachain Runtime] + end + + subgraph Polkadot[The Polkadot Relay Chain] + PolkadotClinet[Polkadot Clinet] + PolkadotRuntime[Polkadot Runtime] + end + + subgraph SubstrateChain[A Substrate-based blockchain] + Clinet + Runtime + end + + FRAME1[FRAME] -.-> Runtime + FRAME2[FRAME] -.-> PolkadotRuntime + FRAME3[FRAME] -.-> ParachainRuntime + + Substrate1[Substrate Client Libraries] -.-> Clinet + Substrate2[Substrate Client Libraries] -.-> PolkadotClinet + Substrate3[Substrate Client Libraries] -.-> ParachainCollator + + Cumulus1[Cumulus Runtime Pallets/Libraries] -.-> ParachainRuntime + Cumulus2[Cumulus Client Libraries] -.-> ParachainCollator diff --git a/docs/mermaid/state.mmd b/docs/mermaid/state.mmd new file mode 100644 index 000000000000..e4f426f532f9 --- /dev/null +++ b/docs/mermaid/state.mmd @@ -0,0 +1,16 @@ +flowchart TB + subgraph Client[Client's Vew Of The State πŸ™ˆ] + direction LR + 0x1234 --> 0x2345 + 0x3456 --> 0x4567 + 0x5678 --> 0x6789 + :code --> code[wasm code] + end + + subgraph Runtime[Runtime's Vew Of The State πŸ™‰] + direction LR + ab[alice's balance] --> abv[known value] + bb[bob's balance] --> bbv[known value] + cb[charlie's balance] --> cbv[known value] + c2[:code] --> c22[wasm code] + end diff --git a/docs/mermaid/stf.mmd b/docs/mermaid/stf.mmd new file mode 100644 index 000000000000..dd6c7c36de66 --- /dev/null +++ b/docs/mermaid/stf.mmd @@ -0,0 +1,21 @@ +flowchart LR + %%{init: {'flowchart' : {'curve' : 'linear'}}}%% + subgraph BData[Blockchain Database] + direction LR + BN[Block N] -.-> BN1[Block N+1] + end + + subgraph SData[State Database] + direction LR + SN[State N] -.-> SN1[State N+1] -.-> SN2[State N+2] + end + + BN --> STFN[STF] + SN --> STFN[STF] + STFN[STF] --> SN1 + + BN1 --> STFN1[STF] + SN1 --> STFN1[STF] + STFN1[STF] --> SN2 + + diff --git a/docs/mermaid/stf_simple.mmd b/docs/mermaid/stf_simple.mmd new file mode 100644 index 000000000000..5db20cf6156c --- /dev/null +++ b/docs/mermaid/stf_simple.mmd @@ -0,0 +1,4 @@ +flowchart LR + B[Block] --> STF + S[State] --> STF + STF --> NS[New State] diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml deleted file mode 100644 index 9e2e0b1a6eec..000000000000 --- a/substrate/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "substrate" -description = "Next-generation framework for blockchain innovation" -license = "GPL-3.0-or-later WITH Classpath-exception-2.0" -homepage = "https://substrate.io" -repository.workspace = true -authors.workspace = true -edition.workspace = true -version = "1.0.0" - -# The dependencies are only needed for docs. -[dependencies] -simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", rev = "e48b187bcfd5cc75111acd9d241f1bd36604344b" } - -subkey = { path = "bin/utils/subkey" } -chain-spec-builder = { path = "bin/utils/chain-spec-builder" } - -sc-service = { path = "client/service" } -sc-cli = { path = "client/cli" } -sc-consensus-aura = { path = "client/consensus/aura" } -sc-consensus-babe = { path = "client/consensus/babe" } -sc-consensus-grandpa = { path = "client/consensus/grandpa" } -sc-consensus-beefy = { path = "client/consensus/beefy" } -sc-consensus-manual-seal = { path = "client/consensus/manual-seal" } -sc-consensus-pow = { path = "client/consensus/pow" } - -sp-runtime = { path = "primitives/runtime" } -frame-support = { path = "frame/support" } diff --git a/substrate/frame/asset-conversion/src/mock.rs b/substrate/frame/asset-conversion/src/mock.rs index 4eee701f193e..ed6c1f58382f 100644 --- a/substrate/frame/asset-conversion/src/mock.rs +++ b/substrate/frame/asset-conversion/src/mock.rs @@ -187,7 +187,5 @@ pub(crate) fn new_test_ext() -> sp_io::TestExternalities { .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + sp_io::TestExternalities::new(t) } diff --git a/substrate/frame/balances/src/tests/mod.rs b/substrate/frame/balances/src/tests/mod.rs index dd3e5b7a85a2..a20bc142a5d7 100644 --- a/substrate/frame/balances/src/tests/mod.rs +++ b/substrate/frame/balances/src/tests/mod.rs @@ -192,9 +192,7 @@ impl ExtBuilder { .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| System::set_block_number(1)); - ext + sp_io::TestExternalities::new(t) } pub fn build_and_execute_with(self, f: impl Fn()) { let other = self.clone(); diff --git a/substrate/frame/election-provider-multi-phase/src/mock.rs b/substrate/frame/election-provider-multi-phase/src/mock.rs index 92144351e8f8..dda5981f2daf 100644 --- a/substrate/frame/election-provider-multi-phase/src/mock.rs +++ b/substrate/frame/election-provider-multi-phase/src/mock.rs @@ -80,11 +80,7 @@ frame_election_provider_support::generate_solution_type!( /// All events of this pallet. pub(crate) fn multi_phase_events() -> Vec> { - System::events() - .into_iter() - .map(|r| r.event) - .filter_map(|e| if let RuntimeEvent::MultiPhase(inner) = e { Some(inner) } else { None }) - .collect::>() + System::read_events_for_pallet::>() } /// To from `now` to block `n`. diff --git a/substrate/frame/examples/kitchensink/src/lib.rs b/substrate/frame/examples/kitchensink/src/lib.rs index 56117c59dc6d..75f9c41023a5 100644 --- a/substrate/frame/examples/kitchensink/src/lib.rs +++ b/substrate/frame/examples/kitchensink/src/lib.rs @@ -288,9 +288,8 @@ pub mod pallet { } } - /// Allows you to define an enum on the pallet which will then instruct - /// `construct_runtime` to amalgamate all similarly-named enums from other - /// pallets into an aggregate enum. + /// Allows you to define an enum on the pallet which will then instruct `construct_runtime` to + /// amalgamate all similarly-named enums from other pallets into an aggregate enum. #[pallet::composite_enum] pub enum HoldReason { Staking, diff --git a/substrate/frame/fast-unstake/src/types.rs b/substrate/frame/fast-unstake/src/types.rs index 15d0a327e917..3fb5720861fa 100644 --- a/substrate/frame/fast-unstake/src/types.rs +++ b/substrate/frame/fast-unstake/src/types.rs @@ -39,6 +39,7 @@ impl frame_support::traits::Get for MaxChecking { } } +#[docify::export] pub(crate) type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; /// An unstake request. diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index 1a8350405a89..c70943c945df 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -15,13 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -//! > Made for [![polkadot]](https://polkadot.network) -//! -//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white -//! //! # FRAME //! -//! ```no_compile +//! ```co_compile //! ______ ______ ________ ___ __ __ ______ //! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ //! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ @@ -34,14 +30,21 @@ //! > **F**ramework for **R**untime **A**ggregation of **M**odularized **E**ntities: Substrate's //! > State Transition Function (Runtime) Framework. //! +//! ## Documentation +//! +//! TODO: Link to devhub +//! //! ## Warning: Experimental //! //! This crate and all of its content is experimental, and should not yet be used in production. //! -//! ## Getting Started +//! ## Underlying dependencies //! -//! TODO: link to `developer_hub::polkadot_sdk::frame`. The `developer_hub` hasn't been published -//! yet, this can be updated once it is linkable. +//! This crate is an amalgamation of multiple other crates that are often used together to compose a +//! pallet. It is not necessary to use it, and it may fall short for certain purposes. +//! +//! In short, this crate only re-exports types and traits from multiple sources. All of these +//! sources are listed (and re-exported again) in [`deps`]. #![cfg_attr(not(feature = "std"), no_std)] #![cfg(feature = "experimental")] @@ -54,9 +57,19 @@ /// `#[pallet::bar]` inside the mod. pub use frame_support::pallet; +pub use frame_support::pallet_macros::{import_section, pallet_section}; + /// The logging library of the runtime. Can normally be the classic `log` crate. pub use log; +/// A list of all macros used within the main [`pallet`] macro. +/// +/// Note: All of these macros are "stubs" and not really usable outside `#[pallet] mod pallet { .. +/// }`. They are mainly provided for documentation and IDE support. +pub mod pallet_macros { + pub use frame_support::{derive_impl, pallet, pallet_macros::*}; +} + /// The main prelude of FRAME. /// /// This prelude should almost always be the first line of code in any pallet or runtime. @@ -78,9 +91,6 @@ pub mod prelude { /// Pallet prelude of `frame-support`. /// /// Note: this needs to revised once `frame-support` evolves. - // `frame-support` will be break down https://github.com/paritytech/polkadot-sdk/issues/127 and its reexports will - // most likely change. These wildcard reexportings can be optimized once `frame-support` has - // changed. #[doc(no_inline)] pub use frame_support::pallet_prelude::*; @@ -156,6 +166,9 @@ pub mod runtime { /// Types to define your runtime version. pub use sp_version::{create_runtime_str, runtime_version, RuntimeVersion}; + /// Macro to implement runtime APIs. + pub use sp_api::impl_runtime_apis; + #[cfg(feature = "std")] pub use sp_version::NativeVersion; } @@ -180,9 +193,6 @@ pub mod runtime { pub use sp_inherents::{CheckInherentsResult, InherentData}; pub use sp_runtime::ApplyExtrinsicResult; - /// Macro to implement runtime APIs. - pub use sp_api::impl_runtime_apis; - pub use frame_system_rpc_runtime_api::*; pub use sp_api::{self, *}; pub use sp_block_builder::*; diff --git a/substrate/frame/support/procedural/src/lib.rs b/substrate/frame/support/procedural/src/lib.rs index 9c551b9f2306..db2266eb61ca 100644 --- a/substrate/frame/support/procedural/src/lib.rs +++ b/substrate/frame/support/procedural/src/lib.rs @@ -1092,56 +1092,28 @@ pub fn weight(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Compact encoding for arguments can be achieved via `#[pallet::compact]`. The function must -/// return a `DispatchResultWithPostInfo` or `DispatchResult`. +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::call`. #[proc_macro_attribute] pub fn compact(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } -/// Each dispatchable may also be annotated with the `#[pallet::call_index($idx)]` attribute, -/// which explicitly defines the codec index for the dispatchable function in the `Call` enum. -/// -/// All call indexes start from 0, until it encounters a dispatchable function with a defined -/// call index. The dispatchable function that lexically follows the function with a defined -/// call index will have that call index, but incremented by 1, e.g. if there are 3 -/// dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` -/// has a call index of 10, then `fn qux` will have an index of 11, instead of 1. -/// -/// All arguments must implement [`Debug`], [`PartialEq`], [`Eq`], `Decode`, `Encode`, and -/// [`Clone`]. For ease of use, bound by the trait `frame_support::pallet_prelude::Member`. -/// -/// If no `#[pallet::call]` exists, then a default implementation corresponding to the -/// following code is automatically generated: -/// -/// ```ignore -/// #[pallet::call] -/// impl Pallet {} -/// ``` -/// -/// **WARNING**: modifying dispatchables, changing their order, removing some, etc., must be -/// done with care. Indeed this will change the outer runtime call type (which is an enum with -/// one variant per pallet), this outer runtime call can be stored on-chain (e.g. in -/// `pallet-scheduler`). Thus migration might be needed. To mitigate against some of this, the -/// `#[pallet::call_index($idx)]` attribute can be used to fix the order of the dispatchable so -/// that the `Call` enum encoding does not change after modification. As a general rule of -/// thumb, it is therefore adventageous to always add new calls to the end so you can maintain -/// the existing order of calls. -/// -/// ### Macro expansion -/// -/// The macro creates an enum `Call` with one variant per dispatchable. This enum implements: -/// [`Clone`], [`Eq`], [`PartialEq`], [`Debug`] (with stripped implementation in `not("std")`), -/// `Encode`, `Decode`, `GetDispatchInfo`, `GetCallName`, `GetCallIndex` and -/// `UnfilteredDispatchable`. -/// -/// The macro implements the `Callable` trait on `Pallet` and a function `call_functions` -/// which returns the dispatchable metadata. + +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::call`. #[proc_macro_attribute] pub fn call_index(_: TokenStream, _: TokenStream) -> TokenStream { pallet_macro_stub() } +/// **Rust-Analyzer users**: See the documentation of the Rust item in +/// `frame_support::pallet_macros::call`. +#[proc_macro_attribute] +pub fn call(_: TokenStream, _: TokenStream) -> TokenStream { + pallet_macro_stub() +} + /// Allows you to define some extra constants to be added into constant metadata. /// /// Item must be defined as: diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index 90631f264b92..c7e45cace6ee 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -25,6 +25,7 @@ use syn::spanned::Spanned; mod keyword { syn::custom_keyword!(Call); syn::custom_keyword!(OriginFor); + syn::custom_keyword!(RuntimeOrigin); syn::custom_keyword!(weight); syn::custom_keyword!(call_index); syn::custom_keyword!(compact); @@ -138,10 +139,10 @@ impl syn::parse::Parse for ArgAttrIsCompact { } } -/// Check the syntax is `OriginFor` -pub fn check_dispatchable_first_arg_type(ty: &syn::Type) -> syn::Result<()> { - pub struct CheckDispatchableFirstArg; - impl syn::parse::Parse for CheckDispatchableFirstArg { +/// Check the syntax is `OriginFor` or `T::RuntimeOrigin` or `::RuntimeOrigin`. +pub fn check_dispatchable_first_arg_type(ty: &syn::Type, system: &syn::Path) -> syn::Result<()> { + pub struct CheckOriginFor; + impl syn::parse::Parse for CheckOriginFor { fn parse(input: syn::parse::ParseStream) -> syn::Result { input.parse::()?; input.parse::()?; @@ -152,12 +153,34 @@ pub fn check_dispatchable_first_arg_type(ty: &syn::Type) -> syn::Result<()> { } } - syn::parse2::(ty.to_token_stream()).map_err(|e| { - let msg = "Invalid type: expected `OriginFor`"; - let mut err = syn::Error::new(ty.span(), msg); - err.combine(e); - err - })?; + pub struct CheckRuntimeOrigin; + impl syn::parse::Parse for CheckRuntimeOrigin { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + input.parse::()?; + input.parse::()?; + + Ok(Self) + } + } + + pub struct CheckSystemRuntimeOrigin; + impl syn::parse::Parse for CheckSystemRuntimeOrigin { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + input.parse::()?; + input.parse::()?; + input.parse::()?; + + Ok(Self) + } + } + + // syn::parse2::(ty.to_token_stream()).map_err(|e| { + // let msg = "Invalid type: expected `OriginFor`"; + // let mut err = syn::Error::new(ty.span(), msg); + // err.combine(e); + // err + // })?; Ok(()) } @@ -251,8 +274,8 @@ impl CallDef { 0 if dev_mode => CallWeightDef::DevModeDefault, 0 => return Err(syn::Error::new( method.sig.span(), - "A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an - inherited weight from the `#[pallet:call(weight($type))]` attribute, but + "A pallet::call requires either a concrete `#[pallet::weight($expr)]` or an + inherited weight from the `#[pallet:call(weight($type))]` attribute, but none were given.", )), 1 => match weight_attrs.pop().unwrap() { diff --git a/substrate/frame/support/src/dispatch.rs b/substrate/frame/support/src/dispatch.rs index e6a090ebcae8..3f58fcd03587 100644 --- a/substrate/frame/support/src/dispatch.rs +++ b/substrate/frame/support/src/dispatch.rs @@ -36,7 +36,8 @@ use sp_weights::Weight; /// returned from a dispatch. pub type DispatchResultWithPostInfo = sp_runtime::DispatchResultWithInfo; -/// Unaugmented version of `DispatchResultWithPostInfo` that can be returned from +#[docify::export] +/// Un-augmented version of `DispatchResultWithPostInfo` that can be returned from /// dispatchable functions and is automatically converted to the augmented type. Should be /// used whenever the `PostDispatchInfo` does not need to be overwritten. As this should /// be the common case it is the implicit return type when none is specified. diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 1c696bbb84ac..c8756c955597 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -57,6 +57,7 @@ pub mod __private { pub use sp_std; pub use sp_tracing; pub use tt_call::*; + pub use sp_io::TestExternalities; } #[macro_use] @@ -2199,13 +2200,157 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros pub mod pallet_macros { pub use frame_support_procedural::{ - call_index, compact, composite_enum, config, constant, - disable_frame_system_supertrait_check, error, event, extra_constants, generate_deposit, - generate_store, getter, hooks, import_section, inherent, no_default, no_default_bounds, - origin, pallet_section, storage, storage_prefix, storage_version, type_value, unbounded, - validate_unsigned, weight, whitelist_storage, + composite_enum, config, constant, disable_frame_system_supertrait_check, error, + event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, + inherent, no_default, no_default_bounds, origin, pallet_section, storage, storage_prefix, + storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; + /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. In slightly + /// simplified terms, this macro declares the set of "transactions" of a pallet. + /// + /// > The exact definition of **extrinsic** can be found in + /// > [`sp_runtime::generic::UncheckedExtrinsic`]. + /// + /// A **dispatchable** is a common term in FRAME, referring to process of constructing a + /// function, and dispatching it with the correct inputs. This is commonly used with extrinsics, + /// for example "an extrinsic has been dispatched". See [`sp_runtime::traits::Dispatchable`] and + /// [`crate::dispatch::UnfilteredDispatch`]. + /// + /// ## Call Enum + /// + /// The macro is called `call` (rather than `#[pallet::extrinsics]`) because of the generation + /// of a `enum Call`. This enum contains only the encoding of the function arguments of the + /// dispatchable, alongside the information needed to route it to the correct function. + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// pub mod custom_pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::BuildGenesisConfig; + /// #[pallet::call] + /// impl Pallet { + /// pub fn some_dispatchable(_origin: OriginFor, _input: u32) -> DispatchResult { + /// Ok(()) + /// } + /// pub fn other(_origin: OriginFor, _input: u64) -> DispatchResult { + /// Ok(()) + /// } + /// } + /// + /// // generates something like: + /// // enum Call { + /// // some_dispatchable { input: u32 } + /// // other { input: u64 } + /// // } + /// } + /// + /// fn main() { + /// # use frame_support::{derive_impl, construct_runtime}; + /// # use frame_support::__private::codec::Encode; + /// # use frame_support::__private::TestExternalities; + /// # use frame_support::traits::UnfilteredDispatchable; + /// # impl custom_pallet::Config for Runtime {} + /// # #[derive_impl(frame_system::config_preludes::TestDefaultConfig as frame_system::DefaultConfig)] + /// # impl frame_system::Config for Runtime { + /// # type Block = frame_system::mocking::MockBlock; + /// # } + /// construct_runtime! { + /// pub struct Runtime { + /// System: frame_system, + /// Custom: custom_pallet + /// } + /// } + /// + /// # TestExternalities::new_empty().execute_with(|| { + /// let origin: RuntimeOrigin = frame_system::RawOrigin::Signed(10).into(); + /// // calling into a dispatchable from within the runtime is simply a function call. + /// let _ = custom_pallet::Pallet::::some_dispatchable(origin.clone(), 10); + /// + /// // calling into a dispatchable from the outer world involves constructing the bytes of + /// let call = custom_pallet::Call::::some_dispatchable { input: 10 }; + /// let _ = call.clone().dispatch_bypass_filter(origin); + /// + /// // the routing of a dispatchable is simply done through encoding of the `Call` enum, + /// // which is the index of the variant, followed by the arguments. + /// assert_eq!(call.encode(), vec![0u8, 10, 0, 0, 0]); + /// + /// // notice how in the encoding of the second function, the first byte is different and + /// // referring to the second variant of `enum Call`. + /// let call = custom_pallet::Call::::other { input: 10 }; + /// assert_eq!(call.encode(), vec![1u8, 10, 0, 0, 0, 0, 0, 0, 0]); + /// # }); + /// } + /// ``` + /// + /// Further properties of dispatchable functions are as follows: + /// + /// - Unless if annotated by `dev_mode`, it must contain [`weight`] to denote the pre-dispatch + /// weight consumed. + /// - The dispatchable must declare its index via [`call_index`], which can override the + /// position of a function in `enum Call`. + /// - The first argument is always an `OriginFor` (or `T::RuntimeOrigin`). + /// - The return type is always [`crate::dispatch::DispatchResult`] (or + /// [`crate::dispatch::DispatchResultWithPostInfo`]). + /// + /// **WARNING**: modifying dispatchables, changing their order (ie. using [`call_index`]), + /// removing some, etc., must be done with care. This will change the encoding of the , and the + /// call can be stored on-chain (e.g. in `pallet-scheduler`). Thus, migration might be needed. + /// This is why the use of `call_index` is mandatory by default in FRAME. + /// + /// ## Default Behavior + /// + /// If no `#[pallet::call]` exists, then a default implementation corresponding to the following + /// code is automatically generated: + /// + /// ```ignore + /// #[pallet::call] + /// impl Pallet {} + /// ``` + pub use frame_support_procedural::call; + + /// Enforce the index of a variant in the generated `enum Call`. See [`call`] for more + /// information. + /// + /// All call indexes start from 0, until it encounters a dispatchable function with a defined + /// call index. The dispatchable function that lexically follows the function with a defined + /// call index will have that call index, but incremented by 1, e.g. if there are 3 dispatchable + /// functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` has a call index + /// of 10, then `fn qux` will have an index of 11, instead of 1. + pub use frame_support_procedural::call_index; + + /// Declares the arguments of a [`call`] function to be encoded using + /// [`parity_scale_codec::Compact`]. This will results in smaller extrinsic encoding. + /// + /// A common example of `compact` is for numeric values that are often times far far away from + /// their theoretical maximum. For example, in the context of a crypto-currency, the balance of + /// an individual account is often times way less then what the numeric type allows. In all such + /// cases, using `compact` is sensible. + /// + /// ``` + /// #[frame_support::pallet(dev_mode)] + /// pub mod custom_pallet { + /// # use frame_support::pallet_prelude::*; + /// # use frame_system::pallet_prelude::*; + /// # #[pallet::config] + /// # pub trait Config: frame_system::Config {} + /// # #[pallet::pallet] + /// # pub struct Pallet(_); + /// # use frame_support::traits::BuildGenesisConfig; + /// #[pallet::call] + /// impl Pallet { + /// pub fn some_dispatchable(_origin: OriginFor, #[pallet::compact] _input: u32) -> DispatchResult { + /// Ok(()) + /// } + /// } + /// } + pub use frame_support_procedural::compact; + /// Allows you to define the genesis configuration for the pallet. /// /// Item is defined as either an enum or a struct. It needs to be public and implement the diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index f7733e312c3b..36ca9d0ddb36 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -26,6 +26,8 @@ sp-std = { path = "../../primitives/std", default-features = false} sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } +docify = { version = "0.2.4" } + [dev-dependencies] criterion = "0.4.0" sp-externalities = { path = "../../primitives/externalities" } diff --git a/substrate/frame/system/src/lib.rs b/substrate/frame/system/src/lib.rs index dfdacc9a8eb9..1bf19b334f42 100644 --- a/substrate/frame/system/src/lib.rs +++ b/substrate/frame/system/src/lib.rs @@ -1021,6 +1021,7 @@ impl_ensure_origin_with_arg_ignoring_arg! { {} } +#[docify::export] /// Ensure that the origin `o` represents a signed extrinsic (i.e. transaction). /// Returns `Ok` with the account that signed the extrinsic or an `Err` otherwise. pub fn ensure_signed(o: OuterOrigin) -> Result @@ -1353,10 +1354,13 @@ impl Pallet { /// This will update storage entries that correspond to the specified topics. /// It is expected that light-clients could subscribe to this topics. /// - /// NOTE: Events not registered at the genesis block and quietly omitted. + /// NOTE: Events not registered at the genesis block and `not(feature = "std")` and quietly + /// omitted. But, in testing (`feature = "std"`) events are deposited normally. pub fn deposit_event_indexed(topics: &[T::Hash], event: T::RuntimeEvent) { let block_number = Self::block_number(); - // Don't populate events on genesis. + + // Don't populate events on "real" genesis + #[cfg(not(feature = "std"))] if block_number.is_zero() { return } @@ -1539,12 +1543,7 @@ impl Pallet { /// NOTE: Events not registered at the genesis block and quietly omitted. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] pub fn events() -> Vec> { - debug_assert!( - !Self::block_number().is_zero(), - "events not registered at the genesis block" - ); - // Dereferencing the events here is fine since we are not in the - // memory-restricted runtime. + // Dereferencing the events here is fine since we are not in the memory-restricted runtime. Self::read_events_no_consensus().map(|e| *e).collect() } @@ -1565,6 +1564,21 @@ impl Pallet { Events::::stream_iter() } + /// Read and return the events of a specific pallet, as denoted by `E`. + /// + /// This is useful for a pallet that wishes to read only the events it has deposited into + /// `frame_system` using the standard `fn deposit_event`. + pub fn read_events_for_pallet() -> Vec + where + T::RuntimeEvent: TryInto, + { + Events::::get() + .into_iter() + .map(|er| er.event) + .filter_map(|e| e.try_into().ok()) + .collect::<_>() + } + /// Set the block number to something in particular. Can be used as an alternative to /// `initialize` for tests that don't need to bother with the other environment entries. #[cfg(any(feature = "std", feature = "runtime-benchmarks", test))] diff --git a/substrate/frame/tx-pause/src/mock.rs b/substrate/frame/tx-pause/src/mock.rs index 66218c8c015c..609d6d88d2ac 100644 --- a/substrate/frame/tx-pause/src/mock.rs +++ b/substrate/frame/tx-pause/src/mock.rs @@ -206,11 +206,7 @@ pub fn new_test_ext() -> sp_io::TestExternalities { .assimilate_storage(&mut t) .unwrap(); - let mut ext = sp_io::TestExternalities::new(t); - ext.execute_with(|| { - System::set_block_number(1); - }); - ext + sp_io::TestExternalities::new(t) } pub fn next_block() { diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index fcd1779fb5a6..fa9609348079 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -29,6 +29,9 @@ sp-core = { path = "../core", default-features = false} sp-io = { path = "../io", default-features = false} sp-std = { path = "../std", default-features = false} sp-weights = { path = "../weights", default-features = false} +docify = "0.2.4" + +simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } [dev-dependencies] rand = "0.8.5" diff --git a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs index 4b0e017f4517..44325920beee 100644 --- a/substrate/primitives/runtime/src/generic/checked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/checked_extrinsic.rs @@ -26,9 +26,11 @@ use crate::{ transaction_validity::{TransactionSource, TransactionValidity}, }; -/// Definition of something that the external world might want to say; its -/// existence implies that it has been checked and is good, particularly with -/// regards to the signature. +/// Definition of something that the external world might want to say; its existence implies that it +/// has been checked and is good, particularly with regards to the signature. +/// +/// This is typically passed into [`traits::Applyable::apply`], which should execute +/// [`CheckedExtrinsic::function`], alongside all other bits and bobs. #[derive(PartialEq, Eq, Clone, sp_core::RuntimeDebug)] pub struct CheckedExtrinsic { /// Who this purports to be from and the number of extrinsics have come before diff --git a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs index 1cdc0b8e4051..92d8e1e34698 100644 --- a/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs +++ b/substrate/primitives/runtime/src/generic/unchecked_extrinsic.rs @@ -43,16 +43,38 @@ const EXTRINSIC_FORMAT_VERSION: u8 = 4; /// The `SingaturePayload` of `UncheckedExtrinsic`. type UncheckedSignaturePayload = (Address, Signature, Extra); -/// A extrinsic right from the external world. This is unchecked and so -/// can contain a signature. +/// An extrinsic right from the external world. This is unchecked and so can contain a signature. +/// +/// An extrinsic is formally described as any external data that is originating from the outside of +/// the runtime and fed into the runtime as a part of the block-body. +/// +/// Inherents are special types of extrinsics that are placed into the block by the block-builder. +/// they are unsigned because the assertion is that they are "inherently true" by virtue of getting +/// past all validators. +/// +/// Transaction are all other statements provided by external entities that the chain deems values +/// and decided to include in the block. This value is typically in the form of fee payment, but it +/// could in principle be any other interaction. Transactions are either signed, or unsigned. A +/// sensible transaction pool should ensure that only transactions that are worthwhile are +/// considered for block-building. +/// +#[doc = simple_mermaid::mermaid!("../../../../../docs/mermaid/extrinsics.mmd")] +/// This type is by no means enforced within substrate, but given its generic-ness, it is highly +/// likely that for most use-cases it will suffice. Thus, the encoding of this type will dictate +/// exactly what bytes should be sent to a runtime to transact with it. +/// +/// This can be checked using [`Checkable`], yielding a [`CheckedExtrinsic`], which is the +/// counterpart of this type after its signature (and other non-negotiable validity checks) have +/// passed. #[derive(PartialEq, Eq, Clone)] pub struct UncheckedExtrinsic where Extra: SignedExtension, { - /// The signature, address, number of extrinsics have come before from - /// the same signer and an era describing the longevity of this transaction, - /// if this is a signed extrinsic. + /// The signature, address, number of extrinsics have come before from the same signer and an + /// era describing the longevity of this transaction, if this is a signed extrinsic. + /// + /// `None` if it is unsigned or an inherent. pub signature: Option>, /// The function that should be called. pub function: Call, @@ -286,6 +308,7 @@ where } } +#[docify::export(unchecked_extrinsic_encode_impl)] impl Encode for UncheckedExtrinsic where Address: Encode, diff --git a/substrate/src/lib.rs b/substrate/src/lib.rs deleted file mode 100644 index be9eef9952f8..000000000000 --- a/substrate/src/lib.rs +++ /dev/null @@ -1,238 +0,0 @@ -// This file is part of Substrate. - -// Copyright (C) Parity Technologies (UK) Ltd. -// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -//! # 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 Polkadot ecosystem. -//! -//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/) - [![polkadot]](https://polkadot.network) -//! -//! This crate in itself does not contain any code and is just meant ot be a documentation hub for -//! substrate-based crates. -//! -//! ## Overview -//! -//! Substrate approaches blockchain development with an acknowledgement of a few self-evident -//! truths: -//! -//! 1. Society and technology evolves. -//! 2. Humans are fallible. -//! -//! This, specifically, makes the task of designing a correct, safe and long-lasting blockchain -//! system hard. -//! -//! Nonetheless, in order to achieve 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 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 onchain. The rest of the system (called "Client") 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 (without forks). The upgrade -//! is merely a matter of the Wasm blob being changed in the chain state, which is, in principle, -//! same as updating an account's balance. -//! -//! ### Architecture -//! -//! Therefore, Substrate can be visualized as follows: -#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_simple.mmd")] -//! -//! The client and the runtime of course need to communicate. This is done through two concepts: -//! -//! 1. Host functions: a way for the (Wasm) runtime to talk to the client. 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. -//! 2. Runtime APIs: a way for the client 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 basic -//! runtime API that any blockchain must implement in order to be able to (re) execute blocks. -#![doc = simple_mermaid::mermaid!("../../docs/mermaid/substrate_client_runtime.mmd")] -//! -//! [`FRAME`], Substrate's default runtime development library takes the above even further by -//! embracing a declarative programming model whereby correctness is enhanced and the system is -//! highly configurable through parameterization. -//! -//! All in all, this design enables all substrate-based chains to achieve forkless, self-enacting -//! upgrades out of the box. Combined with governance abilities that are shipped with `FRAME`, this -//! enables a chain to survive the test of time. -//! -//! ## How to Get Stared -//! -//! Most developers want to leave the client side code as-is, and focus on the runtime. To do so, -//! look into the [`frame`] crate, which is the entry point crate into runtime development with -//! FRAME. -//! -//! > Side note, it is entirely possible to craft a substrate-based runtime without FRAME, an -//! > example of which can be found [here](https://github.com/JoshOrndorff/frameless-node-template). -//! -//! In more broad terms, the following avenues exist into developing with substrate: -//! -//! * **Templates**: A number of substrate-based templates exist and they can be used for various -//! purposes, with zero to little additional code needed. All of these templates contain runtimes -//! that are highly configurable and are likely suitable for basic needs. -//! * [`FRAME`]: If need, one can customize that runtime even further, by using `FRAME` and -//! developing custom modules. -//! * **Core**: To the contrary, some developers may want to customize the client side software to -//! achieve novel goals such as a new consensus engine, or a new database backend. While -//! Substrate's main configurability is in the runtime, the client is also highly generic and can -//! be customized to a great extent. -//! -//! ## Structure -//! -//! Substrate is a massive cargo workspace with hundreds of crates, therefore it is useful to know -//! how to navigate its crates. -//! -//! In broad terms, it is divided into three categories: -//! -//! * `sc-*` (short for *substrate-client*) crates, located under `./client` folder. These are all -//! the client crates. Notable examples are crates such as [`sc-network`], various consensus -//! crates, [`sc-rpc-api`] and [`sc-client-db`], all of which are expected to reside in the client -//! side. -//! * `sp-*` (short for *substrate-primitives*) crates, located under `./primitives` folder. These -//! are the traits that glue the client and runtime together, 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 client 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 commandsOnce built, the wasm file is placed in -//! `./target/{debug|release}/wbuild/{runtime_name}.wasm`. -//! -//! ### Binaries -//! -//! Multiple binaries are shipped with substrate, the most important of which are located in the -//! `./bin` folder. -//! -//! * [`node`] is an extensive substrate node that contains the superset of all runtime and client -//! 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. -//! * [`chain-spec-builder`]: Utility to build more detailed chain-specs for the aforementioned -//! node. Other projects typically contain a `build-spec` subcommand that does the same. -//! * [`node-template`]: a template node that contains a minimal set of features and can act as a -//! starting point of a project. -//! * [`subkey`]: Substrate's key management utility. -//! -//! ### Anatomy of a Binary Crate -//! -//! From the above, [`node`] 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_support::construct_runtime`] macro, which is the -//! final definition of a runtime. -//! -//! * Under `./node`, a `main.rs`, which is the point, and a `./service.rs`, which contains all the -//! client side components. Skimming this file yields an overview of the networking, database, -//! consensus and similar client side components. -//! -//! > The above two are conventions, not rules. -//! -//! ## Parachain? -//! -//! As noted above, Substrate is the main engine behind the Polkadot ecosystem. One of the ways -//! through which Polkadot can be utilized is by building "parachains", blockchains that are -//! connected to Polkadot's shared security. -//! -//! To build a parachain, one could use -//! [`Cumulus`](https://github.com/paritytech/polkadot-sdk/tree/master/cumulus), the library on top -//! of Substrate, empowering any substrate-based chain to be a Polkadot parachain. -//! -//! ## 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`] -//! - [`sc-consensus-manual-seal`] -//! - [`sc-consensus-pow`] -//! -//! Additional noteworthy external resources: -//! -//! - [Substrate Developer Hub](https://substrate.dev) -//! - [Parity Tech's Documentation Hub](https://paritytech.github.io/) -//! - [Frontier: Substrate's Ethereum Compatibility Library](https://paritytech.github.io/frontier/) -//! - [Polkadot Wiki](https://wiki.polkadot.network/en/) -//! -//! Notable upstream crates: -//! -//! - [`parity-scale-codec`](https://github.com/paritytech/parity-scale-codec) -//! - [`parity-db`](https://github.com/paritytech/parity-db) -//! - [`trie`](https://github.com/paritytech/trie) -//! - [`parity-common`](https://github.com/paritytech/parity-common) -//! -//! Templates: -//! -//! - classic [`substrate-node-template`](https://github.com/substrate-developer-hub/substrate-node-template) -//! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) -//! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) -//! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) -//! -//! [polkadot]: -//! https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white -//! [github]: -//! https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github -//! [`FRAME`]: ../frame/index.html -//! [`sp-io`]: ../sp_io/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sp-api`]: ../sp_api/index.html -//! [`sc-client-db`]: ../sc_client_db/index.html -//! [`sc-network`]: ../sc_network/index.html -//! [`sc-rpc-api`]: ../sc_rpc_api/index.html -//! [`sc-rpc`]: ../sc_rpc/index.html -//! [`sc-cli`]: ../sc_cli/index.html -//! [`sc-consensus-aura`]: ../sc_consensus_aura/index.html -//! [`sc-consensus-babe`]: ../sc_consensus_babe/index.html -//! [`sc-consensus-grandpa`]: ../sc_consensus_grandpa/index.html -//! [`sc-consensus-beefy`]: ../sc_consensus_beefy/index.html -//! [`sc-consensus-manual-seal`]: ../sc_consensus_manual_seal/index.html -//! [`sc-consensus-pow`]: ../sc_consensus_pow/index.html -//! [`node`]: ../node_cli/index.html -//! [`node-template`]: ../node_template/index.html -//! [`kitchensink_runtime`]: ../kitchensink_runtime/index.html -//! [`subkey`]: ../subkey/index.html -//! [`chain-spec-builder`]: ../chain_spec_builder/index.html -//! [`substrate-wasm-builder`]: https://crates.io/crates/substrate-wasm-builder - -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::private_intra_doc_links)] From 68a053b3911d770348c1ed8880bc7995c63967d5 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 10:58:38 +0000 Subject: [PATCH 02/66] fix some things --- .github/workflows/docs.yml | 34 ------------------- Cargo.lock | 15 ++++++++ developer-hub/Cargo.toml | 32 ++++++++--------- developer-hub/src/lib.rs | 4 +-- .../src/polkadot_sdk/frame_runtime.rs | 11 +++--- .../src/reference_docs/wasm_meta_protocol.rs | 2 +- .../src/tutorial/currency_simple/mod.rs | 2 +- .../procedural/src/pallet/parse/call.rs | 30 ++++++---------- 8 files changed, 53 insertions(+), 77 deletions(-) delete mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index 7c9404c66c90..000000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: Rust Docs - -on: - push: - branches: [kiz-umbrella-crates] - -jobs: - docs: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - - # Setup protoc - - name: Set up Protocol Buffers - uses: arduino/setup-protoc@v1 - - - name: Setup Rust - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - components: rust-docs - target: wasm32-unknown-unknown - - - name: Generate docs - run: cargo doc -p developer-hub -p sp-io -p sp-runtime -p frame -p frame-support --no-deps - - - name: Deploy - uses: JamesIves/github-pages-deploy-action@v4 - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages # The branch the action should deploy to. - FOLDER: target/doc # The folder the action should deploy. diff --git a/Cargo.lock b/Cargo.lock index 9a00f6214b81..f2da733ff7bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4413,15 +4413,29 @@ dependencies = [ name = "developer-hub" version = "0.0.1" dependencies = [ + "chain-spec-builder", "cumulus-pallet-aura-ext", "cumulus-pallet-parachain-system", "docify", "frame", + "kitchensink-runtime", + "node-cli", "pallet-aura", "pallet-default-config-example", "pallet-timestamp", "parachain-info", "parity-scale-codec", + "sc-cli", + "sc-client-db", + "sc-consensus-aura", + "sc-consensus-babe", + "sc-consensus-beefy", + "sc-consensus-grandpa", + "sc-consensus-manual-seal", + "sc-consensus-pow", + "sc-network", + "sc-rpc", + "sc-rpc-api", "scale-info", "simple-mermaid 0.1.0 (git+https://github.com/kianenigma/simple-mermaid.git?branch=main)", "sp-api", @@ -4429,6 +4443,7 @@ dependencies = [ "sp-io", "sp-keyring", "sp-runtime", + "subkey", "substrate-wasm-builder", ] diff --git a/developer-hub/Cargo.toml b/developer-hub/Cargo.toml index 304173e7250d..765c3ee26436 100644 --- a/developer-hub/Cargo.toml +++ b/developer-hub/Cargo.toml @@ -21,22 +21,22 @@ simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", bra docify = "0.2.6" # Polkadot SDK docs, typically all should only be scope such that we can link to their doc item. -# node-cli = { path = "../substrate/bin/node/cli" } -# kitchensink-runtime = { path = "../substrate/bin/node/runtime" } -# chain-spec-builder = { path = "../substrate/bin/utils/chain-spec-builder" } -# subkey = { path = "../substrate/bin/utils/subkey" } - -# sc-network = { path = "../substrate/client/network" } -# sc-rpc-api = { path = "../substrate/client/rpc-api" } -# sc-rpc = { path = "../substrate/client/rpc" } -# sc-client-db = { path = "../substrate/client/db" } -# sc-cli = { path = "../substrate/client/cli" } -# sc-consensus-aura = { path = "../substrate/client/consensus/aura" } -# sc-consensus-babe = { path = "../substrate/client/consensus/babe" } -# sc-consensus-grandpa = { path = "../substrate/client/consensus/grandpa" } -# sc-consensus-beefy = { path = "../substrate/client/consensus/beefy" } -# sc-consensus-manual-seal = { path = "../substrate/client/consensus/manual-seal" } -# sc-consensus-pow = { path = "../substrate/client/consensus/pow" } +node-cli = { path = "../substrate/bin/node/cli" } +kitchensink-runtime = { path = "../substrate/bin/node/runtime" } +chain-spec-builder = { path = "../substrate/bin/utils/chain-spec-builder" } +subkey = { path = "../substrate/bin/utils/subkey" } + +sc-network = { path = "../substrate/client/network" } +sc-rpc-api = { path = "../substrate/client/rpc-api" } +sc-rpc = { path = "../substrate/client/rpc" } +sc-client-db = { path = "../substrate/client/db" } +sc-cli = { path = "../substrate/client/cli" } +sc-consensus-aura = { path = "../substrate/client/consensus/aura" } +sc-consensus-babe = { path = "../substrate/client/consensus/babe" } +sc-consensus-grandpa = { path = "../substrate/client/consensus/grandpa" } +sc-consensus-beefy = { path = "../substrate/client/consensus/beefy" } +sc-consensus-manual-seal = { path = "../substrate/client/consensus/manual-seal" } +sc-consensus-pow = { path = "../substrate/client/consensus/pow" } sp-io = { path = "../substrate/primitives/io" } sp-api = { path = "../substrate/primitives/api" } diff --git a/developer-hub/src/lib.rs b/developer-hub/src/lib.rs index f8a168813968..365fa60d64cf 100644 --- a/developer-hub/src/lib.rs +++ b/developer-hub/src/lib.rs @@ -102,8 +102,8 @@ //! //! For more details about documenting guidelines, see: //! -#![warn(rustdoc::broken_intra_doc_links)] -#![warn(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] /// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, /// the tools that are provided as a part of it, and to gain a high level understanding of each. diff --git a/developer-hub/src/polkadot_sdk/frame_runtime.rs b/developer-hub/src/polkadot_sdk/frame_runtime.rs index 30bff8ad91e7..f6e10d0b485a 100644 --- a/developer-hub/src/polkadot_sdk/frame_runtime.rs +++ b/developer-hub/src/polkadot_sdk/frame_runtime.rs @@ -34,11 +34,14 @@ //! make as few assumptions about the general runtime as possible. A pallet 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 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: //! -//! - [Config](frame::pallet_macros::config), allowing a pallet to make itself configurable and generic over types, values and such. +//! - [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 aka. Extrinsics](frame::pallet_macros::call), allowing a pallet to define extrinsics that are callable by end users, from the outer world. +//! - [Dispatchable function aka. Extrinsics](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. //! @@ -58,7 +61,7 @@ //! //! 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::impl_runtime_apis`] macro. +//! [`frame::runtime::prelude::impl_runtime_apis`] macro. //! //! ### Example //! diff --git a/developer-hub/src/reference_docs/wasm_meta_protocol.rs b/developer-hub/src/reference_docs/wasm_meta_protocol.rs index 83a7bbf66c15..d4e5df765722 100644 --- a/developer-hub/src/reference_docs/wasm_meta_protocol.rs +++ b/developer-hub/src/reference_docs/wasm_meta_protocol.rs @@ -104,4 +104,4 @@ //! //! ## Example: Block Execution. //! -//! TODO: +//! diff --git a/developer-hub/src/tutorial/currency_simple/mod.rs b/developer-hub/src/tutorial/currency_simple/mod.rs index b968a0f8343e..29d81f876a8e 100644 --- a/developer-hub/src/tutorial/currency_simple/mod.rs +++ b/developer-hub/src/tutorial/currency_simple/mod.rs @@ -24,7 +24,7 @@ //! - [Event](frame::pallet_macros::event) //! - [Error](frame::pallet_macros::error) //! - Basics of testing a pallet. -//! - [Constructing a runtime](frame::runtime::construct_runtime) +//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime) //! //! ## Writing Your First Pallet //! diff --git a/substrate/frame/support/procedural/src/pallet/parse/call.rs b/substrate/frame/support/procedural/src/pallet/parse/call.rs index c7e45cace6ee..8ebc162ea0db 100644 --- a/substrate/frame/support/procedural/src/pallet/parse/call.rs +++ b/substrate/frame/support/procedural/src/pallet/parse/call.rs @@ -139,8 +139,8 @@ impl syn::parse::Parse for ArgAttrIsCompact { } } -/// Check the syntax is `OriginFor` or `T::RuntimeOrigin` or `::RuntimeOrigin`. -pub fn check_dispatchable_first_arg_type(ty: &syn::Type, system: &syn::Path) -> syn::Result<()> { +/// Check the syntax is `OriginFor` or `T::RuntimeOrigin`. +pub fn check_dispatchable_first_arg_type(ty: &syn::Type) -> syn::Result<()> { pub struct CheckOriginFor; impl syn::parse::Parse for CheckOriginFor { fn parse(input: syn::parse::ParseStream) -> syn::Result { @@ -164,23 +164,15 @@ pub fn check_dispatchable_first_arg_type(ty: &syn::Type, system: &syn::Path) -> } } - pub struct CheckSystemRuntimeOrigin; - impl syn::parse::Parse for CheckSystemRuntimeOrigin { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - input.parse::()?; - input.parse::()?; - input.parse::()?; - - Ok(Self) - } - } - - // syn::parse2::(ty.to_token_stream()).map_err(|e| { - // let msg = "Invalid type: expected `OriginFor`"; - // let mut err = syn::Error::new(ty.span(), msg); - // err.combine(e); - // err - // })?; + syn::parse2::(ty.to_token_stream()) + .map(|_| ()) + .or_else(|_| syn::parse2::(ty.to_token_stream()).map(|_| ())) + .map_err(|e| { + let msg = "Invalid type: expected `OriginFor`"; + let mut err = syn::Error::new(ty.span(), msg); + err.combine(e); + err + })?; Ok(()) } From f7460d86073bbd4e8259cce3c7730e48456f4139 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 11:14:12 +0000 Subject: [PATCH 03/66] small fixes --- developer-hub/src/polkadot_sdk/frame_runtime.rs | 2 +- substrate/frame/src/lib.rs | 2 +- substrate/frame/system/Cargo.toml | 2 +- substrate/primitives/runtime/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/developer-hub/src/polkadot_sdk/frame_runtime.rs b/developer-hub/src/polkadot_sdk/frame_runtime.rs index f6e10d0b485a..7424792a8773 100644 --- a/developer-hub/src/polkadot_sdk/frame_runtime.rs +++ b/developer-hub/src/polkadot_sdk/frame_runtime.rs @@ -1,6 +1,6 @@ //! # FRAME //! -//! ```co_compile +//! ```no_compile //! ______ ______ ________ ___ __ __ ______ //! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ //! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ diff --git a/substrate/frame/src/lib.rs b/substrate/frame/src/lib.rs index c70943c945df..c123b54cd30e 100644 --- a/substrate/frame/src/lib.rs +++ b/substrate/frame/src/lib.rs @@ -17,7 +17,7 @@ //! # FRAME //! -//! ```co_compile +//! ```no_compile //! ______ ______ ________ ___ __ __ ______ //! /_____/\ /_____/\ /_______/\ /__//_//_/\ /_____/\ //! \::::_\/_\:::_ \ \ \::: _ \ \\::\| \| \ \\::::_\/_ diff --git a/substrate/frame/system/Cargo.toml b/substrate/frame/system/Cargo.toml index 36ca9d0ddb36..6a2143653ef4 100644 --- a/substrate/frame/system/Cargo.toml +++ b/substrate/frame/system/Cargo.toml @@ -26,7 +26,7 @@ sp-std = { path = "../../primitives/std", default-features = false} sp-version = { path = "../../primitives/version", default-features = false, features = ["serde"] } sp-weights = { path = "../../primitives/weights", default-features = false, features = ["serde"] } -docify = { version = "0.2.4" } +docify = { version = "0.2.6" } [dev-dependencies] criterion = "0.4.0" diff --git a/substrate/primitives/runtime/Cargo.toml b/substrate/primitives/runtime/Cargo.toml index fa9609348079..1e9115c30e32 100644 --- a/substrate/primitives/runtime/Cargo.toml +++ b/substrate/primitives/runtime/Cargo.toml @@ -29,7 +29,7 @@ sp-core = { path = "../core", default-features = false} sp-io = { path = "../io", default-features = false} sp-std = { path = "../std", default-features = false} sp-weights = { path = "../weights", default-features = false} -docify = "0.2.4" +docify = { version = "0.2.6" } simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } From b785e5c9d719553e902e2734b60e75cc43c0cd2e Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:16:27 +0000 Subject: [PATCH 04/66] Create docs.yml --- .github/workflows/docs.yml | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000000..7c9404c66c90 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,34 @@ +name: Rust Docs + +on: + push: + branches: [kiz-umbrella-crates] + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + # Setup protoc + - name: Set up Protocol Buffers + uses: arduino/setup-protoc@v1 + + - name: Setup Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + components: rust-docs + target: wasm32-unknown-unknown + + - name: Generate docs + run: cargo doc -p developer-hub -p sp-io -p sp-runtime -p frame -p frame-support --no-deps + + - name: Deploy + uses: JamesIves/github-pages-deploy-action@v4 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages # The branch the action should deploy to. + FOLDER: target/doc # The folder the action should deploy. From 00a0fec1ec0ad8c56d43edacd0faabf67a502870 Mon Sep 17 00:00:00 2001 From: Kian Paimani <5588131+kianenigma@users.noreply.github.com> Date: Tue, 31 Oct 2023 11:16:41 +0000 Subject: [PATCH 05/66] Update docs.yml --- .github/workflows/docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 7c9404c66c90..13ac21cd9000 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -2,7 +2,7 @@ name: Rust Docs on: push: - branches: [kiz-umbrella-crates] + branches: [kiz-developer-hub] jobs: docs: From 50c78b44dbec76e49fc14cad85b3bbd00ac5a54a Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 11:36:33 +0000 Subject: [PATCH 06/66] fix some warnings --- substrate/frame/support/src/lib.rs | 65 ++++++++++---------- substrate/frame/support/src/migrations.rs | 3 +- substrate/frame/support/src/storage/child.rs | 6 +- substrate/frame/support/src/storage/mod.rs | 6 +- 4 files changed, 40 insertions(+), 40 deletions(-) diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index c8756c955597..0d59cba6b760 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -47,7 +47,7 @@ pub mod __private { pub use sp_core::{OpaqueMetadata, Void}; pub use sp_core_hashing_proc_macro; pub use sp_inherents; - pub use sp_io::{self, storage::root as storage_root}; + pub use sp_io::{self, storage::root as storage_root, TestExternalities}; pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; @@ -57,7 +57,6 @@ pub mod __private { pub use sp_std; pub use sp_tracing; pub use tt_call::*; - pub use sp_io::TestExternalities; } #[macro_use] @@ -2200,28 +2199,30 @@ pub use frame_support_procedural::pallet; /// Contains macro stubs for all of the pallet:: macros pub mod pallet_macros { pub use frame_support_procedural::{ - composite_enum, config, constant, disable_frame_system_supertrait_check, error, - event, extra_constants, generate_deposit, generate_store, getter, hooks, import_section, - inherent, no_default, no_default_bounds, origin, pallet_section, storage, storage_prefix, + composite_enum, config, constant, disable_frame_system_supertrait_check, error, event, + extra_constants, generate_deposit, generate_store, getter, hooks, import_section, inherent, + no_default, no_default_bounds, origin, pallet_section, storage, storage_prefix, storage_version, type_value, unbounded, validate_unsigned, weight, whitelist_storage, }; - /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. In slightly - /// simplified terms, this macro declares the set of "transactions" of a pallet. + /// Allows a pallet to declare a set of functions as a *dispatchable extrinsic*. In + /// slightly simplified terms, this macro declares the set of "transactions" of a pallet. /// /// > The exact definition of **extrinsic** can be found in /// > [`sp_runtime::generic::UncheckedExtrinsic`]. /// /// A **dispatchable** is a common term in FRAME, referring to process of constructing a - /// function, and dispatching it with the correct inputs. This is commonly used with extrinsics, - /// for example "an extrinsic has been dispatched". See [`sp_runtime::traits::Dispatchable`] and - /// [`crate::dispatch::UnfilteredDispatch`]. + /// function, and dispatching it with the correct inputs. This is commonly used with + /// extrinsics, for example "an extrinsic has been dispatched". See + /// [`sp_runtime::traits::Dispatchable`] and + /// [`crate::traits::UnfilteredDispatchable`]. /// /// ## Call Enum /// - /// The macro is called `call` (rather than `#[pallet::extrinsics]`) because of the generation - /// of a `enum Call`. This enum contains only the encoding of the function arguments of the - /// dispatchable, alongside the information needed to route it to the correct function. + /// The macro is called `call` (rather than `#[pallet::extrinsics]`) because of the + /// generation of a `enum Call`. This enum contains only the encoding of the function + /// arguments of the dispatchable, alongside the information needed to route it to the + /// correct function. /// /// ``` /// #[frame_support::pallet(dev_mode)] @@ -2270,7 +2271,7 @@ pub mod pallet_macros { /// # TestExternalities::new_empty().execute_with(|| { /// let origin: RuntimeOrigin = frame_system::RawOrigin::Signed(10).into(); /// // calling into a dispatchable from within the runtime is simply a function call. - /// let _ = custom_pallet::Pallet::::some_dispatchable(origin.clone(), 10); + /// let _ = custom_pallet::Pallet::::some_dispatchable(origin.clone(), 10); /// /// // calling into a dispatchable from the outer world involves constructing the bytes of /// let call = custom_pallet::Call::::some_dispatchable { input: 10 }; @@ -2284,14 +2285,14 @@ pub mod pallet_macros { /// // referring to the second variant of `enum Call`. /// let call = custom_pallet::Call::::other { input: 10 }; /// assert_eq!(call.encode(), vec![1u8, 10, 0, 0, 0, 0, 0, 0, 0]); - /// # }); + /// # }); /// } /// ``` /// /// Further properties of dispatchable functions are as follows: /// - /// - Unless if annotated by `dev_mode`, it must contain [`weight`] to denote the pre-dispatch - /// weight consumed. + /// - Unless if annotated by `dev_mode`, it must contain [`weight`] to denote the + /// pre-dispatch weight consumed. /// - The dispatchable must declare its index via [`call_index`], which can override the /// position of a function in `enum Call`. /// - The first argument is always an `OriginFor` (or `T::RuntimeOrigin`). @@ -2299,14 +2300,14 @@ pub mod pallet_macros { /// [`crate::dispatch::DispatchResultWithPostInfo`]). /// /// **WARNING**: modifying dispatchables, changing their order (ie. using [`call_index`]), - /// removing some, etc., must be done with care. This will change the encoding of the , and the - /// call can be stored on-chain (e.g. in `pallet-scheduler`). Thus, migration might be needed. - /// This is why the use of `call_index` is mandatory by default in FRAME. + /// removing some, etc., must be done with care. This will change the encoding of the , and + /// the call can be stored on-chain (e.g. in `pallet-scheduler`). Thus, migration might be + /// needed. This is why the use of `call_index` is mandatory by default in FRAME. /// /// ## Default Behavior /// - /// If no `#[pallet::call]` exists, then a default implementation corresponding to the following - /// code is automatically generated: + /// If no `#[pallet::call]` exists, then a default implementation corresponding to the + /// following code is automatically generated: /// /// ```ignore /// #[pallet::call] @@ -2317,20 +2318,20 @@ pub mod pallet_macros { /// Enforce the index of a variant in the generated `enum Call`. See [`call`] for more /// information. /// - /// All call indexes start from 0, until it encounters a dispatchable function with a defined - /// call index. The dispatchable function that lexically follows the function with a defined - /// call index will have that call index, but incremented by 1, e.g. if there are 3 dispatchable - /// functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn bar` has a call index - /// of 10, then `fn qux` will have an index of 11, instead of 1. + /// All call indexes start from 0, until it encounters a dispatchable function with a + /// defined call index. The dispatchable function that lexically follows the function with + /// a defined call index will have that call index, but incremented by 1, e.g. if there are + /// 3 dispatchable functions `fn foo`, `fn bar` and `fn qux` in that order, and only `fn + /// bar` has a call index of 10, then `fn qux` will have an index of 11, instead of 1. pub use frame_support_procedural::call_index; /// Declares the arguments of a [`call`] function to be encoded using - /// [`parity_scale_codec::Compact`]. This will results in smaller extrinsic encoding. + /// [`codec::Compact`]. This will results in smaller extrinsic encoding. /// - /// A common example of `compact` is for numeric values that are often times far far away from - /// their theoretical maximum. For example, in the context of a crypto-currency, the balance of - /// an individual account is often times way less then what the numeric type allows. In all such - /// cases, using `compact` is sensible. + /// A common example of `compact` is for numeric values that are often times far far away + /// from their theoretical maximum. For example, in the context of a crypto-currency, the + /// balance of an individual account is often times way less then what the numeric type + /// allows. In all such cases, using `compact` is sensible. /// /// ``` /// #[frame_support::pallet(dev_mode)] diff --git a/substrate/frame/support/src/migrations.rs b/substrate/frame/support/src/migrations.rs index d6ae6c6291b1..ed0ed15cb78a 100644 --- a/substrate/frame/support/src/migrations.rs +++ b/substrate/frame/support/src/migrations.rs @@ -224,8 +224,7 @@ impl PalletVersionToStorageVersionHelper for T { } } -/// Migrate from the `PalletVersion` struct to the new -/// [`StorageVersion`](crate::traits::StorageVersion) struct. +/// Migrate from the `PalletVersion` struct to the new [`StorageVersion`] struct. /// /// This will remove all `PalletVersion's` from the state and insert the current storage version. pub fn migrate_from_pallet_version_to_storage_version< diff --git a/substrate/frame/support/src/storage/child.rs b/substrate/frame/support/src/storage/child.rs index e54002d18db3..76e6f4ee4023 100644 --- a/substrate/frame/support/src/storage/child.rs +++ b/substrate/frame/support/src/storage/child.rs @@ -165,9 +165,9 @@ pub fn kill_storage(child_info: &ChildInfo, limit: Option) -> KillStorageRe /// guarantee that the subsequent call is in a new block; in this case the previous call's result /// cursor need not be passed in an a `None` may be passed instead. This exception may be useful /// then making this call solely from a block-hook such as `on_initialize`. -/// -/// Returns [`MultiRemovalResults`](sp_io::MultiRemovalResults) to inform about the result. Once the -/// resultant `maybe_cursor` field is `None`, then no further items remain to be deleted. + +/// Returns [`MultiRemovalResults`] to inform about the result. Once the resultant `maybe_cursor` +/// field is `None`, then no further items remain to be deleted. /// /// NOTE: After the initial call for any given child storage, it is important that no keys further /// keys are inserted. If so, then they may or may not be deleted by subsequent calls. diff --git a/substrate/frame/support/src/storage/mod.rs b/substrate/frame/support/src/storage/mod.rs index 851b0687bd12..9b95d040eb8a 100644 --- a/substrate/frame/support/src/storage/mod.rs +++ b/substrate/frame/support/src/storage/mod.rs @@ -1486,7 +1486,7 @@ pub trait StorageTryAppend: StorageDecodeLength + private::Sealed { fn bound() -> usize; } -/// Storage value that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage value that is capable of [`StorageTryAppend`]. pub trait TryAppendValue, I: Encode> { /// Try and append the `item` into the storage item. /// @@ -1515,7 +1515,7 @@ where } } -/// Storage map that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage map that is capable of [`StorageTryAppend`]. pub trait TryAppendMap, I: Encode> { /// Try and append the `item` into the storage map at the given `key`. /// @@ -1549,7 +1549,7 @@ where } } -/// Storage double map that is capable of [`StorageTryAppend`](crate::storage::StorageTryAppend). +/// Storage double map that is capable of [`StorageTryAppend`]. pub trait TryAppendDoubleMap, I: Encode> { /// Try and append the `item` into the storage double map at the given `key`. /// From c91250b17d713866a727764e441442bc10408de9 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 12:38:57 +0000 Subject: [PATCH 07/66] fix some warnings --- developer-hub/src/lib.rs | 8 +-- developer-hub/src/polkadot_sdk/mod.rs | 5 +- developer-hub/src/polkadot_sdk/polkadot.rs | 57 +++++++++++++++++--- developer-hub/src/polkadot_sdk/templates.rs | 10 ++++ developer-hub/src/polkadot_sdk/xcm.rs | 1 + developer-hub/src/reference_docs/metadata.rs | 0 developer-hub/src/reference_docs/mod.rs | 4 ++ docs/mermaid/IA.mmd | 1 + substrate/frame/support/src/lib.rs | 4 +- 9 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 developer-hub/src/polkadot_sdk/xcm.rs create mode 100644 developer-hub/src/reference_docs/metadata.rs diff --git a/developer-hub/src/lib.rs b/developer-hub/src/lib.rs index 365fa60d64cf..ae4e37fb4c3e 100644 --- a/developer-hub/src/lib.rs +++ b/developer-hub/src/lib.rs @@ -31,7 +31,9 @@ //! //! ### Checklist //! -//! TODO +//! - [ ] Always make sure all downstream types and items are improved. +//! - [ ] Make sure you read all relevant documents, build on top of. Imagine the process of posting +//! something new in SE. //! //! ### Note on `crates.io` and Publishing //! @@ -102,8 +104,8 @@ //! //! For more details about documenting guidelines, see: //! -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(rustdoc::private_intra_doc_links)] +#![warn(rustdoc::broken_intra_doc_links)] +#![warn(rustdoc::private_intra_doc_links)] /// An introduction to the Polkadot SDK. Read this module to learn about the structure of the SDK, /// the tools that are provided as a part of it, and to gain a high level understanding of each. diff --git a/developer-hub/src/polkadot_sdk/mod.rs b/developer-hub/src/polkadot_sdk/mod.rs index a7b0c687b2da..5aa36f87551b 100644 --- a/developer-hub/src/polkadot_sdk/mod.rs +++ b/developer-hub/src/polkadot_sdk/mod.rs @@ -15,12 +15,12 @@ //! [![Runtime](https://img.shields.io/badge/fellowship-runtimes-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/runtimes) //! [![Manifesto](https://img.shields.io/badge/fellowship-manifesto-e6007a?logo=polkadot)](https://github.com/polkadot-fellows/manifesto) //! -//! //! ## Getting Started //! //! The primary way to get started with the Polkadot SDK is to start writing a Substrate-based //! runtime using FRAME. See: //! +//! 0. [`polkadot`], to understand what is Polkadot as a development platform. //! 1. [`substrate`], for an overview of what Substrate is. //! 2. Jump right into [`frame`] to learn about how to write a FRAME-based blockchain runtime. //! 3. Continue with the [`developer_hub`'s "getting started"](crate#getting-started). @@ -119,3 +119,6 @@ pub mod smart_contracts; pub mod substrate; /// Index of all the templates that can act as an initial scaffold for a new project. pub mod templates; + +/// Learn about XCM, the de-facto communication language between different consensus systems. +pub mod xcm; diff --git a/developer-hub/src/polkadot_sdk/polkadot.rs b/developer-hub/src/polkadot_sdk/polkadot.rs index d6bbcd4d7fea..13b6d8f7b75e 100644 --- a/developer-hub/src/polkadot_sdk/polkadot.rs +++ b/developer-hub/src/polkadot_sdk/polkadot.rs @@ -4,10 +4,55 @@ //! //! ## Getting Involved //! -//! [![PolkadotForum](https://img.shields.io/badge/Polkadot_Forum-e6007a?logo=polkadot)](https://forum.polkadot.network/) -//! - RFCs TODO -//! - Polkadot Fellowship TODO -//! - Polkadot Specs -//! - Polkadot Implementor's guide +//! - [Polkadot Forum](https://forum.polkadot.network/) +//! - Polkadot Fellowship +//! - [Runtimes](https://github.com/polkadot-fellows/runtimes) +//! - [RFCs](https://github.com/polkadot-fellows/rfcs) +//! - [Polkadot Specs](spec.polkadot.network) +//! - [The Polkadot Parachain Host Implementers' Guide](https://paritytech.github.io/polkadot-sdk/book/) +//! - [Whitepaper](https://www.polkadot.network/whitepaper/) //! -//! ## What is Polkadot +//! ## Platform +//! +//! ### Polkadot 1.x +//! +//! The original vision of Polkadot (i.e. **Polkadot 1**) revolves around the following arguments: +//! +//! * Future is multi-chain, because we need different chains with different specialization to +//! achieve widespread goals. +//! * In other words, no single chain is good enough to achieve this. +//! * A multi-chain future will inadvertently suffer from fragmentation of economic security. +//! * This stake fragmentation will make communication over consensus system with varying security +//! levels inherently unsafe. +//! +//! Polkadot's answer to the above is: +//! +//! * Shared Security: The idea of shared economic security sits at the core of Polkadot. Polkadot +//! enables different blockchains (ie. "*Parachains*") to pool their economic security from +//! Polkadot (ie. "*Relay Chain*"). +//! * A framework to build blockchains: In order to materialize the multi-chain future, an easy +//! blockchain framework must exist. This is [`crate::polkadot_sdk::substrate`], +//! [`crate::polkadot_sdk::frame_runtime`] and [`crate::polkadot_sdk::cumulus`]. +//! * A communication language between blockchains: In order for these blockchains to communicate, +//! they need a shared language. [`crate::polkadot_sdk::xcm`] is one such language. +//! +//! > Note that the interoperability promised by Polkadot is unparalleled in that any two parachains +//! > connected to Polkadot have the same security and can have much higher guarantees about the +//! > security of the recipient of any message. +//! +//! Polkadot delivers the above vision, alongside a flexible means for parachains to schedule +//! themselves with the Relay Chain. To achieve this, Polkadot has been developed with an +//! architecture similar to that of a computer. Polkadot Relay Chain has a number of "cores". Each +//! is (in simple terms) is capable of progressing 1 parachain a a time. For example, a parachain +//! can schedule itself for on a single core for 5 blocks. +//! +//! Within the scope of Polkadot 1.x, two main scheduling ways has been considered: +//! +//! * Long term Parachains, obtained through locking a sum of DOT in an auction system. +//! * on-demand Parachains, purchased through paying DOT to the relay-chain whenever needed. +//! +//! This scheduling system, and its evolution is the segway into Polkadot 2.x +//! +//! ### Polkadot 2.x +//! +//! diff --git a/developer-hub/src/polkadot_sdk/templates.rs b/developer-hub/src/polkadot_sdk/templates.rs index bd1a2520334f..fa9a7480ddee 100644 --- a/developer-hub/src/polkadot_sdk/templates.rs +++ b/developer-hub/src/polkadot_sdk/templates.rs @@ -4,3 +4,13 @@ //! - classic [cumulus-parachain-template](https://github.com/substrate-developer-hub/substrate-parachain-template) //! - [`extended-parachain-template`](https://github.com/paritytech/extended-parachain-template) //! - [`frontier-parachain-template`](https://github.com/paritytech/frontier-parachain-template) + +// NOTE: a super important detail that I am looking forward to here is +// and +// . Meaning that I would not spend time on +// teaching someone too much detail about the ugly thing we call "node" nowadays. In the future, I +// am sure we will either have a better "node-builder" code that can actually be tested, or an +// "omni-node" that can run (almost) any wasm file. We should already build tutorials in this +// direction IMO. This also affects all the templates. If we have a good neat runtime file, which we +// are moving toward, and a good node-builder, we don't need all of these damn templates. These +// templates are only there because the boilerplate is super horrible atm. diff --git a/developer-hub/src/polkadot_sdk/xcm.rs b/developer-hub/src/polkadot_sdk/xcm.rs new file mode 100644 index 000000000000..9cdf70eb309e --- /dev/null +++ b/developer-hub/src/polkadot_sdk/xcm.rs @@ -0,0 +1 @@ +//! # XCM diff --git a/developer-hub/src/reference_docs/metadata.rs b/developer-hub/src/reference_docs/metadata.rs new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/developer-hub/src/reference_docs/mod.rs b/developer-hub/src/reference_docs/mod.rs index 99f0f2559ecb..6c7a94cd7ebe 100644 --- a/developer-hub/src/reference_docs/mod.rs +++ b/developer-hub/src/reference_docs/mod.rs @@ -56,3 +56,7 @@ pub mod frame_composite_enums; /// Learn about how to make a pallet/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 upgrade-able runtime communicate its +/// properties to the outside world. +pub mod metadata; diff --git a/docs/mermaid/IA.mmd b/docs/mermaid/IA.mmd index 0fd95951931b..8fcb74fa0a91 100644 --- a/docs/mermaid/IA.mmd +++ b/docs/mermaid/IA.mmd @@ -9,5 +9,6 @@ flowchart polkadot_sdk --> frame polkadot_sdk --> cumulus polkadot_sdk --> polkadot + polkadot_sdk --> xcm diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index 0d59cba6b760..58c14b36e193 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -47,7 +47,9 @@ pub mod __private { pub use sp_core::{OpaqueMetadata, Void}; pub use sp_core_hashing_proc_macro; pub use sp_inherents; - pub use sp_io::{self, storage::root as storage_root, TestExternalities}; + #[cfg(feature = "std")] + pub use sp_io::TestExternalities; + pub use sp_io::{self, storage::root as storage_root}; pub use sp_metadata_ir as metadata_ir; #[cfg(feature = "std")] pub use sp_runtime::{bounded_btree_map, bounded_vec}; From 6d57d2e9755b570277dc8a3a9e61962f989de926 Mon Sep 17 00:00:00 2001 From: kianenigma Date: Tue, 31 Oct 2023 13:39:53 +0000 Subject: [PATCH 08/66] fix warns --- developer-hub/src/lib.rs | 7 ++++--- developer-hub/src/polkadot_sdk/polkadot.rs | 2 +- developer-hub/src/polkadot_sdk/substrate.rs | 2 +- developer-hub/src/reference_docs/wasm_meta_protocol.rs | 4 ++-- developer-hub/src/tutorial/currency_simple/mod.rs | 6 ++---- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/developer-hub/src/lib.rs b/developer-hub/src/lib.rs index ae4e37fb4c3e..722424ab5e60 100644 --- a/developer-hub/src/lib.rs +++ b/developer-hub/src/lib.rs @@ -31,14 +31,15 @@ //! //! ### Checklist //! -//! - [ ] Always make sure all downstream types and items are improved. +//! - [ ] Always make sure all downstream types and items are improved. Don't assume too many "this +//! is blackbox". It should be a box that if I want to learn, there should be a way for it. //! - [ ] Make sure you read all relevant documents, build on top of. Imagine the process of posting //! something new in SE. //! //! ### Note on `crates.io` and Publishing //! -//! TODO: This crate cannot be published for now, and that is fine. We use `paritytech.github.io` as -//! the entry point. +//! TODO: This crate cannot be published for now, and that is fine. We use `paritytech.github.io` +//! as the entry point. //! TODO: link checker. //! //! ### Why Rust Docs? diff --git a/developer-hub/src/polkadot_sdk/polkadot.rs b/developer-hub/src/polkadot_sdk/polkadot.rs index 13b6d8f7b75e..f1d333145ed5 100644 --- a/developer-hub/src/polkadot_sdk/polkadot.rs +++ b/developer-hub/src/polkadot_sdk/polkadot.rs @@ -55,4 +55,4 @@ //! //! ### Polkadot 2.x //! -//! +//! TODO diff --git a/developer-hub/src/polkadot_sdk/substrate.rs b/developer-hub/src/polkadot_sdk/substrate.rs index 65c7b40ba8e5..8ebaaa60befe 100644 --- a/developer-hub/src/polkadot_sdk/substrate.rs +++ b/developer-hub/src/polkadot_sdk/substrate.rs @@ -141,7 +141,7 @@ //! - [`sc_consensus_aura`] //! - [`sc_consensus_babe`] //! - [`sc_consensus_grandpa`] -//! - [`sc_consensus_beefy`] (TODO: adrian, add some high level docs) +//! - [`sc_consensus_beefy`] (TODO: @adrian, add some high level docs) //! - [`sc_consensus_manual_seal`] //! - [`sc_consensus_pow`] diff --git a/developer-hub/src/reference_docs/wasm_meta_protocol.rs b/developer-hub/src/reference_docs/wasm_meta_protocol.rs index d4e5df765722..f728cf6e581e 100644 --- a/developer-hub/src/reference_docs/wasm_meta_protocol.rs +++ b/developer-hub/src/reference_docs/wasm_meta_protocol.rs @@ -45,7 +45,7 @@ #![doc = simple_mermaid::mermaid!("../../../docs/mermaid/substrate_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 as an example of how to add custom +//! functionality, but it can also expose more APIs. See TODO as an example of how to add custom //! runtime APIs to your FRAME-based runtime. //! //! Similarly, for a runtime to be "compatible" with a client, the client must implement the full @@ -104,4 +104,4 @@ //! //! ## Example: Block Execution. //! -//! +//! TODO diff --git a/developer-hub/src/tutorial/currency_simple/mod.rs b/developer-hub/src/tutorial/currency_simple/mod.rs index 29d81f876a8e..516920f69b3a 100644 --- a/developer-hub/src/tutorial/currency_simple/mod.rs +++ b/developer-hub/src/tutorial/currency_simple/mod.rs @@ -225,8 +225,6 @@ //! //! ### Event and Error //! -//! TODO: this should be a new tutorial. -//! //! Our pallet is mainly missing two parts that are common in most FRAME pallets: Events, and //! Errors. First, let's understand what each are. //! @@ -244,8 +242,8 @@ //! (eg. a light-client, A DApp) to listen to particular events happening, without needing to //! re-execute the whole state transition function. //! -//! TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation of -//! event is probably not the best. +//! TODO: both need to be improved a lot at the pallet-macro rust-doc level. Also my explanation +//! of event is probably not the best. //! //! 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 an extra `#[frame::event/error]` attribute From 76f22773e98adb7c19eac45f1f14b24164ca135b Mon Sep 17 00:00:00 2001 From: kianenigma Date: Wed, 1 Nov 2023 14:15:24 +0000 Subject: [PATCH 09/66] update --- Cargo.lock | 1 + developer-hub/Cargo.toml | 1 + developer-hub/headers/toc.html | 8 +- developer-hub/src/lib.rs | 113 ++++++++++++------ developer-hub/src/polkadot_sdk/cumulus.rs | 5 +- .../src/polkadot_sdk/frame_runtime.rs | 4 + developer-hub/src/polkadot_sdk/mod.rs | 43 +++---- developer-hub/src/polkadot_sdk/templates.rs | 5 + developer-hub/src/polkadot_sdk/xcm.rs | 4 + .../src/tutorial/currency_simple/mod.rs | 2 - .../protocol/src/request_response/mod.rs | 4 +- substrate/client/allocator/src/lib.rs | 2 +- substrate/client/executor/src/lib.rs | 2 +- substrate/frame/balances/src/lib.rs | 48 ++++---- substrate/frame/bounties/src/migrations/v4.rs | 4 +- .../frame/collective/src/migrations/v4.rs | 4 +- .../elections-phragmen/src/migrations/v4.rs | 4 +- .../elections-phragmen/src/migrations/v5.rs | 2 +- substrate/frame/grandpa/src/migrations/v4.rs | 4 +- .../frame/membership/src/migrations/v4.rs | 4 +- .../frame/session/src/historical/offchain.rs | 10 +- substrate/frame/support/procedural/src/lib.rs | 11 +- substrate/frame/tips/src/migrations/v4.rs | 4 +- substrate/primitives/api/src/lib.rs | 16 +-- .../primitives/npos-elections/src/lib.rs | 5 +- .../runtime-interface/src/pass_by.rs | 2 +- .../runtime/src/offchain/storage_lock.rs | 2 +- 27 files changed, 187 insertions(+), 127 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2da733ff7bf..fe22f32b5c28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4422,6 +4422,7 @@ dependencies = [ "node-cli", "pallet-aura", "pallet-default-config-example", + "pallet-examples", "pallet-timestamp", "parachain-info", "parity-scale-codec", diff --git a/developer-hub/Cargo.toml b/developer-hub/Cargo.toml index 765c3ee26436..69a881983128 100644 --- a/developer-hub/Cargo.toml +++ b/developer-hub/Cargo.toml @@ -15,6 +15,7 @@ version = "0.0.1" parity-scale-codec = { version = "3.0.0", default-features = false } scale-info = { version = "2.6.0", default-features = false } frame = { path = "../substrate/frame", features = ["runtime", "experimental"] } +pallet-examples = { path = "../substrate/frame/examples" } # How we build docs in rust-docs simple-mermaid = { git = "https://github.com/kianenigma/simple-mermaid.git", branch = "main" } diff --git a/developer-hub/headers/toc.html b/developer-hub/headers/toc.html index 4520fd29072a..9b3aba67eced 100644 --- a/developer-hub/headers/toc.html +++ b/developer-hub/headers/toc.html @@ -1,13 +1,19 @@