diff --git a/ic-spec/assets/images/simplified-canister-workflow.svg b/ic-spec/assets/images/simplified-canister-workflow.svg
new file mode 100644
index 000000000..53c74ee80
--- /dev/null
+++ b/ic-spec/assets/images/simplified-canister-workflow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ic-spec/examples/certificates.cddl b/ic-spec/examples/certificates.cddl
new file mode 100644
index 000000000..dbcb6ad85
--- /dev/null
+++ b/ic-spec/examples/certificates.cddl
@@ -0,0 +1,31 @@
+certificate = tagged<{
+ tree : hash-tree
+ signature : signature
+ ? delegation : delegation
+}>
+
+hash-tree =
+ tree-empty /
+ tree-fork /
+ tree-labeled /
+ tree-leaf /
+ tree-pruned
+
+; Trees are represented as CBOR arrays instead of records with textual field
+; labels, for conciseness
+tree-empty = [ 0 ]
+tree-fork = [ 1 hash-tree hash-tree ]
+tree-labeled = [ 2 bytes hash-tree ]
+tree-leaf = [ 3 bytes ]
+tree-pruned = [ 4 hash ]
+
+delegation = {
+ subnet_id : bytes
+ certificate: bytes
+}
+
+tagged = #6.55799(t) ; the CBOR tag
+
+hash = bytes
+pubkey = bytes
+signature = bytes
diff --git a/ic-spec/examples/changelog.adoc b/ic-spec/examples/changelog.adoc
new file mode 100644
index 000000000..77e8bf1ea
--- /dev/null
+++ b/ic-spec/examples/changelog.adoc
@@ -0,0 +1,241 @@
+[#changelog]
+== Changelog
+
+[#unreleased]
+=== ∞ (unreleased)
+
+* Spec: The cleanup callback is introduced
+* Spec: Ingress rate limiting
+* Spec: Add ECDSA signatures on curve secp256k1
+
+[#0_15_1]
+=== 0.15.1 (2021-02-09)
+
+* The document is renamed to “Internet Computer Interface Spec”
+
+[#0_15_0]
+=== 0.15.0 (2020-12-17)
+
+* Spec: Support for raw Ed25519 keys is removed
+
+[#0_14_1]
+=== 0.14.1 (2020-12-08)
+
+* Spec: The default `memory_allocation` becomes unspecified
+
+[#0_14_0]
+=== 0.14.0 (2020-11-18)
+
+* Support for funds is scaled back to only support cycles
+* The `ic0.msg_cycles_accept` system call now returns the actually accepted
+ cycles
+* The `provisional_` management calls are introduced
+
+[#0_13_2]
+=== 0.13.2 (2020-11-12)
+
+* Spec: The `ic0.canister_status` system call
+
+[#0_13_1]
+=== 0.13.1 (2020-11-06)
+
+* Spec: Delegation between user public keys
+
+[#0_13_0]
+=== 0.13.0 (2020-10-19)
+
+* Spec: Certification (also removes “request-status” request)
+
+[#0_12_2]
+=== 0.12.2 (2020-10-23)
+
+* Spec: User authentication method based on WebAuthn is introduced
+* Spec: User authentication can use ECDSA
+* Spec: Public keys are DER-encoded
+
+[#0_12_1]
+=== 0.12.1 (2020-10-16)
+
+* Spec: Return more information in the `canister_status` management call
+
+[#0_12_0]
+=== 0.12.0 (2020-10-13)
+
+* Spec: Anonymous requests must have the sender field set
+
+[#0_11_1]
+=== 0.11.1 (2020-10-01)
+
+* Spec: The `deposit_funds` call
+* ic-ref(-test): Implement and test the above changes
+
+[#0_11_0]
+=== 0.11.0 (2020-09-23)
+
+* Spec: Inter-canister calls are now performed using a builder-like API
+* Spec: Support for funds (balances and transfers)
+
+[#v0_10_3]
+=== 0.10.3 (2020-09-21)
+
+* Spec: The anonymous user is introduced
+
+[#v0_10_2]
+=== 0.10.2 (2020-09-08)
+
+* ic-ref(-test): Bugfix: A query response should _not_ include a `time` field
+
+[#v0_10_1]
+=== 0.10.1 (2020-09-01)
+
+* Forward-port changes from 0.9.3
+
+[#v0_10_0]
+=== 0.10.0 (2020-08-06)
+
+* Spec: Users can set/update a memory allocation when installing/upgrading a canister.
+* Spec: The `expiry` field is added to requests
+* ic-ref(-test): Implement and test the above changes, as far as possible
+
+[#v0_9_3]
+=== 0.9.3 (2020-09-01)
+
+* Spec: The management canister supports the `raw_rand` method
+* ic-ref(-test): Implement and test the above changes
+
+[#v0_9_2]
+=== 0.9.2 (2020-08-05)
+
+* Spec: Canister controllers can stop/start canisters and can query their status.
+* Spec: Canister controllers can delete canisters
+* ic-ref(-test): Implement and test the above changes
+* ic-ref: refactorings
+
+[#v0_9_1]
+=== 0.9.1 (2020-07-20)
+
+* Forward-port changes from 0.8.2
+
+[#v0_9_0]
+=== 0.9.0 (2020-07-15)
+
+* Spec: Introduction of a domain separator (again)
+* Spec: The calculation of “derived ids” has changed
+* Spec: The self-authenticating and derived id forms use a truncated hash
+* Spec: The textual representation of principals has changed
+* ic-ref(-test): Implement the above changes
+* ic-ref-test: Also send read requests with nonces
+
+[#v0_8_2]
+=== 0.8.2 (2020-07-17)
+
+* ic-ref-test: Also send read requests with nonces
+* Spec: Installing code via `reinstall` works also on the empty canister
+* ic-ref(-test): Implement and test the above changes
+
+[#v0_8_1]
+=== 0.8.1 (2020-07-10)
+
+* Reflect refined process in README and intro.
+* Spec: `ic0.time` added
+* ic-ref(-test): Implement and test `ic0.time`
+
+[#v0_8_0]
+=== 0.8.0 (2020-06-23)
+
+* Spec: Revert the introduction of a domain separator
+* ic-ref(-test): Implement and test the above changes
+
+[#v0_6_2]
+=== 0.6.2 (2020-06-23)
+
+* Spec: Fix meaning-changing typos in `ic.did`
+* ic-ref-test: Be more liberal about the precise reject code in some cases.
+
+[#v0_6_0]
+=== 0.6.0 (2020-06-08)
+
+* Spec: Make all canister ids system-chosen
+* Spec: HTTP requests for management features are removed
+* ic-ref(-test): Implement and test the above changes
+
+[#v0_4_0]
+=== 0.4.0 (2020-05-25)
+
+* Spec (editorial): the term “principal” is now used for the _id_ of a canister or
+ user, not the canister or user itself
+* Spec: The signature of a request needs to be calculated using a domain separator
+* Spec: Describe the `controller` attribute, add a request to change it
+* Spec: The IC management canister is introduced
+* ic-ref(-test): Implement and test the above changes
+
+[#v0_2_16]
+=== 0.2.16 (2020-05-29)
+
+* More tests about calls from query methods
+
+[#v0_2_14]
+=== 0.2.14 (2020-05-14)
+
+* Spec: Bugfix: Mode should be `reinstall`, not `replace`
+* ic-ref-test: A few more tests, refactorings
+
+[#v0_2_12]
+=== 0.2.12 (2020-05-06)
+
+* ic-ref-test: Remove code to work around lack of creater canister.
+* ic-ref-test: Stricter tests for bad signatures
+* ic-ref: Also accept CBOR maps of indeterminate length
+
+[#v0_2_10]
+=== 0.2.10 (2020-04-29)
+
+* ic-ref: Bind to 127.0.0.1 instead of 0.0.0.0
+* ic-ref: Set content-type even for error responses
+* ic-ref-test: Tests related to query calls
+* ic-ref-test: Test “reply after trap in prior callback”
+
+[#v0_2_8]
+=== 0.2.8 (2020-04-23)
+
+* Spec: Include section with CDDL description
+* ic-ref-test: Block less tests on `create_canister` support
+
+[#v0_2_6]
+=== 0.2.6 (2020-04-01)
+
+* ic-ref-run: Accept any canister id in `install` commands
+* ic-ref-test: More defensive printing of HTTP bodies
+
+[#v0_2_4]
+=== 0.2.4 (2020-03-23)
+
+* simplify versioning (only three components), skip 0.2.2 to avoid confusion with 0.2.0.2
+* spec: Clarification: `reply` field is always present
+* spec: General cleanup based on front-to-back reading
+* ic-ref(-test): Enforce signature checking
+* ic-ref(-test): Desired canister ids must be derived from sender
+* ic-ref(-test): Require the 55799 semantic CBOR tag, as specified
+* ic-ref: Ignore duplicate requests
+* ic-ref-test: Run more tests independent of each other (try `-j 8`)
+* ic-ref-test: Submit requests with nonces
+* ic-ref-test: Test various trap conditions in reply and reject callbacks.
+* ic-ref-test: Test that `ic0.debug_print` with invalid bounds does _not_ trap
+* ic-ref-test: Allow unspecified fields to appear in the status response
+* ic-ref-test: Canister upgrade tests
+
+[#v0_2_0_2]
+=== 0.2.0.2 (2020-03-19)
+
+* ic-ref: Return status 202, empty body, on `submit`, to match spec
+* ic-ref: Allow update or inter-canister calls to query methods
+* ic-ref: Trap upon calls from queries
+* ic-ref-test: If the IC does not claim to be spec compliant, always succeed
+ (but still report errors)
+* ic-ref-test: Support --html reports
+* ic-ref-test: Use the “Universal Canister” to drive tests; more tests.
+
+[#v0_2_0_0]
+=== 0.2.0.0 (2020-03-11)
+
+* This is the first release. Subsequent releases will include a changelog.
diff --git a/ic-spec/examples/ic.did b/ic-spec/examples/ic.did
new file mode 100644
index 000000000..ed72e6176
--- /dev/null
+++ b/ic-spec/examples/ic.did
@@ -0,0 +1,34 @@
+type canister_id = principal;
+type user_id = principal;
+type wasm_module = blob;
+type unit = blob;
+service ic : {
+ create_canister : () -> (record {canister_id : canister_id});
+ install_code : (record {
+ mode : variant {install; reinstall; upgrade};
+ canister_id : canister_id;
+ wasm_module : wasm_module;
+ arg : blob;
+ compute_allocation : opt nat;
+ memory_allocation : opt nat;
+ }) -> ();
+ set_controller : (record {canister_id : canister_id; new_controller : principal}) -> ();
+ start_canister : (record {canister_id : canister_id}) -> ();
+ stop_canister : (record {canister_id : canister_id}) -> ();
+ canister_status : (record {canister_id : canister_id}) -> (record {
+ status : variant { running; stopping; stopped };
+ module_hash: opt blob;
+ controller: principal;
+ memory_size: nat;
+ cycles: nat;
+ });
+ delete_canister : (record {canister_id : canister_id}) -> ();
+ deposit_cycles : (record {canister_id : canister_id}) -> ();
+ raw_rand : () -> (blob);
+
+ // provisional interfaces for the pre-ledger world
+ provisional_create_canister_with_cycles :
+ (record { amount: opt nat }) -> (record {canister_id : canister_id});
+ provisional_top_up_canister :
+ (record { canister_id: canister_id; amount: nat }) -> ();
+}
diff --git a/ic-spec/examples/requests.cddl b/ic-spec/examples/requests.cddl
new file mode 100644
index 000000000..ff7a629a0
--- /dev/null
+++ b/ic-spec/examples/requests.cddl
@@ -0,0 +1,102 @@
+; The "root type" of the CDDL file is a hack: We want to define multiple
+; types in one file (to shared common definitions), but CDDL requires a single
+; root type. So we just list the types defined here. This is a common CDDL idiom.
+start =
+ async-request /
+ sync-request /
+ response
+
+; common wrappers
+
+tagged = #6.55799(t) ; the CBOR tag
+
+envelope = tagged<{
+ content: t
+ ? sender_pubkey: pubkey
+ ? sender_delegation: [*4 signed-delegation]
+ ? sender_sig: signature
+}>
+
+
+; A request as submitted to /api/v1/submit
+async-request = envelope
+async-content =
+ call-request
+
+call-request = {
+ request_type: "call"
+ ? nonce : bytes
+ ingress_expiry : timestamp
+ sender : principal
+ canister_id : principal
+ method_name : text
+ arg : bytes
+}
+
+; A request as submitted to /api/v1/read
+sync-request = envelope
+sync-content =
+ read-state-request /
+ query-request
+
+read-state-request = {
+ request_type: "read_state"
+ ? nonce : bytes
+ ingress_expiry : timestamp
+ sender : principal
+ paths: [* state-path]
+}
+
+state-path = [* path-label]
+path-label = bytes
+
+query-request = {
+ request_type: "query"
+ ? nonce : bytes
+ ingress_expiry : timestamp
+ sender : principal
+ canister_id : principal
+ method_name : text
+ arg : bytes
+}
+
+; The response, as returned from /api/v1/read
+
+response = tagged
+response-content =
+ read-state-response /
+ query-response
+
+read-state-response = {
+ certificate: bytes
+}
+
+query-response = {
+ status: "replied"
+ reply: call-reply
+ //
+ status: "rejected"
+ reject_code: unsigned
+ reject_message: text
+}
+
+call-reply = {
+ arg : bytes
+}
+
+signed-delegation = {
+ delegation: {
+ pubkey: bytes
+ expiration: timestamp
+ ? targets: [* principal]
+ }
+ signature: bytes
+}
+
+; some common data types
+
+principal = bytes .size (0..29)
+
+pubkey = bytes
+signature = bytes
+timestamp = unsigned
diff --git a/ic-spec/pages/about-the-spec.adoc b/ic-spec/pages/about-the-spec.adoc
new file mode 100644
index 000000000..5f36edda7
--- /dev/null
+++ b/ic-spec/pages/about-the-spec.adoc
@@ -0,0 +1,101 @@
+= About the Internet Computer Interface Specification
+:doctitle: Internet Computer Interface Specification
+
+As discussed in link:../developers-guide/concepts/what-is-IC{outfilesuffix}[What is the {IC}?], the {IC} runs on a large number of physical computers that work together in non-trivial ways, but appear to act as a single, shared, secure, and globally-accessible computer.
+
+The complexity that makes a large network of computers operate like a single computer is largely invisible to the developers who deploy their applications on the {IC} and to the end-users who access applications running on the {IC}.
+
+For most application developers and users,interacting with the {IC} doesn't require any access to low-level interfaces or any knowledge of the relationship between those interfaces.
+In most cases, developers build their applications using higher-level interfaces such as the link:../developers-guide/cli-reference/dfx-parent{outfilesuffix}[DFX command-line interface] or the link:../rust-guide/rust-intro{outfilesuffix}[Rust Canister Development Kit (CDK)].
+
+For developers interested in building tools for the {IC}—for example, to support canister development or user agents in new languages—the _{doctitle}_ describes the _external_ interfaces that the {IC} provides and the behavior to expect when using these interfaces.
+
+== Intended audience
+
+The _{doctitle}_ is intended for a technical audience with a need to understand the low-level operations and behavior for the {IC} external interfaces.
+
+Depending on your role and interests, you should consult the information in the {doctitle} if you want to:
+
+* use any of the low-level interfaces to implement agents, canister developments kits, emulators, or other {IC} tooling.
+
+* implement features that are described by the specification but not yet implemented in existing tooling, for example as a developer working on the {IC} project.
+
+* analyze the intricacies of the Internet Computer’s behavior in great detail, for example, as part of a security review or audit.
+
+== Scope of this document
+
+If you think of the Internet Computer as a distributed execution engine that provides a WebAssembly-based hosting service for applications, then this document describes exclusively the service hosting aspect of it.
+To the extent possible, this document does _not_ talk about block chains, consensus protocols, nodes, subnets, orthogonal persistence, or governance.
+
+This document also tries to be implementation-agnostic.
+It would apply just as well to a (hypothetical) compatible re-implementation of the Internet Computer.
+This implies that this document does not cover interfaces towards those running the Internet Computer (for example, data center operators, protocol developers, governance users), as topics like node updates, monitoring, logging are inherently tied to the actual _implementation_ and its architecture.
+
+== Documentation conventions and terminology
+
+For consistency, this document uses the following conventions for terminology:
+
+* _User_ denotes any external entity interacting with the {IC}.
++
+--
+
+* The term _user_ is used to avoid the more ambiguous term _client_. In most cases within the context of the {doctitle}, however, _user_ refers to code acting as an _agent_ on behalf of a person.
+
+* Canisters, users, and other entities are identified by a _principal_, sometimes also called an _id_.
+
+* _Users_ interact with the system by issuing _requests_ on the HTTPS interface.
+Requests have responses which can either be replies or rejects. Some requests cause internal messages to be created.
+
+--
+
+* The public entry points of canisters are called _methods_.
++
+--
+
+* Methods can be declared to be either _update methods_, in which state mutation is preserved, or _query methods_, in which state mutation is discarded and no further calls can be made.
+
+* Methods can be _called_, from _caller_ to _callee_.
+
+* Method calls eventually incur a _response_ which is either a _reply_ or a _reject_.
+
+* A method can have _parameters_, which are provided with concrete _arguments_ in a method call.
+
+* Internally, a call or a response is transmitted as a _message_ from a _sender_ to a _receiver_.
+Messages do not have a response.
+
+--
+
+* _Inter-canister calls_ describe calls from one canister to another or calls from a canister to itself
++
+--
+* Inter-canister calls can preserve state mutation.
+
+* Because inter-canister calls do not distinguish between update and query methods, all inter-canister calls are treated as update method calls.
+
+* External update calls can call update or query methods.
+
+* External query calls can _only_ call query methods.
+--
+
+* [[define-wasm-fn]]WebAssembly _functions_ are exported by the WebAssembly module or provided by the canister interface system API.
++
+--
+* WebAssembly functions are _invoked_.
+
+* WebAssembly functions can either _trap_ or _return_, possibly with a return value.
+
+* WebAssembly Functions can also have parameters and take arguments.
+--
+
+== Unspecified constants and limits
+
+This specification may refer to certain constants and limits without specifying their concrete value because the values are implementation defined.
+Many of these values are resource limits that are relevant only to specify the error-handling behavior of the system. This list is not complete.
+
+* `MAX_CYCLES_PER_MESSAGE`
++
+Amount of cycles that a canister has to have before a message is attempted to be executed, which is deducted from the canister balance before message execution. See link:index{outfilesuffix}#rule-message-execution[Message execution].
+
+* `MAX_CANISTER_BALANCE`
++
+Maximum canister cycle balance. Any excess is discarded. Less than 2^64^.
diff --git a/ic-spec/pages/index.adoc b/ic-spec/pages/index.adoc
new file mode 100644
index 000000000..c8249381f
--- /dev/null
+++ b/ic-spec/pages/index.adoc
@@ -0,0 +1,3520 @@
+= Internet Computer Interface Specification
+DFINITY Foundation
+∞ (unreleased)
+:stem: latexmath
+:icons: font
+
+Welcome to the Internet Computer! We speak of “the” Internet Computer, because although under the hood a large number of physical computers are working together in non-trivial ways, in the end we have the appearance of a single, shared, secure and world-wide accessible computer. Much, if not all, of the advanced and complex machinery is hidden from those that use the Internet Computer to run their applications and those who use these applications.
+
+This document is a rigorous, technically-dense reference.
+It is not an introduction to the Internet Computer, and as such most useful to those who understand the high-level concepts.
+For an introduction to the {IC} and high-level concepts, see the following before using this specification:
+
+* link:../developers-guide/concepts/what-is-IC{outfilesuffix}[What is the {IC}?]
+* link:url[Academy talks]
+
+== Internet Computer overview
+
+If you want to use the Internet Computer as an application developer, you first create a _canister module_ that contains the WebAssembly code and configuration for your application, and deploy it using the <>. You can create canisters using the Motoko language and the SDK, which is more convenient. If you want to use your own tooling, however, then this document describes <> and how the <>.
+
+Once your application is running on the Internet Computer, it is a _canister_, and users can interact with it. They can use the <> to interact with the canister according to the <>.
+
+The user can also use the HTTP interface to issue read-only queries, which are faster, but cannot change the state of a canister.
+
+.A typical use of the Internet Computer. (This is a simplified view; some of the arrows represent multiple interaction steps or polling.)
+
+[plantuml]
+....
+actor Developer
+actor User
+participant "Internet Computer" as IC
+participant "Canister 1" as Can1
+Developer -> IC : /submit create canister
+create Can1
+IC -> Can1 : create
+Developer <-- IC : canister-id=1
+Developer -> IC : /submit install module
+IC -> Can1 : initialize
+|||
+User -> IC : /submit call “hello”
+IC -> Can1 : hello
+return "Hello world!"
+User <-- IC : "Hello World!"
+....
+
+Sections “<>” and “<>” describe these interfaces, together with a brief description of what they do. Afterwards, you will find a <> of the Internet Computer that describes its abstract behavior with more rigor.
+
+=== Nomenclature
+
+To get some consistency in this document, we try to use the following terms with precision:
+
+We avoid the term “client”, as it could be the client of the Internet Computer or the client inside the distributed network that makes up the Internet Computer. Instead, we use the term _user_ to denote the external entity interacting with the internet computer, even if in most cases it will be some code (sometimes called “agent”) acting on behalf of a (human) user.
+
+The public entry points of canisters are called _methods_. Methods can be declared to be either _update methods_ (state mutation is preserved) or _query methods_ (state mutation is discarded, no further calls can be made).
+
+Methods can be _called_, from _caller_ to _callee_, and will eventually incur a _response_ which is either a _reply_ or a _reject_. A method may have _parameters_, which are provided with concrete _arguments_ in a method call.
+
+Inter-canister calls do not distinguish between update and query methods; inter-canister calls can preserve state mutation and are therefore akin to update method calls. Note that calls from a canister to itself also count as "inter-canister". External calls can be update calls, which can call both kinds of methods, and query calls, which can _only_ call query methods.
+
+Internally, a call or a response is transmitted as a _message_ from a _sender_ to a _receiver_. Messages do not have a response.
+
+[[define-wasm-fn]]WebAssembly _functions_ are exported by the WebAssembly module or provided by the System API. These are _invoked_ and can either _trap_ or _return_, possibly with a return value. Functions, too, have parameters and take arguments.
+
+External _users_ interact with the system by issuing _requests_ on the HTTPS interface. Requests have responses which can either be replies or rejects. Some requests cause internal messages to be created.
+
+Canisters, users, etc. are identified by a _principal_, sometimes also called an _id_.
+
+== Unspecified constants and limits
+
+This specification may refer to certain constants and limits without specifying their concrete value (yet), i.e. they are implementation defined. Many are resource limits which are relevant only to specify the error-handling behaviour of the system (which, as mentioned above, is also not yet precisely described in this document). This list is not complete.
+
+* `MAX_CYCLES_PER_MESSAGE`
++
+Amount of cycles that a canister has to have before a message is attempted to be executed, which is deducted from the canister balance before message execution. See <>.
+
+* `MAX_CANISTER_BALANCE`
++
+Maximum canister cycle balance. Any excess is discarded. Less than 2^64^.
+
+== Principals
+
+Principals, like canister, user and subnet ids, are – as far as most uses of the system are concerned – binary blobs with a length between 0 and 29 bytes. There is, however, some structure to them to encode specific authentication and authorization behavior.
+
+
+
+[#id-classes]
+=== Special forms of IDs
+
+In this section, `H` denotes SHA-224, `·` denotes blob concatenation and `|p|` denotes the length of `p` in bytes, encoded as a single byte.
+
+There are several classes of ids:
+
+1. _Opaque ids_.
++
+These are always generated by the system and have no structure of interest outside the system.
++
+NOTE: Typically, these end with the byte `0x01`, but users of the IC should not need to care about that.
+
+2. _Self-authenticating ids_.
++
+These have the form `H(public_key) · 0x02` (29 bytes).
++
+An external user can use these ids as the `sender` of a request if they own the corresponding private key.
+The public key uses one of the encodings described in <>.
+
+3. _Derived ids_
++
+These have the form `H(|registering_principal| · registering_principal · derivation_nonce) · 0x03` (29 bytes).
++
+These ids are treated specially when an id needs to be registered. In such a request, whoever requests an id can provide a `derivation_nonce`. By hashing that together with the principal of the caller, every principal has a space of ids that only they can register ids from.
++
+NOTE: Derived IDs are currently not explicitly used in this document, but they may be used internally or in the future.
+
+4. _Anonymous id_
++
+This has the form `0x04`, and is used for the anonymous caller. It can be used in call and query requests without a signature.
+
+When the system creates a _fresh_ id, it never creates a self-authenticating id, an anonymous id or an id derived from what could be a canister or user.
+
+
+[#textual-ids]
+=== Textual representation of principals
+
+NOTE: This textual representation does not actually show up in the interface (which always deals with blobs), so it is merely a recommended convention.
+
+We specify a _canonical textual format_ that is recommended whenever principals need to be printed or read in textual format, e.g. in log messages, transactions browser, command line tools, source code.
+
+The textual representation of a blob `b` is `Grouped(Base32(CRC32(b) · b))` where
+
+ * `CRC32` is a four byte check sequence, calculated as defined by ISO 3309, ITU-T V.42 and https://www.w3.org/TR/2003/REC-PNG-20031110/#5CRC-algorithm[elsewhere]
+ * `Base32` is the Base32 encoding as defined in https://tools.ietf.org/html/rfc4648#section-6[RFC 4648], with no padding character added.
+ * The middle dot denotes concatenation.
+ * `Grouped` takes an ASCII string and inserts the separator `-` (dash) every 5 characters. The last group may contain less than 5 characters. A separator never appears at the beginning or end.
+
+The textual representation is conventionally printed with _lower case letters_, but parsed case-insensitively.
+
+Because the maximum size of a principal is 29 bytes, the textual representation will be no longer than 63 characters (10 times 5 plus 3 characters with 10 separators in between them).
+
+[TIP]
+=====
+The canister with id `0xABCD01` has check sequence `0x233FF206` (https://crccalc.com/?crc=ABCD01&method=crc32&datatype=hex&outtype=hex[online calculator]); the final id is thus `em77e-bvlzu-aq`.
+
+Example encoding from hex, and decoding to hex, in bash (the following can be pasted into a terminal as it):
+....
+function textual_encode() {
+ ( echo "$1" | xxd -r -p | /usr/bin/crc32 /dev/stdin; echo -n "$1" ) |
+ xxd -r -p | base32 | tr A-Z a-z |
+ tr -d = | fold -w5 | paste -sd'-' -
+}
+
+function textual_decode() {
+ echo -n "$1" | tr -d - | tr a-z A-Z |
+ fold -w 8 | xargs -n1 printf '%-8s' | tr ' ' = |
+ base32 -d | xxd -p | tr -d '\n' | cut -b9- | tr a-z A-Z
+}
+....
+=====
+
+[#signatures]
+== Signatures
+
+Digital signature schemes are used for authenticating messages in various parts of the IC infrastructure.
+Signatures are domain separated, which means that every message is prefixed with a byte string that is unique to the purpose of the signature.
+The IC supports plain signatures as well as signatures generated via web authentication.
+
+- Plain signatures are supported for the schemes
++
+ * https://ed25519.cr.yp.to/index.html[*Ed25519*] or
+ * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf[*ECDSA*] on curve P-256 (also known as `secp256r1`), using SHA-256 as hash function, as well as on the Koblitz curve `secp256k1`.
++
+The signature is calculated by signing the concatenation of the domain separator and the message.
++
+ * Public keys must be valid for signature schemes Ed25519 or ECDSA and are encoded as DER.
+ - See https://tools.ietf.org/html/rfc8410[RFC 8410] for DER encoding of Ed25519 public keys.
+ - See https://tools.ietf.org/rfc/rfc5480[RFC 5480] for DER encoding of ECDSA public keys; the DER encoding must not specify a hash function.
+ For curve `secp256k1`, the OID 1.3.132.0.10 is used.
+ The points must be specified in uncompressed form (i.e. `0x04` followed by the big-endian 32byte encodings of `x` and `y`).
+ * The signatures are encoded as the concatenation of the 32 byte big endian encodings of the two values _r_ and _s_.
+
+- The only allowed signature scheme for web authentication is
++
+ * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf[*ECDSA*] on curve P-256 (also known as `secp256r1`), using SHA-256 as hash function.
++
+The signature is calculated by using the concatenation of the domain separator and the message as the challenge in the web authentication assertion.
++
+The signature is checked by verifying that the `challenge` field contains the https://tools.ietf.org/html/rfc4648#section-5[base64url encoding] of the concatenation of the domain separator and the message, and that `signature` verifies on `authenticatorData · SHA-256(utf8(clientDataJSON))`, as specified in the https://www.w3.org/TR/webauthn/#op-get-assertion[WebAuthn w3c recommendation].
++
+ * The public key is encoded as DER-wrapped COSE key as detailed below.
+ * The signature is a CBOR encoding of a map with three mandatory fields:
+ - `authenticator_data` (`blob`): WebAuthn authenticator data.
+ - `client_data_json` (`text`): WebAuthn client data in JSON representation.
+ - `signature` (`blob`): Signature as specified in the https://www.w3.org/TR/webauthn/#signature-attestation-types[WebAuthn w3c recommendation], which means DER encoding in the case of an ECDSA signature.
+
+[#oid-der-wrapped-cose]
+
+The DER-wrapped COSE format uses the `SubjectPublicKeyInfo` type used for other types of public keys (see, e.g., https://tools.ietf.org/html/rfc8410#section-4[RFC 8410, Section 4]), with OID 1.3.6.1.4.1.56387.1.1 (iso.org.dod.internet.private.enterprise.dfinity.mechanisms.der-wrapped-cose). The `BIT STRING` field `subjectPublicKey` contains the COSE encoding.
+See https://www.w3.org/TR/webauthn/#sctn-encoded-credPubKey-examples[WebAuthn w3c recommendation] or https://tools.ietf.org/html/rfc8152#section-13.1[RFC 8152] for details on the COSE encoding.
+
+[TIP]
+====
+A DER wrapping of a COSE key is shown below. It can be parsed via the command `sed "s/#.*//" | xxd -r -p | openssl asn1parse -inform der`.
+....
+30 5E # SEQUENCE of length 94 bytes
+ 30 0C # SEQUENCE of length 12 bytes
+ 06 0A 2B 06 01 04 01 83 B8 43 01 01 # OID 1.3.6.1.4.1.56387.1.1
+ 03 4E 00 # BIT STRING encoding of length 78,
+ A501 0203 2620 0121 5820 7FFD 8363 2072 # length is at byte boundary
+ FD1B FEAF 3FBA A431 46E0 EF95 C3F5 5E39 # contents is a valid COSE key
+ 94A4 1BBF 2B51 74D7 71DA 2258 2032 497E # with ECDSA on curve P-256
+ ED0A 7F6F 0009 2876 5B83 1816 2CFD 80A9
+ 4E52 5A6A 368C 2363 063D 04E6 ED
+....
+The same, on https://lapo.it/asn1js/#MF4wDAYKKwYBBAGDuEMBAQNOAKUBAgMmIAEhWCB__YNjIHL9G_6vP7qkMUbg75XD9V45lKQbvytRdNdx2iJYIDJJfu0Kf28ACSh2W4MYFiz9gKlOUlpqNowjYwY9BObt[in an online ASN.1 JavaScript decoder].
+====
+
+[#state-tree]
+== The system state tree
+
+Parts of the system state are publicly exposed (e.g. via <> or, eventually, certified variables) in a verified way (see <> for the machinery for certifying). This section describes the content of the system state abstractly.
+
+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, where the domain is prefix-free.
+
+Labels are always blobs (but often with an human readable representation). In this document, paths are written suggestively with slashes as separators; the actual encoding is not actually using slashes as delimitors, and labels may contain the 0x2F byte (ASCII `/`) just fine. Values are either natural numbers, text values or blob values.
+
+This section specifies the publicly relevant paths in the tree.
+
+[#state-tree-time]
+=== Certification time
+
+* `/time` (natural):
++
+All certificate trees include a timestamp, indicating the time at which the state tree is current.
+
+[#state-tree-subnet]
+=== Subnet information
+
+The state tree contains information about the topology of the Internet Computer.
+
+* `/subnet//public_key` (blob)
++
+The public key of the subnet (a DER-encoded BLS key, see <>)
+
+[#state-tree-request-status]
+=== Request status
+
+For each asynchronous request known to the system, its status is in a subtree at `/request_status/`. Please see <> for more details on how asynchronous requests work.
+
+* `/request_status//status` (text)
++
+One of `received`, `processing`, `replied`, `rejected` or `done`, see <> for more details on what each status means.
+
+* `/request_status//reply` (blob)
++
+If the status is `replied`, then this path contains the reply blob, else it is not present.
+
+* `/request_status//reject_code` (natural)
++
+If the status is `rejected`, then this path contains the reject code (see <>), else it is not present.
+
+* `/request_status//reject_message` (text)
++
+If the status is `rejected`, then this path contains a textual diagnostic message, else it is not present.
+
+NOTE: Immediately after submitting a request, the request may not show up yet as the system is still working on accepting the request as pending.
+
+NOTE: Request statuses will not actually be kept around indefinitely, and eventually the system forgets about the request. This will happen no sooner than the request’s expiry time, so that replay attacks are prevented, but likely longer, so that users have a chance to fetch it. The precise policy is not yet defined.
+
+[#state-tree-certified-data]
+=== Certified data
+
+* `/canister//certified_data` (blob):
++
+The certified data of the canister with the given id, see <>.
+
+[#http-interface]
+== HTTPS Interface
+
+The concrete mechanism that users use to send requests to the Internet Computer is via an HTTPS API, which exposes two endpoints to handle the requests, plus one for diagnostics.
+
+[#async-requests]
+=== Asynchronous requests
+
+Certain interactions change the state of the Internet Computer. By the very nature of a distributed implementation, they cannot be acted upon immediately, but only with a delay. Moreover, the actual node that the user talks to may not be honest or, for other reasons, may fail to get the request on the way. This implies the following high-level workflow:
+
+1. A user submits a request via the <>. No useful information is returned from the node (as it would not be trustworthy anyways).
+2. For a certain amount of time, the system behaves as if it does not know about the request. (Although as part of the HTTP interface the receiving endpoint gives an untrusted acknowledgment of receipt or an untrusted declination of the request.)
+3. At some point, the system may accept the request for processing and set its status to `received`. This indicates that the system as a whole has received the request and plans on processing it (although it may still not get processed if the system is under high load). Further, the user should also be able to ask any endpoint (for the canister) about the status of the pending request.
+4. Once it is clear that the request will be acted upon (sufficient resources, request not yet expired), the status changes to `processing`. Now the user has the guarantee that the request will have an effect (e.g. in the case of a canister call, that it will reach the canister).
+5. Now the system is processing the request. For some requests this may be atomic, for others this involves multiple internal steps.
+6. Eventually, a response will be produced, and can be retrieved for a certain amount of time. The response is either a `reply`, indicating success, or a `reject`, indicating some form of error.
+7. In the case that the response has been retained for long enough, but the request has not expired yet, the system can forget the response data and only remember the request as `done`, to prevent a replay.
+8. Once the expiry time is past, the system can prune the request and its response, and completely forget about it.
+
+
+This yields the following interaction diagram:
+
+[plantuml]
+....
+(*) --> "User creates request" #DDDDDD
+ --> "Submitted to node\n(with 202 response)" as submit #DDDDDD
+ --> "received"
+ --> "processing"
+if "" as X then
+ --> "replied"
+ --> "done"
+ else
+ --> "rejected (canister)"
+ --> "done"
+
+ "X" --> "rejected (system)"
+ "received" --> "rejected (system)"
+ --> "done"
+
+ "received" --> "pruned" #DDDDDD
+ "submit" --> "dropped" #DDDDDD
+ "done" --> "pruned" #DDDDDD
+
+endif
+....
+
+State transitions may be instantaneous and not always externally visible. For example, the system may move from `Received` via `Processing` to `Replied` in one go. Similarly, the system may not implement the `Done` state at all, and keep requests in the previous state until they are dropped.
+
+All gray states are _not_ explicitly represented in the system state, and are indistinguishable from “request does not exist”.
+
+The characteristic property of the `Received` state is that the request has made it past the (potentionally malicious) endpoint _into to the system_. It is now pointless (but harmless) to submit the (identical) request again. Before reaching that state, submitting the identical request to further nodes might be a useful safeguard against a malicious or misbehaving node.
+
+The characteristic property of the `Processing` state is _the initial effect of the request has or will happen_. This is best explained by an example: Consider a counter canister. It exports a method `inc` that increases the counter. Assume that the canister is bug free, and is not going to be forcibly removed. A user submits a request to call `inc`. If the user sees request status `Processing`, the state change is guaranteed to happen, and the user can stop monitoring the status and does not have to retry submitting.
+
+A request may be rejected by the system or the canister. In either case, there is no guarantee about how much processing of the request has happened.
+
+To avoid replay attacks, the transition from `done` or `received` to `pruned` must happen no earlier than the request’s `ingress_expiry` field.
+
+Requests must stay in `Replied` or `Rejected` long enough for polling clients to catch the response.
+
+When asking the system about the state or response of a request, the user uses the request id (see <>) to read the request status (see <>) from the state tree (see <>).
+
+=== Synchronous requests
+
+Other interactions do not change the state of the system, but only _read_ from it. These may either be untrustworthy, in the sense that a malicious node can make up stuff (e.g. query calls to canisters), or certified, in the sense that the node can prove to the user that this is indeed the system's view of things (e.g. reading request statuses, reading account balances). All these reads go through the `read` endpoint.
+
+We use the term _request_ both for the asynchronous requests that passed to `submit`, as well as for the parameters of a _read_, so that common operations like signing can be done in the same way.
+
+
+[#api-endpoints]
+=== Request Endpoints
+
+NOTE: This document does not yet explain how to find the location and port of a running Internet Computer Node, nor how to find out which node(s) to talk to for a given canister.
+
+The following API endpoints are provided:
+....
+/api/v1/submit
+/api/v1/read
+....
+
+For these endpoints, the user performs a POST request over HTTPS with `Content-type: application/cbor`. The body is a CBOR value containing the request object.
+
+* The `/api/v1/submit` endpoint accepts the _asynchronous_ requests. Upon successful submission, a (code 202) HTTP response without a body is returned; the user can read the state tree (see <>) to determine the response.
+* The `/api/v1/read` endpoint accepts the _synchronous_ requests. It returns a response (a CBOR value) as the body of the (code 200) HTTP response.
+
+In both cases, the usual HTTP errors (e.g. 503) may occur. In particular, if the server can determine already that the request is invalid (e.g. too large, wrong or missing fields, invalid signatures) and has no chance to reach the `received` state, it can respond with a suitable 4xx code (e.g. 413 if the request is too large).
+
+[#field-types]
+=== Field types
+
+The requests supported by the system are expressed as records, i.e. fields with names and values. The fields are typed and can have one of these types:
+
+* `nat`: A (possibly unbounded) natural number (non-negative integer, zero is permitted)
+* `text`: Human readable text (e.g. sequence of Unicode codepoints)
+* `blob`: Arbitrary binary data
+* sequences (i.e. arrays, lists) of values
+
+For readability, we use the following type synonyms:
+....
+type Principal = blob
+type CanisterId = Principal
+type UserId = Principal
+....
+
+NOTE: Of course, user ids and canister ids are _not_ just arbitrary binary blobs, but have structure. Some of that structure is documented in <>. But since that structure is meant to be extensible without breaking existing code (especially running canisters), the interfaces are phrased in terms of arbitrary blobs.
+
+All requests coming in via the HTTP interface need to be _authenticated_ using a cryptographic signature. To that end, the following fields are added to these requests:
+
+The following fields are common among all requests:
+
+* `request_type` (`text`): Indicates the type of request, and is one of the values specified in <>.
+* The fields `nonce` and `ingress_expiry`, as specified in <>.
+
+[#authentication]
+=== Authentication
+
+All requests coming in via the HTTP interface need to be either _anonymous_ or _authenticated_ using a cryptographic signature. To that end, the following fields are added to all request records (next to `request_type`):
+
+* `nonce` (`blob`, optional): Arbitrary user-provided data, typically randomly generated. This can be used to create distinct requests with otherwise identical fields.
+* `ingress_expiry` (`nat`, required): An upper limit on the validity of the request, expressed in nanoseconds since 1970-01-01 (like <>). This avoids replay attacks: The system will not accept requests, or transition requests from status `received` to status `processing`, if their expiry date is in the past. The system may refuse to accept requests with an ingress expiry date too far in the future. This applies to synchronous and asynchronous requests alike (and could have been called `signature_expiry`).
+* `sender` (`Principal`, required): The user who issued the request.
+
+Furthermore, the whole request record is wrapped in a envelope record with these fields:
+
+* `content` (`record`): the actual request content
+* `sender_pubkey` (`blob`, optional): Public key used to authenticate this request. Since a user may in the future have more than one key, this field tells the system which key is used.
+* `sender_delegation` (`array` of maps, optional): a chain of delegations, starting with the one signed by `sender_pubkey` and ending with the one delegating to the key relating to `sender_sig`.
+* `sender_sig` (`blob`, optional): Signature to authenticate this request.
+
+The public key must authenticate the `sender` principal:
+
+* A public key can authenticate a principal if the latter is a self-authenticating id derived from that public key (see <>).
+* The fields `sender_pubkey`, `sender_sig`, and `sender_delegation` must be omitted if the `sender` field is the anonymous principal.
+ The fields `sender_pubkey` and `sender_sig` must be set if the `sender` field is not the anonymous principal.
+
+The request id (see <>) is calculated from the content record. This allows the signature to be based on the request id, and implies that signature and public key are not semantically relevant.
+
+The field `sender_pubkey` contains a public key supported by one of the schemes described in <>.
+
+Signing transactions can be delegated from a one key to another one.
+If delegation is used, then the `sender_delegation` field contains an array of delegations, each of which is a map with the following fields:
+
+ * `delegation` (`map`): Map with fields:
+ - `pubkey` (`blob`): Public key as described in <>.
+ - `expiration` (`nat`): Expiration of the delegation, in nanoseconds since 1970-01-01, analogously to the `ingress_expiry` field above.
+ - `targets` (`array` of `CanisterId`, optional): If this field is set, the delegation only applies for requests sent to the canisters in the list.
+ * `signature` (`blob`): Signature on the 32-byte <> of the map contained in the `delegation` field as described in <>, using the 27 bytes `\x1Aic-request-auth-delegation` as the the domain separator.
++
+For the first delegation in the array, this signature is created with the key corresponding to the public key from the `sender_pubkey` field, all subsequent delegations are signed with the key corresponding to the public key contained in the preceding delegation.
+
+The `sender_sig` field is calculated by signing the concatenation of the 11 bytes `\x0Aic-request` (the domain separator) and the 32 byte <> with the secret key that belongs to the key specified in the last delegation or, if no delegations are present, the public key specified in `sender_pubkey`.
+
+The delegation field, if present, must not contain more than four delegations.
+
+[#request-types]
+=== Request types
+
+The following subsections list all supported requests.
+
+[#api-update]
+==== Canister update call
+
+The maybe most important request type is calling an exported method of a canister.
+
+Synchronicity:: asynchronous
+Request type:: `call`
+Request fields::
+* `canister_id` (`CanisterId`): The id of the canister to call.
+* `method_name` (`text`): Name of the canister method to call
+* `arg` (`blob`): Argument to pass to the canister method
+Response fields::
+None, the server returns no body and HTTP status 202 (or an HTTP error code if declining the request).
+
+This request type can _also_ be used to call a query method. A user may choose to go this way, instead of via the likely faster and cheaper <> below, if they want to get a _certified_ response.
+
+The response will be represented in the state tree, as described in <>, and can be read using <>.
+
+NOTE: The system functionality exposed via the <> can be used this way.
+
+[#api-request-read-state]
+==== State tree reads
+
+Synchronicity:: synchronous
+Request type:: `read_state`
+Request fields::
+* `paths` (sequence of paths): A list of paths, where a path is itself a sequence of blobs.
+Response fields::
+* `certificate` (`blob`): A certificate (see <>).
+
+The returned certificate reveals all values whose path is a suffix of the list of requested paths. It also always reveals `/time`, even if not explicitly requested.
+
+All requested paths must have one of the following paths as prefix:
+
+ * `/time`. Can be requested by anyone.
+ * `/subnet`. Can be requested by anyone.
+ * `/request_status/`. Can only be read if `/request_id/` is not present in the state tree, or if this `read_state` request was signed by same sender as the original request referenced by ``.
+
+Note that the paths `/canisters//certified_data` are not accessible with this method; these paths are only exposed to the canister themselves via the System API (see <>).
+
+See <> for details on the state tree.
+
+[#api-query]
+==== Canister query call
+
+Canister methods that do not change the canister state can be executed more efficiently. This method provides that ability, and returns the canister’s response directly within the HTTP response.
+
+Synchronicity:: synchronous
+Request type:: `query`
+Request fields::
+* `canister_id` (`CanisterId`): The id of the canister to query.
+* `method_name` (`text`): Name of the canister query method to call
+* `arg` (`blob`): Argument to pass to the canister method
+Response fields::
+* `status` (`text`): One of `replied` or `rejected`
+* `reply`: If the status is `replied`, then this member contains the call reply, just as specified in <>.
+* `reject_code` (`nat`): If the status is `rejected`, then this member contains the reject code (see <>).
+* `reject_message` (`text`): If the status is `rejected`, then this member contains a textual diagnostic message.
+
+[#api-hash-of-map]
+=== Representation-independent hashing of structured data
+
+Structured data, such as (recursive) maps, are authenticated by signing a representation-independent hash of the data.
+This hash is computed as follows (using SHA256 in the steps below):
+
+1. For each field that is present in the map (i.e. omitted optional fields are indeed omitted):
+ * concatenate the hash of the field's name (in ascii-encoding, without terminal `\x00`) and the hash of the value (with the encoding specified below).
+2. Sort these concatenations from low to high
+3. Concatenate the sorted elements, and hash the result.
+
+The resulting hash of 256 bits (32 bytes) is the representation-independent hash.
+
+The following encodings of field values as blobs are used
+
+* Binary blobs (`canister_id`, `arg`, `nonce`, `module`) are used as-is.
+* Strings (`request_type`, `method_name`) are encoded in UTF-8, without a terminal `\x00`.
+* Natural numbers (`compute_allocation`, `memory_allocation`, `ingress_expiry`) are encoded using the shortest form https://en.wikipedia.org/wiki/LEB128#Unsigned_LEB128[Unsigned LEB128] encoding.
+ For example, `0` should be encoded as a single zero byte `[0x00]` and `624485` should be encoded as byte sequence `[0xE5, 0x8E, 0x26]`.
+* Arrays (`paths`) are encoded as the concatenation of the hashes of the encodings of the array elements.
+* Maps (`sender_delegation`) are encoded by recursively computing the representation-independent hash.
+
+[#api-request-id]
+=== Request ids
+
+When querying the status of a request (see <>) in the state tree, the user identifies the request using a _request id_, which is an object hash of the request's `content`, calculated using the following steps. The hash operation is always SHA-256.
+
+The request id is computed as the <> of `content`.
+
+NOTE: The request id is independent of the representation of the request (JSON, CBOR, something else), and does not change if the specification adds further optional field to a request type.
+
+NOTE: The recommended textual representation of a request id is a hexadecimal string with lower-case letters prefixed with '0x'.
+E.g., request id consisting of bytes `[00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 0A, 0B, 0C, 0D, 0E, 0F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 1C, 1D, 1E, 1F]` should be displayed as `0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f`.
+
+[TIP]
+====
+Example calculation (where `H` denotes SHA-256 and `·` denotes blob concatenation):
+
+[source,,options="nowrap"]
+----
+hash_of_map({ request_type: "call", canister_id: 0x00000000000004D2, method_name: "hello", arg: "DIDL\x00\xFD*"})
+ = H(concat (sort
+ [ H("request_type") · H("call")
+ , H("canister_id") · H("\x00\x00\x00\x00\x00\x00\x04\xD2")
+ , H("method_name") · H("hello")
+ , H("arg") · H("DIDL\x00\xFD*")
+ ]))
+ = H(concat (sort
+ [ 769e6f87bdda39c859642b74ce9763cdd37cb1cd672733e8c54efaa33ab78af9 · 7edb360f06acaef2cc80dba16cf563f199d347db4443da04da0c8173e3f9e4ed
+ , 0a3eb2ba16702a387e6321066dd952db7a31f9b5cc92981e0a92dd56802d3df9 · 4d8c47c3c1c837964011441882d745f7e92d10a40cef0520447c63029eafe396
+ , 293536232cf9231c86002f4ee293176a0179c002daa9fc24be9bb51acdd642b6 · 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
+ , b25f03dedd69be07f356a06fe35c1b0ddc0de77dcd9066c4be0c6bbde14b23ff · 6c0b2ae49718f6995c02ac5700c9c789d7b7862a0d53e6d40a73f1fcd2f70189
+ ]))
+ = H(concat
+ [ 0a3eb2ba16702a387e6321066dd952db7a31f9b5cc92981e0a92dd56802d3df9 · 4d8c47c3c1c837964011441882d745f7e92d10a40cef0520447c63029eafe396
+ , 293536232cf9231c86002f4ee293176a0179c002daa9fc24be9bb51acdd642b6 · 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
+ , 769e6f87bdda39c859642b74ce9763cdd37cb1cd672733e8c54efaa33ab78af9 · 7edb360f06acaef2cc80dba16cf563f199d347db4443da04da0c8173e3f9e4ed
+ , b25f03dedd69be07f356a06fe35c1b0ddc0de77dcd9066c4be0c6bbde14b23ff · 6c0b2ae49718f6995c02ac5700c9c789d7b7862a0d53e6d40a73f1fcd2f70189
+ ])
+ = 8781291c347db32a9d8c10eb62b710fce5a93be676474c42babc74c51858f94b
+----
+====
+
+[#reject-codes]
+=== Reject codes
+
+An API request or inter-canister call that is pending in the system will eventually result in either a _reply_ (indicating success, and carrying data) or a _reject_ (indicating an error of some sorts). A reject contains a _rejection code_ that classifies the error and a hopefully helpful _reject message_ string.
+
+Rejection codes are member of the following enumeration:
+
+* `SYS_FATAL` (1): Fatal system error, retry unlikely to be useful.
+* `SYS_TRANSIENT` (2): Transient system error, retry might be possible.
+* `DESTINATION_INVALID` (3): Invalid destination (e.g. canister/account does not exist)
+* `CANISTER_REJECT` (4): Explicit reject by the canister.
+* [[CANISTER_ERROR]]`CANISTER_ERROR` (5): Canister error (e.g., trap, no response)
+
+The symbolic names of this enumeration are used throughout this specification, but on all interfaces (HTTPS API, System API), they are represented as positive numbers as given in the list above.
+
+The error message is guaranteed to be a string, i.e. not arbitrary binary data.
+
+When canisters explicitly reject a message (see <>), they can specify the reject message, but _not_ the reject code; it is always `CANISTER_REJECT`. In this sense, the reject code is trustworthy: If the system responds with a `SYS_FATAL` reject, then it really was the system issuing this reject.
+
+[#api-status]
+=== Status endpoint
+
+Additionally, the Internet Computer provides an API endpoint to obtain various status fields at
+....
+/api/v1/status
+....
+
+For this endpoint, the user performs a GET request, and receives a CBOR value with the following fields. The Internet Computer may include additional implementation-specific fields.
+
+* `ic_api_version` (string, mandatory): Identifies the interface version supported, i.e. the version of the present document that the internet computer aims to support, e.g. `0.8.1`. The implementation may also return `unversioned` to indicate that it does _not_ comply to a particular version, e.g. in between releases.
+* `impl_source` (string, optional): Identifies the implementation of the Internet Computer, by convention with the canonical location of the source code (e.g. `https://github.com/dfinity/dfinity`).
+* `impl_version` (string, optional): If the user is talking to a released version of an Internet Computer implementation, this is the version number. For non-released versions, output of `git describe` like `0.1.13-13-g2414721` would also be very suitable.
+* `impl_revision` (string, optional): The precise git revision of the Internet Computer implementation
+* `root_key` (blob, only in development instances): The public key (a DER-encoded BLS key) of the root key of this Internet Computer instance. This _must_ be present in short-lived development instances, to allow the client to fetch the public key. In production environments, clients must have an independent trustworthy source for this data, and must not be tempted to fetch it from this insecure location.
+
+See <> for details on the precise CBOR encoding of this object.
+
+NOTE: Future additions may include local time, geographic location, and other
+useful implementation-specific information such as blockheight. This data may
+possibly signed by the node.
+
+[#api-cbor]
+=== CBOR encoding of requests and responses
+
+Requests and responses are specified here as records with named fields and using suggestive human readable syntax. The actual format in the body of the HTTP request or response, however, is https://en.wikipedia.org/wiki/CBOR[CBOR].
+
+Concretely, it consists of a data item with major type 6 (“Semantic tag”) and tag value `55799` (see https://tools.ietf.org/html/rfc7049#section-2.4.5[Self-Describe CBOR]), followed by a record.
+
+Requests consist of an envelope record with keys `sender_sig` (a blob), `sender_pubkey` (a blob) and `content` (a record). The first two are metadata that are used for request authentication, while the last one is the actual content of the request.
+
+The following encodings are used:
+
+* Strings: Major type 3 (“Text string”).
+* Blobs: Major type 2 (“Byte string”).
+* Nats: Major type 0 (“Unsigned integer”) if small enough to fit that type, else the https://tools.ietf.org/html/rfc7049#section-2.4.2[Bignum] format is used.
+* Records: Major type 5 (“Map of pairs of data items”), followed by the fields, where keys are encoded with major type 3 (“Text string”).
+* Arrays: Major type 4 ("Array of data items").
+
+As advised by https://tools.ietf.org/html/rfc7049#section-3[section “Creating CBOR-Based Protocols”] of the CBOR spec, we clarify that:
+
+* Floating-point numbers may not be used to encode integers.
+* Duplicate keys are prohibited in CBOR maps.
+
+[TIP]
+====
+A typical request would be (written in https://tools.ietf.org/html/rfc7049#section-6[CBOR diagnostic notation], which can be checked and converted on http://cbor.me/[cbor.me]):
+....
+55799({
+ "content": {
+ "request_type": "call",
+ "canister_id": h'ABCD01',
+ "method_name": "say_hello",
+ "arg": h'0061736d01000000',
+ },
+ "sender_sig": h'DEADBEEF',
+ "sender_pubkey": h'b7a3c12dc0c8c748ab07525b701122b88bd78f600c76342d27f25e5f92444cde'
+})
+....
+
+====
+
+[#api-cddl]
+=== CDDL description of requests and responses
+
+The https://tools.ietf.org/html/rfc8610[Concise Data Definition Language (CDDL)] is a data description language for CBOR. This section summarizes the format of the CBOR data passed to and from the entry points described above. You can also link:./requests.cddl[download the file].
+
+[source,bash]
+----
+include::example$requests.cddl[]
+----
+
+=== Ordering guarantees
+
+In order to allow for a distributed implementation of the Internet Computer, the order in which the various messages between canisters are delivered and executed is not fully specified.
+
+The guarantee we do give is that function calls between two canisters are executed in order, so that a canister that requires in-order execution need not wait for the response from an earlier message to a canister before sending a later message to that same canister.
+
+More precisely:
+
+ * Method calls between any _two_ canisters are delivered in order, as if they
+ were communicating over a single simple FIFO queue.
+ * If a WebAssembly function, within a single invocation, makes multiple calls
+ to the same canister, they are queued in the order of invocations to `ic0.call_perform`.
+ * Responses (including replies with `ic0.msg_reply`, explicit rejects with `ic0.msg_reject` and system-generated error responses) do _not_ have any ordering guarantee relative to each other or to method calls.
+ * There is no particular order guarantee for ingress messages submitted via
+ the HTTP interface.
+
+=== Synchronicity across nodes
+
+This document describes the Internet Computer as having a single global state that can be modified and queried. In reality, it consists of many nodes, which may not be perfectly in sync.
+
+As long as you talk to one (honest) node only, the observed behavior is nicely sequential. If you issue an update (i.e. state-mutating) call to a canister (e.g. bump a counter), and node A indicates that the call has been executed, and you then issue a query call to node A, then A's response is guaranteed to include the effect of the update call (and you will receive the updated counter value).
+
+If you then (quickly) issue a read request to node B, it may be that B responds to your read query based on the old state of the canister (and you might receive the old counter value).
+
+A related problem is that query calls are not certified, and nodes may be dishonest in their response. In that case, the user might want to get more assurance by querying multiple nodes and comparing the result. However, it is (currently) not possible to query a _specific_ state.
+
+NOTE: Applications can work around these problems. For the first problem, the query result could be such that the user can tell if the update has been received or not. For the second problem, even if using <> is not possible, if replies are monotonic in some sense the user can get assurance in their intersection (e.g. if the query returns a list of events that grows over time, then even if different nodes return different lists, the user can get assurance in those events that are reported by many nodes).
+
+
+[#canister-module-format]
+== Canister module format
+
+A canister module is simply a https://webassembly.github.io/spec/core/index.html[WebAssembly module] in binary format (typically `.wasm`).
+
+[#system-api]
+== Canister interface (System API)
+
+The System API is the interface between the running canister and the Internet Computer. It allows the WebAssembly module of a canister to expose functionality to the users (method entry points) and the system (e.g. initialization), and exposes system functionality to the canister (e.g. calling other canisters). Because WebAssembly is rather low-level, it also explains how to express higher level concepts (e.g. binary blobs).
+
+We want to leverage advanced WebAssembly features, such as WebAssembly host references. But as they are not yet supported by all tools involved, this section describes an initial System API that does not rely on host references. To emphasize that this is just a preliminary interface, we group the system methods under the module name `ic0`, planning to use `ic` for the real deal.
+In section <>, we outline some of the proposed uses of WebAssembly host references.
+
+[#system-api-module]
+=== WebAssembly module requirements
+
+In order for a WebAssembly module to be usable as the code for the canister, it needs to conform to the following requirements:
+
+* If it imports a memory, it must import it from `env.memory`. In the following, “the Wasm memory” refers to this memory.
+* If it imports a table, it must import it from `env.table`. In the following, “the Wasm table” refers to this table.
+* It may only import a function if it is listed in <>.
+* It may have a `(start)` function.
+* If it exports a function called `canister_init`, the function must have type `+() -> ()+`.
+* If it exports functions called `canister_get_ingress_bucket` or `canister_get_ingress_limit_per_second`, the functions must have type `+() -> ()+`. It must export either both or none of these two functions.
+* If it exports any functions called `canister_update ` or `canister_query ` for some `name`, the functions must have type `+() -> ()+`.
+* It may not export both `canister_update ` and `canister_query ` with the same `name`.
+
+=== Interpretation of numbers
+
+WebAssembly number types (`i32`, `i64`) do not indicate if the numbers are to be interpreted as signed or unsigned. Unless noted otherwise, whenever the System API interprets them as numbers (e.g. memory pointers, buffer offsets, array sizes), they are to be interpreted as unsigned.
+
+=== Entry points
+
+The canister provides entry points which are invoked by the system under various circumstances:
+
+* The canister may export a function named `canister_init` and type `+() -> ()+`.
+* The canister may export a function named `canister_pre_upgrade` and type `+() -> ()+`.
+* The canister may export a function named `canister_post_upgrade` and type `+() -> ()+`.
+* The canister may export functions named `canister_get_ingress_bucket` and `canister_get_ingress_limit_per_second` with type `+() -> ()+`. It must export none or both of these functions.
+* The canister may export functions named `canister_update ` and type `+() -> ()+`.
+* The canister may export functions named `canister_query ` and type `+() -> ()+`.
+* The canister table may contain functions of type `+(env : i32) -> ()+` which may be used as callbacks for inter-canister calls.
+
+If the execution of any of these entry points traps for any reason, then all changes to the WebAssembly state, as well as the effect of any externally visible system call (like `ic0.msg_reply`, `ic0.msg_reject`, `ic0.call_perform`), are discarded. For upgrades, this transactional behaviour applies to the `canister_pre_upgrade`/`canister_post_upgrade` sequence as a whole.
+
+
+[#system-api-init]
+==== Canister initializaion
+
+If `canister_init` is present, then this is the first exported WebAssembly function invoked by the system. The argument that was passed along with the canister initialization call (see <>) is available to the canister via `ic0.msg_arg_data_size/copy`.
+
+The system assumes the canister to be fully instantiated if the `canister_init` method entry point returns. If the `canister_init` method entry point traps, then canister installation has failed, and the canister is reverted to its previous state (i.e. empty with `install`, or whatever it was for a `reinstall`).
+
+[#system-api-upgrades]
+==== Canister upgrades
+
+When a canister is upgraded to a new WebAssembly module, the system:
+
+ 1. Invokes `canister_pre_upgrade` (if present) on the old instance, to give the canister a chance to clean up (e.g. move data to <>).
+ 2. Instantiates the new module, including the execution of `(start)`, with a fresh WebAssembly state.
+ 3. Invokes `canister_post_upgrade` (if present) on the new instance, passing the `arg` provided in the `install_code` call (<>).
+
+The stable memory is preserved throughout the process; any other WebAssembly state is discarded.
+
+During these steps, no other entry point of the old or new canister is invoked. The `canister_init` function of the new canister is _not_ invoked.
+
+These steps are atomic: If `canister_pre_upgrade` or `canister_post_upgrade` trap, the upgrade has failed, and the canister is reverted to the previous state. Otherwise, the upgrade has succeeded, and the old instance is discarded.
+
+[#system-api-requests]
+==== Public methods
+
+To define a public method of name `name`, a WebAssembly module exports a function with name `canister_update ` or `canister_query ` and type `+() -> ()+`. We call this the _method entry point_. The name of the exported function distinguishes update and query methods.
+
+NOTE: The space in `canister_update ` resp. `canister_query ` is intentional. There is exactly one space between `canister_update/canister_query` and the ``.
+
+The argument of the call (e.g. the content of the `arg` field in the <>) is copied into the canister on demand using the System functions shown below.
+
+Eventually, a method will want to send a response, using `ic0.reply` or `ic0.reject`
+
+==== Callbacks
+
+Callbacks are addressed by their table index (as a proxy for a Wasm `funcref`).
+
+In the reply callback of a <>, the argument refers to the response to that call. In reject callbacks, no argument is available.
+
+
+[#system-api-imports]
+=== Overview of imports
+
+The following sections describe various system imports, which we summarize here.
+
+....
+ic0.msg_arg_data_size : () -> i32; // I U Q Ry Lb
+ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> (); // I U Q Ry Lb
+ic0.msg_caller_size : () -> i32; // I G U Q Lb
+ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> (); // I G U Q Lb
+ic0.msg_reject_code : () -> i32; // Ry Rt
+ic0.msg_reject_msg_size : () -> i32; // Rt
+ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> (); // Rt
+
+ic0.msg_reply_data_append : (src : i32, size : i32) -> (); // U Q Ry Rt
+ic0.msg_reply : () -> (); // U Q Ry Rt
+ic0.msg_reject : (src : i32, size : i32) -> (); // U Q Ry Rt
+
+ic0.msg_cycles_available : () -> i64; // U Rt Ry Lb
+ic0.msg_cycles_refunded : () -> i64; // Rt Ry
+ic0.msg_cycles_accept : ( max_amount : i64 ) -> ( amount : i64 ); // U Rt Ry
+
+ic0.canister_self_size : () -> i32; // *
+ic0.canister_self_copy : (dst : i32, offset : i32, size : i32) -> (); // *
+ic0.canister_cycle_balance : () -> i64; // *
+ic0.canister_status : () -> i32; // *
+
+ic0.ingress_rate_bucket_size : () -> i32; // Ll
+ic0.ingress_rate_bucket_copy : (dst : i32, offset : i32, size : i32) -> (); // Ll
+ic0.return_ingress_bucket :
+ ( bucket_src : i32,
+ bucket_size : i32,
+ cost : i64
+ ) -> (); // Lb
+ic0.return_ingress_limit_per_second : (limit : i64) -> (); // Ll
+
+ic0.call_new : // U Ry Rt
+ ( callee_src : i32,
+ callee_size : i32,
+ name_src : i32,
+ name_size : i32,
+ reply_fun : i32,
+ reply_env : i32,
+ reject_fun : i32,
+ reject_env : i32
+ ) -> ();
+ic0.call_on_cleanup : (fun : i32, env : i32) -> (); // U Ry Rt
+ic0.call_data_append : (src : i32, size : i32) -> (); // U Ry Rt
+ic0.call_cycles_add : ( amount : i64 ) -> (); // U Ry Rt
+ic0.call_perform : () -> ( err_code : i32 ); // U Ry Rt
+
+ic0.stable_size : () -> (page_count : i32); // *
+ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32); // *
+ic0.stable_write : (offset : i32, src : i32, size : i32) -> (); // *
+ic0.stable_read : (dst : i32, offset : i32, size : i32) -> (); // *
+
+ic0.certified_data_set : (src: i32, size: i32) -> () // I G U Ry Rt
+ic0.data_certificate_present : () -> i32 // Q
+ic0.data_certificate_size : () -> i32 // Q
+ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> () // Q
+
+ic0.time : () -> (timestamp : i64); // *
+
+ic0.debug_print : (src : i32, size : i32) -> (); // * s
+ic0.trap : (src : i32, size : i32) -> (); // * s
+....
+
+The comment after each function lists from where these functions may be invoked:
+
+* `I`: from `canister_init` or `canister_post_upgrade`
+* `G`: from `canister_pre_upgrade`
+* `U`: from `canister_update …`
+* `Q`: from `canister_query …`
+* `Ry`: from a reply callback
+* `Rt`: from a reject callback
+* `C`: from a cleanup callback
+* `s`: the `(start)` module initialization function
+* `Lb`: from `canister_get_ingress_bucket`
+* `Ll`: from `canister_get_ingress_limit_per_second`
+* `*` = `I G U Q Ry Rt C Lb Ll` (NB: Not `(start)`)
+
+If the canister invokes a system import from somewhere else, it will trap.
+
+=== Blob-typed arguments and results
+
+WebAssembly functions parameter and result types can only be primitive number types. To model functions that accept or return blobs or text values, the following idiom is used:
+
+To provide access to a string or blob `foo`, the System API provides two functions:
+
+ ic0.foo_size : () -> i32
+ ic0.foo_copy : (dst : i32, offset: i32, size : i32) -> ()
+
+The `*_size` function indicates the size, in bytes, of `foo`. The `*_copy` function copies `size` bytes from `foo[offset..offset+size]` to `memory[dst..dst+size]`. This traps if `offset+size` is greater than the size of `foo`, or if `dst+size` exceeds the size of the Wasm memory.
+
+
+Dually, a System API function that conceptually takes a blob or string as a parameter `foo` has two parameters:
+
+ ic0.set_foo : (src : i32, size: i32) -> …
+
+which copies, at the time of function invocation, the data referred to by `src`/`size` out of the canister. Unless otherwise noted, this traps if `src+size` exceeds the size of the WebAssembly memory.
+
+=== Method arguments
+
+The canister can access an argument. For `canister_init`, `canister_post_upgrade` and method entry points, the argument is the argument of the call; in a reply callback, it refers to the received reply. So the lifetime of the argument data is a single WebAssembly function execution, not the whole method call tree.
+
+* {blank}
++
+ ic0.msg_arg_data_size : () -> i32
+ ic0.msg_arg_data_copy : (dst : i32, offset : i32, size : i32) -> ()
++
+The message argument data.
+
+* {blank}
++
+ ic0.msg_caller_size : () -> i32
+ ic0.msg_caller_copy : (dst : i32, offset: i32, size : i32) -> ()
++
+The identity of the caller, which may be a canister id or a user id. During canister installation or upgrade, this is the id of of the user or canister requesting the installation or upgrade.
+
+* `+ic0.msg_reject_code : () -> i32+`
++
+Returns the reject code, if the current function is invoked as a reject callback.
++
+It returns the special “no error” code `0` if the callback is _not_ invoked as a reject callback; this allows canisters to use a single entry point for both the reply and reject callback, if they choose to do so.
++
+* {blank}
++
+ ic0.msg_reject_msg_size : () -> i32
+ ic0.msg_reject_msg_copy : (dst : i32, offset : i32, size : i32) -> ()
++
+The reject message. Traps if there there is no reject message (i.e. if `reject_code` is `0`).
+
+[#responding]
+=== Responding
+
+Eventually, the canister will want to respond to the original call, either by replying (indicating success) or rejecting (signalling an error):
+
+* `+ic0.msg_reply_data_append : (src : i32, size : i32) -> ()+`
++
+Appends idata it to the (initially empty) data reply.
++
+NOTE: This can be invoked multiple times to build up the argument with data from various places on the Wasm heap. This way, the canister does not have to first copy all the pieces from various places into one location.
++
+This traps if the current call already has been responded to.
+
+* `+ic0.msg_reply : () -> ()+`
++
+Replies to the sender with the data assembled using `ic0.msg_reply_data_append`.
++
+This function can be called at most once (a second call will trap), and must be called exactly once to indicate success.
++
+See <> for how this interacts with cycles available on this call.
+
+* `+ic0.msg_reject : (src : i32, size : i32) -> ()+`
++
+Rejects the call. The data referred to by `src`/`size` is used for the diagnostic message.
++
+This system call traps if `src+size` exceeds the size of the WebAssembly memory, or if the current call already has been responded to, or if the data referred to by `src`/`size` is not valid UTF8.
++
+The other end will receive this reject with reject code `CANISTER_REJECT`, see <>.
++
+Possible reply data assembled using `ic0.msg_reply_data_append` is discarded.
++
+See <> for how this interacts with cycles available on this call.
+
+[#system-api-rate-limiting]
+=== Ingress message rate limiting
+
+A canister can apply a rate limiting mechanism to ingress messages. When the IC receives an update call from a user, the IC will use the canister methods `canister_get_ingress_bucket` and `canister_get_ingress_limit_per_second` to obtain rate limiting information from the canister, and will ensure that the specified rates are respected.
+If the canister does not implement `canister_get_ingress_bucket` and does not implement `canister_get_ingress_limit_per_second`, then no rate limiting is applied and the canister will receive the update calls.
+
+The function `canister_get_ingress_bucket` is called for each message, possibly (but not necessarily) even multiple times, on different canister states.
+The function `canister_get_ingress_limit_per_second` is called periodically (typically every few seconds) for buckets for which new messages arrive.
+This means, in particular, that the canister state on which `canister_get_ingress_bucket` is called for a message, and the state on which `canister_get_ingress_limit_per_second` is called for determining the rate limit affecting that same message, may differ.
+
+* In `canister_get_ingress_bucket`, the canister can specify a bucket and a cost for the message by invoking
++
+`ic0.return_ingress_bucket : ( bucket_src : i32, bucket_size : i32, cost : i64 ) -> ()`.
++
+This function assigns to the message the bucket identified by the `bucket_*` parameters, and the cost specified by `cost`. All messages assigned to the same bucket are treated together during rate limiting, whereas messages in different buckets are handled independently. Buckets are identified by opaque blobs of size at most 64 bytes.
++
+The unit of cost is completely up to the canister.
++
+This function traps if invoked twice, or if `bucket_size` exceeds 64.
++
+If the canister traps in `canister_get_ingress_bucket` or does not call `ic0.return_ingress_bucket`, then the access is denied.
+
+* In `canister_get_ingress_limit`, the canister obtains a blob of length at most 64 bytes (the bucket) as an argument, which can be retrieved via `ic0.ingress_rate_bucket_*`. The canister can specify a limit for the bucket by invoking
++
+`ic0.return_ingress_limit_per_second : ( limit : i64 ) -> ()`.
++
+The unit of limit (just like that of cost above) is completely up to the canister, but the platform guarantees that (possibly with a rolling average over a few seconds) the accumulated cost per second does not exceed limit.
++
+This function traps if invoked twice. If the canister traps or the canister does not call `ic0.return_ingress_limit_per_second`, the canister does not receive any messages from that bucket.
+
+[#system-api-canister-self]
+=== Self-identification
+
+A canister can learn about its own identity:
+
+* {blank}
++
+ ic0.canister_self_size : () -> i32
+ ic0.canister_self_copy: (dst : i32, offset : i32, size : i32) -> ()
++
+These functions allow the canister to query its own canister id (as a blob).
+
+[#system-api-canister-status]
+=== Canister status
+
+This function allows a canister to find out if it is running, stopping or stopped (see <> and <> for context).
+
+* `ic0.canister_status : () -> i32`
++
+returns the current status of the canister:
++
+Status `1` indicates running, `2` indicates stopping, and `3` indicates stopped.
++
+Status `3` (stopped) can be observed, for example, in `canister_pre_upgrade` and can be used to prevent accidentally upgrading a canister that is not fully stopped.
+
+[#system-api-call]
+=== Inter-canister method calls
+
+When handling an update call (or a callback), a canister can do further calls to another canister. Calls are assembled in a builder-like fashion, starting with `ic0.call_new`, adding more attributes using the `ic0.call_*` functions, and eventually performing the call with `ic0.call_perform`.
+
+* {blank}
++
+--
+ ic0.call_new :
+ ( callee_src : i32,
+ callee_size : i32,
+ name_src : i32,
+ name_size : i32,
+ reply_fun : i32,
+ reply_env : i32,
+ reject_fun : i32,
+ reject_env : i32,
+ ) -> ()
+
+Begins assembling a call to the canister specified by `callee_src/_size` at method `name_src/_size`.
+
+The system records two mandatory callback functions, represented by a table entry index `fun` and some additional value `env`. When the response comes back, the table is read at the corresponding index, expected to be a function of type `+(env : i32) -> ()+` and passed the corresponding `env` value.
+
+The reply callback is executed upon successful completion of the method call, which can query the reply using `ic0.msg_arg_data_*`.
+
+The reject callback is executed if the method calls fails asynchronously or the other canister explicitly rejects the call. The reject code and message can be queried using `ic0.msg_reject_code` and `ic0.msg_reject_msg_*`.
+
+Subsequent calls to the following functions set further attributes of that call, until the call is concluded (with `ic0.call_perform`) or discarded (by returning without calling `ic0.call_perform` or by starting a new call with `ic0.call_new`.)
+--
+
+* {blank}
++
+--
+ ic0.call_on_cleanup : (fun : i32, env : i32) -> ()
+
+If the a cleanup callback is specified for this call, it is executed if and only if the `reply` or the `reject` callback was executed and trapped (for any reason).
+
+During the execution of the `cleanup` function, only a subset of the System API is available (namely `ic0.debug_print`, `ic0.trap` and the `ic0.stable_*` functions). The cleanup function is expected to run swiftly (within a fixed, yet to be specified cycle limit) and serves to free resources associated with the callback.
+
+If this traps (e.g. runs out of gas), the state changes from the `cleanup` function are discarded, as usual, and no further actions are taken related to that call. Canisters likely want to avoid this from happening.
+
+There must be at most one call to `ic0.call_on_cleanup` between `ic0.call_new` and `ic0.call_perform`.
+--
+
+* `+ic0.call_data_append : (src : i32, size : i32)+`
++
+Appends the specified bytes to the argument of the call. Initially, the argument is empty.
++
+This may be called multiple times between `ic0.call_new` and `ic0.call_perform`.
+
+
+* `+ic0.call_cycles_add : ( amount : i64) -> ()+`
++
+This adds cycles onto a call. See <>.
++
+This may be called multiple times between `ic0.call_new` and `ic0.call_perform`.
+
+* `+ic0.call_perform : () -> ( err_code : i32 )+`
++
+This call concludes assembling the call. It queues the call message to the given destination, but does not actually act on it until the current WebAssembly function returns without trapping.
++
+If the system returns `0` as the `err_code`, the system was able to enqueue the call. In this case, the call will either be delivered, or returned because the destination canister does not exist or returned because of an out of gas condition. This also means that exactly one of the reply or reject callback will be executed.
++
+If the system returns a non-zero value, the call cannot (and will not be) performed.
++
+After `ic0.call_perform` and before the next call to `ic0.call_new`, all other `ic0.call_*` function calls trap
+
+[#system-api-cycles]
+=== Cycles
+
+Each canister maintains a balance of _cycles_, the utility token used to pay for platform usage.
+
+NOTE: This specification currently does not go into details about which actions cost how many cycles and/or when. In general, you must assume that the canister’s cycle balance can change arbitrarily between method executions, and during each system function API call, unless explicitly mentioned otherwise.
+
+* `ic0.canister_cycle_balance : () -> i64`
++
+indicates the current cycle balance of the canister. It is the canister balance before the execution of the current message, minus a reserve to pay for the execution of the current message, minus any cycles queued up to be sent via `ic0.call_cycles_add`. After execution of the message, the system may add unused cycles from the reserve back to the balance.
++
+NOTE: Should a future version of this specification allow `MAX_CANISTER_BALANCE` >= 2^64^, then this call will report 2^64^-1 if the balance exceeds 2^64^. A new, wider System API will then be provided for canisters that need to deal precisely with large canister balances.
+
+* `ic0.msg_cycles_available : () -> i64`
++
+returns the amount of cycles that were transferred by the caller of the current call, and is still available in this message.
++
+Initially, in the update method entry point, this is the amount that the caller passed to the canister. When cycles are accepted (`ic0.msg_cycles_accept`), this reports less cycles accordingly. When the call is responsed to (reply or reject), all available cycles are refunded to the caller, and this will return 0.
+
+* `ic0.msg_cycles_accept : ( max_amount : i64 ) -> ( amount : i64 )`
++
+--
+This moves cycles from the call to the canister balance. It moves as many cycles as possible, up to these constraints:
+
+* It moves no more cycles than `max_amount`.
+
+* It moves no more cycles than available according to `ic0.msg_cycles_available`, and
+
+* The canister balance afterwards does not exceeed `MAX_CANISTER_BALANCE` minus any possible outstanding balances. The precise logic of this limit is not yet specified here.
+
+It can be called multiple times, each time possibly adding more cycles to the balance.
+
+The return value indicates how much cycles were actually moved.
+
+This does not trap.
+
+[TIP]
+=====
+Example: To accept all cycles provided in a call, invoke `ic0.msg_cycles_accept(ic0.msg_cycles_available())` in the method handler or a callback handler, _before_ calling reply or reject.
+=====
+--
+
+* `ic0.call_cycles_add : ( amount : i64 ) -> ()`
++
+This function moves cycles from the canister balance onto the call under construction, to be transferred with that call.
++
+The cycles are deducted from the balance as shown by `ic0.canister_cycle_balance` immediately, and moved back if the call cannot be performed (e.g. if `ic0.call_perform` signals an error, or if the canister invokes `ic0.call_new` or returns without callling `ic0.call_perform`).
++
+This traps if trying to transfer more cycles than are in the current balance of the canister.
+
+* `ic0.msg_cycles_refunded : () -> i64`
++
+this can only be used in a callback handler (reply or reject), and indicates the amount of cycles that came back with the response as a refund. The refund has already been added to the canister balance automatically.
+
+[#system-api-stable-memory]
+=== Stable memory
+
+Canisters have the ability to store and retrieve data from a secondary memory. The purpose of this _stable memory_ is to provide space to store data beyond upgrades. The interface mirrors roughly the memory-related instructions of WebAssembly, and tries to be forward compatible with exposing this feature as an additional memory.
+
+The stable memory is initially empty.
+
+* {blank}
++
+ ic0.stable_size : () -> (page_count : i32)
++
+returns the current size of the stable memory in WebAssembly pages. (One WebAssembly page is 64Ki bytes.)
+
+* {blank}
++
+ ic0.stable_grow : (new_pages : i32) -> (old_page_count : i32)
++
+tries to grow the memory by `new_pages` many pages containing zeroes.
+
+If successful, returns the _previous_ size of the memory (in pages). Otherwise, returns `-1`.
+
+* {blank}
++
+ ic0.stable_write : (offset : i32, src : i32, size : i32) -> ()
++
+copies the data referred to by `src`/`size` out of the canister and replaces the corresponding segment starting at `offset` in the stable memory.
+
+This system call traps if `src+size` exceeds the size of the WebAssembly memory or `offset+size` exceeds the size of the stable memory.
+
+* {blank}
++
+ ic0.stable_read : (dst : i32, offset : i32, size : i32) -> ()
++
+copies the data referred to by `offset`/`size` out of the stable memory and replaces the corresponding bytes starting at `dest` in the canister memory.
+
+This system call traps if `dst+size` exceeds the size of the WebAssembly memory or `offset+size` exceeds the size of the stable memory.
+
+[#system-api-time]
+=== System time
+
+The canister can query the system for the current time.
+
+`+ic0.time : () -> i64+`
+
+The time is given as nanoseconds since 1970-01-01. The system guarantees that
+
+ * the time, as observed by the canister, is monotonically increasing, even across canister upgrades.
+ * within an invocation of one entry point, the time is constant.
+
+The system times of different canisters are unrelated, and calls from one canister to another may appear to travel “backwards in time”.
+
+NOTE: While an implementation will likely try to keep the System Time close to the real time, this is not formally part of this specification.
+
+[#system-api-certified-data]
+=== Certified data
+
+For each canister, the system keeps track of “certified data”, a canister-defined blob. For fresh canisters, this blob is the empty blob (`""`).
+
+* `+ic0.certified_data_set : (src: i32, size : i32) -> ()+`
++
+The canister can update the certified data with this call. The passed data must be no larger than 32 bytes. This can be used any number of times.
+
+When executing a query method via a query call (i.e. in non-replicated state), the canister can fetch a certificate that authenticates to third parties the value last set via `ic0.certified_data_set`.
+
+* `+ic0.data_certificate_present : () -> i32+`
++
+returns `1` if a certificate is present, and `0` otherwise.
++
+This will return `0` if the query method is executed within replicated execution (e.g. when invoked via an update call or inter-canister call).
++
+NOTE: In the future, this may also return `0` for query calls if the system executes query calls on not-yet-certified states.
+
+* {blank}
++
+ ic0.data_certificate_size : () -> i32
+ ic0.data_certificate_copy : (dst: i32, offset: i32, size: i32) -> ()
++
+Copies the certificate for the current value of the certified data to the canister.
++
+The certificate is a blob as described in <> that contains the values at path `/canister//certified_data` and at path `/time` of <>.
++
+This traps if `ic0.data_certificate_present()` returns `0`.
+
+
+=== Debugging aids
+
+During local development and execution on a local network, the canister needs a way to emit textual trace messages. On the “real” network, these do not do anything.
+
+* `+ic0.debug_print : (src : i32, size : i32) -> ()+`
++
+When executing in an environment that supports debugging, this copies out the data specified by `src` and `size`, and logs, prints or stores it in an environment-appropriate way. The copied data may likely be a valid string in UTF8-encoding, but the environment should be prepared to handle binary data (e.g. by printing it in escaped form). The data does typically not include a terminating `\0` or `\n`.
++
+Semantically, this function is always a no-op, and never traps, even if the `src+size` exceeds the size of the memory, or if this function is executed from `(start)`. If the environment cannot perform the print, it just skips it.
+
+Similarly, the system allows the canister to effectively trap, but give some indication about why it trapped:
+
+* `+ic0.trap : (src : i32, size : i32) -> ()+`
++
+This function always traps.
++
+The environment may copy out the data specified by `src` and `size`, and log, print or store it in an environment-appropriate way, or include it in system-generated reject messages where appropriate. The copied data may likely be a valid string in UTF8-encoding, but the environment should be prepared to handle binary data (e.g. by printing it in escaped form or substituting invalid characters).
+
+[#host-references]
+=== Outlook: Using Host References
+
+The Internet Computer aims to make the most of the WebAssembly platform, and embraces WebAssembly features. With WebAssembly host references, we can make the platform more secure, the interfaces more abstract and more compositional. The above `ic0` System API does not yet use WebAssembly host references. Once they become available on our platform, a new version of the System API using host references will be available via the `ic` module. The changes will be, at least
+
+1. The introduction of a `api_nonce` reference, which models the capability to use the System API. It is passed as an argument to `canister_init`, `canister_update ` etc., and expected as an argument by almost all system function calls. (The debugging aids remain unconstrainted.)
+2. The use of references, instead of binary blobs, to address principals (user ids, canister ids), e.g. in `ic0.msg_caller` or in `ic0.call_new`. Additional functions will be provided to convert between the transparent binary representation of principals and references.
+3. Making the builder interface to create calls build calls identified by a reference, rather than having an implicit partial call in the background.
+
+A canister may only use the old _or_ the new interface; the system detects which interface the canister intends to use based on the names and types of its function imports and exports.
+
+[#ic-management-canister]
+== The IC management canister
+
+The interfaces above provide the fundamental ability for external users and canisters to contact other canisters. But the Internet Computer provides additional functionality, such as canister and user management. This functionality is exposed to external users and canisters via the _IC management canister_.
+
+NOTE: The _IC management canister_ is just a facade; it does not actually exist as a canister (with isolated state, Wasm code, etc.).
+
+The IC management canister address is `aaaaa-aa` (i.e. the empty blob).
+
+[#ic-candid]
+=== Interface overview
+
+The following interface description, in https://github.com/dfinity/candid/blob/master/spec/Candid.md[Candid syntax], describes the available functionality. You can also link:./ic.did[download the file].
+----
+include::example$ic.did[]
+----
+
+The binary encoding of arguments and results are as per Candid specification.
+
+[#ic-create_canister]
+=== IC method `create_canister`
+
+Before deploying a canister, the administrator of the canister first has to register it with the system, to get a canister id (with an empty canister behind it), and then separately install the code.
+
+A canister has an attribute _controller_; initially, the user who has registered the canister is the controller, but this can be changed using <>
+
+Until code is installed, the canister behaves like one with no public methods.
+
+[#ic-install_code]
+=== IC method `install_code`
+
+This method installs code into a canister.
+
+Only the _controller_ of the canister can install code.
+
+If `mode = install` or `mode = reinstall`, this will instantiate the canister module and invoke its `canister_init` system method (if present), as explained in Section “<>”, passing the `arg` to the canister. Upon replacing an existing canister, all state (including the stable memory) is cleared.
+
+If `mode = upgrade`, this will perform an upgrade of an existing canister module as described in <>, passing `arg` to the `canister_post_upgrade` system method of the new instance.
+
+This is atomic: If the response to this request is a `reject`, then this call had no effect.
+
+The optional field `compute_allocation`, if present, must be a number between 0 and 100, inclusively. It indicates how much compute power should be guaranteed to this canister, expressed as a percentage of the maximum compute power that a single canister can allocate. If absent, it is treated like an allocation of 0. If the system cannot provide the requested allocation, for example because it is oversubscribed, the call will be rejected.
+
+The optional field `memory_allocation`, if present, must be a number between 0 and 2^48^ (i.e 256TB), inclusively. It indicates how much memory the canister is allowed to use in total. Any attempt to grow memory usage beyond this allocation will fail. If absent, an implementation-defined default applies. If the system cannot provide the requested allocation, for example because it is oversubscribed, the request will be rejected.
+
+NOTE: Some canisters may not be able to make sense of callbacks after upgrades; these should be stopped first, to wait for all outstanding callbacks. It is expected that the canister admin (or admin tooling) does that separately.
+
+[#ic-set_controller]
+=== IC method `set_controller`
+
+Initially, the user or canister that created a canister is its _controller_, but control can be yielded to another user or canister.
+
+Only the current controller of the canister can change the controller.
+
+[#ic-canister_status]
+=== IC method `canister_status`
+
+Indicates various information about the canister. It contains:
+
+* The status of the canister. It could be one of `Running`, `Stopping` or `Stopped`.
+* A hash of the module installed on the canister. This is `null` if no code is installed.
+* The controller of the canister.
+* The memory size taken by this canister.
+* The balances of this canister. It includes Cycles and ICPTs.
+
+Only the current controller of the canister can request its status.
+
+[#ic-stop_canister]
+=== IC method `stop_canister`
+
+The controller of a canister may stop a canister (e.g., to prepare for a canister upgrade).
+
+Stopping a canister is not an atomic action. The immediate effect is that the status of the canister is changed to `Stopping` (unless the canister is already stopped).
+The system will reject all calls to a stopping canister, indicating that the canister is stopping.
+Responses to a stopping canister are processed as usual.
+When all outstanding responses have been processed (so there are no open call contexts), the canister status is changed to `Stopped` and the management canister responds to the caller of the `stop_canister` request.
+
+[#ic-start_canister]
+=== IC method `start_canister`
+A canister may be started by its controller.
+
+If the canister status was 'Stopped' or `Stopping` then the canister status is simply set to `Running`.
+In the latter case all `stop_canister` calls which are processing fail (and are rejected).
+
+If the canister was already `Running` then the status stays unchanged.
+
+[#ic-delete_canister]
+=== IC method `delete_canister`
+
+This method deletes a canister from the IC.
+
+Only the _controller_ of the canister can delete it and the canister must already be stopped. Deleting a canister cannot be undone, any state stored on the canister is permanently deleted and its cycles are discarded. Once a canister is deleted, its ID cannot be reused.
+
+[#ic-deposit_cycles]
+=== IC method `deposit_cycles`
+
+This method deposits the cycles included in this call into the specified canister.
+
+Only the controller of the canister can deposit cycles.
+
+[#ic-raw_rand]
+=== IC method `raw_rand`
+
+This method takes no input and returns 32 pseudo-random bytes to the caller. The return value is unknown to any part of the IC at time of the submission of this call. A new return value is generated for each call to this method.
+
+[#ic-provisional_create_canister_with_cycles]
+=== IC method `provisional_create_canister_with_cycles`
+
+As a provisional method, until developers can convert real ICP tokens to provision a new canister with cycles, the system provides the `provisional_create_canister_with_cycles` method. It behaves as `create_canister`, but initializes the canister’s balance with `amount` fresh cycles (using `MAX_CANISTER_BALANCE` if `amount = null`, else capping the balance at `MAX_CANISTER_BALANCE`).
+
+Cycles added to this call via `ic0.call_cycles_add` are returned to the caller.
+
+This method is only available in local development instances, and will be removed in the future.
+
+[#ic-provisional_top_up_canister]
+=== IC method `provisional_top_up_canister`
+
+As a provisional method, until developers can convert real ICP tokens to a top up an existing canister, the system provides the `provisional_top_up_canister` method. It adds `amount` cycles to the balance of canister identified by `amount` (implicitly capping it at `MAX_CANISTER_BALANCE`).
+
+Cycles added to this call via `ic0.call_cycles_add` are returned to the caller.
+
+Any user can top-up any canister this way.
+
+This method is only available in local development instances, and will be removed in the future.
+
+[#certification]
+== Certification
+
+Some parts of the system state are exposed to clients in a tamperproof way via certification: the system can reveal a _partial state tree_ which includes just the data of interest, together with a signature of the state tree. This means that a client can be sure that the response is correct, even if the client happens to be communicating with a malicious server, or have received the certificate via some other untrusted way.
+
+To validate a value using a certificate, the client conceptually
+
+ 1. checks the validity of the partial tree using `verify_cert`,
+ 2. looks up the data in the certificate using `lookup` at a given path,
+
+This mechanism is used in the `read_state` request type, and eventually also for other purposes.
+
+=== Root of trust
+
+The root of trust is the _root public key_, which must be known to the client a priori. For temporary instances of the internet computer, e.g. during local development, the key can be fetched via the <> endpoint.
+
+=== Certificate
+
+A certificate consists of
+
+ * the partial system state, which contains the data of interest, and allows to recover the _tree root hash_,
+ * a signature on the tree root hash valid under some _public key_
+ * an optional _delegation_ that link that public key to _root public key_.
+
+More formally, certificate is thus described by the following data structure:
+....
+Certificate = {
+ tree : HashTree
+ signature : Signature
+ delegation : NoDelegation | Delegation
+}
+HashTree
+ = Empty
+ | Fork HashTree HashTree
+ | Labeled Label HashTree
+ | Leaf blob
+ | Pruned Hash
+Label = Blob
+Hash = Blob
+Signature = Blob
+PublicKey = Blob
+Timestamp = Nat
+....
+
+A certificate is validated with regard to the root of trust by the following algorithm (which uses `check_delegation` defined in <>):
+....
+verify_cert(cert) =
+ let root_hash = reconstruct(cert.tree)
+ let der_key = check_delegation(cert.delegation) // see section Delegations below
+ bls_key = extract_der(der_key)
+ verify_bls_signature(key, cert.signature, domain_sep("ic-state-root") · root_hash)
+
+reconstruct(Empty) = H(domain_sep("ic-hashtree-empty"))
+reconstruct(Fork t1 t2) = H(domain_sep("ic-hashtree-fork") · reconstruct(t1) · reconstruct(t2))
+reconstruct(Labeled l t) = H(domain_sep("ic-hashtree-labeled") · label · reconstruct(t))
+reconstruct(Leaf v) = H(domain_sep("ic-hashtree-leaf") · v)
+reconstruct(Pruned h) = h
+
+domain_sep(s) = byte(|s|) · s
+....
+where `H` is the SHA-256 hash function,
+....
+verify_bls_signature : PublicKey -> Signature -> Blob -> Bool
+....
+is the https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-4[BLS signature verification function], ciphersuite BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_. See that document also for details on the encoding of BLS public keys and signatures, and
+....
+extract_der : Blob -> Blob
+....
+implements DER decoding of the public key, following https://tools.ietf.org/html/rfc5480[RFC4580] using OID 1.3.6.1.4.1.44668.5.3.1.2.1 for the algorithm and 1.3.6.1.4.1.44668.5.3.2.1 for the curve.
+
+All certificate trees include the time at path `/time` (see <>). Clients can use this timestamp to guard against old certificates in cases where they expect a fresh certificate.
+
+=== Lookup
+
+Given a (verified) tree, the client can fetch the value at a given path, which is a sequence of labels (blobs). In this document, we write paths suggestively with slashes as separators; the actual encoding is not actually using slashes as delimitors.
+
+The following algorithm looks up a `path` in a certificate, and returns either
+
+ * the value
+ * `Absent`, if the value is guaranteed to be absent in the original state tree,
+ * `Unknown`, if this partial view does not include information about this path, or
+ * `Error`, if the path does not make sense for this certificate:
+
+....
+lookup(path, cert) = lookup_path(path, cert.tree)
+
+lookup_path([], Empty) = Absent
+lookup_path([], Leaf v) = v
+lookup_path([], Pruned _) = Unknown
+lookup_path([], Labeled _ _) = Error
+lookup_path([], Fork _ _) = Error
+
+lookup_path(l::ls, tree) =
+ match find_label(l, flatten_forks(tree)) with
+ | Absent -> Absent
+ | Unknown -> Unknown
+ | Error -> Error
+ | Found subtree -> lookup_path ls subtree
+
+flatten_forks(Empty) = []
+flatten_forks(Fork t1 t2) = flatten_forks(t1) · flatten_forks(t2)
+flatten_forks(t) = [t]
+
+find_label(l, _ · Labeled l1 t · _) | l == l1 = Found t
+find_label(l, _ · Labeled l1 _ · Labeled l2 _ · _) | l1 < l < l2 = Absent
+find_label(l, Labeled l2 _ · _) | l < l2 = Absent
+find_label(l, _ · Labeled l1 _ ) | l1 < l = Absent
+find_label(l, []) = Absent
+find_label(l, _) = Unknown
+....
+
+The system will only produce well-formed trees, and the above algorithm assumes welformed trees. These have the property that labeled subtrees apper in strictly increasing order of labels, and are not mixed with leaves. More formally:
+....
+well_formed(tree) =
+ (tree = Leaf _) ∨ (well_formed_forest(flatten_forks(tree)))
+
+well_formed_forest(trees) =
+ strictly_increasing([l | Label l _ ∈ trees]) ∧
+ ∀ Label _ t ∈ trees. well_formed(t) ∧
+ ∀ t ∈ trees ≠ Leaf _
+....
+
+[#certification-delegation]
+=== Delegation
+
+To facilitate a distributed implementation of the Internet Computer, the root key can delegate certification authority to other keys.
+
+A certificate by the root subnet does not have a delegation field. A certificate by other subnets include a delegation, which is itself a certificate that proves that the subnet is listed in the root subnet’s state tree (see <>), and reveals its public key.
+
+NOTE: The nested certificate _typically_ does not itself again contain a delegation, although there is no reason why agents should enforce that property.
+....
+Delegation =
+ Delegation {
+ subnet_id : Principal;
+ certificate : Certificate;
+ }
+....
+
+A chain of delegations is verified using the following algorithm, which also returns the delegated key (a DER-encoded BLS key):
+
+....
+check_delegations(NoDelegation) : public_bls_key =
+ return root_public_key
+check_delegations(Delegation d) : public_bls_key =
+ verify_cert(d.certificate)
+ return lookup(["subnet",d.subnet_id,"public_key"],d.certificate)
+....
+where `root_public_key` is the a priori known root key of the Internet Computer instance.
+
+=== Encoding of certificates
+
+The binary encoding of a certificate is a CBOR value according to the following CDDL. You can also link:./certificates.cddl[download the file].
+
+[source,bash]
+----
+include::example$certificates.cddl[]
+----
+
+The values in the <> are encoded to blobs as follows:
+
+* natural numbers are leb128-encoded.
+* text values are UTF-8-encoded
+* blob values are encoded as is
+
+=== Example
+
+Consider the following tree-shaped data (all single charachter strings denote labels, all other denote values)
+....
+─┬╴ "a" ─┬─ "x" ─╴"hello"
+ │ └╴ "y" ─╴"world"
+ ├╴ "b" ──╴ "good"
+ ├╴ "c"
+ └╴ "d" ──╴ "morning"
+....
+
+A possible hash tree for this labeled tree might be, where `┬` denotes a fork.
+This is not a typical encoding (a fork with `Empty` on one side can be
+avoided), but it is valid.
+....
+─┬─┬╴"a" ─┬─┬╴"x" ─╴"hello"
+ │ │ │ └╴Empty
+ │ │ └╴ "y" ─╴"world"
+ │ └╴"b" ──╴"good"
+ └─┬╴"c" ──╴Empty
+ └╴"d" ──╴"morning"
+....
+
+// The following is checked in `impl/src/IC/Test/HashTree.hs`, so please keep
+// in sync
+
+This tree has the following CBOR encoding
+....
+8301830183024161830183018302417882034568656c6c6f810083024179820345776f726c6483024162820344676f6f648301830241638100830241648203476d6f726e696e67
+....
+and the following root hash
+....
+eb5c5b2195e62d996b84c9bcc8259d19a83786a2f59e0878cec84c811f669aa0
+....
+
+Pruning this tree with the following paths
+....
+ /a/y
+ /ax
+ /d
+....
+would lead to this tree (with pruned subtree represented by their hash):
+....
+─┬─┬╴"a" ─┬─ 1B4FEFF9BEF8131788B0C9DC6DBAD6E81E524249C879E9F10F71CE3749F5A638
+ │ │ └╴ "y" ─╴"world"
+ │ └╴"b" ──╴7B32AC0C6BA8CE35AC82C255FC7906F7FC130DAB2A090F80FE12F9C2CAE83BA6
+ └─┬╴EC8324B8A1F1AC16BD2E806EDBA78006479C9877FED4EB464A25485465AF601D
+ └╴"d" ──╴"morning"
+....
+Note that the `"b"` label is included (without content) to prove the absence of the `/ax` path.
+
+This tree encodes to CBOR as
+....
+83018301830241618301820458201b4feff9bef8131788b0c9dc6dbad6e81e524249c879e9f10f71ce3749f5a63883024179820345776f726c6483024162820458207b32ac0c6ba8ce35ac82c255fc7906f7fc130dab2a090f80fe12f9c2cae83ba6830182045820ec8324b8a1f1ac16bd2e806edba78006479c9877fed4eb464a25485465af601d830241648203476d6f726e696e67
+....
+and (obviously) the same root hash.
+
+In the pruned tree, the `lookup_path` function behaves as follows:
+....
+lookup_path(["a", "a"], pruned_tree) = Unknown
+lookup_path(["a", "y"], pruned_tree) = Found "world"
+lookup_path(["aa"], pruned_tree) = Absent
+lookup_path(["ax"], pruned_tree) = Absent
+lookup_path(["b"], pruned_tree) = Unknown
+lookup_path(["bb"], pruned_tree) = Unknown
+lookup_path(["d"], pruned_tree) = Found "morning"
+lookup_path(["e"], pruned_tree) = Absent
+....
+
+
+[#abstract-behavior]
+== Abstract behavior
+
+The previous sections describe the interfaces, i.e. outer edges of the Internet Computer, but give only intuitive and vague information in prose about what these interfaces actually do.
+
+The present section aims to address that question with great precision, by describing the _abstract state_ of the whole Internet Computer, and how this state can change in response to API function calls, or spontaneously (modeling asynchronous, distributed or non-deterministic execution).
+
+The design of this abstract specification (e.g. how and where pending messages are stored) are _not_ to be understood to in any way prescribe a concrete implementation or software architecture. The goals here are formal precision and clarity, but not implementability, so this can lead to different ways of phrasing.
+
+=== Notation
+
+We specify the behavior of the system using ad hoc pseudocode.
+
+The manipulated values are primitive values (numbers, text, binary blobs), aggregate values (lists, unordered lists a.k.a. bags, partial maps, records with fixed fields, named constructors) and functions.
+
+We use a concatenation operator `·` with various types: to extend sets and maps, or to concatenate lists with lists or lists with elements.
+
+The shape of values is described using a hand-wavy type system. We use `Foo = Nat` to define type aliases; now `Foo` can be used instead of `Nat`. Often, the right-hand side is a more complex type here, e.g. a record, or multiple possible types separated by a vertical bar (`|`). Partial maps are written as `Key ↦ Value` and the function type as `Argument -> Result`.
+
+NOTE: All values are immutable! State change is specified by describing the new state, not by changing existing state.
+
+Record fields are accessed using dot-notation (e.g. `S.request_id > 0`). To create a new record from an existing record `R` with some fields changed, the syntax `R where field = new_value` is used. This syntax can also be used to create new records with some deeply nested field changed: `R where some_map[key].field = new_value`.
+
+In the state transitions, upper-case variables (`S`, `C`, `Req_id`) are free variables: The state transition may be taken for any possible value of these variables. `S` always refers to the state of the system before. A state transition often comes with a list of _conditions_, which may restrict the values of these free variables. The _state after_ is usually described using the record update syntax by starting with `S where`.
+
+For example, the condition `S.messages = Older_messages · M · Younger_messages` says that `M` is some message in field `messages` of the record `S`, and that `Younger_messages` and `Older_messages` are the other messages in the system. If the “state after” specifies `S with messages = Older_messages · Younger_messages`, then the message `M` is removed from the state.
+
+=== Abstract state
+
+In this specification, we describe the Internet Computer as a state machine. In particular, there is a single piece of data that describes the complete state of the system, called `S`.
+
+Of course, this is a huge simplification: The real Internet Computer is distributed and has a multi-component architecture, and the state is spread over many different components, some physically separated. But this simplification allows us to have a concise description of the system, and to easily make global decisions (such as, “is there any pending message”), without having to specify the bookkeeping that allows such global decision.
+
+==== Identifiers
+
+Principals (canister ids and user ids) are blobs, but some of them have special form, as explained in <>.
+....
+type Principal = Blob
+....
+
+The function
+....
+mk_self_authenticating_id : PublicKey -> Principal
+mk_self_authenticating_id pk = H(pk) · 0x02
+....
+calculates self-authenticating ids.
+
+The function
+....
+mk_derived_id : Principal -> Blob -> Principal
+mk_derived_id p nonce = H(|p| · p · nonce) · 0x03
+....
+calculates derived ids. With `|p|` we denote the length of the principal, in bytes, encoded as a single byte.
+
+The principal of the anonymous user is fixed:
+....
+anonymous_id : Principal
+anonymous_id = 0x04
+....
+
+These function domains and fixed values are mutually disjoint.
+
+Method names can be arbitrary pieces of text:
+....
+MethodName = Text
+....
+
+[#abstract-canisters]
+==== Abstract canisters
+
+The <> is relatively low-level, and some of its details (e.g. that the argument data is queried using separate calls, and that closures are represented by a function pointer and a number, that method names need to be mangled) would clutter this section. Therefore, we abstract over the WebAssembly details as follows:
+
+* The state of a WebAssembly module (memory, tables, globals) is hidden behind an abstract `WasmState`. The `WasmState` contains the `StableMemory`, which can be extracted using `pre_upgrade` and passed to `post_upgrade`.
+
+* A canister module `CanisterModule` consists of an initial state, and a (pure) function that models function invocation. It either indicates that the canister function traps, or returns a new state together with a description of the invoked asynchronous System API calls.
++
+....
+WasmState = (abstract)
+StableMemory = (abstract)
+Callback = (abstract)
+
+Arg = {
+ data : Blob
+ caller: Principal
+}
+
+Timestamp = Nat;
+Env = {
+ time : Timestamp
+ balance : Nat;
+ certificate : NoCertificate | Blob
+ status : Running | Stopping | Stopped
+}
+
+RejectCode = Nat
+Response = Reply Blob | Reject (RejectCode, Text)
+MethodCall = {
+ callee : CanisterId;
+ method_name: MethodName;
+ arg: Blob;
+ transferred_cycles: Nat;
+ callback: Callback;
+}
+
+UpdateFunc = WasmState -> Trap | Return {
+ new_state : WasmState;
+ new_calls : List MethodCall;
+ new_certified_data : NoCertifiedData | Blob
+ response : NoResponse | Response;
+ cycles_accepted : Nat;
+}
+QueryFunc = WasmState -> Trap | Return Response
+
+AvailableCycles = Nat
+RefundedCycles = Nat
+
+BucketCost = { bucket : Blob, cost : i64 }
+
+CanisterModule = {
+ init : (CanisterId, Arg, Env) -> Trap | Return WasmState
+ pre_upgrade : (WasmState, caller : Principal, Env) -> Trap | Return StableMemory
+ post_upgrade : (CanisterId, StableMemory, Arg, Env) -> Trap | Return WasmState
+ update_methods : MethodName ↦ ((Arg, Env, AvailableCycles) -> UpdateFunc)
+ query_methods : MethodName ↦ ((Arg, Env) -> QueryFunc)
+ callbacks : (Callback, Response, RefundedCycles, Env, AvailableCycles) -> UpdateFunc
+ get_ingress_bucket : (MethodName, WasmState, Arg, Env) -> Trap | Return (bucket : Blob, cost : i64)
+ get_ingress_limit_per_second : (WasmState, Timestamp, Env, bucket : Blob) -> Trap | Return (NoLimit | limit : i64)
+}
+....
+
+This high-level interface presents a pure, mathematical model of a canister, and hides the bookkeeping required to provide the System API as seen in Section <>.
+
+The `CanisterId` parameter of `init` and `post_upgrade` is merely passed through to the canister, via the `canister.self` system call.
+
+The `Env` parameter provides synchronous read-only access to portions of the system state and canister metadata that are always available.
+
+The parsing of a blob to a canister module is modelled via the (possibly implicitly failing) function
+....
+parse_wasm_mod : Blob -> CanisterModule
+....
+
+The concrete mapping of this abstract `CanisterModule` to actual WebAssembly concepts and the System API is described separately in section <>.
+
+
+==== Call contexts
+
+The Internet Computer provides certain messaging guarantees: If a user or a canister calls another canister, it will eventually get a single response (a reply or a rejection), even if some canister code along the way fails.
+
+To ensure that only one response is generated, and also to detect when no response can be generated any more, the system maintains a _call context_. The `responded` field is set to `true` once the call has received a response. Further attempts to respond will now fail.
+
+....
+CallCtxt = {
+ canister : CanisterId;
+ origin : CallOrigin;
+ responded : bool;
+ available_cycles : Nat;
+}
+CallId = (abstract)
+CallOrigin
+ = FromUser {
+ request : Request;
+ }
+ | FromCanister {
+ calling_context : CallId;
+ callback: Callback
+ }
+....
+
+==== Calls and Messages
+
+Calls into and within the Internet Computer are implemented as messages passed between canisters. During their lifetime, messages change shape: they begin as a call to a public method, which is resolved to a WebAssembly function that is then executed, potentially generating a response which is then delivered.
+
+Therefore, a message can have different shapes:
+....
+Queue = Unordered | Queue { from : CanisterId; to : CanisterId }
+EntryPoint
+ = PublicMethod MethodName Principal Blob
+ | Callback Callback Response RefundedCycles
+
+Message
+ = CallMessage {
+ origin : CallOrigin;
+ caller : Principal;
+ callee : CanisterId;
+ method_name : Text;
+ data : Blob;
+ transferred_cycles : Nat;
+ queue : Queue;
+ bucket : None | Blob;
+ cost : i64;
+ rate_limit_time : None | Timestamp;
+ }
+ | FuncMessage {
+ call_context : CallId;
+ receiver : CanisterId;
+ entry_point : EntryPoint;
+ queue : Queue;
+ bucket : None | Blob;
+ cost : i64;
+ rate_limit_time : None | Timestamp;
+ }
+ | ResponseMessage {
+ origin : CallOrigin;
+ response : Response;
+ refunded_cycles : Nat;
+ }
+....
+
+The `queue` field is used to describe the message ordering behavior. Its concrete value is only used to determine when the relative order of two messages must be preserved, and is otherwise not interpreted. Response messages are not ordered, as explained above, so they have no `queue` field.
+
+A reference implementation would likely maintain a separate list of `messages` for each such queue to efficiently find eligible messages; this document uses a single global list for a simpler and more concise system state.
+
+==== API requests
+
+We distinguish between the _asynchronous_ API requests passed to `/api/v1/submit`, which may be present in the system state, and the _synchronous_ API requests passed to `/api/v1/read`, which are only ephemeral.
+
+....
+Envelope = {
+ content : Request | APIReadRequest;
+ sender_pubkey : PublicKey | NoPublicKey;
+ sender_sig : Signature | NoSignature;
+ sender_delegation: [SignedDelegation]
+}
+
+Request
+ = CanisterUpdateCall = {
+ nonce : Blob;
+ ingress_expiry : Nat;
+ sender : UserId;
+ canister_id : CanisterId;
+ method_name : Text;
+ data : Blob;
+ }
+....
+
+The evolution of a `Request` goes through these states, as explained in <>:
+....
+RequestStatus
+ = Received
+ | Processing
+ | Rejected (RejectCode, Text)
+ | Replied Blob
+ | Done
+....
+
+These are the synchronous read messages:
+....
+Path = List(Blob)
+APIReadRequest
+ = StateRead = {
+ nonce : Blob;
+ ingress_expiry : Nat;
+ sender : UserId;
+ paths : List(Path);
+ }
+ | CanisterQuery = {
+ nonce : Blob;
+ ingress_expiry : Nat;
+ sender : UserId;
+ canister_id : CanisterId;
+ method_name : Text;
+ data : Blob;
+ }
+....
+
+A `Path` may refer to a request by way of a _request id_, as specified in <>:
+....
+Request = Blob
+hash_of_map: Request -> Request
+....
+
+For the signatures in a `Request`, we assume that the following function implements signature verification as described in <>.
+This function picks the corresponding signature scheme according to the on the DER-encoded metadata in the public key.
+....
+PublicKey = Blob
+Signature = Blob
+verify_signature : PublicKey -> Signature -> Blob -> Bool
+....
+
+Signed delegations contain the (unsigned) delegation data in a nested record, next to the signature of that data.
+....
+SignedDelegation = {
+ delegation : {
+ pubkey : PublicKey;
+ targets : [CanisterId] | Unrestricted;
+ expiration : Timestamp
+ };
+ signature : Signature
+}
+....
+
+==== The system state
+
+Finally, we can describe the state of the Internet Computer as a record having the following fields:
+
+....
+S = {
+ requests : Request ↦ RequestStatus;
+ canisters : CanisterId ↦ CanState;
+ controllers : CanisterId ↦ Principal;
+ canister_status: CanisterId ↦ CanStatus;
+ time : CanisterId ↦ Timestamp;
+ balances: CanisterId ↦ Nat;
+ certified_data: CanisterId ↦ Blob;
+ system_time : Timestamp
+ call_contexts : CallId ↦ CallCtxt;
+ messages : List Message; // ordered!
+ root_key : PublicKey
+}
+CanState
+ = EmptyCanister | {
+ wasm_state : WasmState;
+ module : CanisterModule;
+ raw_module : Blob;
+}
+CanStatus
+ = Running
+ | Stopping (List (CallOrigin, Nat))
+ | Stopped
+....
+
+==== Initial state
+
+The initial state of the system is
+....
+{
+ requests = ();
+ canisters = ();
+ controllers = ();
+ time = ();
+ balances = ();
+ system_time = T;
+ call_contexts = ();
+ messages = ();
+ root_key = PublicKey;
+}
+....
+for some time stamp `T`, some DER-encoded BLS public key `PublicKey`, and using `()` to denote the empty map or bag.
+
+=== State transitions
+
+Based on this abstract notion of the state, we can describe the behavior of the system. There are three classes of behaviors:
+
+ * Asynchronous API requests that are submitted via `/api/v1/submit`. These transitions describes checks that the request must pass to be considered received.
+ * Spontaneous transitions that model the internal behavior of the system, by describing conditions on the state that allow the transition to happen, and the state after.
+ * Responses to reads (i.e. `/api/v1/read`). By definition, these do _not_ change the state of the system, and merely describe the response based on the read request and the current system state.
+
+The state transitions are not complete with regard to error handling. For example, the behavior of sending a request to a non-existent canister is not specified here. For now, we trust implementors to make sensible decisions there.
+
+We model the <> with one state transition per method. There, we assume a function
+....
+candid : Value -> Blob
+....
+that represents Candid encoding; this is implicitly taking the method types, as declared in <>, into account. We model the parsing of Candid values in the “Conditions” section using `candid` as well, by treating it as a non-deterministic function.
+
+The principal of the management ic canister is the empty blob (i.e. `aaaaa-aa`):
+....
+ic_principal : principal = ""
+....
+
+==== Envelope Authentication
+
+The following predicate describes when an envelope `E` correctly signs the enclosed request with a key belonging to a user `U`, at time `T`:
+It returns which canister ids this envelope may be used at (as a set of principals).
+....
+verify_envelope({ content = C }, U, T)
+ = { p : p is PrincipalId } if U = anonymous_id
+verify_envelope({ content = C, sender_pubkey = PK, sender_sig = Sig, sender_delegation = DS}, U, T)
+ = TS if U = mk_self_authenticating_id E.sender_pubkey
+ ∧ (PK', TS) = verify_delegations(DS, PK, T, { p : p is PrincipalId })
+ ∧ verify_signature ("\x0Aic-request" · hash_of_map(C), PK')
+
+verify_delegations([], PK, T, TS) = (PK, TS)
+verify_delegations([D] · DS, PK, T, TS)
+ = verify_delegations(C, DS, D.pubkey, T, TS ∩ delegation_targets(DS))
+ if verify_signature PK D.signature ("\x1Aic-request-auth-delegation" · hash_of_map(D.delegation))
+ ∧ D.delegation.expiration ≥ T
+
+delegation_targets(DS)
+ = if D.targets = Unrestricted
+ then { p : p is PrincipalId }
+ else D.targets
+....
+
+==== API Request submission
+
+After a node accepts a request via `/api/v1/submit`, it gets added to the system in the `Received` state.
+
+This may only happen if the signature is valid and is created with a correct key.
+Due to this check, the envelope is discarded after this point.
+
+Requests that have expired are dropped here.
+
+Submitted request:: `E : Envelope`
+Conditions::
+....
+ E.content.canister_id ∈ verify_envelope(E, E.content.sender, S.system_time)
+ E.content ∉ requests
+ S.system_time <= E.content.ingress_expiry
+....
+State after::
+....
+S with
+ requests[E.content] = Received
+....
+
+NOTE: This is not instantaneous (the system takes some time to agree it accepts the request) nor guaranteed (a node could just drop the request, or maybe it did not pass validation). But once it has entered the system like this, it will be acted upon.
+
+==== Request rejection
+
+The system may reject a received message for internal reasons (high load, low resources) or expiry. The precise conditions are not specified here, but the reject code must indicate this to be a system error.
+
+Conditions::
+....
+ S.requests[R] = Received
+ Code = SYS_FATAL or Code = SYS_TRANSIENT
+....
+State after::
+....
+S with
+ requests[R] = Rejected (Code, Msg)
+....
+
+==== Initiating canister calls
+
+A first step in processing a canister update call is to create a `CallMessage` in the message queue.
+
+This is only allowed if the request has not expired and potential rate limiting is respected.
+
+The `request` field of the `FromUser` origin establishes the connection to the api message. One could use the corresponding `hash_of_map` for this purpose, but this formulation is more abstract.
+
+We do not make any guarantees about the order of incoming messages.
+
+Conditions::
+....
+ S.requests[CanisterUpdateCall R] = Received
+ S.system_time <= R.ingress_expiry
+ C = S.canisters[R.canister_id]
+ Arg = { data = R.data; caller = R.sender; time = S.time[R.canister_id] }
+ C.module.get_ingress_bucket (R.method_name, C.wasm_state, Arg, S.balance[R.canister_id]) = Return (assigned_bucket, assigned_cost)
+ C.module.get_ingress_limit_per_second : (C.wasm_state, S.time[R.canister_id], assigned_bucket) = Return assigned_limit
+ assigned_limit = NoLimit || assigned_limit ≥ assigned_cost + bucket_cost(S, R.canister_id, assigned_bucket)
+....
+State after::
+....
+S with
+ requests[CanisterUpdateCall R] = Processing
+ messages =
+ CallMessage {
+ origin = FromUser { request = CanisterUpdateCall R };
+ caller = R.sender;
+ callee = R.canister_id;
+ method_name = R.method_name;
+ arg = R.arg;
+ transferred_cycles = 0;
+ queue = Unordered;
+ bucket = assigned_bucket;
+ cost = assigned_cost;
+ rate_limit_timestamp = S.time[R.canister_id];
+ } · S.messages
+....
+
+This uses the following helper function that sums up the cost of all in-flight messages in the same bucket and within the latest second:
+....
+bucket_cost(S, canister_id, bucket) =
+ ∑ [ M.cost | CallMessage M ∈ S.messages, M.receiver = canister_id,
+ M.bucket = bucket, M.rate_limit_timestamp >= S.time[R.canister_id] - 1s ] +
+ ∑ [ M.cost | FuncMessage M ∈ S.messages, M.receiver = canister_id,
+ M.bucket = bucket, M.rate_limit_timestamp >= S.time[R.canister_id] - 1s ]
+....
+
+==== Calls to stopped/stopping canisters are rejected
+
+A call to a canister which is stopping or stopped is automatically rejected.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage CM · Younger_messages
+ (CM.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ CM.queue)
+ S.canister_status[CM.callee] = Stopped or S.canister_status[CM.callee] = Stopping _
+....
+
+State after::
+....
+ S.messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = S.call_contexts[CM.call_context].origin
+ response = Reject (CANISTER_ERROR, "canister stopped");
+ refunded_cycles = CM.transferred_cycles;
+ }
+....
+
+==== Call context creation
+
+Before invoking a message to a public entry point, some bookkeeping is required:
+
+ * A call context is created, and the method is looked up in the list of exports. This happens for both ingress and inter-canister messages.
+The canister must be running (so not stopped, or stopping).
+
+The position of the message in the queue is unchanged.
+
+This only happens for “real” canisters, not the IC management canister.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage CM · Younger_messages
+ S.canisters[CM.callee] ≠ EmptyCanister
+ S.canister_status[CM.callee] = Running
+ Ctxt_id ∉ dom S.call_contexts
+....
+State after::
+....
+S with
+ messages =
+ Older_messages ·
+ FuncMessage {
+ call_context = Ctxt_id;
+ receiver = CM.callee;
+ entry_point = PublicMethod CM.method_name CM.caller CM.data
+ queue = CM.queue;
+ bucket = CM.bucket;
+ cost = CM.cost;
+ rate_limit_timestamp = CM.rate_limit_timestamp;
+ } ·
+ Younger_messages
+ call_contexts[Ctxt_id] = {
+ canister = CM.callee;
+ origin = CM.origin;
+ responded = false;
+ available_cycles = CM.transferred_cycles;
+ }
+....
+
+We can execute any message that is at the head of its queue, i.e. there is no older message with the same abstract `queue` field. The actual message execution, if successful, may enqueue further messages and -- if the function returns a response -- record this response. The new call and response messages are enqueued at the end.
+
+[#rule-message-execution]
+==== Message execution
+
+The transition models the actual execution of a message, whether it is an initial call to a public method or a response. In either case, a call context already exists (see transition “Call context creation”).
+
+Conditions::
+....
+ S.messages = Older_messages · FuncMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ S.canisters[M.receiver] ≠ EmptyCanister
+ Mod = S.canisters[M.receiver].module
+
+ Visible_balance = S.balances[M.receiver] - MAX_CYCLES_PER_MESSAGE
+ Env = {
+ time = S.time[M.receiver];
+ balance = Visible_balance;
+ certificate = NoCertificate;
+ status = S.status[M.receiver];
+ }
+
+ Available = S.call_contexts[M.call_contexts].available_cycles
+ ( M.entry_point = PublicMethod Name Caller Data
+ Arg = { data = Data; caller = Caller }
+ (F = M.update_methods[M.method_name](Arg, Env, Available)
+ or
+ (F = as_update(Mod.query_methods[M.method_name], Arg, Env))
+ )
+ or
+ ( M.entry_point = Callback Callback Response
+ F = Mod.callbacks(Callback, Response, Env, Available)
+ )
+
+ R = F(S.canisters[M.receiver].wasm_state)
+....
+State after::
+....
+if
+ R = Return res
+ Cycles_used ≤ Max_cycles
+ res.cycles_accepted ≤ Available
+ Cycles_used + ∑ [ call.transferred_cycles | call ∈ res.new_calls ]
+ ≤ S.balances[M.receiver] + res.cycles_accepted
+ (res.response = NoResponse) or (S.call_contexts[M.call_context].responded = false)
+then
+ S with
+ canisters[M.receiver].wasm_state = res.new_state;
+ messages =
+ Older_messages ·
+ Younger_messages ·
+ [ CallMessage {
+ origin = FromCanister {
+ call_context = M.call_context;
+ callback = call.callback
+ };
+ caller = C.callee;
+ callee = call.callee;
+ method_name = call.method_name;
+ arg = call.arg;
+ transferred_cycles = call.transferred_cycles
+ queue = Queue { from = M.receiver; to = call.callee };
+ }
+ | call ∈ res.new_calls ] ·
+ [ ResponseMessage {
+ origin = S.call_contexts[M.call_context].origin
+ response = res.response;
+ refunded_cycles = Available - res.cycles_accepted;
+ }
+ | res.response ≠ NoResponse ]
+
+ if res.response = NoResponse:
+ call_contexts[M.call_context].available_cycles = Available - res.cycles_accepted
+ else
+ call_contexts[M.call_context].responded = true
+ call_contexts[M.call_context].available_cycles = 0
+
+ if res.new_certified_data ≠ NoCertifiedData:
+ certified_data[M.receiver] = res.new_certified_data
+
+ balances[M.receiver] =
+ min(
+ S.balances[M.receiver] + res.cycles_accepted
+ - Cycles_used - ∑ [ call.transferred_cycles | call ∈ res.new_calls ]
+ , MAX_CANISTER_BALANCE)
+else
+ S with
+ messages = Older_messages · Younger_messages
+ balances[M.receiver] = S.balances[M.receiver] - Cycles_used
+....
+
+The cycle consumption of executing this message is modeled via the unspecified `Cycles_used` variable. The maximum number of cycles to consume is also unspecified, and expressed as `Max_cycles`.
+
+This transition detects certain behaviour that will appear as a trap (and which an implementation may implement by trapping directly in a system call):
+
+ * Responding if the present call context has already been responded to
+ * Accepting more cycles than are available on the call context
+ * Sending out more cycles than available to the canister
+ * Consuming more cycles than allowed (and reserved)
+
+If message execution <>, the message gets dropped. No response is generated (as some other message may still fulfill this calling context). Any state mutation is discarded.
+
+If message execution <>, the state is updated and possible outbound calls and responses are enqueued.
+
+Note that returning does _not_ imply that the call associated with this message now _succeeds_ in the sense defined in <>; that would requre a (unique) call to `ic0.reply`.
+Note also that the state changes are persisted even when the system is set to synthesize a <> reject immediately afterward (which happens when this returns without calling `ic0.reply` or `ic0.reject`, the corresponding call has not been responded to and there are no outstanding callbacks, see <>).
+
+The function `as_update` turns a query function into an update function, this is merely a notational trick to simplify the rule
+....
+as_update(f, arg, env) = λ wasm_state →
+ match f(arg, env)(wasm_state) with
+ Trap → Trap
+ Return res → Return {
+ new_state = wasm_state;
+ new_calls = [];
+ response = res;
+ cycles_accepted = 0;
+ new_certified_data = NoCertifiedData;
+ }
+....
+Note that by construction, a query function will either trap or return with a response; it will never send calls, and it will never change the state of the canister.
+
+[#rule-starvation]
+==== Call context starvation
+
+If there is no call, downstream calling context or response that could possibly fulfill a calling context, then a reject is synthesized. The error message below is _not_ indicative. In particular, if the system has an idea about _why_ this starved, it can put that in there (e.g. the initial message handler trapped with an out-of-memory access).
+
+Conditions::
+....
+ S.call_contexts[Ctxt_id].responded = false
+ ∀ CallMessage M ∈ S.messages. M.origin.calling_context ≠ Ctxt_id
+ ∀ ResponseMessage M ∈ S.messages. M.origin.calling_context ≠ Ctxt_id
+ ∀ ctxt_ids.
+ S.call_contexts[ctxt_ids].responded = false
+ ==> S.call_contexts[ctxt_ids].origin.calling_context ≠ Ctxt_id
+....
+State after::
+....
+S with
+ call_contexts[Ctxt_id].responded = true
+ call_contexts[Ctxt_id].available_cycles = 0
+ messages =
+ S.messages ·
+ ResponseMessage {
+ origin = S.call_contexts[Ctxt_id].origin;
+ response = Reject (CANISTER_ERROR, "starvation");
+ refunded_cycles = S.call_contexts[Ctxt_id].available_cycles
+ }
+....
+
+==== Call context removal
+
+If there is no call, downstream calling context or response that references a call context, and the call context has been replied to, then the call context can be removed.
+
+Conditions::
+....
+ S.call_contexts[Ctxt_id].responded = true
+ ∀ CallMessage M ∈ S.messages. M.origin.calling_context ≠ Ctxt_id
+ ∀ ResponseMessage M ∈ S.messages. M.origin.calling_context ≠ Ctxt_id
+ ∀ ctxt_ids.
+ S.call_contexts[ctxt_ids].responded = false
+ ==> S.call_contexts[ctxt_ids].origin.calling_context ≠ Ctxt_id
+....
+State after::
+....
+S with
+ call_contexts[Ctxt_id] = (deleted)
+....
+
+
+==== IC Management Canister: Canister creation
+
+The system chooses an appropriate canister id and instantiates a new (empty) canister identified by this id. The issuer of the request is set to be the controller of newly created canister. The canister status is set to 'Running'. All cycles on this call are now the canister's initial cycles.
+
+This is also when the System Time of the new canister starts ticking.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'create_canister'
+ M.arg = candid()
+ is_system_assigned CanisterId
+ CanisterId ∉ dom S.canisters
+....
+State after::
+....
+S with
+ canisters[CanisterId] = EmptyCanister
+ time[CanisterId] = CurrentTime
+ controllers[CanisterId] = M.caller
+ balances[CanisterId] = M.transferred_cycles
+ certified_data[CanisterId] = ""
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid({canister_id = CanisterId}))
+ refunded_cycles = 0
+ }
+ canister_status[CanisterId] = Running
+....
+
+This uses the predicate
+....
+is_system_assigned : Principal -> Bool
+....
+which characterizes all system-assigned ids.
+
+To avoid clashes with potential user ids or is derived from users or canisters, we require (somewhat handwavy) that
+
+ * `is_system_assigned (mk_self_authenticating_id pk) = false` for possible public keys `pk` and
+ * `is_system_assigned (mk_derived_id p dn) = false` for any `p` that could be a user id or canister id.
+ * `is_system_assigned p = false` for `|p| > 29`.
+
+==== IC Management Canister: Canister status
+
+The controller of a canister can check for its status (i.e. one of Running, Stopping, or Stopped).
+
+The `Memory_size` is the (in this specification underspecified) total size of storage in bytes.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'canister_status'
+ M.arg = candid(A)
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = candid({
+ status = S.canister_status[A.canister_id];
+ module_hash =
+ if S.canisters[A.canister_id] = EmptyCanister
+ then null
+ else ?(SHA-265(S.canisters[A.canister_id].raw_module));
+ controller = S.controllers[A.canister_id];
+ memory_size = Memory_size;
+ cycles = S.balance[A.canister_id];
+ })
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Code installation
+
+Only the controller of the given canister can install code. This transition installs new code over an empty or existing canister. This involves invoking the `canister_init` system method (see <>), which must succeed and must not invoke other methods.
+
+The `compute_allocation` and `memory_allocation` are ignored in this abstract model of the Internet Computer, as it does not address questions of performance or scheduling.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_princpal
+ M.method_name = 'install_code'
+ M.arg = candid(A)
+ Mod = parse_wasm_mod(A.wasm_module)
+ (A.mode = install && S.canisters[A.canister_id] = EmptyCanister)
+ or A.mode = reinstall
+ M.caller = S.controllers[A.canister_id]
+ Arg = {
+ data = A.arg;
+ caller = M.caller;
+ }
+ Env = {
+ time = S.time[M.receiver];
+ balance = S.balances[M.receiver];
+ certificate = NoCertificate;
+ status = S.status[M.receiver];
+ }
+ Mod.init(A.canister_id, Arg, Env) = Return New_state
+....
+State after::
+....
+S with
+ canisters[A.canister_id] =
+ { wasm_state = New_state; module = Mod; raw_module = A.wasm_module }
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Code upgrade
+
+Only the controller of the given canister can install new code. This changes the code of an _existing_ canister, preserving the state in the stable memory. This involves invoking the `canister_pre_upgrade` system method on the old and `canister_post_upgrade` system method on the new canister, which must succeed and must not invoke other methods.
+
+The `compute_allocation` and `memory_allocation` are ignored in this abstract model of the Internet Computer, as it does not address questions of performance or scheduling.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'install_code'
+ M.arg = candid(A)
+ Mod = parse_wasm_mod(A.wasm_module)
+
+ A.mode = upgrade
+ S.canisters[A.canister_id] ≠ EmptyCanister
+ M.caller = S.controllers[A.canister_id]
+ S.canisters[A.canister_id] = { wasm_state = Old_state; module = Old_module }
+ Env = {
+ time = S.time[M.receiver];
+ balance = S.balances[M.receiver];
+ certificate = NoCertificate;
+ status = S.status[M.receiver];
+ }
+ Old_module.pre_upgrade(Old_State, M.caller, Env) = Return Stable_memory
+ Arg = {
+ data = A.arg;
+ caller = M.caller;
+ }
+ Mod.post_upgrade(A.canister_id, Stable_memory, Arg, Env) = Return New_state
+....
+State after::
+....
+S with
+ canisters[A.canister_id] =
+ { wasm_state = New_state; module = Mod; raw_module = A.wasm_module }
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Setting controllers
+
+Only the controller of the given canister can modify the controller field.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'set_controller'
+ M.arg = candid(A)
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ controllers[A.canister_id] = A.new_controller
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Stopping a canister
+
+The controller of a canister can stop a canister. Stopping a canister goes through two steps. First, the status of the canister is set to `Stopping`; as explained above, a stopping canister rejects all incoming requests and continues processing outstanding responses. When a stopping canister has no more open call contexts, its status is changed to `Stopped` and a response is generated. Note that when processing responses, a stopping canister can make calls to other canisters and thus create new call contexts. In addition, a canister which is stopped, or stopping will accept (and respond) to further `stop_canister` requests.
+
+We encode this behavior via three (types of) transitions:
+
+1. First, any `stop_canister` call sets the state of the canister to `Stopping`; we record in the status the origin (and cycles) of all `stop_canister` calls which arrive at the canister while it is stopping (or stopped).
+2. Next, when the canister has no open call contexts (so, in particular, all outstanding responses to the canister have been processed), the status of the canister is set to `Stopped`.
+3. Finally, each pending `stop_canister` call (which are encoded in the status) is responded to, to indicate that that the canister is stopped.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'stop_canister'
+ M.arg = candid(A)
+ S.canister_status[A.canister_id] = Running
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ messages = Older_messages · Younger_messages
+ S.status[A.canister_id] = Stopping [(M.origin, M.transferred_cycles)]
+....
+
+The next two transition record any additional 'stop_canister' requests that arrive at a stopping (or stopped) canister in its status.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'stop_canister'
+ M.arg = candid(A)
+ S.canister_status[A.canister_id] = Stopping Origins
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ messages = Older_messages · Younger_messages
+ S.status[A.canister_id] = Stopping (Origins · (M.origin, M.transferred_cycles))
+....
+
+
+The status of a stopping canister which has no open call contexts is set to `Stopped`, and all pending `stop_canister` calls are replied to.
+
+Conditions::
+....
+ S.canister_status[A.canister_id] = Stopping Origins
+ ∀ Ctxt_id. S.call_contexts[Ctxt_id].canister ≠ A.canister_id
+....
+State after::
+....
+ S.canister_status[CanisterId] = Stopped
+ S.messages = Messages ·
+ [ ResponseMessage {
+ origin = O
+ response = Accepted (candid())
+ refunded_cycles = C
+ }
+ | (O, C) ∈ Origins
+ ]
+....
+
+NOTE: Sending a `stop_canister` message to an already stopped canister is acknowledged (i.e. responded with success), but is otherwise a no-op:
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'stop_canister'
+ M.arg = candid(A)
+ S.canister_status[A.canister_id] = Stopped
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ messages = Older_messages · Younger_messages
+ S.messages = Messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ }
+....
+
+==== IC Management Canister: Starting a canister
+
+The controller of a canister can start a stopped canister. If the canister is already running, the command has no effect on the canister.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'start_canister'
+ M.arg = candid(A)
+ S.status[A.canister_id] = Running or S.status[A.canister_id] = Stopped
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ S.status[A.canister_id] = Running
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage{
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+
+If the status of the canister was 'Stopping', then the canister status is set to `Running`. The pending `stop_canister` request(s) are rejected.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'start_canister'
+ M.arg = candid(A)
+ S.status[A.canister_id] = Stopping Origins
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ S.status[A.canister_id] = Running
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage{
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ } ·
+ [ ResponseMessage {
+ origin = O
+ response = Reject (CANISTER_REJECT, 'Canister has been restarted')
+ refunded_cycles = C
+ }
+ | (O, C) ∈ Origins
+ ]
+....
+
+==== IC Management Canister: Canister deletion
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'delete_canister'
+ M.arg = candid(A)
+ S.canister_status[A.canister_id] = Stopped
+ M.caller = S.controllers[A.canister_id]
+....
+State after::
+....
+S with
+ canisters[CanisterId] = (deleted)
+ controllers[CanisterId] = (deleted)
+ canister_status[CanisterId] = (deleted)
+ time[CanisterId] = (deleted)
+ balances[CanisterId] = (deleted)
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Depositing cycles
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'deposit_cycles'
+ M.arg = candid(A)
+ M.caller = S.controllers[A.canister_id]
+ Cycle_cost ≤ S.balances[A.canister_id] + M.transferred_cycles
+....
+State after::
+....
+S with
+ balances[CanisterId] =
+ min(S.balances[A.canister_id] + M.transferred_cycles, MAX_CANISTER_BALANCE)
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid())
+ refunded_cycles = 0
+ }
+....
+
+==== IC Management Canister: Random numbers
+
+The management canister can produce pseudo-random bytes. It always returns a 32-byte `blob`:
+
+The precise guarantees around the randomness, e.g. unpredictability, are not captured in this formal semantics.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'raw_rand'
+ M.arg = candid()
+ |B| = 32
+....
+State after::
+....
+S with
+ controllers[A.canister_id] = A.new_controller
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid(B))
+ refunded_cycles = M.transferred_cycles
+ }
+....
+
+==== IC Management Canister: Canister creation with cycles
+
+This is a variant of `create_canister`, which sets the initial cycle balance based on the `amount` argument.
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'provisional_create_canister_with_cycles'
+ M.arg = candid(A)
+ is_system_assigned CanisterId
+ CanisterId ∉ dom S.canisters
+....
+State after::
+....
+S with
+ canisters[CanisterId] = EmptyCanister
+ time[CanisterId] = CurrentTime
+ controllers[CanisterId] = M.caller
+ balances[CanisterId] = min(A.amount, MAX_CANISTER_BALANCE)
+ certified_data[CanisterId] = ""
+ messages = Older_messages · Younger_messages ·
+ ResponseMessage {
+ origin = M.origin
+ response = Accepted (candid({canister_id = CanisterId}))
+ transferred_cycles = M.transferred_cycles
+ }
+ canister_status[CanisterId] = Running
+....
+
+==== IC Management Canister: Top up canister
+
+Conditions::
+....
+ S.messages = Older_messages · CallMessage M · Younger_messages
+ (M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
+ M.callee = ic_principal
+ M.method_name = 'provisional_top_up_canister'
+ M.arg = candid(A)
+ A.canister_id ∈ dom S.canisters
+....
+State after::
+....
+S with
+ balances[CanisterId] = min(balances[CanisterId] + A.amount, MAX_CANISTER_BALANCE)
+....
+
+
+==== Callback invocation
+
+When an inter-canister call has been responded to, we can queue the call to the callback.
+
+This “bookkeeping transition” must be immediately followed by the corresponding “Message execution” transition.
+
+Conditions::
+....
+ S.messages = Older_messages · ResponseMessage RM · Younger_messages
+ RM.origin = FromCanister {
+ call_context = Ctxt_id
+ callback = Callback
+ }
+....
+State after::
+....
+S with
+ balances[S.call_contexts[Ctxt_id].canister] =
+ min(balances[S.call_contexts[Ctxt_id].canister] + RM.refunded_cycles,
+ MAX_CANISTER_BALANCE)
+ messages =
+ Older_messages ·
+ FuncMessage {
+ call_context = Ctxt_id2
+ receiver = C
+ entry_point = Callback Callback FM.response RM.refunded_cycles
+ queue = Unordered
+ bucket = None
+ cost = 0
+ rate_limit_timestamp = None
+ } ·
+ Younger_messages
+....
+
+==== Respond to user request
+
+When an ingress method call has been responded to, we can record the response in the list of queries.
+
+Conditions::
+....
+ S.requests[M] = Processing
+ S.messages = Older_messages · ResponseMessage RM · Younger_messages
+ RM.origin = FromUser { request = M }
+....
+State after::
+....
+S with
+ messages = Older_messages · Younger_messages
+ requests[M] =
+ | Replied R if response = Reply R
+ | Rejected R if response = Reject R
+....
+
+NB: The refunded cycles, `RM.refunded_cycles` are, by construction, empty.
+
+==== Request clean up
+
+The system will keep the data for a completed or rejected request around for a certain, implementation defined amount of time, to allow clients to poll for the data. After that time, the data of the request will be dropped:
+
+Conditions::
+....
+ (S.requests[M] = Replied _) or (S.requests[M] = Rejected _)
+....
+State after::
+....
+S with
+ requests[M] = Done
+....
+
+
+At the same or some later point, the request will be removed from memory of the system. This must happen no earlier than the ingress expiry time set in the request.
+
+Conditions::
+....
+ (S.requests[M] = Replied _) or (S.requests[M] = Rejected _) or (S.requests[M] = Done)
+ M.ingress_expiry < S.system_time
+....
+State after::
+....
+S with
+ requests[M] = (deleted)
+....
+
+==== Time progressing
+
+Time progresses. Abstractly, it does so independently for each canister, and in unspecified intervals.
+
+Conditions::
+....
+ T0 = S.time[CanisterId]
+ T1 > T0
+....
+State after::
+....
+S with
+ time[CanisterId] = T1
+....
+
+Similarly, the system time, used to expire requests, progresses:
+
+Conditions::
+....
+ T0 = S.system_time
+ T1 > T0
+....
+State after::
+....
+S with
+ system_time = T1
+....
+
+==== Read: query call
+
+Canister query calls can be executed directly. They can only be executed against canisters which are `Running`.
+
+During the execution of a query call, a certificate is provided to the canister that is valid, is current (or “recent enough”; the specification is currently vague about how old the certificate may be) and reveals the canister’s <>.
+
+Submitted request:: `E`
+Conditions::
+....
+ E.content = CanisterQuery Q
+ Q.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
+ S.system_time <= Q.ingress_expiry
+ S.canisters[Q.canister_id] ≠ EmptyCanister
+ S.canister_status[Q.canister_id] = Running
+ C = S.canisters[Q.canister_id]
+ F = C.module.query_methods[Q.method_name]
+ Arg = {
+ data = Q.arg;
+ caller = Q.sender;
+ }
+ verify_cert(Cert)
+ lookup(["canister",Q.canister_id,"certified_data"], Cert) = Found S.certified_data[Q.canister_id]
+ lookup(["time"], Cert) = Found S.system_time // or “recent enough”
+ Env = {
+ time = S.time[Q.receiver];
+ balance = S.balances[Q.canister_id];
+ certificate = Cert;
+ status = S.status[Q.receiver];
+ }
+....
+Read response::
+* If `F(Arg, Env) = Trap` then
++
+....
+{status: failed; error: "Query execution trapped"}
+....
+* Else if `F(Arg, Env) = Return (Reject (code, msg))` then
++
+....
+{status: rejected; reject_code: : reject_message: }
+....
+* Else if `F(Arg, Env) = Return (Reply R)` then
++
+....
+{status: success; reply: { arg : } }
+....
+
+==== Read: Certified state reads
+
+The user can read elements of the _state tree_, using a `read_state` request.
+
+Submitted request:: `E`
+Conditions::
+....
+ E.content = ReadState RS
+ TS = verify_envelope(E, RS.sender, S.system_time)
+ S.system_time <= RS.ingress_expiry
+ ∀ path ∈ RS.paths. may_read_path(S, R.sender, path)
+ ∀ ["request_status", Rid] · _ ∈ RS.paths. ∃ R ∈ S.requests ∧ hash_of_map(R) = Rid ∧ R.canister_id ∈ TS
+....
+Read response::
+A record with
+* `{certificate: C}`
+
+The predicate `may_read_path` is defined as follows, implementing the access control outlined in <>:
+....
+may_read_path(S, _, ["time"]) = True
+may_read_path(S, _, ["request_status", Rid] · _) =
+ if ∃ R ∈ S.requests ∧ hash_of_map(R) = Rid
+ then RS.sender = R.sender
+ else True
+may_read_path(S, _, _) = False
+....
+
+The response is a certificate `cert`, as specified in <>, which passes `verify_cert` (assuming `S.root_key` as the root of trust), and where for every `path` documented in <> that is a suffix of a path in `RS.paths` or of `["time"]`, we have
+....
+lookup(path, cert) = lookup_in_tree(path, state_tree(S))
+....
+where `state_tree` constructs the a labeled tree from the system state `S` and the (so far underspecified) set of subnets `subnets`, as per <>
+....
+state_tree(S) = {
+ "time": S.system_time;
+ "request_id": { request_id(R): request_status_tree(S) | (R ↦ S) ∈ S.requests };
+ "subnet": { subnet_id : { "public_key" : pub } | (subnet_id, subnet_pk) ∈ subnets };
+}
+
+request_status_tree(Received) =
+ { "status": "received" }
+request_status_tree(Processing) =
+ { "status": "processing" }
+request_status_tree(Rejected (code,msg)) =
+ { "status": "rejected"; "reject_code": code; "reject_message": msg }
+request_status_tree(Replied arg) =
+ { "status": "replied"; "reply": arg }
+request_status_tree(Done) =
+ { "status": "Done" }
+....
+and where `lookup_in_tree` is a function that returns the value or `Absent` as appropriately.
+
+[#concrete-canisters]
+=== Abstract Canisters to System API
+
+In Section <> we introduced an abstraction over the interface to a canister, to avoid cluttering the abstract specification of the Internet Computer from WebAssembly details. In this section, we will fill the gap and explain how the abstract canister interface maps to the <> and the WebAssembly concepts as defined in the https://webassembly.github.io/spec/core/index.html[WebAssembly specification].
+
+==== The concrete `WasmState`
+
+The abstract `WasmState` above models the WebAssembly _store_ `S`, which encompasses the functions, tables, memories and globals of the WebAssembly program, plus additional data maintained by the system, such as the stable memory:
+....
+WasmState = {
+ store : S; // a store as per WebAssembly spec
+ self_id : CanId;
+ stable_mem : Blob
+}
+....
+
+As explained in Section “<>”, the WebAssembly module imports at most _one_ memory and at most _one_ table; in the following, _the_ memory (resp. table) and the fields `mem` and `table` of `S` refer to that. Any system call that accesses the memory (resp. table) will trap if the module does not import the memory (resp. table).
+
+We model `mem` as an array of bytes, and `table` as an array of execution functions.
+
+The abstract `Callback` type above models an entry point for responses:
+....
+Closure = {
+ fun : i32,
+ env : i32,
+}
+
+Callback = {
+ on_reply : Closure;
+ on_reject : Closure;
+ on_cleanup : Closure | NoClosure;
+}
+....
+
+==== The execution state
+
+We can model the execution of WebAssembly functions as stateful functions that have access to the WebAssembly store. In order to also model the behavior of the system imports, which have access to additional data structures, we extend the state as follows:
+....
+Params = {
+ data : NoData | Blob;
+ caller : NoCaller | Principal;
+ reject_code : 0 | SYS_FATAL | SYS_TRANSIENT | …;
+ reject_message : Text;
+ sysenv : Env;
+ cycles_refundend : Nat;
+ ingress_rate_bucket : NoBucket | Blob;
+}
+ExecutionState = {
+ wasm_state : WasmState;
+ params : Params;
+ response : NoResponse | Response;
+ cycles_accepted : Nat;
+ cycles_available : Nat;
+ balance : Funds;
+ reply_params : { arg : Blob };
+ pending_call : MethodCall | NoPendingCall;
+ calls : List MethodCall;
+ new_certified_data : NoCertifiedData | Blob;
+ bucket_cost : NoBucket | BucketCost
+ rate_limit : NoLimit | i64
+}
+....
+
+This allows us to model WebAssembly functions, including host-provided imports, as functions with implicit mutable access to an `ExecutionState`, dubbed _execution functions_.
+Syntactically, we express this using an implicit argument of type `ref ExecutionState` in angle brackets (e.g. `func(x)` for the invocation of a WebAssembly function with type `+(x : i32) -> ()+`). The lifetime of the `ExecutionState` data structure is that of one such function invocation.
+
+WARNING: It is nonsensical to pass to an execution function a WebAssembly store `S` that comes from a different WebAssembly module than one defining the function.
+
+==== The concrete `CanisterModule`
+
+Finally we can specify the abstract `CanisterModule` that models a concrete WebAssembly module.
+
+* The `initial_wasm_store` mentioned below is the store of the WebAssembly module after _instantiation_ (as per WebAssembly spec) of the WasmModule contained in the <>, including executing a potential `(start)` function.
+
+* For more convenience when creating a new `ExecutionState`, we define the following partial records:
++
+....
+empty_params = {
+ data = NoData;
+ caller = NoCaller;
+ reject_code = 0;
+ reject_message = "";
+ cycles_refundend = 0;
+}
+
+empty_execution_state = {
+ wasm_state = (undefined);
+ params = (undefined);
+ response = NoResponse;
+ cycles_accepted = 0;
+ cycles_available = 0;
+ balance = 0;
+ reply_params = { arg = "" };
+ pending_call = NoPendingCall;
+ calls = [];
+ new_certified_data = NoCertifiedData;
+ bucket_cost = NoBucket;
+ rate_limit = NoLimit;
+}
+....
+
+
+* The `init` field of the `CanisterModule` is defined as follows:
++
+If the WebAssembly module does not export a function called under the name `canister_init`, then the argument blob is ignored and the `initial_wasm_store` is returned:
++
+....
+init = λ (self_id, arg, sysenv) →
+ Return { store = initial_wasm_store; self_id = self_id; stable_mem = "" }
+....
++
+Otherwise, if the WebAssembly module exports a function `func` under the name `canister_init`, it is
++
+....
+init = λ (self_id, arg, sysenv) →
+ let es = ref {empty_execution_state with
+ wasm_state = { store = initial_wasm_store; self_id = self_id; stable_mem = "" }
+ params = empty_params with { data = arg.data; caller = arg.caller; sysenv }
+ balance = sysenv.balance
+ }
+ try func() with Trap then Trap
+ if es.performed_calls ≠ [] then Trap
+ if es.response ≠ NoResponse then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return es.wasm_state
+....
++
+This formulation checks afterwards that the system calls `call.perform` or `msg.reply` were not invoked; an implementation can of course trap as soon as these system calls are invoked.
+
+* The `pre_upgrade` field of the `CanisterModule` is defined as follows:
++
+If the WebAssembly module does not export a function called under the name `canister_pre_upgrade`, then it simply returns the stable memory:
++
+....
+pre_upgrade = λ (old_state, caller, sysenv) → Return old_state.stable_mem
+....
++
+Otherwise, if the WebAssembly module exports a function `func` under the name `canister_pre_upgrade`, it is
++
+....
+pre_upgrade = λ (old_state, caller, sysenv) →
+ let es = ref {empty_execution_state with
+ wasm_state = old_state
+ params = { empty_params with caller = caller; sysenv }
+ balance = sysenv.balance
+ }
+ try func() with Trap then Trap
+ if es.performed_calls ≠ [] then Trap
+ if es.response ≠ NoResponse then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return es.wasm_state.stable_mem
+....
+
+
+* The `post_upgrade` field of the `CanisterModule` is defined as follows:
++
+If the WebAssembly module does not export a function called under the name `canister_post_upgrade`, then the argument blob is ignored and the `initial_wasm_store` is returned:
++
+....
+post_upgrade = λ (self_id, stable_mem, arg, sysenv) →
+ Return { store = initial_wasm_store; self_id = self_id; stable_mem = stable_mem }
+....
++
+Otherwise, if the WebAssembly module exports a function `func` under the name `canister_post_upgrade`, it is
++
+....
+post_upgrade = λ (self_id, stable_mem, arg, sysenv) →
+ let es = ref {empty_execution_state with
+ wasm_state = { store = initial_wasm_store; self_id = self_id; stable_mem = stable_mem }
+ params = { empty_params with data = arg.data; caller = arg.caller; sysenv }
+ balance = sysenv.balance
+ }
+ try func() with Trap then Trap
+ if es.performed_calls ≠ [] then Trap
+ if es.response ≠ NoResponse then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return es.wasm_state
+....
+
+* The partial map `update_methods` of the `CanisterModule` is defined for all method names `method` for which the WebAssembly program exports a function `func` named `canister_update `, and has value
++
+....
+update_methods[method] = λ (arg, sysenv, available) → λ wasm_state →
+ let es = ref {empty_execution_state with
+ wasm_state = wasm_state;
+ params = empty_params with { data = arg.data; caller = arg.caller; sysenv }
+ balance = sysenv.balance
+ cycles_available = arg.cycles;
+ }
+ try func() with Trap then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return {
+ new_state = es.wasm_state;
+ new_calls = es.calls;
+ response = es.response;
+ cycles_accepted = es.cycles_accepted;
+ new_certified_data = es.new_certified_data
+ }
+....
+
+* The partial map `query_methods` of the `CanisterModule` is defined for all method names `method` for which the WebAssembly program exports a function `func` named `canister_query `, and has value
++
+....
+query_methods[method] = λ (arg, sysenv) → λ wasm_state →
+ let es = ref {empty_execution_state with
+ wasm_state = wasm_state;
+ params = empty_params with { data = arg.data; caller = arg.caller; sysenv }
+ balance = sysenv.balance
+ }
+ try func() with Trap then Trap
+ if es.cycles_accepted ≠ 0 then Trap
+ if es.calls ≠ () then Trap
+ if es.response = NoResponse then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return es.response;
+....
++
+This formulation checks afterwards that the system call `ic0.call_perform` was not invoked; an implementation can of course trap already when these system calls have been invoked.
++
+By construction, the (possibly modified) `es.wasm_state` is discarded.
+
+* The function `callbacks` of the `CanisterModule` is defined as follows
++
+....
+callbacks = λ(callbacks, response, sysenv, available) → λ wasm_state →
+ let params0 = { empty_params with
+ sysenv
+ cycles_received = refund;
+ }
+ let (fun, env, params) = match response with
+ Reply data ->
+ (callbacks.on_reply.fun, callbacks.on_reply.env,
+ { params0 with data})
+ Reject (reject_code, reject_message)->
+ (callbacks.on_reject.fun, callbacks.on_reject.env,
+ { params0 with reject_code; reject_message})
+ try
+ if fun > |es.wasm_state.store.table| then Trap
+ let func = es.wasm_state.store.table[fun]
+ if typeof(func) ≠ func (i32) -> () then Trap
+
+ let es = ref {empty_execution_state with
+ wasm_state = wasm_state;
+ params = params;
+ balance = sysenv.balance;
+ cycles_available = available;
+ }
+ func(env)
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ Return {
+ new_state = es.wasm_state;
+ new_calls = es.calls;
+ response = es.response;
+ cycles_accepted = es.cycles_accepted;
+ new_certified_data = es.certified_data;
+ }
+ with Trap
+ if callbacks.on_cleanup = NoClosure then Trap
+ if callbacks.on_cleanup.fun > |es.wasm_state.store.table| then Trap
+ let func = es.wasm_state.store.table[callbacks.on_cleanup.fun]
+ if typeof(func) ≠ func (i32) -> () then Trap
+
+ let es = ref { empty_execution_state with
+ wasm_state;
+ }
+ func(callbacks.on_cleanup.env)
+ Return {
+ new_state = es.wasm_state;
+ new_calls = [];
+ response = NoResponse;
+ cycles_accepted = 0;
+ }
+....
++
+Note that if the initial callback handler traps, the cleanup callback (if
+present) is executed, and the canister has the chance to update its state.
+
+* The `get_ingress_bucket` field of the `CanisterModule` is defined as follows.
++
+If the WebAssembly module does not export a function called under the name `canister_get_ingress_bucket`, then access is always granted:
++
+....
+get_ingress_bucket = λ (method_name, wasm_state, arg, sysenv) →
+ Return { bucket = None; cost = 0 }
+....
+Otherwise, if the WebAssembly module exports a function `func` under the name `canister_get_ingress_bucket`, it is
++
+....
+get_ingress_bucket = λ (method_name, wasm_state, arg, sysenv) →
+ let es = ref {empty_execution_state with
+ wasm_state = wasm_state;
+ params = empty_params with {
+ data = arg.data;
+ caller = arg.caller;
+ sysenv
+ }
+ balance = sysenv.balance;
+ funds_available = no_funds; // ingress requests have no funds
+ }
+ try func() with Trap then Trap
+ if es.calls ≠ () then Trap
+ if es.response ≠ NoResponse then Trap
+ if es.rate_limit ≠ NoLimit then Trap
+ if es.bucket_cost = NoBucket then Trap
+ Return es.bucket_cost;
+....
+
+* The `get_ingress_limit_per_second` field of the `CanisterModule` is defined as follows.
++
+If the WebAssembly module does not export a function called under the name `canister_get_ingress_limit_per_second`, then access is always granted:
++
+....
+get_ingress_limit_per_second = λ (wasm_state, time, sysenv, bucket) →
+ Return NoLimit
+....
+Otherwise, if the WebAssembly module exports a function `func` under the name `canister_get_ingress_limit_per_second`, it is
++
+....
+get_ingress_limit_per_second = λ (wasm_state, time, sysenv, bucket) →
+ let es = ref {empty_execution_state with
+ wasm_state = wasm_state;
+ params = empty_params with { sysenv, ingress_rate_bucket = bucket };
+ balance = sysenv.balance;
+ }
+ try func() with Trap then Trap
+ if es.calls ≠ () then Trap
+ if es.response ≠ NoResponse then Trap
+ if es.bucket_cost ≠ NoBucket then Trap
+ if es.rate_limit = NoLimit then Trap
+ Return es.rate_limit;
+....
+
+==== Helper functions
+
+In the following section, we use the these helper functions
+
+....
+copy_to_canister(dst : i32, offset : i32, size : i32, data : blob) =
+ if offset+size > |data| then Trap
+ if dst+size > |es.wasm_state.store.mem| then Trap
+ es.wasm_state.store.mem[dst..dst+size] := data[offset..offset+size]
+
+copy_from_canister(src : i32, size : i32) blob =
+ if src+size > |es.wasm_state.store.mem| then Trap
+ return es.wasm_state.store.mem[src..src+size]
+....
+
+==== System imports
+
+Upon _instantiation_ of the WebAssembly module, we can provide the following functions as imports.
+
+The pseudo-code below does _not_ explicitly enforce the restrictions of which imports are available in which contexts; for that the table in <> is authorative, and is assumed to be part of the implementation.
+
+....
+ic0.msg_arg_data_size() : i32 =
+ return |es.params.arg|
+
+ic0.msg_arg_data_copy(dst:i32, offset:i32, size:i32) =
+ copy_to_canister(dst, offset, size, es.param.arg)
+
+ic0.msg_caller_size() : i32 =
+ return |es.params.caller|
+
+ic0.msg_caller_copy(dst:i32, offset:i32, size:i32) : i32 =
+ copy_to_canister(dst, offset, size, es.params.caller)
+
+ic0.msg_reject_code() : i32 =
+ es.params.reject_code
+
+ic0.msg_reject_msg_size() : i32 =
+ return |es.params.reject_msg|
+
+ic0.msg_reject_msg_copy(dst:i32, offset:i32, size:i32) : i32 =
+ copy_to_canister(dst, offset, size, es.params.reject_msg)
+
+ic0.msg_reply_data_append(src : i32, size : i32) =
+ if es.response ≠ NoResponse then Trap
+ es.reply_params.arg := es.reply_params.arg · copy_from_canister(src, size)
+
+ic0.msg_reply() =
+ if es.response ≠ NoResponse then Trap
+ es.response := Reply (es.reply_params.arg)
+ es.cycles_available := 0
+
+ic0.msg_reject(src : i32, size : i32) =
+ if es.response ≠ NoResponse then Trap
+ es.response := Reject (CANISTER_REJECT, copy_from_canister(src, size))
+ es.cycles_available := 0
+
+ic0.msg_cycles_available() : i64 =
+ return es.cycles_available
+
+ic0.msg_cycles_refunded() : i64 =
+ return es.params.cycles_refundend
+
+ic0.ingress_rate_bucket_size() =
+ return |es.params.ingress_rate_bucket|
+
+ic0.ingress_rate_bucket_copy(dst : i32, offset : i32, size : i32) =
+ copy_to_canister(dst, offset, size, es.params.ingress_rate_bucket)
+
+ic0.return_ingress_bucket(bucket_src : i32, bucket_size : i32, cost : i64) =
+ if es.bucket_cost ≠ NoBucket then Trap
+ if bucket_size > 64 then Trap
+ es.bucket_cost.bucket = copy_from_canister(bucket_src, bucket_size)
+ es.bucket_cost.cost = cost
+
+ic0.return_ingress_limit_per_second(limit : i64) =
+ if es.rate_limit ≠ NoLimit then Trap
+ es.rate_limit = limit
+
+ic0.msg_cycles_accept( max_amount : i64 ) : i64 =
+ let amount = min(max_amount, es.cycles_available, MAX_CANISTER_BALANCE - es.balance)
+ es.cycles_available := es.cycles_available - amount
+ es.cycles_accepted := es.cycles_accepted + amount
+ es.balance := es.balance + amount
+ return amount
+
+ic0.canister_self_size() : i32 =
+ return |es.wasm_state.self_id|
+
+ic0.canister_self_copy(dst:i32, offset:i32, size:i32) =
+ copy_to_canister(dst, offset, size, es.wasm_state.self_id)
+
+ic0.canister_cycle_balance() : i64 =
+ return es.balance
+
+ic0.canister_status() : i32 =
+ match es.params.sysenv.canister_status with
+ Running -> return 1
+ Stopping -> return 2
+ Stopped -> return 3
+
+ic0.call_new(
+ callee_src : i32,
+ callee_size : i32,
+ name_src : i32,
+ name_size : i32,
+ reply_fun : i32,
+ reply_env : i32,
+ reject_fun : i32,
+ reject_env : i32,
+ ) =
+ discard_pending_call()
+
+ callee := copy_from_canister(callee_src, callee_size);
+ method_name := copy_from_canister(name_src, name_size);
+
+ if reply_fun > |es.wasm_state.store.table| then Trap
+ if typeof(es.wasm_state.store.table[reply_fun]) ≠ func (anyref, i32) -> () then Trap
+
+ if reject_fun > |es.wasm_state.store.table| then Trap
+ if typeof(es.wasm_state.store.table[reject_fun]) ≠ func (anyref, i32) -> () then Trap
+
+ es.pending_call = MethodCall {
+ callee = callee;
+ method_name = callee;
+ arg = "";
+ transferred_cycles = 0;
+ callback = Callback {
+ on_reply = Closure { fun = reply_fun; env = reply_env }
+ on_reject = Closure { fun = reject_fun; env = reject_env }
+ on_cleanup = NoClosure
+ };
+ bucket = None;
+ cost = 0;
+ rate_limit_time = None
+ }
+
+ic0.call_data_append (src : i32, size : i32) =
+ if es.pending_call = NoPendingCall then Trap
+ es.pending_call.arg := es.pending_call.arg · copy_from_canister(src, size)
+
+ic0.call_on_cleanup (fun : i32, env : i32) =
+ if fun > |es.wasm_state.store.table| then Trap
+ if typeof(es.wasm_state.store.table[fun]) ≠ func (anyref, i32) -> () then Trap
+ if es.pending_call = NoPendingCall then Trap
+ if es.pending_call.callback.on_cleanup ≠ NoClosure then Trap
+ es.pending_call.callback.on_cleanup := Closure { fun = fun; env = env}
+
+ic0.call_cycles_add(amount : i32) =
+ if es.pending_call = NoPendingCall then Trap
+ if amount > es.balance then Trap
+
+ es.balance := es.balance - amount
+ es.pending_call.transferred_cycles := es.pending_call.transferred_cycles + amount
+
+ic0.call_peform() : ( err_code : i32 ) =
+ if es.pending_call = NoPendingCall then Trap
+
+ if arbitrary()
+ then
+ discard_pending_call()
+ return 1
+ or
+ es.calls := es.calls · es.pending_call
+ es.pending_call := NoPendingCall
+ return 0
+
+// helper function
+discard_pending_call() =
+ if es.pending_call ≠ NoPendingCall then
+ es.balance := min(es.balance + es.pending_call.transferred_cycles, MAX_CANISTER_BALANCE)
+ es.pending_call := NoPendingCall
+
+ic0.stable_size() : (page_count : i32) =
+ return |es.wasm_state.stable_mem| / 64k
+
+ic0.stable_grow(new_pages : i32) : (old_page_count : i32) =
+ if arbitrary()
+ then return -1
+ else
+ old_size := |es.wasm_state.stable_mem| / 64k
+ es.wasm_state.stable_mem :=
+ es.wasm_state.stable_mem · repeat(0x00, new_pages * 64k)
+ return old_size
+
+ic0.stable_write(offset : i32, src : i32, size : i32)
+ if src+size > |es.wasm_state.store.mem| then Trap
+ if offset+size > |es.wasm_state.stable_mem| then Trap
+
+ es.wasm_state.stable_mem[offset..offset+size] := es.wasm_state.store.mem[src..src+size]
+
+ic0.stable_read(dst : i32, offset : i32, size : i32)
+ if offset+size > |es.wasm_state.stable_mem| then Trap
+ if dst+size > |es.wasm_state.store.mem| then Trap
+
+ es.wasm_state.store.mem[offset..offset+size] := es.wasm_state.stable.mem[src..src+size]
+
+ic0.time() : i32 =
+ return es.params.time
+
+ic0.certified_data_set(src: i32, size: i32) =
+ es.new_certified_data := es.wasm_state[src..src+size]
+
+ic0.data_certificate_present() : i32 =
+ if es.params.sysenv.certificate = NoCertificate
+ then return 0
+ else return 1
+
+ic0.data_certificate_size() : i32 =
+ if es.params.sysenv.certificate = NoCertificate then Trap
+ return |es.params.sysenv.certificate|
+
+ic0.data_certificate_copy(dst: i32, offset: i32, size: i32) =
+ if es.params.sysenv.certificate = NoCertificate then Trap
+ copy_to_canister(dst, offset, size, es.params.sysenv.certificate)
+
+
+ic0.debug_print(src : i32, size : i32) =
+ return
+
+ic0.trap(src : i32, size : i32) =
+ Trap
+....
+
+
+
+include::example$changelog.adoc[]
diff --git a/ic-spec/pages/intro-canisters.adoc b/ic-spec/pages/intro-canisters.adoc
new file mode 100644
index 000000000..098ee24fb
--- /dev/null
+++ b/ic-spec/pages/intro-canisters.adoc
@@ -0,0 +1,27 @@
+= Introduction to key interfaces
+
+If you want to use the Internet Computer as an application developer, you first write a program in a language that can be compiled into WebAssembly code.
+
+When you are ready to deploy your application on the {IC}, the Web Assembly code is incorporated into a computational unit called a _canister_.
+
+Interacting with a canister—as an application developer or as an end-user—typically involves interacting with the following underlying interfaces:
+
+* HTTP handler interface
+* System application programming interface
+
+If you use existing tools like the DFINITY Canister SDK to work with canisters, the tools interact with these lower-level interfaces on your behalf and you don't need to know the details about how they work.
+If you want to create your own tooling for working with canisters, however, you need to know a little about the canister format. how to use the link:index{outfilesuffix}#http-handler[HTTP interface] to interact with canisters, and the operations that the link:index{outfilesuffix}#system-api[system API] supports.
+
+The following diagram provides a simplified view of the work flow for an application running on the {IC}.
+
+image:simplified-canister-workflow.svg[]
+
+As this diagram suggests, requests to canisters deployed on the {IC} pass through a `+/submit+` endpoint to perform canister management operations.
+
+For details about specific interfaces and operations and how they work, see the following sections:
+
+* link:index{outfilesuffix}#http-interface[HTTP interfaces]
+* link:index{outfilesuffix}#system-api[Canister interface (System API)]
+* link:index{outfilesuffix}#ic-management-canister[IC management canister]
+
+For a more formal description and precise information about state-related operations for the Internet Computer as a whole, see the link:index{outfilesuffix}#abstract-behavior[Abstract behavior] section.
diff --git a/modules/ROOT/nav.adoc b/modules/ROOT/nav.adoc
index 46915bff6..b4d4a7d88 100644
--- a/modules/ROOT/nav.adoc
+++ b/modules/ROOT/nav.adoc
@@ -18,7 +18,7 @@
//xref:developer-guide:connect-network.adoc[Connect to a network]
** xref:developers-guide:design-apps.adoc[Design apps]
** xref:developers-guide:customize-projects.adoc[Manage projects]
-** xref:developers-guide:work-with-languages.adoc[Develop using different languages]
+** xref:developers-guide:work-with-languages.adoc[Develop using different backend languages]
//*** xref:language-guide:at-a-glance.adoc[Motoko]
//*** xref:rust-guide:basic-syntax-rules.adoc[Rust]
//*** xref:developers-guide:basic-syntax-rules.adoc[C and C++]
@@ -47,6 +47,7 @@
** xref:candid-guide:candid-types.adoc[Candid supported types]
** xref:developers-guide:lang-service-ide.adoc[Language server protocol client]
** xref:developers-guide:glossary.adoc[Glossary]
+//** xref:ic-spec:index.adoc[Interface specification]
.xref:languages:languages-overview.adoc[Languages]
* xref:candid-guide:candid-intro.adoc[Candid]
diff --git a/modules/developers-guide/assets/images/principal-identities.png b/modules/developers-guide/assets/images/principal-identities.png
new file mode 100644
index 000000000..6fefe4bde
Binary files /dev/null and b/modules/developers-guide/assets/images/principal-identities.png differ
diff --git a/modules/developers-guide/examples/mycontacts/mod-index.jsx b/modules/developers-guide/examples/mycontacts/mod-index.jsx
index 2328e3dbe..70a6f1864 100644
--- a/modules/developers-guide/examples/mycontacts/mod-index.jsx
+++ b/modules/developers-guide/examples/mycontacts/mod-index.jsx
@@ -1,8 +1,12 @@
-import contact from 'ic:canisters/contacts';
+import { Actor, HttpAgent } from '@dfinity/agent';
+import { idlFactory as contacts_idl, canisterId as contacts_id } from 'dfx-generated/contacts';
+
import * as React from 'react';
import { render } from 'react-dom';
+import '../assets/mycontacts.css'; // Import custom styles
-import './mycontacts.css'; // Import custom styles
+const agent = new HttpAgent();
+const contacts = Actor.createActor(contacts_idl, { agent, canisterId: contacts_id });
class Contact extends React.Component {
constructor(props) {
@@ -18,12 +22,12 @@ class Contact extends React.Component {
let email = document.getElementById("newEntryEmail").value;
let phone = document.getElementById("newEntryPhone").value;
- contact.insert(name, add1, add2, email, parseInt(phone, 10));
+ contacts.insert(name, add1, add2, email, parseInt(phone, 10));
}
async lookup() {
let name = document.getElementById("lookupName").value;
- contact.lookup(name).then(opt_entry => {
+ contacts.lookup(name).then(opt_entry => {
let entry;
if (opt_entry.length == 0) {
@@ -70,4 +74,4 @@ class Contact extends React.Component {
document.title = "DFINITY CONTACT EXAMPLE";
-render(, document.getElementById('app'));
+render(, document.getElementById('contacts'));
diff --git a/modules/developers-guide/examples/react-index.jsx b/modules/developers-guide/examples/react-index.jsx
index 4029d2511..954fc9ea5 100644
--- a/modules/developers-guide/examples/react-index.jsx
+++ b/modules/developers-guide/examples/react-index.jsx
@@ -1,7 +1,10 @@
-import custom_greeting from 'ic:canisters/custom_greeting';
+// Insert these lines after the import statements for
+// importing an agent and an actor
import * as React from 'react';
import { render } from 'react-dom';
+// Replace the default index.js content with
+// React JavaScript
class MyHello extends React.Component {
constructor(props) {
super(props);
diff --git a/modules/developers-guide/examples/react-revised-index.jsx b/modules/developers-guide/examples/react-revised-index.jsx
index e88b214c4..41085f039 100644
--- a/modules/developers-guide/examples/react-revised-index.jsx
+++ b/modules/developers-guide/examples/react-revised-index.jsx
@@ -1,7 +1,4 @@
-import custom_greeting from 'ic:canisters/custom_greeting';
-import * as React from 'react';
-import { render } from 'react-dom';
-
+// Modify the front-end in the React JavaScript
class MyHello extends React.Component {
constructor(props) {
super(props);
diff --git a/modules/developers-guide/examples/sample-tsconfig.json b/modules/developers-guide/examples/sample-tsconfig.json
index 646a50aa1..cf3b4f008 100644
--- a/modules/developers-guide/examples/sample-tsconfig.json
+++ b/modules/developers-guide/examples/sample-tsconfig.json
@@ -1,7 +1,6 @@
{
"compilerOptions": {
"target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
- "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
"lib": ["ES2018", "DOM"], /* Specify library files to be included in the compilation. */
"allowJs": true, /* Allow javascript files to be compiled. */
"jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
diff --git a/modules/developers-guide/pages/tutorials/access-control.adoc b/modules/developers-guide/pages/tutorials/access-control.adoc
index 5cc36d416..5014ef40e 100644
--- a/modules/developers-guide/pages/tutorials/access-control.adoc
+++ b/modules/developers-guide/pages/tutorials/access-control.adoc
@@ -207,7 +207,6 @@ The command displays output similar to the following:
+
....
Creating identity: "ic_admin".
-Created identity: "ic_admin".
....
. Call the `+my_role+` function to see that your new user identity has not been assigned to any role.
+
@@ -289,7 +288,6 @@ The command displays output similar to the following:
+
....
Creating identity: "alice_auth".
-Created identity: "alice_auth".
....
. Store the principal for the new user in an environment variable by running the following command:
+
@@ -363,7 +361,6 @@ The command displays output similar to the following:
+
....
Creating identity: "bob_standard".
-Created identity: "bob_standard".
....
. Call the `+my_role+` function to see that your new user identity has not been assigned to any role.
+
diff --git a/modules/developers-guide/pages/tutorials/custom-frontend.adoc b/modules/developers-guide/pages/tutorials/custom-frontend.adoc
index 426b790e0..9c312c76a 100644
--- a/modules/developers-guide/pages/tutorials/custom-frontend.adoc
+++ b/modules/developers-guide/pages/tutorials/custom-frontend.adoc
@@ -12,8 +12,7 @@ Now that you have a basic understanding of how to create, build, and deploy a si
This tutorial illustrates using a simple React framework to create a new front-end for the default sample program and guides you through some basic modifications to customize the interface displayed.
Later tutorials expand on the techniques introduced here, but if you already know how to use CSS, HTML, JavaScript, and React or other frameworks to build your user interface, you can skip this tutorial.
-NOTE: Currently, you can only use Javascript to implement the front-end for your canister.
-This tutorial illustrates using the React framework to manage the Document Object Model (DOM) for your canister.
+NOTE: This tutorial illustrates using the React framework to manage the Document Object Model (DOM) for your canister.
Because React has its own custom DOM syntax, you need to modify the webpack configuration to compile the front-end code, which is written in JSX. For more information about learning to use React and JSX, see link:https://reactjs.org/docs/getting-started.html[Getting started] on the https://reactjs.org/[React website].
== Before you begin
@@ -30,6 +29,8 @@ For information about installing node for your local operating system and packag
* You have stopped any {IC} network processes running on the local
computer.
+This tutorial takes approximately 30 minutes to complete.
+
== Create a new project
To create a new project directory for your custom front-end application:
@@ -87,11 +88,11 @@ NOTE: As an alternative to installing these modules, you can edit the default `+
include::example$custom-frontend-package.json[]
....
-== Modify the default configuration
+== Review the default configuration
-For this tutorial, you need to modify the default front-end settings in the `+dfx.json+` configuration file for your project.
+Before we make any changes to use React for this tutorial, let's review the default front-end settings in the `+dfx.json+` configuration file for your project.
-To modify the default `+dfx.json+` configuration file:
+To review the default `+dfx.json+` configuration file:
. Open the `+dfx.json+` configuration file in a text editor.
. Notice that the `+canisters+` key includes settings for a `custom_greeting_assets` canister.
@@ -106,7 +107,7 @@ To modify the default `+dfx.json+` configuration file:
"custom_greeting"
],
"frontend": {
- "entrypoint": "src/custom_greeting_assets/public/index.js"
+ "entrypoint": "src/custom_greeting_assets/src/index.html"
},
"source": [
"src/custom_greeting_assets/assets",
@@ -125,41 +126,58 @@ Let's take a look at the settings in this section.
* The assets canister has a default dependency on the main canister for the project.
-* The `+frontend.entrypoint+` setting specifies the path to a file—in this case, the `+index.js+` file—to use as your application entry point.
-If you had a different starting point—for example, a custom `index.html` file—you would modify this setting.
+* The `+frontend.entrypoint+` setting specifies the path to a file—in this case, the `+index.html+` file—to use as your application entry point.
+If you had a different starting point—for example, a custom `first-page.html` file—you would modify this setting.
-* The `+source+` setting specifies the path to a directory for static assets that will be included in your assets canister when you build your project.
-If you had custom cascading stylesheet (CSS) or JavaScript files, you would include them in this source folder.
-After building the project, these assets are served from the directory specified by the `+frontend.output+` setting.
+* The `+source+` settings specify the path to your `src` and `dist` directories. The `src` setting specifies the directory to use for static assets that will be included in your assets canister when you build your project.
+If you have custom cascading stylesheet (CSS) or JavaScript files, you would include them in the folder specified by this path.
+After building the project, the project assets are served from the directory specified by the `+dist+` setting.
* The `+type+` setting specifies that the `+custom_greeting_assets+` is an asset canister rather than a program canister.
--
+
-For this tutorial, change the `+entrypoint+` file name to `+index.jsx+` to enable adding HTML directly inside the React Javascript front-end.
-+
-....
-"entrypoint": "src/custom_greeting_assets/public/index.jsx",
-....
+For this tutorial, we are going to add React JavaScript in an `+index.jsx+` file, but that won't require any changes to the default settings in the `dfx.json` file.
. Close the `+dfx.json+` file to continue.
-== Review the default program
+== Review the default front-end files
-For this tutorial, you are going to use the default `+main.mo+` file.
-Later, you can return to this file and make changes to see how you can use the front-end to reflect changes in your program code.
+For this tutorial, you are going to use the default `+main.mo+` program and only manipulate the application by modifying the front-end.
+Before you make any changes, though, let's take a look at what's in the default front-end files for a project.
-To review the default program:
+To review the default front-end files:
-. Change to the `+src/custom_greeting+` directory.
+. Open the `+src/custom_greeting_assets/src/index.html+` file in a text editor.
+
-[source,bash]
-----
-cd src/custom_greeting
-----
-. Open the `+main.mo+` file to review the default code.
+This template file is the default front-end entry point for the application as specified by the `+frontend.entrypoint+` setting in the `dfx.json` file.
+
-The default program consists of one actor, one `+greet+` function, and one `+name+` argument.
-As you saw in link:explore-templates{outfilesuffix}#default-frontend[Viewing the default front-end], the default front-end for this program uses a few lines of raw JavaScript to place the `+greet+` function and returned `+name+` argument a simple alert window.
-. Close the `+main.mo+` file to continue.
+This file contains standard HTML with references to a CSS file and an image that are located in the `+src/custom_greeting_assets/assets+` directory.
+The default `+index.html+` file also includes standard HTML syntax for displaying an input field for the `+name+` argument and a clickable button.
++
+This is the same default front-end you saw in link:explore-templates{outfilesuffix}#default-frontend[Viewing the default front-end].
+. Open the `+src/custom_greeting_assets/src/index.js+` file in a text editor.
++
+....
+import { Actor, HttpAgent } from '@dfinity/agent';
+import { idlFactory as custom_greeting_idl, canisterId as custom_greeting_id } from 'dfx-generated/custom_greeting';
+
+const agent = new HttpAgent();
+const custom_greeting = Actor.createActor(custom_greeting_idl, { agent, canisterId: custom_greeting_id });
+
+document.getElementById("clickMeBtn").addEventListener("click", async () => {
+ const name = document.getElementById("name").value.toString();
+ const greeting = await custom_greeting.greet(name);
+
+ document.getElementById("greeting").innerText = greeting;
+});
+....
++
+--
+* The first `import` statement in the default `index.js` file creates an actor and an agent instance using the JavaScript agent library.
+* The second `import` statement prepares the `custom_greeting` canister for the actor object to be constructed.
+* The next two statements construct the agent and actor objects.
+* The remaining lines provide the document object handling for the default application.
+--
+. Close the `+index.js+` file to continue.
== Modify the front-end files
@@ -167,8 +185,16 @@ You are now ready to create a new front-end for the default program.
To prepare the front-end files:
-. Navigate back to the root of your project directory.
. Open the webpack configuration file (`webpack.config.js`) in a text editor.
+. Modify the front-end entry to replace the default `+index.html+` with `+index.jsx+`.
++
+....
+entry: {
+ // The frontend.entrypoint points to the HTML file for this build, so we need
+ // to replace the extension to `.js`.
+ index: path.join(__dirname, info.frontend.entrypoint).replace(/\.html$/, ".jsx"),
+},
+....
. Add the following `+module+` key above the `+plugins+` section:
+
[source,json]
@@ -180,8 +206,9 @@ module: {
},
----
+
-This setting enables the program to use the `+ts-loader+` compiler for the `+index.jsx+` file.
-. Create a new file named `+tsconfig.json+` in your project directory.
+This setting enables the program to use the `+ts-loader+` compiler for a React JavaScript `+index.jsx+` file.
+Note that there's a commented section in the default `webpack.config.js` file that you can modify to add the `module` key.
+. Create a new file named `+tsconfig.json+` in the root directory for your project.
. Open the `+tsconfig.json+` file in a text editor, then copy and paste the following into the file:
+
[source,json]
@@ -189,8 +216,7 @@ This setting enables the program to use the `+ts-loader+` compiler for the `+ind
include::example$sample-tsconfig.json[]
----
. Save your changes and close the `+tsconfig.json+` file to continue.
-. Change to the `+src/custom_greeting_assets/public+` directory.
-. Open the default `+src/custom_greeting_assets/public/index.js+` file in a text editor and delete the existing content.
+. Open the default `+src/custom_greeting_assets/src/index.js+` file in a text editor and delete lines 7 to 12.
. Copy and paste the following sample code into the `+index.js+` file:
+
[source,react]
@@ -201,8 +227,28 @@ include::example$react-index.jsx[]
+
[source,bash]
----
-mv src/custom_greeting_assets/public/index.js src/custom_greeting_assets/public/index.jsx
+mv src/custom_greeting_assets/src/index.js src/custom_greeting_assets/src/index.jsx
----
+. Open the default `+src/custom_greeting_assets/src/index.html+` file in a text editor, then replace the body contents with `++`.
++
+For example:
++
+....
+
+
+
+
+
+ custom_greeting
+
+
+
+
+
+
+
+
+....
== Start the local network
@@ -210,7 +256,6 @@ Before you can build the `+custom_greeting+` project, you need to connect to the
To start the network locally:
-[arabic]
. Open a new terminal window or tab on your local computer.
. Navigate to the root directory for your project, if necessary.
. Start the {IC} network on your local computer by running the following command:
diff --git a/modules/developers-guide/pages/tutorials/my-contacts.adoc b/modules/developers-guide/pages/tutorials/my-contacts.adoc
index 401dbac44..b6c08198b 100644
--- a/modules/developers-guide/pages/tutorials/my-contacts.adoc
+++ b/modules/developers-guide/pages/tutorials/my-contacts.adoc
@@ -12,8 +12,7 @@ Cascading stylesheets represent one of the most common ways to customize the use
This tutorial illustrates how to add a stylesheet when you use React to create a new front-end for your project.
If you already know how to add cascading stylesheets (CSS) to a React-based project, you can skip this tutorial.
-NOTE: Currently, you can only use Javascript to implement the front-end for your canister.
-This tutorial illustrates using the React framework to manage the Document Object Model (DOM) for your canister.
+NOTE: This tutorial illustrates using the React framework to manage the Document Object Model (DOM) for your canister.
Because React has its own custom DOM syntax, you need to modify the webpack configuration to compile the front-end code, which is written in JSX. For more information about learning to use React and JSX, see link:https://reactjs.org/docs/getting-started.html[Getting started] on the https://reactjs.org/[React website].
== Before you begin
@@ -84,50 +83,36 @@ NOTE: As an alternative to installing these modules, you can edit the default `+
include::example$add-stylesheet-package.json[]
....
-== Modify the default configuration
-
-For this tutorial, you need to modify the default front-end settings in the `+dfx.json+` configuration file for your project.
-
-To modify settings in the default `+dfx.json+` configuration file:
-
-. Open the `+dfx.json+` configuration file in a text editor.
-. Under the `+canisters.contacts+` section, change the name of the main program file from `+main.mo+` to `+contacts.mo+`.
-. Under the `+canisters.contacts_assets+` section, change the `+frontend.entrypoint+` file name from `+index.js+` to `+index.jsx+` to enable adding HTML directly inside JavaScript.
-. Save your changes and close the `+dfx.json+` file to continue.
-
== Modify the default program
-For this tutorial, you are going to rename the main program file and modify the file content to replace the default program with a program that allow you to store and look up contact information.
+For this tutorial, you are going to modify the main program to with code that allows you to store and look up contact information.
To modify the default program:
-. Change to the `+src/contacts+` directory.
-+
-[source,bash]
-----
-cd src/contacts
-----
-. Rename the `+main.mo+` file as `+contacts.mo+` by running the following command:
-+
-[source,bash]
-----
-mv main.mo contacts.mo
-----
-. Open the `+contacts.mo+` file in a text editor and delete the existing content.
+. Open the `+src/contacts/main.mo+` file in a text editor and delete the existing content.
. Copy and paste the following sample code into the file:
+
[source.copy,motoko,no-repl]
----
include::example$mycontacts/contacts.mo[]
----
-. Save your changes and close the `+contacts.mo+` file to continue.
+. Save your changes and close the `+main.mo+` file to continue.
== Modify the front-end files
You are now ready to create a new front-end for your program.
-. Navigate back to the root of your project directory.
. Open the webpack configuration file (`webpack.config.js`) in a text editor.
+. Modify the front-end entry to replace the default index.html with index.jsx.
++
+[source,js]
+----
+entry: {
+ // The frontend.entrypoint points to the HTML file for this build, so we need
+ // to replace the extension to `.js`.
+ index: path.join(__dirname, info.frontend.entrypoint).replace(/\.html$/, ".jsx"),
+},
+----
. Locate the commented example for the `+module+` key above the `+plugins+` section, then uncomment the following lines:
+
[source,js]
@@ -156,13 +141,19 @@ You are now ready to create a new cascading stylesheet and add it to your projec
To add a stylesheet:
-. Change to the `+src/contacts_assets/public+` directory.
+. Change to the `+src/contacts_assets/assets+` directory.
+
[source,bash]
----
-cd src/contacts_assets/public/
+cd src/contacts_assets/assets/
+----
+. Rename the `+main.css+` file to create a new file named `+mycontacts.css+`.
++
+[source.bash]
+----
+mv main.css mycontacts.css
----
-. Create a new file named `+mycontacts.css+` and open the file in a text editor.
+. Open the `+mycontacts.css+` file in a text editor and delete the existing content.
. Define some style properties for the front-end.
+
For example, copy and paste the following sample styles into the file:
@@ -172,6 +163,12 @@ For example, copy and paste the following sample styles into the file:
include::example$mycontacts/mycontacts.css[]
----
. Save your changes and close the `+mycontacts.css+` file to continue.
+. Change to the `+src/contacts_assets/src+` directory.
++
+[source,bash]
+----
+cd ../src
+----
. Open the default `+index.js+` file in a text editor and delete the existing content.
. Copy and paste the following sample code into the `+index.js+` file:
+
@@ -185,6 +182,27 @@ include::example$mycontacts/mod-index.jsx[]
----
mv index.js index.jsx
----
+. Open the default `src/contacts_assets/src/index.html` file in a text editor, then replace `main.css` as the stylesheet file name with `mycontacts.css` and update the `body` contents with ``.
++
+For example:
++
+[source,bash]
+----
+
+
+
+
+
+ contacts
+
+
+
+
+
+
+
+
+----
. Navigate back to the root of your project directory.
+
For example:
@@ -202,7 +220,6 @@ To start the network locally:
[arabic]
. Open a new terminal window or tab on your local computer.
-. Navigate to the root directory for your project, if necessary.
. Start the {IC} network on your local computer by running the following command:
+
[source,bash]
diff --git a/modules/quickstart/assets/images/front-end-prompt.png b/modules/quickstart/assets/images/front-end-prompt.png
new file mode 100644
index 000000000..f9b383150
Binary files /dev/null and b/modules/quickstart/assets/images/front-end-prompt.png differ
diff --git a/modules/quickstart/assets/images/front-end-result.png b/modules/quickstart/assets/images/front-end-result.png
new file mode 100644
index 000000000..f1e8c6fdf
Binary files /dev/null and b/modules/quickstart/assets/images/front-end-result.png differ
diff --git a/modules/quickstart/assets/images/magnify-welcome.png b/modules/quickstart/assets/images/magnify-welcome.png
new file mode 100644
index 000000000..89668740d
Binary files /dev/null and b/modules/quickstart/assets/images/magnify-welcome.png differ
diff --git a/modules/quickstart/assets/images/net-alert-prompt.png b/modules/quickstart/assets/images/net-alert-prompt.png
deleted file mode 100644
index 703e48c2f..000000000
Binary files a/modules/quickstart/assets/images/net-alert-prompt.png and /dev/null differ
diff --git a/modules/quickstart/assets/images/net-alert-window.png b/modules/quickstart/assets/images/net-alert-window.png
deleted file mode 100644
index d5ad390e0..000000000
Binary files a/modules/quickstart/assets/images/net-alert-window.png and /dev/null differ
diff --git a/modules/quickstart/assets/images/net-front-end-prompt.png b/modules/quickstart/assets/images/net-front-end-prompt.png
new file mode 100644
index 000000000..4af66c49e
Binary files /dev/null and b/modules/quickstart/assets/images/net-front-end-prompt.png differ
diff --git a/modules/quickstart/assets/images/net-result.png b/modules/quickstart/assets/images/net-result.png
new file mode 100644
index 000000000..3398b8035
Binary files /dev/null and b/modules/quickstart/assets/images/net-result.png differ
diff --git a/modules/quickstart/assets/images/no-rooms-available.png b/modules/quickstart/assets/images/no-rooms-available.png
new file mode 100644
index 000000000..b3d0cda00
Binary files /dev/null and b/modules/quickstart/assets/images/no-rooms-available.png differ
diff --git a/modules/quickstart/assets/images/personal-id.png b/modules/quickstart/assets/images/personal-id.png
new file mode 100644
index 000000000..80702e14e
Binary files /dev/null and b/modules/quickstart/assets/images/personal-id.png differ
diff --git a/modules/quickstart/assets/images/quickstart-prompt.png b/modules/quickstart/assets/images/quickstart-prompt.png
deleted file mode 100644
index 8ead58eed..000000000
Binary files a/modules/quickstart/assets/images/quickstart-prompt.png and /dev/null differ
diff --git a/modules/quickstart/assets/images/quickstart-return.png b/modules/quickstart/assets/images/quickstart-return.png
deleted file mode 100644
index 8831a7085..000000000
Binary files a/modules/quickstart/assets/images/quickstart-return.png and /dev/null differ
diff --git a/modules/quickstart/pages/local-quickstart.adoc b/modules/quickstart/pages/local-quickstart.adoc
index 8845a8d20..86938ffa1 100644
--- a/modules/quickstart/pages/local-quickstart.adoc
+++ b/modules/quickstart/pages/local-quickstart.adoc
@@ -17,7 +17,7 @@ ifdef::env-github,env-browser[:outfilesuffix:.adoc]
[[quick-start-intro]]
This _Quick Start_ scenario assumes that you are installing the {sdk-short-name} for the first time and are running the {IC} as part of your *local development environment*.
-To get started, let's build and deploy a simple Hello application that has just one function—called `+greet+`. The `+greet+` function accepts one text argument and returns the result with a greeting similar to **Hello,{nbsp}everyone!** in a terminal if you run the application using the command-line or in an alert pop-up window if you access the application in a browser.
+To get started, let's build and deploy a simple Hello application that has just one function—called `+greet+`. The `+greet+` function accepts one text argument and returns the result with a greeting similar to **Hello,{nbsp}everyone!** in a terminal if you run the application using the command-line or in an HTML page if you access the application in a browser.
[[before-you-begin]]
== Before you begin
@@ -86,7 +86,7 @@ dfx --help
+
The command displays usage information for the `+dfx+` parent command and its subcommands.
-include::example$vscode-plugin.adoc[]
+//include::example$vscode-plugin.adoc[]
[[create-a-new-project]]
== Create a new project
@@ -175,15 +175,13 @@ For example, this step registers two network-specific identifiers—one for the
Creating the "default" identity.
- generating new key at /Users/pubs/.config/dfx/identity/default/identity.pem
Created the "default" identity.
+Creating a wallet canister on the local network.
+The wallet canister on the "local" network for user "default" is "rwlgt-iiaaa-aaaaa-aaaaa-cai"
Deploying all canisters.
Creating canisters...
Creating canister "hello"...
-Creating the canister using the wallet canister...
-Creating a wallet canister on the local network.
-The wallet canister on the "local" network for user "default" is "rwlgt-iiaaa-aaaaa-aaaaa-cai"
"hello" canister created with canister id: "rrkah-fqaaa-aaaaa-aaaaq-cai"
Creating canister "hello_assets"...
-Creating the canister using the wallet canister...
"hello_assets" canister created with canister id: "ryjl3-tyaaa-aaaaa-aaaba-cai"
Building canisters...
Building frontend...
@@ -192,6 +190,13 @@ Installing code for canister hello, with canister_id rrkah-fqaaa-aaaaa-aaaaq-cai
Installing code for canister hello_assets, with canister_id ryjl3-tyaaa-aaaaa-aaaba-cai
Authorizing our identity (default) to the asset canister...
Uploading assets to asset canister...
+ /index.html 1/1 (472 bytes)
+ /index.js 1/1 (295480 bytes)
+ /main.css 1/1 (484 bytes)
+ /sample-asset.txt 1/1 (24 bytes)
+ /logo.png 1/1 (25397 bytes)
+ /index.js.map 1/1 (957052 bytes)
+ /index.js.LICENSE.txt 1/1 (499 bytes)
Deployed canisters.
....
+
@@ -227,20 +232,19 @@ Now that you have verified that your application has been deployed and tested it
For example, the full URL should look similar to the following:
+
....
-http://127.0.0.1:8000/?canisterId=rrkah-fqaaa-aaaaa-aaaaq-cai
+http://127.0.0.1:8000/?canisterId=ryjl3-tyaaa-aaaaa-aaaba-cai
....
+
Navigating to this URL displays the prompt pop-up window.
For example:
+
-image:quickstart-prompt.png[Prompt pop-up window]
+image:front-end-prompt.png[HTML page with prompt]
-. Type a greeting, then click *OK* to return the greeting.
+. Type a greeting, then click *Click Me* to return the greeting.
+
For example:
+
-image:quickstart-return.png[Hello, everyone! greeting]
-. Click *OK* to close the alert pop-up window.
+image:front-end-result.png[Hello, everyone! greeting]
== Stop the local network
diff --git a/modules/quickstart/pages/magnify-users-guide.adoc b/modules/quickstart/pages/magnify-users-guide.adoc
new file mode 100644
index 000000000..46a2c8e0c
--- /dev/null
+++ b/modules/quickstart/pages/magnify-users-guide.adoc
@@ -0,0 +1,83 @@
+= Magnify User's Guide
+:experimental:
+// Define unicode for Apple Command key.
+:commandkey: ⌘
+:proglang: Motoko
+:platform: Internet Computer platform
+:IC: Internet Computer
+:company-id: DFINITY
+:app-short-name: Magnify
+:app-long-name: Magnify Video Conferencing
+:sdk-short-name: DFINITY Canister SDK
+ifdef::env-github,env-browser[:outfilesuffix:.adoc]
+
+[[quick-start-intro]]
+{app-long-name} illustrates how you can create a basic video conferencing application that runs on an {IC} network provider.
+For this demonstration, the {app-short-name} runs on a Digital Ocean instance with a self-signed certificate.
+Depending on your browser and security settings, access to server running {app-short-name} might be blocked by default.
+
+NOTE: If you want to build a local version of {app-short-name}, see link:magnify-quickstart{outfilesuffix}[_Building {app-long-name}_].
+For information about deploying the canister, see link:magnify-quickstart{outfilesuffix}#deploy[How to deploy].
+
+[[before-you-begin]]
+== Before you begin
+
+Before you attempt to use {app-long-name}, verify that ou have an internet connection and access to a Google Chrome, Mozilla Firefox, or macOS Safari browser.
+
+[[open-magnify]]
+== Open {app-short-name} in a browser
+
+To open {app-short-name} in a browser:
+
+. Open a new browser tab or window.
+. Connect to the {app-short-name} canister running on the link:https://161.35.207.208/?canisterId=ic:02000000000000000000000000000000000153[Digital Ocean instance].
+. Review the options displayed on the {app-short-name} welcome page.
++
+image:no-rooms-available.png[]
+. Select a task from the options available:
++
+* Create a new conference.
+* Join an existing conference.
+* Request an invitation by sending someone your personal identifier.
+
+Let's start by creating a new room.
+
+=== Create a new conference
+
+If you are the first participant or want to create a new conference, you first must create a room for your conference.
+After you create the room, you can invite others to join you.
+
+To create a new conference:
+
+. Type a room number in the **New Room** field.
+. Type the name you want displayed for your video stream in the **Your name** field.
+. Click **Create**.
+. Click **Allow** to allow {app-short-name} to access you media devices--for example, the camera and microphone you want to use for the conference.
++
+image:audio.png[Allow or block audio]
++
+Clicking Allow starts your video stream.
+. Type the name of the person you want to invite to the conference in the **Invitee name** field.
+. Paste the personal identifier for the person you want to invite to the conference in the **Invitee principal** field.
+. Click **Invite**.
+
+When your invitation is accepted the invitee video stream is displayed.
+You or your guest can invite additional people to participate.
+
+=== Join a conference in an existing room
+
+If you are not the first participant or have been invited to join an existing conference, select the room number for the conference to which you have been invited.
+
+image:magnify-welcome.png[]
+
+=== Send a host your personal identifier
+
+For you to participate in a secure conference, the host or another participant must have your personal identifier, the invitee principal displayed on the welcome page.
+
+To participate in a conference:
+
+. Copy and send your identifier to the host or another participant.
++
+image:personal-id.png[]
+. Select the conference to join from the list of available rooms.
+
diff --git a/modules/quickstart/pages/network-quickstart.adoc b/modules/quickstart/pages/network-quickstart.adoc
index 18c0507a6..9ecd7c723 100644
--- a/modules/quickstart/pages/network-quickstart.adoc
+++ b/modules/quickstart/pages/network-quickstart.adoc
@@ -16,7 +16,7 @@ This _Quick Start_ scenario assumes that you are installing the {sdk-short-name}
If you are only deploying projects in a local development environment, see the link:local-quickstart{outfilesuffix}[Local development] scenario.
To get started, let's build and deploy a simple Hello application that has just one function—called `+greet+`.
-The `+greet+` function accepts one text argument and returns the result with a greeting similar to **Hello,{nbsp}everyone!** in a terminal if you run the application using the command-line or in an alert pop-up window if you access the application in a browser.
+The `+greet+` function accepts one text argument and returns the result with a greeting similar to **Hello,{nbsp}everyone!** in a terminal if you run the application using the command-line or in an HTML page if you access the application in a browser.
[[net-before]]
== Before you begin
@@ -171,23 +171,28 @@ The `+dfx deploy+` command output displays information about the operations it p
For example, this step registers two network-specific identifiers—one for the `+hello+` main program and one for the `+hello_assets+` front-end user interface—and installation information similar to the following:
+
....
+Creating a wallet canister on the ic network.
+The wallet canister on the "ic" network for user "default" is "pddoi-uiaaa-aaaab-qanua-cai"
Deploying all canisters.
Creating canisters...
Creating canister "hello"...
-Creating the canister using the wallet canister...
-Creating a wallet canister on the ic network.
-The wallet canister on the "ic" network for user "default" is "oi7fh-tiaaa-aaaab-aahpq-cai"
-"hello" canister created on network "ic" with canister id: "lue7c-yaaaa-aaaab-aahqa-cai"
+"hello" canister created on network "ic" with canister id: "peci4-zqaaa-aaaab-qanuq-cai"
Creating canister "hello_assets"...
-Creating the canister using the wallet canister...
-"hello_assets" canister created on network "ic" with canister id: "ltfzw-vyaaa-aaaab-aahqq-cai"
+"hello_assets" canister created on network "ic" with canister id: "pnbda-pyaaa-aaaab-qanva-cai"
Building canisters...
Building frontend...
Installing canisters...
-Installing code for canister hello, with canister_id lue7c-yaaaa-aaaab-aahqa-cai
-Installing code for canister hello_assets, with canister_id ltfzw-vyaaa-aaaab-aahqq-cai
+Installing code for canister hello, with canister_id peci4-zqaaa-aaaab-qanuq-cai
+Installing code for canister hello_assets, with canister_id pnbda-pyaaa-aaaab-qanva-cai
Authorizing our identity (default) to the asset canister...
Uploading assets to asset canister...
+ /index.html 1/1 (472 bytes)
+ /index.js 1/1 (295480 bytes)
+ /main.css 1/1 (484 bytes)
+ /sample-asset.txt 1/1 (24 bytes)
+ /logo.png 1/1 (25397 bytes)
+ /index.js.map 1/1 (957046 bytes)
+ /index.js.LICENSE.txt 1/1 (499 bytes)
Deployed canisters.
....
. Call the `+hello+` canister and the predefined `+greet+` function by running the following command:
@@ -266,7 +271,7 @@ In this example, the new balance is 99,999,974,082,913 cycles.
[[quickstart-frontend]]
== Test the application front-end
-Now that you have verified that your application has been deployed and tested its operation using the command line, let's verify that you can access the front-end pop-up window using your web browser.
+Now that you have verified that your application has been deployed and tested its operation using the command line, let's verify that you can access the front-end using your web browser.
To access the application front-end:
@@ -276,20 +281,19 @@ To access the application front-end:
For example, the full URL should look similar to the following:
+
....
-https://wmbea-daaaa-aaaab-aacjq-cai.ic0.app/
+https://pnbda-pyaaa-aaaab-qanva-cai.ic0.app/
....
+
-Navigating to this URL displays the prompt pop-up window.
+Navigating to this URL displays the HTML entry page for the template application.
For example:
+
-image:net-alert-prompt.png[Prompt pop-up window]
+image:net-front-end-prompt.png[HTML page with prompt ]
-. Type a greeting, then click *OK* to return the greeting.
+. Type a greeting, then click *Click Me* to return the greeting.
+
For example:
+
-image:net-alert-window.png[Hello, everyone! greeting]
-. Click *OK* to close the alert pop-up window.
+image:net-result.png[Hello, Everyone! greeting]
[[next-steps]]
== Next steps