Skip to content

Commit

Permalink
feat: finish polyfill
Browse files Browse the repository at this point in the history
  • Loading branch information
gluax committed Jan 24, 2025
1 parent 8483624 commit 1206215
Show file tree
Hide file tree
Showing 16 changed files with 78 additions and 66 deletions.
9 changes: 5 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ members = ["libtallyvm", "runtime/core", "runtime/sdk", "xtask"]

[workspace.package]
rust-version = "1.77.0"
version = "2.2.0"
version = "2.2.1"

[profile.dev]
codegen-units = 512
Expand Down
1 change: 1 addition & 0 deletions libtallyvm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ tracing-appender.workspace = true
cbindgen.workspace = true

[dev-dependencies]
serde_json.workspace = true
tempdir.workspace = true
35 changes: 24 additions & 11 deletions libtallyvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -551,22 +551,35 @@ mod test {
}

#[test]
fn polyfill_does_not_crash_vm() {
fn simple_price_feed() {
let wasm_bytes = include_bytes!("../../simplePriceFeed.wasm");
let mut envs: BTreeMap<String, String> = BTreeMap::new();
envs.insert("VM_MODE".to_string(), "tally".to_string());
envs.insert(DEFAULT_GAS_LIMIT_ENV_VAR.to_string(), "150000000000000".to_string());
envs.insert("VM_MODE".to_string(), "dr".to_string());
envs.insert(DEFAULT_GAS_LIMIT_ENV_VAR.to_string(), "300000000000000".to_string());

let tempdir = std::env::temp_dir();
let result = _execute_tally_vm(&tempdir, wasm_bytes.to_vec(), vec![hex::encode("btc:usdc")], envs).unwrap();
dbg!(&result);
let result = _execute_tally_vm(&tempdir, wasm_bytes.to_vec(), vec![hex::encode("btc-usdc")], envs).unwrap();
result.stdout.iter().for_each(|line| print!("{}", line));

assert_eq!(
result.exit_info.exit_message,
"Error while fetching price feed".to_string()
);
}

#[test]
fn polyfill_does_not_crash_vm() {
let wasm_bytes = include_bytes!("../../randomNumber.wasm");
let mut envs: BTreeMap<String, String> = BTreeMap::new();
envs.insert("VM_MODE".to_string(), "dr".to_string());
envs.insert(DEFAULT_GAS_LIMIT_ENV_VAR.to_string(), "300000000000000".to_string());

let tempdir = std::env::temp_dir().join("foo");
std::fs::create_dir_all(&tempdir).unwrap();
let result = _execute_tally_vm(&tempdir, wasm_bytes.to_vec(), vec![], envs).unwrap();
result.stdout.iter().for_each(|line| print!("{}", line));

// assert_eq!(
// String::from_utf8(result.result.unwrap()).unwrap(),
// // "testKeccak256" hashed
// "fe8baa653979909c621153b53c973bab3832768b5e77896a5b5944d20d48c7a6"
// );
// assert_eq!(result.gas_used, 5157033460000);
assert_eq!(result.exit_info.exit_code, 252);
assert!(result.exit_info.exit_message.is_empty());
}
}
Binary file added randomNumber.wasm
Binary file not shown.
60 changes: 19 additions & 41 deletions runtime/core/src/core_vm_imports/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use secp256_k1::secp256k1_verify_import_obj;
use wasmer::{imports, FunctionEnv, Imports, Store};
use wasmer::{imports, FunctionEnv, Imports, Store, WasmPtr};

use crate::context::VmContext;

Expand All @@ -8,16 +7,14 @@ mod execution_result;
mod keccak256;
mod secp256_k1;

// TODO: need a way to add additional arguments to the polyfill
#[macro_export]
macro_rules! generic_polyfill_import_obj {
($name:expr, $ret:ty) => {
($name:expr, $ret:ty $(, $arg_name:ident: $arg_type:ty)*) => {
|store: &mut ::wasmer::Store,
vm_context: &::wasmer::FunctionEnv<crate::context::VmContext>|
vm_context: &::wasmer::FunctionEnv<$crate::context::VmContext>|
-> ::wasmer::Function {
fn generic_polyfill(_: ::wasmer::FunctionEnvMut<'_, VmContext>) -> crate::errors::Result<$ret> {
tracing::info!("Polyfill for function {} is not implemented in tally mode", $name);

Ok(<$ret>::default())
fn generic_polyfill(_: ::wasmer::FunctionEnvMut<'_, $crate::context::VmContext>, $($arg_name: $arg_type,)*) -> $crate::errors::Result<$ret> {
Err($crate::errors::RuntimeError::Polyfilled(stringify!($name)))
}

::wasmer::Function::new_typed_with_env(store, vm_context, generic_polyfill)
Expand All @@ -28,40 +25,21 @@ macro_rules! generic_polyfill_import_obj {
pub fn create_custom_core_imports(store: &mut Store, vm_context: &FunctionEnv<VmContext>) -> Imports {
let core_imports = imports! {
"seda_v1" => {
// TODO: when merged to run the dr vm these should not be polyfills
"shared_memory_contains_key" => generic_polyfill_import_obj!("shared_memory_contains_key", u8)(store, vm_context),
"shared_memory_read" => generic_polyfill_import_obj!("shared_memory_read", ())(store, vm_context),
"shared_memory_read_length" => generic_polyfill_import_obj!("shared_memory_read_length", i64)(store, vm_context),
"shared_memory_write" => generic_polyfill_import_obj!("shared_memory_write", ())(store, vm_context),
"shared_memory_remove" => generic_polyfill_import_obj!("shared_memory_remove", ())(store, vm_context),
"shared_memory_range" => generic_polyfill_import_obj!("shared_memory_range", u32)(store, vm_context),
"_log" => generic_polyfill_import_obj!("_log", ())(store, vm_context),
"bn254_verify" => generic_polyfill_import_obj!("bn254_verify", u8)(store, vm_context),
"proxy_http_fetch" => generic_polyfill_import_obj!("proxy_http_fetch", u32)(store, vm_context),
"http_fetch" => generic_polyfill_import_obj!("http_fetch", u32)(store, vm_context),
"chain_view" => generic_polyfill_import_obj!("chain_view", u32)(store, vm_context),
"chain_send_tx" => generic_polyfill_import_obj!("chain_send_tx", u32)(store, vm_context),
"chain_tx_status" => generic_polyfill_import_obj!("chain_tx_status", u32)(store, vm_context),
"main_chain_call" => generic_polyfill_import_obj!("main_chain_call", u32)(store, vm_context),
"main_chain_call_tx_status" => generic_polyfill_import_obj!("main_chain_call_tx_status", u32)(store, vm_context),
"main_chain_view" => generic_polyfill_import_obj!("main_chain_view", u32)(store, vm_context),
"main_chain_query" => generic_polyfill_import_obj!("main_chain_query", u32)(store, vm_context),
"vm_call" => generic_polyfill_import_obj!("vm_call", u32)(store, vm_context),
"db_set" => generic_polyfill_import_obj!("db_set", u32)(store, vm_context),
"db_get" => generic_polyfill_import_obj!("db_get", u32)(store, vm_context),
"trigger_event" => generic_polyfill_import_obj!("trigger_event", ())(store, vm_context),
"wasm_exists" => generic_polyfill_import_obj!("wasm_exists", u8)(store, vm_context),
"wasm_store" => generic_polyfill_import_obj!("wasm_store", u32)(store, vm_context),
"identity_sign" => generic_polyfill_import_obj!("identity_sign", u32)(store, vm_context),
"use_gas" => generic_polyfill_import_obj!("use_gas", ())(store, vm_context),
"abort_app" => generic_polyfill_import_obj!("abort_app", ())(store, vm_context),

"call_result_write" => call_result::call_result_value_write_import_obj(store, vm_context),
"bn254_verify" => generic_polyfill_import_obj!(
"bn254_verify", u8,
_message: WasmPtr<u8>,
_message_length: i64,
_signature: WasmPtr<u8>,
_signature_length: i64,
_public_key: WasmPtr<u8>,
_public_key_length: i64
)(store, vm_context),
"call_result_length" => call_result::call_result_value_length_import_obj(store, vm_context),
"call_result_write" => call_result::call_result_value_write_import_obj(store, vm_context),
"execution_result" => execution_result::execution_result_import_obj(store, vm_context),
"secp256k1_verify" => secp256k1_verify_import_obj(store, vm_context),
"keccak256" => keccak256::keccak256_import_obj(store, vm_context)
}
"keccak256" => keccak256::keccak256_import_obj(store, vm_context),
"secp256k1_verify" => secp256_k1::secp256k1_verify_import_obj(store, vm_context)
},
};

core_imports
Expand Down
3 changes: 3 additions & 0 deletions runtime/core/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ pub enum RuntimeError {

#[error("Out of gas")]
OutOfGas,

#[error("Polyfill for function {0} is not implemented in tally mode")]
Polyfilled(&'static str),
}

pub type Result<T, E = RuntimeError> = core::result::Result<T, E>;
17 changes: 13 additions & 4 deletions runtime/core/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,20 @@ fn internal_run_vm(

if let Err(err) = runtime_result {
tracing::error!("Error running WASM: {err:?}");
// we convert the error to a wasix error
let wasix_error = WasiRuntimeError::from(err);

if let Some(wasi_exit_code) = wasix_error.as_exit_code() {
exit_code = wasi_exit_code.raw();
// TODO this makes me think that wasm host functions should
// return a different kind of error rather than a RuntimeError.
if err.is::<crate::errors::RuntimeError>() {
let runtime_error = err.downcast::<crate::errors::RuntimeError>().unwrap();
stderr.push(format!("Runtime error: {runtime_error}"));
exit_code = 252;
} else {
// we convert the error to a wasix error
let wasix_error = WasiRuntimeError::from(err);

if let Some(wasi_exit_code) = wasix_error.as_exit_code() {
exit_code = wasi_exit_code.raw();
}
}
}

Expand Down
4 changes: 0 additions & 4 deletions runtime/core/src/safe_wasi_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ use lazy_static::lazy_static;
lazy_static! {
pub static ref SAFE_WASI_IMPORTS: Vec<String> = {
[
// "execution_result",
// "http_fetch",
// "call_result_write",
"args_get",
"args_sizes_get",
"proc_exit",
// "random_get",
"fd_write",
"environ_get",
"environ_sizes_get",
Expand Down
13 changes: 12 additions & 1 deletion runtime/core/src/vm_imports.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use seda_runtime_sdk::{VmCallData, VmType};
use wasmer::{Exports, FunctionEnv, Imports, Module, Store};
use wasmer::{Exports, FunctionEnv, Imports, Module, Store, WasmPtr};
use wasmer_wasix::{get_wasi_version, WasiFunctionEnv};

use crate::{
Expand Down Expand Up @@ -50,6 +50,17 @@ pub fn create_wasm_imports(
final_imports.register_namespace("seda_v1", allowed_host_exports);

if let Some(wasi_version) = wasi_version {
// additionally polyfill the "random_get" wasi import
allowed_wasi_exports.insert(
"random_get".to_string(),
// https://wasix.org/docs/api-reference/wasi/random_get
// https://docs.rs/wasix/latest/wasix/lib_generated64/fn.random_get.html
crate::generic_polyfill_import_obj!(
"random_get", i32,
_buf: WasmPtr<u8>,
_buf_len: i32
)(store, vm_context),
);
final_imports.register_namespace(wasi_version.get_namespace_str(), allowed_wasi_exports);
}

Expand Down
Binary file modified simplePriceFeed.wasm
Binary file not shown.
Binary file modified tallyvm/libseda_tally_vm.aarch64.so
Binary file not shown.
Binary file modified tallyvm/libseda_tally_vm.dylib
Binary file not shown.
Binary file modified tallyvm/libseda_tally_vm.x86_64.so
Binary file not shown.
Binary file modified tallyvm/libseda_tally_vm_muslc.aarch64.a
Binary file not shown.
Binary file modified tallyvm/libseda_tally_vm_muslc.x86_64.a
Binary file not shown.

0 comments on commit 1206215

Please sign in to comment.