From a880a682b4159eb1feede4ee0bd3b02d76ce380a Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Mon, 8 Mar 2021 23:18:54 -0800 Subject: [PATCH 1/7] call wallet bypass --- src/dfx/src/commands/canister/call.rs | 68 ++++++++++++++++++++++++--- src/dfx/src/commands/canister/mod.rs | 2 +- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index bd9b9aab38..1c33c020cc 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -1,12 +1,16 @@ +use crate::commands::command_utils::CallSender; use crate::lib::canister_info::CanisterInfo; use crate::lib::environment::Environment; use crate::lib::error::DfxResult; +use crate::lib::identity::Identity; use crate::lib::models::canister_id_store::CanisterIdStore; use crate::lib::root_key::fetch_root_key_if_needed; use crate::lib::waiter::waiter_with_exponential_backoff; use crate::util::{blob_from_arguments, expiry_duration, get_candid_type, print_idl_blob}; use anyhow::{anyhow, bail, Context}; +use candid::{CandidType, Deserialize}; +use candid::de::ArgumentDecoder; use clap::Clap; use ic_types::principal::Principal as CanisterId; use std::option::Option; @@ -65,7 +69,10 @@ fn get_local_cid_and_candid_path( )) } -pub async fn exec(env: &dyn Environment, opts: CanisterCallOpts) -> DfxResult { +pub async fn exec (env: &dyn Environment, opts: CanisterCallOpts, call_sender: &CallSender) -> DfxResult +where + O: for<'de> ArgumentDecoder<'de> + Sync + Send, +{ let callee_canister = opts.canister_name.as_str(); let method_name = opts.method_name.as_str(); let canister_id_store = CanisterIdStore::for_env(env)?; @@ -124,6 +131,15 @@ pub async fn exec(env: &dyn Environment, opts: CanisterCallOpts) -> DfxResult { let timeout = expiry_duration(); + #[derive(CandidType, Deserialize)] + struct In { + canister: CanisterId, + method_name: String, + #[serde(with = "serde_bytes")] + args: Vec, + cycles: u64, + } + if is_query { let blob = agent .query(&canister_id, method_name) @@ -141,12 +157,50 @@ pub async fn exec(env: &dyn Environment, opts: CanisterCallOpts) -> DfxResult { eprint!("Request ID: "); println!("0x{}", String::from(request_id)); } else { - let blob = agent - .update(&canister_id, method_name) - .with_arg(&arg_value) - .expire_after(timeout) - .call_and_wait(waiter_with_exponential_backoff()) - .await?; + // let blob = agent + // .update(&canister_id, method_name) + // .with_arg(&arg_value) + // .expire_after(timeout) + // .call_and_wait(waiter_with_exponential_backoff()) + // .await?; + + let blob = match call_sender { + CallSender::SelectedId => { + agent + .update(&canister_id, method_name) + .with_arg(&arg_value) + .expire_after(timeout) + .call_and_wait(waiter_with_exponential_backoff()) + .await? + } + CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { + let wallet = if call_sender == &CallSender::Wallet(some_id.clone()) { + let id = some_id + .as_ref() + .expect("Wallet canister id should have been provided here."); + Identity::build_wallet_canister(id.clone(), env)? + } else { + // CallSender::SelectedIdWallet(some_id) + let identity_name = env.get_selected_identity().expect("No selected identity."); + let network = env + .get_network_descriptor() + .expect("No network descriptor."); + Identity::get_wallet_canister(env, network, &identity_name).await? + }; + let blob: O = wallet + .update_("wallet_call") + .with_arg(In { + canister: canister_id, + method_name: method_name.to_string(), + args: arg_value, + cycles: 0_u64, + }) + .build() + .call_and_wait(waiter_with_exponential_backoff()) + .await?; + blob + } + }; print_idl_blob(&blob, output_type, &method_type) .context("Invalid data: Invalid IDL blob.")?; diff --git a/src/dfx/src/commands/canister/mod.rs b/src/dfx/src/commands/canister/mod.rs index ab1162b553..a5b02b6846 100644 --- a/src/dfx/src/commands/canister/mod.rs +++ b/src/dfx/src/commands/canister/mod.rs @@ -63,7 +63,7 @@ pub fn exec(env: &dyn Environment, opts: CanisterOpts) -> DfxResult { runtime.block_on(async { let call_sender = call_sender(&agent_env, &opts.wallet, opts.no_wallet).await?; match opts.subcmd { - SubCommand::Call(v) => call::exec(&agent_env, v).await, + SubCommand::Call(v) => call::exec(&agent_env, v, &call_sender).await, SubCommand::Create(v) => create::exec(&agent_env, v, &call_sender).await, SubCommand::Delete(v) => delete::exec(&agent_env, v, &call_sender).await, SubCommand::Id(v) => id::exec(&agent_env, v).await, From 25e36e66f0b99f5f0de9ff2d4e07d7de26cc9da2 Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 11:49:41 -0800 Subject: [PATCH 2/7] patch update and async call --- src/dfx/src/commands/canister/call.rs | 82 +++++++++++++++++++++------ 1 file changed, 66 insertions(+), 16 deletions(-) diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index 1c33c020cc..b8e804837e 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -10,9 +10,11 @@ use crate::util::{blob_from_arguments, expiry_duration, get_candid_type, print_i use anyhow::{anyhow, bail, Context}; use candid::{CandidType, Deserialize}; -use candid::de::ArgumentDecoder; use clap::Clap; use ic_types::principal::Principal as CanisterId; +use ic_utils::canister::{Argument, Canister}; +use ic_utils::interfaces::wallet::{CallForwarder, CallResult}; +use ic_utils::interfaces::Wallet; use std::option::Option; use std::path::PathBuf; @@ -69,10 +71,34 @@ fn get_local_cid_and_candid_path( )) } -pub async fn exec (env: &dyn Environment, opts: CanisterCallOpts, call_sender: &CallSender) -> DfxResult +async fn request_id_via_wallet_call( + wallet: &Canister<'_, Wallet>, + canister: &Canister<'_>, + method_name: &str, + args: Argument, + cycles: u64, +) -> DfxResult where - O: for<'de> ArgumentDecoder<'de> + Sync + Send, { + #[derive(Deserialize)] + struct Out { + #[allow(dead_code)] + r#return: CallResult, + } + + let call_forwarder: CallForwarder<'_, '_, (Out,)> = + wallet.call(canister, method_name, args, cycles); + call_forwarder + .call() + .await + .map_err(|err| anyhow!("Agent error {}", err)) +} + +pub async fn exec( + env: &dyn Environment, + opts: CanisterCallOpts, + call_sender: &CallSender, +) -> DfxResult { let callee_canister = opts.canister_name.as_str(); let method_name = opts.method_name.as_str(); let canister_id_store = CanisterIdStore::for_env(env)?; @@ -149,21 +175,45 @@ where print_idl_blob(&blob, output_type, &method_type) .context("Invalid data: Invalid IDL blob.")?; } else if opts.r#async { - let request_id = agent - .update(&canister_id, method_name) - .with_arg(&arg_value) - .call() - .await?; + let request_id = match call_sender { + CallSender::SelectedId => { + agent + .update(&canister_id, method_name) + .with_arg(&arg_value) + .call() + .await? + } + CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { + let wallet = if call_sender == &CallSender::Wallet(some_id.clone()) { + let id = some_id + .as_ref() + .expect("Wallet canister id should have been provided here."); + Identity::build_wallet_canister(id.clone(), env)? + } else { + // CallSender::SelectedIdWallet(some_id) + let identity_name = env.get_selected_identity().expect("No selected identity."); + let network = env + .get_network_descriptor() + .expect("No network descriptor."); + Identity::get_wallet_canister(env, network, &identity_name).await? + }; + // This is overkill, wallet.call should accept a Principal parameter + // Why do we need to construct a Canister? + let canister = Canister::builder() + .with_agent(agent) + .with_canister_id(canister_id) + .build() + .unwrap(); + // + let mut args = Argument::default(); + args.set_raw_arg(arg_value); + + request_id_via_wallet_call(&wallet, &canister, method_name, args, 0_u64).await? + } + }; eprint!("Request ID: "); println!("0x{}", String::from(request_id)); } else { - // let blob = agent - // .update(&canister_id, method_name) - // .with_arg(&arg_value) - // .expire_after(timeout) - // .call_and_wait(waiter_with_exponential_backoff()) - // .await?; - let blob = match call_sender { CallSender::SelectedId => { agent @@ -187,7 +237,7 @@ where .expect("No network descriptor."); Identity::get_wallet_canister(env, network, &identity_name).await? }; - let blob: O = wallet + let (blob,): (Vec,) = wallet .update_("wallet_call") .with_arg(In { canister: canister_id, From 3b1a7e93cd6eac633cf31e5d30e183e71079cf52 Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 12:59:41 -0800 Subject: [PATCH 3/7] add with cycles to call and fix to use CallResult as return --- src/dfx/src/commands/canister/call.rs | 57 ++++++++++++++------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index b8e804837e..63c533b161 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -6,6 +6,7 @@ use crate::lib::identity::Identity; use crate::lib::models::canister_id_store::CanisterIdStore; use crate::lib::root_key::fetch_root_key_if_needed; use crate::lib::waiter::waiter_with_exponential_backoff; +use crate::util::clap::validators::cycle_amount_validator; use crate::util::{blob_from_arguments, expiry_duration, get_candid_type, print_idl_blob}; use anyhow::{anyhow, bail, Context}; @@ -56,6 +57,11 @@ pub struct CanisterCallOpts { #[clap(long, conflicts_with("async"), possible_values(&["idl", "raw", "pp"]))] output: Option, + + /// Specifies the amount of cycles to send on the call. + /// Deducted from the wallet. + #[clap(long, validator(cycle_amount_validator))] + with_cycles: Option, } fn get_local_cid_and_candid_path( @@ -80,13 +86,7 @@ async fn request_id_via_wallet_call( ) -> DfxResult where { - #[derive(Deserialize)] - struct Out { - #[allow(dead_code)] - r#return: CallResult, - } - - let call_forwarder: CallForwarder<'_, '_, (Out,)> = + let call_forwarder: CallForwarder<'_, '_, (CallResult,)> = wallet.call(canister, method_name, args, cycles); call_forwarder .call() @@ -157,14 +157,10 @@ pub async fn exec( let timeout = expiry_duration(); - #[derive(CandidType, Deserialize)] - struct In { - canister: CanisterId, - method_name: String, - #[serde(with = "serde_bytes")] - args: Vec, - cycles: u64, - } + let identity_name = env.get_selected_identity().expect("No selected identity."); + let network = env + .get_network_descriptor() + .expect("No network descriptor."); if is_query { let blob = agent @@ -191,10 +187,6 @@ pub async fn exec( Identity::build_wallet_canister(id.clone(), env)? } else { // CallSender::SelectedIdWallet(some_id) - let identity_name = env.get_selected_identity().expect("No selected identity."); - let network = env - .get_network_descriptor() - .expect("No network descriptor."); Identity::get_wallet_canister(env, network, &identity_name).await? }; // This is overkill, wallet.call should accept a Principal parameter @@ -204,7 +196,6 @@ pub async fn exec( .with_canister_id(canister_id) .build() .unwrap(); - // let mut args = Argument::default(); args.set_raw_arg(arg_value); @@ -231,24 +222,36 @@ pub async fn exec( Identity::build_wallet_canister(id.clone(), env)? } else { // CallSender::SelectedIdWallet(some_id) - let identity_name = env.get_selected_identity().expect("No selected identity."); - let network = env - .get_network_descriptor() - .expect("No network descriptor."); Identity::get_wallet_canister(env, network, &identity_name).await? }; - let (blob,): (Vec,) = wallet + + // amount has been validated by cycle_amount_validator + let cycles = opts + .with_cycles + .as_deref() + .map_or(0_u64, |amount| amount.parse::().unwrap()); + + #[derive(CandidType, Deserialize)] + struct In { + canister: CanisterId, + method_name: String, + #[serde(with = "serde_bytes")] + args: Vec, + cycles: u64, + } + + let (result,): (CallResult,) = wallet .update_("wallet_call") .with_arg(In { canister: canister_id, method_name: method_name.to_string(), args: arg_value, - cycles: 0_u64, + cycles, }) .build() .call_and_wait(waiter_with_exponential_backoff()) .await?; - blob + result.r#return } }; From a89825a02c855c3107757a7bf3bc86b60f4289b2 Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 14:56:13 -0800 Subject: [PATCH 4/7] refactor --- src/dfx/src/commands/canister/call.rs | 95 +++++++++++++-------------- src/dfx/src/commands/command_utils.rs | 28 ++++++++ 2 files changed, 75 insertions(+), 48 deletions(-) diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index 63c533b161..38d7fab649 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -1,8 +1,7 @@ -use crate::commands::command_utils::CallSender; +use crate::commands::command_utils::{wallet_for_call_sender, CallSender}; use crate::lib::canister_info::CanisterInfo; use crate::lib::environment::Environment; -use crate::lib::error::DfxResult; -use crate::lib::identity::Identity; +use crate::lib::error::{DfxError, DfxResult}; use crate::lib::models::canister_id_store::CanisterIdStore; use crate::lib::root_key::fetch_root_key_if_needed; use crate::lib::waiter::waiter_with_exponential_backoff; @@ -13,6 +12,7 @@ use anyhow::{anyhow, bail, Context}; use candid::{CandidType, Deserialize}; use clap::Clap; use ic_types::principal::Principal as CanisterId; +use ic_utils::call::SyncCall; use ic_utils::canister::{Argument, Canister}; use ic_utils::interfaces::wallet::{CallForwarder, CallResult}; use ic_utils::interfaces::Wallet; @@ -64,6 +64,15 @@ pub struct CanisterCallOpts { with_cycles: Option, } +#[derive(CandidType, Deserialize)] +struct CallIn { + canister: CanisterId, + method_name: String, + #[serde(with = "serde_bytes")] + args: Vec, + cycles: u64, +} + fn get_local_cid_and_candid_path( env: &dyn Environment, canister_name: &str, @@ -157,17 +166,38 @@ pub async fn exec( let timeout = expiry_duration(); - let identity_name = env.get_selected_identity().expect("No selected identity."); - let network = env - .get_network_descriptor() - .expect("No network descriptor."); + // amount has been validated by cycle_amount_validator + let cycles = opts + .with_cycles + .as_deref() + .map_or(0_u64, |amount| amount.parse::().unwrap()); if is_query { - let blob = agent - .query(&canister_id, method_name) - .with_arg(&arg_value) - .call() - .await?; + let blob = match call_sender { + CallSender::SelectedId => { + agent + .query(&canister_id, method_name) + .with_arg(&arg_value) + .call() + .await? + } + CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { + let wallet = wallet_for_call_sender(env, call_sender, some_id).await?; + + let (result,): (CallResult,) = wallet + .query_("wallet_call") + .with_arg(CallIn { + canister: canister_id, + method_name: method_name.to_string(), + args: arg_value, + cycles, + }) + .build() + .call() + .await?; + result.r#return + } + }; print_idl_blob(&blob, output_type, &method_type) .context("Invalid data: Invalid IDL blob.")?; } else if opts.r#async { @@ -180,26 +210,18 @@ pub async fn exec( .await? } CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { - let wallet = if call_sender == &CallSender::Wallet(some_id.clone()) { - let id = some_id - .as_ref() - .expect("Wallet canister id should have been provided here."); - Identity::build_wallet_canister(id.clone(), env)? - } else { - // CallSender::SelectedIdWallet(some_id) - Identity::get_wallet_canister(env, network, &identity_name).await? - }; + let wallet = wallet_for_call_sender(env, call_sender, some_id).await?; // This is overkill, wallet.call should accept a Principal parameter // Why do we need to construct a Canister? let canister = Canister::builder() .with_agent(agent) .with_canister_id(canister_id) .build() - .unwrap(); + .map_err(DfxError::from)?; let mut args = Argument::default(); args.set_raw_arg(arg_value); - request_id_via_wallet_call(&wallet, &canister, method_name, args, 0_u64).await? + request_id_via_wallet_call(&wallet, &canister, method_name, args, cycles).await? } }; eprint!("Request ID: "); @@ -215,34 +237,11 @@ pub async fn exec( .await? } CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { - let wallet = if call_sender == &CallSender::Wallet(some_id.clone()) { - let id = some_id - .as_ref() - .expect("Wallet canister id should have been provided here."); - Identity::build_wallet_canister(id.clone(), env)? - } else { - // CallSender::SelectedIdWallet(some_id) - Identity::get_wallet_canister(env, network, &identity_name).await? - }; - - // amount has been validated by cycle_amount_validator - let cycles = opts - .with_cycles - .as_deref() - .map_or(0_u64, |amount| amount.parse::().unwrap()); - - #[derive(CandidType, Deserialize)] - struct In { - canister: CanisterId, - method_name: String, - #[serde(with = "serde_bytes")] - args: Vec, - cycles: u64, - } + let wallet = wallet_for_call_sender(env, call_sender, some_id).await?; let (result,): (CallResult,) = wallet .update_("wallet_call") - .with_arg(In { + .with_arg(CallIn { canister: canister_id, method_name: method_name.to_string(), args: arg_value, diff --git a/src/dfx/src/commands/command_utils.rs b/src/dfx/src/commands/command_utils.rs index 993dfa487d..3fd0df73c6 100644 --- a/src/dfx/src/commands/command_utils.rs +++ b/src/dfx/src/commands/command_utils.rs @@ -2,7 +2,10 @@ use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::identity::Identity; +use anyhow::anyhow; use ic_types::principal::Principal; +use ic_utils::canister::Canister; +use ic_utils::interfaces::Wallet; #[derive(Debug, PartialEq)] pub enum CallSender { @@ -38,3 +41,28 @@ pub async fn call_sender( }; Ok(sender) } + +#[allow(clippy::needless_lifetimes)] +pub async fn wallet_for_call_sender<'env>( + env: &'env dyn Environment, + call_sender: &CallSender, + some_id: &Option, +) -> DfxResult> { + let network = env + .get_network_descriptor() + .expect("No network descriptor."); + let identity_name = env.get_selected_identity().expect("No selected identity."); + if call_sender == &CallSender::Wallet(some_id.clone()) { + let id = some_id + .as_ref() + .expect("Wallet canister id should have been provided here."); + Identity::build_wallet_canister(id.clone(), env) + } else if call_sender == &CallSender::SelectedIdWallet(some_id.clone()) { + Identity::get_wallet_canister(env, network, &identity_name).await + } else { + Err(anyhow!( + "Attempted get a wallet for an invalid CallSender variant: {:?}", + call_sender + )) + } +} From 13b20dcbe4589e363926ccc338d0b0d381676e98 Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 15:45:05 -0800 Subject: [PATCH 5/7] refactor and call query method via correct update wallet_call --- src/dfx/src/commands/canister/call.rs | 41 ++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index 38d7fab649..31e4cd5dea 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -12,7 +12,6 @@ use anyhow::{anyhow, bail, Context}; use candid::{CandidType, Deserialize}; use clap::Clap; use ic_types::principal::Principal as CanisterId; -use ic_utils::call::SyncCall; use ic_utils::canister::{Argument, Canister}; use ic_utils::interfaces::wallet::{CallForwarder, CallResult}; use ic_utils::interfaces::Wallet; @@ -86,6 +85,16 @@ fn get_local_cid_and_candid_path( )) } +async fn do_wallet_call(wallet: &Canister<'_, Wallet>, args: &CallIn) -> DfxResult> { + let (result,): (CallResult,) = wallet + .update_("wallet_call") + .with_arg(args) + .build() + .call_and_wait(waiter_with_exponential_backoff()) + .await?; + Ok(result.r#return) +} + async fn request_id_via_wallet_call( wallet: &Canister<'_, Wallet>, canister: &Canister<'_>, @@ -183,19 +192,16 @@ pub async fn exec( } CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { let wallet = wallet_for_call_sender(env, call_sender, some_id).await?; - - let (result,): (CallResult,) = wallet - .query_("wallet_call") - .with_arg(CallIn { + do_wallet_call( + &wallet, + &CallIn { canister: canister_id, method_name: method_name.to_string(), args: arg_value, cycles, - }) - .build() - .call() - .await?; - result.r#return + }, + ) + .await? } }; print_idl_blob(&blob, output_type, &method_type) @@ -238,19 +244,16 @@ pub async fn exec( } CallSender::Wallet(some_id) | CallSender::SelectedIdWallet(some_id) => { let wallet = wallet_for_call_sender(env, call_sender, some_id).await?; - - let (result,): (CallResult,) = wallet - .update_("wallet_call") - .with_arg(CallIn { + do_wallet_call( + &wallet, + &CallIn { canister: canister_id, method_name: method_name.to_string(), args: arg_value, cycles, - }) - .build() - .call_and_wait(waiter_with_exponential_backoff()) - .await?; - result.r#return + }, + ) + .await? } }; From 82c250c614ed5cc3f79ebac4678bedcfc0a58aea Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 17:00:16 -0800 Subject: [PATCH 6/7] update basic-project and identity test --- e2e/tests-dfx/basic-project.bash | 19 +++++++++++++++++-- e2e/tests-dfx/identity.bash | 27 ++++++++++++++++----------- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/e2e/tests-dfx/basic-project.bash b/e2e/tests-dfx/basic-project.bash index f23b670ed6..aede89d8b0 100644 --- a/e2e/tests-dfx/basic-project.bash +++ b/e2e/tests-dfx/basic-project.bash @@ -33,11 +33,19 @@ teardown() { assert_eq '("Hello, Bongalo!")' # Using call --async and request-status. - assert_command dfx canister call --async hello greet Blueberry + # Call with user Identity as Sender + assert_command dfx canister --no-wallet call --async hello greet Blueberry # At this point $output is the request ID. # shellcheck disable=SC2154 assert_command dfx canister request-status "$stdout" assert_eq '("Hello, Blueberry!")' + + # Call using the wallet's call forwarding + assert_command dfx canister call --async hello greet Blueberry + # At this point $output is the request ID. + # shellcheck disable=SC2154 + assert_command dfx canister request-status "$stdout" + assert_eq '(record { 153_986_224 = blob "DIDL\00\01q\11Hello, Blueberry!" })' } @test "build + install + call + request-status -- counter_mo" { @@ -79,9 +87,16 @@ teardown() { assert_eq "()" # Write has no return value. But we can _call_ read too. - assert_command dfx canister call hello read --async + # Call with user Identity as Sender + assert_command dfx canister --no-wallet call hello read --async assert_command dfx canister request-status "$stdout" assert_eq "(1_337)" + + # Call using the wallet's call forwarding + assert_command dfx canister call hello read --async + assert_command dfx canister request-status "$stdout" + assert_eq '(record { 153_986_224 = blob "DIDL\00\01}\b9\0a" })' + } @test "build + install + call -- counter_idl_mo" { diff --git a/e2e/tests-dfx/identity.bash b/e2e/tests-dfx/identity.bash index 9e37910f9c..3e9381a60f 100644 --- a/e2e/tests-dfx/identity.bash +++ b/e2e/tests-dfx/identity.bash @@ -88,27 +88,32 @@ teardown() { assert_command dfx --identity alice build assert_command dfx --identity alice canister install --all + # The wallet is the initializer assert_command dfx --identity alice canister call e2e_project amInitializer + assert_eq '(true)' + + # The user Identity's principal is not the initializer + assert_command dfx --identity alice canister --no-wallet call e2e_project amInitializer assert_eq '(false)' - assert_command dfx --identity alice canister call \ + assert_command dfx --identity alice canister --no-wallet call \ "$(dfx --identity alice identity get-wallet)" wallet_call \ "(record { canister = principal \"$(dfx canister id e2e_project)\"; method_name = \"amInitializer\"; args = blob \"DIDL\00\00\"; cycles = (0:nat64)})" assert_eq '(record { 153_986_224 = blob "DIDL\00\01~\01" })' # True in DIDL. - assert_command dfx --identity bob canister call e2e_project amInitializer + assert_command dfx --identity bob canister --no-wallet call e2e_project amInitializer assert_eq '(false)' # these all fail (other identities are not initializer; cannot store assets): - assert_command_fail dfx --identity bob canister call e2e_project_assets store '("B", vec { 88; 87; 86 })' - assert_command_fail dfx --identity default canister call e2e_project_assets store '("B", vec { 88; 87; 86 })' - assert_command_fail dfx canister call e2e_project_assets store '("B", vec { 88; 87; 86 })' - assert_command_fail dfx canister call e2e_project_assets retrieve '("B")' + assert_command_fail dfx --identity bob canister --no-wallet call e2e_project_assets store '("B", vec { 88; 87; 86 })' + assert_command_fail dfx --identity default canister --no-wallet call e2e_project_assets store '("B", vec { 88; 87; 86 })' + assert_command_fail dfx canister --no-wallet call e2e_project_assets store '("B", vec { 88; 87; 86 })' + assert_command_fail dfx canister --no-wallet call e2e_project_assets retrieve '("B")' # but alice, the initializer, can store assets: assert_command dfx --identity alice canister call e2e_project_assets store '("B", vec { 88; 87; 86 })' assert_eq '()' - assert_command dfx canister call --output idl e2e_project_assets retrieve '("B")' + assert_command dfx canister --no-wallet call --output idl e2e_project_assets retrieve '("B")' assert_eq '(blob "XWV")' } @@ -120,24 +125,24 @@ teardown() { dfx --identity alice canister create --all assert_command dfx --identity alice build assert_command dfx --identity alice canister install --all - assert_command dfx --identity alice canister call \ + assert_command dfx --identity alice canister --no-wallet call \ "$(dfx --identity alice identity get-wallet)" wallet_call \ "(record { canister = principal \"$(dfx canister id e2e_project)\"; method_name = \"amInitializer\"; args = blob \"DIDL\00\00\"; cycles = (0:nat64)})" assert_eq '(record { 153_986_224 = blob "DIDL\00\01~\01" })' # True in DIDL. - assert_command dfx canister call e2e_project amInitializer + assert_command dfx canister --no-wallet call e2e_project amInitializer assert_eq '(false)' assert_command dfx identity rename alice bob assert_command dfx identity whoami assert_eq 'default' - assert_command dfx --identity bob canister call \ + assert_command dfx --identity bob canister --no-wallet call \ "$(dfx --identity bob identity get-wallet)" wallet_call \ "(record { canister = principal \"$(dfx canister id e2e_project)\"; method_name = \"amInitializer\"; args = blob \"DIDL\00\00\"; cycles = (0:nat64)})" assert_eq '(record { 153_986_224 = blob "DIDL\00\01~\01" })' # True in DIDL. assert_command dfx --identity bob canister call e2e_project_assets store '("B", blob "hello")' assert_eq '()' - assert_command dfx canister call --output idl e2e_project_assets retrieve '("B")' + assert_command dfx canister --no-wallet call --output idl e2e_project_assets retrieve '("B")' assert_eq '(blob "hello")' } From 50e7112056fadc9715b113895fee268e3bfd5467 Mon Sep 17 00:00:00 2001 From: Prithvi Shahi Date: Tue, 9 Mar 2021 17:17:47 -0800 Subject: [PATCH 7/7] patch certificate.bash --- e2e/tests-dfx/certificate.bash | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e/tests-dfx/certificate.bash b/e2e/tests-dfx/certificate.bash index 5ffff42812..a89c3cded9 100644 --- a/e2e/tests-dfx/certificate.bash +++ b/e2e/tests-dfx/certificate.bash @@ -60,6 +60,9 @@ teardown() { } @test "mitm attack - query: attack succeeds because there is no certificate to verify" { - assert_command dfx canister call certificate hello_query '("Buckaroo")' + # The wallet does not have a query call forward method (currently calls forward from wallet's update method) + # So call with users Identity as sender here + # There may need to be a query version of wallet_call + assert_command dfx canister --no-wallet call certificate hello_query '("Buckaroo")' assert_eq '("Hullo, Buckaroo!")' }