use crate::api::{BlockchainAPI, StorageAPI};
use crate::error::HostError;
use crate::memory::Pointer;
use alloc::vec::Vec;
use core::any::Any;
use minicbor::{Decode, Encode};
#[cfg(not(test))]
#[link(wasm_import_module = "pactus")]
extern "C" {
fn write_storage(offset: u32, ptr: u32, len: u32) -> i32;
fn read_storage(offset: u32, ptr: u32, len: u32) -> i32;
fn get_param(param_id: u32, ptr: *mut u32, len: *mut u32) -> i32;
}
pub struct Kelk {}
impl Kelk {
pub fn new() -> Self {
Self {}
}
}
impl Default for Kelk {
fn default() -> Self {
Self::new()
}
}
impl StorageAPI for Kelk {
fn read(&self, offset: u32, data: &mut [u8]) -> Result<(), HostError> {
let ptr = data.as_ptr() as u32;
let len = data.len() as u32;
let code = unsafe { read_storage(offset, ptr, len) };
if code != 0 {
return Err(HostError { code });
}
Ok(())
}
fn write(&self, offset: u32, data: &[u8]) -> Result<(), HostError> {
let ptr = data.as_ptr() as u32;
let len = data.len() as u32;
let code = unsafe { write_storage(offset, ptr, len) };
if code != 0 {
return Err(HostError { code });
}
Ok(())
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
impl BlockchainAPI for Kelk {
fn get_param(&self, param_id: u32) -> Result<Vec<u8>, HostError> {
let mut len = 0;
let mut ptr = 0;
let code = unsafe { get_param(param_id, &mut ptr, &mut len) };
if code != 0 {
return Err(HostError { code });
}
let slice = unsafe { core::slice::from_raw_parts(ptr as *const u8, len as usize) };
Ok(slice.to_vec())
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
pub fn do_instantiate<'a, T, D: Decode<'a, ()>, E: Encode<()>>(
instantiate_fn: &dyn Fn(T, D) -> Result<(), E>,
ctx: T,
msg_ptr: u64,
) -> u64 {
do_execute(instantiate_fn, ctx, msg_ptr)
}
pub fn do_process<'a, T, D: Decode<'a, ()>, E: Encode<()>>(
process_fn: &dyn Fn(T, D) -> Result<(), E>,
ctx: T,
msg_ptr: u64,
) -> u64 {
do_execute(process_fn, ctx, msg_ptr)
}
pub fn do_query<'a, T, D: Decode<'a, ()>, R: Encode<()>, E: Encode<()>>(
query_fn: &dyn Fn(T, D) -> Result<R, E>,
ctx: T,
msg_ptr: u64,
) -> u64 {
do_execute(query_fn, ctx, msg_ptr)
}
fn do_execute<'a, T, D: Decode<'a, ()>, R: Encode<()>, E: Encode<()>>(
func: &dyn Fn(T, D) -> Result<R, E>,
ctx: T,
msg_ptr: u64,
) -> u64 {
let ptr = Pointer::from_u64(msg_ptr);
let buf = unsafe { ptr.to_slice() };
let msg = minicbor::decode(buf).expect("Decoding failed");
let res = func(ctx, msg);
let mut vec = crate::alloc::vec::Vec::new();
minicbor::encode(res, &mut vec).expect("Encoding failed");
Pointer::release_buffer(vec).as_u64()
}
#[cfg(test)]
pub unsafe fn write_storage(_offset: u32, _ptr: u32, _len: u32) -> i32 {
0
}
#[cfg(test)]
pub unsafe fn read_storage(_offset: u32, _ptr: u32, _len: u32) -> i32 {
0
}
#[cfg(test)]
pub unsafe fn get_param(_param_id: u32, _ptr: *mut u32, _len: *mut u32) -> i32 {
0
}
#[cfg(test)]
mod tests {
use super::*;
use crate::alloc::vec;
use wasm_bindgen_test::*;
#[wasm_bindgen_test]
fn test_instantiate() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_instantiate(
&|_: (), _: i32| -> Result<(), i32> { Ok(()) },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x00, 0x80]); }
#[wasm_bindgen_test]
fn test_instantiate_error() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_instantiate(
&|_: (), _: i32| -> Result<(), i32> { Err(0x0e) },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x01, 0x0e]); }
#[wasm_bindgen_test]
fn test_process() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_process(
&|_: (), _: i32| -> Result<(), i32> { Ok(()) },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x00, 0x80]); }
#[wasm_bindgen_test]
fn test_process_error() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_process(
&|_: (), _: i32| -> Result<(), i32> { Err(0x0e) },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x01, 0x0e]); }
#[wasm_bindgen_test]
fn test_query() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_query(
&|_: (), _: i32| -> Result<&str, i32> { Ok("foo") },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x00, 0x63, 0x66, 0x6f, 0x6f]); }
#[wasm_bindgen_test]
fn test_query_error() {
let msg_data = vec![0x00]; let msg_ptr = Pointer::release_buffer(msg_data);
let res_ptr = do_query(
&|_: (), _: i32| -> Result<&str, i32> { Err(0x0e) },
(),
msg_ptr.as_u64(),
);
let res_data = unsafe { Pointer::from_u64(res_ptr).to_slice() };
assert_eq!(res_data, vec![0x82, 0x01, 0x0e]); }
}