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

feat(boundary): setup of rate-limit canister #1961

Draft
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

nikolay-komarevskiy
Copy link
Contributor

@nikolay-komarevskiy nikolay-komarevskiy commented Oct 10, 2024

This MR sets some boiler plate code for the rate-limit canister:

  1. Rust candid types are stored in rs/boundary_node/rate_limits/api as a lib crate. This allows to reuse this interface e.g. in the canister-client (4).
  2. Code of the canister is organized in ic/rs/boundary_node/rate_limits/canister (as a lib crate) and implements one function get_config() from the candid interface.did. Canister uses one variable stored in the stable memory for testing.
  3. dfx deployment of the canister can be done with dfx deploy rate_limit_canister --network playground --no-wallet
  4. Minimal canister-client to interact with the deployed canister. Note: copy canister ID from the previous dfx command

@nikolay-komarevskiy nikolay-komarevskiy force-pushed the komarevskiy/setup-rate-limit-canister branch from acca095 to 2d6a3fe Compare October 10, 2024 12:32
@github-actions github-actions bot added the feat label Oct 10, 2024
@nikolay-komarevskiy nikolay-komarevskiy force-pushed the komarevskiy/setup-rate-limit-canister branch from 2d6a3fe to db4c0a6 Compare October 10, 2024 12:36
Err: text;
};

type DiscloseRulesByIncidentIdResponse = variant {
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that you have a lot of

type XResponse = variant {
  Ok;
  Err: text;
};

maybe it'd make sense to consolidate those somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These types could be consolidate at some later point. But once consolidated the extensibility/flexibility is lost. Probably some Ok variant will contain messages, i haven't yet carefully thought through.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, but couldn't that just be a new Response type? I didn't mean you can only respond with this smaller type. E.g

type EmptyResponse = variant {
  Ok;
  Err: text;
};

type ListResponse = variant {
  Ok: vec RuleId,
  Err: text;
};

service: {
  disclose: (DiscloseArg) -> EmptyResponse;
  list: (ListArg) -> ListResponse;
};

type InputConfig = record {
schema_version: SchemaVersion; // schema version used to serialized the rules
rules: vec InputRule;
};
Copy link
Contributor

Choose a reason for hiding this comment

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

Should it be possible when specifying rules to also specify whether they are public or not? Or do you have to basically set the config, and then in another call disclose rules? I guess what I'm asking is "what does a normal user flow look like?"

Copy link
Contributor Author

@nikolay-komarevskiy nikolay-komarevskiy Oct 10, 2024

Choose a reason for hiding this comment

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

The expected flow is:

  1. Each newly added rule is confidential by default
  2. To open the rule for public viewing a separate call to disclose_() function is needed
    We could indeed add an additional field policy with private/public, but it seems to be unnecessary. If needed it can be added.

disclose_rules_by_rule_ids: (vec RuleId) -> (DiscloseRulesByRuleIdsResponse);

// Make the viewing of the specified rules related to an incident ID publicly accessible
disclose_rules_by_incident_id: (IncidentId) -> (DiscloseRulesByIncidentIdResponse);
Copy link
Contributor

@rikonor rikonor Oct 10, 2024

Choose a reason for hiding this comment

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

Any thoughts on consolidating these two disclose methods? e.g

type DiscloseArg = variant {
  Rules: vec RuleId;
  Incidents: vec IncidentId;
};

disclose: (vec DiscloseArg) -> (DiscloseResponse);

and similarly for get_rules:

type ListArg = variant {
  Rules: vec RuleId;
  Incidents: vec IncidentId;
};

list: (vec ListArg) -> (ListResponse);

Copy link
Contributor Author

@nikolay-komarevskiy nikolay-komarevskiy Oct 10, 2024

Choose a reason for hiding this comment

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

I do like the disclose one! but for get_rules it would be strange as for a RuleId it returns a single rule.

mod types;

#[ic_cdk_macros::update]
fn get_config(version: Option<Version>) -> GetConfigResponse {
Copy link
Contributor

Choose a reason for hiding this comment

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

Friendly suggestion - you may not agree with it. Notice that canisters don't really have a main function, so it's hard to gauge "what runs first". This can make it tricky to have a clear understanding of the order of operations happening in the canister upon startup (the various initialization steps, like declaring stable memory, canister methods, etc). For that reason, my suggestion would be to not rush to break up the canister code into separate files. Instead, treat canister/lib.rs similarly to how you would treat your main.rs file, meaning configure all your initialization logic there sequentially, like you would do in a main function. So in this case:

# lib.rs

... define stable memory

... define dependencies that will be used in your canister methods

... define canister methods

then on a per-need basis you'd create new files to host things that get imported into your lib.rs. All this is mostly so that it's easier to understand the flow of the canister. As it is right now, you would have to ask yourself, what's happening first? Stable memory in storage.rs? Canister methods in canister.rs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Notice that canisters don't really have a main function, so it's hard to gauge "what runs first".

Yes, canister is an actor.

For that reason, my suggestion would be to not rush to break up the canister code into separate files.

I understand. Since I have already prototyped the canister locally, i wanted to have at least a minimum separation of files. For example canister/types.rs and canister/canister.rs (lib.rs) make sense already now IMO. Stable memory variables and init i can add in the next MR. Wdyt? However, I still wanted a working canister at this point.

@nikolay-komarevskiy nikolay-komarevskiy force-pushed the komarevskiy/setup-rate-limit-canister branch from c90662c to 9c7347a Compare October 11, 2024 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants