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 pub creation_execution_margin: Cycles,
197}
198
199#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
206#[serde(deny_unknown_fields)]
207pub struct ComponentSpecAdmission {
208 pub component_spec: ComponentSpecId,
209 pub spec_hash: [u8; 32],
210 pub maximum_root_instances: u32,
211}
212
213#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
220#[serde(deny_unknown_fields)]
221pub struct FleetSubnetRootLimits {
222 pub maximum_component_instances: u32,
223 pub maximum_registry_bytes: u64,
224 pub maximum_wasm_store_bytes: u64,
225 pub canister_pool: FleetSubnetCanisterPoolConfig,
226 pub cycles_funding: CyclesFundingBudget,
227 pub maximum_group_placements: u32,
229}
230
231#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
238#[serde(deny_unknown_fields)]
239pub struct FleetCoordinatorBinding {
240 pub fleet: FleetBinding,
241 pub coordinator_subnet: SubnetId,
242 pub coordinator: Principal,
243}
244
245#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
252#[serde(deny_unknown_fields)]
253pub struct FleetRegistryAuthority {
254 pub binding: FleetCoordinatorBinding,
255 pub epoch: u64,
256}
257
258#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
265#[serde(deny_unknown_fields)]
266pub struct FleetSubnetRootBinding {
267 pub authority: FleetRegistryAuthority,
268 pub placement_subnet: SubnetId,
269 pub fleet_subnet_root: Principal,
270 pub component_admissions: Vec<ComponentSpecAdmission>,
271 pub component_topology_digest: ComponentTopologyDigest,
272 pub limits: FleetSubnetRootLimits,
273 pub funding: FleetSubnetRootFundingAuthority,
274}
275
276#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
283#[serde(deny_unknown_fields)]
284pub struct FleetSubnetWasmStoreAuthority {
285 pub authority: FleetRegistryAuthority,
286 pub placement_subnet: SubnetId,
287 pub fleet_subnet_root: Principal,
288 pub wasm_store: Principal,
289 pub installation_controller: Principal,
290 pub release_build_id: ReleaseBuildId,
291 pub wasm_module_hash: [u8; 32],
292}
293
294#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
296pub struct FleetSubnetWasmStoreActivationAuthority {
297 pub fleet: FleetBinding,
298 pub operation_id: [u8; 32],
299 pub fleet_subnet_root: Principal,
300 pub wasm_store: Principal,
301 pub release_build_id: ReleaseBuildId,
302 pub component_topology_digest: ComponentTopologyDigest,
303 pub controllers: Vec<Principal>,
304 pub manifest_digest: ReleaseSetDigest,
305}
306
307#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
314#[serde(deny_unknown_fields)]
315pub struct ComponentBinding {
316 pub authority: FleetRegistryAuthority,
317 pub component: ComponentInstanceId,
318 pub component_spec: ComponentSpecId,
319 pub spec_hash: [u8; 32],
320 pub role: CanisterRole,
321 pub placement_subnet: SubnetId,
322 pub fleet_subnet_root: Principal,
323 pub canister_id: Principal,
324}
325
326#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
333#[serde(deny_unknown_fields)]
334pub struct ComponentChildBinding {
335 pub component: ComponentBinding,
336 pub parent_canister_id: Principal,
337 pub role: CanisterRole,
338 pub canister_id: Principal,
339}
340
341#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
348#[serde(deny_unknown_fields)]
349pub enum ManagedCanisterBinding {
350 Component(ComponentBinding),
351 ComponentChild(ComponentChildBinding),
352}
353
354#[cfg(test)]
355mod tests {
356 use super::*;
357
358 #[test]
359 fn funding_profile_candid_spelling_roundtrips() {
360 for profile in [
361 FleetFundingProfile::SingleSubnet,
362 FleetFundingProfile::PreviewMultiSubnet,
363 FleetFundingProfile::MultiSubnet,
364 ] {
365 let bytes = candid::encode_one(profile).expect("encode funding profile Candid");
366 assert_eq!(
367 candid::decode_one::<FleetFundingProfile>(&bytes)
368 .expect("decode funding profile Candid"),
369 profile
370 );
371 }
372 }
373}