1use crate::{
8 dto::{fleet_registry::FleetRegistryVersion, root_store::RootStoreBootstrapRequest},
9 ids::{
10 CanisterRole, ComponentInstanceId, ComponentSpecId, ComponentTopologyDigest,
11 FleetSubnetRootReleaseSet,
12 },
13};
14use candid::{CandidType, Principal};
15use serde::{Deserialize, Serialize};
16
17#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
24pub struct RootComponentRegistryPreparationRequest {
25 pub store_bootstrap: RootStoreBootstrapRequest,
26 pub expected_fleet_registry: FleetRegistryVersion,
27}
28
29#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
36pub struct RootComponentRegistryStatusResponse {
37 pub fleet_subnet_root: Principal,
38 pub prepared_against_registry: FleetRegistryVersion,
39 pub release_set: FleetSubnetRootReleaseSet,
40 pub component_topology_digest: ComponentTopologyDigest,
41 pub next_allocation_sequence: u64,
42 pub reserved_component_instances: u32,
43 pub committed_component_instances: u32,
44 pub managed_descendants: u32,
45 pub encoded_bytes: u64,
46}
47
48#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
55pub struct RootComponentAllocationRequest {
56 pub operation_id: [u8; 32],
57 pub component_spec: ComponentSpecId,
58}
59
60#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
67pub struct RootComponentAllocationStatusRequest {
68 pub operation_id: [u8; 32],
69}
70
71#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
78pub enum ComponentProvisioningOrigin {
79 FleetAdministrator { caller: Principal },
80}
81
82#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
89pub enum RootComponentAllocationPhase {
90 Reserved,
91}
92
93#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
100pub struct RootComponentAllocationResponse {
101 pub operation_id: [u8; 32],
102 pub allocation_sequence: u64,
103 pub component: ComponentInstanceId,
104 pub component_spec: ComponentSpecId,
105 pub spec_hash: [u8; 32],
106 pub role: CanisterRole,
107 pub provisioning_origin: ComponentProvisioningOrigin,
108 pub release_set: FleetSubnetRootReleaseSet,
109 pub phase: RootComponentAllocationPhase,
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::{
116 dto::root_store::RootStoreBootstrapRequest,
117 ids::{
118 AppId, CanonicalNetworkId, FleetCoordinatorBinding, FleetId, FleetKey,
119 FleetRegistryAuthority, ReleaseBuildId, ReleaseBuildNonce, ReleaseSetDigest, SubnetId,
120 },
121 };
122
123 #[test]
124 fn component_registry_contracts_round_trip_through_candid() {
125 let authority = FleetRegistryAuthority {
126 binding: FleetCoordinatorBinding {
127 fleet: crate::ids::FleetBinding {
128 fleet: FleetKey {
129 canonical_network_id: CanonicalNetworkId::public_ic(),
130 fleet_id: FleetId::from_generated_bytes([1; 32]),
131 },
132 app: AppId::from("toko"),
133 },
134 coordinator_subnet: SubnetId::from_principal(Principal::from_slice(&[2; 29])),
135 coordinator: Principal::from_slice(&[3; 29]),
136 },
137 epoch: 1,
138 };
139 let request = RootComponentRegistryPreparationRequest {
140 store_bootstrap: RootStoreBootstrapRequest {
141 manifest_payload_size_bytes: 128,
142 },
143 expected_fleet_registry: FleetRegistryVersion {
144 authority,
145 revision: 4,
146 content_hash: [5; 32],
147 },
148 };
149 let response = RootComponentRegistryStatusResponse {
150 fleet_subnet_root: Principal::from_slice(&[6; 29]),
151 prepared_against_registry: request.expected_fleet_registry.clone(),
152 release_set: FleetSubnetRootReleaseSet {
153 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
154 [7; 32],
155 )),
156 manifest_digest: ReleaseSetDigest::from_bytes([8; 32]),
157 },
158 component_topology_digest: ComponentTopologyDigest::from_bytes([9; 32]),
159 next_allocation_sequence: 1,
160 reserved_component_instances: 0,
161 committed_component_instances: 0,
162 managed_descendants: 0,
163 encoded_bytes: 0,
164 };
165 let allocation = RootComponentAllocationResponse {
166 operation_id: [10; 32],
167 allocation_sequence: 1,
168 component: ComponentInstanceId::from_generated_bytes([11; 32]),
169 component_spec: "projects".parse().expect("Component Spec ID"),
170 spec_hash: [12; 32],
171 role: CanisterRole::new("project_hub"),
172 provisioning_origin: ComponentProvisioningOrigin::FleetAdministrator {
173 caller: Principal::from_slice(&[13; 29]),
174 },
175 release_set: response.release_set,
176 phase: RootComponentAllocationPhase::Reserved,
177 };
178
179 let request_bytes = candid::encode_one(&request).expect("encode request");
180 let response_bytes = candid::encode_one(&response).expect("encode response");
181 let allocation_bytes = candid::encode_one(&allocation).expect("encode allocation");
182
183 assert_eq!(
184 candid::decode_one::<RootComponentRegistryPreparationRequest>(&request_bytes)
185 .expect("decode request"),
186 request
187 );
188 assert_eq!(
189 candid::decode_one::<RootComponentRegistryStatusResponse>(&response_bytes)
190 .expect("decode response"),
191 response
192 );
193 assert_eq!(
194 candid::decode_one::<RootComponentAllocationResponse>(&allocation_bytes)
195 .expect("decode allocation"),
196 allocation
197 );
198 }
199}