Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add utilities for principal type identification #127

Merged
merged 4 commits into from
Feb 5, 2025

Conversation

ByronBecker
Copy link
Contributor

As we already have Principal.isAnonymous(), it's a pretty standard use case to want to know if a call was made by an opaque, self identifying, or reserved principal.

This has been asked for by a few different developers on the forum, and comes up in our code often.

You may want to consider whether or not to rename isCanister() to isOpaque(), although I believe isCanister() reads better. The documentation doesn't provide cases where non-canister ids are opaque.

We also have our own test suite here (this code if from a util package that we have) with the following cases (all pass)

import { describe; it; Suite } = "mo:testing/Suite";
import { assertAllTrue } = "mo:testing/Assert";
import Principal "mo:base/Principal";
import Util "../canisters/lib/Util";

let s = Suite();

await* s.run([
  describe(
    "isCanister",
    [
      it(
        "returns true for opaque ids (typically canister principals)",
        func() : Bool {
          assertAllTrue([
            Util.isCanisterPrincipal(Principal.fromText("rwlgt-iiaaa-aaaaa-aaaaa-cai")),
            Util.isCanisterPrincipal(Principal.fromText("rrkah-fqaaa-aaaaa-aaaaq-cai")),
            Util.isCanisterPrincipal(Principal.fromText("ryjl3-tyaaa-aaaaa-aaaba-cai")),
            Util.isCanisterPrincipal(Principal.fromText("yoizw-hyaaa-aaaab-qacea-cai")),
            Util.isCanisterPrincipal(Principal.fromText("n4mvt-mqaaa-aaaap-ahmzq-cai")),
            Util.isCanisterPrincipal(Principal.fromText("2daxo-giaaa-aaaap-anvca-cai")),
            Util.isCanisterPrincipal(Principal.fromText("i663v-bqaaa-aaaar-qaheq-cai")),
          ])
        }
      ),
      it(
        "returns false for the management canister",
        func() : Bool {
          not Util.isCanisterPrincipal(Principal.fromText("aaaaa-aa"));
        }
      ),
      it(
        "returns false for the anonymous principal",
        func() : Bool {
          not Util.isCanisterPrincipal(Principal.fromText("2vxsx-fae"));
        }
      ),
      it(
        "returns false for self-authenticating ids (typically user principals)",
        func() : Bool {
          assertAllTrue([
            not Util.isCanisterPrincipal(Principal.fromText("6rgy7-3uukz-jrj2k-crt3v-u2wjm-dmn3t-p26d6-ndilt-3gusv-75ybk-jae")),
            not Util.isCanisterPrincipal(Principal.fromText("u2raz-tjwf4-cj7t5-7j5yd-cnqna-yj3z4-mohwc-hfve3-fidzp-fnd5u-eae")),
            not Util.isCanisterPrincipal(Principal.fromText("rvulb-jedtr-5esx3-xth6u-evhyu-evngq-4ftg3-ldbwr-qdxkk-mdi5z-nqe")),
            not Util.isCanisterPrincipal(Principal.fromText("l3e24-yowsz-w7lez-3gsgl-2tpob-z5kov-xwtuo-ap3vj-4pxee-2hhbt-vqe")),
            not Util.isCanisterPrincipal(Principal.fromText("a6bxj-cy5lv-vrl22-5hesn-br6t5-4gjtt-ch2pe-vmeth-72u23-7sad4-iqe")),
            not Util.isCanisterPrincipal(Principal.fromText("eqhzi-tc2i7-ge4gn-nqdho-eg5qo-tian6-55tr3-u4csn-mlzqn-cxan2-mqe")),
          ])
        }
      ),
      it(
        "returns false for reserved principals",
        func() : Bool {
          assertAllTrue([
            not Util.isCanisterPrincipal(Principal.fromText("sfgyh-vddpf-rwyzl-pobzx-izlbn-unwyz-s5aym-nellq-yhkzl-nnx4f-yh6")),
            not Util.isCanisterPrincipal(Principal.fromText("bnffp-h3dpf-rwyzl-pobzx-izlbn-unwyz-3gb2u-ngoey-64bzq-fl5xm-jh6")),
            not Util.isCanisterPrincipal(Principal.fromText("qlxgs-zldpf-rwyzl-pobzx-izlbn-uowyl-gdlpd-vig4g-adn7z-xmfl6-nx6")),
            not Util.isCanisterPrincipal(Principal.fromText("4ji6x-kldpf-rwyzl-pobzx-izlbn-uoxhr-owz77-gtxm2-b26co-rgns7-vx6")),
          ])
        }
      )
    ]
  )
])

@ByronBecker ByronBecker requested a review from a team as a code owner February 3, 2025 19:57
@ByronBecker
Copy link
Contributor Author

@rvanasa tagging for review when time permits, no rush!

@rvanasa
Copy link
Collaborator

rvanasa commented Feb 5, 2025

Thank you for the PR! We are looking this over internally (might be some delays due to time zone differences, etc).

A few quick notes:

  • Running npm run validate will fix the "Tests / validate" CI error. I'll look into fixing or deactivating the GH Pages one for external contributions.
  • Principal.test.mo is now included in the main branch. Feel free to add the test cases, and otherwise we could do this on our end before merging.

src/Principal.mo Outdated
public func isSelfAuthenticating(p: Principal) : Bool {
let byteArray = toByteArray(p);

byteArray.size() <= 29 and
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, need to fix this to be

Suggested change
byteArray.size() <= 29 and
byteArray.size() == 29 and

@ByronBecker
Copy link
Contributor Author

  • Running npm run validate will fix the "Tests / validate" CI error. I'll look into fixing or deactivating the GH Pages one for external contributions.

Done!

  • Principal.test.mo is now included in the main branch. Feel free to add the test cases, and otherwise we could do this on our end before merging.

Rebased and added. Note that we've been using a mix of https://github.com/aviate-labs/testing.mo and matchers in our testing. These tests should be easy enough to move over to matchers if you'd prefer everyone use that library. The testing library does have some significant advantages in being able to mock async behavior (say if you wanted to test out async library additions, such as parallel futures, etc.

Copy link
Collaborator

@rvanasa rvanasa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I like the idea of gradually migrating the base library to use testing.mo in place of matchers.

@rvanasa rvanasa merged commit 444da36 into dfinity:main Feb 5, 2025
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants