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