Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

34 changes: 30 additions & 4 deletions docs/concepts/canisters.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ For a deeper dive, see [Orthogonal persistence](orthogonal-persistence.md).

## Canister IDs and principals

Every canister gets a globally unique **canister ID** when it is created. This ID is a [principal](https://learn.internetcomputer.org/hc/en-us/articles/34250491785108): the same type of identifier used for users: and serves as the canister's address on the network.
Every canister gets a globally unique **canister ID** when it is created. This ID is a [principal](principals.md): the same type of identifier used for users, and serves as the canister's address on the network.

To send a message to a canister, you include its canister ID in the message header. The network routes the message to the correct subnet and places it in the canister's input queue for processing.

Expand All @@ -90,7 +90,13 @@ Installing uploads a Wasm module to the canister and runs its initialization log

### Upgrade

Upgrading replaces the canister's Wasm module while preserving stable memory. The system runs a pre-upgrade hook (to save heap data to stable memory if needed), swaps the Wasm, then runs a post-upgrade hook (to restore data).
Upgrading replaces the canister's Wasm module while preserving stable memory. The runtime executes three steps atomically:

1. `pre_upgrade` (or `system func preupgrade` in Motoko): save any heap data to stable memory before the code swap.
2. New Wasm module is installed.
3. `post_upgrade` (or `system func postupgrade`): read data back from stable memory into the new heap layout.

If `pre_upgrade` traps, the upgrade is aborted and the canister continues running the old code. If `post_upgrade` traps, the new code is installed but the canister is left in a failed state. If a canister ensures all persistent data is always in stable memory, steps 1 and 3 can be left empty.

### Stop and delete

Expand All @@ -102,7 +108,16 @@ For step-by-step CLI commands, see [Canister lifecycle management](../guides/can

Controllers are principals (users or other canisters) that have permission to manage a canister: upgrade its code, change its settings, stop it, or delete it.

If a canister has **no controllers**, it is immutable: no one can change its code or settings. This is a strong guarantee for users who want to verify that a canister's behavior will never change.
The control structure can take several forms:

| Control structure | Who is the controller | Effect |
|---|---|---|
| Centralized | A single developer's principal | Full developer control; standard during development |
| Multi-signature | A multi-signer wallet like [Orbit](https://orbitwallet.io/) | Requires multiple keys to approve any change |
| SNS-governed | A Service Nervous System (SNS) governance canister | Upgrades require a governance proposal voted on by asset holders |
| No controller | Empty controller list | Immutable canister; code can never be changed |

If a canister has **no controllers**, it is immutable: no one can change its code or settings. This is a strong trust guarantee for users. Immutability can be verified on the [ICP Dashboard](https://dashboard.internetcomputer.org).

## Canister internals

Expand All @@ -114,11 +129,22 @@ Under the hood, each canister maintains several components:
- **Controllers list**: the set of principals authorized to manage the canister.
- **Settings**: configurable parameters like compute allocation, memory allocation, and the freezing threshold (the cycles balance below which the canister stops accepting new messages to avoid running out).

## Inter-canister messaging and error handling

Canisters communicate by sending **requests** to other canisters and registering a **callback** to be invoked when the callee sends a response. The network guarantees that every request receives a reply: if a callee becomes unreachable or explicitly rejects a call, the Internet Computer synthesizes a reject response and delivers it to the caller's callback. Callbacks are never dropped.

This bidirectional request/reply model is one way canisters differ from pure actors in classical actor-based systems, which typically use one-way fire-and-forget messages.

**Trap behavior with outgoing calls:** When a canister processes a message, it may send outgoing requests before completing. Each time a canister sends a request, the network records a commit point. If the canister later traps while awaiting a response, its state reverts to what it was immediately after that last outgoing request was dispatched, not to the beginning of the original incoming message. This means any state changes made after the last outgoing call are rolled back, while changes made before it are preserved.

This has a practical implication: if a canister modifies state and then makes an inter-canister call in the same message, it must account for the possibility that subsequent code (including the callback handler) will see the state as it was when the call was sent.

## Next steps

- [Cycles](cycles.md): how canisters pay for computation
- [Principals](principals.md): the identity model and caller authentication
- [App architecture](app-architecture.md): how canisters fit into application design
- [Canister lifecycle](../guides/canister-management/lifecycle.md): practical guide to managing canisters
- [Network overview](network-overview.md): the infrastructure canisters run on

<!-- Upstream: informed by dfinity/portal docs/building-apps/essentials/canisters.mdx, message-execution.mdx -->
<!-- Upstream: informed by dfinity/portal docs/building-apps/essentials/canisters.mdx, message-execution.mdx; informed by Learn Hub articles "Canister Smart Contracts", "Computational Model", "Canister Control" (migrated, source retired) -->
1 change: 1 addition & 0 deletions docs/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Understand the ideas behind the Internet Computer before you build on it. These
- **[Application Architecture](app-architecture.md)**: How ICP applications are structured: canisters, frontends, and inter-canister communication.
- **[Canisters](canisters.md)**: Programs that run WebAssembly, hold state, serve HTTP, and pay for their own compute.
- **[Protocol Stack](protocol/index.md)**: The four-layer architecture (peer-to-peer, consensus, message routing, execution) and protocol internals including performance benchmarks.
- **[Principals](principals.md)**: The identity model: who can call a canister, and how caller identity works.

## Core capabilities

Expand Down
40 changes: 40 additions & 0 deletions docs/concepts/principals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
title: "Principals"
description: "What principals are on ICP: the five principal classes and how caller identity works in practice"
---

A **principal** is any entity that can authenticate with the Internet Computer and be identified when calling a canister. Principals are the building block of identity and access control on ICP: canisters use them to identify callers, enforce permissions, and determine which entities have control over which resources.

## Principal classes

ICP defines five principal classes, though one (derived IDs) has never been implemented:

**1. Management canister principal (`aaaaa-aa`):** The IC management canister is a virtual system API that canisters call to perform operations like creating other canisters or changing settings. It does not run at a real canister address; it uses the fixed principal `aaaaa-aa`. Canisters call it with `ic_cdk::management_canister::*` (Rust) or via actor references in Motoko.

**2. Canister IDs:** Each canister on ICP has a unique principal derived when the canister is created. Canister principals look like `ryjl3-tyaaa-aaaaa-aaaba-cai`. When a canister makes a call to another canister, the callee sees the calling canister's canister ID as the caller principal.

**3. Self-authenticating IDs:** User identities are derived from public keys using a domain-separated hash. Anyone holding the corresponding private key can authenticate and call canisters under that principal. Self-authenticating principals look like `o2ivq-5dsbb-hhfso-w2o5v-7qiaq-g4fbm-6qhhb-xbj6w-szpxa-lflfa-mae` for Ed25519 keys or similar for ECDSA keys. The [Internet Identity](https://identity.ic0.app/) service manages key-backed identities for end users.

**4. Anonymous principal (`2vxsx-fae`):** Messages that are not signed use the anonymous principal as their caller identity. Any canister can check whether a caller is anonymous and decide how to handle unsigned requests (for example, allowing public reads but rejecting state changes from anonymous callers).

**5. Derived IDs:** Reserved in the specification but never implemented.

## How principals are used in practice

When a user calls a canister, the Internet Computer authenticates the user's signature and passes the corresponding principal as the `caller` to the canister's message handler. Canisters can then make authorization decisions based on the caller:

```
Caller is user → self-authenticating principal (derived from their public key)
Caller is another canister → that canister's canister ID
Unsigned request → 2vxsx-fae (anonymous principal)
```

This means that from a canister's perspective, all callers are principals. There is no separate "user object" or session token: the principal is the identity.

## Next steps

- [Canisters](canisters.md): how canisters work, controllers, lifecycle, and message types
- [Authentication](../guides/authentication/internet-identity.md): integrating Internet Identity and other authentication providers
- [IC Interface Specification: Principals](../references/ic-interface-spec/index.md#principal): the formal specification

<!-- Upstream: informed by Learn Hub article "What is a Principal?" (migrated, source retired) -->
6 changes: 1 addition & 5 deletions docs/references/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -522,11 +522,7 @@ builds upon this functionality.

#### principal

A **principal** is an entity that can be authenticated by the [Internet Computer](#internet-computer-protocol-icp). This is the same sense of the
word principal as the [Wikipedia
definition](https://en.wikipedia.org/wiki/Principal-(computer-security)).
Principals that interact with the Internet Computer do so using a
certain [identity](#identity).
A **principal** is an entity that can be authenticated by the [Internet Computer](#internet-computer-protocol-icp). Principals include canister IDs, user identities derived from public keys, and the anonymous principal. See [Principals](../concepts/principals.md) for the full classification and how they are used for access control.

#### proposal

Expand Down
1 change: 1 addition & 0 deletions sidebar.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ export const sidebar = [
items: [
{ slug: "concepts/network-overview" },
{ slug: "concepts/canisters" },
{ slug: "concepts/principals" },
{ slug: "concepts/app-architecture" },
{ slug: "concepts/node-infrastructure" },
{ slug: "concepts/edge-infrastructure" },
Expand Down
Loading