Skip to main content

ic_query/cloud_engine/
mod.rs

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