Skip to content

Commit

Permalink
make parallel calls (#96)
Browse files Browse the repository at this point in the history
* make parallel calls

* readme

* bump version
  • Loading branch information
chenyan-dfinity authored Sep 4, 2024
1 parent 4a5555e commit 746bea2
Show file tree
Hide file tree
Showing 8 changed files with 404 additions and 197 deletions.
480 changes: 292 additions & 188 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ic-repl"
version = "0.7.4"
version = "0.7.5"
authors = ["DFINITY Team"]
edition = "2021"
default-run = "ic-repl"
Expand Down Expand Up @@ -47,4 +47,5 @@ qrcode = "0.13"
image = { version = "0.24", default-features = false, features = ["png"] }
libflate = "2.0"
base64 = "0.21"
futures = "0.3.30"

8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ ic-repl [--replica [local|ic|url] | --offline [--format [json|ascii|png]]] --con
| <var> <transformer>* // variable with optional transformers
| fail <exp> // convert error message as text
| call (as <name>)? <name> . <name> (( <exp>,* ))? // call a canister method, and store the result as a single value
| par_call [ (<name> . <name> (( <exp>,* ))),* ] // make concurrent canister calls, and store the result as a tuple record
| encode (<name> . <name>)? (( <exp>,* ))? // encode candid arguments as a blob value. canister.__init_args represents init args
| decode (as <name> . <name>)? <exp> // decode blob as candid values
| <id> ( <exp>,* ) // function application
Expand Down Expand Up @@ -166,11 +167,12 @@ function deploy(wasm) {
identity alice;
let id = deploy(file("greet.wasm"));
let status = call ic.canister_status(id);
let canister = id.canister_id;
let res = par_call [ic.canister_status(id), canister.greet("test")];
let status = res[0];
assert status.settings ~= record { controllers = vec { alice } };
assert status.module_hash? == blob "...";
let canister = id.canister_id;
call canister.greet("test");
assert res[1] == "Hello, test!";
```

### wallet.sh
Expand Down
8 changes: 4 additions & 4 deletions examples/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ function deploy(wasm) {

identity alice;
let id = deploy(file("greet.wasm"));
let status = call ic.canister_status(id);
let canister = id.canister_id;
let res = par_call [ic.canister_status(id), canister.greet("test")];
let status = res[0];
assert status.settings ~= record { controllers = vec { alice } };
assert status.module_hash? == blob "\ab\a7h\8cH\e0]\e7W]\8b\07\92\ac\9fH\95\7f\f4\97\d0\efX\c4~\0d\83\91\01<\da\1d";
let canister = id.canister_id;
call canister.greet("test");
assert _ == "Hello, test!";
assert res[1] == "Hello, test!";
call ic.stop_canister(id);
call ic.delete_canister(id);
53 changes: 53 additions & 0 deletions src/exp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use candid::{
utils::check_unique,
Principal, TypeEnv,
};
use futures::future::try_join_all;
use std::collections::BTreeMap;

#[derive(Debug, Clone)]
Expand All @@ -24,6 +25,9 @@ pub enum Exp {
args: Option<Vec<Exp>>,
mode: CallMode,
},
ParCall {
calls: Vec<FuncCall>,
},
Decode {
method: Option<Method>,
blob: Box<Exp>,
Expand Down Expand Up @@ -57,12 +61,18 @@ pub enum CallMode {
Proxy(String),
}
#[derive(Debug, Clone)]
pub struct FuncCall {
pub method: Method,
pub args: Vec<Exp>,
}
#[derive(Debug, Clone)]
pub struct Field {
pub id: Label,
pub val: Exp,
}
impl Exp {
pub fn is_call(&self) -> bool {
// Used to decide if we want to report profiling numbers. Ignore par_call for now
matches!(
self,
Exp::Call {
Expand Down Expand Up @@ -568,6 +578,42 @@ impl Exp {
};
args_to_value(args)
}
Exp::ParCall { calls } => {
let mut futures = Vec::with_capacity(calls.len());
for call in calls {
let mut args = Vec::with_capacity(call.args.len());
for arg in call.args.into_iter() {
args.push(arg.eval(helper)?);
}
let args = IDLArgs { args };
let info = call.method.get_info(helper, false)?;
let bytes = if let Some((env, func)) = &info.signature {
args.to_bytes_with_types(env, &func.args)?
} else {
args.to_bytes()?
};
let method = &call.method.method;
let effective_id = get_effective_canister_id(info.canister_id, method, &bytes)?;
let mut builder = helper.agent.update(&info.canister_id, method);
builder = builder
.with_arg(bytes)
.with_effective_canister_id(effective_id);
let call_future = async move {
let res = builder.call_and_wait().await?;
if let Some((env, func)) = &info.signature {
Ok(IDLArgs::from_bytes_with_types(&res, env, &func.rets)?)
} else {
Ok(IDLArgs::from_bytes(&res)?)
}
};
futures.push(call_future);
}
let res = parallel_calls(futures)?;
let res = IDLArgs {
args: res.into_iter().map(args_to_value).collect(),
};
args_to_value(res)
}
Exp::Call { method, args, mode } => {
let args = if let Some(args) = args {
let mut res = Vec::with_capacity(args.len());
Expand Down Expand Up @@ -866,6 +912,13 @@ pub fn apply_func(helper: &MyHelper, func: &str, args: Vec<IDLValue>) -> Result<
}
}
}
#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn parallel_calls(
futures: Vec<impl std::future::Future<Output = anyhow::Result<IDLArgs>>>,
) -> anyhow::Result<Vec<IDLArgs>> {
let res = try_join_all(futures).await?;
Ok(res)
}
#[tokio::main]
async fn call(
helper: &MyHelper,
Expand Down
5 changes: 4 additions & 1 deletion src/grammar.lalrpop
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::exp::{Field, Exp, Method, CallMode};
use super::exp::{Field, Exp, Method, CallMode, FuncCall};
use super::selector::Selector;
use candid_parser::types::{IDLType, TypeField, PrimType, FuncType, Binding};
use candid::utils::check_unique;
Expand Down Expand Up @@ -34,6 +34,7 @@ extern {
"load" => Token::Load,
"principal" => Token::Principal,
"call" => Token::Call,
"par_call" => Token::ParCall,
"encode" => Token::Encode,
"decode" => Token::Decode,
"as" => Token::As,
Expand Down Expand Up @@ -101,11 +102,13 @@ pub Exp: Exp = {
Variable => <>,
"fail" <Exp> => Exp::Fail(Box::new(<>)),
"call" <method:Method> <args:Exps?> => Exp::Call{method:Some(method), args, mode: CallMode::Call},
"par_call" "[" <calls:SepBy<FuncCall, ",">> "]" => Exp::ParCall { calls },
"call" "as" <proxy:Name> <method:Method> <args:Exps?> => Exp::Call{method:Some(method), args, mode: CallMode::Proxy(proxy)},
"encode" <method:Method?> <args:Exps?> => Exp::Call{method, args, mode: CallMode::Encode},
"decode" <method:("as" <Method>)?> <blob:Exp> => Exp::Decode{method, blob:Box::new(blob)},
<func:"id"> "(" <args:SepBy<Exp, ",">> ")" => Exp::Apply(func, args),
}
FuncCall: FuncCall = <method:Method> <args:Exps> => FuncCall { method, args };
Variable: Exp = <v:"id"> <path:(<Selector>)*> => Exp::Path(v, path);
Selector: Selector = {
"?" => Selector::Option,
Expand Down
42 changes: 42 additions & 0 deletions src/ic.did
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ type change_details = variant {
mode : variant { install; reinstall; upgrade };
module_hash : blob;
};
load_snapshot : record {
canister_version : nat64;
taken_at_timestamp : nat64;
};
controllers_change : record {
controllers : vec principal;
};
Expand Down Expand Up @@ -341,6 +345,38 @@ type bitcoin_get_balance_query_result = satoshi;

type bitcoin_get_current_fee_percentiles_result = vec millisatoshi_per_byte;

type snapshot_id = blob;

type snapshot = record {
id : snapshot_id;
taken_at_timestamp : nat64;
total_size : nat64;
};

type take_canister_snapshot_args = record {
canister_id : canister_id;
replace_snapshot : opt snapshot_id;
};

type take_canister_snapshot_result = snapshot;

type load_canister_snapshot_args = record {
canister_id : canister_id;
snapshot_id : snapshot_id;
sender_canister_version : opt nat64;
};

type list_canister_snapshots_args = record {
canister_id : canister_id;
};

type list_canister_snapshots_result = vec snapshot;

type delete_canister_snapshot_args = record {
canister_id : canister_id;
snapshot_id : snapshot_id;
};

type fetch_canister_logs_args = record {
canister_id : canister_id;
};
Expand Down Expand Up @@ -392,6 +428,12 @@ service ic : {
provisional_create_canister_with_cycles : (provisional_create_canister_with_cycles_args) -> (provisional_create_canister_with_cycles_result);
provisional_top_up_canister : (provisional_top_up_canister_args) -> ();

// Canister snapshots
take_canister_snapshot : (take_canister_snapshot_args) -> (take_canister_snapshot_result);
load_canister_snapshot : (load_canister_snapshot_args) -> ();
list_canister_snapshots : (list_canister_snapshots_args) -> (list_canister_snapshots_result);
delete_canister_snapshot : (delete_canister_snapshot_args) -> ();

// canister logging
fetch_canister_logs : (fetch_canister_logs_args) -> (fetch_canister_logs_result) query;
};
2 changes: 2 additions & 0 deletions src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ pub enum Token {
Fail,
#[token("call")]
Call,
#[token("par_call")]
ParCall,
#[token("encode")]
Encode,
#[token("decode")]
Expand Down

0 comments on commit 746bea2

Please sign in to comment.