mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
(semi-)working wasm contract
This commit is contained in:
@@ -37,9 +37,11 @@ pub struct Args {
|
||||
// Through here, you can branch out into different functions inside
|
||||
// this library.
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(_state: &[u8], ix: &[u8]) -> ContractResult {
|
||||
fn process_instruction(/*_state: &[u8], */ ix: &[u8]) -> ContractResult {
|
||||
msg!("Hello from the VM runtime!");
|
||||
// Deserialize the payload into `Args`.
|
||||
let args: Args = deserialize(ix)?;
|
||||
msg!("deserializing payload worked");
|
||||
|
||||
if args.a < args.b {
|
||||
// Returning custom errors
|
||||
|
||||
@@ -49,7 +49,8 @@ pub fn nullifier_exists(mut env: FunctionEnvMut<Env>, ptr: u32, len: u32) -> i32
|
||||
*/
|
||||
|
||||
error!(target: "wasm_runtime::nullifier_exists", "Failed to read bytes from VM memory");
|
||||
-2
|
||||
//-2
|
||||
0
|
||||
}
|
||||
|
||||
/// Try to read a `MerkleNode` from the given pointer and check if it's
|
||||
@@ -78,5 +79,6 @@ pub fn is_valid_merkle(mut env: FunctionEnvMut<Env>, ptr: u32, len: u32) -> i32
|
||||
*/
|
||||
|
||||
error!(target: "wasm_runtime::is_valid_merkle", "Failed to read bytes from VM memory");
|
||||
-2
|
||||
//-2
|
||||
0
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ pub(crate) fn drk_log(mut ctx: FunctionEnvMut<Env>, ptr: WasmPtr<u8>, len: u32)
|
||||
std::mem::drop(logs);
|
||||
},
|
||||
Err(_) => {
|
||||
error!(target: "wasm_runtime::drk_log", "Failed to UTF-8 string from VM memory");
|
||||
error!(target: "wasm_runtime::drk_log", "Failed to read UTF-8 string from VM memory");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ use darkfi_sdk::entrypoint;
|
||||
use log::{debug, info};
|
||||
use wasmer::{
|
||||
imports, wasmparser::Operator, AsStoreRef, CompilerConfig, Function, FunctionEnv, Instance,
|
||||
Memory, MemoryView, Module, Store, Value,
|
||||
Memory, MemoryView, Module, Store, Value, WasmPtr,
|
||||
};
|
||||
use wasmer_compiler_singlepass::Singlepass;
|
||||
use wasmer_middlewares::{
|
||||
@@ -107,7 +107,8 @@ pub struct ExecutionResult {
|
||||
|
||||
pub struct Runtime {
|
||||
pub instance: Instance,
|
||||
pub env: FunctionEnv<Env>,
|
||||
pub store: Store,
|
||||
pub ctx: FunctionEnv<Env>,
|
||||
}
|
||||
|
||||
impl Runtime {
|
||||
@@ -146,26 +147,26 @@ impl Runtime {
|
||||
let state_machine = Arc::new(state_machine);
|
||||
let state_updates = Arc::new(Mutex::new(vec![]));
|
||||
|
||||
let env =
|
||||
let ctx =
|
||||
FunctionEnv::new(&mut store, Env { logs, memory: None, state_machine, state_updates });
|
||||
|
||||
let imports = imports! {
|
||||
"env" => {
|
||||
"drk_log_" => Function::new_typed_with_env(
|
||||
&mut store,
|
||||
&env,
|
||||
&ctx,
|
||||
drk_log,
|
||||
),
|
||||
|
||||
"nullifier_exists_" => Function::new_typed_with_env(
|
||||
&mut store,
|
||||
&env,
|
||||
&ctx,
|
||||
nullifier_exists,
|
||||
),
|
||||
|
||||
"is_valid_merkle_" => Function::new_typed_with_env(
|
||||
&mut store,
|
||||
&env,
|
||||
&ctx,
|
||||
is_valid_merkle,
|
||||
),
|
||||
}
|
||||
@@ -174,31 +175,39 @@ impl Runtime {
|
||||
debug!(target: "wasm_runtime::new", "Instantiating module");
|
||||
let instance = Instance::new(&mut store, &module, &imports)?;
|
||||
|
||||
let mut env_mut = env.as_mut(&mut store);
|
||||
let mut env_mut = ctx.as_mut(&mut store);
|
||||
env_mut.memory = Some(instance.exports.get_with_generics(MEMORY)?);
|
||||
|
||||
Ok(Self { instance, env })
|
||||
Ok(Self { instance, store, ctx })
|
||||
}
|
||||
|
||||
/// Run the hardcoded `ENTRYPOINT` function with the given payload as input.
|
||||
pub fn run(&mut self, payload: &[u8]) -> Result<()> {
|
||||
/*
|
||||
// TODO: needs factoring
|
||||
let mem_offset = self.guest_mem_alloc(payload.len())?;
|
||||
{
|
||||
let env = self.ctx.as_ref(&self.store);
|
||||
let memory_view = env.memory_view(&self.store);
|
||||
let ptr: WasmPtr<u8> = WasmPtr::new(mem_offset);
|
||||
let slice = ptr.slice(&memory_view, payload.len() as u32).expect("FIXME FIXME FIXME");
|
||||
slice.write_slice(payload).expect("FIXME FIXME FIXME");
|
||||
}
|
||||
|
||||
// Get module linear memory
|
||||
let memory = self.memory()?;
|
||||
//let memory = self.memory()?;
|
||||
|
||||
// Retrieve ptr to pass data, and write the payload into the vm memory
|
||||
let mem_offset = self.guest_mem_alloc(payload.len())?;
|
||||
memory.write(mem_offset, payload)?;
|
||||
//memory.write(mem_offset, payload)?;
|
||||
|
||||
debug!(target: "wasm_runtime::run", "Getting entrypoint function");
|
||||
let entrypoint = self.instance.exports.get_function(ENTRYPOINT)?;
|
||||
|
||||
debug!(target: "wasm_runtime::run", "Executing wasm");
|
||||
let ret = match entrypoint.call(&[Value::I32(mem_offset as i32)]) {
|
||||
Ok(v) => {
|
||||
let ret = match entrypoint.call(&mut self.store, &[Value::I32(mem_offset as i32)]) {
|
||||
Ok(retvals) => {
|
||||
self.print_logs();
|
||||
debug!(target: "wasm_runtime::run", "{}", self.gas_info());
|
||||
v
|
||||
retvals
|
||||
}
|
||||
Err(e) => {
|
||||
self.print_logs();
|
||||
@@ -220,16 +229,13 @@ impl Runtime {
|
||||
// _ => Err(ContractError(retval)),
|
||||
_ => todo!(),
|
||||
}
|
||||
*/
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_logs(&self) {
|
||||
// DISABLED
|
||||
/*let logs = self.env.logs.lock().unwrap();
|
||||
let logs = self.ctx.as_ref(&self.store).logs.borrow();
|
||||
for msg in logs.iter() {
|
||||
debug!(target: "wasm_runtime::run", "Contract log: {}", msg);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
fn gas_info(&self) -> String {
|
||||
@@ -246,16 +252,18 @@ impl Runtime {
|
||||
}
|
||||
}
|
||||
*/
|
||||
"foo".to_string()
|
||||
"(gas info temporarily disabled)".to_string()
|
||||
}
|
||||
|
||||
/// Allocate some memory space on a wasm linear memory to allow direct rw.
|
||||
fn guest_mem_alloc(&self, size: usize) -> Result<u32> {
|
||||
// DISABLED
|
||||
//let mem_alloc = self.instance.exports.get_function(WASM_MEM_ALLOC)?;
|
||||
//let res_target_ptr = mem_alloc.call(&[Value::I32(size as i32)])?.to_vec();
|
||||
//Ok(res_target_ptr[0].unwrap_i32() as u32)
|
||||
Ok(0)
|
||||
// TODO: we should maybe use memory.grow() instead which expands memory by pages
|
||||
// https://docs.rs/wasmer/3.0.0-rc.1/wasmer/struct.Memory.html#method.grow
|
||||
// TODO: https://docs.rs/wasmer/3.0.0-rc.1/wasmer/constant.WASM_PAGE_SIZE.html
|
||||
fn guest_mem_alloc(&mut self, size: usize) -> Result<u32> {
|
||||
let mem_alloc_func = self.instance.exports.get_function(WASM_MEM_ALLOC)?;
|
||||
let res_target_ptr =
|
||||
mem_alloc_func.call(&mut self.store, &[Value::I32(size as i32)])?.to_vec();
|
||||
Ok(res_target_ptr[0].unwrap_i32() as u32)
|
||||
}
|
||||
|
||||
/// Retrieve linear memory from a wasm module and return its reference.
|
||||
|
||||
@@ -32,9 +32,10 @@ macro_rules! entrypoint {
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
|
||||
let (state, instruction_data) = $crate::entrypoint::deserialize(input);
|
||||
//let (state, instruction_data) = $crate::entrypoint::deserialize(input);
|
||||
let instruction_data = $crate::entrypoint::deserialize(input);
|
||||
|
||||
match $process_instruction(&state, &instruction_data) {
|
||||
match $process_instruction(/*&state, */ &instruction_data) {
|
||||
Ok(()) => $crate::entrypoint::SUCCESS,
|
||||
Err(e) => e.into(),
|
||||
}
|
||||
@@ -44,19 +45,23 @@ macro_rules! entrypoint {
|
||||
|
||||
/// Deserialize a given payload in `entrypoint`
|
||||
/// # Safety
|
||||
pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a [u8], &'a [u8]) {
|
||||
//pub unsafe fn deserialize<'a>(input: *mut u8) -> (&'a [u8], &'a [u8]) {
|
||||
pub unsafe fn deserialize<'a>(input: *mut u8) -> &'a [u8] {
|
||||
let mut offset: usize = 0;
|
||||
|
||||
/*
|
||||
let state_data_len = *(input.add(offset) as *const u64) as usize;
|
||||
offset += size_of::<u64>();
|
||||
let state_data = { from_raw_parts(input.add(offset), state_data_len) };
|
||||
offset += state_data_len;
|
||||
*/
|
||||
|
||||
let instruction_data_len = *(input.add(offset) as *const u64) as usize;
|
||||
offset += size_of::<u64>();
|
||||
let instruction_data = { from_raw_parts(input.add(offset), instruction_data_len) };
|
||||
|
||||
(state_data, instruction_data)
|
||||
//(state_data, instruction_data)
|
||||
instruction_data
|
||||
}
|
||||
|
||||
/// Allocate a piece of memory in the wasm VM
|
||||
|
||||
Reference in New Issue
Block a user