1use crate::{
8 cdk::types::Cycles,
9 config::schema::ComponentChildKind,
10 dto::{
11 fleet_registry::{FleetDirectorySnapshot, FleetRegistryVersion},
12 root_store::RootStoreBootstrapRequest,
13 },
14 ids::{
15 CanisterRole, ComponentBinding, ComponentChildBinding, ComponentInstanceId,
16 ComponentSpecId, ComponentTopologyDigest, FleetSubnetRootReleaseSet,
17 ManagedCanisterBinding,
18 },
19};
20use candid::{CandidType, Principal};
21use serde::{Deserialize, Serialize};
22
23#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
30pub struct RootComponentRegistryPreparationRequest {
31 pub store_bootstrap: RootStoreBootstrapRequest,
32 pub expected_fleet_registry: FleetRegistryVersion,
33}
34
35#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
42pub struct RootComponentInitialInventoryStatus {
43 pub fleet_activation_operation_id: [u8; 32],
44 pub component_count: u32,
45 pub inventory_hash: [u8; 32],
46 pub sealed_at_ns: u64,
47 pub directories_converged: bool,
48 pub root_runtime_activated: bool,
49}
50
51#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
58pub struct RootComponentRegistryStatusResponse {
59 pub fleet_subnet_root: Principal,
60 pub prepared_against_registry: FleetRegistryVersion,
61 pub release_set: FleetSubnetRootReleaseSet,
62 pub component_topology_digest: ComponentTopologyDigest,
63 pub next_allocation_sequence: u64,
64 pub reserved_component_instances: u32,
65 pub committed_component_instances: u32,
66 pub managed_descendants: u32,
67 pub known_created_component_canisters: u32,
68 pub encoded_bytes: u64,
69 pub initial_inventory: Option<RootComponentInitialInventoryStatus>,
70}
71
72#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
79pub struct RootComponentAllocationRequest {
80 pub operation_id: [u8; 32],
81 pub component_spec: ComponentSpecId,
82}
83
84#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
91pub struct RootComponentAllocationStatusRequest {
92 pub operation_id: [u8; 32],
93}
94
95#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
102pub struct RootComponentChildAllocationRequest {
103 pub operation_id: [u8; 32],
104 pub component: ComponentInstanceId,
105 pub expected_registry: ComponentRegistryHead,
106 pub child_role: CanisterRole,
107}
108
109#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
116pub struct RootComponentChildAllocationStatusRequest {
117 pub operation_id: [u8; 32],
118 pub component: ComponentInstanceId,
119}
120
121#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
128pub struct RootComponentChildCreationRequest {
129 pub operation_id: [u8; 32],
130 pub component: ComponentInstanceId,
131}
132
133#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
140pub struct RootComponentChildInstallRequest {
141 pub operation_id: [u8; 32],
142 pub component: ComponentInstanceId,
143}
144
145#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
152pub struct RootComponentCreationRequest {
153 pub operation_id: [u8; 32],
154}
155
156#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
163pub struct RootComponentInstallRequest {
164 pub operation_id: [u8; 32],
165}
166
167#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
174pub struct RootComponentCommitRequest {
175 pub operation_id: [u8; 32],
176}
177
178#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
185pub struct RootComponentDirectoryPreparationRequest {
186 pub operation_id: [u8; 32],
187}
188
189#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
196pub struct RootComponentRuntimeActivationRequest {
197 pub operation_id: [u8; 32],
198}
199
200#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
207pub struct RootComponentMembershipActivationRequest {
208 pub operation_id: [u8; 32],
209}
210
211#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
218pub enum ComponentProvisioningOrigin {
219 FleetAdministrator { caller: Principal },
220}
221
222#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
229pub enum RootComponentAllocationPhase {
230 Reserved,
231 CreationIntent,
232 Created,
233 InstallIntent,
234 Installed,
235 Verified,
236 Committed,
237}
238
239#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
246pub enum ComponentLifecycleStatus {
247 Prepared,
248 Active,
249 Draining,
250 Removed,
251}
252
253#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
260pub struct ComponentRegistryHead {
261 pub component: ComponentInstanceId,
262 pub revision: u64,
263 pub content_hash: [u8; 32],
264}
265
266#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
273pub struct ComponentRegistryPartitionRequest {
274 pub component: ComponentInstanceId,
275}
276
277#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
284pub struct ComponentRegistryPartitionResponse {
285 pub head: ComponentRegistryHead,
286 pub binding: ComponentBinding,
287 pub provisioning_origin: ComponentProvisioningOrigin,
288 pub release_set: FleetSubnetRootReleaseSet,
289 pub status: ComponentLifecycleStatus,
290 pub reserved_descendants: u32,
291 pub committed_descendants: u32,
292 pub encoded_bytes: u64,
293}
294
295#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
302pub struct ComponentDirectoryProvenance {
303 pub component: ComponentBinding,
304 pub source_fleet_subnet_root: Principal,
305 pub component_registry_revision: u64,
306 pub component_registry_content_hash: [u8; 32],
307 pub synchronized_at_ns: u64,
308}
309
310#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
317pub struct ComponentDirectoryHead {
318 pub provenance: ComponentDirectoryProvenance,
319 pub descendant_count: u32,
320}
321
322#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
329pub struct ComponentDirectoryHeadRequest {
330 pub component: ComponentInstanceId,
331}
332
333#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
340pub struct ComponentRuntimeDirectoryAuthority {
341 pub fleet: FleetDirectorySnapshot,
342 pub component: ComponentDirectoryHead,
343}
344
345#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
352pub struct ComponentRuntimeDirectoryPreparationRequest {
353 pub operation_id: [u8; 32],
354 pub authority: ComponentRuntimeDirectoryAuthority,
355}
356
357#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
364pub struct ComponentRuntimeDirectorySynchronizationRequest {
365 pub operation_id: [u8; 32],
366 pub authority: ComponentRuntimeDirectoryAuthority,
367}
368
369#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
376pub enum ComponentRuntimePhase {
377 AwaitingDirectory,
378 DirectoryPrepared,
379 Active,
380}
381
382#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
389pub struct ComponentRuntimeActivationEvidence {
390 pub directory_authority_hash: [u8; 32],
391 pub activated_at_ns: u64,
392}
393
394#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
401pub struct ComponentRuntimeActivationRequest {
402 pub operation_id: [u8; 32],
403 pub directory_authority_hash: [u8; 32],
404}
405
406#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
413pub struct ComponentRuntimeStatusResponse {
414 pub operation_id: [u8; 32],
415 pub binding: ManagedCanisterBinding,
416 pub phase: ComponentRuntimePhase,
417 pub authority: Option<ComponentRuntimeDirectoryAuthority>,
418 pub authority_hash: Option<[u8; 32]>,
419 pub activation: Option<ComponentRuntimeActivationEvidence>,
420}
421
422#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
429pub struct RootComponentCreationEvidence {
430 pub wasm_store: Principal,
431 pub payload_hash: [u8; 32],
432 pub payload_size_bytes: u64,
433 pub initial_cycles: Cycles,
434 pub controller: Principal,
435 pub canister: Option<Principal>,
436}
437
438#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
445pub struct RootComponentInstallEvidence {
446 pub raw_module_hash: [u8; 32],
447 pub chunk_hashes: Vec<Vec<u8>>,
448 pub binding: ComponentBinding,
449}
450
451#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
458pub struct RootComponentChildInstallEvidence {
459 pub raw_module_hash: [u8; 32],
460 pub chunk_hashes: Vec<Vec<u8>>,
461 pub binding: ComponentChildBinding,
462}
463
464#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
471pub struct RootComponentAllocationResponse {
472 pub operation_id: [u8; 32],
473 pub allocation_sequence: u64,
474 pub component: ComponentInstanceId,
475 pub component_spec: ComponentSpecId,
476 pub spec_hash: [u8; 32],
477 pub role: CanisterRole,
478 pub provisioning_origin: ComponentProvisioningOrigin,
479 pub release_set: FleetSubnetRootReleaseSet,
480 pub phase: RootComponentAllocationPhase,
481 pub creation: Option<RootComponentCreationEvidence>,
482 pub installation: Option<RootComponentInstallEvidence>,
483}
484
485#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
492pub struct RootComponentChildAllocationResponse {
493 pub operation_id: [u8; 32],
494 pub component: ComponentInstanceId,
495 pub parent_canister_id: Principal,
496 pub parent_role: CanisterRole,
497 pub child_role: CanisterRole,
498 pub child_kind: ComponentChildKind,
499 pub maximum_instances_per_parent: u32,
500 pub maximum_descendants: u32,
501 pub maximum_registry_bytes: u64,
502 pub reserved_against_registry: ComponentRegistryHead,
503 pub release_set: FleetSubnetRootReleaseSet,
504 pub phase: RootComponentAllocationPhase,
505 pub creation: Option<RootComponentCreationEvidence>,
506 pub installation: Option<RootComponentChildInstallEvidence>,
507}
508
509#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
516pub struct RootComponentCommitResponse {
517 pub allocation: RootComponentAllocationResponse,
518 pub registry: ComponentRegistryPartitionResponse,
519 pub directory: ComponentDirectoryHead,
520}
521
522#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
529pub struct RootComponentDirectoryPreparationResponse {
530 pub committed: RootComponentCommitResponse,
531 pub target: ComponentRuntimeStatusResponse,
532}
533
534#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
541pub struct RootComponentRuntimeActivationResponse {
542 pub committed: RootComponentCommitResponse,
543 pub target: ComponentRuntimeStatusResponse,
544}
545
546#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
553pub struct RootComponentMembershipActivationResponse {
554 pub allocation: RootComponentAllocationResponse,
555 pub registry: ComponentRegistryPartitionResponse,
556 pub directory: ComponentDirectoryHead,
557 pub target: ComponentRuntimeStatusResponse,
558}
559
560#[cfg(test)]
561mod tests {
562 use super::*;
563 use crate::{
564 dto::root_store::RootStoreBootstrapRequest,
565 ids::{
566 AppId, CanonicalNetworkId, FleetCoordinatorBinding, FleetId, FleetKey,
567 FleetRegistryAuthority, ReleaseBuildId, ReleaseBuildNonce, ReleaseSetDigest, SubnetId,
568 },
569 };
570
571 #[test]
572 fn component_registry_contracts_round_trip_through_candid() {
573 let request = RootComponentRegistryPreparationRequest {
574 store_bootstrap: RootStoreBootstrapRequest {
575 manifest_payload_size_bytes: 128,
576 },
577 expected_fleet_registry: FleetRegistryVersion {
578 authority: fleet_registry_authority(),
579 revision: 4,
580 content_hash: [5; 32],
581 },
582 };
583 let response = RootComponentRegistryStatusResponse {
584 fleet_subnet_root: Principal::from_slice(&[6; 29]),
585 prepared_against_registry: request.expected_fleet_registry.clone(),
586 release_set: FleetSubnetRootReleaseSet {
587 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
588 [7; 32],
589 )),
590 manifest_digest: ReleaseSetDigest::from_bytes([8; 32]),
591 },
592 component_topology_digest: ComponentTopologyDigest::from_bytes([9; 32]),
593 next_allocation_sequence: 1,
594 reserved_component_instances: 0,
595 committed_component_instances: 0,
596 managed_descendants: 0,
597 known_created_component_canisters: 0,
598 encoded_bytes: 0,
599 initial_inventory: Some(RootComponentInitialInventoryStatus {
600 fleet_activation_operation_id: [10; 32],
601 component_count: 0,
602 inventory_hash: [11; 32],
603 sealed_at_ns: 12,
604 directories_converged: true,
605 root_runtime_activated: true,
606 }),
607 };
608 let allocation = RootComponentAllocationResponse {
609 operation_id: [10; 32],
610 allocation_sequence: 1,
611 component: ComponentInstanceId::from_generated_bytes([11; 32]),
612 component_spec: "projects".parse().expect("Component Spec ID"),
613 spec_hash: [12; 32],
614 role: CanisterRole::new("project_hub"),
615 provisioning_origin: ComponentProvisioningOrigin::FleetAdministrator {
616 caller: Principal::from_slice(&[13; 29]),
617 },
618 release_set: response.release_set,
619 phase: RootComponentAllocationPhase::Reserved,
620 creation: None,
621 installation: None,
622 };
623 let created = RootComponentAllocationResponse {
624 phase: RootComponentAllocationPhase::Created,
625 creation: Some(RootComponentCreationEvidence {
626 wasm_store: Principal::from_slice(&[14; 29]),
627 payload_hash: [15; 32],
628 payload_size_bytes: 4_096,
629 initial_cycles: Cycles::new(5_000_000_000_000),
630 controller: Principal::from_slice(&[6; 29]),
631 canister: Some(Principal::from_slice(&[16; 29])),
632 }),
633 installation: None,
634 ..allocation.clone()
635 };
636 let request_bytes = candid::encode_one(&request).expect("encode request");
637 let response_bytes = candid::encode_one(&response).expect("encode response");
638 let allocation_bytes = candid::encode_one(&allocation).expect("encode allocation");
639 let created_bytes = candid::encode_one(&created).expect("encode created allocation");
640
641 assert_eq!(
642 candid::decode_one::<RootComponentRegistryPreparationRequest>(&request_bytes)
643 .expect("decode request"),
644 request
645 );
646 assert_eq!(
647 candid::decode_one::<RootComponentRegistryStatusResponse>(&response_bytes)
648 .expect("decode response"),
649 response
650 );
651 assert_eq!(
652 candid::decode_one::<RootComponentAllocationResponse>(&allocation_bytes)
653 .expect("decode allocation"),
654 allocation
655 );
656 assert_eq!(
657 candid::decode_one::<RootComponentAllocationResponse>(&created_bytes)
658 .expect("decode created allocation"),
659 created
660 );
661 }
662
663 #[test]
664 fn component_commit_response_round_trips_through_candid() {
665 let root = Principal::from_slice(&[6; 29]);
666 let component = ComponentInstanceId::from_generated_bytes([11; 32]);
667 let component_spec: ComponentSpecId = "projects".parse().expect("Component Spec ID");
668 let release_set = FleetSubnetRootReleaseSet {
669 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
670 [7; 32],
671 )),
672 manifest_digest: ReleaseSetDigest::from_bytes([8; 32]),
673 };
674 let provisioning_origin = ComponentProvisioningOrigin::FleetAdministrator {
675 caller: Principal::from_slice(&[13; 29]),
676 };
677 let binding = ComponentBinding {
678 authority: fleet_registry_authority(),
679 component,
680 component_spec: component_spec.clone(),
681 spec_hash: [12; 32],
682 role: CanisterRole::new("project_hub"),
683 placement_subnet: SubnetId::from_principal(Principal::from_slice(&[17; 29])),
684 fleet_subnet_root: root,
685 canister_id: Principal::from_slice(&[16; 29]),
686 };
687 let head = ComponentRegistryHead {
688 component,
689 revision: 1,
690 content_hash: [18; 32],
691 };
692 let committed = RootComponentCommitResponse {
693 allocation: RootComponentAllocationResponse {
694 operation_id: [10; 32],
695 allocation_sequence: 1,
696 component,
697 component_spec,
698 spec_hash: binding.spec_hash,
699 role: binding.role.clone(),
700 provisioning_origin: provisioning_origin.clone(),
701 release_set,
702 phase: RootComponentAllocationPhase::Committed,
703 creation: Some(RootComponentCreationEvidence {
704 wasm_store: Principal::from_slice(&[14; 29]),
705 payload_hash: [15; 32],
706 payload_size_bytes: 4_096,
707 initial_cycles: Cycles::new(5_000_000_000_000),
708 controller: root,
709 canister: Some(binding.canister_id),
710 }),
711 installation: Some(RootComponentInstallEvidence {
712 raw_module_hash: [20; 32],
713 chunk_hashes: vec![vec![21; 32]],
714 binding: binding.clone(),
715 }),
716 },
717 registry: ComponentRegistryPartitionResponse {
718 head: head.clone(),
719 binding: binding.clone(),
720 provisioning_origin,
721 release_set,
722 status: ComponentLifecycleStatus::Prepared,
723 reserved_descendants: 0,
724 committed_descendants: 0,
725 encoded_bytes: 2_048,
726 },
727 directory: ComponentDirectoryHead {
728 provenance: ComponentDirectoryProvenance {
729 component: binding,
730 source_fleet_subnet_root: root,
731 component_registry_revision: head.revision,
732 component_registry_content_hash: head.content_hash,
733 synchronized_at_ns: 19,
734 },
735 descendant_count: 0,
736 },
737 };
738 let committed_bytes = candid::encode_one(&committed).expect("encode committed allocation");
739
740 assert_eq!(
741 candid::decode_one::<RootComponentCommitResponse>(&committed_bytes)
742 .expect("decode committed allocation"),
743 committed
744 );
745 }
746
747 fn fleet_registry_authority() -> FleetRegistryAuthority {
748 FleetRegistryAuthority {
749 binding: FleetCoordinatorBinding {
750 fleet: crate::ids::FleetBinding {
751 fleet: FleetKey {
752 canonical_network_id: CanonicalNetworkId::public_ic(),
753 fleet_id: FleetId::from_generated_bytes([1; 32]),
754 },
755 app: AppId::from("toko"),
756 },
757 coordinator_subnet: SubnetId::from_principal(Principal::from_slice(&[2; 29])),
758 coordinator: Principal::from_slice(&[3; 29]),
759 },
760 epoch: 1,
761 }
762 }
763
764 #[test]
765 fn component_creation_request_round_trips_through_candid() {
766 let request = RootComponentCreationRequest {
767 operation_id: [10; 32],
768 };
769 let bytes = candid::encode_one(request).expect("encode creation request");
770
771 assert_eq!(
772 candid::decode_one::<RootComponentCreationRequest>(&bytes)
773 .expect("decode creation request"),
774 request
775 );
776 }
777
778 #[test]
779 #[expect(
780 clippy::too_many_lines,
781 reason = "one round-trip test keeps the complete child lifecycle boundary coherent"
782 )]
783 fn component_child_lifecycle_contracts_round_trip_through_candid() {
784 let component = ComponentInstanceId::from_generated_bytes([11; 32]);
785 let registry = ComponentRegistryHead {
786 component,
787 revision: 2,
788 content_hash: [12; 32],
789 };
790 let request = RootComponentChildAllocationRequest {
791 operation_id: [13; 32],
792 component,
793 expected_registry: registry.clone(),
794 child_role: CanisterRole::new("project_instance"),
795 };
796 let status_request = RootComponentChildAllocationStatusRequest {
797 operation_id: request.operation_id,
798 component,
799 };
800 let creation_request = RootComponentChildCreationRequest {
801 operation_id: request.operation_id,
802 component,
803 };
804 let install_request = RootComponentChildInstallRequest {
805 operation_id: request.operation_id,
806 component,
807 };
808 let root = Principal::from_slice(&[17; 29]);
809 let parent = Principal::from_slice(&[14; 29]);
810 let child = Principal::from_slice(&[18; 29]);
811 let child_binding = ComponentChildBinding {
812 component: ComponentBinding {
813 authority: fleet_registry_authority(),
814 component,
815 component_spec: "projects".parse().expect("Component Spec"),
816 spec_hash: [19; 32],
817 role: CanisterRole::new("project_hub"),
818 placement_subnet: SubnetId::from_principal(Principal::from_slice(&[20; 29])),
819 fleet_subnet_root: root,
820 canister_id: parent,
821 },
822 parent_canister_id: parent,
823 role: request.child_role.clone(),
824 canister_id: child,
825 };
826 let response = RootComponentChildAllocationResponse {
827 operation_id: request.operation_id,
828 component,
829 parent_canister_id: parent,
830 parent_role: CanisterRole::new("project_hub"),
831 child_role: request.child_role.clone(),
832 child_kind: ComponentChildKind::Instance,
833 maximum_instances_per_parent: 10_000,
834 maximum_descendants: 20_000,
835 maximum_registry_bytes: 16_777_216,
836 reserved_against_registry: registry,
837 release_set: FleetSubnetRootReleaseSet {
838 release_build_id: ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes(
839 [15; 32],
840 )),
841 manifest_digest: ReleaseSetDigest::from_bytes([16; 32]),
842 },
843 phase: RootComponentAllocationPhase::Verified,
844 creation: Some(RootComponentCreationEvidence {
845 wasm_store: Principal::from_slice(&[21; 29]),
846 payload_hash: [22; 32],
847 payload_size_bytes: 4_096,
848 initial_cycles: Cycles::new(5_000_000_000_000),
849 controller: root,
850 canister: Some(child),
851 }),
852 installation: Some(RootComponentChildInstallEvidence {
853 raw_module_hash: [23; 32],
854 chunk_hashes: vec![vec![24; 32]],
855 binding: child_binding,
856 }),
857 };
858
859 let request_bytes = candid::encode_one(&request).expect("encode child reservation");
860 let status_bytes =
861 candid::encode_one(status_request).expect("encode child reservation status");
862 let creation_bytes =
863 candid::encode_one(creation_request).expect("encode child creation request");
864 let install_bytes =
865 candid::encode_one(install_request).expect("encode child install request");
866 let response_bytes = candid::encode_one(&response).expect("encode child response");
867
868 assert_eq!(
869 candid::decode_one::<RootComponentChildAllocationRequest>(&request_bytes)
870 .expect("decode child reservation"),
871 request
872 );
873 assert_eq!(
874 candid::decode_one::<RootComponentChildAllocationStatusRequest>(&status_bytes)
875 .expect("decode child reservation status"),
876 status_request
877 );
878 assert_eq!(
879 candid::decode_one::<RootComponentChildCreationRequest>(&creation_bytes)
880 .expect("decode child creation request"),
881 creation_request
882 );
883 assert_eq!(
884 candid::decode_one::<RootComponentChildInstallRequest>(&install_bytes)
885 .expect("decode child install request"),
886 install_request
887 );
888 assert_eq!(
889 candid::decode_one::<RootComponentChildAllocationResponse>(&response_bytes)
890 .expect("decode child response"),
891 response
892 );
893 }
894
895 #[test]
896 fn component_install_request_round_trips_through_candid() {
897 let request = RootComponentInstallRequest {
898 operation_id: [10; 32],
899 };
900 let bytes = candid::encode_one(request).expect("encode install request");
901
902 assert_eq!(
903 candid::decode_one::<RootComponentInstallRequest>(&bytes)
904 .expect("decode install request"),
905 request
906 );
907 }
908
909 #[test]
910 fn component_commit_request_round_trips_through_candid() {
911 let request = RootComponentCommitRequest {
912 operation_id: [10; 32],
913 };
914 let bytes = candid::encode_one(request).expect("encode commit request");
915
916 assert_eq!(
917 candid::decode_one::<RootComponentCommitRequest>(&bytes)
918 .expect("decode commit request"),
919 request
920 );
921 }
922
923 #[test]
924 fn component_runtime_activation_requests_round_trip_through_candid() {
925 let root_request = RootComponentRuntimeActivationRequest {
926 operation_id: [22; 32],
927 };
928 let target_request = ComponentRuntimeActivationRequest {
929 operation_id: root_request.operation_id,
930 directory_authority_hash: [23; 32],
931 };
932 let membership_request = RootComponentMembershipActivationRequest {
933 operation_id: root_request.operation_id,
934 };
935 let root_bytes = candid::encode_one(root_request).expect("encode root activation request");
936 let target_bytes =
937 candid::encode_one(target_request).expect("encode target activation request");
938 let membership_bytes =
939 candid::encode_one(membership_request).expect("encode membership activation request");
940
941 assert_eq!(
942 candid::decode_one::<RootComponentRuntimeActivationRequest>(&root_bytes)
943 .expect("decode root activation request"),
944 root_request
945 );
946 assert_eq!(
947 candid::decode_one::<ComponentRuntimeActivationRequest>(&target_bytes)
948 .expect("decode target activation request"),
949 target_request
950 );
951 assert_eq!(
952 candid::decode_one::<RootComponentMembershipActivationRequest>(&membership_bytes)
953 .expect("decode membership activation request"),
954 membership_request
955 );
956 }
957}