From db4c0a6cdea987209ad7b9a139f366d4e1fda3d3 Mon Sep 17 00:00:00 2001 From: IDX GitLab Automation Date: Thu, 10 Oct 2024 12:09:28 +0000 Subject: [PATCH] feat: setup rate-limit canister --- Cargo.lock | 32 ++++++++++++ Cargo.toml | 3 ++ rs/boundary_node/rate_limits/Cargo.toml | 21 ++++++++ rs/boundary_node/rate_limits/api/Cargo.toml | 14 ++++++ rs/boundary_node/rate_limits/api/src/lib.rs | 28 +++++++++++ .../rate_limits/canister/canister.rs | 23 +++++++++ .../canister}/interface.did | 0 .../rate_limits/canister/storage.rs | 31 ++++++++++++ .../rate_limits/canister/types.rs | 49 +++++++++++++++++++ .../rate_limits/canister_client/Cargo.toml | 13 +++++ .../rate_limits/canister_client/src/main.rs | 33 +++++++++++++ rs/boundary_node/rate_limits/dfx.json | 21 ++++++++ 12 files changed, 268 insertions(+) create mode 100644 rs/boundary_node/rate_limits/Cargo.toml create mode 100644 rs/boundary_node/rate_limits/api/Cargo.toml create mode 100644 rs/boundary_node/rate_limits/api/src/lib.rs create mode 100644 rs/boundary_node/rate_limits/canister/canister.rs rename rs/boundary_node/{rate_limit_canister => rate_limits/canister}/interface.did (100%) create mode 100644 rs/boundary_node/rate_limits/canister/storage.rs create mode 100644 rs/boundary_node/rate_limits/canister/types.rs create mode 100644 rs/boundary_node/rate_limits/canister_client/Cargo.toml create mode 100644 rs/boundary_node/rate_limits/canister_client/src/main.rs create mode 100644 rs/boundary_node/rate_limits/dfx.json diff --git a/Cargo.lock b/Cargo.lock index 71dc80bfcf1..4123a6de0e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1823,6 +1823,16 @@ dependencies = [ "wat", ] +[[package]] +name = "canister_client" +version = "0.9.0" +dependencies = [ + "candid", + "ic-agent", + "rate-limits-api", + "tokio", +] + [[package]] name = "canister_http" version = "0.9.0" @@ -17353,6 +17363,28 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f60fcc7d6849342eff22c4350c8b9a989ee8ceabc4b481253e8946b9fe83d684" +[[package]] +name = "rate-limits-api" +version = "0.9.0" +dependencies = [ + "candid", + "serde", +] + +[[package]] +name = "rate_limits" +version = "0.9.0" +dependencies = [ + "candid", + "ciborium", + "ic-cdk 0.13.5", + "ic-cdk-macros 0.9.0", + "ic-cdk-timers", + "ic-stable-structures", + "rate-limits-api", + "serde", +] + [[package]] name = "ratelimit" version = "0.9.1" diff --git a/Cargo.toml b/Cargo.toml index 5d8000b75a3..abfdf6286c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,9 @@ members = [ "rs/boundary_node/certificate_issuance/certificate_orchestrator", "rs/boundary_node/discower_bowndary", "rs/boundary_node/ic_boundary", + "rs/boundary_node/rate_limits", + "rs/boundary_node/rate_limits/api", + "rs/boundary_node/rate_limits/canister_client", "rs/boundary_node/systemd_journal_gatewayd_shim", "rs/canister_client", "rs/canister_client/sender", diff --git a/rs/boundary_node/rate_limits/Cargo.toml b/rs/boundary_node/rate_limits/Cargo.toml new file mode 100644 index 00000000000..5ddd2967435 --- /dev/null +++ b/rs/boundary_node/rate_limits/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "rate_limits" +version.workspace = true +authors.workspace = true +edition.workspace = true +description.workspace = true +documentation.workspace = true + +[dependencies] +candid = { workspace = true } +ciborium = { workspace = true } +ic-cdk = { workspace = true } +ic-cdk-macros = { workspace = true } +ic-cdk-timers = { workspace = true } +ic-stable-structures = { workspace = true } +rate-limits-api = { path = "./api" } +serde = { workspace = true } + +[lib] +crate-type = ["cdylib"] +path = "canister/canister.rs" \ No newline at end of file diff --git a/rs/boundary_node/rate_limits/api/Cargo.toml b/rs/boundary_node/rate_limits/api/Cargo.toml new file mode 100644 index 00000000000..adcae36afc6 --- /dev/null +++ b/rs/boundary_node/rate_limits/api/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "rate-limits-api" +version.workspace = true +authors.workspace = true +edition.workspace = true +description.workspace = true +documentation.workspace = true + +[dependencies] +candid = {workspace = true} +serde = {workspace = true} + +[lib] +path = "src/lib.rs" \ No newline at end of file diff --git a/rs/boundary_node/rate_limits/api/src/lib.rs b/rs/boundary_node/rate_limits/api/src/lib.rs new file mode 100644 index 00000000000..c0753cf8cb5 --- /dev/null +++ b/rs/boundary_node/rate_limits/api/src/lib.rs @@ -0,0 +1,28 @@ +use candid::CandidType; +use serde::Deserialize; + +pub type Version = u64; +pub type Timestamp = u64; +pub type RuleId = String; + +pub type GetConfigResponse = Result; + +#[derive(CandidType, Deserialize, Debug)] +pub struct ConfigResponse { + pub version: Version, + pub active_since: Timestamp, + pub config: OutputConfig, +} + +#[derive(CandidType, Deserialize, Debug)] +pub struct OutputConfig { + pub rules: Vec, +} + +#[derive(CandidType, Deserialize, Debug)] +pub struct OutputRule { + pub id: RuleId, + pub rule_raw: Option>, + pub description: Option, + pub disclosed_at: Option, +} diff --git a/rs/boundary_node/rate_limits/canister/canister.rs b/rs/boundary_node/rate_limits/canister/canister.rs new file mode 100644 index 00000000000..6330bc38f7f --- /dev/null +++ b/rs/boundary_node/rate_limits/canister/canister.rs @@ -0,0 +1,23 @@ +use rate_limits_api::{GetConfigResponse, Version}; +use storage::VERSION; +use types::{ConfigResponse, OutputConfig}; +mod storage; +mod types; + +#[ic_cdk_macros::update] +fn get_config(version: Option) -> GetConfigResponse { + let test_version_inc = VERSION.with(|v| { + let mut ver = v.borrow_mut(); + let current_version = ver.get(&()).unwrap_or(0); + ver.insert((), current_version + 1); + current_version + }); + + let response = ConfigResponse { + version: version.unwrap_or(test_version_inc), + active_since: 1, + config: OutputConfig { rules: vec![] }, + }; + + Ok(response.into()) +} diff --git a/rs/boundary_node/rate_limit_canister/interface.did b/rs/boundary_node/rate_limits/canister/interface.did similarity index 100% rename from rs/boundary_node/rate_limit_canister/interface.did rename to rs/boundary_node/rate_limits/canister/interface.did diff --git a/rs/boundary_node/rate_limits/canister/storage.rs b/rs/boundary_node/rate_limits/canister/storage.rs new file mode 100644 index 00000000000..dc6eba38ecc --- /dev/null +++ b/rs/boundary_node/rate_limits/canister/storage.rs @@ -0,0 +1,31 @@ +use std::cell::RefCell; + +use ic_stable_structures::{ + memory_manager::{MemoryId, MemoryManager, VirtualMemory}, + DefaultMemoryImpl, StableBTreeMap, +}; + +use crate::types::Version; + +// Stable Memory +type Memory = VirtualMemory; + +type StableMap = StableBTreeMap; +type _StableSet = StableMap; +type StableValue = StableMap<(), T>; + +const MEMORY_ID_VERSION: u8 = 0; + +// Memory +thread_local! { + static MEMORY_MANAGER: RefCell> = + RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); +} + +thread_local! { + pub static VERSION: RefCell> = RefCell::new( + StableValue::init( + MEMORY_MANAGER.with(|m| m.borrow().get(MemoryId::new(MEMORY_ID_VERSION))), + ) + ); +} diff --git a/rs/boundary_node/rate_limits/canister/types.rs b/rs/boundary_node/rate_limits/canister/types.rs new file mode 100644 index 00000000000..b634433ed4c --- /dev/null +++ b/rs/boundary_node/rate_limits/canister/types.rs @@ -0,0 +1,49 @@ +pub type Version = u64; +pub type Timestamp = u64; +pub type RuleId = String; + +pub struct ConfigResponse { + pub version: Version, + pub active_since: Timestamp, + pub config: OutputConfig, +} + +pub struct OutputConfig { + pub rules: Vec, +} + +pub struct OutputRule { + pub id: RuleId, + pub rule_raw: Option>, + pub description: Option, + pub disclosed_at: Option, +} + +impl From for rate_limits_api::OutputRule { + fn from(value: OutputRule) -> Self { + rate_limits_api::OutputRule { + description: value.description, + disclosed_at: value.disclosed_at, + id: value.id, + rule_raw: value.rule_raw, + } + } +} + +impl From for rate_limits_api::OutputConfig { + fn from(value: OutputConfig) -> Self { + rate_limits_api::OutputConfig { + rules: value.rules.into_iter().map(|r| r.into()).collect(), + } + } +} + +impl From for rate_limits_api::ConfigResponse { + fn from(value: ConfigResponse) -> Self { + rate_limits_api::ConfigResponse { + version: value.version, + active_since: value.active_since, + config: value.config.into(), + } + } +} diff --git a/rs/boundary_node/rate_limits/canister_client/Cargo.toml b/rs/boundary_node/rate_limits/canister_client/Cargo.toml new file mode 100644 index 00000000000..78240adbdab --- /dev/null +++ b/rs/boundary_node/rate_limits/canister_client/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "canister_client" +version.workspace = true +authors.workspace = true +edition.workspace = true +description.workspace = true +documentation.workspace = true + +[dependencies] +rate-limits-api = { path = "../api" } +ic-agent = { workspace = true } +tokio = { workspace = true } +candid = { workspace = true } \ No newline at end of file diff --git a/rs/boundary_node/rate_limits/canister_client/src/main.rs b/rs/boundary_node/rate_limits/canister_client/src/main.rs new file mode 100644 index 00000000000..ae8b0bc6e84 --- /dev/null +++ b/rs/boundary_node/rate_limits/canister_client/src/main.rs @@ -0,0 +1,33 @@ +use candid::{Decode, Encode, Principal}; +use ic_agent::{identity::AnonymousIdentity, Agent}; +use rate_limits_api::GetConfigResponse; + +const RATE_LIMIT_CANISTER_ID: &str = "zwbmv-jyaaa-aaaab-qacaa-cai"; +const IC_DOMAIN: &str = "https://ic0.app"; + +#[tokio::main] +async fn main() { + let agent = Agent::builder() + .with_url(IC_DOMAIN) + .with_identity(AnonymousIdentity {}) + .build() + .expect("failed to build the agent"); + + agent.fetch_root_key().await.unwrap(); + + let canister_id = Principal::from_text(RATE_LIMIT_CANISTER_ID).unwrap(); + + // let args = Encode!(&Some(1u64)).unwrap(); + let args = Encode!(&None::).unwrap(); + + let response = agent + .update(&canister_id, "get_config") + .with_arg(args) + .call_and_wait() + .await + .expect("update call failed"); + + let decoded = Decode!(&response, GetConfigResponse).expect("failed to decode candid response"); + + println!("get_config response: {decoded:#?}"); +} diff --git a/rs/boundary_node/rate_limits/dfx.json b/rs/boundary_node/rate_limits/dfx.json new file mode 100644 index 00000000000..8c7477ff548 --- /dev/null +++ b/rs/boundary_node/rate_limits/dfx.json @@ -0,0 +1,21 @@ +{ + "version": 1, + "canisters": { + "rate_limit_canister": { + "type": "rust", + "package": "rate_limits", + "candid": "canister/interface.did" + } + }, + "defaults": { + "build": { + "packtool": "" + } + }, + "networks": { + "local": { + "bind": "127.0.0.1:8080", + "type": "ephemeral" + } + } + } \ No newline at end of file