use crate::{
InternalError, InternalErrorOrigin, VERSION,
domain::policy::pure::env::{EnvInput, EnvPolicyError, validate_or_default},
dto::fleet_activation::{CurrentRootInstallIdentity, FleetActivationPhase},
ids::{CanisterRole, SubnetSlotId},
log::Topic,
ops::{
config::ConfigOps,
ic::{IcOps, build_network::BuildNetworkOps, release_build::ReleaseBuildOps},
runtime::{
env::EnvOps, fleet_activation::FleetActivationRuntimeOps, memory::MemoryRegistryOps,
},
storage::{
fleet_activation::FleetActivationOps, registry::subnet::SubnetRegistryOps,
state::fleet::FleetStateOps,
},
},
workflow::runtime::{
RuntimeWorkflow, auth::RuntimeAuthWorkflow, log_memory_summary,
rebuild_root_derived_storage_indexes, require_no_resumable_refill_for_upgrade,
},
};
pub fn init_root_canister(identity: CurrentRootInstallIdentity) -> Result<(), InternalError> {
MemoryRegistryOps::bootstrap_registry().map_err(|err| {
InternalError::invariant(
InternalErrorOrigin::Workflow,
format!("memory init failed: {err}"),
)
})?;
rebuild_root_derived_storage_indexes()?;
FleetActivationRuntimeOps::set_managed();
crate::log::set_ready();
let embedded_release_build_id = ReleaseBuildOps::embedded_release_build_id()?;
FleetActivationOps::initialize_root_prepared(identity.clone(), embedded_release_build_id)
.map_err(crate::ops::storage::StorageOpsError::from)?;
IcOps::println("");
IcOps::println("");
IcOps::println("");
crate::log!(
Topic::Init,
Info,
"🔧 --------------------- canic v{VERSION} -----------------------",
);
crate::log!(Topic::Init, Info, "🏁 init: root ({identity:?})");
log_memory_summary();
let self_pid = IcOps::canister_self();
let subnet_pid = self_pid;
let subnet_role = SubnetSlotId::DEFAULT;
let prime_root_pid = self_pid;
let module_hash = identity.expected_module_hash.map(|hash| hash.to_vec());
let input = EnvInput {
prime_root_pid: Some(prime_root_pid),
subnet_role: Some(subnet_role),
subnet_pid: Some(subnet_pid),
root_pid: Some(self_pid),
canister_role: Some(CanisterRole::ROOT),
parent_pid: Some(prime_root_pid),
};
let build_network = BuildNetworkOps::build_network().ok_or_else(|| {
InternalError::invariant(
InternalErrorOrigin::Workflow,
"build network unavailable; set ICP_ENVIRONMENT=local|ic at build time".to_string(),
)
})?;
crate::log!(Topic::Init, Info, "build network: {build_network}");
let validated = match validate_or_default(input) {
Ok(validated) => validated,
Err(EnvPolicyError::MissingEnvFields(missing)) => {
return Err(InternalError::invariant(
InternalErrorOrigin::Workflow,
format!("env args missing {missing}; local builds require explicit env fields"),
));
}
};
if let Err(err) = EnvOps::import_validated(validated) {
return Err(InternalError::invariant(
InternalErrorOrigin::Workflow,
format!("env import failed: {err}"),
));
}
let app_mode = ConfigOps::app_init_mode().map_err(|err| {
InternalError::invariant(
InternalErrorOrigin::Workflow,
format!("app mode init failed: {err}"),
)
})?;
FleetStateOps::init_mode(app_mode);
RuntimeAuthWorkflow::ensure_root_crypto_contract()?;
let created_at = IcOps::now_secs();
SubnetRegistryOps::register_root_with_module_hash(self_pid, created_at, module_hash);
Ok(())
}
pub fn post_upgrade_root_canister_after_memory_init() -> Result<bool, InternalError> {
rebuild_root_derived_storage_indexes()?;
FleetActivationRuntimeOps::set_managed();
require_no_resumable_refill_for_upgrade()?;
crate::log::set_ready();
crate::log!(Topic::Init, Info, "🏁 post_upgrade_root_canister");
log_memory_summary();
RuntimeAuthWorkflow::ensure_root_crypto_contract()?;
let active = FleetActivationOps::status(true)
.map_err(crate::ops::storage::StorageOpsError::from)?
.phase
== FleetActivationPhase::Active;
if active {
RuntimeWorkflow::start_all_root().map_err(|err| {
InternalError::invariant(
InternalErrorOrigin::Workflow,
format!("root service startup failed: {err}"),
)
})?;
}
Ok(active)
}