use crate::{
cache_file::{CacheFileError, HostCacheError},
ic_registry::RegistryFetchError,
network::enforce_mainnet_network_with,
subnet_catalog::CatalogError,
};
use std::path::PathBuf;
use thiserror::Error as ThisError;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SubnetCatalogErrorCode {
UnsupportedNetwork,
MissingCatalog,
InvalidReadPolicy,
CacheOperation,
RegistryRefresh,
CatalogValidation,
}
impl SubnetCatalogErrorCode {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::UnsupportedNetwork => "unsupported_network",
Self::MissingCatalog => "missing_catalog",
Self::InvalidReadPolicy => "invalid_read_policy",
Self::CacheOperation => "cache_operation",
Self::RegistryRefresh => "registry_refresh",
Self::CatalogValidation => "catalog_validation",
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SubnetCatalogErrorCategory {
Input,
Missing,
CacheIo,
Network,
Authority,
Validation,
}
impl SubnetCatalogErrorCategory {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Input => "input",
Self::Missing => "missing",
Self::CacheIo => "cache_io",
Self::Network => "network",
Self::Authority => "authority",
Self::Validation => "validation",
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SubnetCatalogRetryability {
Retryable,
NotRetryable,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SubnetCatalogRemediation {
UseMainnet,
RefreshCatalog,
}
#[derive(Debug, ThisError)]
pub enum SubnetCatalogHostError {
#[error("unsupported Subnet Catalog network {network:?}; expected mainnet identity \"ic\"")]
UnsupportedNetwork { network: String },
#[error("subnet catalog cache is missing at {}", path.display())]
MissingCatalog { path: PathBuf },
#[error("invalid subnet catalog read policy: {reason}")]
InvalidReadPolicy {
reason: String,
},
#[error(transparent)]
Cache(#[from] HostCacheError),
#[error("live NNS registry refresh failed: {0}")]
RegistryRefresh(#[from] RegistryFetchError),
#[error(transparent)]
Catalog(#[from] CatalogError),
}
impl SubnetCatalogHostError {
#[must_use]
pub const fn code(&self) -> SubnetCatalogErrorCode {
match self {
Self::UnsupportedNetwork { .. } => SubnetCatalogErrorCode::UnsupportedNetwork,
Self::MissingCatalog { .. } => SubnetCatalogErrorCode::MissingCatalog,
Self::InvalidReadPolicy { .. } => SubnetCatalogErrorCode::InvalidReadPolicy,
Self::Cache(_) => SubnetCatalogErrorCode::CacheOperation,
Self::RegistryRefresh(_) => SubnetCatalogErrorCode::RegistryRefresh,
Self::Catalog(_) => SubnetCatalogErrorCode::CatalogValidation,
}
}
#[must_use]
pub const fn category(&self) -> SubnetCatalogErrorCategory {
match self {
Self::UnsupportedNetwork { .. } | Self::InvalidReadPolicy { .. } => {
SubnetCatalogErrorCategory::Input
}
Self::MissingCatalog { .. } => SubnetCatalogErrorCategory::Missing,
Self::Cache(_) => SubnetCatalogErrorCategory::CacheIo,
Self::RegistryRefresh(_) => SubnetCatalogErrorCategory::Network,
Self::Catalog(
CatalogError::NetworkMismatch { .. }
| CatalogError::RegistryCanisterMismatch { .. }
| CatalogError::UnsupportedAssurance { .. }
| CatalogError::ClassificationPolicyVersionMismatch { .. }
| CatalogError::ClassificationPolicyDigestMismatch { .. }
| CatalogError::ResolverPolicyMismatch { .. }
| CatalogError::CatalogDigestMismatch { .. },
) => SubnetCatalogErrorCategory::Authority,
Self::Catalog(_) => SubnetCatalogErrorCategory::Validation,
}
}
#[must_use]
pub const fn retryability(&self) -> SubnetCatalogRetryability {
match self {
Self::RegistryRefresh(_) => SubnetCatalogRetryability::Retryable,
_ => SubnetCatalogRetryability::NotRetryable,
}
}
#[must_use]
pub const fn remediation(&self) -> Option<SubnetCatalogRemediation> {
match self {
Self::UnsupportedNetwork { .. } => Some(SubnetCatalogRemediation::UseMainnet),
Self::MissingCatalog { .. } => Some(SubnetCatalogRemediation::RefreshCatalog),
_ => None,
}
}
}
pub(super) fn enforce_mainnet_network(network: &str) -> Result<(), SubnetCatalogHostError> {
enforce_mainnet_network_with(network, |network| {
SubnetCatalogHostError::UnsupportedNetwork { network }
})
}
pub(super) fn subnet_cache_error(err: CacheFileError) -> SubnetCatalogHostError {
HostCacheError::operation("subnet catalog", err).into()
}