canic_core/ops/
mod.rs

1//! Business-logic helpers that sit between endpoint handlers and the state
2//! layer.
3//!
4//! The ops layer orchestrates multi-step workflows such as provisioning new
5//! canisters,  running scaling/sharding policies, and
6//! synchronizing topology snapshots. Endpoint macros call into these modules so
7//! the public surface remains thin while policy, logging, and validation live
8//! here.
9
10pub mod bootstrap;
11pub mod command;
12pub mod config;
13pub mod ic;
14pub mod icrc;
15pub mod orchestration;
16pub mod perf;
17pub mod placement;
18pub mod reserve;
19pub mod rpc;
20pub mod runtime;
21pub mod service;
22pub mod storage;
23pub mod wasm;
24
25use std::time::Duration;
26
27///
28/// Constants
29///
30
31/// Shared initial delay for ops timers to allow init work to settle.
32pub const OPS_INIT_DELAY: Duration = Duration::from_secs(10);
33
34/// Shared cadence for cycle tracking (10 minutes).
35pub const OPS_CYCLE_TRACK_INTERVAL: Duration = Duration::from_secs(60 * 10);
36
37/// Shared cadence for log retention (10 minutes).
38pub const OPS_LOG_RETENTION_INTERVAL: Duration = Duration::from_secs(60 * 10);
39
40/// Reserve timer initial delay (30 seconds) before first check.
41pub const OPS_RESERVE_INIT_DELAY: Duration = Duration::from_secs(30);
42
43/// Reserve check cadence (30 minutes).
44pub const OPS_RESERVE_CHECK_INTERVAL: Duration = Duration::from_secs(30 * 60);
45
46///
47/// Prelude
48///
49
50/// Common imports for ops submodules and consumers.
51pub mod prelude {
52    pub use crate::{
53        cdk::{
54            api::{canister_self, msg_caller},
55            candid::CandidType,
56            types::{Account, Int, Nat, Principal, Subaccount},
57        },
58        ids::CanisterRole,
59        log,
60        log::Level,
61        ops::{
62            OpsError,
63            ic::{call::Call, call_and_decode},
64        },
65        types::Cycles,
66    };
67    pub use serde::{Deserialize, Serialize};
68}
69
70use crate::{ThisError, ops::storage::env::EnvOps};
71
72///
73/// OpsError
74/// Error envelope shared across operations submodules
75///
76
77#[derive(Debug, ThisError)]
78pub enum OpsError {
79    /// Raised when a function requires root context, but was called from a child.
80    #[error("operation must be called from the root canister")]
81    NotRoot,
82
83    /// Raised when a function must not be called from root.
84    #[error("operation cannot be called from the root canister")]
85    IsRoot,
86
87    #[error(transparent)]
88    ConfigOpsError(#[from] config::ConfigOpsError),
89
90    #[error(transparent)]
91    IcOpsError(#[from] ic::IcOpsError),
92
93    #[error(transparent)]
94    OrchestrationOpsError(#[from] orchestration::OrchestrationOpsError),
95
96    #[error(transparent)]
97    ReserveOpsError(#[from] reserve::ReserveOpsError),
98
99    #[error(transparent)]
100    RpcOpsError(#[from] rpc::RpcOpsError),
101
102    #[error(transparent)]
103    StorageOpsError(#[from] storage::StorageOpsError),
104}
105
106impl OpsError {
107    /// Ensure the caller is the root canister.
108    pub fn require_root() -> Result<(), Self> {
109        if EnvOps::is_root() {
110            Ok(())
111        } else {
112            Err(Self::NotRoot)
113        }
114    }
115
116    /// Ensure the caller is not the root canister.
117    pub fn deny_root() -> Result<(), Self> {
118        if EnvOps::is_root() {
119            Err(Self::IsRoot)
120        } else {
121            Ok(())
122        }
123    }
124}