Overview of ICP
The Internet Computer Protocol (ICP) bridges the gap between traditional programming and blockchain-based development. Smart contracts on ICP are expressive and scalable like traditional apps, but benefit from the trustless and decentralized execution of a blockchain.
ICP is designed for a practical balance in the tradeoff between scalability and decentralization.
In the conceptual diagram above, decentralization increases going from centralized servers to Ethereum, but that happens at the expense of scalability. ICP is located in the middle of this spectrum. The rest of this page walks through the core concepts and features of ICP to show why that's the case.
One of the keys for high scalability is sharding. ICP shards smart contracts over multiple instances of the blockchain. Each instance is called a subnet and has its own set of decentralized nodes running the consensus algorithm among themselves, building their own chain of blocks, and executing smart contracts. Each subnet runs in parallel with other subnets. A smart contract on one subnet can communicate with another smart contract on a different subnet through sending messages. Users can also send messages to smart contracts. The following diagram shows the flow of a message on ICP:
- The message goes to one of the boundary nodes (RPC nodes).
- The boundary node routes the message to the subnet that hosts the target smart contract.
- The consensus algorithm of that subnet adds the message to a new block in the subnet's blockchain.
- The message is added to the input queue of the target smart contract.
- The smart contract executes the message.
Note that steps 3-5 are asynchronous and decoupled from each other, which may be unusual for developers who are used to Ethereum-style atomic transactions that are executed when they are added to a block. The motivation for this design is scalability.
Subnets can have different sizes, i.e. replication factors, which determines the cost of running smart contracts on that subnet. It also impacts the time to finality and security.
Each ICP subnet has a fixed public key. The corresponding private key is not stored on a single node, nor is it ever available on any node. Instead, it is split into multiple secret shares and distributed over all nodes using threshold cryptography. Nodes can collectively sign messages to users and other subnets using these secret shares. This makes validation of the state and results trivial for users since all they need to do is verify the digital signature against the fixed public key without downloading and validating blocks in the blockchain.
This feature has profound implications and use cases:
- There is no need to keep the blocks in the blockchain available forever, which would be a scalability bottleneck. In fact, ICP actively garbage collects old blocks to keep storage usage bounded.
- Smart contracts can have their own secret keys and can sign transactions for other blockchains such as Bitcoin and Ethereum. This enables trustless interaction with those blockchains.
This feature is called Chain-Key Cryptography on ICP.
Furthermore, a single smart contract on ICP is powerful enough to host an entire Ethereum Virtual Machine (EVM). This allows the deployment of EVM smart contracts written in Solidity.
A unique feature of ICP is that smart contracts can handle HTTP requests and serve web assets such as HTML, JS, CSS. In other words, it is possible to write a Web3 application with both backend and frontend hosted fully on-chain. Smart contracts can also make requests to other Web2 services outside ICP.
Ethereum developers may be used to the notion that smart contracts run sequentially within an atomic transaction. ICP embraces scalability and runs smart contracts in parallel. In that regard, smart contracts are similar to processes or microservices from traditional programming. Smart contracts can be fully autonomous and can schedule execution using timers without relying on users sending messages.
In terms of storage, a smart contract can store arbitrary data in its WebAssembly memory. Additionally, a smart contract can use a larger stable memory. The difference between the two memories is important for upgradable smart contracts: the WebAssembly memory is cleared on an upgrade whereas the stable memory is preserved (hence the name “stable”). For immutable smart contracts, there is no observable difference between the two memories except for the size and functions to access it.
In the context of ICP, smart contracts are referred to as canisters.
Accounts and keys
ICP derives the address of a user account from the user’s public key by hashing it.
The textual encoding of an address includes a checksum that looks something like this:
ICP supports multiple types of keys (ECDSA, Ed25519, BLS). Developer tools usually generate and accept keys in PEM format.
Since smart contracts can have private keys, they can provide user accounts as a service. Internet Identity is an example of a smart contract that allows Web2 users to have blockchain accounts with the private keys stored securely on the blockchain itself.
You can also use hardware and browser-extension wallets.
In the context of ICP, addresses are referred to as principals.
Accounts on ICP do not have built-in balances, which is a large design difference when compared to other chains like Ethereum. All tokens are implemented by smart contracts. ICP has an equivalent of the ERC-20 standard, called ICRC-2. If a smart contract implements ICRC-2, then it implements a fungible token and has a ledger for it.
The programming model of ICP is similar to the Actor model, where calls are made by sending messages instead of transactions. The difference between a transaction and a message becomes apparent only when the smart contract calls other smart contracts. A transaction is atomic in the sense that it rolls back all state changes if any of the calls fail. A message does not have such atomicity guarantees across calls. Programming on ICP is more asynchronous compared to Ethereum. If the smart contract does not make any calls, then the message behaves exactly like a transaction.
On other blockchains such as Ethereum, users pay a variable fee for sending and executing transactions depending on the current gas price. In order to simplify the experience of users browsing Web3 applications, ICP employs a “reverse gas model”, where canisters pay for consumed resources by burning cycles. This is similar to gas in Ethereum, but has a fixed price correlating to a group of fiat currencies.
ICP is governed by a decentralized autonomous organization (DAO) community called the Network Nervous System (NNS). It is implemented as a set of smart contracts running on ICP itself. Community members can participate in governance by staking ICP tokens and voting on proposals. All operational changes to ICP, such as upgrading nodes, go through voting. NNS automatically executes proposals that have passed voting which ensures that nodes run the same version of the protocol and thus avoids hard forks.
Governance and node ownership are decoupled. It is possible to participate in governance without having a node and vice versa.
Becoming a node provider on ICP requires voting from the DAO community. There are two reasons for this:
- It ensures that the hardware meets the high standards of ICP: 64 CPU cores, 512GiB of RAM, 30TB of NVMe SSD. Such nodes can sustain high throughput and enable powerful Web3 applications.
- It ensures that the identity of the node provider is known to the community. The node provider has signed a declaration of good intent and may be liable if the node misbehaves. This makes Sybil attacks harder to pull off and allows for the ability to reduce the number of nodes while keeping the Nakamoto coefficient high. Nodes are assigned to subnets such that they maximize decentralization, in terms of operators, geography and jurisdiction. This is called deterministic decentralization.
Currently, subnets contain between 13 and 40 nodes, and most of them are geographically distributed. However, there can also be localized subnets to support applications that need to comply with local regulations.
Quick comparison with Ethereum
|Smart contracts can sign messages
|HTTP calls to Web2 from smart contracts
|Solidity, Vyper, Yul
|JS, Python, Rust, Solidity, Motoko, and more
|Async message passing
|Upgradable or immutable
|Smart contract pays
|Few million instructions per block (based on the 30 million gas limit)
|2 billion instructions per block (per subnet)
|Average tx/msg fee
|32KB (1024 of 256-bit values)
|24KB (more with code sharing)
|404GiB (4GiB Wasm memory + 400GiB of stable memory)
|$18M per GiB (based on 640K gas per KB)
|$5 per GiB per year
|Number of nodes
|~500 in total, 13-40 per subnet