List all canisters

Is there a way to list all the canisters that are running on IC?
I thought that the registry canister on the NNS subnet was storing that information but could find a method to query anything similar. Is there a way to do so?
I would like to get the information directly from IC and not via a service like ic.rocks. How do they get that info?

1 Like

Hiya Dustin.

The NNS does not know which canisters actually exist. But the following information is available that can allow you to build up the list.

So my understanding is that the way services like ic.rocks enumerate all the canisters is by first figuring out how many subnets exist and what canister ID ranges exist on them. Then they look up the metadata for each canister in sequence till they find a canister for which there is no metadata.

Maybe @wang can also comment on this. Their source code for ic.rocks is available at GitHub - ic-rocks/ic-rocks: Analytics and explorer for the DFINITY Internet Computer as well.

I hope this helps.

7 Likes

Hi Akhi,
thanks a lot for the thorough reply. This sounds pretty much like what I’m looking for. I’ll give this a try.

1 Like

It’s me again, I’ve looked into this and have two questions to get started with this. Hope you or anyone else can help me here.

  • As a start, would you recommend implementing such a tool in Motoko or directly in a front-end language e.g. Typescript. The ic-rocks git only shows the front-end implementation and they call their own API, so I’m not sure how the API is implemented.
  • Where can I find and query the information about the different subnets? E.g. where do I find the documentation that describes the routing table data structure within the registry.
1 Like

Hey Dustin. Both are good questions. I am not sure if I am the best person to answer them though. I haven’t kept up with all the APIs, etc. that currently exist. Maybe @free knows what documentation exist and can suggest how to get started.

This is the code that deserializes the registry routing table. It is encoded as a protocol buffer, defined here.

3 Likes

Hi @free, thanks a lot for the links. Please excuse my ignorance but my experience is too little to be able to work with that.

Is there an example available on how to call the routing table? I am struggling even on how to even start here. Should I do it in Rust, Motoko or another language? Do I take the canister API or the HTTPS interface?

I was thinking this could be a good application to get going with developing on ICP but may turn out to be more complicated than expected.

You need to query the registry canister for a specific key (namely "routing_table").

E.g. by going to Principal rwlgt-iiaaa-aaaaa-aaaaa-cai | ic.rocks, scrolling down to get_value, inputiing the registry version (can be grabbed from get_latest_version, just above) and UTF-8 string routing_table. The output is a protocol buffer-encoded RoutingTable struct, as defined here.

The code I linked to above actually retrieves that key and decodes it into a Rust struct. It is of course part of the IC replica, so it comes with a lot of dependencies.

Thanks a lot. With your links I was able to find the agent-pb extension from ic-rocks. This allowed me to retrieve the routing table from the registry canister :slight_smile: I’m using the example code of the agent-pb and modified it to allow me to get the data for all the subnets. This looks like the image below
image

Now I’m stuck at decoding the principal Id for the subnets. It’s encoded in a buffer of 29bytes and I’m struggling to find out how to decode that. I basically extended the showRegistry() method in the index.js of the example in the agent-pb by the code below.

let routingTableResponse = await registry.get_value({
    key: Buffer.from('routing_table'),
});
let output = root.lookupType('RoutingTable').decode(routingTableResponse.value);

let tmp = output.entries[0].subnetId.principalId.raw;
let subnetId = root.lookupType('PrincipalId').decode(tmp);

All works fine until the last line. There, I’m misunderstanding something on how to decode the principal id. I get the error as shown in the image below

Any suggestions on how to solve this are highly appreciated :slight_smile:

I missed part of the error message of the bottom image and can’t edit for some reason. Here’s the entire image:

Solved it. Was obviously a beginner’s misunderstanding. I’m still gonna post the solution for anyone who might have the same issue in the future.
The principalIDs (therefore also subnets, canisters, …) are encoded using base32 as described here.
The step by step solution (also from that source) to get from principal byte array to string is described as:

The textual representation of a blob b is Grouped(Base32(CRC32(b) · b)) where

  • CRC32 is a four byte check sequence, calculated as defined by ISO 3309, ITU-T V.42 and elsewhere
  • Base32 is the Base32 encoding as defined in RFC 4648, with no padding character added.
  • The middle dot denotes concatenation.
  • Grouped takes an ASCII string and inserts the separator - (dash) every 5 characters. The last group may contain less than 5 characters. A separator never appears at the beginning or end.

Hope this helps anyone else who is also learning how things roll on IC.

1 Like