Skip to main content

ic_query/cloud_engine/
mod.rs

1//! CloudEngine control-plane and official Dashboard report models, adapters.
2
3#[cfg(feature = "cloud-engine-host")]
4mod build;
5#[cfg(all(feature = "cloud-engine-host", feature = "subnet-catalog-host"))]
6mod list;
7mod model;
8mod node;
9mod provider;
10#[cfg(feature = "cloud-engine-host")]
11mod source;
12#[cfg(feature = "cloud-engine-host")]
13mod wire;
14
15#[cfg(feature = "cloud-engine-host")]
16use thiserror::Error as ThisError;
17
18#[cfg(feature = "cloud-engine-host")]
19pub use build::{
20    build_cloud_engine_operator_report, build_cloud_engine_operator_report_with_source,
21    build_cloud_engine_prices_report, build_cloud_engine_prices_report_with_source,
22};
23#[cfg(all(feature = "cloud-engine-host", feature = "subnet-catalog-host"))]
24pub use list::{
25    build_cloud_engine_list_report, build_cloud_engine_list_report_with_sources_and_progress,
26};
27#[cfg(all(feature = "cloud-engine-host", feature = "subnet-catalog-host"))]
28pub use model::{CloudEngineListReport, CloudEngineListRow};
29pub use model::{
30    CloudEngineNodeType, CloudEngineOperatorReport, CloudEnginePriceRow, CloudEnginePricesReport,
31    CloudEngineReportContext,
32};
33#[cfg(feature = "cloud-engine-host")]
34pub use model::{
35    CloudEngineOperatorBindingSourceData, CloudEngineOperatorSourceData,
36    CloudEnginePricesSourceData,
37};
38pub use node::{
39    CLOUD_ENGINE_NODE_INCLUDED_STATUSES, CLOUD_ENGINE_NODE_REWARD_TYPE, CloudEngineNodeInfoReport,
40    CloudEngineNodeInfoRequest, CloudEngineNodeListReport, CloudEngineNodeListRequest,
41    CloudEngineNodeRow, MAX_CLOUD_ENGINE_NODE_ROWS,
42};
43#[cfg(feature = "dashboard-host")]
44pub use node::{
45    CloudEngineNodeInfoSourceData, CloudEngineNodeListSourceData, CloudEngineNodeSource,
46    build_cloud_engine_node_info_report, build_cloud_engine_node_info_report_with_source,
47    build_cloud_engine_node_list_report, build_cloud_engine_node_list_report_with_source,
48};
49pub use provider::{
50    CloudEngineProviderInfoReport, CloudEngineProviderInfoRequest, CloudEngineProviderListReport,
51    CloudEngineProviderListRequest, CloudEngineProviderLocation, CloudEngineProviderRow,
52    MAX_CLOUD_ENGINE_PROVIDER_LOCATIONS, MAX_CLOUD_ENGINE_PROVIDER_SOURCE_ROWS,
53};
54#[cfg(feature = "dashboard-host")]
55pub use provider::{
56    CloudEngineProviderInfoSourceData, CloudEngineProviderListSourceData,
57    CloudEngineProviderSource, build_cloud_engine_provider_info_report,
58    build_cloud_engine_provider_info_report_with_source, build_cloud_engine_provider_list_report,
59    build_cloud_engine_provider_list_report_with_source,
60};
61#[cfg(feature = "cloud-engine-host")]
62pub use source::{CloudEngineOperatorBindingSource, CloudEngineSource, LiveCloudEngineSource};
63
64/// Mainnet CloudEngine control-plane registry canister principal.
65pub const MAINNET_CLOUD_ENGINE_CANISTER_ID: &str = "q6cfj-fyaaa-aaaar-qb77q-cai";
66
67/// Default replica endpoint used for live CloudEngine control-plane queries.
68pub const DEFAULT_CLOUD_ENGINE_SOURCE_ENDPOINT: &str = "https://icp-api.io";
69
70/// Default official Dashboard endpoint for CloudEngine provider and Type4 node reports.
71pub const DEFAULT_CLOUD_ENGINE_DASHBOARD_SOURCE_ENDPOINT: &str =
72    "https://ic-api.internetcomputer.org/api/v3";
73
74/// Maximum marketplace rows accepted from one live response.
75pub const MAX_CLOUD_ENGINE_PRICE_ROWS: usize = 1_000;
76
77/// Maximum Registry CloudEngine Subnets followed by one list invocation.
78pub const MAX_CLOUD_ENGINE_LIST_ROWS: usize = 100;
79
80/// Maximum claimed domains accepted from one engine operator.
81pub const MAX_CLOUD_ENGINE_DOMAINS: usize = 100;
82
83/// Maximum decimal digits accepted for one marketplace cycle amount.
84pub const MAX_CLOUD_ENGINE_CYCLE_DECIMAL_DIGITS: usize = 256;
85
86#[cfg(feature = "cloud-engine-host")]
87const CLOUD_ENGINE_REPORT_SCHEMA_VERSION: u32 = 1;
88#[cfg(feature = "cloud-engine-host")]
89const CLOUD_ENGINE_AUTHORITY: &str = "cloud_engine_control_plane_canister";
90
91///
92/// CloudEngineHostError
93///
94/// Failure while collecting or validating one live CloudEngine report.
95///
96
97#[cfg(feature = "cloud-engine-host")]
98#[derive(Debug, ThisError)]
99pub enum CloudEngineHostError {
100    /// The requested network is not the supported mainnet identity.
101    #[error(
102        "`icq cloud-engine` supports only the mainnet `ic` network\n\nThese reports query the mainnet CloudEngine control-plane canister.\n\nTry:\n  icq --network ic cloud-engine prices"
103    )]
104    UnsupportedNetwork {
105        /// Rejected network identity.
106        network: String,
107    },
108
109    /// A requested principal is invalid.
110    #[error("invalid {field}: {reason}")]
111    InvalidPrincipal {
112        /// Principal field being parsed.
113        field: &'static str,
114        /// Principal parsing failure.
115        reason: String,
116    },
117
118    /// The IC agent could not be constructed for the requested endpoint.
119    #[error("failed to build IC agent for {endpoint}: {reason}")]
120    AgentBuild {
121        /// Endpoint used to build the agent.
122        endpoint: String,
123        /// Agent construction failure.
124        reason: String,
125    },
126
127    /// The built-in CloudEngine control-plane principal could not be parsed.
128    #[error("invalid built-in CloudEngine canister principal: {reason}")]
129    CanisterId {
130        /// Principal parsing failure.
131        reason: String,
132    },
133
134    /// A CloudEngine control-plane query failed.
135    #[error("CloudEngine agent call {method} failed: {reason}")]
136    AgentCall {
137        /// Canister method being queried.
138        method: &'static str,
139        /// Agent call failure.
140        reason: String,
141    },
142
143    /// A CloudEngine query argument could not be Candid encoded.
144    #[error("failed to encode Candid {message}: {reason}")]
145    CandidEncode {
146        /// Candid request type.
147        message: &'static str,
148        /// Encoding failure.
149        reason: String,
150    },
151
152    /// A CloudEngine response could not be Candid decoded.
153    #[error("failed to decode Candid {message}: {reason}")]
154    CandidDecode {
155        /// Candid response type.
156        message: &'static str,
157        /// Decoding failure.
158        reason: String,
159    },
160
161    /// A custom CloudEngine source returned inconsistent or excessive data.
162    #[error("invalid CloudEngine source data: {reason}")]
163    InvalidSourceData {
164        /// Deterministic source-contract failure.
165        reason: String,
166    },
167
168    /// The Registry-backed Subnet Catalog could not supply the list inventory.
169    #[cfg(feature = "subnet-catalog-host")]
170    #[error(transparent)]
171    SubnetCatalog(#[from] crate::subnet_catalog::SubnetCatalogHostError),
172}
173
174#[cfg(feature = "cloud-engine-host")]
175fn enforce_mainnet_network(network: &str) -> Result<(), CloudEngineHostError> {
176    crate::network::enforce_mainnet_network_with(network, |network| {
177        CloudEngineHostError::UnsupportedNetwork { network }
178    })
179}
180
181#[cfg(all(test, feature = "cloud-engine-host"))]
182mod tests;