1use crate::{
8 cdk::types::Cycles,
9 ids::{
10 CanisterRole, ComponentInstanceId, ComponentSpecId, FleetBinding, ReleaseBuildId,
11 ReleaseSetDigest, SubnetId,
12 },
13};
14use candid::{CandidType, Principal};
15use serde::{Deserialize, Serialize};
16use std::fmt;
17
18#[derive(
25 CandidType, Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
26)]
27#[serde(transparent)]
28pub struct ComponentTopologyDigest([u8; 32]);
29
30impl ComponentTopologyDigest {
31 #[must_use]
32 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
33 Self(bytes)
34 }
35
36 #[must_use]
37 pub const fn as_bytes(&self) -> &[u8; 32] {
38 &self.0
39 }
40
41 #[must_use]
42 pub const fn into_bytes(self) -> [u8; 32] {
43 self.0
44 }
45}
46
47impl fmt::Display for ComponentTopologyDigest {
48 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
49 for byte in self.0 {
50 write!(formatter, "{byte:02x}")?;
51 }
52 Ok(())
53 }
54}
55
56#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
63#[serde(deny_unknown_fields)]
64pub struct CyclesFundingBudget {
65 pub window_secs: u64,
66 pub maximum_cycles: Cycles,
67}
68
69#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
71pub enum FleetFundingProfile {
72 #[serde(rename = "single_subnet")]
73 SingleSubnet,
74 #[serde(rename = "multi_subnet")]
75 MultiSubnet,
76 #[serde(rename = "preview_multi_subnet")]
77 PreviewMultiSubnet,
78}
79
80pub const COORDINATOR_ROOT_FUNDING_EXECUTION_RESERVE_FLOOR_CYCLES: u128 = 100_000_000;
82
83pub const FLEET_ROOT_FUNDING_CALL_RESERVATION_CYCLES: u128 = 42_118_809_000;
85
86pub const FLEET_SUBNET_ROOT_FUNDING_REQUEST_FLOOR_CYCLES: u128 = 42_200_000_000;
88
89pub const FLEET_SUBNET_ROOT_ICP_REFILL_FLOOR_CYCLES: u128 = 42_200_000_000;
91
92pub const MAX_FLEET_ROOT_FUNDING_SLOTS: usize = 4_096;
94
95#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
102#[serde(deny_unknown_fields)]
103pub struct FleetCoordinatorRootFundingPolicy {
104 pub funding_profile: FleetFundingProfile,
105 pub minimum_reserve_cycles: Cycles,
106 pub budget: CyclesFundingBudget,
107 pub maximum_automatic_grants: u32,
108 pub maximum_automatic_cycles: Cycles,
109}
110
111#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
118#[serde(deny_unknown_fields)]
119pub struct FleetSubnetRootFundingPolicy {
120 pub funding_profile: FleetFundingProfile,
121 pub request_threshold: Cycles,
122 pub target_balance: Cycles,
123 pub cooldown_secs: u64,
124 pub budget: CyclesFundingBudget,
125 pub maximum_automatic_grants: u32,
126 pub maximum_automatic_cycles: Cycles,
127}
128
129#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
136#[serde(deny_unknown_fields)]
137pub struct FleetSubnetRootAutomaticIcpRefillPolicy {
138 pub emergency_threshold: Cycles,
139 pub target_balance: Cycles,
140 pub maximum_automatic_refills: u32,
141 pub maximum_automatic_refill_e8s: u64,
142}
143
144#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
151#[serde(deny_unknown_fields)]
152pub struct FleetSubnetRootIcpRefillPolicy {
153 pub max_refill_e8s_per_call: u64,
154 pub window_secs: u64,
155 pub maximum_refill_e8s: u64,
156 pub minimum_icp_balance_e8s: u64,
157 pub min_xdr_permyriad_per_icp: Option<u64>,
158 pub ledger_canister_id: Option<Principal>,
159 pub cmc_canister_id: Option<Principal>,
160 pub allow_ic_system_canister_overrides: bool,
161 pub automatic: Option<FleetSubnetRootAutomaticIcpRefillPolicy>,
162}
163
164#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
171#[serde(deny_unknown_fields)]
172pub struct FleetSubnetRootFundingAuthority {
173 pub root_funding: FleetSubnetRootFundingPolicy,
174 pub icp_refill: Option<FleetSubnetRootIcpRefillPolicy>,
175}
176
177#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
184#[serde(deny_unknown_fields)]
185pub struct FleetSubnetCanisterPoolConfig {
186 pub minimum_size: u32,
188 pub maximum_size: u32,
192 pub canister_cycles: Cycles,
194}
195
196#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
203#[serde(deny_unknown_fields)]
204pub struct ComponentSpecAdmission {
205 pub component_spec: ComponentSpecId,
206 pub spec_hash: [u8; 32],
207 pub maximum_root_instances: u32,
208}
209
210#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
217#[serde(deny_unknown_fields)]
218pub struct FleetSubnetRootLimits {
219 pub maximum_component_instances: u32,
220 pub maximum_registry_bytes: u64,
221 pub maximum_wasm_store_bytes: u64,
222 pub canister_pool: FleetSubnetCanisterPoolConfig,
223 pub cycles_funding: CyclesFundingBudget,
224 pub maximum_group_placements: u32,
226}
227
228#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
235#[serde(deny_unknown_fields)]
236pub struct FleetCoordinatorBinding {
237 pub fleet: FleetBinding,
238 pub coordinator_subnet: SubnetId,
239 pub coordinator: Principal,
240}
241
242#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
249#[serde(deny_unknown_fields)]
250pub struct FleetRegistryAuthority {
251 pub binding: FleetCoordinatorBinding,
252 pub epoch: u64,
253}
254
255#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
262#[serde(deny_unknown_fields)]
263pub struct FleetSubnetRootBinding {
264 pub authority: FleetRegistryAuthority,
265 pub placement_subnet: SubnetId,
266 pub fleet_subnet_root: Principal,
267 pub component_admissions: Vec<ComponentSpecAdmission>,
268 pub component_topology_digest: ComponentTopologyDigest,
269 pub limits: FleetSubnetRootLimits,
270 pub funding: FleetSubnetRootFundingAuthority,
271}
272
273#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
280#[serde(deny_unknown_fields)]
281pub struct FleetSubnetWasmStoreAuthority {
282 pub authority: FleetRegistryAuthority,
283 pub placement_subnet: SubnetId,
284 pub fleet_subnet_root: Principal,
285 pub wasm_store: Principal,
286 pub installation_controller: Principal,
287 pub release_build_id: ReleaseBuildId,
288 pub wasm_module_hash: [u8; 32],
289}
290
291#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
293pub struct FleetSubnetWasmStoreActivationAuthority {
294 pub fleet: FleetBinding,
295 pub operation_id: [u8; 32],
296 pub fleet_subnet_root: Principal,
297 pub wasm_store: Principal,
298 pub release_build_id: ReleaseBuildId,
299 pub component_topology_digest: ComponentTopologyDigest,
300 pub controllers: Vec<Principal>,
301 pub manifest_digest: ReleaseSetDigest,
302}
303
304#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
311#[serde(deny_unknown_fields)]
312pub struct ComponentBinding {
313 pub authority: FleetRegistryAuthority,
314 pub component: ComponentInstanceId,
315 pub component_spec: ComponentSpecId,
316 pub spec_hash: [u8; 32],
317 pub role: CanisterRole,
318 pub placement_subnet: SubnetId,
319 pub fleet_subnet_root: Principal,
320 pub canister_id: Principal,
321}
322
323#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
330#[serde(deny_unknown_fields)]
331pub struct ComponentChildBinding {
332 pub component: ComponentBinding,
333 pub parent_canister_id: Principal,
334 pub role: CanisterRole,
335 pub canister_id: Principal,
336}
337
338#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
345#[serde(deny_unknown_fields)]
346pub enum ManagedCanisterBinding {
347 Component(ComponentBinding),
348 ComponentChild(ComponentChildBinding),
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354
355 #[test]
356 fn funding_profile_candid_spelling_roundtrips() {
357 for profile in [
358 FleetFundingProfile::SingleSubnet,
359 FleetFundingProfile::PreviewMultiSubnet,
360 FleetFundingProfile::MultiSubnet,
361 ] {
362 let bytes = candid::encode_one(profile).expect("encode funding profile Candid");
363 assert_eq!(
364 candid::decode_one::<FleetFundingProfile>(&bytes)
365 .expect("decode funding profile Candid"),
366 profile
367 );
368 }
369 }
370}