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