Canisters (dapps/smart contracts)
Canisters are smart contracts that scale — interoperable compute units designed for internet-scale services. A dapp built on the Internet Computer can be composed of one or more canisters. Some of the dapp's canisters may provide web interfaces that end-users can access through their browser.
Some key design features of canisters include:
- They are general purpose, meaning that the class of smart contract programs is Turing complete (i.e., anything computable can be computed by a smart contract).
- They are tamperproof, meaning that the instructions of the program are carried out faithfully and that intermediate and final results are accurately stored and/or transmitted.
- They're autonomous, meaning that a smart contract is executed automatically by the network, without the need for any action on the part of any individual.
Beyond this, canisters
- are composable, in that they may interact with one another, and
- support tokenization, meaning that they may use and trade digital tokens.
An important feature to note is that the IC allows a range of mutability policies for canisters, ranging from purely immutable to unilaterally upgradable, with other options in between. Immutability is essential in some cases, one may for instance imagine a financial contract where it is important the code in the canister never changes. In other cases, mutability is called for, the canister can be upgraded to better serve users or to fix a bug.
From smart contracts to canisters
A smart contract is a piece of software or a computer program that acts on inputs and faithfully produces certified results while maintaining the integrity of its internal state. For a smart contract to be trusted, it has to run on a trustworthy platform such as the Internet Computer. Smart contracts have huge advantages over traditional software in that they provide a chain of trust from inputs to outputs and cannot be tampered with.
Canisters are first and foremost smart contracts. However, there are several analogies which may be easier to understand from different perspectives.
- A canister is similar to a process, as in an operating system.
- A canister is similar to a container, as used by docker and the open container initiative.
- A canister is a WebAssembly module instance.
- A canister is an actor, as in the actor model.
Canisters as smart contracts
A key difference between smart contracts deployed on the Internet Computer and on a traditional blockchain is how data from smart contracts can be verified. The Internet Computer is powered by Chain Key Cryptography which enables any artifact certified by any smart contract running on any subnet blockchain to be verified using a single 48-byte public key for the whole Internet Computer. This is in contrast to traditional blockchains, where the entire blockchain from Genesis is needed to verify the current state of affairs.
A useful analogy is that between a traditional database and its transaction log. A subnet blockchain is the transaction log of the cryptographically certified subnet state. In a traditional blockchain, the whole transaction log needs to be replayed to certify the state of smart contracts running on the blockchain. On a subnet blockchain, the subnetwork state, i.e., the state of all smart contracts running on the blockchain, is periodically recertified (currently every 100 blocks) so the whole subnet blockchain doesn't need to be kept around forever, or, if need be, it can be stored away as a backup. This gives smart contracts running on the Internet Computer clear scalability advantages over smart contracts running on traditional blockchains.
Canisters as processes
A canister is much like a process in an operating system like Linux, MacOS, or Windows. The operating system keeps track of valid memory ranges for a process, while the Internet Computer enforces a boundary on a canister's linear memory. The operating system scheduler wakes up a process when there is work to be done, while the IC schedules the execution of canisters on their inputs. The operating system maintains state on behalf of a process, like open file descriptors and the parent process. Similarly, the Internet Computer maintains state on behalf of a canister, but instead of things like file descriptors, it keeps track of the canister's balance of cycles, outstanding calls, permissions, and more. Just as a process cannot directly modify its table of file descriptors, a canister cannot directly modify its balances of cycles.
The operating system provides functionality to processes that allow them to perform special operations, like manipulating files and communicating with peripheral devices. Similarly, the Internet Computer provides APIs to canisters so that they can:
- make payments;
- call out to other canisters;
- create and manage canisters;
- manage permissions; and
- get the system time - a non-trivial function in a distributed system.
A unique feature of the Internet Computer is that it provides access to secure randomness. Soon, canisters will also be able to sign Bitcoin and Ethereum transactions through such APIs.
Behind the scenes, the biggest difference between a process and a canister is that a canister is replicated over several nodes. When a process malfunctions it crashes, but when a canister malfunctions, caused by a trap in WebAssembly, it does not crash. Instead its state is rolled back to what it was before the current message started executing, so that the canister can continue executing new messages. Of course, this is of little help if the canister crashes on all of the messages it receives, but it is a very useful safeguard against accidentally missed cases in the logic of a canister. In fact, a canister cannot terminate in the same way a process can terminate — because there is no exit() or abort() system call. A canister can only be removed from the Internet Computer by a controller through an administrative command. A controller of a canister is a user or another canister that is allowed to perform administrative commands, such as removing or upgrading the canister. The ability of a canister to control another canister is a key ingredient when building autonomous or self-governing services on the Internet Computer.
Canisters as containers
The meaning of the word canister is similar to the word container, in fact, a canister is typically understood as a cylindrical container. And, indeed, the canister concept has several things in common with the container concept.
Docker provides the following definition: "A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another."
Containers and canisters are also similar in that they can be running and paused (container) or stopped (canisters). They can be moved around while stopped. Containers run a process inside them so they also have to deal with the process exiting.
Thus, the main difference between containers and canisters is that a canister is a smart contract, i.e., it provides s security guarantees and runs on trusted platform.
Canisters as WebAssembly instances
A canister is much like a WebAssembly module instance. This is more than just an analogy — this is how canisters are actually implemented on the Internet Computer.
Technically, the code part of a canister is a WebAssembly module that imports the System API; that is, the functionality provided to the canister by the Internet Computer. Moreover, a canister can export an API of its own, which can be called by users and other canisters.
According to the WebAssembly specification: “A module instance is the dynamic representation of a module, complete with its own state and execution stack.” Therefore, a canister deployed on a subnet blockchain is a WebAssembly module instance, not just a WebAssembly module — an important distinction - since there could be many canisters running the same WebAssembly module.
Canisters use orthogonal persistence to make it seem like the module instance lives forever, rendering databases or file I/O obsolete. To persistently store a variable, developers can just write the variable to memory. The operation of persisting the data is completely transparent to the developer, and orthogonal in the sense that the developer doesn't have to do anything special to persist the data.
All “writes” to a canister’s linear memory are tracked, for two reasons. First, so that failed computations or WebAssembly traps can be rolled back. Next, if one replica crashes due to unforeseen events such as power outages, when the replica comes back online, it will request modified pages from other replicas, so it can resume operation. This is how the Internet Computer maintains the illusion of providing WebAssembly module instances with indefinite lifetime.
Embracing WebAssembly gives the Internet Computer several benefits:
- Canisters can be written in any language that can compile to WebAssembly (e.g. Motoko, Rust), and canisters written in different languages are fully interoperable.
- WebAssembly is deterministic, except for a few edge cases that are easy to rule out.
- WebAssembly has formal semantics. Over a longer time horizon, there may be end-to-end formally verified WebAssembly execution environments, for additional security.
Moreover, the Internet Computer will evolve with the WebAssembly specification, adding support for new features as they become mature enough.
Canisters as actors
The actor model is a mathematical model of concurrent computation, where, in response to a message, an actor can modify its state, send messages, and create more actors.
A canister is like an actor in many respects. For example, an actor has:
- a private state that can only be modified by the canister itself;
- a single thread of execution, so it does not need lock-based synchronization;
- the ability to communicate with other canisters through asynchronous messages; and
- the ability to create new canisters.
An important difference between traditional actors and canisters is that canisters on the Internet Computer have bidirectional message passing. Messages are divided into requests and responses, where requests can be replied to and the Internet Computer keeps track of the callback for responses.
In actor terminology, each actor has a mailing address that is used to receive messages. A canister also has a mailing address, which happens to look similar to an IPv6 address.
A single canister has only one thread of execution for updates, but the Internet Computer executes a potentially massive number of canisters in parallel. In addition, we make a distinction between requests that need to update the state of a canister, and queries, which cannot modify the state of a canister.
While a canister's update throughput is limited by consensus of the blockchain and the single thread of execution, a canister can serve hundreds of queries concurrently, achieving throughput in the order of thousands of queries per second, and latency measured in milliseconds.
To complete this picture, it should be added that end users also participate as actors in the model. This means that browsers and mobile apps can directly perform update and query operations on canisters.
In addition, the Motoko programming language, which is tailored to the Internet Computer, is inspired by the actor model.
Advantages over other types of smart contracts
Canisters have all the features of smart contracts on other blockchains. "In contrast to smart contracts, however, canisters have performance characteristics that makes it possible to use them to build software services that scale. Canisters are better suited for distributed systems and concurrency because of their embracing of the actor model.
The number of canisters on the IC are represented in the IC dashboard.