Skip to content

Commit 520d0ba

Browse files
feat: Certification versions V27 and V28 (#332)
Update to the specifications related to the new `last_install_timestamp` and `canister_creation_timestamp` leaves in the state tree. --------- Co-authored-by: Martin Raszyk <martin.raszyk@dfinity.org>
1 parent b238f36 commit 520d0ba

4 files changed

Lines changed: 43 additions & 1 deletion

File tree

docs/references/ic-interface-spec/abstract-behavior.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ S = {
519519
environment_variables: CanisterId ↦ (Text ↦ Text)
520520
on_low_wasm_memory_hook_status: CanisterId ↦ OnLowWasmMemoryHookStatus;
521521
certified_data: CanisterId ↦ Blob;
522+
canister_creation_timestamp: CanisterId ↦ Timestamp;
523+
last_install_timestamp: CanisterId ↦ Timestamp;
522524
canister_history: CanisterId ↦ CanisterHistory;
523525
canister_log_visibility: CanisterId ↦ CanisterLogVisibility;
524526
canister_snapshot_visibility: CanisterId ↦ CanisterSnapshotVisibility;
@@ -630,6 +632,8 @@ The initial state of the IC is
630632
environment_variables = ();
631633
on_low_wasm_memory_hook_status = ();
632634
certified_data = ();
635+
canister_creation_timestamp = ();
636+
last_install_timestamp = ();
633637
canister_history = ();
634638
canister_log_visibility = ();
635639
canister_snapshot_visibility = ();
@@ -1778,6 +1782,7 @@ S' = S with
17781782
canisters[Canister_id] = EmptyCanister
17791783
snapshots[A.canister_id] = null
17801784
time[Canister_id] = CurrentTime
1785+
canister_creation_timestamp[Canister_id] = CurrentTime
17811786
global_timer[Canister_id] = 0
17821787
controllers[Canister_id] = New_controllers
17831788
chunk_store[Canister_id] = ()
@@ -2434,6 +2439,7 @@ S' = S with
24342439
else:
24352440
global_timer[A.canister_id] = 0
24362441
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
2442+
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
24372443
balances[A.canister_id] = New_balance
24382444
reserved_balances[A.canister_id] = New_reserved_balance
24392445
canister_history[A.canister_id] = New_canister_history
@@ -2600,6 +2606,7 @@ S' = S with
26002606
else:
26012607
global_timer[A.canister_id] = 0
26022608
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
2609+
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
26032610
balances[A.canister_id] = New_balance;
26042611
reserved_balances[A.canister_id] = New_reserved_balance;
26052612
canister_history[A.canister_id] = New_canister_history
@@ -2679,6 +2686,7 @@ State after
26792686
26802687
S with
26812688
canisters[A.canister_id] = EmptyCanister
2689+
last_install_timestamp[A.canister_id] = (deleted)
26822690
certified_data[A.canister_id] = ""
26832691
chunk_store = ()
26842692
canister_history[A.canister_id] = {
@@ -2969,13 +2977,16 @@ S with
29692977
canister_version[A.canister_id] = (deleted)
29702978
canister_subnet[A.canister_id] = (deleted)
29712979
time[A.canister_id] = (deleted)
2980+
canister_creation_timestamp[A.canister_id] = (deleted)
2981+
last_install_timestamp[A.canister_id] = (deleted)
29722982
global_timer[A.canister_id] = (deleted)
29732983
balances[A.canister_id] = (deleted)
29742984
reserved_balances[A.canister_id] = (deleted)
29752985
reserved_balance_limits[A.canister_id] = (deleted)
29762986
minimum_incoming_canister_call_cycles[A.canister_id] = (deleted)
29772987
wasm_memory_limit[A.canister_id] = (deleted)
29782988
wasm_memory_threshold[A.canister_id] = (deleted)
2989+
environment_variables[A.canister_id] = (deleted)
29792990
on_low_wasm_memory_hook_status[A.canister_id] = (deleted)
29802991
certified_data[A.canister_id] = (deleted)
29812992
canister_history[A.canister_id] = (deleted)
@@ -3237,6 +3248,7 @@ S' = S with
32373248
canisters[Canister_id] = EmptyCanister
32383249
snapshots[Canister_id] = null
32393250
time[Canister_id] = CurrentTime
3251+
canister_creation_timestamp[Canister_id] = CurrentTime
32403252
global_timer[Canister_id] = 0
32413253
controllers[Canister_id] = New_controllers
32423254
compute_allocation[Canister_id] = New_compute_allocation
@@ -3419,6 +3431,7 @@ S' = S with
34193431
reserved_balances[A.canister_id] = New_reserved_balance
34203432

34213433
canisters[A.canister_id] = EmptyCanister
3434+
last_install_timestamp[A.canister_id] = (deleted)
34223435
certified_data[A.canister_id] = ""
34233436
chunk_store = ()
34243437
canister_history[A.canister_id] = {
@@ -3573,6 +3586,7 @@ S' = S with
35733586
reserved_balances[A.canister_id] = New_reserved_balance
35743587
canister_history[A.canister_id] = New_canister_history
35753588
canister_version[A.canister_id] = S.canister_version[A.canister_id] + 1
3589+
last_install_timestamp[A.canister_id] = S.time[A.canister_id]
35763590
messages = Older_messages · Younger_messages ·
35773591
ResponseMessage {
35783592
origin = M.origin;
@@ -4101,6 +4115,7 @@ State after
41014115

41024116
S with
41034117
canisters[CanisterId] = EmptyCanister
4118+
last_install_timestamp[Canister_id] = (deleted)
41044119
snapshots[CanisterId] = null
41054120
certified_data[CanisterId] = ""
41064121
canister_history[CanisterId] = {
@@ -4193,6 +4208,10 @@ State after
41934208
S with
41944209
canisters[New_canister_id] = S.canisters[Canister_id]
41954210
canisters[Canister_id] = (deleted)
4211+
canister_creation_timestamp[New_canister_id] = S.canister_creation_timestamp[Canister_id]
4212+
canister_creation_timestamp[Canister_id] = (deleted)
4213+
last_install_timestamp[New_canister_id] = S.last_install_timestamp[Canister_id]
4214+
last_install_timestamp[Canister_id] = (deleted)
41964215
snapshots[New_canister_id] = {}
41974216
snapshots[Canister_id] = (deleted)
41984217
controllers[New_canister_id] = S.controllers[Canister_id]
@@ -4780,6 +4799,8 @@ may_read_path_for_canister(S, _, ["request_status", Rid, "error_code"]) =
47804799
∀ (R ↦ (_, ECID')) ∈ dom(S.requests). hash_of_map(R) = Rid => RS.sender == R.sender ∧ ECID == ECID'
47814800
may_read_path_for_canister(S, _, ["canister", cid, "module_hash"]) = cid == ECID
47824801
may_read_path_for_canister(S, _, ["canister", cid, "controllers"]) = cid == ECID
4802+
may_read_path_for_canister(S, _, ["canister", cid, "canister_creation_timestamp"]) = cid == ECID
4803+
may_read_path_for_canister(S, _, ["canister", cid, "last_install_timestamp"]) = cid == ECID
47834804
may_read_path_for_canister(S, _, ["canister", cid, "metadata", name]) = cid == ECID ∧ UTF8(name) ∧
47844805
(cid ∉ dom(S.canisters[cid]) ∨
47854806
S.canisters[cid] = EmptyCanister ∨
@@ -4857,6 +4878,8 @@ state_tree(S) = {
48574878
{ canister_id :
48584879
{ "module_hash" : SHA256(C.raw_module) | if C ≠ EmptyCanister } ∪
48594880
{ "controllers" : CBOR(S.controllers[canister_id]) } ∪
4881+
{ "canister_creation_timestamp" : S.canister_creation_timestamp[canister_id] } ∪
4882+
{ "last_install_timestamp" : S.last_install_timestamp[canister_id] | if C ≠ EmptyCanister } ∪
48604883
{ "metadata": { name: blob | (name, blob) ∈ S.canisters[canister_id].public_custom_sections ∪ S.canisters[canister_id].private_custom_sections } }
48614884
| (canister_id, C) ∈ S.canisters };
48624885
}

docs/references/ic-interface-spec/changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ sidebar:
88

99
## Changelog {#changelog}
1010

11+
### 0.66.0 (2026-08-17) {$0_66_0}
12+
* Two new paths in the certified state tree, `/canister/<canister_id>/canister_creation_timestamp`
13+
(the time at which the canister was created) and `/canister/<canister_id>/last_install_timestamp`
14+
(the time at which the canister's code was most recently deployed or a snapshot was loaded onto it),
15+
both expressed in nanoseconds since 1970-01-01. Both can be requested via `read_state` if
16+
`<canister_id>` matches the effective canister id of the request.
17+
1118
### 0.65.0 (2026-08-03) {$0_65_0}
1219
* New canister setting `status_visibility` controlling who can read a canister's status via the
1320
`canister_status` endpoint: `controllers` (default) restricts access to the canister's controllers,

docs/references/ic-interface-spec/https-interface.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,10 @@ All requested paths must have the following form:
314314

315315
- `/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.
316316

317+
- `/canister/<canister_id>/canister_creation_timestamp`. Can be requested if `<canister_id>` matches `<effective_canister_id>`.
318+
319+
- `/canister/<canister_id>/last_install_timestamp`. Can be requested if `<canister_id>` matches `<effective_canister_id>`.
320+
317321
- `/canister/<canister_id>/metadata/<name>`. Can be requested if `<canister_id>` matches `<effective_canister_id>`, `<name>` is encoded in UTF-8, and
318322

319323
- canister with canister id `<canister_id>` does not exist or

docs/references/ic-interface-spec/index.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ Request statuses will not actually be kept around indefinitely, and eventually t
615615
616616
### Canister information {#state-tree-canister-information}
617617
618-
Users have the ability to learn about the hash of the canister's module, its current controllers, and metadata in a certified way.
618+
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.
619619
620620
- `/canister/<canister_id>/module_hash` (blob):
621621
@@ -625,6 +625,14 @@ Users have the ability to learn about the hash of the canister's module, its cur
625625
626626
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)).
627627
628+
- `/canister/<canister_id>/canister_creation_timestamp` (natural):
629+
630+
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.
631+
632+
- `/canister/<canister_id>/last_install_timestamp` (natural):
633+
634+
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.
635+
628636
- `/canister/<canister_id>/metadata/<name>` (blob):
629637
630638
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.

0 commit comments

Comments
 (0)