diff --git a/canister_templates/stable.wasm b/canister_templates/stable.wasm index eda45c789f..7bf87656d7 100644 Binary files a/canister_templates/stable.wasm and b/canister_templates/stable.wasm differ diff --git a/src/build/stable/commands/compile/candid_and_method_meta/execute.ts b/src/build/stable/commands/compile/candid_and_method_meta/execute.ts index 52e6c302d7..27e74ea804 100644 --- a/src/build/stable/commands/compile/candid_and_method_meta/execute.ts +++ b/src/build/stable/commands/compile/candid_and_method_meta/execute.ts @@ -30,6 +30,7 @@ export async function execute( len ); const message = new TextDecoder('utf8').decode(memory); + console.info(message); }, global_timer_set: (): void => {}, @@ -63,7 +64,18 @@ export async function execute( stable64_size: (): void => {}, stable64_write: (): void => {}, time: (): bigint => 0n, - trap: (): void => {} + trap: (ptr: number, len: number): void => { + const memory = new Uint8Array( + (wasmInstance.exports.memory as any).buffer, + ptr, + len + ); + const message = new TextDecoder('utf8').decode(memory); + + console.error(message); + + process.exit(1); + } } // env: { // azle_log(ptr: number, len: number) { diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs index e9e04839c1..4176e1b894 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/benchmarking.rs @@ -1,6 +1,8 @@ use std::{cell::RefCell, error::Error}; use candid::CandidType; +use ic_cdk::api::time; +use rquickjs::Object; use crate::quickjs_with_ctx; @@ -17,12 +19,17 @@ thread_local! { pub fn record_benchmark(function_name: &str, instructions: u64) -> Result<(), Box> { quickjs_with_ctx(|ctx| { - let timestamp = ic_cdk::api::time(); + let timestamp = time(); - let method_names: rquickjs::Object = - ctx.clone().globals().get("_azleCanisterMethodNames")?; + let method_names: Object = ctx + .clone() + .globals() + .get("_azleCanisterMethodNames") + .map_err(|e| format!("Failed to get globalThis._azleCanisterMethodNames: {e}"))?; - let method_name: String = method_names.get(function_name)?; + let method_name: String = method_names.get(function_name).map_err(|e| { + format!("Failed to get globalThis._azleCanisterMethodNames[{function_name}]: {e}") + })?; BENCHMARKS_REF_CELL.with(|benchmarks_ref_cell| { let mut benchmarks = benchmarks_ref_cell.borrow_mut(); diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs index 1be5a877c0..86bdc48227 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/candid.rs @@ -1,66 +1,69 @@ +use std::{error::Error, ffi::CString, os::raw::c_char, str}; + +use ic_cdk::trap; +use rquickjs::{Context, Function, Module, Object, Runtime}; + use crate::{ - ic, quickjs_with_ctx, wasm_binary_manipulation::get_js_code, CONTEXT_REF_CELL, MODULE_NAME, + error::{handle_promise_error, quickjs_call_with_error_handling}, + ic::register, + quickjs_with_ctx, + wasm_binary_manipulation::get_js_code, + CONTEXT_REF_CELL, MODULE_NAME, }; -// TODO we might not need any of these panic hooks +type CCharPtr = *mut c_char; -// Heavily inspired by https://stackoverflow.com/a/47676844 #[no_mangle] -pub fn get_candid_and_method_meta_pointer() -> *mut std::os::raw::c_char { - std::panic::set_hook(Box::new(|panic_info| { - let msg = match panic_info.payload().downcast_ref::<&str>() { - Some(s) => *s, - None => "Unknown panic message", - }; - let location = if let Some(location) = panic_info.location() { - format!(" at {}:{}", location.file(), location.line()) - } else { - " (unknown location)".to_string() - }; - - let message = &format!("Panic occurred: {}{}", msg, location); - - ic_cdk::println!("{}", message); - })); - - let runtime = rquickjs::Runtime::new().unwrap(); - let context = rquickjs::Context::full(&runtime).unwrap(); +pub fn get_candid_and_method_meta_pointer() -> CCharPtr { + match initialize_and_get_candid() { + Ok(c_char_ptr) => c_char_ptr, + Err(error) => { + trap(&format!("Azle CandidAndMethodMetaError: {error}")); + } + } +} + +fn initialize_and_get_candid() -> Result> { + let runtime = Runtime::new()?; + let context = Context::full(&runtime)?; CONTEXT_REF_CELL.with(|context_ref_cell| { *context_ref_cell.borrow_mut() = Some(context); }); - quickjs_with_ctx(|ctx| { - ctx.clone() - .globals() - .set("_azleNodeWasmEnvironment", true) - .unwrap(); + quickjs_with_ctx(|ctx| -> Result> { + let globals = ctx.globals(); - ic::register(ctx.clone()); + globals.set("_azleNodeWasmEnvironment", true)?; - ctx.clone() - .globals() - .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) - .unwrap(); + globals.set("exports", Object::new(ctx.clone())?)?; - ctx.clone() - .globals() - .set("_azleExperimental", false) - .unwrap(); + globals.set("_azleExperimental", false)?; + + register(ctx.clone())?; let js = get_js_code(); - // TODO is there a better name for this main module? - // TODO this returns a promise...make sure we handle it appropriately - rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); + let promise = Module::evaluate(ctx.clone(), MODULE_NAME, str::from_utf8(&js)?)?; + + handle_promise_error(ctx.clone(), promise)?; + + let get_candid_and_method_meta: Function = ctx + .globals() + .get("_azleGetCandidAndMethodMeta") + .map_err(|e| format!("Failed to get globalThis._azleGetCandidAndMethodMeta: {e}"))?; - let get_candid_and_method_meta: rquickjs::Function = - ctx.globals().get("_azleGetCandidAndMethodMeta").unwrap(); + let candid_and_method_meta_js_value = + quickjs_call_with_error_handling(ctx.clone(), get_candid_and_method_meta, ())?; - let candid_and_method_meta: String = get_candid_and_method_meta.call(()).unwrap(); + let candid_and_method_meta: String = candid_and_method_meta_js_value + .as_string() + .ok_or("Failed to convert candidAndMethodMeta JS value to string")? + .to_string()?; - let c_string = std::ffi::CString::new(candid_and_method_meta).unwrap(); + let c_string = CString::new(candid_and_method_meta)?; + let c_char_ptr = c_string.into_raw(); - c_string.into_raw() + Ok(c_char_ptr) }) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs index 78e9f70558..cc009cbeee 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/chunk.rs @@ -1,7 +1,9 @@ +use ic_cdk::{api::call::call_raw128, id}; + #[allow(unused)] pub async fn chunk() { - let id = ic_cdk::id(); + let id = id(); let method = "_azle_chunk"; let args_raw = [68, 73, 68, 76, 0, 0]; // '()' pre encoded - let _ = ic_cdk::api::call::call_raw128(id, method, args_raw, 0).await; + let _ = call_raw128(id, method, args_raw, 0).await; } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/error.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/error.rs new file mode 100644 index 0000000000..57adc8494f --- /dev/null +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/error.rs @@ -0,0 +1,57 @@ +use std::error::Error; + +use ic_cdk::trap; +use rquickjs::{ + function::IntoArgs, promise::PromiseState, Ctx, Exception, Function, Promise, Value, +}; + +use crate::quickjs_with_ctx::run_event_loop; + +pub fn quickjs_call_with_error_handling<'a>( + ctx: Ctx<'a>, + function: Function<'a>, + args: impl IntoArgs<'a>, +) -> Result, Box> { + let result: Value = match function.call(args) { + Ok(value) => value, + Err(_) => trap_on_last_exception(ctx.clone())?, + }; + + // TODO we run the event loop here and also in handle_promise_error, is that a problem? + run_event_loop(ctx.clone()); + + if result.is_promise() { + let promise: Promise = result + .clone() + .into_promise() + .ok_or("Failed to convert function call return JS value to promise")?; + handle_promise_error(ctx.clone(), promise)?; + } + + Ok(result) +} + +fn trap_on_last_exception(ctx: Ctx) -> Result> { + let exception: Exception = ctx + .clone() + .catch() + .as_exception() + .ok_or("No exception found")? + .clone(); + + trap(&exception.to_string()); +} + +pub fn handle_promise_error(ctx: Ctx, promise: Promise) -> Result<(), Box> { + run_event_loop(ctx.clone()); + + match promise.state() { + PromiseState::Rejected => { + promise.result::(); + trap_on_last_exception(ctx.clone())?; + } + _ => {} + }; + + Ok(()) +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs index 444c9c540a..67c67d1c61 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/execute_method_js.rs @@ -1,35 +1,65 @@ -use crate::{benchmarking::record_benchmark, quickjs_with_ctx, WASM_DATA_REF_CELL}; +use std::error::Error; + +use ic_cdk::{ + api::{call::arg_data_raw, performance_counter}, + trap, +}; +use rquickjs::{Function, Object}; + +use crate::{ + benchmarking::record_benchmark, error::quickjs_call_with_error_handling, quickjs_with_ctx, + WASM_DATA_REF_CELL, +}; #[no_mangle] #[allow(unused)] -pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data: i32) { - let function_name = &function_index.to_string(); - let pass_arg_data = if pass_arg_data == 1 { true } else { false }; +pub extern "C" fn execute_method_js(function_index: i32, pass_arg_data_raw: i32) { + let function_name = function_index.to_string(); + let pass_arg_data = pass_arg_data_raw == 1; + + let result = execute_method_js_with_result(function_name, pass_arg_data); + + if let Err(e) = result { + trap(&format!("Azle CanisterMethodError: {}", e)); + } +} +fn execute_method_js_with_result( + function_name: String, + pass_arg_data: bool, +) -> Result<(), Box> { quickjs_with_ctx(|ctx| { - let callbacks: rquickjs::Object = ctx.clone().globals().get("_azleCallbacks").unwrap(); + let callbacks: Object = ctx + .clone() + .globals() + .get("_azleCallbacks") + .map_err(|e| format!("Failed to get globalThis._azleCallbacks: {e}"))?; - let method_callback: rquickjs::Function = callbacks.get(function_name).unwrap(); + let method_callback: Function = callbacks.get(&function_name).map_err(|e| { + format!("Failed to get globalThis._azleCallbacks[{function_name}]: {e}") + })?; let candid_args = if pass_arg_data { - ic_cdk::api::call::arg_data_raw() + arg_data_raw() } else { vec![] }; - method_callback - .call::<_, rquickjs::Undefined>((candid_args,)) - .unwrap(); - }); - - if WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| { - wasm_data_ref_cell - .borrow() - .as_ref() - .unwrap() - .record_benchmarks - }) { - let instructions = ic_cdk::api::performance_counter(1); - record_benchmark(&function_name, instructions); + quickjs_call_with_error_handling(ctx.clone(), method_callback, (candid_args,))?; + + Ok(()) + })?; + + let record_benchmarks = WASM_DATA_REF_CELL + .with(|wasm_data_ref_cell| wasm_data_ref_cell.borrow().clone()) + .as_ref() + .ok_or("could not convert wasm_data_ref_cell to ref")? + .record_benchmarks; + + if record_benchmarks { + let instructions = performance_counter(1); + record_benchmark(&function_name, instructions)?; } + + Ok(()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs index a6993b3005..8620d2fbe6 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/guards.rs @@ -1,6 +1,8 @@ +use ic_cdk::api::{caller, is_controller}; + #[allow(unused)] pub fn guard_against_non_controllers() -> Result<(), String> { - if ic_cdk::api::is_controller(&ic_cdk::api::caller()) { + if is_controller(&caller()) { return Ok(()); } return Err( diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs index be743b1e03..83fac62828 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/accept_message.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::accept_message; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || { - ic_cdk::api::call::accept_message(); - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || accept_message()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs index 18648c2133..a1978d5b89 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/arg_data_raw.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use ic_cdk::api::call::arg_data_raw; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context.clone(), move || { - TypedArray::::new(context.clone(), ic_cdk::api::call::arg_data_raw()) - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || arg_data_raw()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs index a15cb91428..2942bc460c 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/call_raw.rs @@ -1,67 +1,88 @@ -use crate::quickjs_with_ctx; -use rquickjs::{Ctx, Exception, Function, IntoJs, TypedArray}; +use std::error::Error; -pub fn get_function(ctx: Ctx) -> Function { +use candid::Principal; +use ic_cdk::{ + api::call::{call_raw128, RejectionCode}, + spawn, trap, +}; +use rquickjs::{ + Ctx, Exception, Function, IntoJs, Object, Result as QuickJsResult, TypedArray, Value, +}; + +use crate::{error::quickjs_call_with_error_handling, ic::throw_error, quickjs_with_ctx}; + +pub fn get_function(ctx: Ctx) -> QuickJsResult { Function::new( - ctx, - |promise_id: String, - canister_id_bytes: TypedArray, - method: String, - args_raw: TypedArray, - payment_string: String| { - let canister_id = candid::Principal::from_slice(canister_id_bytes.as_ref()); - let args_raw = args_raw.as_bytes().unwrap().to_vec(); - let payment: u128 = payment_string.parse().unwrap(); - - ic_cdk::spawn(async move { - let call_result = - ic_cdk::api::call::call_raw128(canister_id, &method, args_raw, payment).await; - - quickjs_with_ctx(move |ctx| { - resolve_or_reject(ctx.clone(), &call_result, &promise_id); + ctx.clone(), + move |promise_id: String, + canister_id_bytes: TypedArray, + method: String, + args_raw: TypedArray, + payment_string: String| + -> QuickJsResult<()> { + let canister_id = Principal::from_slice(canister_id_bytes.as_ref()); + let args_raw = args_raw + .as_bytes() + .ok_or(throw_error( + ctx.clone(), + "args_raw could not be converted into bytes", + ))? + .to_vec(); + let payment: u128 = payment_string + .parse() + .map_err(|e| throw_error(ctx.clone(), e))?; + + spawn(async move { + let call_result = call_raw128(canister_id, &method, args_raw, payment).await; + + let result = quickjs_with_ctx(|ctx| { + resolve_or_reject(ctx.clone(), &call_result, &promise_id)?; + + Ok(()) }); + + if let Err(e) = result { + trap(&format!("Azle CallRawError: {e}")); + } }); - rquickjs::Undefined + Ok(()) }, ) - .unwrap() } fn resolve_or_reject<'a>( ctx: Ctx<'a>, - call_result: &Result, (ic_cdk::api::call::RejectionCode, String)>, + call_result: &Result, (RejectionCode, String)>, promise_id: &str, -) { - let (should_resolve, js_value) = prepare_js_value(ctx.clone(), &call_result); - let callback = get_callback(ctx.clone(), &promise_id, should_resolve); +) -> Result<(), Box> { + let (should_resolve, js_value) = prepare_js_value(ctx.clone(), &call_result)?; + let callback = get_callback(ctx.clone(), &promise_id, should_resolve)?; + + quickjs_call_with_error_handling(ctx.clone(), callback, (js_value,))?; - callback - .call::<_, rquickjs::Undefined>((js_value,)) - .unwrap(); + Ok(()) } fn prepare_js_value<'a>( ctx: Ctx<'a>, - call_result: &Result, (ic_cdk::api::call::RejectionCode, String)>, -) -> (bool, rquickjs::Value<'a>) { + call_result: &Result, (RejectionCode, String)>, +) -> Result<(bool, Value<'a>), Box> { match call_result { Ok(candid_bytes) => { - let candid_bytes_js_value = TypedArray::::new(ctx.clone(), candid_bytes.clone()) - .into_js(&ctx) - .unwrap(); + let candid_bytes_js_value = + TypedArray::::new(ctx.clone(), candid_bytes.clone()).into_js(&ctx)?; - (true, candid_bytes_js_value) + Ok((true, candid_bytes_js_value)) } Err(err) => { let err_js_value = Exception::from_message( ctx.clone(), &format!("Rejection code {}, {}", (err.0 as i32).to_string(), err.1), ) - .into_js(&ctx) - .unwrap(); + .into_js(&ctx)?; - (false, err_js_value) + Ok((false, err_js_value)) } } } @@ -70,19 +91,23 @@ fn get_callback<'a>( ctx: Ctx<'a>, promise_id: &str, should_resolve: bool, -) -> rquickjs::Function<'a> { - let global_object = get_resolve_or_reject_global_object(ctx.clone(), should_resolve); +) -> Result, Box> { + let global_object = get_resolve_or_reject_global_object(ctx.clone(), should_resolve)?; let callback_name = get_resolve_or_reject_callback_name(&promise_id, should_resolve); - global_object.get(callback_name).unwrap() + Ok(global_object.get(callback_name)?) } -fn get_resolve_or_reject_global_object(ctx: Ctx, should_resolve: bool) -> rquickjs::Object { - let global = ctx.globals(); +fn get_resolve_or_reject_global_object( + ctx: Ctx, + should_resolve: bool, +) -> Result> { + let globals = ctx.globals(); + if should_resolve { - global.get("_azleResolveIds").unwrap() + Ok(globals.get("_azleResolveIds")?) } else { - global.get("_azleRejectIds").unwrap() + Ok(globals.get("_azleRejectIds")?) } } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs index a58cad407b..1cb32ae8fc 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/caller.rs @@ -1,8 +1,8 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use ic_cdk::api::caller; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context.clone(), move || { - TypedArray::::new(context.clone(), ic_cdk::api::caller().as_slice()) +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move || { + TypedArray::::new(ctx.clone(), caller().as_slice()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs index 2fec0196bb..9a068bf9c9 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_compiler.rs @@ -1,11 +1,15 @@ -use rquickjs::{Ctx, Function}; use std::path::Path; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |candid_path: String| { - let (env, actor) = candid_parser::pretty_check_file(Path::new(&candid_path)).unwrap(); +use candid_parser::{bindings::javascript::compile, pretty_check_file}; +use rquickjs::{Ctx, Function, Result}; - candid_parser::bindings::javascript::compile(&env, &actor) +use crate::ic::throw_error; + +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move |candid_path: String| -> Result { + let (env, actor) = + pretty_check_file(Path::new(&candid_path)).map_err(|e| throw_error(ctx.clone(), e))?; + + Ok(compile(&env, &actor)) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs index e573fbb21a..c360f33d59 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_decode.rs @@ -1,12 +1,18 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use candid::IDLArgs; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |candid_encoded: TypedArray| { - let candid_bytes = candid_encoded.as_ref(); - let candid_args: candid::IDLArgs = candid::IDLArgs::from_bytes(candid_bytes).unwrap(); - let candid_string = candid_args.to_string(); +use crate::ic::throw_error; - candid_string - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |candid_encoded: TypedArray| -> Result { + let candid_bytes = candid_encoded.as_ref(); + let candid_args: IDLArgs = + IDLArgs::from_bytes(candid_bytes).map_err(|e| throw_error(ctx.clone(), e))?; + let candid_string = candid_args.to_string(); + + Ok(candid_string) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs index 8f293ec22d..b8eb07d406 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/candid_encode.rs @@ -1,11 +1,19 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use candid_parser::parse_idl_args; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context.clone(), move |candid_string: String| { - let candid_args = candid_parser::parse_idl_args(&candid_string).unwrap(); - let candid_encoded = candid_args.to_bytes().unwrap(); +use crate::ic::throw_error; - TypedArray::::new(context.clone(), candid_encoded) - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |candid_string: String| -> Result> { + let candid_args = + parse_idl_args(&candid_string).map_err(|e| throw_error(ctx.clone(), e))?; + let candid_encoded = candid_args + .to_bytes() + .map_err(|e| throw_error(ctx.clone(), e))?; + + TypedArray::::new(ctx.clone(), candid_encoded) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs index 5f3c6fc85b..8103e9bed1 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_balance.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::canister_balance128; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::canister_balance128().to_string()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || canister_balance128().to_string()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs index adac460569..5ac5497063 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/canister_version.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::canister_version; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::canister_version()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || canister_version()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs index 1d53f6d3e9..38a37634e6 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/clear_timer.rs @@ -1,10 +1,15 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk_timers::{clear_timer, TimerId}; +use rquickjs::{Ctx, Function, Result}; +use slotmap::KeyData; -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |timer_id: String| { - ic_cdk_timers::clear_timer(ic_cdk_timers::TimerId::from(slotmap::KeyData::from_ffi( - timer_id.parse().unwrap(), +use crate::ic::throw_error; + +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move |timer_id: String| -> Result<()> { + clear_timer(TimerId::from(KeyData::from_ffi( + timer_id.parse().map_err(|e| throw_error(ctx.clone(), e))?, ))); + + Ok(()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs index e92965c240..24e542802c 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/cycles_burn.rs @@ -1,10 +1,17 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::cycles_burn; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |amount_string: String| { - let amount: u128 = amount_string.parse().unwrap(); +use crate::ic::throw_error; - ic_cdk::api::cycles_burn(amount).to_string() - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |amount_string: String| -> Result { + let amount: u128 = amount_string + .parse() + .map_err(|e| throw_error(ctx.clone(), e))?; + + Ok(cycles_burn(amount).to_string()) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs index cb76330ad7..8ef489bb93 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/data_certificate.rs @@ -1,17 +1,13 @@ -use rquickjs::{Ctx, Function, IntoJs, TypedArray}; +use ic_cdk::api::data_certificate; +use rquickjs::{Ctx, Function, IntoJs, Result, TypedArray, Undefined, Value}; -pub fn get_function(context: Ctx) -> Function { - Function::new( - context.clone(), - move || match ic_cdk::api::data_certificate() { +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move || -> Result { + match data_certificate() { Some(data_certificate_vec_u8) => { - TypedArray::::new(context.clone(), data_certificate_vec_u8) - .unwrap() - .into_js(&context) - .unwrap() + TypedArray::::new(ctx.clone(), data_certificate_vec_u8)?.into_js(&ctx) } - None => rquickjs::Undefined.into_js(&context).unwrap(), - }, - ) - .unwrap() + None => Undefined.into_js(&ctx), + } + }) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs index a97d966c03..a1ebf143d2 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/id.rs @@ -1,8 +1,8 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use ic_cdk::id; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context.clone(), move || { - TypedArray::::new(context.clone(), ic_cdk::id().as_slice()) +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move || -> Result> { + TypedArray::::new(ctx.clone(), id().as_slice()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs index 0053a016a0..4c20cd6b9d 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/instruction_counter.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::instruction_counter; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::instruction_counter()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || instruction_counter()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs index 5a08676eca..62f6aa2582 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/is_controller.rs @@ -1,10 +1,11 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use candid::Principal; +use ic_cdk::api::is_controller; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |principal_bytes: TypedArray| { - let principal = candid::Principal::from_slice(principal_bytes.as_ref()); +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |principal_bytes: TypedArray| { + let principal = Principal::from_slice(principal_bytes.as_ref()); - ic_cdk::api::is_controller(&principal) + is_controller(&principal) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs index b1ccc04776..0d3073069a 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/method_name.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::method_name; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::call::method_name()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || method_name()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs index e1fdf03216..73b31dfa25 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/mod.rs @@ -1,3 +1,7 @@ +use std::fmt::Display; + +use rquickjs::{Ctx, Error, Object, Result, String}; + mod accept_message; mod arg_data_raw; mod call_raw; @@ -41,197 +45,162 @@ mod time; mod trap; #[allow(unused)] -pub fn register(context: rquickjs::Ctx) { - let ic = rquickjs::Object::new(context.clone()).unwrap(); +pub fn register(ctx: Ctx) -> Result<()> { + let ic = Object::new(ctx.clone())?; - ic.set( - "acceptMessage", - accept_message::get_function(context.clone()), - ) - .unwrap(); + ic.set("acceptMessage", accept_message::get_function(ctx.clone()))?; - ic.set("argDataRaw", arg_data_raw::get_function(context.clone())) - .unwrap(); + ic.set("argDataRaw", arg_data_raw::get_function(ctx.clone()))?; - ic.set("callRaw", call_raw::get_function(context.clone())) - .unwrap(); + ic.set("callRaw", call_raw::get_function(ctx.clone()))?; - ic.set("caller", caller::get_function(context.clone())) - .unwrap(); + ic.set("caller", caller::get_function(ctx.clone()))?; - ic.set( - "candidCompiler", - candid_compiler::get_function(context.clone()), - ) - .unwrap(); + ic.set("candidCompiler", candid_compiler::get_function(ctx.clone()))?; - ic.set("candidDecode", candid_decode::get_function(context.clone())) - .unwrap(); + ic.set("candidDecode", candid_decode::get_function(ctx.clone()))?; - ic.set("candidEncode", candid_encode::get_function(context.clone())) - .unwrap(); + ic.set("candidEncode", candid_encode::get_function(ctx.clone()))?; ic.set( "canisterBalance", - canister_balance::get_function(context.clone()), - ) - .unwrap(); + canister_balance::get_function(ctx.clone()), + )?; ic.set( "canisterVersion", - canister_version::get_function(context.clone()), - ) - .unwrap(); + canister_version::get_function(ctx.clone()), + )?; - ic.set("clearTimer", clear_timer::get_function(context.clone())) - .unwrap(); + ic.set("clearTimer", clear_timer::get_function(ctx.clone()))?; - ic.set("cyclesBurn", cycles_burn::get_function(context.clone())) - .unwrap(); + ic.set("cyclesBurn", cycles_burn::get_function(ctx.clone()))?; ic.set( "dataCertificate", - data_certificate::get_function(context.clone()), - ) - .unwrap(); + data_certificate::get_function(ctx.clone()), + )?; - ic.set("id", id::get_function(context.clone())).unwrap(); + ic.set("id", id::get_function(ctx.clone()))?; ic.set( "instructionCounter", - instruction_counter::get_function(context.clone()), - ) - .unwrap(); + instruction_counter::get_function(ctx.clone()), + )?; - ic.set("isController", is_controller::get_function(context.clone())) - .unwrap(); + ic.set("isController", is_controller::get_function(ctx.clone()))?; - ic.set("methodName", method_name::get_function(context.clone())) - .unwrap(); + ic.set("methodName", method_name::get_function(ctx.clone()))?; ic.set( "msgCyclesAccept", - msg_cycles_accept::get_function(context.clone()), - ) - .unwrap(); + msg_cycles_accept::get_function(ctx.clone()), + )?; ic.set( "msgCyclesAvailable", - msg_cycles_available::get_function(context.clone()), - ) - .unwrap(); + msg_cycles_available::get_function(ctx.clone()), + )?; ic.set( "msgCyclesRefunded", - msg_cycles_refunded::get_function(context.clone()), - ) - .unwrap(); + msg_cycles_refunded::get_function(ctx.clone()), + )?; - ic.set("notifyRaw", notify_raw::get_function(context.clone())) - .unwrap(); + ic.set("notifyRaw", notify_raw::get_function(ctx.clone()))?; ic.set( "performanceCounter", - performance_counter::get_function(context.clone()), - ) - .unwrap(); + performance_counter::get_function(ctx.clone()), + )?; - ic.set("print", print::get_function(context.clone())) - .unwrap(); + ic.set("print", print::get_function(ctx.clone()))?; - ic.set("reject", reject::get_function(context.clone())) - .unwrap(); + ic.set("reject", reject::get_function(ctx.clone()))?; - ic.set("rejectCode", reject_code::get_function(context.clone())) - .unwrap(); + ic.set("rejectCode", reject_code::get_function(ctx.clone()))?; - ic.set( - "rejectMessage", - reject_message::get_function(context.clone()), - ) - .unwrap(); + ic.set("rejectMessage", reject_message::get_function(ctx.clone()))?; - ic.set("replyRaw", reply_raw::get_function(context.clone())) - .unwrap(); + ic.set("replyRaw", reply_raw::get_function(ctx.clone()))?; ic.set( "setCertifiedData", - set_certified_data::get_function(context.clone()), - ) - .unwrap(); + set_certified_data::get_function(ctx.clone()), + )?; - ic.set("setTimer", set_timer::get_function(context.clone())) - .unwrap(); + ic.set("setTimer", set_timer::get_function(ctx.clone()))?; ic.set( "setTimerInterval", - set_timer_interval::get_function(context.clone()), - ) - .unwrap(); + set_timer_interval::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapContainsKey", - stable_b_tree_map_contains_key::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_contains_key::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapGet", - stable_b_tree_map_get::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_get::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapInit", - stable_b_tree_map_init::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_init::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapInsert", - stable_b_tree_map_insert::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_insert::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapIsEmpty", - stable_b_tree_map_is_empty::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_is_empty::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapItems", - stable_b_tree_map_items::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_items::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapKeys", - stable_b_tree_map_keys::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_keys::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapLen", - stable_b_tree_map_len::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_len::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapRemove", - stable_b_tree_map_remove::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_remove::get_function(ctx.clone()), + )?; ic.set( "stableBTreeMapValues", - stable_b_tree_map_values::get_function(context.clone()), - ) - .unwrap(); + stable_b_tree_map_values::get_function(ctx.clone()), + )?; + + ic.set("time", time::get_function(ctx.clone()))?; - ic.set("time", time::get_function(context.clone())).unwrap(); + ic.set("trap", trap::get_function(ctx.clone()))?; - ic.set("trap", trap::get_function(context.clone())).unwrap(); + ctx.globals().set("_azleIcStable", ic)?; + + Ok(()) +} - context.clone().globals().set("_azleIcStable", ic).unwrap(); +pub fn throw_error(ctx: Ctx, error: E) -> Error { + match String::from_str(ctx.clone(), &error.to_string()) { + Ok(error_string) => { + let error_value = error_string.into(); + ctx.clone().throw(error_value) + } + Err(e) => e, + } } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs index 95bfe3b268..0ff6a37111 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_accept.rs @@ -1,10 +1,17 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::msg_cycles_accept128; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |max_amount_string: String| { - let max_amount: u128 = max_amount_string.parse().unwrap(); +use crate::ic::throw_error; - ic_cdk::api::call::msg_cycles_accept128(max_amount).to_string() - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |max_amount_string: String| -> Result { + let max_amount: u128 = max_amount_string + .parse() + .map_err(|e| throw_error(ctx.clone(), e))?; + + Ok(msg_cycles_accept128(max_amount).to_string()) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs index eaba647961..8846a4be03 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_available.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::msg_cycles_available128; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || { - ic_cdk::api::call::msg_cycles_available128().to_string() - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || msg_cycles_available128().to_string()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs index 1eaeaa9194..b19e3cf209 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/msg_cycles_refunded.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::msg_cycles_refunded128; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || { - ic_cdk::api::call::msg_cycles_refunded128().to_string() - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || msg_cycles_refunded128().to_string()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs index b05ea92c99..65eb210867 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/notify_raw.rs @@ -1,34 +1,44 @@ -use rquickjs::{Ctx, Function, IntoJs, TypedArray}; +use candid::Principal; +use ic_cdk::api::call::notify_raw; +use rquickjs::{Ctx, Exception, Function, IntoJs, Result, TypedArray, Undefined, Value}; -pub fn get_function(ctx: Ctx) -> Function { +use crate::ic::throw_error; + +pub fn get_function(ctx: Ctx) -> Result { Function::new( ctx.clone(), move |canister_id_bytes: TypedArray, method: String, args_raw: TypedArray, - payment_string: String| { - let canister_id = candid::Principal::from_slice(canister_id_bytes.as_ref()); - let args_raw = args_raw.as_bytes().unwrap().to_vec(); - let payment: u128 = payment_string.parse().unwrap(); + payment_string: String| + -> Result { + let canister_id = Principal::from_slice(canister_id_bytes.as_ref()); + let args_raw = args_raw + .as_bytes() + .ok_or(throw_error( + ctx.clone(), + "args_raw could not be converted into bytes", + ))? + .to_vec(); + let payment: u128 = payment_string + .parse() + .map_err(|e| throw_error(ctx.clone(), e))?; - let notify_result = - ic_cdk::api::call::notify_raw(canister_id, &method, &args_raw, payment); + let notify_result = notify_raw(canister_id, &method, &args_raw, payment); match notify_result { - Ok(_) => rquickjs::Undefined.into_js(&ctx).unwrap(), + Ok(_) => Undefined.into_js(&ctx), Err(err) => { let err_string = format!( "Rejection code {rejection_code}", rejection_code = (err as i32).to_string() ); - let err_js_value = rquickjs::Exception::from_message(ctx.clone(), &err_string) - .into_js(&ctx) - .unwrap(); + let err_js_value = + Exception::from_message(ctx.clone(), &err_string).into_js(&ctx)?; - err_js_value + Ok(err_js_value) } } }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs index b7af20f182..b09c2a775d 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/performance_counter.rs @@ -1,8 +1,8 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::performance_counter; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |counter_type: u32| { - ic_cdk::api::performance_counter(counter_type) +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |counter_type: u32| -> u64 { + performance_counter(counter_type) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs index f35d190399..73f63aa8f2 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/print.rs @@ -1,8 +1,8 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::print; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> rquickjs::Function { - Function::new(context, |message: String| { - ic_cdk::print(message); +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |message: String| { + print(message); }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs index a43452c82a..891aed3612 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::reject; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |message: String| { - ic_cdk::api::call::reject(&message); - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |message: String| reject(&message)) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs index 0ceb9b6d22..1a24e04e1e 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_code.rs @@ -1,20 +1,18 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::{reject_code, RejectionCode}; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || { - let reject_code = ic_cdk::api::call::reject_code(); +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || { + let reject_code = reject_code(); - let reject_code_number = match reject_code { - ic_cdk::api::call::RejectionCode::NoError => 0, - ic_cdk::api::call::RejectionCode::SysFatal => 1, - ic_cdk::api::call::RejectionCode::SysTransient => 2, - ic_cdk::api::call::RejectionCode::DestinationInvalid => 3, - ic_cdk::api::call::RejectionCode::CanisterReject => 4, - ic_cdk::api::call::RejectionCode::CanisterError => 5, - ic_cdk::api::call::RejectionCode::Unknown => 6, - }; - - reject_code_number + match reject_code { + RejectionCode::NoError => 0, + RejectionCode::SysFatal => 1, + RejectionCode::SysTransient => 2, + RejectionCode::DestinationInvalid => 3, + RejectionCode::CanisterReject => 4, + RejectionCode::CanisterError => 5, + RejectionCode::Unknown => 6, + } }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs index 5fa76ffa33..ae217c9180 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reject_message.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::reject_message; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::call::reject_message()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || reject_message()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs index 4ef5b4295d..c3a4f5cedd 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/reply_raw.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::call::reply_raw; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> rquickjs::Function { - Function::new(context, |bytes: rquickjs::TypedArray| { - ic_cdk::api::call::reply_raw(bytes.as_ref()); - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |bytes: TypedArray| reply_raw(bytes.as_ref())) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs index 94a4fb1c67..2b6bb48639 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_certified_data.rs @@ -1,8 +1,8 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::set_certified_data; +use rquickjs::{Ctx, Function, Result, TypedArray}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |bytes: rquickjs::TypedArray| { - ic_cdk::api::set_certified_data(bytes.as_ref()); +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |bytes: TypedArray| { + set_certified_data(bytes.as_ref()) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs index f675303c43..5966bbaf2e 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer.rs @@ -1,33 +1,48 @@ -use rquickjs::{Ctx, Function}; +use core::time::Duration; + +use ic_cdk::trap; +use ic_cdk_timers::{set_timer, TimerId}; +use rquickjs::{Ctx, Function, Object, Result}; use slotmap::Key; -use crate::quickjs_with_ctx; +use crate::{error::quickjs_call_with_error_handling, ic::throw_error, quickjs_with_ctx}; + +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |delay: String, callback_id: String| -> Result { + let delay: u64 = delay.parse().map_err(|e| throw_error(ctx.clone(), e))?; + let delay_duration = Duration::new(delay, 0); + + let closure = move || { + let result = quickjs_with_ctx(|ctx| { + let globals = ctx.globals(); -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |delay: String, callback_id: String| { - let delay: u64 = delay.parse().unwrap(); - let delay_duration = core::time::Duration::new(delay, 0); + let timer_callbacks: Object = + globals.get("_azleTimerCallbacks").map_err(|e| { + format!("Failed to get globalThis._azleTimerCallbacks: {e}") + })?; + let timer_callback: Function = + timer_callbacks.get(callback_id.as_str()).map_err(|e| { + format!( + "Failed to get globalThis._azleTimerCallbacks[{callback_id}]: {e}" + ) + })?; - let closure = move || { - quickjs_with_ctx(|ctx| { - let global = ctx.globals(); - let timer_callbacks = global - .get::<_, rquickjs::Object>("_azleTimerCallbacks") - .unwrap(); - let timer_callback: Function = timer_callbacks.get(callback_id.as_str()).unwrap(); + quickjs_call_with_error_handling(ctx, timer_callback, ())?; - let result = timer_callback.call::<_, rquickjs::Value>(()).unwrap(); + Ok(()) + }); - if result.is_exception() { - panic!("Timer callback threw an exception"); + if let Err(e) = result { + trap(&format!("Azle TimerError: {e}")); } - }); - }; + }; - let timer_id: ic_cdk_timers::TimerId = ic_cdk_timers::set_timer(delay_duration, closure); - let timer_id_u64: u64 = timer_id.data().as_ffi(); + let timer_id: TimerId = set_timer(delay_duration, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); - timer_id_u64 - }) - .unwrap() + Ok(timer_id_u64) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs index f79a5cf391..e1b505b5e5 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/set_timer_interval.rs @@ -1,34 +1,48 @@ -use rquickjs::{Ctx, Function}; +use core::time::Duration; + +use ic_cdk::trap; +use ic_cdk_timers::{set_timer_interval, TimerId}; +use rquickjs::{Ctx, Function, Object, Result}; use slotmap::Key; -use crate::quickjs_with_ctx; +use crate::{error::quickjs_call_with_error_handling, ic::throw_error, quickjs_with_ctx}; + +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |interval: String, callback_id: String| -> Result { + let interval: u64 = interval.parse().map_err(|e| throw_error(ctx.clone(), e))?; + let interval_duration = Duration::new(interval, 0); + + let closure = move || { + let result = quickjs_with_ctx(|ctx| { + let globals = ctx.globals(); -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |interval: String, callback_id: String| { - let interval: u64 = interval.parse().unwrap(); - let interval_duration = core::time::Duration::new(interval, 0); + let timer_callbacks: Object = + globals.get("_azleTimerCallbacks").map_err(|e| { + format!("Failed to get globalThis._azleTimerCallbacks: {e}") + })?; + let timer_callback: Function = + timer_callbacks.get(callback_id.as_str()).map_err(|e| { + format!( + "Failed to get globalThis._azleTimerCallbacks[{callback_id}]: {e}" + ) + })?; - let closure = move || { - quickjs_with_ctx(|ctx| { - let global = ctx.globals(); - let timer_callbacks = global - .get::<_, rquickjs::Object>("_azleTimerCallbacks") - .unwrap(); - let timer_callback: Function = timer_callbacks.get(callback_id.as_str()).unwrap(); + quickjs_call_with_error_handling(ctx, timer_callback, ())?; - let result = timer_callback.call::<_, rquickjs::Value>(()).unwrap(); + Ok(()) + }); - if result.is_exception() { - panic!("Timer interval callback threw an exception"); + if let Err(e) = result { + trap(&format!("Azle TimerIntervalError: {e}")); } - }); - }; + }; - let timer_id: ic_cdk_timers::TimerId = - ic_cdk_timers::set_timer_interval(interval_duration, closure); - let timer_id_u64: u64 = timer_id.data().as_ffi(); + let timer_id: TimerId = set_timer_interval(interval_duration, closure); + let timer_id_u64: u64 = timer_id.data().as_ffi(); - timer_id_u64 - }) - .unwrap() + Ok(timer_id_u64) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs index 47e307ad83..77c5810cc3 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_contains_key.rs @@ -1,17 +1,17 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -use crate::stable_b_tree_map::{AzleStableBTreeMapKey, STABLE_B_TREE_MAPS}; +use crate::stable_b_tree_map::{with_stable_b_tree_map, AzleStableBTreeMapKey}; -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |memory_id: u8, key_typed_array: TypedArray| { - let key_slice: &[u8] = key_typed_array.as_ref(); - let key: Vec = key_slice.to_vec(); +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |memory_id: u8, key_typed_array: TypedArray| -> Result { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); - STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - - stable_b_tree_maps[&memory_id].contains_key(&AzleStableBTreeMapKey { bytes: key }) - }) - }) - .unwrap() + stable_b_tree_map.contains_key(&AzleStableBTreeMapKey { bytes: key }) + }) + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs index 7a554532f8..fe4ef4c446 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_get.rs @@ -1,21 +1,20 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -use crate::stable_b_tree_map::{ - AzleStableBTreeMapKey, AzleStableBTreeMapValue, STABLE_B_TREE_MAPS, -}; +use crate::stable_b_tree_map::{with_stable_b_tree_map, AzleStableBTreeMapKey}; -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |memory_id: u8, key_typed_array: TypedArray| { - let key_slice: &[u8] = key_typed_array.as_ref(); - let key: Vec = key_slice.to_vec(); +pub fn get_function(ctx: Ctx) -> Result { + Function::new( + ctx.clone(), + move |memory_id: u8, key_typed_array: TypedArray| -> Result>> { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); - STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - - stable_b_tree_maps[&memory_id] - .get(&AzleStableBTreeMapKey { bytes: key }) - .map(|value: AzleStableBTreeMapValue| value.bytes.clone()) - }) - }) - .unwrap() + stable_b_tree_map + .get(&AzleStableBTreeMapKey { bytes: key }) + .map(|value| TypedArray::new(ctx.clone(), value.bytes)) + .transpose() + })? + }, + ) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs index 30fbbf81d2..9beaf2a74e 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_init.rs @@ -1,9 +1,9 @@ use ic_stable_structures::{memory_manager::MemoryId, StableBTreeMap}; -use rquickjs::{Ctx, Function}; +use rquickjs::{Ctx, Function, Result}; use crate::{stable_b_tree_map::STABLE_B_TREE_MAPS, MEMORY_MANAGER_REF_CELL}; -pub fn get_function(ctx: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new(ctx, |memory_id: u8| { STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); @@ -16,5 +16,4 @@ pub fn get_function(ctx: Ctx) -> Function { ); }); }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs index 79953414f4..89b555a39e 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_insert.rs @@ -1,30 +1,33 @@ -use rquickjs::{Ctx, Function, TypedArray}; +use rquickjs::{Ctx, Function, IntoJs, Result, TypedArray, Undefined, Value}; use crate::stable_b_tree_map::{ - AzleStableBTreeMapKey, AzleStableBTreeMapValue, STABLE_B_TREE_MAPS, + with_stable_b_tree_map_mut, AzleStableBTreeMapKey, AzleStableBTreeMapValue, }; -pub fn get_function(context: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new( - context, - |memory_id: u8, key_typed_array: TypedArray, value_typed_array: TypedArray| { - let key_slice: &[u8] = key_typed_array.as_ref(); - let key: Vec = key_slice.to_vec(); + ctx.clone(), + move |memory_id: u8, + key_typed_array: TypedArray, + value_typed_array: TypedArray| + -> Result { + with_stable_b_tree_map_mut(ctx.clone(), memory_id, |stable_b_tree_map| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); - let value_slice: &[u8] = value_typed_array.as_ref(); - let value: Vec = value_slice.to_vec(); + let value_slice: &[u8] = value_typed_array.as_ref(); + let value: Vec = value_slice.to_vec(); - let value_option = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); - - stable_b_tree_maps.get_mut(&memory_id).unwrap().insert( + match stable_b_tree_map.insert( AzleStableBTreeMapKey { bytes: key }, AzleStableBTreeMapValue { bytes: value }, - ) - }); - - value_option.map(|value| value.bytes) + ) { + Some(value) => { + TypedArray::::new(ctx.clone(), value.bytes.as_slice())?.into_js(&ctx) + } + None => Undefined.into_js(&ctx), + } + })? }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs index 9cef1f804a..ada2840fa1 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_is_empty.rs @@ -1,13 +1,11 @@ -use rquickjs::{Ctx, Function}; +use rquickjs::{Ctx, Function, Result}; -use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; +use crate::stable_b_tree_map::with_stable_b_tree_map; -pub fn get_function(ctx: Ctx) -> Function { - Function::new(ctx, |memory_id: u8| { - STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - stable_b_tree_maps.get(&memory_id).unwrap().is_empty() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move |memory_id: u8| -> Result { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + stable_b_tree_map.is_empty() }) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs index e0a284d577..38069bb161 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_items.rs @@ -1,31 +1,41 @@ use std::convert::TryInto; -use rquickjs::{Array, Ctx, FromIteratorJs, Function}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; +use crate::{ic::throw_error, stable_b_tree_map::with_stable_b_tree_map}; -pub fn get_function(ctx: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new( ctx.clone(), - move |memory_id: u8, start_index: u64, length: i64| { - let items: Vec>> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + move |memory_id: u8, start_index: u64, length: i64| -> Result>>> { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + let skip_amount: usize = start_index + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))?; - stable_b_tree_map + let take_amount: usize = if length == -1 { + stable_b_tree_map + .len() + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))? + } else { + length.try_into().map_err(|e| throw_error(ctx.clone(), e))? + }; + + let items: Vec>> = stable_b_tree_map .iter() - .skip(start_index.try_into().unwrap()) - .take(if length == -1 { - stable_b_tree_map.len().try_into().unwrap() - } else { - length.try_into().unwrap() + .skip(skip_amount) + .take(take_amount) + .map(|(key, value)| { + Ok(vec![ + TypedArray::new(ctx.clone(), key.bytes)?, + TypedArray::new(ctx.clone(), value.bytes)?, + ]) }) - .map(|(key, value)| vec![key.bytes, value.bytes]) - .collect() - }); + .collect::>>>>()?; - Array::from_iter_js(&ctx, items.into_iter()) + Ok(items) + })? }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs index a584f9899e..1cdca6570a 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_keys.rs @@ -1,31 +1,36 @@ use std::convert::TryInto; -use rquickjs::{Array, Ctx, FromIteratorJs, Function}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; +use crate::{ic::throw_error, stable_b_tree_map::with_stable_b_tree_map}; -pub fn get_function(ctx: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new( ctx.clone(), - move |memory_id: u8, start_index: u64, length: i64| { - let keys: Vec> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + move |memory_id: u8, start_index: u64, length: i64| -> Result>> { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + let skip_amount: usize = start_index + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))?; - stable_b_tree_map + let take_amount: usize = if length == -1 { + stable_b_tree_map + .len() + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))? + } else { + length.try_into().map_err(|e| throw_error(ctx.clone(), e))? + }; + + let keys: Vec> = stable_b_tree_map .iter() - .skip(start_index.try_into().unwrap()) - .take(if length == -1 { - stable_b_tree_map.len().try_into().unwrap() - } else { - length.try_into().unwrap() - }) - .map(|(key, _)| key.bytes) - .collect() - }); + .skip(skip_amount) + .take(take_amount) + .map(|(key, _)| TypedArray::new(ctx.clone(), key.bytes)) + .collect::>>>()?; - Array::from_iter_js(&ctx, keys.into_iter()) + Ok(keys) + })? }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs index ecd41dfeca..b30dd455bc 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_len.rs @@ -1,15 +1,11 @@ -use rquickjs::{Ctx, Function}; +use rquickjs::{Ctx, Function, Result}; -use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; +use crate::stable_b_tree_map::with_stable_b_tree_map; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |memory_id: u8| { - let len = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - stable_b_tree_maps[&memory_id].len() - }); - - len.to_string() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx.clone(), move |memory_id: u8| -> Result { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + stable_b_tree_map.len() + }) }) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs index 536d361dbc..1e40a6673c 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_remove.rs @@ -1,31 +1,22 @@ -use rquickjs::{Ctx, Function, IntoJs, TypedArray}; +use rquickjs::{Ctx, Function, IntoJs, Result, TypedArray, Undefined, Value}; -use crate::stable_b_tree_map::{AzleStableBTreeMapKey, STABLE_B_TREE_MAPS}; +use crate::stable_b_tree_map::{with_stable_b_tree_map_mut, AzleStableBTreeMapKey}; -pub fn get_function(ctx: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new( ctx.clone(), - move |memory_id: u8, key_typed_array: TypedArray| { - let key_slice: &[u8] = key_typed_array.as_ref(); - let key: Vec = key_slice.to_vec(); + move |memory_id: u8, key_typed_array: TypedArray| -> Result { + with_stable_b_tree_map_mut(ctx.clone(), memory_id, |stable_b_tree_map| { + let key_slice: &[u8] = key_typed_array.as_ref(); + let key: Vec = key_slice.to_vec(); - let value_option = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); - - stable_b_tree_maps - .get_mut(&memory_id) - .unwrap() - .remove(&AzleStableBTreeMapKey { bytes: key }) - }); - - match value_option { - Some(value) => TypedArray::::new(ctx.clone(), value.bytes.as_slice()) - .unwrap() - .into_js(&ctx) - .unwrap(), - None => rquickjs::Undefined.into_js(&ctx).unwrap(), - } + match stable_b_tree_map.remove(&AzleStableBTreeMapKey { bytes: key }) { + Some(value) => { + TypedArray::::new(ctx.clone(), value.bytes.as_slice())?.into_js(&ctx) + } + None => Undefined.into_js(&ctx), + } + })? }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs index 89ad549ad0..1f6ac906cd 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/stable_b_tree_map_values.rs @@ -1,31 +1,36 @@ use std::convert::TryInto; -use rquickjs::{Array, Ctx, FromIteratorJs, Function}; +use rquickjs::{Ctx, Function, Result, TypedArray}; -use crate::stable_b_tree_map::STABLE_B_TREE_MAPS; +use crate::{ic::throw_error, stable_b_tree_map::with_stable_b_tree_map}; -pub fn get_function(ctx: Ctx) -> Function { +pub fn get_function(ctx: Ctx) -> Result { Function::new( ctx.clone(), - move |memory_id: u8, start_index: u64, length: i64| { - let values: Vec> = STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { - let stable_b_tree_maps = stable_b_tree_maps.borrow(); - let stable_b_tree_map = &stable_b_tree_maps[&memory_id]; + move |memory_id: u8, start_index: u64, length: i64| -> Result>> { + with_stable_b_tree_map(ctx.clone(), memory_id, |stable_b_tree_map| { + let skip_amount: usize = start_index + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))?; - stable_b_tree_map + let take_amount: usize = if length == -1 { + stable_b_tree_map + .len() + .try_into() + .map_err(|e| throw_error(ctx.clone(), e))? + } else { + length.try_into().map_err(|e| throw_error(ctx.clone(), e))? + }; + + let values: Vec> = stable_b_tree_map .iter() - .skip(start_index.try_into().unwrap()) - .take(if length == -1 { - stable_b_tree_map.len().try_into().unwrap() - } else { - length.try_into().unwrap() - }) - .map(|(_, value)| value.bytes) - .collect() - }); + .skip(skip_amount) + .take(take_amount) + .map(|(_, value)| TypedArray::new(ctx.clone(), value.bytes)) + .collect::>>>()?; - Array::from_iter_js(&ctx, values.into_iter()) + Ok(values) + })? }, ) - .unwrap() } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs index 43a150f23c..ff960cb5fb 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/time.rs @@ -1,5 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::time; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, || ic_cdk::api::time()).unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, || time()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs index 572aa5719f..a67c220e13 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/ic/trap.rs @@ -1,8 +1,6 @@ -use rquickjs::{Ctx, Function}; +use ic_cdk::api::trap; +use rquickjs::{Ctx, Function, Result}; -pub fn get_function(context: Ctx) -> Function { - Function::new(context, |message: String| { - ic_cdk::api::trap(&message); - }) - .unwrap() +pub fn get_function(ctx: Ctx) -> Result { + Function::new(ctx, |message: String| trap(&message)) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs index 5c27679e0c..2f7695502f 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/init_and_post_upgrade.rs @@ -1,8 +1,15 @@ +use std::{env, error::Error, str}; + +use ic_cdk::trap; use ic_stable_structures::memory_manager::MemoryId; +use ic_wasi_polyfill::init_with_memory; +use rquickjs::{Context, Module, Object, Runtime}; use crate::{ + error::handle_promise_error, execute_method_js::execute_method_js, - ic, quickjs_with_ctx, + ic::register, + quickjs_with_ctx, wasm_binary_manipulation::{get_js_code, get_wasm_data}, CONTEXT_REF_CELL, MEMORY_MANAGER_REF_CELL, MODULE_NAME, WASM_DATA_REF_CELL, }; @@ -15,17 +22,21 @@ pub extern "C" fn init(function_index: i32, pass_arg_data: i32) { // This causes problems during Wasm binary manipulation format!("prevent init and post_upgrade optimization"); - initialize(true, function_index, pass_arg_data); + if let Err(e) = initialize(true, function_index, pass_arg_data) { + trap(&format!("Azle InitError: {}", e)); + } } #[inline(never)] #[no_mangle] pub extern "C" fn post_upgrade(function_index: i32, pass_arg_data: i32) { - initialize(false, function_index, pass_arg_data); + if let Err(e) = initialize(false, function_index, pass_arg_data) { + trap(&format!("Azle PostUpgradeError: {}", e)); + } } -fn initialize(init: bool, function_index: i32, pass_arg_data: i32) { - let wasm_data = get_wasm_data(); +fn initialize(init: bool, function_index: i32, pass_arg_data: i32) -> Result<(), Box> { + let wasm_data = get_wasm_data()?; WASM_DATA_REF_CELL.with(|wasm_data_ref_cell| { *wasm_data_ref_cell.borrow_mut() = Some(wasm_data.clone()); @@ -39,77 +50,82 @@ fn initialize(init: bool, function_index: i32, pass_arg_data: i32) { let polyfill_memory = MEMORY_MANAGER_REF_CELL.with(|manager| manager.borrow().get(MemoryId::new(254))); - ic_wasi_polyfill::init_with_memory(&[], &env_vars, polyfill_memory); + + init_with_memory(&[], &env_vars, polyfill_memory); let js = get_js_code(); - initialize_js( - std::str::from_utf8(&js).unwrap(), - init, - function_index, - pass_arg_data, - ); + initialize_js(str::from_utf8(&js)?, init, function_index, pass_arg_data)?; + + Ok(()) } -// TODO do we need all these clonse? -// TODO do not forget to deal with the event loop everywhere -pub fn initialize_js(js: &str, init: bool, function_index: i32, pass_arg_data: i32) { - let runtime = rquickjs::Runtime::new().unwrap(); - let context = rquickjs::Context::full(&runtime).unwrap(); +pub fn initialize_js( + js: &str, + init: bool, + function_index: i32, + pass_arg_data: i32, +) -> Result<(), Box> { + let runtime = Runtime::new()?; + let context = Context::full(&runtime)?; CONTEXT_REF_CELL.with(|context_ref_cell| { *context_ref_cell.borrow_mut() = Some(context); }); - quickjs_with_ctx(|ctx| { - ctx.clone() - .globals() - .set("_azleNodeWasmEnvironment", false) - .unwrap(); + quickjs_with_ctx(|ctx| -> Result<(), Box> { + let globals = ctx.globals(); + + let env = Object::new(ctx.clone())?; + + for (key, value) in env::vars() { + env.set(key, value)?; + } + + let process = Object::new(ctx.clone())?; + + process.set("env", env)?; + + globals.set("process", process)?; - ic::register(ctx.clone()); + globals.set("_azleNodeWasmEnvironment", false)?; - let env = rquickjs::Object::new(ctx.clone()).unwrap(); + globals.set("exports", Object::new(ctx.clone())?)?; - for (key, value) in std::env::vars() { - env.set(key, value).unwrap(); + globals.set("_azleExperimental", false)?; + + if init { + globals.set("_azleInitCalled", true)?; + globals.set("_azlePostUpgradeCalled", false)?; + } else { + globals.set("_azleInitCalled", false)?; + globals.set("_azlePostUpgradeCalled", true)?; } - let process = rquickjs::Object::new(ctx.clone()).unwrap(); + let record_benchmarks = WASM_DATA_REF_CELL + .with(|wasm_data_ref_cell| wasm_data_ref_cell.borrow().clone()) + .as_ref() + .ok_or("could not convert wasm_data_ref_cell to ref")? + .record_benchmarks; - process.set("env", env).unwrap(); + globals.set("_azleRecordBenchmarks", record_benchmarks)?; - ctx.clone().globals().set("process", process).unwrap(); + register(ctx.clone())?; - ctx.clone() - .globals() - .set("exports", rquickjs::Object::new(ctx.clone()).unwrap()) - .unwrap(); + let promise = Module::evaluate(ctx.clone(), MODULE_NAME, js)?; - ctx.clone() - .globals() - .set("_azleExperimental", false) - .unwrap(); + handle_promise_error(ctx.clone(), promise)?; - // TODO is there a better name for this main module? - // TODO this returns a promise...make sure we handle it appropriately - rquickjs::Module::evaluate(ctx.clone(), MODULE_NAME, js).unwrap(); - }); + Ok(()) + })?; + + execute_developer_init_or_post_upgrade(function_index, pass_arg_data); + + Ok(()) +} - // TODO is it possible to just put this all in the same quickjs_with_ctx? +fn execute_developer_init_or_post_upgrade(function_index: i32, pass_arg_data: i32) { if function_index != -1 { execute_method_js(function_index, pass_arg_data); } - - // _azleInitCalled and _azlePostUpgradeCalled refer to Azle's own init/post_upgrade methods being called - // these variables do not indicate if the developer's own init/post_upgrade methods were called - quickjs_with_ctx(|ctx| { - let assignment = if init { - "globalThis._azleInitCalled = true;" - } else { - "globalThis._azlePostUpgradeCalled = true;" - }; - - ctx.eval::<(), _>(assignment).unwrap(); - }); } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs index f801ba0101..27f98508ad 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/lib.rs @@ -1,19 +1,19 @@ -// TODO the plan is to integrate rquickjs for stable -// TODO and at that time create two crates -// TODO we should place each crate at src/build/stable/commands/compile/rust -// TODO and src/build/experimental/commands/compile/rust respectively - use std::cell::RefCell; -// #[allow(unused)] +use benchmarking::{BenchmarkEntry, BENCHMARKS_REF_CELL}; +use guards::guard_against_non_controllers; use ic_stable_structures::{ memory_manager::{MemoryManager, VirtualMemory}, DefaultMemoryImpl, }; +use quickjs_with_ctx::quickjs_with_ctx; +use rquickjs::Context; +use wasm_binary_manipulation::WasmData; mod benchmarking; mod candid; mod chunk; +mod error; mod execute_method_js; mod guards; mod ic; @@ -22,25 +22,23 @@ mod quickjs_with_ctx; mod stable_b_tree_map; mod wasm_binary_manipulation; -use guards::guard_against_non_controllers; -pub use quickjs_with_ctx::quickjs_with_ctx; - -const MODULE_NAME: &str = "main"; +// TODO dynamically get the canister name +// TODO send it in through the Wasm meta data +const MODULE_NAME: &str = ".azle/[canister_name]/main.js"; #[allow(unused)] type Memory = VirtualMemory; thread_local! { - static CONTEXT_REF_CELL: RefCell> = RefCell::new(None); + static CONTEXT_REF_CELL: RefCell> = RefCell::new(None); pub static MEMORY_MANAGER_REF_CELL: RefCell> = RefCell::new(MemoryManager::init(DefaultMemoryImpl::default())); - static WASM_DATA_REF_CELL: RefCell> = RefCell::new(None); + static WASM_DATA_REF_CELL: RefCell> = RefCell::new(None); } #[ic_cdk_macros::update] pub fn _azle_chunk() {} #[ic_cdk_macros::query(guard = guard_against_non_controllers)] -pub fn _azle_get_benchmarks() -> Vec { - benchmarking::BENCHMARKS_REF_CELL - .with(|benchmarks_ref_cell| benchmarks_ref_cell.borrow().clone()) +pub fn _azle_get_benchmarks() -> Vec { + BENCHMARKS_REF_CELL.with(|benchmarks_ref_cell| benchmarks_ref_cell.borrow().clone()) } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs index 9f5c999062..9a6b5f5f8f 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/quickjs_with_ctx.rs @@ -1,30 +1,30 @@ -use crate::CONTEXT_REF_CELL; +use std::error::Error; + use rquickjs::Ctx; -pub fn quickjs_with_ctx(callback: F) -> R +use crate::CONTEXT_REF_CELL; + +pub fn quickjs_with_ctx(callback: F) -> Result> where - F: FnOnce(Ctx) -> R, + F: FnOnce(Ctx) -> Result>, { CONTEXT_REF_CELL.with(|context_ref_cell| { let context_ref = context_ref_cell.borrow(); - let context = context_ref.as_ref().unwrap(); + let context = context_ref + .as_ref() + .ok_or("QuickJS context not initialized")?; context.with(|ctx| { - let result = callback(ctx.clone()); + let result = callback(ctx.clone()) + .map_err(|e| format!("QuickJS callback execution failed: {e}"))?; run_event_loop(ctx); - result + Ok(result) }) }) } -fn run_event_loop(ctx: rquickjs::Ctx) { - loop { - let result = ctx.execute_pending_job(); - - if result == false { - break; - } - } +pub fn run_event_loop(ctx: Ctx) { + while ctx.execute_pending_job() {} } diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs index 705b045999..2aa5288767 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/stable_b_tree_map.rs @@ -1,11 +1,13 @@ -use std::{cell::RefCell, collections::BTreeMap}; +use std::{borrow::Cow, cell::RefCell, collections::BTreeMap}; use ic_stable_structures::{storable::Bound, StableBTreeMap, Storable}; +use rquickjs::{Ctx, Result}; -use crate::Memory; +use crate::{ic::throw_error, Memory}; #[allow(unused)] -type AzleStableBTreeMap = StableBTreeMap; +pub type AzleStableBTreeMap = + StableBTreeMap; thread_local! { pub static STABLE_B_TREE_MAPS: RefCell> = RefCell::new(BTreeMap::new()); @@ -17,11 +19,11 @@ pub struct AzleStableBTreeMapKey { } impl Storable for AzleStableBTreeMapKey { - fn to_bytes(&self) -> std::borrow::Cow<[u8]> { - std::borrow::Cow::Borrowed(&self.bytes) + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Borrowed(&self.bytes) } - fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { + fn from_bytes(bytes: Cow<[u8]>) -> Self { AzleStableBTreeMapKey { bytes: bytes.to_vec(), } @@ -36,11 +38,11 @@ pub struct AzleStableBTreeMapValue { } impl Storable for AzleStableBTreeMapValue { - fn to_bytes(&self) -> std::borrow::Cow<[u8]> { - std::borrow::Cow::Borrowed(&self.bytes) + fn to_bytes(&self) -> Cow<[u8]> { + Cow::Borrowed(&self.bytes) } - fn from_bytes(bytes: std::borrow::Cow<[u8]>) -> Self { + fn from_bytes(bytes: Cow<[u8]>) -> Self { AzleStableBTreeMapValue { bytes: bytes.to_vec(), } @@ -48,3 +50,35 @@ impl Storable for AzleStableBTreeMapValue { const BOUND: Bound = Bound::Unbounded; } + +pub fn with_stable_b_tree_map(ctx: Ctx, memory_id: u8, f: F) -> Result +where + F: FnOnce(&AzleStableBTreeMap) -> R, +{ + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let stable_b_tree_maps = stable_b_tree_maps.borrow(); + + let stable_b_tree_map = stable_b_tree_maps.get(&memory_id).ok_or(throw_error( + ctx, + &format!("Could not find StableBTreeMap with memory id {memory_id}"), + ))?; + + Ok(f(stable_b_tree_map)) + }) +} + +pub fn with_stable_b_tree_map_mut(ctx: Ctx, memory_id: u8, f: F) -> Result +where + F: FnOnce(&mut AzleStableBTreeMap) -> R, +{ + STABLE_B_TREE_MAPS.with(|stable_b_tree_maps| { + let mut stable_b_tree_maps = stable_b_tree_maps.borrow_mut(); + + let stable_b_tree_map = stable_b_tree_maps.get_mut(&memory_id).ok_or(throw_error( + ctx, + &format!("Could not find StableBTreeMap with memory id {memory_id}"), + ))?; + + Ok(f(stable_b_tree_map)) + }) +} diff --git a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs index 158db8a844..c844943705 100644 --- a/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs +++ b/src/build/stable/commands/compile/wasm_binary/rust/stable_canister_template/src/wasm_binary_manipulation.rs @@ -1,4 +1,7 @@ +use std::{env, error::Error, str}; + use serde::{Deserialize, Serialize}; +use serde_json; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct WasmData { @@ -11,15 +14,15 @@ pub struct WasmData { #[inline(never)] #[no_mangle] extern "C" fn init_js_passive_data(js_vec_location: i32) -> usize { - "123_456_789".parse::().unwrap() + js_vec_location as usize // TODO must be like this for weird optimization reasons + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + env::var("init_js_passive_data").map_or(0, |s| s.len()) + js_vec_location as usize } -// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called -// TODO hopefully there's a less hacky way to do this #[inline(never)] #[no_mangle] extern "C" fn js_passive_data_size() -> usize { - "123_456_789".parse().unwrap() + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + env::var("js_passive_data_size").map_or(0, |s| s.len()) } // TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs @@ -36,24 +39,38 @@ pub fn get_js_code() -> Vec { #[inline(never)] #[no_mangle] extern "C" fn init_wasm_data_passive_data(wasm_data_vec_location: i32) -> usize { - "123_456_789".parse::().unwrap() + wasm_data_vec_location as usize // TODO must be like this for weird optimization reasons + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + env::var("init_wasm_data_passive_data").map_or(0, |s| s.len()) + wasm_data_vec_location as usize } -// TODO seems we need to do this to stop the compiler from hard-coding the result of this function where it is called -// TODO hopefully there's a less hacky way to do this #[inline(never)] #[no_mangle] extern "C" fn wasm_data_passive_data_size() -> usize { - "123_456_789".parse().unwrap() + // This is to prevent compiler optimizations that interfere with the Wasm binary manipulation + env::var("wasm_data_passive_data_size").map_or(0, |s| s.len()) } // TODO waiting on license inspired from https://github.com/adambratschikaye/wasm-inject-data/blob/main/src/static_wasm.rs -pub fn get_wasm_data() -> WasmData { +pub fn get_wasm_data() -> Result> { let size = wasm_data_passive_data_size(); let mut wasm_data_vec = vec![243; size]; let wasm_data_vec_location = wasm_data_vec.as_mut_ptr() as i32; init_wasm_data_passive_data(wasm_data_vec_location); - serde_json::from_str(std::str::from_utf8(&wasm_data_vec).unwrap()).unwrap() + let wasm_data_str = str::from_utf8(&wasm_data_vec).map_err(|e| { + format!( + "WasmData conversion failed while converting Vec to String: {}", + e + ) + })?; + + let wasm_data: WasmData = serde_json::from_str(wasm_data_str).map_err(|e| { + format!( + "WasmData conversion failed while converting String to WasmData struct: {}", + e + ) + })?; + + Ok(wasm_data) } diff --git a/src/lib/stable/canister_methods/heartbeat.ts b/src/lib/stable/canister_methods/heartbeat.ts index 5ebd24db31..80c40fe044 100644 --- a/src/lib/stable/canister_methods/heartbeat.ts +++ b/src/lib/stable/canister_methods/heartbeat.ts @@ -1,4 +1,5 @@ import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function heartbeat( originalMethod: (this: This, ...args: Args) => Return, @@ -13,14 +14,18 @@ export function heartbeat( index }; - globalThis._azleCallbacks[indexString] = (): void => { - executeAndReplyWithCandidSerde( - 'heartbeat', - [], - originalMethod.bind(globalThis._azleCanisterClassInstance), - [], - undefined, - false - ); + globalThis._azleCallbacks[indexString] = async (): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'heartbeat', + [], + originalMethod.bind(globalThis._azleCanisterClassInstance), + [], + undefined, + false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; } diff --git a/src/lib/stable/canister_methods/init.ts b/src/lib/stable/canister_methods/init.ts index 727d24014b..3a3936d64b 100644 --- a/src/lib/stable/canister_methods/init.ts +++ b/src/lib/stable/canister_methods/init.ts @@ -1,6 +1,7 @@ import { IDL } from '@dfinity/candid'; import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function init( paramIdlTypes: IDL.Type[] @@ -22,15 +23,21 @@ export function init( IDL.Func(paramIdlTypes, [], ['init']) ); - globalThis._azleCallbacks[indexString] = (...args: any[]): void => { - executeAndReplyWithCandidSerde( - 'init', - args, - originalMethod.bind(globalThis._azleCanisterClassInstance), - paramIdlTypes, - undefined, - false - ); + globalThis._azleCallbacks[indexString] = async ( + ...args: any[] + ): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'init', + args, + originalMethod.bind(globalThis._azleCanisterClassInstance), + paramIdlTypes, + undefined, + false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; }; } diff --git a/src/lib/stable/canister_methods/inspect_message.ts b/src/lib/stable/canister_methods/inspect_message.ts index 69300bfc9e..0366cf08b5 100644 --- a/src/lib/stable/canister_methods/inspect_message.ts +++ b/src/lib/stable/canister_methods/inspect_message.ts @@ -1,4 +1,5 @@ import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; // TODO explain here in a jsdoc that the dev can get the raw args using argDataRaw export function inspectMessage( @@ -14,14 +15,18 @@ export function inspectMessage( index }; - globalThis._azleCallbacks[indexString] = (): void => { - executeAndReplyWithCandidSerde( - 'inspectMessage', - [], - originalMethod.bind(globalThis._azleCanisterClassInstance), - [], - undefined, - false - ); + globalThis._azleCallbacks[indexString] = async (): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'inspectMessage', + [], + originalMethod.bind(globalThis._azleCanisterClassInstance), + [], + undefined, + false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; } diff --git a/src/lib/stable/canister_methods/post_upgrade.ts b/src/lib/stable/canister_methods/post_upgrade.ts index ee1cdc5615..07074acf23 100644 --- a/src/lib/stable/canister_methods/post_upgrade.ts +++ b/src/lib/stable/canister_methods/post_upgrade.ts @@ -1,6 +1,7 @@ import { IDL } from '@dfinity/candid'; import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function postUpgrade( paramIdlTypes: IDL.Type[] @@ -22,15 +23,21 @@ export function postUpgrade( IDL.Func(paramIdlTypes, [], ['post_upgrade']) ); - globalThis._azleCallbacks[indexString] = (...args: any[]): void => { - executeAndReplyWithCandidSerde( - 'postUpgrade', - args, - originalMethod.bind(globalThis._azleCanisterClassInstance), - paramIdlTypes, - undefined, - false - ); + globalThis._azleCallbacks[indexString] = async ( + ...args: any[] + ): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'postUpgrade', + args, + originalMethod.bind(globalThis._azleCanisterClassInstance), + paramIdlTypes, + undefined, + false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; }; } diff --git a/src/lib/stable/canister_methods/pre_upgrade.ts b/src/lib/stable/canister_methods/pre_upgrade.ts index 265e5e1335..3b28ba5857 100644 --- a/src/lib/stable/canister_methods/pre_upgrade.ts +++ b/src/lib/stable/canister_methods/pre_upgrade.ts @@ -1,4 +1,5 @@ import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function preUpgrade( originalMethod: (this: This, ...args: Args) => Return, @@ -13,14 +14,18 @@ export function preUpgrade( index }; - globalThis._azleCallbacks[indexString] = (): void => { - executeAndReplyWithCandidSerde( - 'preUpgrade', - [], - originalMethod.bind(globalThis._azleCanisterClassInstance), - [], - undefined, - false - ); + globalThis._azleCallbacks[indexString] = async (): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'preUpgrade', + [], + originalMethod.bind(globalThis._azleCanisterClassInstance), + [], + undefined, + false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; } diff --git a/src/lib/stable/canister_methods/query.ts b/src/lib/stable/canister_methods/query.ts index 90cf703f2d..4de3dbbd89 100644 --- a/src/lib/stable/canister_methods/query.ts +++ b/src/lib/stable/canister_methods/query.ts @@ -1,6 +1,7 @@ import { IDL } from '@dfinity/candid'; import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function query( paramIdlTypes: IDL.Type[], @@ -31,15 +32,21 @@ export function query( ['query'] ); - globalThis._azleCallbacks[indexString] = (...args: any[]): void => { - executeAndReplyWithCandidSerde( - 'query', - args, - originalMethod.bind(globalThis._azleCanisterClassInstance), - paramIdlTypes, - returnIdlType, - options?.manual ?? false - ); + globalThis._azleCallbacks[indexString] = async ( + ...args: any[] + ): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'query', + args, + originalMethod.bind(globalThis._azleCanisterClassInstance), + paramIdlTypes, + returnIdlType, + options?.manual ?? false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; }; } diff --git a/src/lib/stable/canister_methods/update.ts b/src/lib/stable/canister_methods/update.ts index 73b56d377d..9fdcdfa37e 100644 --- a/src/lib/stable/canister_methods/update.ts +++ b/src/lib/stable/canister_methods/update.ts @@ -1,6 +1,7 @@ import { IDL } from '@dfinity/candid'; import { executeAndReplyWithCandidSerde } from '../execute_with_candid_serde'; +import { trap } from '../ic_apis'; export function update( paramIdlTypes: IDL.Type[], @@ -23,15 +24,21 @@ export function update( returnIdlType === undefined ? [] : [returnIdlType] ); - globalThis._azleCallbacks[indexString] = (...args: any[]): void => { - executeAndReplyWithCandidSerde( - 'update', - args, - originalMethod.bind(globalThis._azleCanisterClassInstance), - paramIdlTypes, - returnIdlType, - options?.manual ?? false - ); + globalThis._azleCallbacks[indexString] = async ( + ...args: any[] + ): Promise => { + try { + await executeAndReplyWithCandidSerde( + 'update', + args, + originalMethod.bind(globalThis._azleCanisterClassInstance), + paramIdlTypes, + returnIdlType, + options?.manual ?? false + ); + } catch (error: any) { + trap(`Uncaught Error: ${error.toString()}`); + } }; }; } diff --git a/src/lib/stable/error.ts b/src/lib/stable/error.ts deleted file mode 100644 index af5f48c9da..0000000000 --- a/src/lib/stable/error.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import { trap } from './ic_apis/trap'; // TODO why does this break bitcoin_psbt examples? https://github.com/demergent-labs/azle/issues/2003 -import { trap } from '.'; - -export function handleUncaughtError(rawError: any): never { - const error = rawError instanceof Error ? rawError : new Error(rawError); - - const azleError = `Uncaught ${error.name}: ${error.message}${error.stack}`; - - trap(azleError); -} diff --git a/src/lib/stable/execute_with_candid_serde.ts b/src/lib/stable/execute_with_candid_serde.ts index 8f1f6631c7..5fd0d5fe31 100644 --- a/src/lib/stable/execute_with_candid_serde.ts +++ b/src/lib/stable/execute_with_candid_serde.ts @@ -1,7 +1,6 @@ import { IDL, JsonValue } from '@dfinity/candid'; -import { handleUncaughtError } from './error'; -import { reply, trap } from './ic_apis'; +import { reply } from './ic_apis'; type CanisterMethodMode = | 'query' @@ -20,13 +19,9 @@ export async function executeAndReplyWithCandidSerde( returnIdlType: IDL.Type | undefined, manual: boolean ): Promise { - try { - const decodedArgs = decodeArgs(mode, args, paramIdlTypes); - const unencodedResult = await getUnencodedResult(decodedArgs, callback); - encodeResultAndReply(mode, manual, unencodedResult, returnIdlType); - } catch (error: any) { - trap(error.toString()); - } + const decodedArgs = decodeArgs(mode, args, paramIdlTypes); + const unencodedResult = await getUnencodedResult(decodedArgs, callback); + encodeResultAndReply(mode, manual, unencodedResult, returnIdlType); } function decodeArgs( @@ -50,11 +45,7 @@ async function getUnencodedResult( args: JsonValue[], callback: (...args: any) => any ): Promise { - try { - return await callback(...args); - } catch (error) { - handleUncaughtError(error); - } + return await callback(...args); } function encodeResultAndReply( diff --git a/tests/end_to_end/candid_rpc/class_syntax/cross_canister_calls/benchmarks.md b/tests/end_to_end/candid_rpc/class_syntax/cross_canister_calls/benchmarks.md index cdf6f48d90..1b1bb55226 100644 --- a/tests/end_to_end/candid_rpc/class_syntax/cross_canister_calls/benchmarks.md +++ b/tests/end_to_end/candid_rpc/class_syntax/cross_canister_calls/benchmarks.md @@ -20,21 +20,31 @@ ## Baseline benchmarks Azle version: 0.25.0 -| Id | Method Name | Instructions | Cycles | USD | USD/Million Calls | +<<<<<<< HEAD +No benchmarks reported + +## Baseline benchmarks Azle version: 0.25.0 + +======= +| Id | Method Name | Instructions | Cycles | USD | USD/Million Calls | | --- | ---------------- | ------------ | --------- | ------------- | ----------------- | -| 0 | balance | 2_296_025 | 1_508_410 | $0.0000020057 | $2.00 | -| 1 | account | 3_635_289 | 2_044_115 | $0.0000027180 | $2.71 | -| 2 | balance | 2_217_840 | 1_477_136 | $0.0000019641 | $1.96 | -| 3 | account | 3_613_420 | 2_035_368 | $0.0000027064 | $2.70 | -| 4 | accounts | 1_653_154 | 1_251_261 | $0.0000016638 | $1.66 | -| 5 | transfer | 3_562_571 | 2_015_028 | $0.0000026793 | $2.67 | -| 6 | balance | 2_213_914 | 1_475_565 | $0.0000019620 | $1.96 | -| 7 | account | 3_605_228 | 2_032_091 | $0.0000027020 | $2.70 | -| 8 | balance | 2_211_079 | 1_474_431 | $0.0000019605 | $1.96 | -| 9 | account | 3_609_636 | 2_033_854 | $0.0000027044 | $2.70 | -| 10 | accounts | 1_651_452 | 1_250_580 | $0.0000016629 | $1.66 | -| 11 | trap | 1_622_561 | 1_239_024 | $0.0000016475 | $1.64 | -| 12 | sendNotification | 2_655_331 | 1_652_132 | $0.0000021968 | $2.19 | +| 0 | balance | 2_296_025 | 1_508_410 | $0.0000020057 | $2.00 | +| 1 | account | 3_635_289 | 2_044_115 | $0.0000027180 | $2.71 | +| 2 | balance | 2_217_840 | 1_477_136 | $0.0000019641 | $1.96 | +| 3 | account | 3_613_420 | 2_035_368 | $0.0000027064 | $2.70 | +| 4 | accounts | 1_653_154 | 1_251_261 | $0.0000016638 | $1.66 | +| 5 | transfer | 3_562_571 | 2_015_028 | $0.0000026793 | $2.67 | +| 6 | balance | 2_213_914 | 1_475_565 | $0.0000019620 | $1.96 | +| 7 | account | 3_605_228 | 2_032_091 | $0.0000027020 | $2.70 | +| 8 | balance | 2_211_079 | 1_474_431 | $0.0000019605 | $1.96 | +| 9 | account | 3_609_636 | 2_033_854 | $0.0000027044 | $2.70 | +| 10 | accounts | 1_651_452 | 1_250_580 | $0.0000016629 | $1.66 | +| 11 | trap | 1_622_561 | 1_239_024 | $0.0000016475 | $1.64 | +| 12 | sendNotification | 2_655_331 | 1_652_132 | $0.0000021968 | $2.19 | + +> > > > > > > b1592ee660f8960b25c7f11a791c3684f9eb7ba3 + +No benchmarks reported # Benchmarks for canister2 @@ -52,6 +62,8 @@ | 0 | transfer | 2_157_380 | 1_452_952 | $0.0000019319 | $1.93 | | 1 | receiveNotification | 1_383_243 | 1_143_297 | $0.0000015202 | $1.52 | +No benchmarks reported + --- **Note on calculations:** diff --git a/tests/end_to_end/candid_rpc/class_syntax/primitive_types/src/index.ts b/tests/end_to_end/candid_rpc/class_syntax/primitive_types/src/index.ts index 4b38ba3309..4bf3187471 100644 --- a/tests/end_to_end/candid_rpc/class_syntax/primitive_types/src/index.ts +++ b/tests/end_to_end/candid_rpc/class_syntax/primitive_types/src/index.ts @@ -214,6 +214,7 @@ export default class { getEmpty(): never { throw 'Anything you want'; } + // Note: It is impossible to call this function because it requires an argument // but there is no way to pass an "empty" value as an argument. @query([IDL.Empty], IDL.Empty) diff --git a/tests/end_to_end/candid_rpc/functional_syntax/cross_canister_calls/test/tests.ts b/tests/end_to_end/candid_rpc/functional_syntax/cross_canister_calls/test/tests.ts index 61aeaaf8ba..90364cfdb6 100644 --- a/tests/end_to_end/candid_rpc/functional_syntax/cross_canister_calls/test/tests.ts +++ b/tests/end_to_end/candid_rpc/functional_syntax/cross_canister_calls/test/tests.ts @@ -103,7 +103,7 @@ export function getTests( const canister1Id = getCanisterId('canister1'); const canister2Id = getCanisterId('canister2'); const partialErrorMessage = new RegExp( - `Error from Canister ${canister1Id}: Canister called \`ic0.trap\` with message: Uncaught Error: Rejection code 5, IC0503: Error from Canister ${canister2Id}: Canister called \`ic0.trap\` with message: hahahaha` + `Error from Canister ${canister1Id}: Canister called \`ic0.trap\` with message: Uncaught Error: Error: Rejection code 5, IC0503: Error from Canister ${canister2Id}: Canister called \`ic0.trap\` with message: hahahaha` ); await expect(canister1.trap()).rejects.toThrow(partialErrorMessage);