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