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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions docs/references/ic-interface-spec/abstract-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,8 @@ S = {
environment_variables: CanisterId ↦ (Text ↦ Text)
on_low_wasm_memory_hook_status: CanisterId ↦ OnLowWasmMemoryHookStatus;
certified_data: CanisterId ↦ Blob;
canister_creation_timestamp: CanisterId ↦ Timestamp;
last_install_timestamp: CanisterId ↦ Timestamp;
canister_history: CanisterId ↦ CanisterHistory;
canister_log_visibility: CanisterId ↦ CanisterLogVisibility;
canister_snapshot_visibility: CanisterId ↦ CanisterSnapshotVisibility;
Expand Down Expand Up @@ -625,6 +627,8 @@ The initial state of the IC is
environment_variables = ();
on_low_wasm_memory_hook_status = ();
certified_data = ();
canister_creation_timestamp = ();
last_install_timestamp = ();
canister_history = ();
canister_log_visibility = ();
canister_snapshot_visibility = ();
Expand Down Expand Up @@ -1755,6 +1759,7 @@ S' = S with
canisters[Canister_id] = EmptyCanister
snapshots[A.canister_id] = null
time[Canister_id] = CurrentTime
canister_creation_timestamp[Canister_id] = CurrentTime
global_timer[Canister_id] = 0
controllers[Canister_id] = New_controllers
chunk_store[Canister_id] = ()
Expand Down Expand Up @@ -2395,6 +2400,7 @@ S' = S with
else:
global_timer[A.canister_id] = 0
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
balances[A.canister_id] = New_balance
reserved_balances[A.canister_id] = New_reserved_balance
canister_history[A.canister_id] = New_canister_history
Expand Down Expand Up @@ -2561,6 +2567,7 @@ S' = S with
else:
global_timer[A.canister_id] = 0
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
balances[A.canister_id] = New_balance;
reserved_balances[A.canister_id] = New_reserved_balance;
canister_history[A.canister_id] = New_canister_history
Expand Down Expand Up @@ -2640,6 +2647,7 @@ State after

S with
canisters[A.canister_id] = EmptyCanister
last_install_timestamp[A.canister_id] = (deleted)
certified_data[A.canister_id] = ""
chunk_store = ()
canister_history[A.canister_id] = {
Expand Down Expand Up @@ -2930,13 +2938,16 @@ S with
canister_version[A.canister_id] = (deleted)
canister_subnet[A.canister_id] = (deleted)
time[A.canister_id] = (deleted)
canister_creation_timestamp[A.canister_id] = (deleted)
last_install_timestamp[A.canister_id] = (deleted)
global_timer[A.canister_id] = (deleted)
balances[A.canister_id] = (deleted)
reserved_balances[A.canister_id] = (deleted)
reserved_balance_limits[A.canister_id] = (deleted)
minimum_incoming_canister_call_cycles[A.canister_id] = (deleted)
wasm_memory_limit[A.canister_id] = (deleted)
wasm_memory_threshold[A.canister_id] = (deleted)
environment_variables[A.canister_id] = (deleted)
on_low_wasm_memory_hook_status[A.canister_id] = (deleted)
certified_data[A.canister_id] = (deleted)
canister_history[A.canister_id] = (deleted)
Expand Down Expand Up @@ -3192,6 +3203,7 @@ S' = S with
canisters[Canister_id] = EmptyCanister
snapshots[Canister_id] = null
time[Canister_id] = CurrentTime
canister_creation_timestamp[Canister_id] = CurrentTime
global_timer[Canister_id] = 0
controllers[Canister_id] = New_controllers
compute_allocation[Canister_id] = New_compute_allocation
Expand Down Expand Up @@ -3373,6 +3385,7 @@ S' = S with
reserved_balances[A.canister_id] = New_reserved_balance

canisters[A.canister_id] = EmptyCanister
last_install_timestamp[A.canister_id] = (deleted)
certified_data[A.canister_id] = ""
chunk_store = ()
canister_history[A.canister_id] = {
Expand Down Expand Up @@ -3527,6 +3540,7 @@ S' = S with
reserved_balances[A.canister_id] = New_reserved_balance
canister_history[A.canister_id] = New_canister_history
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
messages = Older_messages · Younger_messages ·
ResponseMessage {
origin = M.origin;
Expand Down Expand Up @@ -4055,6 +4069,7 @@ State after

S with
canisters[CanisterId] = EmptyCanister
last_install_timestamp[Canister_id] = (deleted)
snapshots[CanisterId] = null
certified_data[CanisterId] = ""
canister_history[CanisterId] = {
Expand Down Expand Up @@ -4147,6 +4162,10 @@ State after
S with
canisters[New_canister_id] = S.canisters[Canister_id]
canisters[Canister_id] = (deleted)
canister_creation_timestamp[New_canister_id] = S.canister_creation_timestamp[Canister_id]
canister_creation_timestamp[Canister_id] = (deleted)
last_install_timestamp[New_canister_id] = S.last_install_timestamp[Canister_id]
last_install_timestamp[Canister_id] = (deleted)
snapshots[New_canister_id] = {}
snapshots[Canister_id] = (deleted)
controllers[New_canister_id] = S.controllers[Canister_id]
Expand Down Expand Up @@ -4732,6 +4751,8 @@ may_read_path_for_canister(S, _, ["request_status", Rid, "error_code"]) =
∀ (R ↦ (_, ECID')) ∈ dom(S.requests). hash_of_map(R) = Rid => RS.sender == R.sender ∧ ECID == ECID'
may_read_path_for_canister(S, _, ["canister", cid, "module_hash"]) = cid == ECID
may_read_path_for_canister(S, _, ["canister", cid, "controllers"]) = cid == ECID
may_read_path_for_canister(S, _, ["canister", cid, "canister_creation_timestamp"]) = cid == ECID
may_read_path_for_canister(S, _, ["canister", cid, "last_install_timestamp"]) = cid == ECID
may_read_path_for_canister(S, _, ["canister", cid, "metadata", name]) = cid == ECID ∧ UTF8(name) ∧
(cid ∉ dom(S.canisters[cid]) ∨
S.canisters[cid] = EmptyCanister ∨
Expand Down Expand Up @@ -4809,6 +4830,8 @@ state_tree(S) = {
{ canister_id :
{ "module_hash" : SHA256(C.raw_module) | if C ≠ EmptyCanister } ∪
{ "controllers" : CBOR(S.controllers[canister_id]) } ∪
{ "canister_creation_timestamp" : S.canister_creation_timestamp[canister_id] } ∪
{ "last_install_timestamp" : S.last_install_timestamp[canister_id] | if C ≠ EmptyCanister } ∪
{ "metadata": { name: blob | (name, blob) ∈ S.canisters[canister_id].public_custom_sections ∪ S.canisters[canister_id].private_custom_sections } }
| (canister_id, C) ∈ S.canisters };
}
Expand Down
7 changes: 7 additions & 0 deletions docs/references/ic-interface-spec/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ sidebar:

## Changelog {#changelog}

### 0.65.0 (2026-07-24) {$0_65_0}
* Two new paths in the certified state tree, `/canister/<canister_id>/canister_creation_timestamp`
(the time at which the canister was created) and `/canister/<canister_id>/last_install_timestamp`
(the time at which the canister's code was most recently deployed or a snapshot was loaded onto it),
both expressed in nanoseconds since 1970-01-01. Both can be requested via `read_state` if
`<canister_id>` matches the effective canister id of the request.

### 0.64.0 (2026-07-06) {$0_64_0}
* New optional `permissions` field in request delegations restricting the kinds of requests
the delegation applies for: the value `"queries"` restricts the delegation to query calls
Expand Down
4 changes: 4 additions & 0 deletions docs/references/ic-interface-spec/https-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,10 @@ All requested paths must have the following form:

- `/canister/<canister_id>/controllers`. Can be requested if `<canister_id>` matches `<effective_canister_id>`. The order of controllers in the value at this path may vary depending on the implementation.

- `/canister/<canister_id>/canister_creation_timestamp`. Can be requested if `<canister_id>` matches `<effective_canister_id>`.

- `/canister/<canister_id>/last_install_timestamp`. Can be requested if `<canister_id>` matches `<effective_canister_id>`.

- `/canister/<canister_id>/metadata/<name>`. Can be requested if `<canister_id>` matches `<effective_canister_id>`, `<name>` is encoded in UTF-8, and

- canister with canister id `<canister_id>` does not exist or
Expand Down
10 changes: 9 additions & 1 deletion docs/references/ic-interface-spec/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ Request statuses will not actually be kept around indefinitely, and eventually t

### Canister information {#state-tree-canister-information}

Users have the ability to learn about the hash of the canister's module, its current controllers, and metadata in a certified way.
Users have the ability to learn about the hash of the canister's module, its current controllers, metadata, creation time, and last install time in a certified way.

- `/canister/<canister_id>/module_hash` (blob):

Expand All @@ -625,6 +625,14 @@ Users have the ability to learn about the hash of the canister's module, its cur

The current controllers of the canister. The value consists of a CBOR (see [CBOR](#cbor)) data item with major type 6 ("Semantic tag") and tag value `55799`, followed by an array of principals in their binary form (CDDL `#6.55799([* bytes .size (0..29)])`, see [CDDL](#cddl)).

- `/canister/<canister_id>/canister_creation_timestamp` (natural):

The time at which the canister was created, expressed in nanoseconds since 1970-01-01. If the canister was created before this information was recorded, this path does not exist.

- `/canister/<canister_id>/last_install_timestamp` (natural):

The time at which the canister's code was most recently deployed ([code install, reinstall, or upgrade](./management-canister.md#ic-install_code)) or a [snapshot was loaded](./management-canister.md#ic-load_canister_snapshot) onto it, expressed in nanoseconds since 1970-01-01. If the canister is empty, or its code was deployed before this information was recorded, this path does not exist.

- `/canister/<canister_id>/metadata/<name>` (blob):

If the canister has a [custom section](https://webassembly.github.io/spec/core/binary/modules.html#custom-section) called `icp:public <name>` or `icp:private <name>`, this path contains the content of the custom section. Otherwise, this path does not exist.
Expand Down
Loading