diff --git a/Cargo.lock b/Cargo.lock index f2be80f9c2..474e1f7b2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6344,6 +6344,7 @@ dependencies = [ name = "moveos-wasm" version = "0.1.0" dependencies = [ + "anyhow", "ciborium", "once_cell", "rand 0.8.5", diff --git a/crates/rooch-framework-tests/src/tests/transaction_validator_tests.rs b/crates/rooch-framework-tests/src/tests/transaction_validator_tests.rs index c8e535b2f5..fe77887a3f 100644 --- a/crates/rooch-framework-tests/src/tests/transaction_validator_tests.rs +++ b/crates/rooch-framework-tests/src/tests/transaction_validator_tests.rs @@ -32,7 +32,8 @@ fn test_session_key_rooch() { ROOCH_FRAMEWORK_ADDRESS, Empty::MODULE_NAME.as_str(), Empty::EMPTY_FUNCTION_NAME.as_str(), - ); + ) + .unwrap(); let max_inactive_interval = 100; let action = rooch_types::framework::session_key::SessionKeyModule::create_session_key_action( session_auth_key.as_ref().to_vec(), diff --git a/crates/rooch-types/src/framework/session_key.rs b/crates/rooch-types/src/framework/session_key.rs index 9a697ac89b..de712e28d6 100644 --- a/crates/rooch-types/src/framework/session_key.rs +++ b/crates/rooch-types/src/framework/session_key.rs @@ -30,12 +30,18 @@ pub struct SessionScope { } impl SessionScope { - pub fn new(module_address: AccountAddress, module_name: &str, function_name: &str) -> Self { - Self { + pub fn new( + module_address: AccountAddress, + module_name: &str, + function_name: &str, + ) -> Result { + let module_name_value = MoveAsciiString::from_str(module_name)?; + let function_name_value = MoveAsciiString::from_str(function_name)?; + Ok(Self { module_address, - module_name: MoveAsciiString::from_str(module_name).expect("invalid module name"), - function_name: MoveAsciiString::from_str(function_name).expect("invalid function name"), - } + module_name: module_name_value, + function_name: function_name_value, + }) } fn is_asterisk(s: &MoveAsciiString) -> bool { @@ -104,7 +110,7 @@ impl FromStr for SessionScope { let function_name = parts .next() .ok_or(anyhow::anyhow!("invalid session scope"))?; - Ok(Self::new(module_address, module_name, function_name)) + Self::new(module_address, module_name, function_name) } } diff --git a/frameworks/bitcoin-move/src/natives/ord/bitseed.rs b/frameworks/bitcoin-move/src/natives/ord/bitseed.rs index bea171cc3e..a1b37ee9af 100644 --- a/frameworks/bitcoin-move/src/natives/ord/bitseed.rs +++ b/frameworks/bitcoin-move/src/natives/ord/bitseed.rs @@ -14,6 +14,7 @@ use move_vm_types::values::Value; use smallvec::smallvec; use moveos_stdlib::natives::helpers::{make_module_natives, make_native}; +use moveos_stdlib::natives::moveos_stdlib::wasm::E_CBOR_MARSHAL_FAILED; #[derive(Debug, Clone)] pub struct ArgsPackingGasParameters { @@ -77,7 +78,10 @@ pub fn native_pack_inscribe_generate_args( )); let mut top_buffer = Vec::new(); - ciborium::into_writer(&ciborium::Value::Map(cbor_buffer_map_pair), &mut top_buffer).expect(""); + match ciborium::into_writer(&ciborium::Value::Map(cbor_buffer_map_pair), &mut top_buffer) { + Ok(_) => {} + Err(_) => return Ok(NativeResult::err(gas_params.base, E_CBOR_MARSHAL_FAILED)), + } let mut cost = gas_params.base; let total_length = user_input_key.len() diff --git a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/wasm.rs b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/wasm.rs index 9f47e4ed0e..5bb3d1d5aa 100644 --- a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/wasm.rs +++ b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/wasm.rs @@ -37,6 +37,10 @@ pub const E_VALUE_NOT_I32: u64 = 11; pub const E_MEMORY_NOT_FOUND: u64 = 12; pub const E_INCORRECT_LENGTH_OF_ARGS: u64 = 13; pub const E_CBOR_UNMARSHAL_FAILED: u64 = 14; +pub const E_GET_INSTANCE_POOL_FAILED: u64 = 15; +pub const E_UNPACK_STRUCT_FAILED: u64 = 16; +pub const E_WASM_INSTANCE_CREATION_FAILED: u64 = 17; +pub const E_WASM_REMOVE_INSTANCE_FAILED: u64 = 18; #[derive(Debug, Clone)] pub struct WASMCreateInstanceGasParameters { @@ -61,9 +65,31 @@ fn native_create_wasm_instance( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 1 { + return Ok(NativeResult::err( + gas_params.base_create_instance, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } let wasm_bytes = pop_arg!(args, Vec); - let wasm_instance = create_wasm_instance(&wasm_bytes); - let instance_id = insert_wasm_instance(wasm_instance); + let wasm_instance = match create_wasm_instance(&wasm_bytes) { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base_create_instance, + E_WASM_INSTANCE_CREATION_FAILED, + )) + } + }; + let instance_id = match insert_wasm_instance(wasm_instance) { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base_create_instance, + E_WASM_INSTANCE_CREATION_FAILED, + )) + } + }; let mut cost = gas_params.base_create_instance; cost += gas_params.per_byte_instance * NumBytes::new(wasm_bytes.len() as u64); @@ -97,6 +123,13 @@ fn native_create_cbor_values( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 1 { + return Ok(NativeResult::err( + gas_params.base, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let value_list = pop_arg!(args, Vec); let mut func_args = Vec::new(); @@ -179,6 +212,13 @@ fn native_add_length_with_data( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 1 { + return Ok(NativeResult::err( + gas_params.base, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let mut data = pop_arg!(args, Vec); let mut buffer_final = Vec::new(); @@ -219,6 +259,13 @@ fn native_create_wasm_args_in_memory( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 3 { + return Ok(NativeResult::err( + gas_params.base_create_args, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let func_args_value = pop_arg!(args, Vec); let _func_name = pop_arg!(args, Vec); // TODO: check the length of function arguments let instance_id = pop_arg!(args, u64); @@ -241,7 +288,16 @@ fn native_create_wasm_args_in_memory( let mut data_ptr_list = Vec::new(); let instance_pool = get_instance_pool(); - match instance_pool.lock().unwrap().get_mut(&instance_id) { + let mut pool_object = match instance_pool.lock() { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base_create_args, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; + match pool_object.get_mut(&instance_id) { None => { return Ok(NativeResult::err( gas_params.base_create_args, @@ -260,8 +316,16 @@ fn native_create_wasm_args_in_memory( let mut arg_buffer = Vec::new(); // arg_buffer.append(&mut (arg.len() as u32).to_be_bytes().to_vec()); arg_buffer.append(&mut c_arg.into_bytes_with_nul()); - let buffer_final_ptr = - put_data_on_stack(stack_alloc_func, &mut instance.store, arg_buffer.as_slice()); + let buffer_final_ptr = match put_data_on_stack( + stack_alloc_func, + &mut instance.store, + arg_buffer.as_slice(), + ) { + Ok(v) => v, + Err(_) => { + return build_err(gas_params.base_create_args, E_WASM_EXECUTION_FAILED) + } + }; data_ptr_list.push(buffer_final_ptr as u64); args_bytes_total += arg.len(); @@ -306,12 +370,28 @@ fn native_execute_wasm_function( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 3 { + return Ok(NativeResult::err( + gas_params.base_create_execution, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let func_args = pop_arg!(args, Vec); let func_name = pop_arg!(args, Vec); let instance_id = pop_arg!(args, u64); let instance_pool = get_instance_pool(); - let ret = match instance_pool.lock().unwrap().get_mut(&instance_id) { + let mut pool_object = match instance_pool.lock() { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base_create_execution, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; + let ret = match pool_object.get_mut(&instance_id) { None => Ok(NativeResult::err( gas_params.base_create_execution, E_INSTANCE_NO_EXISTS, @@ -400,11 +480,27 @@ fn native_read_data_length( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 2 { + return Ok(NativeResult::err( + gas_params.base, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let data_ptr = pop_arg!(args, u64); let instance_id = pop_arg!(args, u64); let instance_pool = get_instance_pool(); - let ret = match instance_pool.lock().unwrap().get_mut(&instance_id) { + let mut pool_object = match instance_pool.lock() { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; + let ret = match pool_object.get_mut(&instance_id) { None => Ok(NativeResult::err(gas_params.base, E_INSTANCE_NO_EXISTS)), Some(instance) => { let memory = match instance.instance.exports.get_memory("memory") { @@ -456,12 +552,28 @@ fn native_read_data_from_heap( _ty_args: Vec, mut args: VecDeque, ) -> PartialVMResult { + if args.len() != 3 { + return Ok(NativeResult::err( + gas_params.base, + E_INCORRECT_LENGTH_OF_ARGS, + )); + } + let data_length = pop_arg!(args, u32); let data_ptr = pop_arg!(args, u32); let instance_id = pop_arg!(args, u64); let instance_pool = get_instance_pool(); - let ret = match instance_pool.lock().unwrap().get_mut(&instance_id) { + let mut pool_object = match instance_pool.lock() { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; + let ret = match pool_object.get_mut(&instance_id) { None => Ok(NativeResult::err(gas_params.base, E_INSTANCE_NO_EXISTS)), Some(instance) => { let memory = match instance.instance.exports.get_memory("memory") { @@ -542,8 +654,14 @@ fn native_release_wasm_instance( Some(v) => v, None => return build_err(gas_params.base, E_INCORRECT_LENGTH_OF_ARGS), }; - let mut fiedls = value.value_as::()?.unpack()?; - let val = fiedls.next().ok_or_else(|| { + let mut fields = match value.value_as::() { + Ok(struct_) => match struct_.unpack() { + Ok(fields_iterator) => fields_iterator, + Err(_) => return Ok(NativeResult::err(gas_params.base, E_UNPACK_STRUCT_FAILED)), + }, + Err(_) => return Ok(NativeResult::err(gas_params.base, E_UNPACK_STRUCT_FAILED)), + }; + let val = fields.next().ok_or_else(|| { PartialVMError::new(StatusCode::TYPE_RESOLUTION_FAILURE) .with_message("There must have only one field".to_owned()) })?; @@ -551,12 +669,29 @@ fn native_release_wasm_instance( let instance_id = val.value_as::()?; let instance_pool = get_instance_pool(); - match instance_pool.lock().unwrap().get_mut(&instance_id) { + let mut pool_object = match instance_pool.lock() { + Ok(v) => v, + Err(_) => { + return Ok(NativeResult::err( + gas_params.base, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; + match pool_object.get_mut(&instance_id) { None => return Ok(NativeResult::err(gas_params.base, E_INSTANCE_NO_EXISTS)), Some(_) => {} }; - moveos_wasm::wasm::remove_instance(instance_id); + match moveos_wasm::wasm::remove_instance(instance_id) { + Ok(_) => {} + Err(_) => { + return Ok(NativeResult::err( + gas_params.base, + E_GET_INSTANCE_POOL_FAILED, + )) + } + }; Ok(NativeResult::Success { cost: gas_params.base, diff --git a/moveos/moveos-wasm/Cargo.toml b/moveos/moveos-wasm/Cargo.toml index 542bea6eeb..9a2975fc48 100644 --- a/moveos/moveos-wasm/Cargo.toml +++ b/moveos/moveos-wasm/Cargo.toml @@ -9,4 +9,5 @@ serde_json = { workspace = true } once_cell = { workspace = true } wasmer = { workspace = true } ciborium = { workspace = true } -rand = { workspace = true } \ No newline at end of file +rand = { workspace = true } +anyhow = { workspace = true } \ No newline at end of file diff --git a/moveos/moveos-wasm/src/wasm.rs b/moveos/moveos-wasm/src/wasm.rs index f2e275c1a2..f77c36106a 100644 --- a/moveos/moveos-wasm/src/wasm.rs +++ b/moveos/moveos-wasm/src/wasm.rs @@ -31,21 +31,19 @@ pub static mut GLOBAL_MEMORY: Lazy>>> = Lazy::new(|| No static mut GLOBAL_INSTANCE_POOL: Lazy>>> = Lazy::new(|| Arc::new(Mutex::new(BTreeMap::new()))); -pub fn insert_wasm_instance(instance: WASMInstance) -> u64 { +pub fn insert_wasm_instance(instance: WASMInstance) -> anyhow::Result { loop { unsafe { let instance_id: u64 = rand::random(); - if GLOBAL_INSTANCE_POOL - .lock() - .unwrap() - .get(&instance_id) - .is_none() - { - GLOBAL_INSTANCE_POOL - .lock() - .unwrap() - .insert(instance_id, instance); - return instance_id; + let mut instance_pool = match GLOBAL_INSTANCE_POOL.lock() { + Ok(pool_guard) => pool_guard, + Err(_) => { + return Err(anyhow::Error::msg("get global instance pool failed")); + } + }; + if instance_pool.get(&instance_id).is_none() { + instance_pool.insert(instance_id, instance); + return Ok(instance_id); } } } @@ -55,9 +53,16 @@ pub fn get_instance_pool() -> Arc>> { unsafe { GLOBAL_INSTANCE_POOL.clone() } } -pub fn remove_instance(instance_id: u64) { +pub fn remove_instance(instance_id: u64) -> anyhow::Result<()> { unsafe { - GLOBAL_INSTANCE_POOL.lock().unwrap().remove(&instance_id); + let mut instance_pool = match GLOBAL_INSTANCE_POOL.lock() { + Ok(pool_guard) => pool_guard, + Err(_) => { + return Err(anyhow::Error::msg("get global instance pool failed")); + } + }; + instance_pool.remove(&instance_id); + Ok(()) } } @@ -135,43 +140,56 @@ fn proc_exit(_env: FunctionEnvMut, code: i32) { eprintln!("program exit with {:}", code) } -pub fn put_data_on_stack(stack_alloc_func: &Function, store: &mut Store, data: &[u8]) -> i32 { +pub fn put_data_on_stack( + stack_alloc_func: &Function, + store: &mut Store, + data: &[u8], +) -> anyhow::Result { let data_len = data.len() as i32; - let result = stack_alloc_func - .call(store, vec![I32(data_len + 1)].as_slice()) - .expect("call stackAlloc failed"); - let return_value = result - .deref() - .first() - .expect("the stackAlloc func does not have return value"); - let offset = return_value - .i32() - .expect("the return value of stackAlloc is not i32"); + let result = stack_alloc_func.call(store, vec![I32(data_len + 1)].as_slice())?; + let return_value = match result.deref().first() { + None => return Err(anyhow::Error::msg("call StaclAlloc function failed")), + Some(v) => v, + }; + let offset = match return_value.i32() { + None => return Err(anyhow::Error::msg("the data of function return is not i32")), + Some(v) => v, + }; let memory = unsafe { GLOBAL_MEMORY.clone().expect("global memory is none") }; - let bindings = memory.lock().expect("getting memory mutex failed"); + let bindings = match memory.lock() { + Ok(v) => v, + Err(_) => return Err(anyhow::Error::msg("memory lock failed")), + }; let memory_view = bindings.view(store); - memory_view - .write(offset as u64, data) - .expect("write memory failed"); + memory_view.write(offset as u64, data)?; - offset + Ok(offset) } -pub fn get_data_from_heap(memory: Arc>, store: &Store, ptr_offset: i32) -> Vec { - let bindings = memory.lock().expect("getting memory mutex failed"); +pub fn get_data_from_heap( + memory: Arc>, + store: &Store, + ptr_offset: i32, +) -> anyhow::Result> { + let bindings = match memory.lock() { + Ok(v) => v, + Err(_) => return Err(anyhow::Error::msg("memory lock failed")), + }; let memory_view = bindings.view(store); let mut length_bytes: [u8; 4] = [0; 4]; - memory_view - .read(ptr_offset as u64, length_bytes.as_mut_slice()) - .expect("read length_bytes failed"); + match memory_view.read(ptr_offset as u64, length_bytes.as_mut_slice()) { + Ok(_) => {} + Err(_) => return Err(anyhow::Error::msg("read memory failed")), + } let length = u32::from_be_bytes(length_bytes); let mut data = vec![0; length as usize]; - memory_view - .read((ptr_offset + 4) as u64, &mut data) - .expect("read uninit failed"); - data + match memory_view.read((ptr_offset + 4) as u64, &mut data) { + Ok(_) => {} + Err(_) => return Err(anyhow::Error::msg("read memory failed")), + } + Ok(data) // let ptr = memory_view.data_ptr().offset(ptr_offset as isize) as *mut c_char; // let c_str = CStr::from_ptr(ptr); @@ -181,7 +199,7 @@ pub fn get_data_from_heap(memory: Arc>, store: &Store, ptr_offset: // owned_str } -pub fn create_wasm_instance(bytecode: &Vec) -> WASMInstance { +pub fn create_wasm_instance(bytecode: &Vec) -> anyhow::Result { let mut store = Store::default(); let module = Module::new(&store, bytecode).unwrap(); @@ -202,9 +220,15 @@ pub fn create_wasm_instance(bytecode: &Vec) -> WASMInstance { } }; - let instance = Instance::new(&mut store, &module, &import_object).unwrap(); - let memory = instance.exports.get_memory("memory").unwrap(); + let instance = match Instance::new(&mut store, &module, &import_object) { + Ok(v) => v, + Err(_) => return Err(anyhow::Error::msg("create wasm instance failed")), + }; + let memory = match instance.exports.get_memory("memory") { + Ok(v) => v, + Err(_) => return Err(anyhow::Error::msg("get memory failed")), + }; unsafe { *GLOBAL_MEMORY = Some(Arc::new(Mutex::new(memory.clone()))) }; - WASMInstance::new(bytecode.clone(), instance, store) + Ok(WASMInstance::new(bytecode.clone(), instance, store)) }