ic_query/subnet_catalog/resolver/
canister.rs1use super::{ResolvedCanisterRoute, ResolvedSubnet, ResolvedSubnetSubject};
2use crate::subnet_catalog::{
3 CatalogError, RawSubnetCatalog, ValidatedSubnetCatalog, parse_principal, principal_bytes,
4};
5
6impl RawSubnetCatalog {
7 pub fn resolve_canister(&self, input_principal: &str) -> Result<ResolvedSubnet, CatalogError> {
9 let canonical_canister = parse_principal(input_principal, "canister_principal")?.to_text();
10 let canister_bytes = principal_bytes(&canonical_canister, "canister_principal")?;
11 let range = self
12 .routing_ranges
13 .iter()
14 .find(|range| range_contains_principal(range, &canister_bytes).unwrap_or(false))
15 .ok_or_else(|| CatalogError::RouteNotFound {
16 canister_principal: canonical_canister.clone(),
17 registry_version: self.provenance.registry_version,
18 catalog_schema_version: self.catalog_schema_version,
19 })?;
20 let subnet = self
21 .subnet_by_principal(&range.subnet_principal)
22 .cloned()
23 .ok_or_else(|| CatalogError::UnknownRoutingSubnet {
24 subnet_principal: range.subnet_principal.clone(),
25 })?;
26 Ok(ResolvedSubnet {
27 input_principal: canonical_canister.clone(),
28 resolved_as: ResolvedSubnetSubject::Canister,
29 resolved_from: "routing_range".to_string(),
30 subnet,
31 matched_canister_principal: Some(canonical_canister),
32 matched_routing_range: Some(range.clone()),
33 catalog_digest: self.catalog_digest.clone(),
34 provenance: self.provenance.clone(),
35 })
36 }
37}
38
39impl ValidatedSubnetCatalog {
40 pub fn resolve_canister_route(
42 &self,
43 input_principal: &str,
44 ) -> Result<ResolvedCanisterRoute, CatalogError> {
45 let resolved = self.raw().resolve_canister(input_principal)?;
46 let canister_text = resolved
47 .matched_canister_principal
48 .as_deref()
49 .ok_or_else(|| CatalogError::RouteNotFound {
50 canister_principal: input_principal.to_string(),
51 registry_version: self.provenance().registry_version,
52 catalog_schema_version: self.raw().catalog_schema_version,
53 })?;
54 let matched_range =
55 resolved
56 .matched_routing_range
57 .ok_or_else(|| CatalogError::RouteNotFound {
58 canister_principal: input_principal.to_string(),
59 registry_version: self.provenance().registry_version,
60 catalog_schema_version: self.raw().catalog_schema_version,
61 })?;
62 Ok(ResolvedCanisterRoute {
63 canister: parse_principal(canister_text, "canister_principal")?,
64 subnet: parse_principal(&matched_range.subnet_principal, "subnet_principal")?,
65 subnet_info: resolved.subnet,
66 matched_range,
67 registry_version: self.provenance().registry_version,
68 catalog_digest: self.catalog_digest(),
69 provenance: self.provenance().clone(),
70 })
71 }
72}
73
74pub(in crate::subnet_catalog) fn routing_range_sorts_after(start: &[u8], end: &[u8]) -> bool {
75 start > end
76}
77
78fn range_contains_principal(
79 range: &crate::subnet_catalog::RoutingRange,
80 principal: &[u8],
81) -> Result<bool, CatalogError> {
82 let start = principal_bytes(&range.start_canister_id, "start_canister_id")?;
83 let end = principal_bytes(&range.end_canister_id, "end_canister_id")?;
84 Ok(start.as_slice() <= principal && principal <= end.as_slice())
85}