Skip to content

Commit

Permalink
Update the pallet guide in sdk-docs (#4735)
Browse files Browse the repository at this point in the history
After using this tutorial in PBA, there was a few areas to improve it.
Moreover, I have:

- Improve `your_first_pallet`, link it in README, improve the parent
`guide` section.
- Updated the templates page, in light of recent efforts related to in
#3155
- Added small ref docs about metadata, completed the one about native
runtime, added one about host functions.
- Remove a lot of unfinished stuff from sdk-docs
- update diagram for `Hooks`
  • Loading branch information
kianenigma authored Jun 13, 2024
1 parent c4aa2ab commit eca1052
Show file tree
Hide file tree
Showing 23 changed files with 302 additions and 160 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ forks](https://img.shields.io/github/forks/paritytech/polkadot-sdk)
## 📚 Documentation

* [🦀 rust-docs](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/index.html)
* [Introduction](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html)
to each component of the Polkadot SDK: Substrate, FRAME, Cumulus, and XCM
* [Introduction](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/index.html)
to each component of the Polkadot SDK: Substrate, FRAME, Cumulus, and XCM
* [Guides](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/index.html),
namely how to build your first FRAME pallet.
* [Templates](https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/polkadot_sdk/templates/index.html)
for starting a new project.
* Other Resources:
* [Polkadot Wiki -> Build](https://wiki.polkadot.network/docs/build-guide)

Expand All @@ -39,6 +43,9 @@ The Polkadot-SDK has two release channels: `stable` and `nightly`. Production so
only use `stable`. `nightly` is meant for tinkerers to try out the latest features. The detailed
release process is described in [RELEASE.md](docs/RELEASE.md).

You can use [`psvm`](https://github.com/paritytech/psvm) to manage your Polkadot-SDK dependency
versions in downstream projects.

### 😌 Stable

`stable` releases have a support duration of **three months**. In this period, the release will not
Expand Down
4 changes: 2 additions & 2 deletions docs/mermaid/IA.mmd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
flowchart
parity[paritytech.github.io] --> devhub[polkadot_sdk_docs]
polkadot[polkadot.network] --> devhub[polkadot_sdk_docs]
polkadot_network[polkadot.network] --> devhub[polkadot_sdk_docs]

devhub --> polkadot_sdk
devhub --> reference_docs
Expand All @@ -9,5 +9,5 @@ flowchart
polkadot_sdk --> substrate
polkadot_sdk --> frame
polkadot_sdk --> cumulus
polkadot_sdk --> polkadot
polkadot_sdk --> polkadot[polkadot node]
polkadot_sdk --> xcm
16 changes: 10 additions & 6 deletions docs/sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,27 +83,31 @@ pallet-democracy = { path = "../../substrate/frame/democracy" }
pallet-uniques = { path = "../../substrate/frame/uniques" }
pallet-nfts = { path = "../../substrate/frame/nfts" }
pallet-scheduler = { path = "../../substrate/frame/scheduler" }
pallet-referenda = { path = "../../substrate/frame/referenda" }
pallet-broker = { path = "../../substrate/frame/broker" }
pallet-babe = { path = "../../substrate/frame/babe" }

# Primitives
sp-io = { path = "../../substrate/primitives/io" }
sp-runtime-interface = { path = "../../substrate/primitives/runtime-interface" }
sp-api = { path = "../../substrate/primitives/api" }
sp-core = { path = "../../substrate/primitives/core" }
sp-keyring = { path = "../../substrate/primitives/keyring" }
sp-runtime = { path = "../../substrate/primitives/runtime" }
sp-arithmetic = { path = "../../substrate/primitives/arithmetic" }
sp-genesis-builder = { path = "../../substrate/primitives/genesis-builder" }

# Misc pallet dependencies
pallet-referenda = { path = "../../substrate/frame/referenda" }
pallet-broker = { path = "../../substrate/frame/broker" }
pallet-babe = { path = "../../substrate/frame/babe" }

sp-offchain = { path = "../../substrate/primitives/offchain" }
sp-version = { path = "../../substrate/primitives/version" }


# XCM
xcm = { package = "staging-xcm", path = "../../polkadot/xcm" }
xcm-docs = { path = "../../polkadot/xcm/docs" }

# runtime guides
chain-spec-guide-runtime = { path = "./src/reference_docs/chain_spec_runtime" }

# Templates
minimal-template-runtime = { path = "../../templates/minimal/runtime" }
solochain-template-runtime = { path = "../../templates/solochain/runtime" }
parachain-template-runtime = { path = "../../templates/parachain/runtime" }
25 changes: 17 additions & 8 deletions docs/sdk/src/guides/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
//! # Polkadot SDK Docs Guides
//!
//! This crate contains a collection of guides that are foundational to the developers of
//! Polkadot SDK. They are common user-journeys that are traversed in the Polkadot ecosystem.
//! This crate contains a collection of guides that are foundational to the developers of Polkadot
//! SDK. They are common user-journeys that are traversed in the Polkadot ecosystem.
//!
//! 1. [`crate::guides::your_first_pallet`] is your starting point with Polkadot SDK. It contains
//! the basics of
//! building a simple crypto currency with FRAME.
//! 2. [`crate::guides::your_first_runtime`] is the next step in your journey. It contains the
//! basics of building a runtime that contains this pallet, plus a few common pallets from FRAME.
//!
//!
//! Other guides are related to other miscellaneous topics and are listed as modules below.

/// Write your first simple pallet, learning the most most basic features of FRAME along the way.
pub mod your_first_pallet;
Expand All @@ -11,18 +20,18 @@ pub mod your_first_pallet;
pub mod your_first_runtime;

/// Running the given runtime with a node. No specific consensus mechanism is used at this stage.
pub mod your_first_node;

/// How to change the consensus engine of both the node and the runtime.
pub mod changing_consensus;
// TODO
// pub mod your_first_node;

/// How to enhance a given runtime and node to be cumulus-enabled, run it as a parachain and connect
/// it to a relay-chain.
pub mod cumulus_enabled_parachain;
// TODO
// pub mod cumulus_enabled_parachain;

/// How to make a given runtime XCM-enabled, capable of sending messages (`Transact`) between itself
/// and the relay chain to which it is connected.
pub mod xcm_enabled_parachain;
// TODO
// pub mod xcm_enabled_parachain;

/// How to enable storage weight reclaiming in a parachain node and runtime.
pub mod enable_pov_reclaim;
Expand Down
109 changes: 70 additions & 39 deletions docs/sdk/src/guides/your_first_pallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,35 +14,43 @@
//! > FRAME-based runtimes use various techniques to re-use a currency pallet instead of writing
//! > one. Further advanced FRAME related topics are discussed in [`crate::reference_docs`].
//!
//! ## Topics Covered
//! ## Writing Your First Pallet
//!
//! The following FRAME topics are covered in this guide:
//! To get started, use one of the templates mentioned in [`crate::polkadot_sdk::templates`]. We
//! recommend using the `polkadot-sdk-minimal-template`. You might need to change small parts of
//! this guide, namely the crate/package names, based on which tutorial you use.
//!
//! - [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::prelude::construct_runtime)
//!
//! ## Writing Your First Pallet
//! > Be aware that you can read the entire source code backing this tutorial by clicking on the
//! > [`source`](./mod.rs.html) button at the top right of the page.
//!
//! You should have studied the following modules as a prelude to this guide:
//!
//! - [`crate::reference_docs::blockchain_state_machines`]
//! - [`crate::reference_docs::trait_based_programming`]
//! - [`crate::polkadot_sdk::frame_runtime`]
//!
//! ## Topics Covered
//!
//! The following FRAME topics are covered in this guide:
//!
//! - [`pallet::storage`]
//! - [`pallet::call`]
//! - [`pallet::event`]
//! - [`pallet::error`]
//! - Basics of testing a pallet
//! - [Constructing a runtime](frame::runtime::prelude::construct_runtime)
//!
//! ### 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.
//! [`pallet::config`] and [`pallet::pallet`] are both mandatory parts of any pallet. Refer to the
//! documentation of each to get an overview of what they do.
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", shell_pallet)]
//!
//! All of the code that follows in this guide should live inside of the `mod pallet`.
//!
//! ### Storage
//!
//! First, we will need to create two onchain storage declarations.
Expand All @@ -55,15 +63,14 @@
//! > generic bounded type in the `Config` trait, and then specify it in the implementation.
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Balance)]
//!
//! The definition of these two storage items, based on [`frame::pallet_macros::storage`] details,
//! is as follows:
//! The definition of these two storage items, based on [`pallet::storage`] details, is as follows:
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", TotalIssuance)]
#![doc = docify::embed!("./src/guides/your_first_pallet/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`.
//! Next, we will define the dispatchable functions. As per [`pallet::call`], these will be defined
//! as normal `fn`s attached to `struct Pallet`.
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", impl_pallet)]
//!
//! The logic of the functions is self-explanatory. Instead, we will focus on the FRAME-related
Expand All @@ -79,7 +86,6 @@
//! 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::<T>::insert`, you can look
//! into [`frame::prelude::StorageMap::insert`].
Expand All @@ -95,8 +101,7 @@
//!
//! - 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`]
//! [`pallet::storage`], and [`frame::prelude::ValueQuery`]/[`frame::prelude::OptionQuery`]
//!
//! ### Improving Errors
//!
Expand All @@ -116,6 +121,25 @@
//!
//! ### Your First (Test) Runtime
//!
//! The typical testing code of a pallet lives in a module that imports some preludes useful for
//! testing, similar to:
//!
//! ```
//! pub mod pallet {
//! // snip -- actually pallet code.
//! }
//!
//! #[cfg(test)]
//! mod tests {
//! // bring in the testing prelude of frame
//! use frame::testing_prelude::*;
//! // bring in all pallet items
//! use super::pallet::*;
//!
//! // snip -- rest of the testing code.
//! }
//! ```
//!
//! 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
Expand Down Expand Up @@ -166,7 +190,6 @@
//! As noted above, the `T::AccountId` is now `u64`. Moreover, `Runtime` is replacing `<T: Config>`.
//! This is why for example you see `Balances::<Runtime>::get(..)`. Finally, notice that the
//! dispatchables are simply functions that can be called on top of the `Pallet` struct.
// TODO: hard to explain exactly `RuntimeOrigin::signed(ALICE)` at this point.
//!
//! Congratulations! You have written your first pallet and tested it! Next, we learn a few optional
//! steps to improve our pallet.
Expand Down Expand Up @@ -236,8 +259,7 @@
//! by one character. FRAME errors are exactly a solution to maintain readability, whilst fixing
//! the drawbacks mentioned. In short, we use an enum to represent different variants of our
//! error. These variants are then mapped in an efficient way (using only `u8` indices) to
//! [`sp_runtime::DispatchError::Module`]. Read more about this in
//! [`frame::pallet_macros::error`].
//! [`sp_runtime::DispatchError::Module`]. Read more about this in [`pallet::error`].
//!
//! - **Event**: Events are akin to the return type of dispatchables. They are mostly data blobs
//! emitted by the runtime to let outside world know what is happening inside the pallet. Since
Expand All @@ -246,20 +268,16 @@
//! use passive tense for event names (eg. `SomethingHappened`). This allows other sub-systems or
//! external parties (eg. a light-node, 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 extra
//! [`#[frame::event]`](frame::pallet_macros::event) and
//! [`#[frame::error]`](frame::pallet_macros::error) attributes attached.
//! fairly familiar syntax: normal Rust enums, with extra [`pallet::event`] and [`pallet::error`]
//! attributes attached.
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Event)]
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", Error)]
//!
//! One slightly custom part of this is the [`#[pallet::generate_deposit(pub(super) fn
//! deposit_event)]`](frame::pallet_macros::generate_deposit) part. Without going into too
//! much detail, in order for a pallet to emit events to the rest of the system, it needs to do two
//! things:
//! One slightly custom part of this is the [`pallet::generate_deposit`] part. Without going into
//! too much detail, in order for a pallet to emit events to the rest of the system, it needs to do
//! two things:
//!
//! 1. Declare a type in its `Config` that refers to the overarching event type of the runtime. In
//! short, by doing this, the pallet is expressing an important bound: `type RuntimeEvent:
Expand All @@ -268,8 +286,8 @@
//! store it where needed.
//!
//! 2. But, doing this conversion and storing is too much to expect each pallet to define. FRAME
//! provides a default way of storing events, and this is what
//! [`pallet::generate_deposit`](frame::pallet_macros::generate_deposit) is doing.
//! provides a default way of storing events, and this is what [`pallet::generate_deposit`] is
//! doing.
#![doc = docify::embed!("./src/guides/your_first_pallet/mod.rs", config_v2)]
//!
//! > These `Runtime*` types are better explained in
Expand Down Expand Up @@ -297,10 +315,17 @@
//! - [`crate::reference_docs::defensive_programming`].
//! - [`crate::reference_docs::frame_origin`].
//! - [`crate::reference_docs::frame_runtime_types`].
//! - The pallet we wrote in this guide was using `dev_mode`, learn more in
//! [`frame::pallet_macros::config`].
//! - The pallet we wrote in this guide was using `dev_mode`, learn more in [`pallet::config`].
//! - Learn more about the individual pallet items/macros, such as event and errors and call, in
//! [`frame::pallet_macros`].
//!
//! [`pallet::storage`]: ../../../frame_support/pallet_macros/attr.config.html
//! [`pallet::call`]: ../../../frame_support/pallet_macros/attr.call.html
//! [`pallet::event`]: ../../../frame_support/pallet_macros/attr.event.html
//! [`pallet::error`]: ../../../frame_support/pallet_macros/attr.error.html
//! [`pallet::pallet`]: ../../../frame_support/pallet_macros/attr.pallet.html
//! [`pallet::config`]: ../../../frame_support/pallet_macros/attr.config.html
//! [`pallet::generate_deposit`]: ../../../frame_support/pallet_macros/attr.generate_deposit.html

