diff --git a/rust/inter-canister-calls/Makefile b/rust/inter-canister-calls/Makefile index 6752e6ea5..46537d746 100644 --- a/rust/inter-canister-calls/Makefile +++ b/rust/inter-canister-calls/Makefile @@ -5,7 +5,8 @@ all: test .SILENT: deploy build: dfx deploy - +SHELL := /bin/bash +.SHELLFLAGS := -euo pipefail -c .PHONY: test .SILENT: test test: build @@ -18,7 +19,17 @@ test: build dfx canister call caller call_get "( principal \"`dfx canister id counter`\" )" | grep '(variant { Ok = 8 : nat })' && echo 'PASS' dfx canister call caller stubborn_set "( principal \"`dfx canister id counter`\", 42 : nat )" | grep '(variant { Ok })' && echo 'PASS' dfx canister call caller call_get "( principal \"`dfx canister id counter`\" )" | grep '(variant { Ok = 42 : nat })' && echo 'PASS' - dfx canister call caller sign_message '("Some text to be signed")' | grep "Ok = \"" && echo PASS + # We'll test that the counter's balance increases when calling send_cycles to it. + # Storing the original balance in a file is the easiest with make. + echo $$(dfx canister status counter | awk '/Balance/ { gsub(/_/, "", $$2); print $$2 }') > .counter_before + # Send 10% of the caller's available cycles + CYCLES_TO_SEND=$$(dfx canister status caller | awk '/Balance/ { gsub(/_/, "", $$2); printf("%d", int($$2/10)) }'); \ + echo "Sending $$CYCLES_TO_SEND cycles to counter canister"; \ + dfx canister call caller send_cycles "( principal \"`dfx canister id counter`\", $$CYCLES_TO_SEND: nat64 )" | grep '(variant { Ok })' && echo PASS + # Check that the counter's balance increased + AFTER=$$(dfx canister status counter | awk '/Balance/ { gsub(/_/, "", $$2); print $$2 }'); \ + BEFORE=$$(cat .counter_before); \ + test $$AFTER -gt $$BEFORE && echo "PASS (cycles increased: $$BEFORE -> $$AFTER)" .PHONY: clean .SILENT: clean diff --git a/rust/inter-canister-calls/src/caller/caller.did b/rust/inter-canister-calls/src/caller/caller.did index 254b6fd63..a7985092e 100644 --- a/rust/inter-canister-calls/src/caller/caller.did +++ b/rust/inter-canister-calls/src/caller/caller.did @@ -13,8 +13,8 @@ type GetResult = variant { "Err" : text; }; -type SignMessageResult = variant { - "Ok" : text; +type SendCyclesResult = variant { + "Ok" : null; "Err" : text; }; @@ -24,5 +24,5 @@ service : { "call_get": (counter: principal) -> (GetResult); "call_increment": (counter: principal) -> (IncrementResult); "stubborn_set": (counter: principal, new_value: nat) -> (StubbornSetResult); - "sign_message": (text) -> (SignMessageResult); + "send_cycles": (target: principal, amount: nat64) -> (SendCyclesResult); } \ No newline at end of file diff --git a/rust/inter-canister-calls/src/caller/src/lib.rs b/rust/inter-canister-calls/src/caller/src/lib.rs index 3d74d0732..cacb4970f 100644 --- a/rust/inter-canister-calls/src/caller/src/lib.rs +++ b/rust/inter-canister-calls/src/caller/src/lib.rs @@ -1,15 +1,16 @@ // Some of the imports will only be used in later examples; we list them here for simplicity use candid::{Nat, Principal}; use ic_cdk::api::time; -use ic_cdk::call::{Call, CallErrorExt, RejectCode}; -use ic_cdk::management_canister::{EcdsaCurve, EcdsaKeyId, SignWithEcdsaArgs, SignWithEcdsaResult, cost_sign_with_ecdsa}; +use ic_cdk::call::{Call, CallErrorExt}; +use ic_cdk::management_canister::{DepositCyclesArgs, CanisterId}; use ic_cdk_macros::update; -use sha2::{Digest, Sha256}; // When calling other canisters: -// 1. The simplest is to mark your function as `update`. Then you can always call any public -// endpoint on any other canister. -// 2. Mark the function as `async`. Then you can use the `Call` API to call other canisters. +// +// 1. The simplest is to mark your function as `update`. Then you can always call any public +// endpoint on any other canister. +// 2. Mark the function as `async`. Then you can use the `Call` API to call other canisters. +// // This particular example requires the caller to provide the principal (i.e., ID) of the counter canister. #[update] pub async fn call_get_and_set(counter: Principal, new_value: Nat) -> Nat { @@ -136,52 +137,17 @@ pub async fn stubborn_set(counter: Principal, new_value: Nat) -> Result<(), Stri } #[update] -pub async fn sign_message(message: String) -> Result { - let message_hash = Sha256::digest(&message).to_vec(); - - let request = SignWithEcdsaArgs { - message_hash, - // This example does not use the fancier signing features - derivation_path: vec![], - key_id: EcdsaKeyId { - curve: EcdsaCurve::Secp256k1, - // This is the key name used for local testing; different - // key names are needed for the mainnet - name: "dfx_test_key".to_string(), - }, +pub async fn send_cycles(target: CanisterId, amount: u64) -> Result<(), String> { + let request = DepositCyclesArgs { + canister_id: target, }; - let cycles_cost = cost_sign_with_ecdsa(&request).map_err(|e| { - format!( - "Failed to compute cycles cost for signing with ECDSA: {:?}", - e - ) - })?; - - // Use bounded-wait calls in this example, since the amount attached is - // fairly low, and losing the attached cycles isn't catastrophic. - match Call::bounded_wait(Principal::management_canister(), "sign_with_ecdsa") + match Call::bounded_wait(Principal::management_canister(), "deposit_cycles") .with_arg(&request) - // Signing with a test key requires 30 billion cycles - .with_cycles(cycles_cost) + .with_cycles(amount as u128) .await { - Ok(resp) => match resp.candid::() { - Ok(signature) => Ok(hex::encode(signature.signature)), - Err(e) => Err(format!("Error decoding response: {:?}", e)), - }, - // A SysUnknown reject code only occurs due to a bounded-wait call timing out. - // It means that no cycles will be refunded, even - // if the call didn't make it to the callee. Here, this is fine since - // only a small amount is used. - Err(ic_cdk::call::CallFailed::CallRejected(e)) - if e.reject_code() == Ok(RejectCode::SysUnknown) => - { - Err(format!( - "Got a SysUnknown error while signing message: {:?}; cycles are not refunded", - e - )) - } - Err(e) => Err(format!("Error signing message: {:?}", e)), + Ok(_) => Ok(()), + Err(e) => Err(format!("Error attaching {} cycles: {:?}", amount, e)), } -} +} \ No newline at end of file