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