Canisters and code

One of the most important principles to keep in mind is that the Internet Computer is primarily a distributed and decentralized platform for running software.

When you write source code for an application that runs on the Internet Computer, you compile the source code into a WebAssembly module. When you deploy the WebAssembly module that contains your program on an Internet Computer replica, the program is executed inside of a conceptual computational unit called a software canister.

Once deployed, end-users can interact with the software canister by accessing the entry point functions you have defined for that canister through a front-end client such as a browser.

Canisters include both program and state

A software canister is similar to a container in that both are deployed as a software unit that contains compiled code and dependencies for an application or service.

Containerization allows for applications to be decoupled from the environment, allowing for easy and reliable deployment. The canister differs from a container, however, in that it also stores information about the current software state with a record of preceding events and user interactions.

While a containerized application might include information about the state of the environment in which the application runs, a software canister is able to persist a record of state changes that resulted from an application’s functions being used.

Query and update methods

This concept of a canister consisting of both program and state is an important one because when a canister function is invoked by sending a message to one of its entry points, there are only two types of calls: non-committing query calls and committing update calls.

Type Key points to remember

Query calls

Allow the user to query the current state of a canister or call a function that operates on the canister’s state without changing it.

  • Are synchronous and answered immediately.

  • Can be made to any node that holds the canister and do not require consensus to verify the result. There is an inherent tradeoff between security and performance because the reply from a single node might be untrustworthy or inaccurate.

  • Do not allow changes to the state of the canister to be persisted. Essentially, programs use query calls to perform read-only operations.

  • Do not allow the called canister to invoke functions exposed by other canisters as inter-canister calls. (Note that this restriction is temporary and that canisters will be able to invoke functions exposed by other canisters when processing query calls in the future.)

Update calls

Allow the user to change the state of the canister and have changes persisted.

  • Are answered asynchronously.

  • Must pass through consensus to return the result. Because consensus is required, changing the state of a canister can take time. Therefore, update calls use the actor-based programming model (with state isolation) to allow concurrent and asynchronous processing. There is an inherent tradeoff between security and performance because two-thirds of the replicas in a subnet must agree on the result.

  • The called canister can invoke functions exposed by other canisters

As a developer, it is important to recognize this relationship between the calls that query the canister and the calls that change the canister state. In particular, you should keep in mind the inherent tradeoff between security and performance.

How to develop applications for the Internet Computer

For programmers and software developers, the Internet Computer platform provides unique capabilities and opportunities within a framework that simplifies how you can design, build, and deploy applications. A key part of this framework is a new, general purpose programming language, Motoko. Motoko is a programming language that has been specifically designed to take full advantage of the unique features that the Internet Computer provides, including:

  • The ability to define programs directly using actor objects and classes.

  • The use of async and await syntax to enable programming asynchronous messaging as if it was synchronous processing.

  • Automatic support for message serialization and deserialization.

  • The ability to leverage orthogonal persistence using data structures without external databases or storage volumes.

As a modern, high-level programming language, Motoko provides some key features of its own, including:

  • Support for big integer operations and overflow protection.

  • A sound type system that statically checks each program to ensure it can execute without type errors on all possible inputs.

  • Support for function abstractions, user-defined type definitions, and user-defined actors.

For more detailed information about the Motoko programming language itself, including syntactical conventions and supported features, see the Motoko Programming Language Guide.

The following diagram provides a simplified drill-down view of the development environment as part of the Internet Computer ecosystem.

Your development environment as part of the Internet Computer ecosystem

Canisters, actors, and the code you produce

One of the most important principles to keep in mind when preparing to write programs using the Motoko programming language is that Motoko uses an actor-based programming model.

An actor is a special kind of object that processes messages in an isolated state, enabling messages to be handled remotely and asynchronously. Many key features of the Internet Computer platform depend on this type of secure and efficient asynchronous message handling.

In general, each software canister includes the compiled code for one actor object. Each canister also includes some additional information such as interface descriptions or front-end assets. You can create projects that include multiple canisters, but each canister can only include one actor.

Why your code is compiled into WebAssembly

When you compile Motoko code, the result is a WebAssembly module. WebAssembly is a low-level computer instruction format that is portable and abstracts program execution cleanly over most modern computer hardware. It is broadly supported for programs that run on the internet and a natural fit for deploying applications that are intended to run on the Internet Computer platform.

With Motoko, developers can compile to portable WebAssembly while still delivering secure applications using a simple and high-level language.

The Motoko language offers many of the features that are common to other higher-level modern languages—like type safety and pattern-matching. In addition, Motoko provides built-in support for defining messaging services using actors in a way that is especially well-suited to the Internet Computer platform and is easy to learn whether you are a new or experienced programmer.

This guide provides an introduction to the basic features of the Motoko programming language in the context of writing programs using the SDK. For more detailed information about the Motoko programming language itself, see the Motoko Programming Language Guide.

Identities and authentication

One of the main differences between a user-initiated canister operation and a canister-to-canister operation is that canisters have an explicitly registered identity on the [IC].

There is no central registry for user principals. Instead, user identifiers are associated specifically with the canisters each user accesses through one or more public-private key pairs. The user’s private key is used to sign messages, which are sent along with their public key to a canister. The [IC] authenticates the user and passes the principal to the canister for the authorization of their operation.

At a high level, first-time users generate an unsigned key pair and derive their principal identifier from the public key during their first interaction with the Internet Computer. Returning users are authenticated using the private key (or keys) that have been stored securely by the user agent. Users with access to multiple canisters can manage the keys and devices used for authentication associated with each canister.

A single user can have multiple public-private key pairs for accessing canisters from different devices—such as browsers running on different computers, mobile phones, or tablets—but these derived keys all map to a primary identifier.

Resource consumption and cycles

In general, all canisters consume resources in the form of CPU cycles for execution, bandwidth for routing messages, and memory for persisted data. Canisters maintain an account balance of cycles to pay for the cost of communication, computation, and storage that their applications consume.

Cycles are intended to reflect the real cost of operations including physical hardware, rack space, energy, storage devices, and bandwidth in a stable or deflationary way so that the cost of program execution remains the same or decreases with operational efficiency.

  • Programs must be able to pay for complete execution (all or nothing), but the cost associated with a unit of cycles will make efficient programs cost-effective.

  • By setting limits on how many cycles a canister can consume, the platform can prevent malicious code from draining resources.

The relative stability of operational costs makes it easier to predict the cycles required to process, for example, a million messages.

The cycles available for program execution are held in a wallet canister. For local deployment, wallet canisters are automatically created and issued cycles. To deploy your application on the Internet Computer network running on external nodes and subnets, however, you’ll need to provide a principal and be issued a wallet canister identifier.

When you deploy canisters locally or to an Internet Computer test network, program execution consumes cycles but there are no funds associated with those cycles. However, it is possible that in calculating the operations to be performed, executing a program might result in an “out of cycles” exception because the operations would exceed a predefined threshold. If you see this exception in testing, you can temporarily configure a higher cycles limit by setting a command-line option.

Want to learn more?

If you are looking for more information about canisters, check out the following related resources: