/* This file is part of DarkFi (https://dark.fi)
*
* Copyright (C) 2020-2023 Dyne.org foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
use std::time::SystemTime;
use log::error;
use wasmer::{FunctionEnvMut, WasmPtr};
use crate::runtime::vm_runtime::{ContractSection, Env};
/// Host function for logging strings.
/// This is injected into the runtime with wasmer's `imports!` macro.
pub(crate) fn drk_log(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) {
let env = ctx.data();
let memory_view = env.memory_view(&ctx);
match ptr.read_utf8_string(&memory_view, len) {
Ok(msg) => {
let mut logs = env.logs.borrow_mut();
logs.push(msg);
std::mem::drop(logs);
}
Err(_) => {
error!(target: "runtime::util", "Failed to read UTF-8 string from VM memory");
}
}
}
pub(crate) fn set_return_data(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i64 {
let env = ctx.data();
match env.contract_section {
ContractSection::Exec | ContractSection::Metadata => {
let memory_view = env.memory_view(&ctx);
let Ok(slice) = ptr.slice(&memory_view, len) else {
return darkfi_sdk::error::INTERNAL_ERROR
};
let Ok(return_data) = slice.read_to_vec() else {
return darkfi_sdk::error::INTERNAL_ERROR
};
// This function should only ever be called once on the runtime.
if env.contract_return_data.take().is_some() {
return darkfi_sdk::error::SET_RETVAL_ERROR
}
env.contract_return_data.set(Some(return_data));
0
}
_ => darkfi_sdk::error::CALLER_ACCESS_DENIED,
}
}
pub(crate) fn put_object_bytes(ctx: FunctionEnvMut, ptr: WasmPtr, len: u32) -> i64 {
let env = ctx.data();
let memory_view = env.memory_view(&ctx);
//debug!(target: "runtime::util", "diagnostic:");
//let pages = memory_view.size().0;
//debug!(target: "runtime::util", " pages: {}", pages);
let Ok(slice) = ptr.slice(&memory_view, len) else {
error!(target: "runtime::util", "Failed to make slice from ptr");
return -2
};
let mut buf = vec![0_u8; len as usize];
if let Err(e) = slice.read_slice(&mut buf) {
error!(target: "runtime::util", "Failed to read from memory slice: {}", e);
return -2
};
// There would be a serious problem if this is zero.
// The number of pages is calculated as a quantity X + 1 where X >= 0
//assert!(pages > 0);
//debug!(target: "runtime::util", " memory: {:02x?}", &buf[0..32]);
//debug!(target: "runtime::util", " {:x?}", &buf[32..64]);
//debug!(target: "runtime::util", " ptr location: {}", ptr.offset());
let mut objects = env.objects.borrow_mut();
objects.push(buf);
let obj_idx = objects.len() - 1;
obj_idx as i64
}
pub(crate) fn get_object_bytes(ctx: FunctionEnvMut, ptr: WasmPtr, idx: u32) -> i64 {
// Get the slice, where we will read the size of the buffer
let env = ctx.data();
let memory_view = env.memory_view(&ctx);
// Get the object from env
let objects = env.objects.borrow();
if idx as usize >= objects.len() {
error!(target: "runtime::util", "Tried to access object out of bounds");
return -5
}
let obj = &objects[idx as usize];
// Read N bytes from the object and write onto the ptr.
// We need to re-read the slice, since in the first run, we just read n
let Ok(slice) = ptr.slice(&memory_view, obj.len() as u32) else {
error!(target: "runtime::util", "Failed to make slice from ptr");
return -2
};
// Put the result in the VM
if let Err(e) = slice.write_slice(obj) {
error!(target: "runtime::util", "Failed to write to memory slice: {}", e);
return -4
};
0
}
pub(crate) fn get_object_size(ctx: FunctionEnvMut, idx: u32) -> i64 {
// Get the slice, where we will read the size of the buffer
let env = ctx.data();
//let memory_view = env.memory_view(&ctx);
// Get the object from env
let objects = env.objects.borrow();
if idx as usize >= objects.len() {
error!(target: "runtime::util", "Tried to access object out of bounds");
return -5
}
let obj = &objects[idx as usize];
obj.len() as i64
}
pub(crate) fn get_system_time() -> i64 {
match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(t) => t.as_secs() as i64,
Err(_) => -1,
}
}