Simple way to detect if the caller is a canister principal or any other type of non-canister principal

I’d like to be able to determine if a request was made by a canister or a user/off-chain client (CLI or SDK).

I’m thinking the simplest way to do this is to check if the principal of the caller is that of a canister. I’ve noticed that that pretty much all canisters (with the exception of the management canister, that isn’t an actual “canister”) end in cai. At the same time, @cryptoschindler mentioned previously that there is no mechanism for telling canisters and users apart.

Is this still the case? Is checking the cai ending enough, or are there limitations to this approach?

At the system level, we cannot distinguish if a principal is a canister or a user. One trick you can do is to use inspect_message. Calls from agent goes to inspect_message first before they get to the update endpoint. You can keep a state in the inspect_message.


What does this mean, you can keep a state?

I was wrong. inspect cannot change state. I was hoping the following would work:

actor {
  var from_agent = false;
  system func inspect({caller : Principal}) : Bool {
    from_agent := true;

But it doesn’t work. The state change is revert back before entering the update method.

In theory maybe the spec doesn’t tell them apart, but in practice:
pretty easy to tell which is which.
The easiest is checking the principal text length.
Or you could convert [Nat8] and check there.
Currently, canisters have sequential ids and if that doesn’t change, you can tell by checking the amount of leading zeroes.
That will be a good mops library to have.
You will also need to remove the anonymous principal - 2vxsx-fae which is …0,0,0,0,4


@chenyan If it was an intentional decision that the canister/non-canister principals are ambiguous, why was this decision made?

Can you elaborate on the pattern going forwards? Even if I would be able to validate this for the next 5-10 million canisters I think that’s worth it. Should work then for at least the next 2-3 years.

I guess a more concrete question might be…does anyone know how many canisters need to be created until the textual representation of a canister id no longer ends in cai?