1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
pub mod auth;
#[cfg(feature = "blob-storage")]
pub mod blob_storage;
pub mod children;
pub mod cycles;
pub mod directory;
pub mod env;
pub mod icp_refill;
pub mod index;
pub mod intent;
pub mod log;
pub mod pool;
pub mod registry;
pub mod replay;
pub mod scaling;
#[cfg(feature = "sharding")]
pub mod sharding;
pub mod state;
///
/// CANIC reserves its primary contiguous range during bootstrap.
///
pub const CANIC_MEMORY_MIN: u8 = 11;
pub const CANIC_MEMORY_MAX: u8 = 79;
///
/// CANIC stable memory IDs
///
/// Principles:
/// - IDs are grouped by state authority
/// - Each group owns a contiguous block
/// - Gaps between blocks are intentional expansion reserves
///
pub mod memory {
// =====================================================================
// Stable memory layout
//
// Conventions:
// - IDs are permanent once assigned
// - Ranges are intentionally reserved for future growth
// - Modules own their entire numeric range
// - This file is ordered by increasing ID, not by dependency
// =====================================================================
// ---------------------------------------------------------------------
// Topology & discovery state (11–15)
//
// Expected growth: low
// ---------------------------------------------------------------------
pub mod topology {
pub const CANISTER_CHILDREN_ID: u8 = 11;
pub const APP_INDEX_ID: u8 = 12;
pub const SUBNET_INDEX_ID: u8 = 13;
pub const APP_REGISTRY_ID: u8 = 14;
pub const SUBNET_REGISTRY_ID: u8 = 15;
}
// ---------------------------------------------------------------------
// Environment & runtime state (16–18)
//
// Expected growth: very low
// ---------------------------------------------------------------------
pub mod env {
pub const ENV_ID: u8 = 16;
pub const SUBNET_STATE_ID: u8 = 17;
pub const APP_STATE_ID: u8 = 18;
}
// ---------------------------------------------------------------------
// Auth & signing state (19–28)
//
// Expected growth: medium → high (structural, permanent)
// ---------------------------------------------------------------------
pub mod auth {
pub const AUTH_STATE_ID: u8 = 19;
#[expect(dead_code)]
// Historical root replay memory ID. Root replay moved to REPLAY_RECEIPTS_ID.
pub const ROOT_REPLAY_ID: u8 = 20;
pub const REPLAY_RECEIPTS_ID: u8 = 21;
// Reserved: 22–28
}
// ---------------------------------------------------------------------
// Observability & accounting (29–38)
//
// Expected growth: medium
// ---------------------------------------------------------------------
pub mod observability {
pub const CYCLE_TRACKER_ID: u8 = 29;
pub const CYCLE_TOPUP_EVENTS_ID: u8 = 30;
pub const LOG_INDEX_ID: u8 = 31;
pub const LOG_DATA_ID: u8 = 32;
pub const ICP_REFILL_RECORDS_ID: u8 = 33;
// Reserved: 34–38
}
// ---------------------------------------------------------------------
// Intent & reservation state (39–48)
//
// Expected growth: high
// ---------------------------------------------------------------------
pub mod intent {
pub const INTENT_META_ID: u8 = 39;
pub const INTENT_RECORDS_ID: u8 = 40;
pub const INTENT_TOTALS_ID: u8 = 41;
pub const INTENT_PENDING_ID: u8 = 42;
// Reserved: 43–48
}
// ---------------------------------------------------------------------
// Pool & capacity state (49–51)
//
// Expected growth: medium
// ---------------------------------------------------------------------
pub mod pool {
pub const CANISTER_POOL_ID: u8 = 49;
// Reserved: 50–51
}
// ---------------------------------------------------------------------
// Placement, scaling & sharding state (52–61)
//
// Expected growth: high
// ---------------------------------------------------------------------
pub mod placement {
pub const SCALING_REGISTRY_ID: u8 = 52;
#[cfg(feature = "sharding")]
pub const SHARDING_REGISTRY_ID: u8 = 53;
#[cfg(feature = "sharding")]
pub const SHARDING_ASSIGNMENT_ID: u8 = 54;
pub const DIRECTORY_REGISTRY_ID: u8 = 55;
#[cfg(feature = "sharding")]
pub const SHARDING_ACTIVE_SET_ID: u8 = 56;
// Reserved for:
// - placement policies
// - shard health / liveness
// - rebalance / drain state
// - migration metadata
// 57–61
}
// ---------------------------------------------------------------------
// Blob storage gateway lifecycle state (62–64)
//
// Expected growth: medium
// ---------------------------------------------------------------------
#[cfg(feature = "blob-storage")]
pub mod blob_storage {
pub const STORED_BLOBS_ID: u8 = 62;
pub const BLOB_DELETION_PENDING_ID: u8 = 63;
pub const STORAGE_GATEWAY_PRINCIPALS_ID: u8 = 64;
}
// 65-79 remain long-horizon Canic core reserve.
}
use crate::{InternalError, storage::prelude::*};
use thiserror::Error as ThisError;
///
/// StableMemoryError
///
#[derive(Debug, ThisError)]
pub enum StableMemoryError {
#[error("log write failed: current_size={current_size}, delta={delta}")]
LogWriteFailed { current_size: u64, delta: u64 },
}
impl From<StableMemoryError> for InternalError {
fn from(err: StableMemoryError) -> Self {
StorageError::StableMemory(err).into()
}
}