Move developer-hub to polkadot-sdk-docs (#2598)

This PR is a continuation of
https://github.com/paritytech/polkadot-sdk/pull/2102 and part of an
initiative started here https://hackmd.io/@romanp/rJ318ZCEp
What has been done:
- The content under `docs/*` (with the exception of `docs/mermaid`) has
been moved to `docs/contributor/`
- Developer Hub has been renamed to Polkadot SDK Docs, and the crate has
been renamed from `developer-hub` to `polkadot-sdk-docs`
- The content under `developer-hub/*` has been moved to `docs/sdk`

---
Original PR https://github.com/paritytech/polkadot-sdk/pull/2565, it has
been close due to too many rebase conflicts

---------

Co-authored-by: Serban Iorga <serban@parity.io>
Co-authored-by: Chevdor <chevdor@users.noreply.github.com>
Co-authored-by: Egor_P <egor@parity.io>
Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
Juan Girini
2023-12-05 10:23:24 +01:00
committed by GitHub
parent 2f9af7873d
commit a310df263d
67 changed files with 153 additions and 154 deletions
@@ -0,0 +1,29 @@
//! # State Transition Function
//!
//! This document briefly explains how in the context of Substrate-based blockchains, we view the
//! blockchain as a **decentralized state transition function**.
//!
//! Recall that a blockchain's main purpose is to help a permissionless set of entities to agree on
//! 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!("../../../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!("../../../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}
//! ```
@@ -0,0 +1,4 @@
//! Chain spec and genesis build.
//!
//! What is chain-spec.
//! What is genesis state and how to build it.
+7
View File
@@ -0,0 +1,7 @@
//! # Command Line Arguments
//!
//!
//! Notes:
//!
//! - Command line arguments of a typical substrate based chain, and how to find and learn them.
//! - How to extend them with your custom stuff.
@@ -0,0 +1,6 @@
//! Consensus Swapping
//!
//! Notes:
//!
//! - The typical workshop done by Joshy in some places where he swaps out the consensus to be PoW.
//! - This could also be a tutorial rather than a ref doc, depending on the size.
@@ -0,0 +1,277 @@
//! # 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` (i.e. 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<AccountId32>`],
//! 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, which is used to determine how the chain's state is
//! altered. This is defined by the second generic parameter of
//! [`sp_runtime::generic::UncheckedExtrinsic`].
//!
//! 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::{Decode, Encode};
// 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 super::call_data::{Call, PalletACall};
use crate::reference_docs::signed_extensions::signed_extensions_example;
use parity_scale_codec::Encode;
use sp_core::crypto::AccountId32;
use sp_keyring::sr25519::Keyring;
use sp_runtime::{
generic::{SignedPayload, UncheckedExtrinsic},
MultiAddress, MultiSignature,
};
// 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<AccountId32, ()>, Call, MultiSignature, SignedExtensions>;
pub fn encode_demo_extrinsic() -> Vec<u8> {
// The "from" address will be our Alice dev account.
let from_address = MultiAddress::<AccountId32, ()>::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
}
}
@@ -0,0 +1,12 @@
//! # Fee-Less Runtime
//!
//!
//! Notes:
//!
//! - An extension of [`runtime_vs_smart_contract`], showcasing the tools needed to build a safe
//! runtime that is fee-less.
//! - Would need to use unsigned origins, custom validate_unsigned, check the existence of some NFT
//! and some kind of rate limiting (eg. any account gets 5 free tx per day).
//! - The rule of thumb is that as long as the unsigned validate does one storage read, similar to
//! nonce, it is fine.
//! - This could possibly be a good tutorial/template, rather than a reference doc.
@@ -0,0 +1,23 @@
//! # FRAME Benchmarking and Weights.
//!
//! Notes:
//!
//! On Weight as a concept.
//!
//! - Why we need it. Super important. People hate this. We need to argue why it is worth it.
//! - Axis of weight: PoV + Time.
//! - pre dispatch weight vs. metering and post dispatch correction.
//! - mention that we will do this for PoV
//! - you can manually refund using `DispatchResultWithPostInfo`.
//! - Technically you can have weights with any benchmarking framework. You just need one number to
//! be computed pre-dispatch. But FRAME gives you a framework for this.
//! - improve documentation of `#[weight = ..]` and `#[pallet::weight(..)]`. All syntax variation
//! should be covered.
//!
//! on FRAME benchmarking machinery:
//!
//! - component analysis, why everything must be linear.
//! - how to write benchmarks, how you must think of worst case.
//! - how to run benchmarks.
//!
//! - https://www.shawntabrizi.com/substrate/substrate-storage-deep-dive/
@@ -0,0 +1 @@
//! # FRAME Composite Enums
@@ -0,0 +1,8 @@
//! FRAME Currency Abstractions and Traits
//!
//! Notes:
//!
//! - History, `Currency` trait.
//! - `Hold` and `Freeze` with diagram.
//! - `HoldReason` and `FreezeReason`
//! - This footgun: https://github.com/paritytech/polkadot-sdk/pull/1900#discussion_r1363783609
@@ -0,0 +1,14 @@
//! # FRAME Origin
//!
//! Notes:
//!
//! - Def talk about account abstraction and how it is a solved issue in frame. See Gav's talk in
//! Protocol Berg 2023
//! - system's raw origin, how it is amalgamated with other origins into one type
//! [`frame_composite_enums`]
//! - signed origin
//! - unsigned origin, link to [`fee_less_runtime`]
//! - Root origin, how no one can obtain it.
//! - Abstract origin: how FRAME allows you to express "origin is 2/3 of the this body or 1/2 of
//! that body or half of the token holders".
//! - `type CustomOrigin: EnsureOrigin<_>` in pallets.
@@ -0,0 +1,9 @@
//! # Runtime Runtime Upgrade and Testing
//!
//!
//! Notes:
//!
//! - Flow of things, when does `on_runtime_upgrade` get called. Link to to `Hooks` and its diagram
//! as source of truth.
//! - Data migration and when it is needed.
//! - Look into the pba-lecture.
@@ -0,0 +1,8 @@
//! # FRAME Accounts
//!
//! How `frame_system` handles accountIds. Nonce. Consumers and Providers, reference counting.
// - poorly understood topics, needs one great article to rul them all.
// - https://github.com/paritytech/substrate/issues/14425
// - https://github.com/paritytech/substrate/pull/12951
// - https://substrate.stackexchange.com/questions/263/what-is-the-meaning-of-the-account-provider-sufficients-and-consumer
+120
View File
@@ -0,0 +1,120 @@
//! # Glossary
//!
//! #### State
//!
//! The data around which the blockchain network wishes to come to consensus. Also
//! referred to as "onchain data", "onchain storage" or sometimes just "storage". In UTXO based
//! blockchains, is referred to as "ledger".
//!
//! **Synonyms**: Onchain data, Onchain storage, Storage, Ledger
//!
//! #### State Transition Function
//!
//! The WASM Blob that dictates how the blockchain should transition its state upon encountering new
//! blocks.
//!
//! #### Host
//!
//! The environment that hosts and executes the [state transition function's WASM
//! blob](#state-transition-function).
//!
//! #### Node
//!
//! The full software artifact that contains the [host](#host), but importantly also all the other
//! modules needed to be part of a blockchain network, such as peer-to-peer networking, database and
//! such.
//!
//! **Synonyms**: Client
//!
//! #### Light Node
//!
//! Same as [node](#nodes), but when capable of following the network only through listening to
//! block headers. Usually capable of running in more constrained environments, such as an embedded
//! device, phone, or a web browser.
//!
//! **Synonyms**: Light Client
//!
//! #### Offchain
//!
//! Refers to operations conducted outside the blockchain's consensus mechanism. They are essential
//! for enhancing scalability and efficiency, enabling activities like data fetching and computation
//! without bloating the blockchain state.
//!
//! #### Host Functions:
//!
//! Host functions are the node's API, these are functions provided by the runtime environment (the
//! [host](#host)) to the Wasm runtime. These functions allow the Wasm code to interact with and
//! perform operations on the [node](#node), like accessing the blockchain state.
//!
//! #### Runtime API:
//!
//! This is the API of the runtime, it acts as a communication bridge between the runtime and the
//! node, serving as the exposed interface that facilitates their interactions.
//!
//! #### Dispatchable:
//!
//! Dispatchables are [function objects](https://en.wikipedia.org/wiki/Function_object) that act as
//! the entry points in [FRAME](frame) pallets. They can be called by internal or external entities
//! to interact with the blockchain's state. They are a core aspect of the runtime logic, handling
//! transactions and other state-changing operations.
//!
//! **Synonyms**: Callable
//!
//! #### Extrinsic
//!
//! An extrinsic is a general term for a piece of data that is originated outside of the runtime,
//! included into a block and leads to some action. This includes user-initiated transactions as
//! well as inherents which are placed into the block by the block-builder.
//!
//! #### Pallet
//!
//! Similar to software modules in traditional programming, [FRAME](frame) pallets in Substrate are
//! modular components that encapsulate distinct functionalities or business logic. Just as
//! libraries or modules are used to build and extend the capabilities of a software application,
//! pallets are the foundational building blocks for constructing a blockchain's runtime with frame.
//! They enable the creation of customizable and upgradeable networks, offering a composable
//! framework for a Substrate-based blockchain. Each pallet can be thought of as a plug-and-play
//! module, enhancing the blockchain's functionality in a cohesive and integrated manner.
//!
//! #### Full Node
//!
//! It is a node that prunes historical states, keeping only recent finalized block states to reduce
//! storage needs. Full nodes provide current chain state access and allow direct submission and
//! validation of extrinsics, maintaining network decentralization.
//!
//! #### Archive Node
//!
//! An archive node is a specialized node that maintains a complete history of all block states and
//! transactions. Unlike a full node, it does not prune historical data, ensuring full access to the
//! entire blockchain history. This makes it essential for detailed blockchain analysis and
//! historical queries, but requires significantly more storage capacity.
//!
//! #### Validator
//!
//! A validator is a node that participates in the consensus mechanism of the network.
//! Its role includes block production, transaction validation, network integrity and security
//! maintenance.
//!
//! #### Collator
//!
//! A collator is a node that is responsible for producing candidate blocks for the validators.
//! Collators are similar to validators on any other blockchain but, they do not need to provide
//! security guarantees as the Relay Chain handles this.
//!
//! #### Parachain
//!
//! Short for "parallelized chain" a parachain is a specialized blockchain that runs in parallel to
//! the Relay Chain (Polkadot, Kusama, etc.), benefiting from the shared security and
//! interoperability features of it.
//!
//! **Synonyms**: AppChain
//!
//! #### PVF
//! The Parachain Validation Function (PVF) is the current runtime Wasm for a parachain that is
//! stored on the Relay chain. It is an essential component in the Polkadot ecosystem, encapsulating
//! the validation logic for each parachain. The PVF is executed by validators to verify the
//! correctness of parachain blocks. This is critical for ensuring that each block follows the logic
//! set by its respective parachain, thus maintaining the integrity and security of the entire
//! network.
//!
//! **Synonyms**: Parachain Validation Function
@@ -0,0 +1,7 @@
//! # Light Clients
//!
//!
//! Notes: should contain only high level information about light clients, then link to how to set
//! it up in PAPI and SubXT
//! https://docs.substrate.io/learn/light-clients-in-substrate-connect/
//! https://github.com/substrate-developer-hub/substrate-front-end-template/pull/277
+1
View File
@@ -0,0 +1 @@
//! # Metadata
+99
View File
@@ -0,0 +1,99 @@
//! # Polkadot SDK Reference Docs.
//!
//! This is the entry point for all reference documents that enhance one's learning experience in
//! the Polkadot SDK.
//!
//! Note that this module also contains the [glossary](crate::reference_docs::glossary).
//!
//! ## 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::guides`]. 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::guides`].
//!
//! We call this class of documents "reference documents". Our goal should be to minimize the number
//! of "reference" docs, as they incur maintenance burden.
/// Learn how Substrate and FRAME use traits and associated types to make modules generic in a
/// 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.
// TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/42
pub mod signed_extensions;
/// Learn about *"Origin"* A topic in FRAME that enables complex account abstractions to be built.
// TODO: @shawntabrizi https://github.com/paritytech/polkadot-sdk-docs/issues/43
pub mod frame_origin;
/// Learn about how to write safe and defensive code in your FRAME runtime.
// TODO: @CrackTheCode016 https://github.com/paritytech/polkadot-sdk-docs/issues/44
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;
/// Learn about metadata, the main means through which an upgradeable runtime communicates its
/// properties to the outside world.
// TODO: @jsdw https://github.com/paritytech/polkadot-sdk-docs/issues/47
pub mod metadata;
/// Learn about how frame-system handles `account-ids`, nonces, consumers and providers.
pub mod frame_system_accounts;
/// Learn about the currency-related abstractions provided in FRAME.
pub mod frame_currency;
/// Learn about benchmarking and weight.
// TODO: @shawntabrizi @ggwpez https://github.com/paritytech/polkadot-sdk-docs/issues/50
pub mod frame_benchmarking_weight;
/// Learn about chain specification file and the genesis state of the blockchain.
// TODO: @michalkucharczyk https://github.com/paritytech/polkadot-sdk-docs/issues/51
pub mod chain_spec_genesis;
/// Learn about all the memory limitations of the WASM runtime when it comes to memory usage.
// TODO: @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/52
pub mod wasm_memory;
/// Learn about Substrate's CLI, and how it can be extended.
// TODO: @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/53
pub mod cli;
/// Learn about Substrate's consensus algorithms, and how you can switch between two.
// TODO: @JoshOrndorff @kianenigma https://github.com/paritytech/polkadot-sdk-docs/issues/54
pub mod consensus_swapping;
/// Learn about all the advance ways to test your coordinate a rutnime upgrade and data migration.
// TODO: @liamaharon https://github.com/paritytech/polkadot-sdk-docs/issues/55
pub mod frame_runtime_migration;
/// Learn about light nodes, how they function, and how Substrate-based chains come
/// light-node-first out of the box.
// TODO: @jsdw @josepot https://github.com/paritytech/polkadot-sdk-docs/issues/68
pub mod light_nodes;
@@ -0,0 +1,6 @@
//! Runtime vs. Smart Contracts
//!
//! Notes:
//!
//! Why one can be weighed, and one MUST be metered.
//! https://forum.polkadot.network/t/where-contracts-fail-and-runtimes-chains-are-needed/4464/3
@@ -0,0 +1 @@
//!
@@ -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<Self::Call>,
_len: usize,
) -> Result<Self::Pre, sp_runtime::transaction_validity::TransactionValidityError> {
Ok(())
}
}
// This is the opposite; nothing will be added to the extrinsic payload,
// but the AdditionalSigned type (`1234u32`) will be added to the
// payload to 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<Self::Call>,
_len: usize,
) -> Result<Self::Pre, sp_runtime::transaction_validity::TransactionValidityError> {
Ok(())
}
}
}
@@ -0,0 +1,229 @@
//! # Trait-based Programming
//!
//! This document 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 Advanced Traits](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html)
//! 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<AccountId> {
//! min_transfer: u128,
//! _marker: std::marker::PhantomData<AccountId>,
//! }
//! ```
//!
//! 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
//! [supertraits](https://doc.rust-lang.org/rust-by-example/trait/supertraits.html).
//!
//! > Interestingly, one downside of associated types is that declaring defaults on them is not
//! > stable yet. In the meantime, we have built our own custom mechanics around declaring defaults
//! for associated types, see [`pallet_default_config_example`].
//!
//! 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 `<T:
//! Config>`, and all types are fetched through `T`, for example `T::AccountId`, `T::MinTransfer`.
//!
//! 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`, which
//! 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
//!
//! - <https://github.com/paritytech/substrate/issues/13836>
//! - [Substrate Seminar - Traits and Generic Types](https://www.youtube.com/watch?v=6cp10jVWNl4)
//! - <https://substrate.stackexchange.com/questions/2228/type-casting-to-trait-t-as-config>
#![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<AccountId, Balance, MinTransfer> {
_marker: std::marker::PhantomData<(AccountId, Balance, MinTransfer)>,
}
impl<AccountId, Balance, MinTransfer> Pallet<AccountId, Balance, MinTransfer>
where
Balance: frame::traits::AtLeast32BitUnsigned,
MinTransfer: frame::traits::Get<Balance>,
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<Self::Balance>;
}
struct Pallet<T: Config>(std::marker::PhantomData<T>);
impl<T: Config> Pallet<T> {
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<Self::Balance>;
}
pub struct Pallet<T: Config>(std::marker::PhantomData<T>);
impl<T: Config> Pallet<T> {
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<T> = <T as SystemConfig>::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<T: Config>(std::marker::PhantomData<T>);
impl<T: Config> Pallet<T> {
fn transfer(
_from: T::AccountId,
_to: T::AccountId,
_amount: <<T as Config>::Currency as CurrencyTrait>::Balance,
) {
unimplemented!();
}
}
/// A common pattern in FRAME.
type BalanceOf<T> = <<T as Config>::Currency as CurrencyTrait>::Balance;
}
@@ -0,0 +1,7 @@
//! # WASM Memory Limitations.
//!
//! Notes:
//!
//! - Stack: Need to use `Box<_>`
//! - Heap: Substrate imposes a limit. PvF execution has its own limits
//! - Heap: There is also a maximum amount that a single allocation can have.
@@ -0,0 +1,113 @@
//! # 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 monolithic 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, in the same fashion
//! that a smart contract platform stores the code of individual contracts in its state. As noted in
//! [`crate::reference_docs::blockchain_state_machines`], this state transition function is called
//! the **Runtime**, and WASM is chosen as the bytecode. The Runtime is stored under a special key
//! in the state (see
//! [`sp_core::storage::well_known_keys`](../../../sp_core/index.html)) 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 **node**, and
//! is a normal binary that is compiled from Rust to different hardware targets.
//!
//! This design enables all Substrate-based chains to be fork-less-ly upgradeable, because the
//! Runtime can be updates on the fly, within the execution of a block, and the node is (for the
//! most part) oblivious to the change that is happening.
//!
//! Therefore, the high-level architecture of a any Substrate-based chain can be demonstrated as
//! follows:
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_simple.mmd")]
//!
//! The node and the runtime need to communicate. This is done through two concepts:
//!
//! 1. **Host functions**: a way for the (WASM) runtime to talk to the node. All host functions are
//! defined in [`sp_io`]. For example, [`sp_io::storage`] are the set of host functions that
//! allow the runtime to read and write data to the on-chain state.
//! 2. **Runtime APIs**: a way for the node to talk to the WASM runtime. Runtime APIs are defined
//! using macros and utilities in [`sp_api`]. For example, [`sp_api::Core`] is the most
//! fundamental runtime API that any blockchain must implement in order to be able to (re)
//! execute blocks.
#![doc = simple_mermaid::mermaid!("../../../mermaid/substrate_client_runtime.mmd")]
//!
//! 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 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 node, the node 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 node (typically) wishes to be capable of re-executing all the
//! previous blocks, this means that a node 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.
//!
//! ## Node vs. Runtime
//!
//! A common question is: which components of the system end up being part of the node, and which
//! ones of 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 node. For example, the database, networking, and even
//! consensus algorithm are all node-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!("../../../mermaid/substrate_with_frame.mmd")]
//!
//! ## State
//!
//! From the previous sections, we know that the a database component is part of the node, not the
//! runtime. We also hinted that a set of host functions ([`sp_io::storage`]) are how the runtime
//! issues commands to the node to read/write to the state. Let's dive deeper into this.
//!
//! The state of the blockchain, what we seek to come to consensus about, is indeed *kept* in the
//! node 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 node side is
//! aware of. The rest of the state, including what logic the runtime has, what balance each user
//! has and such are all only comprehensible to the runtime.
#![doc = simple_mermaid::mermaid!("../../../mermaid/state.mmd")]
//!
//! In the above diagram, all of the state keys and values are opaque bytes to the node. The node
//! does not know what they mean, and it does not now what is the type of the corresponding value
//! (e.g. if it is a number of a vector). Contrary, the runtime knows both the meaning of their
//! keys, and the type of the values.
//!
//! This opaque-ness is the fundamental reason why Substrate-based chains can fork-less-ly upgrade:
//! because the node side code is kept oblivious to all of the details of the state transition
//! function. Therefore, the state transition function can freely upgrade without the node needing
//! to know.
//!
//! ## Native Runtime
//!
//! TODO
//!
//!
//! ## Example: Block Execution.
//!
//! TODO