1use crate::ids::{FleetBinding, FleetKey, ReleaseBuildId};
8use candid::{CandidType, Principal};
9use serde::Deserialize;
10
11#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
17pub struct CurrentRootInstallIdentity {
18 pub fleet: FleetBinding,
19 pub install_id: [u8; 32],
20 pub release_build_id: ReleaseBuildId,
21 pub expected_module_hash: Option<[u8; 32]>,
22}
23
24#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
29pub struct FleetCascadeManifestEntry {
30 pub principal: Principal,
31 pub state_snapshot_hash: [u8; 32],
32 pub topology_snapshot_hash: [u8; 32],
33}
34
35#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
40pub enum FleetCascadeActivationEvidence {
41 Source {
42 cascade_manifest_hash: [u8; 32],
43 },
44 Applied {
45 state_snapshot_hash: [u8; 32],
46 topology_snapshot_hash: [u8; 32],
47 },
48}
49
50#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
55pub struct FleetCredentialGenerationRef {
56 pub generation: u64,
57 pub manifest_hash: [u8; 32],
58}
59
60#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
65pub struct FleetCredentialManifestEntry {
66 pub root_issuer: Principal,
67 pub subject_canister: Principal,
68 pub not_before_ns: u64,
69 pub expires_at_ns: u64,
70 pub key_identity_hash: [u8; 32],
71 pub cert_hash: [u8; 32],
72 pub proof_hash: [u8; 32],
73 pub bundle_hash: [u8; 32],
74}
75
76#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
81pub struct FleetCredentialManifest {
82 pub fleet: FleetKey,
83 pub activation_id: [u8; 32],
84 pub generation: u64,
85 pub root_policy_set_hash: [u8; 32],
86 pub renewal_template_set_hash: [u8; 32],
87 pub entries: Vec<FleetCredentialManifestEntry>,
88}
89
90#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
95pub struct FleetActivationIdentity {
96 pub fleet: FleetBinding,
97 pub operation_id: [u8; 32],
98 pub release_build_id: ReleaseBuildId,
99}
100
101#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
106pub enum FleetActivationPhase {
107 Prepared,
108 Active,
109}
110
111#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
116pub struct FleetActivationStatusResponse {
117 pub phase: FleetActivationPhase,
118 pub identity: FleetActivationIdentity,
119 pub cascade: Option<FleetCascadeActivationEvidence>,
120 pub cascade_manifest: Option<Vec<FleetCascadeManifestEntry>>,
121 pub credential: Option<FleetCredentialGenerationRef>,
122 pub credential_manifest: Option<FleetCredentialManifest>,
123 pub activated_at_ns: Option<u64>,
124}
125
126#[derive(Clone, Debug, Eq, PartialEq)]
131pub struct FleetHostCanisterActivationEvidence {
132 pub principal: Principal,
133 pub activation_evidence_hash: Option<[u8; 32]>,
134}
135
136#[derive(Clone, Debug, Eq, PartialEq)]
141pub struct FleetActivationHostRecord {
142 pub identity: FleetActivationIdentity,
143 pub cascade_manifest: Option<Vec<FleetCascadeManifestEntry>>,
144 pub credential: Option<FleetCredentialGenerationRef>,
145 pub credential_manifest: Option<FleetCredentialManifest>,
146 pub canisters: Vec<FleetHostCanisterActivationEvidence>,
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152 use crate::ids::{AppId, CanonicalNetworkId, FleetId, FleetKey, ReleaseBuildNonce};
153
154 fn fleet_binding() -> FleetBinding {
155 FleetBinding {
156 fleet: FleetKey {
157 network: CanonicalNetworkId::public_ic(),
158 fleet_id: FleetId::from_generated_bytes([7; 32]),
159 },
160 app: AppId::from("toko"),
161 }
162 }
163
164 #[test]
165 fn current_root_install_identity_roundtrips_with_text_ids() {
166 let input = CurrentRootInstallIdentity {
167 fleet: fleet_binding(),
168 install_id: [8; 32],
169 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
170 [9; 32],
171 )),
172 expected_module_hash: Some([10; 32]),
173 };
174
175 let bytes = candid::encode_one(&input).expect("encode current root install identity");
176 let decoded: CurrentRootInstallIdentity =
177 candid::decode_one(&bytes).expect("decode current root install identity");
178
179 assert_eq!(decoded, input);
180 }
181
182 #[test]
183 fn fleet_activation_status_roundtrips_as_named_candid_shapes() {
184 let input = FleetActivationStatusResponse {
185 phase: FleetActivationPhase::Prepared,
186 identity: FleetActivationIdentity {
187 fleet: fleet_binding(),
188 operation_id: [11; 32],
189 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
190 [12; 32],
191 )),
192 },
193 cascade: Some(FleetCascadeActivationEvidence::Source {
194 cascade_manifest_hash: [13; 32],
195 }),
196 cascade_manifest: Some(vec![FleetCascadeManifestEntry {
197 principal: Principal::from_slice(&[14; 29]),
198 state_snapshot_hash: [15; 32],
199 topology_snapshot_hash: [16; 32],
200 }]),
201 credential: None,
202 credential_manifest: None,
203 activated_at_ns: None,
204 };
205
206 let bytes = candid::encode_one(&input).expect("encode activation status");
207 let decoded: FleetActivationStatusResponse =
208 candid::decode_one(&bytes).expect("decode activation status");
209
210 assert_eq!(decoded, input);
211 }
212}