From fc5142ae0084bf0b77b72c22052b505575b23229 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 6 May 2026 17:32:01 +0200 Subject: [PATCH 1/5] =?UTF-8?q?docs:=20batch=209=20=E2=80=94=20principals?= =?UTF-8?q?=20and=20canister=20computational=20model?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add principals.md: 5 principal classes, self-authenticating IDs, anonymous principal, canister control model, upgrade behavior with stable memory - Expand canisters.md: inter-canister messaging callbacks, trap/rollback behavior (reverts to state after last outgoing call, not start of message) - Fix canisters.md: replace Learn Hub principal link with internal principals.md - Update concepts/index.md: add principals.md entry - Update glossary.md: replace verbose principal definition with concise entry linking to principals.md - Remove 4 consumed Learn Hub staging files --- .../canister-control.md | 19 ----- .../canister-smart-contracts.md | 28 -------- .../computational-model.md | 15 ---- .../what-is-a-principal.md | 23 ------ docs/concepts/canisters.md | 15 +++- docs/concepts/index.md | 1 + docs/concepts/principals.md | 72 +++++++++++++++++++ docs/references/glossary.md | 6 +- 8 files changed, 87 insertions(+), 92 deletions(-) delete mode 100644 .migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-control.md delete mode 100644 .migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-smart-contracts.md delete mode 100644 .migration/learn-hub/how-does-icp-work/canister-smart-contracts/computational-model.md delete mode 100644 .migration/learn-hub/how-does-icp-work/canister-smart-contracts/what-is-a-principal.md create mode 100644 docs/concepts/principals.md diff --git a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-control.md b/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-control.md deleted file mode 100644 index 21e4413..0000000 --- a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-control.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -learn_hub_id: 34573932107796 -learn_hub_url: "https://learn.internetcomputer.org/hc/en-us/articles/34573932107796-Canister-Control" -learn_hub_title: "Canister Control" -learn_hub_section: "Canister Smart Contracts" -learn_hub_category: "How does ICP work?" -migrated: false ---- - -# Canister Control - -Canisters are managed by _controllers_ , which can be users or other canisters. Controllers are responsible for deploying, maintaining, and managing canisters. They can perform operations such as starting, stopping, and updating the canister, as well as adjusting canister parameters like the freezing threshold. The control structure can be centralized (e.g., when the controllers include a centralized entity), organizational (e.g. when the controller is a multi-signer wallet like [Orbit](https://orbitwallet.io/)), decentralized (e.g., when the controller is a DAO), or non-existent, resulting in an immutable smart contract. - -Controllers can update the code that runs on canisters by submitting a new Wasm module to replace the older one. By default, updating the Wasm module of a canister wipes out the Wasm memory, but the content of the stable memory remains unchanged. The Internet Computer offers an upgrade mechanism where three actions are executed atomically: serializing the Wasm memory of the canister and writing it to stable memory, installing the new Wasm code, and then deserializing the content of the stable memory. This allows for the Wasm heap memory to be kept even if the Wasm module changes. Of course, a canister may ensure at all times that the data that needs to be persisted across upgrades is stored in the stable memory, in which case the upgrade process is significantly simpler. - -## Additional Resources - -[25min video on creating, installing, upgrading, and managing canisters](https://www.youtube.com/watch?v=c5nv6vIG3OQ) - diff --git a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-smart-contracts.md b/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-smart-contracts.md deleted file mode 100644 index fd7491c..0000000 --- a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/canister-smart-contracts.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -learn_hub_id: 34210839162004 -learn_hub_url: "https://learn.internetcomputer.org/hc/en-us/articles/34210839162004-Canister-Smart-Contracts" -learn_hub_title: "Canister Smart Contracts" -learn_hub_section: "Canister Smart Contracts" -learn_hub_category: "How does ICP work?" -migrated: false ---- - -# Canister Smart Contracts - -Smart contracts on the Internet Computer come in the form of canisters: computational units that bundle code and state. Canisters expose endpoints that can be called by other canisters and parties external to the IC, such as browsers or mobile apps. - -There are two types of endpoints in canisters: **updates** and **queries**. Updates modify the state of the canister, while queries read from the state without making changes. The code of a canister is a [WebAssembly (Wasm)](https://webassembly.org/) module. The state includes the usual Wasm memory heap, a special type of memory called stable memory and metainformation about the canister. - -The articles in this section describe - - * [Computation model:](https://learn.internetcomputer.org/hc/en-us/articles/34573860369172) how canister code is executed - * [Cycles](https://learn.internetcomputer.org/hc/en-us/articles/34573913497108): how resources consumed by canisters are charged - * [Canister control:](https://learn.internetcomputer.org/hc/en-us/articles/34573932107796) who can deploy and manage canisters - * [Principals](https://learn.internetcomputer.org/hc/en-us/articles/34250491785108): who can call canisters - - - -## Additional Resources - -[Canister Developer Docs](https://internetcomputer.org/docs/current/home) - diff --git a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/computational-model.md b/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/computational-model.md deleted file mode 100644 index 625b67b..0000000 --- a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/computational-model.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -learn_hub_id: 34573860369172 -learn_hub_url: "https://learn.internetcomputer.org/hc/en-us/articles/34573860369172-Computational-Model" -learn_hub_title: "Computational Model" -learn_hub_section: "Canister Smart Contracts" -learn_hub_category: "How does ICP work?" -migrated: false ---- - -# Computational Model - -Canisters behave much like actors from the [actor-based concurrency model](https://en.wikipedia.org/wiki/Actor_model). Their code is single-threaded and executed in complete isolation from other canisters. Canisters communicate with one another via asynchronous messaging. When processing a message, a canister can make changes to its state, send messages to other canisters, or even create other canisters. Unlike in the traditional actor model, communication is bidirectional. Canister messages are either requests or replies. For each request sent, the Internet Computer records a callback to be invoked when the callee sends back a response. If the Internet Computer determines that there is no way for the callee to respond, then it will produce a response instead, thereby ensuring that every request receives a reply. - -An important aspect of the canister-based model is how canisters handle errors during message processing. When a canister processes a request, it might send out other requests and wait for some of these replies before completing the original request. If an error occurs (the canister “traps”), the canister’s state reverts to what it was right after its last outgoing message. - diff --git a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/what-is-a-principal.md b/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/what-is-a-principal.md deleted file mode 100644 index 902916d..0000000 --- a/.migration/learn-hub/how-does-icp-work/canister-smart-contracts/what-is-a-principal.md +++ /dev/null @@ -1,23 +0,0 @@ ---- -learn_hub_id: 34250491785108 -learn_hub_url: "https://learn.internetcomputer.org/hc/en-us/articles/34250491785108-What-is-a-Principal" -learn_hub_title: "What is a Principal?" -learn_hub_section: "Canister Smart Contracts" -learn_hub_category: "How does ICP work?" -migrated: false ---- - -# What is a Principal? - -The concept of a principal appears at the level of canister smart contracts. In a nutshell, a principal identifies any entity that can call a canister. As both canisters and external users can call canisters, principals include both canister ids and self-authenticating identifiers derived from public keys of users. There are several classes of principals: - - 1. The [Internet Computer Management Canister](https://internetcomputer.org/docs/current/references/ic-interface-spec#ic-management-canister), which is a specific system API that can be called like a canister, uses the fixed principal _aaaaa-aa_. - 2. Canister ids: each canister on ICP is identified by its canister id. - 3. Self-authenticating ids: derived from public keys to identify users. - 4. Derived ids: a class which has been reserved but never implemented. - 5. The anonymous id, _2vxsx-fae:_ used as the identity of the caller for messages that are not signed. - - - -More details can be found in the [relevant section of the interface specification](https://internetcomputer.org/docs/current/references/ic-interface-spec#principal). - diff --git a/docs/concepts/canisters.md b/docs/concepts/canisters.md index cdbe6c4..706ab50 100644 --- a/docs/concepts/canisters.md +++ b/docs/concepts/canisters.md @@ -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. @@ -114,11 +114,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 canister controllers - [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 - + diff --git a/docs/concepts/index.md b/docs/concepts/index.md index 5605ccc..3b495c3 100644 --- a/docs/concepts/index.md +++ b/docs/concepts/index.md @@ -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: users, canisters, anonymous calls, and canister control. ## Core capabilities diff --git a/docs/concepts/principals.md b/docs/concepts/principals.md new file mode 100644 index 0000000..f2d303d --- /dev/null +++ b/docs/concepts/principals.md @@ -0,0 +1,72 @@ +--- +title: "Principals" +description: "What principals are on ICP: the identity model, principal classes, canister control, and how authentication works" +--- + +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 + +There are four classes of principals on ICP: + +**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 `un4fu-tqaaa-aaaab-qadjq-cai` 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). + +A fifth class, **derived IDs**, was reserved in the specification but has never been 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. + +## Canister control + +Canisters are managed by their **controllers**: a list of principals (users, other canisters, or DAOs) that have permission to perform management operations on the canister. Controllers can: + +- Upgrade the canister's Wasm module. +- Change canister settings (compute allocation, memory allocation, freezing threshold). +- Start or stop the canister. +- Delete the canister and claim its remaining cycles. +- Add or remove other controllers. + +The control structure can take several forms: + +| Control structure | Who is the controller | Effect | +|---|---|---| +| Centralized | A single developer's principal | Full developer control; standard for development | +| Multi-signature | A multi-signer wallet like [Orbit](https://orbitwallet.io/) | Requires multiple keys to approve changes | +| DAO-governed | An SNS governance canister | Upgrades require a governance proposal | +| No controller | Empty controller list | Immutable canister; code can never be changed | + +When a canister has no controllers, it is **immutable**: no one can modify its code or settings. Users who want to trust that a canister's behavior will never change can verify this on the [ICP Dashboard](https://dashboard.internetcomputer.org). + +## Canister upgrades and stable memory + +When a controller upgrades a canister, the new Wasm module replaces the old one. By default, Wasm heap memory is cleared on upgrade because the new module may have a different memory layout. However, **stable memory is always preserved** across upgrades: it is explicitly managed by the canister (via system API calls) and designed to survive code changes. + +The runtime runs upgrade hooks atomically around the code swap: +1. `pre_upgrade` (or `system func preupgrade` in Motoko): save any heap data to stable memory. +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 the `pre_upgrade` hook 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. + +## Next steps + +- [Canisters](canisters.md): how canisters work, lifecycle, and message types +- [Authentication](../guides/authentication/index.md): integrating Internet Identity and other authentication providers +- [IC Interface Specification: Principals](../references/ic-interface-spec/index.md#principal): the formal specification + + diff --git a/docs/references/glossary.md b/docs/references/glossary.md index ff690ff..48f43bb 100644 --- a/docs/references/glossary.md +++ b/docs/references/glossary.md @@ -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 From f417c122f66dd7cc3fed4b1b2244c21ade1494df Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Wed, 6 May 2026 18:52:39 +0200 Subject: [PATCH 2/5] fix(concepts): correct principal example and broken auth link in principals.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace canister-format self-authenticating principal example with correct 29-byte user principal format - Fix broken Next steps link: authentication/index.md → authentication/internet-identity.md --- docs/concepts/principals.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/concepts/principals.md b/docs/concepts/principals.md index f2d303d..2bbde9d 100644 --- a/docs/concepts/principals.md +++ b/docs/concepts/principals.md @@ -13,7 +13,7 @@ There are four classes of principals on ICP: **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 `un4fu-tqaaa-aaaab-qadjq-cai` for Ed25519 keys or similar for ECDSA keys. The [Internet Identity](https://identity.ic0.app/) service manages key-backed identities for end users. +**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). @@ -66,7 +66,7 @@ If the `pre_upgrade` hook traps, the upgrade is aborted and the canister continu ## Next steps - [Canisters](canisters.md): how canisters work, lifecycle, and message types -- [Authentication](../guides/authentication/index.md): integrating Internet Identity and other authentication providers +- [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 From eac260b889a12f0e6d736f59284e9e6842ca7a58 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Sat, 9 May 2026 09:49:18 +0200 Subject: [PATCH 3/5] refactor(concepts): move canister control content from principals to canisters The controller table and upgrade hook sequence belong conceptually with canisters, not principals. principals.md is now focused on identity only (principal classes + caller semantics). canisters.md absorbs the control structure table and detailed upgrade steps from the Canister Control Learn Hub article. --- docs/concepts/canisters.md | 23 ++++++++++++++++++---- docs/concepts/index.md | 2 +- docs/concepts/principals.md | 38 +++---------------------------------- 3 files changed, 23 insertions(+), 40 deletions(-) diff --git a/docs/concepts/canisters.md b/docs/concepts/canisters.md index 706ab50..0e9e65b 100644 --- a/docs/concepts/canisters.md +++ b/docs/concepts/canisters.md @@ -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 @@ -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 | An SNS governance canister | Upgrades require a governance proposal voted on by token 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 @@ -127,9 +142,9 @@ This has a practical implication: if a canister modifies state and then makes an ## Next steps - [Cycles](cycles.md): how canisters pay for computation -- [Principals](principals.md): the identity model and canister controllers +- [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 - + diff --git a/docs/concepts/index.md b/docs/concepts/index.md index 3b495c3..df991bf 100644 --- a/docs/concepts/index.md +++ b/docs/concepts/index.md @@ -13,7 +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: users, canisters, anonymous calls, and canister control. +- **[Principals](principals.md)**: The identity model: who can call a canister, and how caller identity works. ## Core capabilities diff --git a/docs/concepts/principals.md b/docs/concepts/principals.md index 2bbde9d..92a1d76 100644 --- a/docs/concepts/principals.md +++ b/docs/concepts/principals.md @@ -1,6 +1,6 @@ --- title: "Principals" -description: "What principals are on ICP: the identity model, principal classes, canister control, and how authentication works" +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. @@ -31,42 +31,10 @@ 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. -## Canister control - -Canisters are managed by their **controllers**: a list of principals (users, other canisters, or DAOs) that have permission to perform management operations on the canister. Controllers can: - -- Upgrade the canister's Wasm module. -- Change canister settings (compute allocation, memory allocation, freezing threshold). -- Start or stop the canister. -- Delete the canister and claim its remaining cycles. -- Add or remove other controllers. - -The control structure can take several forms: - -| Control structure | Who is the controller | Effect | -|---|---|---| -| Centralized | A single developer's principal | Full developer control; standard for development | -| Multi-signature | A multi-signer wallet like [Orbit](https://orbitwallet.io/) | Requires multiple keys to approve changes | -| DAO-governed | An SNS governance canister | Upgrades require a governance proposal | -| No controller | Empty controller list | Immutable canister; code can never be changed | - -When a canister has no controllers, it is **immutable**: no one can modify its code or settings. Users who want to trust that a canister's behavior will never change can verify this on the [ICP Dashboard](https://dashboard.internetcomputer.org). - -## Canister upgrades and stable memory - -When a controller upgrades a canister, the new Wasm module replaces the old one. By default, Wasm heap memory is cleared on upgrade because the new module may have a different memory layout. However, **stable memory is always preserved** across upgrades: it is explicitly managed by the canister (via system API calls) and designed to survive code changes. - -The runtime runs upgrade hooks atomically around the code swap: -1. `pre_upgrade` (or `system func preupgrade` in Motoko): save any heap data to stable memory. -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 the `pre_upgrade` hook 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. - ## Next steps -- [Canisters](canisters.md): how canisters work, lifecycle, and message types +- [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 - + From 12d14ff27d7dd96fc9251c8a48ce659361abe0c4 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Sat, 9 May 2026 09:57:31 +0200 Subject: [PATCH 4/5] fix(concepts): use 'asset holders' instead of 'token holders' in controllers table --- docs/concepts/canisters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/canisters.md b/docs/concepts/canisters.md index 0e9e65b..f849baa 100644 --- a/docs/concepts/canisters.md +++ b/docs/concepts/canisters.md @@ -114,7 +114,7 @@ The control structure can take several forms: |---|---|---| | 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 | An SNS governance canister | Upgrades require a governance proposal voted on by token holders | +| SNS-governed | An 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). From b25f51f6c32444c7f27f940a54434d0f33f44143 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Sat, 9 May 2026 10:13:26 +0200 Subject: [PATCH 5/5] fix(concepts): address review feedback on principals and canisters pages - Add concepts/principals to sidebar.mjs - Reframe principal classes: 'five classes, one never implemented' - Expand SNS acronym on first use in canisters.md controllers table --- docs/concepts/canisters.md | 2 +- docs/concepts/principals.md | 4 ++-- sidebar.mjs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/concepts/canisters.md b/docs/concepts/canisters.md index f849baa..70a2bce 100644 --- a/docs/concepts/canisters.md +++ b/docs/concepts/canisters.md @@ -114,7 +114,7 @@ The control structure can take several forms: |---|---|---| | 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 | An SNS governance canister | Upgrades require a governance proposal voted on by asset holders | +| 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). diff --git a/docs/concepts/principals.md b/docs/concepts/principals.md index 92a1d76..940b681 100644 --- a/docs/concepts/principals.md +++ b/docs/concepts/principals.md @@ -7,7 +7,7 @@ A **principal** is any entity that can authenticate with the Internet Computer a ## Principal classes -There are four classes of principals on ICP: +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. @@ -17,7 +17,7 @@ There are four classes of principals on ICP: **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). -A fifth class, **derived IDs**, was reserved in the specification but has never been implemented. +**5. Derived IDs:** Reserved in the specification but never implemented. ## How principals are used in practice diff --git a/sidebar.mjs b/sidebar.mjs index afb9122..daf3ef7 100644 --- a/sidebar.mjs +++ b/sidebar.mjs @@ -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" },