Skip to main content

What are canisters?

Beginner
Education
Concept

The smart contracts running on ICP are a powerful evolution of traditional smart contracts. ICP smart contracts are called canisters and are computational units that combine both code and data. Canisters can contain any arbitrary code or data, from serving web pages to creating a secure messaging app or implementing a decentralized token exchange.

Canister

Canisters have special properties that allow developers to build scalable Web3 services. To better understand these properties, one has to consider canisters from different perspectives to form a complete picture of their capabilities.

The Internet Computer Protocol (ICP) accepts and executes canisters in the WebAssembly (Wasm) binary format. In theory, developers could write valid canisters directly in the Wasm bytecode. Since that would be too tedious and time-consuming, the standard practice is to write canister code in a higher-level language, such as JavaScript/TypeScript, Motoko, Python, or Rust, then compile it into Wasm.

The primary developer tool in the ICP ecosystem is the IC SDK, which includes dfx. dfx is a command line multi-tool that assists the developer throughout the entire development process, starting from the generation of developer keys and setting up a new project to compiling, deploying, and managing canisters.

  ICP in the tradeoff space

By default, dfx generates a project structure consisting of two canisters: the frontend canister and the backend canister. The frontend canister contains web assets such as JavaScript, HTML, CSS, and images that are served to the browser. The actual program logic of the application is defined in the backend canister.

The configuration with a frontend and a backend canister is just a convention. It is possible to write a single canister that contains both the program logic and hosts the web assets.

Since canisters can be written in different languages, it is important that they all agree on the binary format in which they accept their arguments and return results. This common format allows users and canisters to call other canisters regardless of the language they were written in. In traditional programming, this concept is known as Application Binary Interface (ABI). ICP has its own ABI language called Candid, which is similar to JSON or Protobuf, but tailored for ICP.

During the build process, dfx uses the backend ABI to automatically generate JavaScript boilerplate code for the frontend. Under the hood, the boilerplate code uses a library called the ICP JavaScript agent to encode Candid values and make HTTP requests from the browser to the backend canister. This is similar to web3.js in Ethereum.

The Wasm standard defines only the instructions and the memory of the Wasm virtual machine; how a Wasm program interacts with other programs and users is left up to the host that embeds the virtual machine. ICP as a Wasm host provides a set of functions that Wasm code can use to read the incoming arguments, call the system and other canisters, and return results. Collectively these functions are referred to as the System API. Developers are not intended to use the System API directly because that would be too low-level and error-prone. Instead, developers should use language-specific Canister Development Kit (CDK) libraries that are high-level wrappers around the System API.

Canister lifecycle

Write

The ICP accepts and executes canister code in the WebAssembly (Wasm) binary format. Usually, developers write code in a higher-level language and then compile the code into a Wasm binary that can be deployed into a canister.

Learn more about writing canister code.

Create

A developer can create an empty canister on ICP by using dfx canister create in the command line or the NNS frontend dapp in the browser. The developer can specify the initial canister settings and choose the target subnet. Once the canister is created, the developer receives its canister ID and becomes the controller of the canister.

Learn more about creating canisters.

Create canister

Compile

Once an empty canister has been created, the canister's code must be compiled into a Wasm binary using dfx build.

Learn more about compiling code into Wasm.

Install

The next step after writing the code, creating a canister, and compiling the code is to install the code into the canister. This can be done by calling the install_code endpoint of the management canister and passing the canister ID and the Wasm binary to it. The dfx canister install command is used for making this call.

Install canister

Deploy

Once a canister has an installed Wasm binary, it can be deployed to the local, playground, or mainnet environments with dfx deploy.

Learn more about deploying canisters.

Call

After deployment, the canister accepts and processes messages (calls) from users and other canisters. Only the public endpoints of the canister can be called. These endpoints correspond to exported Wasm functions that are annotated with canister_update or canister_query in their names.

Call canister

Maintain

Certain system operations that change the state of the canister can be performed only by the controllers of the canister. The most important operation is upgrading the canister by installing a different Wasm binary. In the initial stages of development, the canister is usually controlled by its developer, which allows the developer to iterate quickly. As the canister becomes mature and production ready, the control over it could move to a DAO in order to make the canister secure and trustworthy. Learn more about different types of controllers.

Manage canister

Since ICP uses a reverse gas model, the canister pays for its execution, storage, and other operations with cycles. This means that controllers and/or users of the canister have to ensure that the canister does not run out of cycles. If the canister runs out of cycles, it will be uninstalled by removing its Wasm binary and its storage.

If the canister is no longer used or needed, a controller of the canister can delete it. ICP guarantees that the canister ID will not be reused for another canister.