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