#
pezkuwi_sdk_docs/reference_docs/
wasm_meta_protocol.rs

    1//! # WASM Meta Protocol
    2//!
    3//! All Bizinikiwi based chains adhere to a unique architectural design novel to the Pezkuwi
    4//! ecosystem. We refer to this design as the "**WASM Meta Protocol**".
    5//!
    6//! Consider the fact that a traditional blockchain software is usually a monolithic artifact.
    7//! **Upgrading any part of the system implies upgrading the entire system**. This has historically
    8//! led to cumbersome forkful upgrades to be the status quo in blockchain ecosystems. In other
    9//! words, the entire node software is the specification of the blockchain's [`state transition
    10//! function`](crate::reference_docs::blockchain_state_machines).
    11//!
    12//! Moreover, the idea of "storing code in the state" is explored in the context of smart contracts
    13//! platforms, but has not been expanded further.
    14//!
    15//! Bizinikiwi mixes these two ideas together, and takes the novel approach of storing the
    16//! blockchain's main "state transition function" in the main blockchain state, in the same fashion
    17//! that a smart contract platform stores the code of individual contracts in its state. As noted in
    18//! [`crate::reference_docs::blockchain_state_machines`], this state transition function is called
    19//! the **Runtime**, and WASM is chosen as the bytecode. The Runtime is stored under a special key
    20//! in the state (see [`pezsp_core::storage::well_known_keys`]) and can be updated as a part of the
    21//! state transition function's execution, just like a user's account balance can be updated.
    22//!
    23//! > Note that while we drew an analogy between smart contracts and runtimes in the above, there
    24//! > are fundamental differences between the two, explained in
    25//! > [`crate::reference_docs::runtime_vs_smart_contract`].
    26//!
    27//! The rest of the system that is NOT the state transition function is called the
    28//! [**Node**](crate::reference_docs::glossary#node), and is a normal binary that is compiled from
    29//! Rust to different hardware targets.
    30//!
    31//! This design enables all Bizinikiwi-based chains to be fork-less-ly upgradeable, because the
    32//! Runtime can be updated on the fly, within the execution of a block, and the node is (for the
    33//! most part) oblivious to the change that is happening.
    34//!
    35//! Therefore, the high-level architecture of a any Bizinikiwi-based chain can be demonstrated as
    36//! follows:
    37#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_simple.mmd")]
    38//!
    39//! The node and the runtime need to communicate. This is done through two concepts:
    40//!
    41//! 1. **Host functions**: a way for the (WASM) runtime to talk to the node. All host functions are
    42//!    defined in [`pezsp_io`]. For example, [`pezsp_io::storage`] are the set of host functions
    43//!    that allow the runtime to read and write data to the on-chain state.
    44//! 2. **Runtime APIs**: a way for the node to talk to the WASM runtime. Runtime APIs are defined
    45//!    using macros and utilities in [`pezsp_api`]. For example, [`pezsp_api::Core`] is the most
    46//!    fundamental runtime API that any blockchain must implement in order to be able to (re)
    47//!    execute blocks.
    48#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_client_runtime.mmd")]
    49//!
    50//! A runtime must have a set of runtime APIs in order to have any meaningful blockchain
    51//! functionality, but it can also expose more APIs. See
    52//! [`crate::reference_docs::custom_runtime_api_rpc`] as an example of how to add custom runtime
    53//! APIs to your FRAME-based runtime.
    54//!
    55//! Similarly, for a runtime to be "compatible" with a node, the node must implement the full set of
    56//! host functions that the runtime at any point in time requires. Given the fact that a runtime can
    57//! evolve in time, and a blockchain node (typically) wishes to be capable of re-executing all the
    58//! previous blocks, this means that a node must always maintain support for the old host functions.
    59//! **This implies that adding a new host function is a big commitment and should be done with
    60//! care**. This is why, for example, adding a new host function to Pezkuwi always requires an RFC.
    61//! Learn how to add a new host function to your runtime in
    62//! [`crate::reference_docs::custom_host_functions`].
    63//!
    64//! ## Node vs. Runtime
    65//!
    66//! A common question is: which components of the system end up being part of the node, and which
    67//! ones of the runtime?
    68//!
    69//! Recall from [`crate::reference_docs::blockchain_state_machines`] that the runtime is the state
    70//! transition function. Anything that needs to influence how your blockchain's state is updated,
    71//! should be a part of the runtime. For example, the logic around currency, governance, identity or
    72//! any other application-specific logic that has to do with the state is part of the runtime.
    73//!
    74//! Anything that does not have to do with the state-transition function and will only
    75//! facilitate/enable it is part of the node. For example, the database, networking, and even
    76//! consensus algorithm are all node-side components.
    77//!
    78//! > The consensus is to your runtime what HTTP is to a web-application. It is the underlying
    79//! > engine that enables trustless execution of the runtime in a distributed manner whilst
    80//! > maintaining a canonical outcome of that execution.
    81#![doc = simple_mermaid::mermaid!("../../../mermaid/bizinikiwi_with_frame.mmd")]
    82//!
    83//! ## State
    84//!
    85//! From the previous sections, we know that the database component is part of the node, not the
    86//! runtime. We also hinted that a set of host functions ([`pezsp_io::storage`]) are how the runtime
    87//! issues commands to the node to read/write to the state. Let's dive deeper into this.
    88//!
    89//! The state of the blockchain, what we seek to come to consensus about, is indeed *kept* in the
    90//! node side. Nonetheless, the runtime is the only component that:
    91//!
    92//! 1. Can update the state.
    93//! 2. Can fully interpret the state.
    94//!
    95//! In fact, [`pezsp_core::storage::well_known_keys`] are the only state keys that the node side is
    96//! aware of. The rest of the state, including what logic the runtime has, what balance each user
    97//! has and such, are all only comprehensible to the runtime.
    98#![doc = simple_mermaid::mermaid!("../../../mermaid/state.mmd")]
    99//!
    100//! In the above diagram, all of the state keys and values are opaque bytes to the node. The node
    101//! does not know what they mean, and it does not know what is the type of the corresponding value
    102//! (e.g. if it is a number of a vector). Contrary, the runtime knows both the meaning of their
    103//! keys, and the type of the values.
    104//!
    105//! This opaque-ness is the fundamental reason why Bizinikiwi-based chains can fork-less-ly upgrade:
    106//! because the node side code is kept oblivious to all of the details of the state transition
    107//! function. Therefore, the state transition function can freely upgrade without the node needing
    108//! to know.
    109//!
    110//! ## Native Runtime
    111//!
    112//! Historically, the node software also kept a native copy of the runtime at the time of
    113//! compilation within it. This used to be called the "Native Runtime". The main purpose of the
    114//! native runtime used to be leveraging the faster execution time and better debugging
    115//! infrastructure of native code. However, neither of the two arguments strongly hold and the
    116//! native runtime is being fully removed from the node-sdk.
    117//!
    118//! See: <https://github.com/pezkuwichain/pezkuwi-sdk/issues/243>
    119//!
    120//! > Also, note that the flags [`pezsc_cli::ExecutionStrategy::Native`] is already a noop and all
    121//! > chains built with Bizinikiwi only use WASM execution.
    122//!
    123//! ### Runtime Versions
    124//!
    125//! An important detail of the native execution worth learning about is that the node software,
    126//! obviously, only uses the native runtime if it is the same code as with the wasm blob stored
    127//! onchain. Else, nodes who run the native runtime will come to a different state transition. How
    128//! do nodes determine if two runtimes are the same? Through the very important
    129//! [`pezsp_version::RuntimeVersion`]. All runtimes expose their version via a runtime api
    130//! ([`pezsp_api::Core::version`]) that returns this struct. The node software, or other
    131//! applications, inspect this struct to examine the identity of a runtime, and to determine if two
    132//! runtimes are the same. Namely, [`pezsp_version::RuntimeVersion::spec_version`] is the main key
    133//! that implies two runtimes are the same.
    134//!
    135//! Therefore, it is utmost important to make sure before any runtime upgrade, the spec version is
    136//! updated.
    137//!
    138//! ## Example: Block Execution.
    139//!
    140//! As a final example to recap, let's look at how Bizinikiwi-based nodes execute blocks. Blocks are
    141//! received in the node side software as opaque blobs and in the networking layer.
    142//!
    143//! At some point, based on the consensus algorithm's rules, the node decides to import (aka.
    144//! *validate*) a block.
    145//!
    146//! * First, the node will fetch the state of the parent hash of the block that wishes to be
    147//! imported.
    148//! * The runtime is fetched from this state, and placed into a WASM execution environment.
    149//! * The [`pezsp_api::Core::execute_block`] runtime API is called and the block is passed in as an
    150//! argument.
    151//! * The runtime will then execute the block, and update the state accordingly. Any state update is
    152//!   issued via the [`pezsp_io::storage`] host functions.
    153//! * Both the runtime and node will check the state-root of the state after the block execution to
    154//!   match the one claimed in the block header.
    155//!
    156//! > Example taken from [this
    157//! > lecture](https://www.youtube.com/watch?v=v0cKuddbF_Q&list=PL-w_i5kwVqbkRmfDn5nzeuU1S_FFW8dDg&index=4)
    158//! > of the Pezkuwi Blockchain Academy.