canic-core 0.100.32

Canic — a canister orchestration and management toolkit for the Internet Computer
Documentation
use crate::{
    dto::{env::EnvBootstrapArgs, prelude::*},
    ids::{
        ComponentBinding, ComponentChildBinding, FleetBinding, FleetSubnetRootBinding,
        ReleaseBuildId,
    },
};

///
/// CanisterInitAuthority
///
/// Exact authority from which one managed non-root initializes its immutable identity.
///

#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
pub enum CanisterInitAuthority {
    Infrastructure {
        fleet: FleetBinding,
        env: EnvBootstrapArgs,
    },
    Component {
        root: FleetSubnetRootBinding,
        binding: ComponentBinding,
    },
    ComponentChild {
        root: FleetSubnetRootBinding,
        binding: ComponentChildBinding,
    },
}

//
// CanisterInitPayload
//

#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq)]
pub struct CanisterInitPayload {
    pub install_id: [u8; 32],
    pub release_build_id: ReleaseBuildId,
    pub authority: CanisterInitAuthority,
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::cdk::types::Cycles;
    use crate::ids::{
        AppId, CanisterRole, CanonicalNetworkId, ComponentInstanceId, ComponentSpecId,
        ComponentTopologyDigest, CyclesFundingBudget, FleetCoordinatorBinding, FleetId, FleetKey,
        FleetRegistryAuthority, FleetSubnetRootLimits, ReleaseBuildNonce, SubnetId,
    };

    #[test]
    fn managed_nonroot_init_payload_roundtrips_the_exact_component_authority() {
        let fleet = FleetBinding {
            fleet: FleetKey {
                canonical_network_id: CanonicalNetworkId::public_ic(),
                fleet_id: FleetId::from_generated_bytes([1; 32]),
            },
            app: AppId::from("toko"),
        };
        let release_build_id =
            ReleaseBuildId::from_nonce(ReleaseBuildNonce::from_random_bytes([2; 32]));
        let principal = Principal::from_slice(&[3; 29]);
        let authority = FleetRegistryAuthority {
            binding: FleetCoordinatorBinding {
                fleet,
                coordinator_subnet: SubnetId::from_principal(Principal::from_slice(&[4; 29])),
                coordinator: Principal::from_slice(&[5; 29]),
            },
            epoch: 1,
        };
        let root = FleetSubnetRootBinding {
            authority: authority.clone(),
            placement_subnet: SubnetId::from_principal(Principal::from_slice(&[6; 29])),
            fleet_subnet_root: Principal::from_slice(&[7; 29]),
            component_admissions: Vec::new(),
            component_topology_digest: ComponentTopologyDigest::from_bytes([8; 32]),
            limits: FleetSubnetRootLimits {
                maximum_component_instances: 1,
                maximum_managed_canisters: 20_001,
                maximum_registry_bytes: 16 * 1_024 * 1_024,
                maximum_wasm_store_bytes: 16 * 1_024 * 1_024,
                cycles_funding: CyclesFundingBudget {
                    window_secs: 3_600,
                    maximum_cycles: Cycles::new(1_000_000_000_000),
                },
            },
        };
        let binding = ComponentBinding {
            authority,
            component: ComponentInstanceId::from_generated_bytes([9; 32]),
            component_spec: ComponentSpecId::try_from(String::from("default"))
                .expect("default Component Spec ID"),
            spec_hash: [10; 32],
            role: CanisterRole::new("app"),
            placement_subnet: root.placement_subnet,
            fleet_subnet_root: root.fleet_subnet_root,
            canister_id: principal,
        };
        let payload = CanisterInitPayload {
            install_id: [11; 32],
            release_build_id,
            authority: CanisterInitAuthority::Component {
                root,
                binding: binding.clone(),
            },
        };

        let bytes = candid::encode_one(&payload).expect("encode managed non-root init payload");
        let decoded: CanisterInitPayload =
            candid::decode_one(&bytes).expect("decode managed non-root init payload");

        assert_eq!(decoded.install_id, [11; 32]);
        assert_eq!(decoded.release_build_id, release_build_id);
        assert_eq!(
            decoded.authority,
            CanisterInitAuthority::Component {
                root: match &payload.authority {
                    CanisterInitAuthority::Component { root, .. } => root.clone(),
                    _ => unreachable!(),
                },
                binding,
            }
        );
    }
}