diff --git a/Cargo.lock b/Cargo.lock index efb2a6b86f..2e1204f0e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1886,7 +1886,7 @@ dependencies = [ [[package]] name = "ic-agent" version = "0.2.0" -source = "git+https://github.com/dfinity/agent-rs.git?branch=next#87ca70d82e67b5c7c6367a35580fe1d491c793f5" +source = "git+https://github.com/dfinity/agent-rs.git?branch=next#5472fb610faa6cc1f0c12c82a745e435603fae08" dependencies = [ "async-trait", "base32", @@ -1917,7 +1917,7 @@ dependencies = [ [[package]] name = "ic-identity-hsm" version = "0.2.0" -source = "git+https://github.com/dfinity/agent-rs.git?branch=next#87ca70d82e67b5c7c6367a35580fe1d491c793f5" +source = "git+https://github.com/dfinity/agent-rs.git?branch=next#5472fb610faa6cc1f0c12c82a745e435603fae08" dependencies = [ "hex", "ic-agent", @@ -1932,7 +1932,7 @@ dependencies = [ [[package]] name = "ic-types" version = "0.1.2" -source = "git+https://github.com/dfinity/agent-rs.git?branch=next#87ca70d82e67b5c7c6367a35580fe1d491c793f5" +source = "git+https://github.com/dfinity/agent-rs.git?branch=next#5472fb610faa6cc1f0c12c82a745e435603fae08" dependencies = [ "base32", "crc32fast", @@ -1944,7 +1944,7 @@ dependencies = [ [[package]] name = "ic-utils" version = "0.2.0" -source = "git+https://github.com/dfinity/agent-rs.git?branch=next#87ca70d82e67b5c7c6367a35580fe1d491c793f5" +source = "git+https://github.com/dfinity/agent-rs.git?branch=next#5472fb610faa6cc1f0c12c82a745e435603fae08" dependencies = [ "async-trait", "candid", @@ -1953,6 +1953,8 @@ dependencies = [ "ic-types", "serde", "serde_bytes", + "strum", + "strum_macros", "thiserror", ] @@ -3858,6 +3860,24 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "syn" version = "1.0.64" diff --git a/Cargo.toml b/Cargo.toml index 42e7ae491b..c372a1dc72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,22 +7,22 @@ members = [ version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [patch.crates-io.ic-identity-hsm] version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [patch.crates-io.ic-types] version = "0.1.2" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [patch.crates-io.ic-utils] version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" diff --git a/e2e/tests-dfx/basic-project.bash b/e2e/tests-dfx/basic-project.bash index b94b2780f8..9f7e011a1e 100644 --- a/e2e/tests-dfx/basic-project.bash +++ b/e2e/tests-dfx/basic-project.bash @@ -37,14 +37,14 @@ teardown() { 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_command dfx canister request-status "$stdout" "$(dfx canister id hello)" 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_command dfx canister request-status "$stdout" "$(dfx identity get-wallet)" assert_eq '( variant { 17_724 = record { 153_986_224 = blob "DIDL\00\01q\11Hello, Blueberry!" } }, )' } @@ -80,7 +80,7 @@ teardown() { assert_eq "(3)" assert_command dfx canister call hello inc --async - assert_command dfx canister request-status "$stdout" + assert_command dfx canister request-status "$stdout" "$(dfx identity get-wallet)" # Call write. assert_command dfx canister call hello write 1337 @@ -89,12 +89,12 @@ teardown() { # Write has no return value. But we can _call_ read too. # Call with user Identity as Sender assert_command dfx canister --no-wallet call hello read --async - assert_command dfx canister request-status "$stdout" + assert_command dfx canister request-status "$stdout" "$(dfx canister id hello)" 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_command dfx canister request-status "$stdout" "$(dfx identity get-wallet)" assert_eq '(variant { 17_724 = record { 153_986_224 = blob "DIDL\00\01}\b9\0a" } })' } diff --git a/nix/sources.json b/nix/sources.json index 3cd36cb4bd..f772309dcb 100644 --- a/nix/sources.json +++ b/nix/sources.json @@ -34,13 +34,13 @@ "dfinity": { "branch": "master", "repo": "ssh://git@github.com/dfinity-lab/dfinity", - "rev": "a7d3a895e7c7f684a4c983f226adf5d41e29a64f", + "rev": "c851e777547e2d3ed7b45162277e9c160860e7a0", "type": "git" }, "ic-ref": { + "tag": "0.16.0", "repo": "ssh://git@github.com/dfinity-lab/ic-ref", - "rev": "77f368d006c337eab0df1620659133c1f7e48b10", - "tag": "0.15.5", + "rev": "215641629ace2d590013f89bb3f3fe3b0a0d3c3b", "type": "git" }, "motoko": { diff --git a/src/dfx/Cargo.toml b/src/dfx/Cargo.toml index 5bebd5926e..c43716227e 100644 --- a/src/dfx/Cargo.toml +++ b/src/dfx/Cargo.toml @@ -76,26 +76,26 @@ webpki-roots = "0.21.0" version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" features = ["reqwest"] [dependencies.ic-identity-hsm] version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [dependencies.ic-types] version = "0.1.2" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [dependencies.ic-utils] version = "0.2.0" git = "https://github.com/dfinity/agent-rs.git" branch = "next" -rev = "87ca70d82e67b5c7c6367a35580fe1d491c793f5" +rev = "5472fb610faa6cc1f0c12c82a745e435603fae08" [dev-dependencies] env_logger = "0.6" diff --git a/src/dfx/src/commands/canister/call.rs b/src/dfx/src/commands/canister/call.rs index d61901cd70..06d00e53e1 100644 --- a/src/dfx/src/commands/canister/call.rs +++ b/src/dfx/src/commands/canister/call.rs @@ -10,13 +10,15 @@ 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}; -use candid::{CandidType, Deserialize}; +use candid::{CandidType, Decode, Deserialize}; use clap::{ArgSettings, Clap}; use ic_types::principal::Principal as CanisterId; use ic_utils::canister::{Argument, Canister}; +use ic_utils::interfaces::management_canister::{CanisterInstall, MgmtMethod}; use ic_utils::interfaces::wallet::{CallForwarder, CallResult}; use ic_utils::interfaces::Wallet; use std::option::Option; +use std::str::FromStr; /// Calls a method on a deployed canister. #[derive(Clap)] @@ -98,6 +100,58 @@ async fn request_id_via_wallet_call( .map_err(|err| anyhow!("Agent error {}", err)) } +pub fn get_effective_canister_id( + is_management_canister: bool, + method_name: &str, + arg_value: &[u8], + canister_id: CanisterId, +) -> DfxResult { + if is_management_canister { + let method_name = MgmtMethod::from_str(method_name).map_err(|_| { + anyhow!( + "Attempted to call an unsupported management canister method: {}", + method_name + ) + })?; + match method_name { + MgmtMethod::CreateCanister + | MgmtMethod::RawRand => { + bail!(format!("{} can only be called via an inter-canister call. Try calling this without `--no-wallet`.", + method_name.as_ref())) + }, + MgmtMethod::InstallCode => { + let install_args = candid::Decode!(arg_value, CanisterInstall)?; + Ok(install_args.canister_id) + } + MgmtMethod::SetController => { + #[derive(CandidType, Deserialize)] + struct In { + canister_id: CanisterId, + new_controller: CanisterId, + } + let in_args = candid::Decode!(arg_value, In)?; + Ok(in_args.canister_id) + } + MgmtMethod::StartCanister + | MgmtMethod::StopCanister + | MgmtMethod::CanisterStatus + | MgmtMethod::DeleteCanister + | MgmtMethod::DepositCycles + | MgmtMethod::ProvisionalTopUpCanister => { + #[derive(CandidType, Deserialize)] + struct In { + canister_id: CanisterId, + } + let in_args = candid::Decode!(arg_value, In)?; + Ok(in_args.canister_id) + } + MgmtMethod::ProvisionalCreateCanisterWithCycles => Ok(CanisterId::management_canister()), + } + } else { + Ok(canister_id) + } +} + pub async fn exec( env: &dyn Environment, opts: CanisterCallOpts, @@ -122,6 +176,8 @@ pub async fn exec( } }; + let is_management_canister = canister_id == CanisterId::management_canister(); + let method_type = maybe_candid_path.and_then(|path| get_candid_type(&path, method_name)); let is_query_method = match &method_type { Some((_, f)) => Some(f.is_query()), @@ -170,8 +226,15 @@ pub async fn exec( if is_query { let blob = match call_sender { CallSender::SelectedId => { + let effective_canister_id = get_effective_canister_id( + is_management_canister, + method_name, + &arg_value, + canister_id.clone(), + )?; agent .query(&canister_id, method_name) + .with_effective_canister_id(effective_canister_id) .with_arg(&arg_value) .call() .await? @@ -195,8 +258,15 @@ pub async fn exec( } else if opts.r#async { let request_id = match call_sender { CallSender::SelectedId => { + let effective_canister_id = get_effective_canister_id( + is_management_canister, + method_name, + &arg_value, + canister_id.clone(), + )?; agent .update(&canister_id, method_name) + .with_effective_canister_id(effective_canister_id) .with_arg(&arg_value) .call() .await? @@ -221,8 +291,15 @@ pub async fn exec( } else { let blob = match call_sender { CallSender::SelectedId => { + let effective_canister_id = get_effective_canister_id( + is_management_canister, + method_name, + &arg_value, + canister_id.clone(), + )?; agent .update(&canister_id, method_name) + .with_effective_canister_id(effective_canister_id) .with_arg(&arg_value) .expire_after(timeout) .call_and_wait(waiter_with_exponential_backoff()) diff --git a/src/dfx/src/commands/canister/request_status.rs b/src/dfx/src/commands/canister/request_status.rs index b2614ce531..399e10215e 100644 --- a/src/dfx/src/commands/canister/request_status.rs +++ b/src/dfx/src/commands/canister/request_status.rs @@ -1,5 +1,6 @@ use crate::lib::environment::Environment; 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; use crate::util::clap::validators; @@ -10,6 +11,7 @@ use clap::Clap; use delay::Waiter; use ic_agent::agent::{Replied, RequestStatusResponse}; use ic_agent::{AgentError, RequestId}; +use ic_types::Principal; use std::str::FromStr; /// Requests the status of a specified call from a canister. @@ -19,6 +21,11 @@ pub struct RequestStatusOpts { /// The request identifier is an hexadecimal string starting with 0x. #[clap(validator(validators::is_request_id))] request_id: String, + + /// Specifies the name or id of the canister onto which the request was made. + /// If the request was made to the Management canister, specify the id of the + /// canister it is updating/querying. + canister_name: String, } pub async fn exec(env: &dyn Environment, opts: RequestStatusOpts) -> DfxResult { @@ -30,12 +37,21 @@ pub async fn exec(env: &dyn Environment, opts: RequestStatusOpts) -> DfxResult { fetch_root_key_if_needed(env).await?; + let callee_canister = opts.canister_name.as_str(); + let canister_id_store = CanisterIdStore::for_env(env)?; + + let canister_id = Principal::from_text(callee_canister) + .or_else(|_| canister_id_store.get(callee_canister))?; + let mut waiter = waiter_with_exponential_backoff(); let Replied::CallReplied(blob) = async { waiter.start(); let mut request_accepted = false; loop { - match agent.request_status_raw(&request_id).await? { + match agent + .request_status_raw(&request_id, canister_id.clone()) + .await? + { RequestStatusResponse::Replied { reply } => return Ok(reply), RequestStatusResponse::Rejected { reject_code, diff --git a/src/dfx/src/commands/canister/send.rs b/src/dfx/src/commands/canister/send.rs index b3485f7c99..1e5baad967 100644 --- a/src/dfx/src/commands/canister/send.rs +++ b/src/dfx/src/commands/canister/send.rs @@ -3,11 +3,12 @@ use crate::lib::error::DfxResult; use crate::lib::identity::identity_utils::CallSender; use crate::lib::sign::signed_message::SignedMessageV1; -use ic_agent::agent::ReplicaV1Transport; -use ic_agent::{agent::http_transport::ReqwestHttpReplicaV1Transport, RequestId}; +use ic_agent::agent::ReplicaV2Transport; +use ic_agent::{agent::http_transport::ReqwestHttpReplicaV2Transport, RequestId}; use anyhow::{anyhow, bail}; use clap::Clap; +use ic_types::Principal; use std::{fs::File, path::Path}; use std::{io::Read, str::FromStr}; @@ -55,12 +56,13 @@ pub async fn exec( } let network = message.network; - let transport = ReqwestHttpReplicaV1Transport::create(network)?; + let transport = ReqwestHttpReplicaV2Transport::create(network)?; let content = hex::decode(&message.content)?; + let canister_id = Principal::from_text(message.canister_id)?; match message.call_type.as_str() { "query" => { - let response = transport.read(content).await?; + let response = transport.query(canister_id, content).await?; eprintln!( "To see the content of response, copy-paste the encoded string into cbor.me." ); @@ -73,7 +75,7 @@ pub async fn exec( .request_id .expect("Cannot get request_id from the update message"), )?; - transport.submit(content, request_id).await?; + transport.call(canister_id, content, request_id).await?; eprint!("Request ID: "); println!("0x{}", String::from(request_id)); } diff --git a/src/dfx/src/commands/canister/sign.rs b/src/dfx/src/commands/canister/sign.rs index 661cbc0929..3dc4db7b8f 100644 --- a/src/dfx/src/commands/canister/sign.rs +++ b/src/dfx/src/commands/canister/sign.rs @@ -1,9 +1,10 @@ +use crate::commands::canister::call::get_effective_canister_id; use crate::lib::environment::Environment; use crate::lib::error::DfxResult; use crate::lib::identity::identity_utils::CallSender; use crate::lib::models::canister_id_store::CanisterIdStore; use crate::lib::operations::canister::get_local_cid_and_candid_path; -use crate::lib::sign::sign_transport::SignReplicaV1Transport; +use crate::lib::sign::sign_transport::SignReplicaV2Transport; use crate::lib::sign::signed_message::SignedMessageV1; use crate::util::{blob_from_arguments, get_candid_type}; @@ -159,11 +160,20 @@ pub async fn exec( } let mut sign_agent = agent.clone(); - sign_agent.set_transport(SignReplicaV1Transport::new(file_name, message_template)); + sign_agent.set_transport(SignReplicaV2Transport::new(file_name, message_template)); + + let is_management_canister = canister_id == Principal::management_canister(); + let effective_canister_id = get_effective_canister_id( + is_management_canister, + method_name, + &arg_value, + canister_id.clone(), + )?; if is_query { let res = sign_agent .query(&canister_id, method_name) + .with_effective_canister_id(effective_canister_id) .with_arg(&arg_value) .expire_at(expiration_system_time) .call() @@ -179,6 +189,7 @@ pub async fn exec( } else { let res = sign_agent .update(&canister_id, method_name) + .with_effective_canister_id(effective_canister_id) .with_arg(&arg_value) .expire_at(expiration_system_time) .call() diff --git a/src/dfx/src/commands/start.rs b/src/dfx/src/commands/start.rs index ca55f4fd6d..b381853568 100644 --- a/src/dfx/src/commands/start.rs +++ b/src/dfx/src/commands/start.rs @@ -49,7 +49,7 @@ fn ping_and_wait(frontend_url: &str) -> DfxResult { let agent = Agent::builder() .with_transport( - ic_agent::agent::http_transport::ReqwestHttpReplicaV1Transport::create(frontend_url)?, + ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport::create(frontend_url)?, ) .build()?; diff --git a/src/dfx/src/lib/environment.rs b/src/dfx/src/lib/environment.rs index 39e27b2e4a..036c0a8fa9 100644 --- a/src/dfx/src/lib/environment.rs +++ b/src/dfx/src/lib/environment.rs @@ -454,7 +454,7 @@ fn create_agent( .and_then(|executor| { Agent::builder() .with_transport( - ic_agent::agent::http_transport::ReqwestHttpReplicaV1Transport::create(url) + ic_agent::agent::http_transport::ReqwestHttpReplicaV2Transport::create(url) .unwrap() .with_password_manager(executor), ) diff --git a/src/dfx/src/lib/operations/canister/install_canister.rs b/src/dfx/src/lib/operations/canister/install_canister.rs index c5d821ef41..9b2b469efd 100644 --- a/src/dfx/src/lib/operations/canister/install_canister.rs +++ b/src/dfx/src/lib/operations/canister/install_canister.rs @@ -8,9 +8,10 @@ use crate::lib::waiter::waiter_with_timeout; use anyhow::Context; use ic_agent::Agent; -use ic_types::Principal; use ic_utils::call::AsyncCall; -use ic_utils::interfaces::management_canister::{ComputeAllocation, InstallMode, MemoryAllocation}; +use ic_utils::interfaces::management_canister::{ + CanisterInstall, ComputeAllocation, InstallMode, MemoryAllocation, +}; use ic_utils::interfaces::ManagementCanister; use ic_utils::Canister; use slog::info; @@ -78,16 +79,6 @@ pub async fn install_canister( CallSender::Wallet(wallet_id) | CallSender::SelectedIdWallet(wallet_id) => { let wallet = Identity::build_wallet_canister(wallet_id.clone(), env)?; - #[derive(candid::CandidType)] - struct CanisterInstall { - mode: InstallMode, - canister_id: Principal, - wasm_module: Vec, - arg: Vec, - compute_allocation: Option, - memory_allocation: Option, - } - let install_args = CanisterInstall { mode, canister_id: canister_id.clone(), diff --git a/src/dfx/src/lib/operations/canister/mod.rs b/src/dfx/src/lib/operations/canister/mod.rs index ae9b651f86..20e95ac988 100644 --- a/src/dfx/src/lib/operations/canister/mod.rs +++ b/src/dfx/src/lib/operations/canister/mod.rs @@ -25,6 +25,7 @@ use std::time::Duration; async fn do_management_call( env: &dyn Environment, + destination_canister: Principal, method: &str, arg: A, timeout: Duration, @@ -43,6 +44,7 @@ where CallSender::SelectedId => { mgr.update_(method) .with_arg(arg) + .with_effective_canister_id(destination_canister) .build() .call_and_wait(waiter_with_timeout(timeout)) .await? @@ -73,6 +75,7 @@ pub async fn get_canister_status( let (out,): (StatusCallResult,) = do_management_call( env, + canister_id.clone(), "canister_status", In { canister_id }, timeout, @@ -95,6 +98,7 @@ pub async fn start_canister( let _: () = do_management_call( env, + canister_id.clone(), "start_canister", In { canister_id }, timeout, @@ -117,6 +121,7 @@ pub async fn stop_canister( let _: () = do_management_call( env, + canister_id.clone(), "stop_canister", In { canister_id }, timeout, @@ -141,6 +146,7 @@ pub async fn set_controller( let _: () = do_management_call( env, + canister_id.clone(), "set_controller", In { canister_id, @@ -165,6 +171,7 @@ pub async fn delete_canister( } let _: () = do_management_call( env, + canister_id.clone(), "delete_canister", In { canister_id }, timeout, diff --git a/src/dfx/src/lib/sign/sign_transport.rs b/src/dfx/src/lib/sign/sign_transport.rs index 2d4c5cd53b..e912b61671 100644 --- a/src/dfx/src/lib/sign/sign_transport.rs +++ b/src/dfx/src/lib/sign/sign_transport.rs @@ -1,7 +1,8 @@ use super::signed_message::SignedMessageV1; -use ic_agent::agent::ReplicaV1Transport; +use ic_agent::agent::ReplicaV2Transport; use ic_agent::{AgentError, RequestId}; +use ic_types::Principal; use std::fs::File; use std::future::Future; @@ -16,12 +17,12 @@ enum SerializeStatus { Success(String), } -pub(crate) struct SignReplicaV1Transport { +pub(crate) struct SignReplicaV2Transport { file_name: String, message_template: SignedMessageV1, } -impl SignReplicaV1Transport { +impl SignReplicaV2Transport { pub fn new>(file_name: U, message_template: SignedMessageV1) -> Self { Self { file_name: file_name.into(), @@ -30,16 +31,37 @@ impl SignReplicaV1Transport { } } -impl ReplicaV1Transport for SignReplicaV1Transport { - fn read<'a>( +impl ReplicaV2Transport for SignReplicaV2Transport { + fn read_state<'a>( &'a self, - envelope: Vec, + _effective_canister_id: Principal, + _envelope: Vec, ) -> Pin, AgentError>> + Send + 'a>> { - async fn run(s: &SignReplicaV1Transport, envelope: Vec) -> Result, AgentError> { + async fn run(_: &SignReplicaV2Transport) -> Result, AgentError> { + Err(AgentError::MessageError( + "read_state calls not supported".to_string(), + )) + } + + Box::pin(run(self)) + } + + fn call<'a>( + &'a self, + _effective_canister_id: Principal, + envelope: Vec, + request_id: RequestId, + ) -> Pin> + Send + 'a>> { + async fn run( + s: &SignReplicaV2Transport, + envelope: Vec, + request_id: RequestId, + ) -> Result<(), AgentError> { let message = s .message_template .clone() - .with_call_type("query".to_string()) + .with_call_type("update".to_string()) + .with_request_id(request_id) .with_content(hex::encode(&envelope)); let json = serde_json::to_string(&message) .map_err(|x| AgentError::MessageError(x.to_string()))?; @@ -49,29 +71,24 @@ impl ReplicaV1Transport for SignReplicaV1Transport { file.write_all(json.as_bytes()) .map_err(|x| AgentError::MessageError(x.to_string()))?; Err(AgentError::TransportError( - SerializeStatus::Success(format!("Query message generated at [{}]", &s.file_name)) + SerializeStatus::Success(format!("Update message generated at [{}]", &s.file_name)) .into(), )) } - Box::pin(run(self, envelope)) + Box::pin(run(self, envelope, request_id)) } - fn submit<'a>( + fn query<'a>( &'a self, + _effective_canister_id: Principal, envelope: Vec, - request_id: RequestId, - ) -> Pin> + Send + 'a>> { - async fn run( - s: &SignReplicaV1Transport, - envelope: Vec, - request_id: RequestId, - ) -> Result<(), AgentError> { + ) -> Pin, AgentError>> + Send + 'a>> { + async fn run(s: &SignReplicaV2Transport, envelope: Vec) -> Result, AgentError> { let message = s .message_template .clone() - .with_call_type("update".to_string()) - .with_request_id(request_id) + .with_call_type("query".to_string()) .with_content(hex::encode(&envelope)); let json = serde_json::to_string(&message) .map_err(|x| AgentError::MessageError(x.to_string()))?; @@ -81,18 +98,18 @@ impl ReplicaV1Transport for SignReplicaV1Transport { file.write_all(json.as_bytes()) .map_err(|x| AgentError::MessageError(x.to_string()))?; Err(AgentError::TransportError( - SerializeStatus::Success(format!("Update message generated at [{}]", &s.file_name)) + SerializeStatus::Success(format!("Query message generated at [{}]", &s.file_name)) .into(), )) } - Box::pin(run(self, envelope, request_id)) + Box::pin(run(self, envelope)) } fn status<'a>( &'a self, ) -> Pin, AgentError>> + Send + 'a>> { - async fn run(_: &SignReplicaV1Transport) -> Result, AgentError> { + async fn run(_: &SignReplicaV2Transport) -> Result, AgentError> { Err(AgentError::MessageError( "status calls not supported".to_string(), )) diff --git a/src/dfx/src/lib/webserver.rs b/src/dfx/src/lib/webserver.rs index 17b6e92986..7388152ec9 100644 --- a/src/dfx/src/lib/webserver.rs +++ b/src/dfx/src/lib/webserver.rs @@ -260,7 +260,7 @@ async fn http_request( data.providers[count % data.providers.len()].clone() }; - let transport = http_transport::ReqwestHttpReplicaV1Transport::create(url.to_string()) + let transport = http_transport::ReqwestHttpReplicaV2Transport::create(url.to_string()) .map_err(|err| { actix_web::error::InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR) })?; diff --git a/src/dfx/src/lib/webserver/http_transport.rs b/src/dfx/src/lib/webserver/http_transport.rs index 601bf9d020..f3d07a0b91 100644 --- a/src/dfx/src/lib/webserver/http_transport.rs +++ b/src/dfx/src/lib/webserver/http_transport.rs @@ -1,17 +1,17 @@ use ic_agent::agent::agent_error::HttpErrorPayload; -use ic_agent::AgentError; -use ic_agent::RequestId; +use ic_agent::{AgentError, RequestId}; +use ic_types::Principal; use reqwest::Method; use std::future::Future; use std::pin::Pin; -/// A [ReplicaV1Transport] using Reqwest to make HTTP calls to the internet computer. -pub struct ReqwestHttpReplicaV1Transport { +/// A [ReplicaV2Transport] using Reqwest to make HTTP calls to the internet computer. +pub struct ReqwestHttpReplicaV2Transport { url: reqwest::Url, client: reqwest::Client, } -impl ReqwestHttpReplicaV1Transport { +impl ReqwestHttpReplicaV2Transport { pub fn create>(url: U) -> Result { let mut tls_config = rustls::ClientConfig::new(); @@ -26,7 +26,7 @@ impl ReqwestHttpReplicaV1Transport { Ok(Self { url: reqwest::Url::parse(&url) - .and_then(|url| url.join("api/v1/")) + .and_then(|url| url.join("api/v2/")) .map_err(|_| AgentError::InvalidReplicaUrl(url.clone()))?, client: reqwest::Client::builder() .use_preconfigured_tls(tls_config) @@ -94,40 +94,64 @@ impl ReqwestHttpReplicaV1Transport { } } -impl ic_agent::agent::ReplicaV1Transport for ReqwestHttpReplicaV1Transport { - fn read<'a>( +impl ic_agent::agent::ReplicaV2Transport for ReqwestHttpReplicaV2Transport { + fn read_state<'a>( &'a self, + effective_canister_id: Principal, envelope: Vec, ) -> Pin, AgentError>> + Send + 'a>> { async fn run( - s: &ReqwestHttpReplicaV1Transport, + s: &ReqwestHttpReplicaV2Transport, + effective_canister_id: Principal, envelope: Vec, ) -> Result, AgentError> { - s.execute(Method::POST, "read", Some(envelope)).await + let endpoint = format!("canister/{}/read_state", effective_canister_id); + s.execute(Method::POST, &endpoint, Some(envelope)).await } - Box::pin(run(self, envelope)) + Box::pin(run(self, effective_canister_id, envelope)) } - fn submit<'a>( + fn call<'a>( &'a self, + effective_canister_id: Principal, envelope: Vec, _request_id: RequestId, ) -> Pin> + Send + 'a>> { async fn run( - s: &ReqwestHttpReplicaV1Transport, + s: &ReqwestHttpReplicaV2Transport, + effective_canister_id: Principal, envelope: Vec, ) -> Result<(), AgentError> { - s.execute(Method::POST, "submit", Some(envelope)).await?; + let endpoint = format!("canister/{}/call", effective_canister_id); + s.execute(Method::POST, &endpoint, Some(envelope)).await?; Ok(()) } - Box::pin(run(self, envelope)) + + Box::pin(run(self, effective_canister_id, envelope)) + } + + fn query<'a>( + &'a self, + effective_canister_id: Principal, + envelope: Vec, + ) -> Pin, AgentError>> + Send + 'a>> { + async fn run( + s: &ReqwestHttpReplicaV2Transport, + effective_canister_id: Principal, + envelope: Vec, + ) -> Result, AgentError> { + let endpoint = format!("canister/{}/query", effective_canister_id); + s.execute(Method::POST, &endpoint, Some(envelope)).await + } + + Box::pin(run(self, effective_canister_id, envelope)) } fn status<'a>( &'a self, ) -> Pin, AgentError>> + Send + 'a>> { - async fn run(s: &ReqwestHttpReplicaV1Transport) -> Result, AgentError> { + async fn run(s: &ReqwestHttpReplicaV2Transport) -> Result, AgentError> { s.execute(Method::GET, "status", None).await }