Skip to main content

Inside canisters

Beginner
Concept

Canisters are WebAssembly (Wasm) programs with additional features that allow them to store persistent data, communicate with users and other canisters, and be managed by entities such as DAOs. To enable these functionalities, canisters have additional components alongside the the standard Wasm code and memory. These components are outlined in the diagram below.

Canister

Canister ID

A canister has a unique identifier that is often referred to as the address of the canister or the principal of the canister. When a user or a canister sends a message to another canister, they specify the target canister by its id in the header of the message. The system then routes the message to the target canister and adds it to the input queue of that canister.

Input queue

Canisters have queues for incoming messages. When a canister is scheduled for execution, it takes one message from the queue and runs the corresponding Wasm function specified by that message. The code of the function is stored in the Wasm binary of the canister. During execution, the function reads the payload of the message and modifies data stored in the canister.

The order of messages in the queue depends on the implementation and it is not necessarily FIFO (first-in first-out).

Canister storage

There are two storages available to the canister: the Wasm memory and the stable memory. The function doesn’t need to do anything special to use the Wasm memory since this memory type is automatically used for heap-allocated objects. Wasm memory is currently 32-bit, with a maximum size limitation of 4GiB. Stable memory is 64-bit and allows the canister to scale beyond 4GiB. The function can access the stable memory by calling special system functions such as stable64_read and stable64_write.

Both the Wasm and stable memories are persistent in the sense that the system automatically commits all memory modifications after a successful execution of a message. If the message execution fails, then the changes are not committed. The difference between the Wasm and the stable memory becomes important during canister upgrades to a new Wasm code. A canister upgrade clears the Wasm memory, but preserves the stable memory (hence the name).

Output queue

During execution, the canister may send messages to other canisters. These messages are enqueued in the output queue of the canister after a successful execution. Later on, ICP delivers these messages to the target canisters for processing.

Canister-to-canister calls are implemented on top of messages. Each call consists of two messages: the call message from the caller to callee and the response message from the callee to the caller.

Cycles balance

Canisters pay for execution in cycles. The cost of execution depends on the number and type of executed Wasm instructions. The system charges this cost from the cycles balance of the canister both for successful and failed executions.

Controllers

Only controllers of the canister can do certain system level operations on the canister such as stopping it, starting it, upgrading it, etc. The list of controller principals is stored in the canister. Both users and canisters can be controllers. If the canister has no controllers, then it is immutable in the sense that its Wasm code cannot be changed.

Settings

A canister also has various other settings and flags that can be modified by controllers of the canister. For example, a controller can set the freezing threshold of the canister such that the canister becomes frozen and doesn't execute messages when it is low on cycles in order to reduce chances of running out of cycles. View the full list of canister settings.