From ced88bb8a073d7e8760fc4e94ffd332ee14b52f5 Mon Sep 17 00:00:00 2001 From: QJ Date: Tue, 25 Oct 2022 05:28:20 +0000 Subject: [PATCH 1/3] Updated exchange_rate sample dapps for transform with context. --- motoko/exchange_rate/src/Main.mo | 19 ++++++++++++----- motoko/exchange_rate/src/Types.mo | 14 ++++++++----- rust/exchange_rate/Cargo.lock | 1 + rust/exchange_rate/Cargo.toml | 1 + rust/exchange_rate/src/lib.rs | 35 ++++++++++++++++++++++++++++++- rust/exchange_rate/src/main.rs | 20 +++++++++++------- 6 files changed, 71 insertions(+), 19 deletions(-) diff --git a/motoko/exchange_rate/src/Main.mo b/motoko/exchange_rate/src/Main.mo index 1967c16a4..054b41496 100644 --- a/motoko/exchange_rate/src/Main.mo +++ b/motoko/exchange_rate/src/Main.mo @@ -90,10 +90,10 @@ shared actor class ExchangeRate() = this { ); }; - public query func transform(raw : Types.CanisterHttpResponsePayload) : async Types.CanisterHttpResponsePayload { + public query func transform(raw : Types.TransformArgs) : async Types.CanisterHttpResponsePayload { let transformed : Types.CanisterHttpResponsePayload = { - status = raw.status; - body = raw.body; + status = raw.response.status; + body = raw.response.body; headers = [ { name = "Content-Security-Policy"; @@ -260,13 +260,18 @@ shared actor class ExchangeRate() = this { let url = "https://" # host # "/products/ICP-USD/candles?granularity=" # Nat64.toText(REMOTE_FETCH_GRANULARITY) # "&start=" # Nat64.toText(start_timestamp) # "&end=" # Nat64.toText(end_timestamp); Debug.print(url); + let transform_context : Types.TransformContext = { + function = transform; + context = Blob.fromArray([]); + }; + let request : Types.CanisterHttpRequestArgs = { url = url; max_response_bytes = ?MAX_RESPONSE_BYTES; headers = request_headers; body = null; method = #get; - transform = ?(#function(transform)); + transform = ?transform_context; }; try { Cycles.add(2_000_000_000); @@ -325,13 +330,17 @@ shared actor class ExchangeRate() = this { #Ok : Text; #Err : Text; } { + let transform_context : Types.TransformContext = { + function = transform; + context = Blob.fromArray([]); + }; let request : Types.CanisterHttpRequestArgs = { url = url; max_response_bytes = ?MAX_RESPONSE_BYTES; headers = []; body = null; method = #get; - transform = ?(#function(transform)); + transform = ?transform_context; }; try { Cycles.add(2_000_000_000); diff --git a/motoko/exchange_rate/src/Types.mo b/motoko/exchange_rate/src/Types.mo index c3b7a4fd4..557093ea2 100644 --- a/motoko/exchange_rate/src/Types.mo +++ b/motoko/exchange_rate/src/Types.mo @@ -26,8 +26,9 @@ module Types { #head; }; - public type TransformType = { - #function : shared CanisterHttpResponsePayload -> async CanisterHttpResponsePayload; + public type TransformContext = { + function : shared query TransformArgs -> async CanisterHttpResponsePayload; + context : Blob; }; public type CanisterHttpRequestArgs = { @@ -36,9 +37,7 @@ module Types { headers : [HttpHeader]; body : ?[Nat8]; method : HttpMethod; - transform : ?{ - #function : shared query CanisterHttpResponsePayload -> async CanisterHttpResponsePayload; - }; + transform : ?TransformContext; }; public type CanisterHttpResponsePayload = { @@ -47,6 +46,11 @@ module Types { body : [Nat8]; }; + public type TransformArgs = { + response : CanisterHttpResponsePayload; + context : Blob; + }; + public type IC = actor { http_request : Types.CanisterHttpRequestArgs -> async Types.CanisterHttpResponsePayload; }; diff --git a/rust/exchange_rate/Cargo.lock b/rust/exchange_rate/Cargo.lock index 470633040..49e166289 100644 --- a/rust/exchange_rate/Cargo.lock +++ b/rust/exchange_rate/Cargo.lock @@ -269,6 +269,7 @@ dependencies = [ "ic-cdk", "ic-cdk-macros", "serde", + "serde_bytes", "serde_json", ] diff --git a/rust/exchange_rate/Cargo.toml b/rust/exchange_rate/Cargo.toml index cc5cd6e70..8756f8f4c 100644 --- a/rust/exchange_rate/Cargo.toml +++ b/rust/exchange_rate/Cargo.toml @@ -14,3 +14,4 @@ ic-cdk-macros = "0.5.7" serde = "1.0.126" candid = "0.7.14" serde_json = "1.0.81" +serde_bytes = "0.11.7" diff --git a/rust/exchange_rate/src/lib.rs b/rust/exchange_rate/src/lib.rs index b6c5e8ad9..5f6710d86 100644 --- a/rust/exchange_rate/src/lib.rs +++ b/rust/exchange_rate/src/lib.rs @@ -1,4 +1,9 @@ -use candid::CandidType; +use candid::{ + parser::types::FuncMode, + types::{Function, Serializer, Type}, + CandidType, +}; +use ic_cdk::api::management_canister::http_request::{HttpHeader, HttpMethod, HttpResponse}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -16,3 +21,31 @@ pub struct RatesWithInterval { pub interval: usize, pub rates: HashMap, } + +/// Encapsulating the corresponding candid `func` type. +#[derive(Debug, Clone, Deserialize)] +pub struct TransformFunc(pub candid::Func); + +impl CandidType for TransformFunc { + fn _ty() -> Type { + Type::Func(Function { + modes: vec![FuncMode::Query], + args: vec![TransformArgs::ty()], + rets: vec![HttpResponse::ty()], + }) + } + + fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { + serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) + } +} + +#[derive(CandidType, Deserialize, Debug, Clone)] +pub struct CanisterHttpRequestArgs { + pub url: String, + pub max_response_bytes: Option, + pub headers: Vec, + pub body: Option>, + pub method: HttpMethod, + pub transform: Option, +} diff --git a/rust/exchange_rate/src/main.rs b/rust/exchange_rate/src/main.rs index df42dea59..c9dbc2ea2 100644 --- a/rust/exchange_rate/src/main.rs +++ b/rust/exchange_rate/src/main.rs @@ -1,7 +1,8 @@ use candid::Principal; use exchange_rate::{Rate, RatesWithInterval, TimeRange, Timestamp}; use ic_cdk::api::management_canister::http_request::{ - CanisterHttpRequestArgument, HttpHeader, HttpMethod, HttpResponse, TransformFunc, TransformType, + /*CanisterHttpRequestArgument,*/ HttpHeader, HttpMethod, + HttpResponse, /*TransformFunc, TransformType,*/ }; use ic_cdk::storage; use ic_cdk_macros::{self, heartbeat, post_upgrade, pre_upgrade, query, update}; @@ -205,15 +206,18 @@ async fn get_rate(job: Timestamp) { let url = format!("https://{host}/products/ICP-USD/candles?granularity={REMOTE_FETCH_GRANULARITY}&start={start_timestamp}&end={end_timestamp}"); ic_cdk::api::print(url.clone()); - let request = CanisterHttpRequestArgument { + let request = exchange_rate::CanisterHttpRequestArgs { url: url, method: HttpMethod::GET, body: None, max_response_bytes: Some(MAX_RESPONSE_BYTES), - transform: Some(TransformType::Function(TransformFunc(candid::Func { - principal: ic_cdk::api::id(), - method: "transform".to_string(), - }))), + transform: Some(exchange_rate::TransformContext { + function: exchange_rate::TransformFunc(candid::Func { + principal: ic_cdk::api::id(), + method: "transform".to_string(), + }), + context: vec![0, 1, 2], + }), headers: request_headers, }; @@ -262,8 +266,8 @@ fn decode_body_to_rates(body: &str, fetched: &mut RefMut>) { } #[query] -async fn transform(raw: HttpResponse) -> HttpResponse { - let mut sanitized = raw.clone(); +async fn transform(raw: exchange_rate::TransformArgs) -> HttpResponse { + let mut sanitized = raw.response.clone(); sanitized.headers = vec![ HttpHeader { name: "Content-Security-Policy".to_string(), From 9b4ad4857b491577a9a08c425b12ff53e259f4e9 Mon Sep 17 00:00:00 2001 From: QJ Date: Tue, 25 Oct 2022 15:23:52 +0000 Subject: [PATCH 2/3] CDK integration --- rust/exchange_rate/Cargo.lock | 72 +++++++++++++++++++++++++++++++--- rust/exchange_rate/Cargo.toml | 5 ++- rust/exchange_rate/src/lib.rs | 37 +---------------- rust/exchange_rate/src/main.rs | 38 +++++------------- 4 files changed, 80 insertions(+), 72 deletions(-) diff --git a/rust/exchange_rate/Cargo.lock b/rust/exchange_rate/Cargo.lock index 49e166289..5ba7a0a17 100644 --- a/rust/exchange_rate/Cargo.lock +++ b/rust/exchange_rate/Cargo.lock @@ -123,7 +123,7 @@ dependencies = [ "anyhow", "binread", "byteorder", - "candid_derive", + "candid_derive 0.4.5", "codespan-reporting", "hex", "ic-types", @@ -141,6 +141,35 @@ dependencies = [ "thiserror", ] +[[package]] +name = "candid" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0571f3777880555f86d8aaa63080162560a8bf183d7853e0cc561d9a75458bbd" +dependencies = [ + "anyhow", + "binread", + "byteorder", + "candid_derive 0.5.0", + "codespan-reporting", + "crc32fast", + "data-encoding", + "hex", + "lalrpop", + "lalrpop-util", + "leb128", + "logos", + "num-bigint", + "num-traits", + "num_enum", + "paste", + "pretty", + "serde", + "serde_bytes", + "sha2", + "thiserror", +] + [[package]] name = "candid_derive" version = "0.4.5" @@ -153,6 +182,18 @@ dependencies = [ "syn", ] +[[package]] +name = "candid_derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f1f4db7c7d04b87b70b3a35c5dc5c2c9dd73cef8bdf6760e2f18a0d45350dd" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -265,8 +306,8 @@ dependencies = [ name = "exchange_rate" version = "0.1.0" dependencies = [ - "candid", - "ic-cdk", + "candid 0.8.3", + "ic-cdk 0.6.2", "ic-cdk-macros", "serde", "serde_bytes", @@ -333,19 +374,30 @@ version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0554d77b453140eefcb8c8192a342927f8c48cfda911dfa3cd4561a919dbd32f" dependencies = [ - "candid", + "candid 0.7.16", "cfg-if", "serde", ] +[[package]] +name = "ic-cdk" +version = "0.6.2" +dependencies = [ + "candid 0.8.3", + "cfg-if", + "ic0", + "serde", + "serde_bytes", +] + [[package]] name = "ic-cdk-macros" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "954a421ace8b8c8e52d2847c4aa68c80101396134c800ecb12f63457937c4ab4" dependencies = [ - "candid", - "ic-cdk", + "candid 0.7.16", + "ic-cdk 0.5.7", "proc-macro2", "quote", "serde", @@ -368,6 +420,14 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ic0" +version = "0.18.4" +dependencies = [ + "quote", + "syn", +] + [[package]] name = "indexmap" version = "1.9.1" diff --git a/rust/exchange_rate/Cargo.toml b/rust/exchange_rate/Cargo.toml index 8756f8f4c..1a8f55661 100644 --- a/rust/exchange_rate/Cargo.toml +++ b/rust/exchange_rate/Cargo.toml @@ -9,9 +9,10 @@ name = "exchange_rate" path = "src/main.rs" [dependencies] -ic-cdk = "0.5.7" +# ic-cdk = "0.5.7" +ic-cdk = { path = "../../../cdk-rs/src/ic-cdk" } ic-cdk-macros = "0.5.7" serde = "1.0.126" -candid = "0.7.14" +candid = "0.8.0" serde_json = "1.0.81" serde_bytes = "0.11.7" diff --git a/rust/exchange_rate/src/lib.rs b/rust/exchange_rate/src/lib.rs index 5f6710d86..beb44b34c 100644 --- a/rust/exchange_rate/src/lib.rs +++ b/rust/exchange_rate/src/lib.rs @@ -1,9 +1,4 @@ -use candid::{ - parser::types::FuncMode, - types::{Function, Serializer, Type}, - CandidType, -}; -use ic_cdk::api::management_canister::http_request::{HttpHeader, HttpMethod, HttpResponse}; +use candid::CandidType; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -16,36 +11,8 @@ pub struct TimeRange { pub end: Timestamp, } -#[derive(Clone, Debug, PartialEq, CandidType, Serialize, Deserialize)] +#[derive(CandidType, Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct RatesWithInterval { pub interval: usize, pub rates: HashMap, } - -/// Encapsulating the corresponding candid `func` type. -#[derive(Debug, Clone, Deserialize)] -pub struct TransformFunc(pub candid::Func); - -impl CandidType for TransformFunc { - fn _ty() -> Type { - Type::Func(Function { - modes: vec![FuncMode::Query], - args: vec![TransformArgs::ty()], - rets: vec![HttpResponse::ty()], - }) - } - - fn idl_serialize(&self, serializer: S) -> Result<(), S::Error> { - serializer.serialize_function(self.0.principal.as_slice(), &self.0.method) - } -} - -#[derive(CandidType, Deserialize, Debug, Clone)] -pub struct CanisterHttpRequestArgs { - pub url: String, - pub max_response_bytes: Option, - pub headers: Vec, - pub body: Option>, - pub method: HttpMethod, - pub transform: Option, -} diff --git a/rust/exchange_rate/src/main.rs b/rust/exchange_rate/src/main.rs index c9dbc2ea2..a6cbe27b3 100644 --- a/rust/exchange_rate/src/main.rs +++ b/rust/exchange_rate/src/main.rs @@ -1,8 +1,7 @@ -use candid::Principal; use exchange_rate::{Rate, RatesWithInterval, TimeRange, Timestamp}; use ic_cdk::api::management_canister::http_request::{ - /*CanisterHttpRequestArgument,*/ HttpHeader, HttpMethod, - HttpResponse, /*TransformFunc, TransformType,*/ + http_request, CanisterHttpRequestArgument, HttpHeader, HttpMethod, HttpResponse, TransformArgs, + TransformContext, }; use ic_cdk::storage; use ic_cdk_macros::{self, heartbeat, post_upgrade, pre_upgrade, query, update}; @@ -206,40 +205,21 @@ async fn get_rate(job: Timestamp) { let url = format!("https://{host}/products/ICP-USD/candles?granularity={REMOTE_FETCH_GRANULARITY}&start={start_timestamp}&end={end_timestamp}"); ic_cdk::api::print(url.clone()); - let request = exchange_rate::CanisterHttpRequestArgs { + ic_cdk::api::print(format!("Making IC http_request call {} now.", job)); + let request = CanisterHttpRequestArgument { url: url, method: HttpMethod::GET, body: None, max_response_bytes: Some(MAX_RESPONSE_BYTES), - transform: Some(exchange_rate::TransformContext { - function: exchange_rate::TransformFunc(candid::Func { - principal: ic_cdk::api::id(), - method: "transform".to_string(), - }), - context: vec![0, 1, 2], - }), + transform: Some(TransformContext::new(transform, vec![])), headers: request_headers, }; - - let body = candid::utils::encode_one(&request).unwrap(); - ic_cdk::api::print(format!("Making IC http_request call {} now.", job)); - - match ic_cdk::api::call::call_raw( - Principal::management_canister(), - "http_request", - &body[..], - 2_000_000_000, - ) - .await - { - Ok(result) => { - // decode the result - let decoded_result: HttpResponse = - candid::utils::decode_one(&result).expect("IC http_request failed!"); + match http_request(request).await { + Ok((response,)) => { // put the result to hashmap FETCHED.with(|fetched| { let mut fetched = fetched.borrow_mut(); - let decoded_body = String::from_utf8(decoded_result.body) + let decoded_body = String::from_utf8(response.body) .expect("Remote service response is not UTF-8 encoded."); decode_body_to_rates(&decoded_body, &mut fetched); }); @@ -266,7 +246,7 @@ fn decode_body_to_rates(body: &str, fetched: &mut RefMut>) { } #[query] -async fn transform(raw: exchange_rate::TransformArgs) -> HttpResponse { +fn transform(raw: TransformArgs) -> HttpResponse { let mut sanitized = raw.response.clone(); sanitized.headers = vec![ HttpHeader { From e0899de40ab7711e1f84399844c7c249e10dd01f Mon Sep 17 00:00:00 2001 From: QJ Date: Mon, 7 Nov 2022 18:08:39 +0000 Subject: [PATCH 3/3] dfx version update --- motoko/exchange_rate/README.md | 6 +++--- motoko/exchange_rate/deploy.sh | 2 +- rust/exchange_rate/README.md | 6 +++--- rust/exchange_rate/deploy.sh | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/motoko/exchange_rate/README.md b/motoko/exchange_rate/README.md index bcd7cdcb0..3d18cd5bb 100644 --- a/motoko/exchange_rate/README.md +++ b/motoko/exchange_rate/README.md @@ -13,7 +13,7 @@ With more background already covered in `/rust/exchange_rate/README.md`, the REA intentionally kept short. ## Dependencies -- [ic-cdk v0.5.7](https://crates.io/crates/ic-cdk/0.5.7) or above -- [dfx v0.12.0-beta.3](https://github.com/dfinity/sdk/releases/tag/0.12.0-beta.3) or above. +- [ic-cdk v0.6.5](https://crates.io/crates/ic-cdk/0.6.5) or above +- [dfx v0.12.0-beta.6](https://github.com/dfinity/sdk/releases/tag/0.12.0-beta.6) or above. Use below command to install: -```DFX_VERSION=0.12.0-beta.3 sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"``` +```DFX_VERSION=0.12.0-beta.6 sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"``` diff --git a/motoko/exchange_rate/deploy.sh b/motoko/exchange_rate/deploy.sh index 55957ae18..e8babcf67 100755 --- a/motoko/exchange_rate/deploy.sh +++ b/motoko/exchange_rate/deploy.sh @@ -25,7 +25,7 @@ if [[ $ENV == "local" ]]; then # Check DFX version version=$(dfx -V | sed 's/dfx\ //g' | sed 's/-.*$//g') if [[ "$version" < "0.12.0" ]]; then - echo "dfx 0.12.0 or above required. Please do: dfx upgrade" + echo "dfx 0.12.0-beta.6 or above required. Please do: DFX_VERSION=0.12.0-beta.6 sh -ci \"$(curl -fsSL https://internetcomputer.org/install.sh)\"" exit 1 fi diff --git a/rust/exchange_rate/README.md b/rust/exchange_rate/README.md index 931a74d80..bbd29839f 100644 --- a/rust/exchange_rate/README.md +++ b/rust/exchange_rate/README.md @@ -53,10 +53,10 @@ On top of that, we cache data that's already fetched, to save from future user r triggering remote HTTP calls again. ## Dependencies -- [ic-cdk v0.5.7](https://crates.io/crates/ic-cdk/0.5.7) or above -- [dfx v0.12.0-beta.3](https://github.com/dfinity/sdk/releases/tag/0.12.0-beta.3) or above. +- [ic-cdk v0.6.5](https://crates.io/crates/ic-cdk/0.6.5) or above +- [dfx v0.12.0-beta.6](https://github.com/dfinity/sdk/releases/tag/0.12.0-beta.6) or above. Use below command to install: -```DFX_VERSION=0.12.0-beta.3 sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"``` +```DFX_VERSION=0.12.0-beta.6 sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)"``` ## Building the canister into wasm `cd rust/exchange_rate` diff --git a/rust/exchange_rate/deploy.sh b/rust/exchange_rate/deploy.sh index dc75a273f..0f222dfe5 100755 --- a/rust/exchange_rate/deploy.sh +++ b/rust/exchange_rate/deploy.sh @@ -20,7 +20,7 @@ if [[ $ENV == "local" ]]; then # Check DFX version version=$(dfx -V | sed 's/dfx\ //g' | sed 's/-.*$//g') if [[ "$version" < "0.12.0" ]]; then - echo "dfx 0.12.0 or above required. Please do: dfx upgrade" + echo "dfx 0.12.0-beta.6 or above required. Please do: DFX_VERSION=0.12.0-beta.6 sh -ci \"$(curl -fsSL https://internetcomputer.org/install.sh)\"" exit 1 fi