Verifying asset canister content

How can I verify that two asset canisters serve the same content (i.e. same assets)? Is there a root hash that I can compare? If so, how?

There is a root hash. It’s harder to access than it probably should be. But it also doesn’t say as much as you’d expect.

Right now the asset canister doesn’t have a get_root_hash function. But you can extract the root hash from every response to http_request. If you e.g. request /index.html through a call to http_request, you receive back a response with an IC-Certificate header. In that header there is a tree section. From the spec: tree: Base64 encoded string of self-describing, CBOR-encoded bytes that decode into a valid hash tree as per certificate encoding. This will contain the root hash.

If two root hashes match then the two asset canisters serve the same content. If they don’t match it could mean any of the following:

  • At least one asset doesn’t match
  • At least one asset’s headers don’t match
  • At least one asset’s available encodings don’t match
  • The certification tree implementation is differently structured (AFAIK the asset canister’s tree should be fine)
  • The canisters don’t handle aliases the same way
  • The canisters don’t serve the same certification versions

If you don’t want to go the root hash route, then your best bet is listing all assets. The asset canister has a list function that shows what assets are available. If you then trust the canister to not hide any assets you can compare the assets one by one

1 Like

An example of using this header and checking the hash tree can be found in the @dfinity/assets package: agent-js/packages/assets/src/index.ts at main · dfinity/agent-js · GitHub

1 Like

Just double-checking if there have been updates since.

I see there is a query function certified_tree but I don’t know if it is new or if it has always been there. It returns a “certificate” and a “tree”. I suppose I can also get the root hash from either one of those, or?

git blame says it’s been there for 2 years :person_shrugging: No idea why I didn’t see it last time I looked.

You’re right, the tree field is the complete hash tree with all certified hashes included, and the data that’s certified in the certificate is the root hash of the same tree.

certified_tree will run into issues if there are too many assets in the canister because there is a max response size and this function does not care about that. But for most cases this should work

Does the certificate contain the root hash?

Is the certificate exactly the same as the one in the IC-Certificate header? I mean does it have the same encoding or is it a different encoding?

Where can I read about the structure and encoding of it?

Yes. It is as described in this section. I think it would be the same as IC-Certificate