This document describes the architecture of ink!. The information here targets those who want to understand or modify the inner workings of this project.
In general we treat documentation as a first-class citizen.
All crates mentioned below should be documented really well.
You can find the crate documentation on docs.rs or for our
master
branch under GitHub pages. So for ink_lang
e.g.:
- https://docs.rs/ink_lang/latest/ink_lang (latest)
- https://paritytech.github.io/ink/ink_lang (
master
)
ink! is composed of a number of crates that are all found in the
crates/
folder. On a high-level those can be grouped as:
lang
: The ink! language itself.allocator
: The allocator used for dynamic memory allocation in a contract.engine
: An off-chain testing engine, it simulates a blockchain environment and allows mocking specified conditions.env
: Serves two roles:- Exposes environmental functions, like information about the caller of a contract call, getting random entropy, or e.g. self-terminating the contract.
- Provides the connection to the
pallet-contracts
, so anything that calls into the underlying execution engine of the smart contract. This includes getting and setting a smart contracts storage, as well as the mentioned environmental functions.
metadata
: Describes the contract in a platform agnostic way, i.e. its interface and the types, its storage layout, etc.prelude
: Provides an interface to typical standard library types and functionality (likevec
orstring
). Since contracts are run in ano_std
environment we provide this crate as an entrypoint for accessing functionality of the standard library.primitives
: Utilities that are used internally by multiple ink! crates.storage
: The collections that are available for contract developers to put in a smart contracts storage.
An important thing to note is that the crates are primarily run in
a no_std
environment.
Exceptions are metadata
and engine
, which cover use-cases that
are only relevant off-chain.
ink! contracts are compiled for a WebAssembly (Wasm) target architecture,
i.e. they are executed in a Wasm sandbox execution environment on the
blockchain itself ‒ hence a no_std
environment.
More specifically they are executed by the pallet-contracts
,
a module of the Substrate blockchain framework. This module takes ink!
smart contracts and runs them in a sandbox environment.
The above diagram shows the main components of the ink! language
and how they interact. This pipeline is run once you execute
cargo build
on an ink! smart contract.
The central delegating crate for the ink! eDSL is ink_lang
.
In the crates/lang/
folder you'll find three separate
crates on which ink_lang
relies heavily:
ink_lang_macro
: The procedural macros, they take code annotated with e.g.[ink::contract]
and forwards it toink_lang_ir
.ink_lang_ir
: Defines everything the procedural macro needs in order to parse, analyze and generate code for ink! smart contracts.ink_lang_codegen
: Generates Rust code from the ink! IR.
While you can build an ink! smart contract with just cargo build
, we
recommend using our build tool cargo-contract
.
It automatically compiles for the correct WebAssembly target
architecture and uses an optimal set of compiler flags.
ink! smart contracts use a very simple bump allocator for dynamic
allocations. You can find it in crates/allocator/
.
This allocator never frees allocated space, in case it runs out of a defined limit of space to allocate it crashes. This was done with the intention of reducing its complexity, which would have resulted in higher costs for the user (due to increased gas costs) and a lower transaction throughput. Freeing memory is irrelevant for our use-case anyway, as the entire memory instance is set up fresh for each individual contract call anyway.
We would like to get away from nightly features of Rust in ink!, so
that users can just use stable Rust for building their contracts.
At the moment we're still stuck with one nightly feature though:
alloc_error_handler.
It's needed because we use a specialized memory allocation handler,
the ink_allocator
crate.