#[docify::export]
#[frame::pallet(dev_mode)]
Expand Down Expand Up @@ -418,16 +443,22 @@ pub mod pallet {
#[cfg(any(test, doc))]
pub(crate) mod tests {
use crate::guides::your_first_pallet::pallet::*;

#[docify::export(testing_prelude)]
use frame::testing_prelude::*;
const ALICE: u64 = 1;
const BOB: u64 = 2;
const CHARLIE: u64 = 3;

pub(crate) const ALICE: u64 = 1;
pub(crate) const BOB: u64 = 2;
pub(crate) const CHARLIE: u64 = 3;

#[docify::export]
// This runtime is only used for testing, so it should be somewhere like `#[cfg(test)] mod
// tests { .. }`
mod runtime {
use super::*;
// we need to reference our `mod pallet` as an identifier to pass to
// `construct_runtime`.
// YOU HAVE TO CHANGE THIS LINE BASED ON YOUR TEMPLATE
use crate::guides::your_first_pallet::pallet as pallet_currency;

construct_runtime!(
Expand Down
2 changes: 2 additions & 0 deletions docs/sdk/src/guides/your_first_runtime.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
//! # Your first Runtime
//!
//! 🚧 <https://github.com/paritytech/polkadot-sdk/pull/3946>
Loading

0 comments on commit eca1052

Please sign in to comment.