This is a note of the IC Protocol docs.

1 Introduction

DFINITY was founded in Oct 2016. Four rounds of fund rasing generated $202 millions by Aug 2018. SDK and Motoko were released in 11/2019. Mainnet was launched on May 2021. The IC was created to solve problems faced by today’s web application: community ownship (DAO), improved security (biometrics login), complete decentralization (permessionless p2p), no downtime (>= 13 replicas). It is sefl-governing and runs en masse by independent global data centers. It is unstoppable and tamperproof.

Some cool projects are DSCVR (Reddit), OpenChat (telegram), fleek (Web hosting).

2 The IC

The IC is a public blockchain network that is used to build and run secure, anonymous, and tamper-proof canisters. A canister is an evolution of a smart contract. Network nodes run Internet Computer Protocol (ICP) that is based on Chain Key cryptography. The IC is composed of individual subnet blockchains. Canisters running on a subnet can interoprate canisters hosted in other subnets. The IC runs under the control of a decentralized permissionless governance system, called the Network Nervous System (NNS), which runs completely on-chain. The IC reduces centralized-platform risks and re-imagine how software is build and operated. It provides a secure and efficient Web environment that hides the configuration and operation details of computer, network, and storage. It also provides cryptographically-secure identities to enforce access control.

IC dapps are implemented as canister smart contracts, or canisters for short. IC users (developer, end user or code) access a canister by calling its public entry points, called methods. Methods can be update methods or query methods. Method calls can be external or inter-canister (including self calls). Calls and responses are transmitted as messages. Users issue HTTPS requests whose responses can either be replies or rejects.

Parts of the IC state are publicly exposed in a certified way. Conceptually, the system state is a tree with labeled children, and values in the leaves. Equivalently, the system state is a mapping from paths (sequences of labels) to values. Publicly relevant paths are:

  • Time: /time
  • Subnet information: /subnet/<subnet_id>/public_key and /subnet/<subnet_id>/canister_ranges.
  • Request status: a subtree at /request_status/<request_id> including status (received, processing, replied, rejected, done), replay blob, reject code, reject message.
  • Certified data: /canister/<canister_id>/certified_data. It is a blob.
  • Canister information: /canister/<canister_id>/module_hash and /canister/<canister_id>/controllers.

Some parts of the IC state are exposed to users in a tamperproof way via certification: the IC can reveal a partial state tree which includes just the data of interest, together with a signature on the root hash of the state tree. The root of trust is the root public key, which must be known to the user a priori. In a local canister execution environment, the key can be fetched via the /api/v2/status endpoint.

3 The IC API

The IC expsoes three HTTPS endpoints to handle user interactions and one for diagnostics:

  • /api/v2/canister/<effective_canister_id>/call: a user can submit (asynchronous, state-changing) calls. The POST request body has the following fields. The HTTP response to this request has an empty body and HTTP status 202, or an HTTP error (4xx or 5xx). The user should use read_state to determine the call status.
    • request_type: call
    • sender, nonce, ingress_expiry
    • canister_id
    • method_name
    • arg
  • /api/v2/canister/<effective_canister_id>/read_state: a user can read various information about the state of the Internet Computer. In particular, they can poll for the status of a call here. The POST request body has the following fields. The HTTP response is a certicate blob that has the values of requested paths.
    • request_type: read_state
    • sender, nonce, ingress_expiry
    • paths
  • /api/v2/canister/<effective_canister_id>/query: a user can perform (synchronous, non-state-changing) query calls. The POST request body has the following fields. The response is a map with status of replied/rejected and result (reply) or rejecte code/message.
    • request_type: query
    • sender, nonce, ingress_expiry
    • canister_id
    • method_name
    • arg
  • /api/v2/status: the user can retrieve status information about the IC using a GET request and receive a multi-field value.

the <effective_canister_id> is the textual representation of the effective canister id.

A user request is processed asynchronously as shown in request states. If the user sees request status processing, the state change is guaranteed to happen if the canister is bug free. The user can stop monitoring the status and does not have to retry submitting. If a call is rejected by the IC or the canister, there is no guarantee about how much processing of the call has happened.

To avoid replay attacks, the transition from done or received to pruned must not happen earlier than the call’s ingress_expiry field. Calls must stay in replied or rejected long enough for polling users to catch the response. When asking the IC about the state or call of a request, the user uses the request id to read the request status from the state tree.

All requests coming in via the HTTPS interface need to be either anonymous or authenticated using a cryptographic signature. The signature is calculated by singing the concatenation of the 11 bytes \x0Aic-request (the domain separator) and the 32 byte request id that is representation-independent hash calculated from the request content. The recommended textual representation of a request id is a hexadecimal string with lower-case letters prefixed with 0x like 0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f.

The format in the body of the HTTP request or response is Concise Binary Object Representation (CBOR). Like JSON it allows the transmission of data objects that contain name–value pairs, but in a more concise manner at the cost of human readability. The Concise Data Definition Language (CDDL) is a data description language for CBOR.

4 Principal

Canisters and users are identified by a principal, also called an id. An id is a binary blob with a length between 0 and 29 bytes. There are several classes of ids:

  • Opaque ids: generated by the IC and have no structure, typically ended with 0x01.
  • Self-authenticating ids: a form of Hash(public_key) + 0x02, 29 bytes, used by an external user that can sign the request.
  • Derived ids: having the form Hash(reg_principal_length + reg_principal + nonce) + 0x03, 29 bytes. It is used when an id needs to be registered. Every principal has a space of registered ids dervied from its id.
  • Anonymous id: a fixed form 0x04, used by the anonymous caller without a signature.

An id has a canonical textual format that is a lower case base32 encoding of the id blob and its CRC32 check sequence, separated by a dash separator every 5 characters.

5 Canister

You dapp source code is compiled into a WebAssembly module that is deployed and executed in a canister. A canister is able to persist a record of state changes that resulted from its functions being called.

Developers can create reproducible canisters to make sure that a canister has the correct behavior. A canister is immutable if it doesn’t have an outside controller. A distributed governance mechanism is be used to govern the code change of a canister.

A canister is empty after creation or uninstallation. An empty canister has the following states:

  • an id (a principal)
  • a list of controllers (pincipals)
  • a cycle balance
  • status: one of running, stopping, stopped
  • resource reservation

A canister becomes non-emepty through code installation and has the following states:

  • code, in the form of a canister module
  • state (memories, globals etc)
  • other data such as queues

A canister module is simply a WebAssembly module in binary format .wasm.

A canister pays for the resources it uses from its cycle balance. A canister is deallocated when its cycle balance falls to zero. The IC uninstalls the canister and sets its resouce reservations to zero. The IC perseves the empty canister for 10 years.

The canister interface is the system API between the running canister and the IC. It allows the canister module to expose functionality to the users (method entry points), the IC, and other canisters.

The IC provides additional functionality, such as canister and user management. This functionality is exposed to external users and canisters via the management canister. The IC management canister is just a facade. It does not actually exist as a canister. The IC management canister address is aaaaa-aa, an empty blob "".