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