Skip to main content

ic_query/subnet_catalog/resolver/
canister.rs

1use super::{ResolvedSubnet, ResolvedSubnetSubject};
2use crate::subnet_catalog::{CatalogError, SubnetCatalog, parse_principal, principal_bytes};
3
4impl SubnetCatalog {
5    /// Resolve a canister principal through cached routing ranges.
6    pub fn resolve_canister(&self, input_principal: &str) -> Result<ResolvedSubnet, CatalogError> {
7        let canonical_canister = parse_principal(input_principal, "canister_principal")?.to_text();
8        let canister_bytes = principal_bytes(&canonical_canister, "canister_principal")?;
9        let range = self
10            .routing_ranges
11            .iter()
12            .find(|range| range_contains_principal(range, &canister_bytes).unwrap_or(false))
13            .ok_or_else(|| CatalogError::RouteNotFound {
14                canister_principal: canonical_canister.clone(),
15                registry_version: self.registry_version,
16                catalog_schema_version: self.catalog_schema_version,
17            })?;
18        let subnet = self
19            .subnet_by_principal(&range.subnet_principal)
20            .cloned()
21            .ok_or_else(|| CatalogError::UnknownRoutingSubnet {
22                subnet_principal: range.subnet_principal.clone(),
23            })?;
24        Ok(ResolvedSubnet {
25            input_principal: canonical_canister.clone(),
26            resolved_as: ResolvedSubnetSubject::Canister,
27            resolved_from: "routing_range".to_string(),
28            subnet,
29            matched_canister_principal: Some(canonical_canister),
30            matched_routing_range: Some(range.clone()),
31        })
32    }
33}
34
35pub(in crate::subnet_catalog) fn routing_range_sorts_after(start: &[u8], end: &[u8]) -> bool {
36    start > end
37}
38
39fn range_contains_principal(
40    range: &crate::subnet_catalog::RoutingRange,
41    principal: &[u8],
42) -> Result<bool, CatalogError> {
43    let start = principal_bytes(&range.start_canister_id, "start_canister_id")?;
44    let end = principal_bytes(&range.end_canister_id, "end_canister_id")?;
45    Ok(start.as_slice() <= principal && principal <= end.as_slice())
46}