From 1437ff3d7ab1e01f1384a348e77fea1610b13261 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 23 Feb 2024 11:00:10 -0700 Subject: [PATCH 01/28] initial joint wasip1 implementation --- arbitrator/Cargo.lock | 5 + arbitrator/callerenv/Cargo.toml | 9 + arbitrator/callerenv/src/lib.rs | 33 ++ arbitrator/callerenv/src/wasip1_stub.rs | 293 ++++++++++ arbitrator/jit/Cargo.toml | 1 + arbitrator/jit/src/arbcompress.rs | 8 +- arbitrator/jit/src/callerenv.rs | 127 +++-- arbitrator/jit/src/program.rs | 21 +- arbitrator/jit/src/wasip1_stub.rs | 394 +++++--------- arbitrator/jit/src/wavmio.rs | 16 +- arbitrator/wasm-libraries/Cargo.lock | 12 + .../wasm-libraries/wasi-stub/Cargo.toml | 2 + .../wasm-libraries/wasi-stub/src/lib.rs | 514 +++++++----------- 13 files changed, 786 insertions(+), 649 deletions(-) create mode 100644 arbitrator/callerenv/Cargo.toml create mode 100644 arbitrator/callerenv/src/lib.rs create mode 100644 arbitrator/callerenv/src/wasip1_stub.rs diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index ca210f55b..30af8d02e 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -202,6 +202,10 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "callerenv" +version = "0.1.0" + [[package]] name = "cc" version = "1.0.73" @@ -779,6 +783,7 @@ name = "jit" version = "0.1.0" dependencies = [ "arbutil", + "callerenv", "eyre", "hex", "libc", diff --git a/arbitrator/callerenv/Cargo.toml b/arbitrator/callerenv/Cargo.toml new file mode 100644 index 000000000..6640c5da2 --- /dev/null +++ b/arbitrator/callerenv/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "callerenv" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[features] +wavm = [] diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs new file mode 100644 index 000000000..9e7a1c127 --- /dev/null +++ b/arbitrator/callerenv/src/lib.rs @@ -0,0 +1,33 @@ + +#![no_std] + +pub mod wasip1_stub; + +pub const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; +pub const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; + +pub trait CallerEnv<'a> { + fn caller_read_u8(&self, ptr: u32) -> u8; + + fn caller_read_u16(&self, ptr: u32) -> u16; + + fn caller_read_u32(&self, ptr: u32) -> u32; + + fn caller_read_u64(&self, ptr: u32) -> u64; + + fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self; + + fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self; + + fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self; + + fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self; + + fn caller_print_string(&mut self, ptr: u32, len: u32); + + fn caller_get_time(&self) -> u64; + + fn caller_advance_time(&mut self, delta: u64); + + fn next_rand_u32(&mut self) -> u32; +} diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/callerenv/src/wasip1_stub.rs new file mode 100644 index 000000000..226bbeb77 --- /dev/null +++ b/arbitrator/callerenv/src/wasip1_stub.rs @@ -0,0 +1,293 @@ +use crate::CallerEnv; + +pub type Errno = u16; + +pub type Uptr = u32; + +pub const ERRNO_SUCCESS: Errno = 0; +pub const ERRNO_BADF: Errno = 8; +pub const ERRNO_INTVAL: Errno = 28; + +pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( + mut caller_env: E, + length_ptr: Uptr, + data_size_ptr: Uptr, +) -> Errno { + caller_env.caller_write_u32(length_ptr, 0); + caller_env.caller_write_u32(data_size_ptr, 0); + ERRNO_SUCCESS +} + +pub fn fd_write<'a, E: CallerEnv<'a>>( + mut caller_env: E, + fd: u32, + iovecs_ptr: Uptr, + iovecs_len: u32, + ret_ptr: Uptr, +) -> Errno { + if fd != 1 && fd != 2 { + return ERRNO_BADF; + } + let mut size = 0; + for i in 0..iovecs_len { + let ptr = iovecs_ptr + i * 8; + let iovec = caller_env.caller_read_u32(ptr); + let len = caller_env.caller_read_u32(ptr + 4); + caller_env.caller_print_string(iovec, len); + size += len; + } + caller_env.caller_write_u32(ret_ptr, size); + ERRNO_SUCCESS +} + +pub fn environ_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} + +pub fn fd_close<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_read<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_readdir<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_sync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { + ERRNO_SUCCESS +} + +pub fn fd_seek<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _offset: u64, + _whence: u8, + _filesize: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_datasync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32) -> Errno { + ERRNO_BADF +} + +pub fn path_open<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u64, + _: u64, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_create_directory<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_remove_directory<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_readlink<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_rename<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_filestat_get<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_unlink_file<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_filestat_get<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _filestat: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u64) -> Errno { + ERRNO_BADF +} + +pub fn fd_pread<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_pwrite<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn sock_accept<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn sock_shutdown<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn sched_yield<'a, E: CallerEnv<'a>>(mut _caller_env: E) -> Errno { + ERRNO_SUCCESS +} + +static TIME_INTERVAL: u64 = 10_000_000; + +pub fn clock_time_get<'a, E: CallerEnv<'a>>( + mut caller_env: E, + _clock_id: u32, + _precision: u64, + time_ptr: Uptr, +) -> Errno { + caller_env.caller_advance_time(TIME_INTERVAL); + caller_env.caller_write_u64(time_ptr, caller_env.caller_get_time()); + ERRNO_SUCCESS +} + +pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len: u32) -> Errno { + while len >= 4 { + let next_rand = caller_env.next_rand_u32(); + caller_env.caller_write_u32(buf, next_rand); + buf += 4; + len -= 4; + } + if len > 0 { + let mut rem = caller_env.next_rand_u32(); + for _ in 0..len { + caller_env.caller_write_u8(buf, rem as u8); + buf += 1; + rem >>= 8; + } + } + ERRNO_SUCCESS +} + +pub fn args_sizes_get<'a, E: CallerEnv<'a>>( + mut caller_env: E, + length_ptr: Uptr, + data_size_ptr: Uptr, +) -> Errno { + caller_env.caller_write_u32(length_ptr, 1); + caller_env.caller_write_u32(data_size_ptr, 4); + ERRNO_SUCCESS +} + +pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_buf: Uptr) -> Errno { + caller_env.caller_write_u32(argv_buf, data_buf as u32); + caller_env.caller_write_u32(data_buf, 0x6E6962); // "bin\0" + ERRNO_SUCCESS +} + +// we always simulate a timeout +pub fn poll_oneoff<'a, E: CallerEnv<'a>>( + mut caller_env: E, + in_subs: Uptr, + out_evt: Uptr, + nsubscriptions: u32, + nevents_ptr: Uptr, +) -> Errno { + const SUBSCRIPTION_SIZE: u32 = 48; + for i in 0..nsubscriptions { + let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); + let subs_type = caller_env.caller_read_u32(subs_base + 8); + if subs_type != 0 { + // not a clock subscription type + continue; + } + let user_data = caller_env.caller_read_u32(subs_base); + caller_env.caller_write_u32(out_evt, user_data); + caller_env.caller_write_u32(out_evt + 8, 0); + caller_env.caller_write_u32(nevents_ptr, 1); + return ERRNO_SUCCESS; + } + ERRNO_INTVAL +} + +pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} + +pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} diff --git a/arbitrator/jit/Cargo.toml b/arbitrator/jit/Cargo.toml index 3c94f3ac9..33bb00f81 100644 --- a/arbitrator/jit/Cargo.toml +++ b/arbitrator/jit/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] arbutil = { path = "../arbutil/" } +callerenv = { path = "../callerenv/" } prover = { path = "../prover/", default-features = false, features = ["native"] } stylus = { path = "../stylus/", default-features = false } wasmer = { path = "../tools/wasmer/lib/api/" } diff --git a/arbitrator/jit/src/arbcompress.rs b/arbitrator/jit/src/arbcompress.rs index b85f0611b..a9cb3cba2 100644 --- a/arbitrator/jit/src/arbcompress.rs +++ b/arbitrator/jit/src/arbcompress.rs @@ -1,8 +1,10 @@ // Copyright 2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE +use crate::callerenv::JitCallerEnv; use crate::machine::Escape; -use crate::{callerenv::CallerEnv, machine::WasmEnvMut}; +use crate::machine::WasmEnvMut; +use callerenv::CallerEnv; extern "C" { pub fn BrotliDecoderDecompress( @@ -46,7 +48,7 @@ pub fn brotli_decompress( out_buf_ptr: Uptr, out_len_ptr: Uptr, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let in_slice = caller_env.caller_read_slice(in_buf_ptr, in_buf_len); let orig_output_len = caller_env.caller_read_u32(out_len_ptr) as usize; let mut output = vec![0u8; orig_output_len as usize]; @@ -79,7 +81,7 @@ pub fn brotli_compress( level: u32, window_size: u32, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let in_slice = caller_env.caller_read_slice(in_buf_ptr, in_buf_len); let orig_output_len = caller_env.caller_read_u32(out_len_ptr) as usize; let mut output = vec![0u8; orig_output_len]; diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index 9feb0b9dc..07894cad1 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -4,22 +4,30 @@ #![allow(clippy::useless_transmute)] use crate::machine::{WasmEnv, WasmEnvMut}; +use callerenv::CallerEnv; use arbutil::{Bytes20, Bytes32}; use rand_pcg::Pcg32; +use rand::RngCore; use std::{ collections::{BTreeSet, BinaryHeap}, fmt::Debug, }; use wasmer::{Memory, MemoryView, StoreMut, WasmPtr}; -pub struct CallerEnv<'s> { +pub struct JitCallerEnv<'s> { pub memory: Memory, pub store: StoreMut<'s>, pub wenv: &'s mut WasmEnv, } #[allow(dead_code)] -impl<'s> CallerEnv<'s> { +impl<'s> JitCallerEnv<'s> { + /// Returns the memory size, in bytes. + /// note: wasmer measures memory in 65536-byte pages. + fn memory_size(&self) -> u64 { + self.view().size().0 as u64 * 65536 + } + pub fn new(env: &'s mut WasmEnvMut) -> Self { let memory = env.data().memory.clone().unwrap(); let (data, store) = env.data_and_store_mut(); @@ -34,100 +42,113 @@ impl<'s> CallerEnv<'s> { self.memory.view(&self.store) } - /// Returns the memory size, in bytes. - /// note: wasmer measures memory in 65536-byte pages. - pub fn memory_size(&self) -> u64 { - self.view().size().0 as u64 * 65536 + pub fn caller_write_bytes20(&mut self, ptr: u32, val: Bytes20) { + self.caller_write_slice(ptr, val.as_slice()) + } + + pub fn caller_write_bytes32(&mut self, ptr: u32, val: Bytes32) { + self.caller_write_slice(ptr, val.as_slice()) + } + + pub fn caller_read_bytes20(&mut self, ptr: u32) -> Bytes20 { + self.caller_read_slice(ptr, 20).try_into().unwrap() + } + + pub fn caller_read_bytes32(&mut self, ptr: u32) -> Bytes32 { + self.caller_read_slice(ptr, 32).try_into().unwrap() + } + + pub fn caller_read_string(&mut self, ptr: u32, len: u32) -> String { + let bytes = self.caller_read_slice(ptr, len); + match String::from_utf8(bytes) { + Ok(s) => s, + Err(e) => { + let bytes = e.as_bytes(); + eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); + String::from_utf8_lossy(bytes).into_owned() + } + } } - pub fn caller_read_u8(&self, ptr: u32) -> u8 { + pub fn caller_read_slice(&self, ptr: u32, len: u32) -> Vec { + u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency + let len = u32::try_from(len).expect("length isn't a u32") as usize; + let mut data = vec![0; len]; + self.view() + .read(ptr.into(), &mut data) + .expect("failed to read"); + data + } + + pub fn caller_write_slice>(&self, ptr: T, src: &[u8]) + where + T::Error: Debug, + { + let ptr: u32 = ptr.try_into().expect("Go pointer not a u32"); + self.view().write(ptr.into(), src).unwrap(); + } +} + +impl CallerEnv<'_> for JitCallerEnv<'_> { + fn caller_read_u8(&self, ptr: u32) -> u8 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - pub fn caller_read_u16(&self, ptr: u32) -> u16 { + fn caller_read_u16(&self, ptr: u32) -> u16 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - pub fn caller_read_u32(&self, ptr: u32) -> u32 { + fn caller_read_u32(&self, ptr: u32) -> u32 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - pub fn caller_read_u64(&self, ptr: u32) -> u64 { + fn caller_read_u64(&self, ptr: u32) -> u64 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - pub fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { + fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - pub fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { + fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - pub fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { + fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - pub fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { + fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - pub fn caller_read_slice(&self, ptr: u32, len: u32) -> Vec { - u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency - let len = u32::try_from(len).expect("length isn't a u32") as usize; - let mut data = vec![0; len]; - self.view() - .read(ptr.into(), &mut data) - .expect("failed to read"); - data + fn caller_print_string(&mut self, ptr: u32, len: u32) { + let data = self.caller_read_string(ptr, len); + eprintln!("JIT: WASM says: {data}"); } - pub fn caller_write_slice>(&self, ptr: T, src: &[u8]) - where - T::Error: Debug, - { - let ptr: u32 = ptr.try_into().expect("Go pointer not a u32"); - self.view().write(ptr.into(), src).unwrap(); + fn caller_get_time(&self) -> u64 { + self.wenv.go_state.time } - pub fn caller_write_bytes20(&mut self, ptr: u32, val: Bytes20) { - self.caller_write_slice(ptr, val.as_slice()) + fn caller_advance_time(&mut self, delta: u64) { + self.wenv.go_state.time += delta } - pub fn caller_write_bytes32(&mut self, ptr: u32, val: Bytes32) { - self.caller_write_slice(ptr, val.as_slice()) - } - - pub fn caller_read_bytes20(&mut self, ptr: u32) -> Bytes20 { - self.caller_read_slice(ptr, 20).try_into().unwrap() - } - - pub fn caller_read_bytes32(&mut self, ptr: u32) -> Bytes32 { - self.caller_read_slice(ptr, 32).try_into().unwrap() - } - - pub fn caller_read_string(&mut self, ptr: u32, len: u32) -> String { - let bytes = self.caller_read_slice(ptr, len); - match String::from_utf8(bytes) { - Ok(s) => s, - Err(e) => { - let bytes = e.as_bytes(); - eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); - String::from_utf8_lossy(bytes).into_owned() - } - } + fn next_rand_u32(&mut self) -> u32 { + self.wenv.go_state.rng.next_u32() } } @@ -145,7 +166,7 @@ impl Default for GoRuntimeState { Self { time: 0, time_interval: 10_000_000, - rng: Pcg32::new(0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7), + rng: Pcg32::new(callerenv::PCG_INIT_STATE, callerenv::PCG_INIT_STREAM), } } } diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index c940aefc9..2c7afa0fd 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -1,9 +1,10 @@ // Copyright 2022-2023, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::callerenv::CallerEnv; +use crate::callerenv::JitCallerEnv; use crate::machine::{Escape, MaybeEscape, WasmEnvMut}; use crate::stylus_backend::exec_wasm; +use callerenv::CallerEnv; use arbutil::Bytes32; use arbutil::{evm::EvmData, format::DebugBytes, heapify}; use eyre::eyre; @@ -30,7 +31,7 @@ pub fn activate( err_buf: Uptr, err_buf_len: u32, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let wasm = caller_env.caller_read_slice(wasm_ptr, wasm_size); let debug = debug != 0; @@ -69,7 +70,7 @@ pub fn new_program( evm_data_handler: u64, gas: u64, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let compiled_hash = caller_env.caller_read_bytes32(compiled_hash_ptr); let calldata = caller_env.caller_read_slice(calldata_ptr, calldata_size); let evm_data: EvmData = unsafe { *Box::from_raw(evm_data_handler as *mut EvmData) }; @@ -106,7 +107,7 @@ pub fn new_program( /// module MUST match last module number returned from new_program /// returns request_id for the first request from the program pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); if caller_env.wenv.threads.len() as u32 != module || module == 0 { return Escape::hostio(format!( @@ -123,7 +124,7 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let thread = caller_env.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { @@ -137,7 +138,7 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); let thread = caller_env.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { @@ -158,7 +159,7 @@ pub fn set_response( raw_data_ptr: Uptr, raw_data_len: u32, ) -> MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); let result = caller_env.caller_read_slice(result_ptr, result_len); let raw_data = caller_env.caller_read_slice(raw_data_ptr, raw_data_len); @@ -170,7 +171,7 @@ pub fn set_response( // MUST be called right after set_response to the same id // returns request_id for the next request pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); let thread = caller_env.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != req_id { @@ -183,7 +184,7 @@ pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { // removes the last created program pub fn pop(mut env: WasmEnvMut) -> MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); match caller_env.wenv.threads.pop() { None => Err(Escape::Child(eyre!("no child"))), @@ -231,7 +232,7 @@ pub fn create_evm_data( tx_origin_ptr: Uptr, reentrant: u32, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let evm_data = EvmData { block_basefee: caller_env.caller_read_bytes32(block_basefee_ptr), diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 0e13e6cdf..0f522b320 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -1,305 +1,161 @@ // Copyright 2021-2023, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::callerenv::CallerEnv; +use crate::callerenv::JitCallerEnv; use crate::machine::{Escape, WasmEnvMut}; -use rand::RngCore; - -type Errno = u16; - -type Uptr = u32; - -const ERRNO_SUCCESS: Errno = 0; -const ERRNO_BADF: Errno = 8; -const ERRNO_INTVAL: Errno = 28; +use callerenv::{ + self, + wasip1_stub::{Errno, Uptr}, +}; pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { Err(Escape::Exit(code)) } -pub fn environ_sizes_get( - mut env: WasmEnvMut, - length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Result { - let mut caller_env = CallerEnv::new(&mut env); +macro_rules! wrap { + ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { + let caller_env = JitCallerEnv::new(&mut src); - caller_env.caller_write_u32(length_ptr, 0); - caller_env.caller_write_u32(data_size_ptr, 0); - Ok(ERRNO_SUCCESS) + Ok(callerenv::wasip1_stub::$func_name(caller_env, $($arg_name),*)) + } + }; } -pub fn fd_write( - mut env: WasmEnvMut, +wrap!(clock_time_get( + clock_id: u32, + precision: u64, + time_ptr: Uptr +) -> Errno); + +wrap!(random_get(buf: Uptr, len: u32) -> Errno); + +wrap!(environ_sizes_get(length_ptr: Uptr, data_size_ptr: Uptr) -> Errno); +wrap!(fd_write( fd: u32, iovecs_ptr: Uptr, iovecs_len: u32, - ret_ptr: Uptr, -) -> Result { - let mut caller_env = CallerEnv::new(&mut env); - - if fd != 1 && fd != 2 { - return Ok(ERRNO_BADF); - } - let mut size = 0; - for i in 0..iovecs_len { - let ptr = iovecs_ptr + i * 8; - let iovec = caller_env.caller_read_u32(ptr); - let len = caller_env.caller_read_u32(ptr + 4); - let data = caller_env.caller_read_string(iovec, len); - eprintln!("JIT: WASM says [{fd}]: {data}"); - size += len; - } - caller_env.caller_write_u32(ret_ptr, size); - Ok(ERRNO_SUCCESS) -} - -pub fn environ_get(mut _env: WasmEnvMut, _: u32, _: u32) -> Result { - Ok(ERRNO_INTVAL) -} - -pub fn fd_close(mut _env: WasmEnvMut, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_read(mut _env: WasmEnvMut, _: u32, _: u32, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_readdir( - mut _env: WasmEnvMut, - _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} + ret_ptr: Uptr +) -> Errno); +wrap!(environ_get(a: u32, b: u32) -> Errno); +wrap!(fd_close(fd: u32) -> Errno); +wrap!(fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno); +wrap!(fd_readdir( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 +) -> Errno); -pub fn fd_sync(mut _env: WasmEnvMut, _: u32) -> Result { - Ok(ERRNO_SUCCESS) -} +wrap!(fd_sync(a: u32) -> Errno); -pub fn fd_seek( - mut _env: WasmEnvMut, +wrap!(fd_seek( _fd: u32, _offset: u64, _whence: u8, - _filesize: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_datasync(mut _env: WasmEnvMut, _fd: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_open( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u64, - _: u64, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_create_directory( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_remove_directory( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_readlink( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_rename( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_filestat_get( - mut _env: WasmEnvMut, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn path_unlink_file(mut _env: WasmEnvMut, _: u32, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_prestat_get(mut _env: WasmEnvMut, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_prestat_dir_name(mut _env: WasmEnvMut, _: u32, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_filestat_get(mut _env: WasmEnvMut, _fd: u32, _filestat: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_filestat_set_size(mut _env: WasmEnvMut, _fd: u32, _: u64) -> Result { - Ok(ERRNO_BADF) -} - -pub fn fd_pread( - mut _env: WasmEnvMut, + _filesize: u32 +) -> Errno); + +wrap!(fd_datasync(_fd: u32) -> Errno); + +wrap!(path_open( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u64, + g: u64, + h: u32, + i: u32 +) -> Errno); + +wrap!(path_create_directory( + a: u32, + b: u32, + c: u32 +) -> Errno); + +wrap!(path_remove_directory( + a: u32, + b: u32, + c: u32 +) -> Errno); + +wrap!(path_readlink( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 +) -> Errno); + +wrap!(path_rename( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 +) -> Errno); + +wrap!(path_filestat_get( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32 +) -> Errno); + +wrap!(path_unlink_file(a: u32, b: u32, c: u32) -> Errno); + +wrap!(fd_prestat_get(a: u32, b: u32) -> Errno); + +wrap!(fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno); + +wrap!(fd_filestat_get(_fd: u32, _filestat: u32) -> Errno); + +wrap!(fd_filestat_set_size(_fd: u32, size: u64) -> Errno); + +wrap!(fd_pread( _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} + _a: u32, + _b: u32, + _c: u64, + _d: u32 +) -> Errno); -pub fn fd_pwrite( - mut _env: WasmEnvMut, +wrap!(fd_pwrite( _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Result { - Ok(ERRNO_BADF) -} - -pub fn sock_accept(mut _env: WasmEnvMut, _fd: u32, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn sock_shutdown(mut _env: WasmEnvMut, _: u32, _: u32) -> Result { - Ok(ERRNO_BADF) -} - -pub fn sched_yield(mut _env: WasmEnvMut) -> Result { - Ok(ERRNO_SUCCESS) -} + _a: u32, + _b: u32, + _c: u64, + _d: u32 +) -> Errno); -pub fn clock_time_get( - mut env: WasmEnvMut, - _clock_id: u32, - _precision: u64, - time: Uptr, -) -> Result { - let mut caller_env = CallerEnv::new(&mut env); - caller_env.wenv.go_state.time += caller_env.wenv.go_state.time_interval; - caller_env.caller_write_u32(time, caller_env.wenv.go_state.time as u32); - caller_env.caller_write_u32(time + 4, (caller_env.wenv.go_state.time >> 32) as u32); - Ok(ERRNO_SUCCESS) -} +wrap!(sock_accept(_fd: u32, a: u32, b: u32) -> Errno); -pub fn random_get(mut env: WasmEnvMut, mut buf: u32, mut len: u32) -> Result { - let mut caller_env = CallerEnv::new(&mut env); +wrap!(sock_shutdown(a: u32, b: u32) -> Errno); - while len >= 4 { - let next_rand = caller_env.wenv.go_state.rng.next_u32(); - caller_env.caller_write_u32(buf, next_rand); - buf += 4; - len -= 4; - } - if len > 0 { - let mut rem = caller_env.wenv.go_state.rng.next_u32(); - for _ in 0..len { - caller_env.caller_write_u8(buf, rem as u8); - buf += 1; - rem >>= 8; - } - } - Ok(ERRNO_SUCCESS) -} +wrap!(sched_yield() -> Errno); -pub fn args_sizes_get( - mut env: WasmEnvMut, +wrap!(args_sizes_get( length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Result { - let mut caller_env = CallerEnv::new(&mut env); - caller_env.caller_write_u32(length_ptr, 1); - caller_env.caller_write_u32(data_size_ptr, 4); - Ok(ERRNO_SUCCESS) -} - -pub fn args_get(mut env: WasmEnvMut, argv_buf: Uptr, data_buf: Uptr) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + data_size_ptr: Uptr +) -> Errno); - caller_env.caller_write_u32(argv_buf, data_buf as u32); - caller_env.caller_write_u32(data_buf, 0x6E6962); // "bin\0" - Ok(ERRNO_SUCCESS) -} +wrap!(args_get(argv_buf: Uptr, data_buf: Uptr) -> Errno); // we always simulate a timeout -pub fn poll_oneoff( - mut env: WasmEnvMut, +wrap!(poll_oneoff( in_subs: Uptr, out_evt: Uptr, nsubscriptions: u32, - nevents_ptr: Uptr, -) -> Result { - let mut caller_env = CallerEnv::new(&mut env); - - const SUBSCRIPTION_SIZE: u32 = 48; - for i in 0..nsubscriptions { - let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); - let subs_type = caller_env.caller_read_u32(subs_base + 8); - if subs_type != 0 { - // not a clock subscription type - continue; - } - let user_data = caller_env.caller_read_u32(subs_base); - caller_env.caller_write_u32(out_evt, user_data); - caller_env.caller_write_u32(out_evt + 8, 0); - caller_env.caller_write_u32(nevents_ptr, 1); - return Ok(ERRNO_SUCCESS); - } - Ok(ERRNO_INTVAL) -} + nevents_ptr: Uptr +) -> Errno); -pub fn fd_fdstat_get(mut _env: WasmEnvMut, _: u32, _: u32) -> Result { - Ok(ERRNO_INTVAL) -} +wrap!(fd_fdstat_get(a: u32, b: u32) -> Errno); -pub fn fd_fdstat_set_flags(mut _env: WasmEnvMut, _: u32, _: u32) -> Result { - Ok(ERRNO_INTVAL) -} +wrap!(fd_fdstat_set_flags(a: u32, b: u32) -> Errno); diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index 3cb65cd93..fd79f4775 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -2,7 +2,7 @@ // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::{ - callerenv::CallerEnv, + callerenv::JitCallerEnv, machine::{Escape, MaybeEscape, WasmEnv, WasmEnvMut}, socket, }; @@ -19,7 +19,7 @@ type Uptr = u32; /// Reads 32-bytes of global state pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; let global = match caller_env.wenv.large_globals.get(idx as usize) { @@ -32,7 +32,7 @@ pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> /// Writes 32-bytes of global state pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; let slice = caller_env.caller_read_slice(src_ptr, 32); @@ -48,7 +48,7 @@ pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> /// Reads 8-bytes of global state pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; match caller_env.wenv.small_globals.get(idx as usize) { @@ -59,7 +59,7 @@ pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result MaybeEscape { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; match caller_env.wenv.small_globals.get_mut(idx as usize) { @@ -78,7 +78,7 @@ pub fn read_inbox_message( offset: u32, out_ptr: Uptr, ) -> Result { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; let message = match caller_env.wenv.sequencer_messages.get(&msg_num) { @@ -99,7 +99,7 @@ pub fn read_delayed_inbox_message( offset: u32, out_ptr: Uptr, ) -> Result { - let caller_env = CallerEnv::new(&mut env); + let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; let message = match caller_env.wenv.delayed_messages.get(&msg_num) { @@ -120,7 +120,7 @@ pub fn resolve_preimage( offset: u32, out_ptr: Uptr, ) -> Result { - let mut caller_env = CallerEnv::new(&mut env); + let mut caller_env = JitCallerEnv::new(&mut env); let name = "wavmio.resolvePreImage"; diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 114843201..2b7c3cad7 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -132,6 +132,10 @@ dependencies = [ "syn 1.0.107", ] +[[package]] +name = "callerenv" +version = "0.1.0" + [[package]] name = "cfg-if" version = "1.0.0" @@ -692,6 +696,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1259,6 +1269,8 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" name = "wasi-stub" version = "0.1.0" dependencies = [ + "callerenv", + "paste", "rand", "rand_pcg", ] diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index 154a438fe..8c0a45646 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -8,5 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] +paste = {versoion="1.0.14"} +callerenv = { path = "../../callerenv/" } rand = { version = "0.8.4", default-features = false } rand_pcg = { version = "0.3.1", default-features = false } diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 05fd24139..67200637b 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -4,16 +4,14 @@ #![no_std] use rand::RngCore; +use paste::paste; +use callerenv::{ + self, + wasip1_stub::{Errno, Uptr, ERRNO_SUCCESS, ERRNO_BADF, ERRNO_INTVAL}, + CallerEnv, +}; use rand_pcg::Pcg32; -type Errno = u16; - -type Uptr = usize; - -const ERRNO_SUCCESS: Errno = 0; -const ERRNO_BADF: Errno = 8; -const ERRNO_INTVAL: Errno = 28; - #[allow(dead_code)] extern "C" { fn wavm_caller_load8(ptr: Uptr) -> u8; @@ -37,327 +35,231 @@ pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { } } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__environ_sizes_get( - length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Errno { - wavm_caller_store32(length_ptr, 0); - wavm_caller_store32(data_size_ptr, 0); - ERRNO_SUCCESS -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_write( - fd: usize, - iovecs_ptr: Uptr, - iovecs_len: usize, - ret_ptr: Uptr, -) -> Errno { - if fd != 1 && fd != 2 { - return ERRNO_BADF; - } - let mut size = 0; - for i in 0..iovecs_len { - let ptr = iovecs_ptr + i * 8; - size += wavm_caller_load32(ptr + 4); - } - wavm_caller_store32(ret_ptr, size); - ERRNO_SUCCESS -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__environ_get(_: usize, _: usize) -> Errno { - ERRNO_INTVAL -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_close(_: usize) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_read( - _: usize, - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_readdir( - _fd: usize, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_sync( - _: u32, -) -> Errno { - ERRNO_SUCCESS -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_seek( - _fd: usize, - _offset: u64, - _whence: u8, - _filesize: usize, -) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_datasync(_fd: usize) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_open( - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, - _: u64, - _: u64, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} - -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_create_directory( - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} +static mut TIME: u64 = 0; +static mut RNG: Option = None; -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_remove_directory( - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} +#[derive(Default)] +struct StaticCallerEnv{} -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_readlink( - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} +impl CallerEnv<'static> for StaticCallerEnv { + fn caller_read_u8(&self, ptr: u32) -> u8 { + unsafe { + wavm_caller_load8(ptr) + } + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_rename( - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} + fn caller_read_u16(&self, ptr: u32) -> u16 { + let lsb = self.caller_read_u8(ptr); + let msb = self.caller_read_u8(ptr+1); + (msb as u16) << 8 | (lsb as u16) + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_filestat_get( - _: usize, - _: usize, - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} + fn caller_read_u32(&self, ptr: u32) -> u32 { + let lsb = self.caller_read_u16(ptr); + let msb = self.caller_read_u16(ptr+2); + (msb as u32) << 16 | (lsb as u32) + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__path_unlink_file( - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} + fn caller_read_u64(&self, ptr: u32) -> u64 { + let lsb = self.caller_read_u32(ptr); + let msb = self.caller_read_u32(ptr+4); + (msb as u64) << 32 | (lsb as u64) + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_prestat_get(_: usize, _: usize) -> Errno { - ERRNO_BADF -} + fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { + unsafe { + wavm_caller_store8(ptr, x); + } + self + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_prestat_dir_name( - _: usize, - _: usize, - _: usize, -) -> Errno { - ERRNO_BADF -} + fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { + self.caller_write_u8(ptr, (x & 0xff) as u8); + self.caller_write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); + self + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_filestat_get( - _fd: usize, - _filestat: usize, -) -> Errno { - ERRNO_BADF -} + fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { + self.caller_write_u16(ptr, (x & 0xffff) as u16); + self.caller_write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); + self + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_filestat_set_size( - _fd: usize, - _: u64, -) -> Errno { - ERRNO_BADF -} + fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { + self.caller_write_u32(ptr, (x & 0xffffffff) as u32); + self.caller_write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); + self + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_pread( - _fd: usize, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} + fn caller_print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_pwrite( - _fd: usize, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} + fn caller_get_time(&self) -> u64 { + unsafe { + TIME + } + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__sock_accept( - _fd: usize, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} + fn caller_advance_time(&mut self, delta: u64) { + unsafe { + TIME += delta + } + } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__sock_shutdown( - _: usize, - _: u32, -) -> Errno { - ERRNO_BADF + fn next_rand_u32(&mut self) -> u32 { + unsafe { + RNG.get_or_insert_with(|| Pcg32::new(callerenv::PCG_INIT_STATE, callerenv::PCG_INIT_STREAM)) + } + .next_u32() + } } -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__sched_yield() -> Errno { - ERRNO_SUCCESS -} -// An increasing clock, measured in nanoseconds. -static mut TIME: u64 = 0; -// The amount of TIME advanced each check. Currently 10 milliseconds. -static TIME_INTERVAL: u64 = 10_000_000; +macro_rules! wrap { + ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + paste! { + #[no_mangle] + pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { + let caller_env = StaticCallerEnv::default(); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__clock_time_get( - _clock_id: usize, - _precision: u64, - time: Uptr, -) -> Errno { - TIME += TIME_INTERVAL; - wavm_caller_store32(time, TIME as u32); - wavm_caller_store32(time + 4, (TIME >> 32) as u32); - ERRNO_SUCCESS + callerenv::wasip1_stub::$func_name(caller_env, $($arg_name),*) + } + } + }; } -static mut RNG: Option = None; - -unsafe fn get_rng<'a>() -> &'a mut Pcg32 { - RNG.get_or_insert_with(|| Pcg32::new(0xcafef00dd15ea5e5, 0xa02bdbf7bb3c0a7)) -} +wrap!(clock_time_get( + clock_id: u32, + precision: u64, + time_ptr: Uptr +) -> Errno); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__random_get(mut buf: usize, mut len: usize) -> Errno { - let rng = get_rng(); - while len >= 4 { - wavm_caller_store32(buf, rng.next_u32()); - buf += 4; - len -= 4; - } - if len > 0 { - let mut rem = rng.next_u32(); - for _ in 0..len { - wavm_caller_store8(buf, rem as u8); - buf += 1; - rem >>= 8; - } - } - ERRNO_SUCCESS -} +wrap!(random_get(buf: Uptr, len: u32) -> Errno); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__args_sizes_get( +wrap!(environ_sizes_get(length_ptr: Uptr, data_size_ptr: Uptr) -> Errno); +wrap!(fd_write( + fd: u32, + iovecs_ptr: Uptr, + iovecs_len: u32, + ret_ptr: Uptr +) -> Errno); +wrap!(environ_get(a: u32, b: u32) -> Errno); +wrap!(fd_close(fd: u32) -> Errno); +wrap!(fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno); +wrap!(fd_readdir( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 +) -> Errno); + +wrap!(fd_sync(a: u32) -> Errno); + +wrap!(fd_seek( + _fd: u32, + _offset: u64, + _whence: u8, + _filesize: u32 +) -> Errno); + +wrap!(fd_datasync(_fd: u32) -> Errno); + +wrap!(path_open( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u64, + g: u64, + h: u32, + i: u32 +) -> Errno); + +wrap!(path_create_directory( + a: u32, + b: u32, + c: u32 +) -> Errno); + +wrap!(path_remove_directory( + a: u32, + b: u32, + c: u32 +) -> Errno); + +wrap!(path_readlink( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 +) -> Errno); + +wrap!(path_rename( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 +) -> Errno); + +wrap!(path_filestat_get( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32 +) -> Errno); + +wrap!(path_unlink_file(a: u32, b: u32, c: u32) -> Errno); + +wrap!(fd_prestat_get(a: u32, b: u32) -> Errno); + +wrap!(fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno); + +wrap!(fd_filestat_get(_fd: u32, _filestat: u32) -> Errno); + +wrap!(fd_filestat_set_size(_fd: u32, size: u64) -> Errno); + +wrap!(fd_pread( + _fd: u32, + _a: u32, + _b: u32, + _c: u64, + _d: u32 +) -> Errno); + +wrap!(fd_pwrite( + _fd: u32, + _a: u32, + _b: u32, + _c: u64, + _d: u32 +) -> Errno); + +wrap!(sock_accept(_fd: u32, a: u32, b: u32) -> Errno); + +wrap!(sock_shutdown(a: u32, b: u32) -> Errno); + +wrap!(sched_yield() -> Errno); + +wrap!(args_sizes_get( length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Errno { - wavm_caller_store32(length_ptr, 1); - wavm_caller_store32(data_size_ptr, 4); - ERRNO_SUCCESS -} + data_size_ptr: Uptr +) -> Errno); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__args_get( - argv_buf: Uptr, - data_buf: Uptr -) -> Errno { - wavm_caller_store32(argv_buf, data_buf as u32); - wavm_caller_store32(data_buf, 0x6E6962); // "bin\0" - ERRNO_SUCCESS -} +wrap!(args_get(argv_buf: Uptr, data_buf: Uptr) -> Errno); -#[no_mangle] -// we always simulate a timeout -pub unsafe extern "C" fn wasi_snapshot_preview1__poll_oneoff(in_subs: Uptr, out_evt: Uptr, nsubscriptions: usize, nevents_ptr: Uptr) -> Errno { - const SUBSCRIPTION_SIZE: usize = 48; - for i in 0..nsubscriptions { - let subs_base = in_subs + (SUBSCRIPTION_SIZE * i); - let subs_type = wavm_caller_load32(subs_base + 8); - if subs_type != 0 { - // not a clock subscription type - continue - } - let user_data = wavm_caller_load32(subs_base); - wavm_caller_store32(out_evt, user_data); - wavm_caller_store32(out_evt + 8, 0); - wavm_caller_store32(nevents_ptr, 1); - return ERRNO_SUCCESS; - } - ERRNO_INTVAL -} +wrap!(poll_oneoff( + in_subs: Uptr, + out_evt: Uptr, + nsubscriptions: u32, + nevents_ptr: Uptr +) -> Errno); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_fdstat_get(_: usize, _: usize) -> Errno { - ERRNO_INTVAL -} +wrap!(fd_fdstat_get(a: u32, b: u32) -> Errno); -#[no_mangle] -pub unsafe extern "C" fn wasi_snapshot_preview1__fd_fdstat_set_flags(_: usize, _: usize) -> Errno { - ERRNO_INTVAL -} +wrap!(fd_fdstat_set_flags(a: u32, b: u32) -> Errno); From 54c84d06b50e686386ca87b1307d49d23425f0da Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 28 Feb 2024 10:07:15 -0700 Subject: [PATCH 02/28] caller_env cosmetics --- arbitrator/Cargo.lock | 3 + .../arbutil/src/callerenv/wasip1_stub.rs | 292 ++++++++++++++++++ arbitrator/callerenv/Cargo.toml | 1 + arbitrator/callerenv/src/lib.rs | 31 +- arbitrator/callerenv/src/wasip1_stub.rs | 38 +-- arbitrator/jit/src/arbcompress.rs | 16 +- arbitrator/jit/src/callerenv.rs | 53 ++-- arbitrator/jit/src/program.rs | 50 +-- arbitrator/jit/src/wavmio.rs | 12 +- .../wasm-libraries/wasi-stub/src/lib.rs | 50 +-- 10 files changed, 422 insertions(+), 124 deletions(-) create mode 100644 arbitrator/arbutil/src/callerenv/wasip1_stub.rs diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 30af8d02e..2f41f4b5e 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -205,6 +205,9 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "callerenv" version = "0.1.0" +dependencies = [ + "rand_pcg", +] [[package]] name = "cc" diff --git a/arbitrator/arbutil/src/callerenv/wasip1_stub.rs b/arbitrator/arbutil/src/callerenv/wasip1_stub.rs new file mode 100644 index 000000000..f9e10ab5d --- /dev/null +++ b/arbitrator/arbutil/src/callerenv/wasip1_stub.rs @@ -0,0 +1,292 @@ +use crate::callerenv::CallerEnv; + +pub type Errno = u16; + +pub type Uptr = u32; + +pub const ERRNO_SUCCESS: Errno = 0; +pub const ERRNO_BADF: Errno = 8; +pub const ERRNO_INTVAL: Errno = 28; + +pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( + mut caller_env: E, + length_ptr: Uptr, + data_size_ptr: Uptr, +) -> Errno { + caller_env.write_u32(length_ptr, 0); + caller_env.write_u32(data_size_ptr, 0); + ERRNO_SUCCESS +} + +pub fn fd_write<'a, E: CallerEnv<'a>>( + mut caller_env: E, + fd: u32, + iovecs_ptr: Uptr, + iovecs_len: u32, + ret_ptr: Uptr, +) -> Errno { + if fd != 1 && fd != 2 { + return ERRNO_BADF; + } + let mut size = 0; + for i in 0..iovecs_len { + let ptr = iovecs_ptr + i * 8; + let iovec = caller_env.read_u32(ptr); + let len = caller_env.read_u32(ptr + 4); + caller_env.print_string(iovec, len); + size += len; + } + caller_env.write_u32(ret_ptr, size); + ERRNO_SUCCESS +} + +pub fn environ_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} + +pub fn fd_close<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_read<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_readdir<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_sync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { + ERRNO_SUCCESS +} + +pub fn fd_seek<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _offset: u64, + _whence: u8, + _filesize: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_datasync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32) -> Errno { + ERRNO_BADF +} + +pub fn path_open<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u64, + _: u64, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_create_directory<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_remove_directory<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_readlink<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_rename<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_filestat_get<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn path_unlink_file<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _: u32, + _: u32, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_filestat_get<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _filestat: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u64) -> Errno { + ERRNO_BADF +} + +pub fn fd_pread<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn fd_pwrite<'a, E: CallerEnv<'a>>( + mut _caller_env: E, + _fd: u32, + _: u32, + _: u32, + _: u64, + _: u32, +) -> Errno { + ERRNO_BADF +} + +pub fn sock_accept<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn sock_shutdown<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_BADF +} + +pub fn sched_yield<'a, E: CallerEnv<'a>>(mut _caller_env: E) -> Errno { + ERRNO_SUCCESS +} + +// pub fn clock_time_get<'a, E: CallerEnv<'a>>( +// mut caller_env: E, +// _clock_id: u32, +// _precision: u64, +// time: Uptr, +// ) -> Errno { +// caller_env.wenv.go_state.time += caller_env.wenv.go_state.time_interval; +// caller_env.write_u32(time, caller_env.wenv.go_state.time as u32); +// caller_env.write_u32(time + 4, (caller_env.wenv.go_state.time >> 32) as u32); +// ERRNO_SUCCESS +// } + +// pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len: u32) -> Errno { +// while len >= 4 { +// let next_rand = caller_env.wenv.go_state.rng.next_u32(); +// caller_env.write_u32(buf, next_rand); +// buf += 4; +// len -= 4; +// } +// if len > 0 { +// let mut rem = caller_env.wenv.go_state.rng.next_u32(); +// for _ in 0..len { +// caller_env.write_u8(buf, rem as u8); +// buf += 1; +// rem >>= 8; +// } +// } +// ERRNO_SUCCESS +// } + +pub fn args_sizes_get<'a, E: CallerEnv<'a>>( + mut caller_env: E, + length_ptr: Uptr, + data_size_ptr: Uptr, +) -> Errno { + caller_env.write_u32(length_ptr, 1); + caller_env.write_u32(data_size_ptr, 4); + ERRNO_SUCCESS +} + +pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_buf: Uptr) -> Errno { + caller_env.write_u32(argv_buf, data_buf as u32); + caller_env.write_u32(data_buf, 0x6E6962); // "bin\0" + ERRNO_SUCCESS +} + +// we always simulate a timeout +pub fn poll_oneoff<'a, E: CallerEnv<'a>>( + mut caller_env: E, + in_subs: Uptr, + out_evt: Uptr, + nsubscriptions: u32, + nevents_ptr: Uptr, +) -> Errno { + const SUBSCRIPTION_SIZE: u32 = 48; + for i in 0..nsubscriptions { + let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); + let subs_type = caller_env.read_u32(subs_base + 8); + if subs_type != 0 { + // not a clock subscription type + continue; + } + let user_data = caller_env.read_u32(subs_base); + caller_env.write_u32(out_evt, user_data); + caller_env.write_u32(out_evt + 8, 0); + caller_env.write_u32(nevents_ptr, 1); + return ERRNO_SUCCESS; + } + ERRNO_INTVAL +} + +pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} + +pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { + ERRNO_INTVAL +} diff --git a/arbitrator/callerenv/Cargo.toml b/arbitrator/callerenv/Cargo.toml index 6640c5da2..5db7c7cc4 100644 --- a/arbitrator/callerenv/Cargo.toml +++ b/arbitrator/callerenv/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +rand_pcg = { version = "0.3.1", default-features = false } [features] wavm = [] diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs index 9e7a1c127..872a61d21 100644 --- a/arbitrator/callerenv/src/lib.rs +++ b/arbitrator/callerenv/src/lib.rs @@ -1,33 +1,38 @@ #![no_std] +use rand_pcg::Pcg32; pub mod wasip1_stub; -pub const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; -pub const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; +const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; +const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; + +pub fn create_pcg() -> Pcg32 { + Pcg32::new(PCG_INIT_STATE, PCG_INIT_STREAM) +} pub trait CallerEnv<'a> { - fn caller_read_u8(&self, ptr: u32) -> u8; + fn read_u8(&self, ptr: u32) -> u8; - fn caller_read_u16(&self, ptr: u32) -> u16; + fn read_u16(&self, ptr: u32) -> u16; - fn caller_read_u32(&self, ptr: u32) -> u32; + fn read_u32(&self, ptr: u32) -> u32; - fn caller_read_u64(&self, ptr: u32) -> u64; + fn read_u64(&self, ptr: u32) -> u64; - fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self; + fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self; - fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self; + fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self; - fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self; + fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self; - fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self; + fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self; - fn caller_print_string(&mut self, ptr: u32, len: u32); + fn print_string(&mut self, ptr: u32, len: u32); - fn caller_get_time(&self) -> u64; + fn get_time(&self) -> u64; - fn caller_advance_time(&mut self, delta: u64); + fn advance_time(&mut self, delta: u64); fn next_rand_u32(&mut self) -> u32; } diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/callerenv/src/wasip1_stub.rs index 226bbeb77..c6b8d7a13 100644 --- a/arbitrator/callerenv/src/wasip1_stub.rs +++ b/arbitrator/callerenv/src/wasip1_stub.rs @@ -13,8 +13,8 @@ pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { - caller_env.caller_write_u32(length_ptr, 0); - caller_env.caller_write_u32(data_size_ptr, 0); + caller_env.write_u32(length_ptr, 0); + caller_env.write_u32(data_size_ptr, 0); ERRNO_SUCCESS } @@ -31,12 +31,12 @@ pub fn fd_write<'a, E: CallerEnv<'a>>( let mut size = 0; for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; - let iovec = caller_env.caller_read_u32(ptr); - let len = caller_env.caller_read_u32(ptr + 4); - caller_env.caller_print_string(iovec, len); + let iovec = caller_env.read_u32(ptr); + let len = caller_env.read_u32(ptr + 4); + caller_env.print_string(iovec, len); size += len; } - caller_env.caller_write_u32(ret_ptr, size); + caller_env.write_u32(ret_ptr, size); ERRNO_SUCCESS } @@ -220,22 +220,22 @@ pub fn clock_time_get<'a, E: CallerEnv<'a>>( _precision: u64, time_ptr: Uptr, ) -> Errno { - caller_env.caller_advance_time(TIME_INTERVAL); - caller_env.caller_write_u64(time_ptr, caller_env.caller_get_time()); + caller_env.advance_time(TIME_INTERVAL); + caller_env.write_u64(time_ptr, caller_env.get_time()); ERRNO_SUCCESS } pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len: u32) -> Errno { while len >= 4 { let next_rand = caller_env.next_rand_u32(); - caller_env.caller_write_u32(buf, next_rand); + caller_env.write_u32(buf, next_rand); buf += 4; len -= 4; } if len > 0 { let mut rem = caller_env.next_rand_u32(); for _ in 0..len { - caller_env.caller_write_u8(buf, rem as u8); + caller_env.write_u8(buf, rem as u8); buf += 1; rem >>= 8; } @@ -248,14 +248,14 @@ pub fn args_sizes_get<'a, E: CallerEnv<'a>>( length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { - caller_env.caller_write_u32(length_ptr, 1); - caller_env.caller_write_u32(data_size_ptr, 4); + caller_env.write_u32(length_ptr, 1); + caller_env.write_u32(data_size_ptr, 4); ERRNO_SUCCESS } pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_buf: Uptr) -> Errno { - caller_env.caller_write_u32(argv_buf, data_buf as u32); - caller_env.caller_write_u32(data_buf, 0x6E6962); // "bin\0" + caller_env.write_u32(argv_buf, data_buf as u32); + caller_env.write_u32(data_buf, 0x6E6962); // "bin\0" ERRNO_SUCCESS } @@ -270,15 +270,15 @@ pub fn poll_oneoff<'a, E: CallerEnv<'a>>( const SUBSCRIPTION_SIZE: u32 = 48; for i in 0..nsubscriptions { let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); - let subs_type = caller_env.caller_read_u32(subs_base + 8); + let subs_type = caller_env.read_u32(subs_base + 8); if subs_type != 0 { // not a clock subscription type continue; } - let user_data = caller_env.caller_read_u32(subs_base); - caller_env.caller_write_u32(out_evt, user_data); - caller_env.caller_write_u32(out_evt + 8, 0); - caller_env.caller_write_u32(nevents_ptr, 1); + let user_data = caller_env.read_u32(subs_base); + caller_env.write_u32(out_evt, user_data); + caller_env.write_u32(out_evt + 8, 0); + caller_env.write_u32(nevents_ptr, 1); return ERRNO_SUCCESS; } ERRNO_INTVAL diff --git a/arbitrator/jit/src/arbcompress.rs b/arbitrator/jit/src/arbcompress.rs index a9cb3cba2..2c14a095d 100644 --- a/arbitrator/jit/src/arbcompress.rs +++ b/arbitrator/jit/src/arbcompress.rs @@ -49,8 +49,8 @@ pub fn brotli_decompress( out_len_ptr: Uptr, ) -> Result { let mut caller_env = JitCallerEnv::new(&mut env); - let in_slice = caller_env.caller_read_slice(in_buf_ptr, in_buf_len); - let orig_output_len = caller_env.caller_read_u32(out_len_ptr) as usize; + let in_slice = caller_env.read_slice(in_buf_ptr, in_buf_len); + let orig_output_len = caller_env.read_u32(out_len_ptr) as usize; let mut output = vec![0u8; orig_output_len as usize]; let mut output_len = orig_output_len; unsafe { @@ -64,8 +64,8 @@ pub fn brotli_decompress( return Ok(0); } } - caller_env.caller_write_slice(out_buf_ptr, &output[..output_len]); - caller_env.caller_write_u32(out_len_ptr, output_len as u32); + caller_env.write_slice(out_buf_ptr, &output[..output_len]); + caller_env.write_u32(out_len_ptr, output_len as u32); Ok(1) } @@ -82,8 +82,8 @@ pub fn brotli_compress( window_size: u32, ) -> Result { let mut caller_env = JitCallerEnv::new(&mut env); - let in_slice = caller_env.caller_read_slice(in_buf_ptr, in_buf_len); - let orig_output_len = caller_env.caller_read_u32(out_len_ptr) as usize; + let in_slice = caller_env.read_slice(in_buf_ptr, in_buf_len); + let orig_output_len = caller_env.read_u32(out_len_ptr) as usize; let mut output = vec![0u8; orig_output_len]; let mut output_len = orig_output_len; @@ -101,7 +101,7 @@ pub fn brotli_compress( return Ok(0); } } - caller_env.caller_write_slice(out_buf_ptr, &output[..output_len]); - caller_env.caller_write_u32(out_len_ptr, output_len as u32); + caller_env.write_slice(out_buf_ptr, &output[..output_len]); + caller_env.write_u32(out_len_ptr, output_len as u32); Ok(1) } diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index 07894cad1..a6acc4b11 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -42,24 +42,24 @@ impl<'s> JitCallerEnv<'s> { self.memory.view(&self.store) } - pub fn caller_write_bytes20(&mut self, ptr: u32, val: Bytes20) { - self.caller_write_slice(ptr, val.as_slice()) + pub fn write_bytes20(&mut self, ptr: u32, val: Bytes20) { + self.write_slice(ptr, val.as_slice()) } - pub fn caller_write_bytes32(&mut self, ptr: u32, val: Bytes32) { - self.caller_write_slice(ptr, val.as_slice()) + pub fn write_bytes32(&mut self, ptr: u32, val: Bytes32) { + self.write_slice(ptr, val.as_slice()) } - pub fn caller_read_bytes20(&mut self, ptr: u32) -> Bytes20 { - self.caller_read_slice(ptr, 20).try_into().unwrap() + pub fn read_bytes20(&mut self, ptr: u32) -> Bytes20 { + self.read_slice(ptr, 20).try_into().unwrap() } - pub fn caller_read_bytes32(&mut self, ptr: u32) -> Bytes32 { - self.caller_read_slice(ptr, 32).try_into().unwrap() + pub fn read_bytes32(&mut self, ptr: u32) -> Bytes32 { + self.read_slice(ptr, 32).try_into().unwrap() } - pub fn caller_read_string(&mut self, ptr: u32, len: u32) -> String { - let bytes = self.caller_read_slice(ptr, len); + pub fn read_string(&mut self, ptr: u32, len: u32) -> String { + let bytes = self.read_slice(ptr, len); match String::from_utf8(bytes) { Ok(s) => s, Err(e) => { @@ -70,7 +70,7 @@ impl<'s> JitCallerEnv<'s> { } } - pub fn caller_read_slice(&self, ptr: u32, len: u32) -> Vec { + pub fn read_slice(&self, ptr: u32, len: u32) -> Vec { u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency let len = u32::try_from(len).expect("length isn't a u32") as usize; let mut data = vec![0; len]; @@ -80,7 +80,7 @@ impl<'s> JitCallerEnv<'s> { data } - pub fn caller_write_slice>(&self, ptr: T, src: &[u8]) + pub fn write_slice>(&self, ptr: T, src: &[u8]) where T::Error: Debug, { @@ -90,60 +90,60 @@ impl<'s> JitCallerEnv<'s> { } impl CallerEnv<'_> for JitCallerEnv<'_> { - fn caller_read_u8(&self, ptr: u32) -> u8 { + fn read_u8(&self, ptr: u32) -> u8 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn caller_read_u16(&self, ptr: u32) -> u16 { + fn read_u16(&self, ptr: u32) -> u16 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn caller_read_u32(&self, ptr: u32) -> u32 { + fn read_u32(&self, ptr: u32) -> u32 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn caller_read_u64(&self, ptr: u32) -> u64 { + fn read_u64(&self, ptr: u32) -> u64 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { + fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { + fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { + fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { + fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); self } - fn caller_print_string(&mut self, ptr: u32, len: u32) { - let data = self.caller_read_string(ptr, len); + fn print_string(&mut self, ptr: u32, len: u32) { + let data = self.read_string(ptr, len); eprintln!("JIT: WASM says: {data}"); } - fn caller_get_time(&self) -> u64 { + fn get_time(&self) -> u64 { self.wenv.go_state.time } - fn caller_advance_time(&mut self, delta: u64) { + fn advance_time(&mut self, delta: u64) { self.wenv.go_state.time += delta } @@ -155,8 +155,6 @@ impl CallerEnv<'_> for JitCallerEnv<'_> { pub struct GoRuntimeState { /// An increasing clock used when Go asks for time, measured in nanoseconds pub time: u64, - /// The amount of time advanced each check. Currently 10 milliseconds - pub time_interval: u64, /// Deterministic source of random data pub rng: Pcg32, } @@ -165,8 +163,7 @@ impl Default for GoRuntimeState { fn default() -> Self { Self { time: 0, - time_interval: 10_000_000, - rng: Pcg32::new(callerenv::PCG_INIT_STATE, callerenv::PCG_INIT_STREAM), + rng: callerenv::create_pcg(), } } } diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index 2c7afa0fd..72eddffb2 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -32,27 +32,27 @@ pub fn activate( err_buf_len: u32, ) -> Result { let mut caller_env = JitCallerEnv::new(&mut env); - let wasm = caller_env.caller_read_slice(wasm_ptr, wasm_size); + let wasm = caller_env.read_slice(wasm_ptr, wasm_size); let debug = debug != 0; - let page_limit = caller_env.caller_read_u16(pages_ptr); - let gas_left = &mut caller_env.caller_read_u64(gas_ptr); + let page_limit = caller_env.read_u16(pages_ptr); + let gas_left = &mut caller_env.read_u64(gas_ptr); match Module::activate(&wasm, version, page_limit, debug, gas_left) { Ok((module, data)) => { - caller_env.caller_write_u64(gas_ptr, *gas_left); - caller_env.caller_write_u16(pages_ptr, data.footprint); - caller_env.caller_write_u32(asm_estimate_ptr, data.asm_estimate); - caller_env.caller_write_u32(init_gas_ptr, data.init_gas); - caller_env.caller_write_bytes32(module_hash_ptr, module.hash()); + caller_env.write_u64(gas_ptr, *gas_left); + caller_env.write_u16(pages_ptr, data.footprint); + caller_env.write_u32(asm_estimate_ptr, data.asm_estimate); + caller_env.write_u32(init_gas_ptr, data.init_gas); + caller_env.write_bytes32(module_hash_ptr, module.hash()); Ok(0) } Err(error) => { let mut err_bytes = error.wrap_err("failed to activate").debug_bytes(); err_bytes.truncate(err_buf_len as usize); - caller_env.caller_write_slice(err_buf, &err_bytes); - caller_env.caller_write_u64(gas_ptr, 0); - caller_env.caller_write_u16(pages_ptr, 0); - caller_env.caller_write_bytes32(module_hash_ptr, Bytes32::default()); + caller_env.write_slice(err_buf, &err_bytes); + caller_env.write_u64(gas_ptr, 0); + caller_env.write_u16(pages_ptr, 0); + caller_env.write_bytes32(module_hash_ptr, Bytes32::default()); Ok(err_bytes.len() as u32) } } @@ -71,8 +71,8 @@ pub fn new_program( gas: u64, ) -> Result { let mut caller_env = JitCallerEnv::new(&mut env); - let compiled_hash = caller_env.caller_read_bytes32(compiled_hash_ptr); - let calldata = caller_env.caller_read_slice(calldata_ptr, calldata_size); + let compiled_hash = caller_env.read_bytes32(compiled_hash_ptr); + let calldata = caller_env.read_slice(calldata_ptr, calldata_size); let evm_data: EvmData = unsafe { *Box::from_raw(evm_data_handler as *mut EvmData) }; let config: JitConfig = unsafe { *Box::from_raw(stylus_config_handler as *mut JitConfig) }; @@ -130,7 +130,7 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result MaybeEsc if msg.1 != id { return Escape::hostio("get_request id doesn't match"); }; - caller_env.caller_write_slice(data_ptr, &msg.0.req_data); + caller_env.write_slice(data_ptr, &msg.0.req_data); Ok(()) } @@ -160,8 +160,8 @@ pub fn set_response( raw_data_len: u32, ) -> MaybeEscape { let caller_env = JitCallerEnv::new(&mut env); - let result = caller_env.caller_read_slice(result_ptr, result_len); - let raw_data = caller_env.caller_read_slice(raw_data_ptr, raw_data_len); + let result = caller_env.read_slice(result_ptr, result_len); + let raw_data = caller_env.read_slice(raw_data_ptr, raw_data_len); let thread = caller_env.wenv.threads.last_mut().unwrap(); thread.set_response(id, result, raw_data, gas) @@ -235,17 +235,17 @@ pub fn create_evm_data( let mut caller_env = JitCallerEnv::new(&mut env); let evm_data = EvmData { - block_basefee: caller_env.caller_read_bytes32(block_basefee_ptr), + block_basefee: caller_env.read_bytes32(block_basefee_ptr), chainid, - block_coinbase: caller_env.caller_read_bytes20(block_coinbase_ptr), + block_coinbase: caller_env.read_bytes20(block_coinbase_ptr), block_gas_limit, block_number, block_timestamp, - contract_address: caller_env.caller_read_bytes20(contract_address_ptr), - msg_sender: caller_env.caller_read_bytes20(msg_sender_ptr), - msg_value: caller_env.caller_read_bytes32(msg_value_ptr), - tx_gas_price: caller_env.caller_read_bytes32(tx_gas_price_ptr), - tx_origin: caller_env.caller_read_bytes20(tx_origin_ptr), + contract_address: caller_env.read_bytes20(contract_address_ptr), + msg_sender: caller_env.read_bytes20(msg_sender_ptr), + msg_value: caller_env.read_bytes32(msg_value_ptr), + tx_gas_price: caller_env.read_bytes32(tx_gas_price_ptr), + tx_origin: caller_env.read_bytes20(tx_origin_ptr), reentrant, return_data_len: 0, tracing: false, diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index fd79f4775..03ba014ba 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -26,7 +26,7 @@ pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> Some(global) => global, None => return Escape::hostio("global read out of bounds in wavmio.getGlobalStateBytes32"), }; - caller_env.caller_write_slice(out_ptr, &global[..32]); + caller_env.write_slice(out_ptr, &global[..32]); Ok(()) } @@ -35,7 +35,7 @@ pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> let caller_env = JitCallerEnv::new(&mut env); ready_hostio(caller_env.wenv)?; - let slice = caller_env.caller_read_slice(src_ptr, 32); + let slice = caller_env.read_slice(src_ptr, 32); let slice = &slice.try_into().unwrap(); match caller_env.wenv.large_globals.get_mut(idx as usize) { Some(global) => *global = *slice, @@ -88,7 +88,7 @@ pub fn read_inbox_message( let offset = offset as usize; let len = std::cmp::min(32, message.len().saturating_sub(offset)); let read = message.get(offset..(offset + len)).unwrap_or_default(); - caller_env.caller_write_slice(out_ptr, read); + caller_env.write_slice(out_ptr, read); Ok(read.len() as u32) } @@ -109,7 +109,7 @@ pub fn read_delayed_inbox_message( let offset = offset as usize; let len = std::cmp::min(32, message.len().saturating_sub(offset)); let read = message.get(offset..(offset + len)).unwrap_or_default(); - caller_env.caller_write_slice(out_ptr, read); + caller_env.write_slice(out_ptr, read); Ok(read.len() as u32) } @@ -131,7 +131,7 @@ pub fn resolve_preimage( }}; } - let hash = caller_env.caller_read_bytes32(hash_ptr); + let hash = caller_env.read_bytes32(hash_ptr); let hash_hex = hex::encode(hash); let mut preimage = None; @@ -159,7 +159,7 @@ pub fn resolve_preimage( let len = std::cmp::min(32, preimage.len().saturating_sub(offset)); let read = preimage.get(offset..(offset + len)).unwrap_or_default(); - caller_env.caller_write_slice(out_ptr, read); + caller_env.write_slice(out_ptr, read); Ok(read.len() as u32) } diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 67200637b..639fc7819 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -7,7 +7,7 @@ use rand::RngCore; use paste::paste; use callerenv::{ self, - wasip1_stub::{Errno, Uptr, ERRNO_SUCCESS, ERRNO_BADF, ERRNO_INTVAL}, + wasip1_stub::{Errno, Uptr}, CallerEnv, }; use rand_pcg::Pcg32; @@ -42,64 +42,64 @@ static mut RNG: Option = None; struct StaticCallerEnv{} impl CallerEnv<'static> for StaticCallerEnv { - fn caller_read_u8(&self, ptr: u32) -> u8 { + fn read_u8(&self, ptr: u32) -> u8 { unsafe { wavm_caller_load8(ptr) } } - fn caller_read_u16(&self, ptr: u32) -> u16 { - let lsb = self.caller_read_u8(ptr); - let msb = self.caller_read_u8(ptr+1); + fn read_u16(&self, ptr: u32) -> u16 { + let lsb = self.read_u8(ptr); + let msb = self.read_u8(ptr+1); (msb as u16) << 8 | (lsb as u16) } - fn caller_read_u32(&self, ptr: u32) -> u32 { - let lsb = self.caller_read_u16(ptr); - let msb = self.caller_read_u16(ptr+2); + fn read_u32(&self, ptr: u32) -> u32 { + let lsb = self.read_u16(ptr); + let msb = self.read_u16(ptr+2); (msb as u32) << 16 | (lsb as u32) } - fn caller_read_u64(&self, ptr: u32) -> u64 { - let lsb = self.caller_read_u32(ptr); - let msb = self.caller_read_u32(ptr+4); + fn read_u64(&self, ptr: u32) -> u64 { + let lsb = self.read_u32(ptr); + let msb = self.read_u32(ptr+4); (msb as u64) << 32 | (lsb as u64) } - fn caller_write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { + fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { unsafe { wavm_caller_store8(ptr, x); } self } - fn caller_write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { - self.caller_write_u8(ptr, (x & 0xff) as u8); - self.caller_write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); + fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { + self.write_u8(ptr, (x & 0xff) as u8); + self.write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); self } - fn caller_write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { - self.caller_write_u16(ptr, (x & 0xffff) as u16); - self.caller_write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); + fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { + self.write_u16(ptr, (x & 0xffff) as u16); + self.write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); self } - fn caller_write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { - self.caller_write_u32(ptr, (x & 0xffffffff) as u32); - self.caller_write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); + fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { + self.write_u32(ptr, (x & 0xffffffff) as u32); + self.write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); self } - fn caller_print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? + fn print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? - fn caller_get_time(&self) -> u64 { + fn get_time(&self) -> u64 { unsafe { TIME } } - fn caller_advance_time(&mut self, delta: u64) { + fn advance_time(&mut self, delta: u64) { unsafe { TIME += delta } @@ -107,7 +107,7 @@ impl CallerEnv<'static> for StaticCallerEnv { fn next_rand_u32(&mut self) -> u32 { unsafe { - RNG.get_or_insert_with(|| Pcg32::new(callerenv::PCG_INIT_STATE, callerenv::PCG_INIT_STREAM)) + RNG.get_or_insert_with(|| callerenv::create_pcg()) } .next_u32() } From 1fb2d692359017161eb2ddfe65ba78c452786ced Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 28 Feb 2024 13:13:20 -0700 Subject: [PATCH 03/28] callerenv: move static implementation --- arbitrator/Cargo.lock | 1 + arbitrator/callerenv/Cargo.toml | 2 + arbitrator/callerenv/src/lib.rs | 11 ++- arbitrator/callerenv/src/static_caller.rs | 89 +++++++++++++++++++ arbitrator/callerenv/src/wasip1_stub.rs | 64 ++++++------- arbitrator/jit/src/callerenv.rs | 12 +-- arbitrator/jit/src/wasip1_stub.rs | 4 +- arbitrator/wasm-libraries/Cargo.lock | 4 + .../wasm-libraries/wasi-stub/Cargo.toml | 2 +- .../wasm-libraries/wasi-stub/src/lib.rs | 89 +------------------ 10 files changed, 143 insertions(+), 135 deletions(-) create mode 100644 arbitrator/callerenv/src/static_caller.rs diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 2f41f4b5e..42c7bc888 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -206,6 +206,7 @@ checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" name = "callerenv" version = "0.1.0" dependencies = [ + "rand", "rand_pcg", ] diff --git a/arbitrator/callerenv/Cargo.toml b/arbitrator/callerenv/Cargo.toml index 5db7c7cc4..5b5c6b6d0 100644 --- a/arbitrator/callerenv/Cargo.toml +++ b/arbitrator/callerenv/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] rand_pcg = { version = "0.3.1", default-features = false } +rand = { version = "0.8.4", default-features = false } [features] wavm = [] +static_caller = [] \ No newline at end of file diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs index 872a61d21..78bba8f13 100644 --- a/arbitrator/callerenv/src/lib.rs +++ b/arbitrator/callerenv/src/lib.rs @@ -2,6 +2,9 @@ #![no_std] use rand_pcg::Pcg32; +#[cfg(feature = "static_caller")] +pub mod static_caller; + pub mod wasip1_stub; const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; @@ -20,13 +23,13 @@ pub trait CallerEnv<'a> { fn read_u64(&self, ptr: u32) -> u64; - fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self; + fn write_u8(&mut self, ptr: u32, x: u8); - fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self; + fn write_u16(&mut self, ptr: u32, x: u16); - fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self; + fn write_u32(&mut self, ptr: u32, x: u32); - fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self; + fn write_u64(&mut self, ptr: u32, x: u64); fn print_string(&mut self, ptr: u32, len: u32); diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/callerenv/src/static_caller.rs new file mode 100644 index 000000000..59f4b4ec3 --- /dev/null +++ b/arbitrator/callerenv/src/static_caller.rs @@ -0,0 +1,89 @@ +use crate::{CallerEnv, create_pcg, wasip1_stub::Uptr}; +use rand_pcg::Pcg32; +use rand::RngCore; + +static mut TIME: u64 = 0; +static mut RNG: Option = None; + +#[derive(Default)] +pub struct StaticCallerEnv{} + +pub static mut STATIC_CALLER: StaticCallerEnv = StaticCallerEnv{}; + + +#[allow(dead_code)] +extern "C" { + fn wavm_caller_load8(ptr: Uptr) -> u8; + fn wavm_caller_load32(ptr: Uptr) -> u32; + fn wavm_caller_store8(ptr: Uptr, val: u8); + fn wavm_caller_store32(ptr: Uptr, val: u32); + fn wavm_halt_and_set_finished() -> !; +} + +impl CallerEnv<'static> for StaticCallerEnv { + fn read_u8(&self, ptr: u32) -> u8 { + unsafe { + wavm_caller_load8(ptr) + } + } + + fn read_u16(&self, ptr: u32) -> u16 { + let lsb = self.read_u8(ptr); + let msb = self.read_u8(ptr+1); + (msb as u16) << 8 | (lsb as u16) + } + + fn read_u32(&self, ptr: u32) -> u32 { + let lsb = self.read_u16(ptr); + let msb = self.read_u16(ptr+2); + (msb as u32) << 16 | (lsb as u32) + } + + fn read_u64(&self, ptr: u32) -> u64 { + let lsb = self.read_u32(ptr); + let msb = self.read_u32(ptr+4); + (msb as u64) << 32 | (lsb as u64) + } + + fn write_u8(&mut self, ptr: u32, x: u8 ){ + unsafe { + wavm_caller_store8(ptr, x); + } + } + + fn write_u16(&mut self, ptr: u32, x: u16) { + self.write_u8(ptr, (x & 0xff) as u8); + self.write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); + } + + fn write_u32(&mut self, ptr: u32, x: u32) { + self.write_u16(ptr, (x & 0xffff) as u16); + self.write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); + } + + fn write_u64(&mut self, ptr: u32, x: u64) { + self.write_u32(ptr, (x & 0xffffffff) as u32); + self.write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); + } + + fn print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? + + fn get_time(&self) -> u64 { + unsafe { + TIME + } + } + + fn advance_time(&mut self, delta: u64) { + unsafe { + TIME += delta + } + } + + fn next_rand_u32(&mut self) -> u32 { + unsafe { + RNG.get_or_insert_with(|| create_pcg()) + } + .next_u32() + } +} diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/callerenv/src/wasip1_stub.rs index c6b8d7a13..e3661c296 100644 --- a/arbitrator/callerenv/src/wasip1_stub.rs +++ b/arbitrator/callerenv/src/wasip1_stub.rs @@ -9,7 +9,7 @@ pub const ERRNO_BADF: Errno = 8; pub const ERRNO_INTVAL: Errno = 28; pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( - mut caller_env: E, + caller_env: &mut E, length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { @@ -19,7 +19,7 @@ pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( } pub fn fd_write<'a, E: CallerEnv<'a>>( - mut caller_env: E, + caller_env: &mut E, fd: u32, iovecs_ptr: Uptr, iovecs_len: u32, @@ -40,20 +40,20 @@ pub fn fd_write<'a, E: CallerEnv<'a>>( ERRNO_SUCCESS } -pub fn environ_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { +pub fn environ_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { ERRNO_INTVAL } -pub fn fd_close<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { +pub fn fd_close<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32) -> Errno { ERRNO_BADF } -pub fn fd_read<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32, _: u32) -> Errno { +pub fn fd_read<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32, _: u32, _: u32) -> Errno { ERRNO_BADF } pub fn fd_readdir<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _fd: u32, _: u32, _: u32, @@ -63,12 +63,12 @@ pub fn fd_readdir<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_sync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { +pub fn fd_sync<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32) -> Errno { ERRNO_SUCCESS } pub fn fd_seek<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _fd: u32, _offset: u64, _whence: u8, @@ -77,12 +77,12 @@ pub fn fd_seek<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_datasync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32) -> Errno { +pub fn fd_datasync<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32) -> Errno { ERRNO_BADF } pub fn path_open<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -97,7 +97,7 @@ pub fn path_open<'a, E: CallerEnv<'a>>( } pub fn path_create_directory<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -106,7 +106,7 @@ pub fn path_create_directory<'a, E: CallerEnv<'a>>( } pub fn path_remove_directory<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -115,7 +115,7 @@ pub fn path_remove_directory<'a, E: CallerEnv<'a>>( } pub fn path_readlink<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -127,7 +127,7 @@ pub fn path_readlink<'a, E: CallerEnv<'a>>( } pub fn path_rename<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -139,7 +139,7 @@ pub fn path_rename<'a, E: CallerEnv<'a>>( } pub fn path_filestat_get<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -149,16 +149,16 @@ pub fn path_filestat_get<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_unlink_file<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32) -> Errno { +pub fn path_unlink_file<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32, _: u32) -> Errno { ERRNO_BADF } -pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { +pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _: u32, _: u32, _: u32, @@ -167,19 +167,19 @@ pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( } pub fn fd_filestat_get<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _fd: u32, _filestat: u32, ) -> Errno { ERRNO_BADF } -pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u64) -> Errno { +pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32, _: u64) -> Errno { ERRNO_BADF } pub fn fd_pread<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _fd: u32, _: u32, _: u32, @@ -190,7 +190,7 @@ pub fn fd_pread<'a, E: CallerEnv<'a>>( } pub fn fd_pwrite<'a, E: CallerEnv<'a>>( - mut _caller_env: E, + _caller_env: &mut E, _fd: u32, _: u32, _: u32, @@ -200,22 +200,22 @@ pub fn fd_pwrite<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn sock_accept<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u32, _: u32) -> Errno { +pub fn sock_accept<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32, _: u32, _: u32) -> Errno { ERRNO_BADF } -pub fn sock_shutdown<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { +pub fn sock_shutdown<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } -pub fn sched_yield<'a, E: CallerEnv<'a>>(mut _caller_env: E) -> Errno { +pub fn sched_yield<'a, E: CallerEnv<'a>>(_caller_env: &mut E) -> Errno { ERRNO_SUCCESS } static TIME_INTERVAL: u64 = 10_000_000; pub fn clock_time_get<'a, E: CallerEnv<'a>>( - mut caller_env: E, + caller_env: &mut E, _clock_id: u32, _precision: u64, time_ptr: Uptr, @@ -225,7 +225,7 @@ pub fn clock_time_get<'a, E: CallerEnv<'a>>( ERRNO_SUCCESS } -pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len: u32) -> Errno { +pub fn random_get<'a, E: CallerEnv<'a>>(caller_env: &mut E, mut buf: u32, mut len: u32) -> Errno { while len >= 4 { let next_rand = caller_env.next_rand_u32(); caller_env.write_u32(buf, next_rand); @@ -244,7 +244,7 @@ pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len } pub fn args_sizes_get<'a, E: CallerEnv<'a>>( - mut caller_env: E, + caller_env: &mut E, length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { @@ -253,7 +253,7 @@ pub fn args_sizes_get<'a, E: CallerEnv<'a>>( ERRNO_SUCCESS } -pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_buf: Uptr) -> Errno { +pub fn args_get<'a, E: CallerEnv<'a>>(caller_env: &mut E, argv_buf: Uptr, data_buf: Uptr) -> Errno { caller_env.write_u32(argv_buf, data_buf as u32); caller_env.write_u32(data_buf, 0x6E6962); // "bin\0" ERRNO_SUCCESS @@ -261,7 +261,7 @@ pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_bu // we always simulate a timeout pub fn poll_oneoff<'a, E: CallerEnv<'a>>( - mut caller_env: E, + caller_env: &mut E, in_subs: Uptr, out_evt: Uptr, nsubscriptions: u32, @@ -284,10 +284,10 @@ pub fn poll_oneoff<'a, E: CallerEnv<'a>>( ERRNO_INTVAL } -pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { +pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { ERRNO_INTVAL } -pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { +pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { ERRNO_INTVAL } diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index a6acc4b11..b85e9ee5e 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -110,28 +110,24 @@ impl CallerEnv<'_> for JitCallerEnv<'_> { ptr.deref(&self.view()).read().unwrap() } - fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { + fn write_u8(&mut self, ptr: u32, x: u8) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); - self } - fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { + fn write_u16(&mut self, ptr: u32, x: u16) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); - self } - fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { + fn write_u32(&mut self, ptr: u32, x: u32) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); - self } - fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { + fn write_u64(&mut self, ptr: u32, x: u64) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); - self } fn print_string(&mut self, ptr: u32, len: u32) { diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 0f522b320..24e19fc62 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -15,9 +15,9 @@ pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { macro_rules! wrap { ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let caller_env = JitCallerEnv::new(&mut src); + let mut caller_env = JitCallerEnv::new(&mut src); - Ok(callerenv::wasip1_stub::$func_name(caller_env, $($arg_name),*)) + Ok(callerenv::wasip1_stub::$func_name(&mut caller_env, $($arg_name),*)) } }; } diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 2b7c3cad7..4ae060db4 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -135,6 +135,10 @@ dependencies = [ [[package]] name = "callerenv" version = "0.1.0" +dependencies = [ + "rand", + "rand_pcg", +] [[package]] name = "cfg-if" diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index 8c0a45646..2d5df5edc 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -9,6 +9,6 @@ crate-type = ["cdylib"] [dependencies] paste = {versoion="1.0.14"} -callerenv = { path = "../../callerenv/" } +callerenv = { path = "../../callerenv/", features = ["static_caller"] } rand = { version = "0.8.4", default-features = false } rand_pcg = { version = "0.3.1", default-features = false } diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 639fc7819..80c7bfb59 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -10,14 +10,8 @@ use callerenv::{ wasip1_stub::{Errno, Uptr}, CallerEnv, }; -use rand_pcg::Pcg32; - #[allow(dead_code)] extern "C" { - fn wavm_caller_load8(ptr: Uptr) -> u8; - fn wavm_caller_load32(ptr: Uptr) -> u32; - fn wavm_caller_store8(ptr: Uptr, val: u8); - fn wavm_caller_store32(ptr: Uptr, val: u32); fn wavm_halt_and_set_finished() -> !; } @@ -35,93 +29,12 @@ pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { } } -static mut TIME: u64 = 0; -static mut RNG: Option = None; - -#[derive(Default)] -struct StaticCallerEnv{} - -impl CallerEnv<'static> for StaticCallerEnv { - fn read_u8(&self, ptr: u32) -> u8 { - unsafe { - wavm_caller_load8(ptr) - } - } - - fn read_u16(&self, ptr: u32) -> u16 { - let lsb = self.read_u8(ptr); - let msb = self.read_u8(ptr+1); - (msb as u16) << 8 | (lsb as u16) - } - - fn read_u32(&self, ptr: u32) -> u32 { - let lsb = self.read_u16(ptr); - let msb = self.read_u16(ptr+2); - (msb as u32) << 16 | (lsb as u32) - } - - fn read_u64(&self, ptr: u32) -> u64 { - let lsb = self.read_u32(ptr); - let msb = self.read_u32(ptr+4); - (msb as u64) << 32 | (lsb as u64) - } - - fn write_u8(&mut self, ptr: u32, x: u8) -> &mut Self { - unsafe { - wavm_caller_store8(ptr, x); - } - self - } - - fn write_u16(&mut self, ptr: u32, x: u16) -> &mut Self { - self.write_u8(ptr, (x & 0xff) as u8); - self.write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); - self - } - - fn write_u32(&mut self, ptr: u32, x: u32) -> &mut Self { - self.write_u16(ptr, (x & 0xffff) as u16); - self.write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); - self - } - - fn write_u64(&mut self, ptr: u32, x: u64) -> &mut Self { - self.write_u32(ptr, (x & 0xffffffff) as u32); - self.write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); - self - } - - fn print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? - - fn get_time(&self) -> u64 { - unsafe { - TIME - } - } - - fn advance_time(&mut self, delta: u64) { - unsafe { - TIME += delta - } - } - - fn next_rand_u32(&mut self) -> u32 { - unsafe { - RNG.get_or_insert_with(|| callerenv::create_pcg()) - } - .next_u32() - } -} - - macro_rules! wrap { ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { paste! { #[no_mangle] pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { - let caller_env = StaticCallerEnv::default(); - - callerenv::wasip1_stub::$func_name(caller_env, $($arg_name),*) + callerenv::wasip1_stub::$func_name(&mut callerenv::static_caller::STATIC_CALLER, $($arg_name),*) } } }; From 50670be9810e4f9297c2b7697fecaeb42e7ca270 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 28 Feb 2024 19:45:30 -0700 Subject: [PATCH 04/28] split caller env to mem and exec --- arbcompress/compress_wasm.go | 4 +- arbitrator/callerenv/src/brotli.rs | 104 +++++++++ arbitrator/callerenv/src/lib.rs | 33 ++- arbitrator/callerenv/src/static_caller.rs | 78 ++++--- arbitrator/callerenv/src/wasip1_stub.rs | 201 +++++++++++------- arbitrator/jit/src/arbcompress.rs | 103 ++------- arbitrator/jit/src/callerenv.rs | 76 +++---- arbitrator/jit/src/machine.rs | 4 +- arbitrator/jit/src/program.rs | 96 ++++----- arbitrator/jit/src/socket.rs | 2 +- arbitrator/jit/src/wasip1_stub.rs | 6 +- arbitrator/jit/src/wavmio.rs | 65 +++--- arbitrator/wasm-libraries/Cargo.lock | 34 ++- arbitrator/wasm-libraries/brotli/Cargo.toml | 3 +- arbitrator/wasm-libraries/brotli/src/lib.rs | 107 ++-------- .../wasm-libraries/wasi-stub/Cargo.toml | 4 +- .../wasm-libraries/wasi-stub/src/lib.rs | 13 +- 17 files changed, 516 insertions(+), 417 deletions(-) create mode 100644 arbitrator/callerenv/src/brotli.rs diff --git a/arbcompress/compress_wasm.go b/arbcompress/compress_wasm.go index 9f3ff9404..c99c3ebb2 100644 --- a/arbcompress/compress_wasm.go +++ b/arbcompress/compress_wasm.go @@ -13,10 +13,10 @@ import ( "github.com/offchainlabs/nitro/arbutil" ) -//go:wasmimport arbcompress brotliCompress +//go:wasmimport arbcompress brotli_compress func brotliCompress(inBuf unsafe.Pointer, inBufLen uint32, outBuf unsafe.Pointer, outBufLen unsafe.Pointer, level, windowSize uint32) BrotliStatus -//go:wasmimport arbcompress brotliDecompress +//go:wasmimport arbcompress brotli_decompress func brotliDecompress(inBuf unsafe.Pointer, inBufLen uint32, outBuf unsafe.Pointer, outBufLen unsafe.Pointer) BrotliStatus func Decompress(input []byte, maxSize int) ([]byte, error) { diff --git a/arbitrator/callerenv/src/brotli.rs b/arbitrator/callerenv/src/brotli.rs new file mode 100644 index 000000000..8c5629d6c --- /dev/null +++ b/arbitrator/callerenv/src/brotli.rs @@ -0,0 +1,104 @@ +// Copyright 2021-2023, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE +use crate::{ExecEnv, MemAccess}; +use alloc::vec; + +#[derive(PartialEq)] +#[repr(u32)] +pub enum BrotliStatus { + Failure, + Success, +} + +extern "C" { + pub fn BrotliDecoderDecompress( + encoded_size: usize, + encoded_buffer: *const u8, + decoded_size: *mut usize, + decoded_buffer: *mut u8, + ) -> BrotliStatus; + + pub fn BrotliEncoderCompress( + quality: u32, + lgwin: u32, + mode: u32, + input_size: usize, + input_buffer: *const u8, + encoded_size: *mut usize, + encoded_buffer: *mut u8, + ) -> BrotliStatus; +} + +type Uptr = u32; + +const BROTLI_MODE_GENERIC: u32 = 0; + +/// Brotli decompresses a go slice1 +/// +/// # Safety +/// +/// The output buffer must be sufficiently large enough. +pub fn brotli_decompress( + mem: &mut M, + _env: &mut E, + in_buf_ptr: Uptr, + in_buf_len: u32, + out_buf_ptr: Uptr, + out_len_ptr: Uptr, +) -> u32 { + let in_slice = mem.read_slice(in_buf_ptr, in_buf_len as usize); + let orig_output_len = mem.read_u32(out_len_ptr) as usize; + let mut output = vec![0u8; orig_output_len as usize]; + let mut output_len = orig_output_len; + unsafe { + let res = BrotliDecoderDecompress( + in_buf_len as usize, + in_slice.as_ptr(), + &mut output_len, + output.as_mut_ptr(), + ); + if (res != BrotliStatus::Success) || (output_len > orig_output_len) { + return 0; + } + } + mem.write_slice(out_buf_ptr, &output[..output_len]); + mem.write_u32(out_len_ptr, output_len as u32); + 1 +} + +/// Brotli compresses a go slice +/// +/// The output buffer must be sufficiently large enough. +pub fn brotli_compress( + mem: &mut M, + _env: &mut E, + in_buf_ptr: Uptr, + in_buf_len: u32, + out_buf_ptr: Uptr, + out_len_ptr: Uptr, + level: u32, + window_size: u32, +) -> u32 { + let in_slice = mem.read_slice(in_buf_ptr, in_buf_len as usize); + let orig_output_len = mem.read_u32(out_len_ptr) as usize; + let mut output = vec![0u8; orig_output_len]; + let mut output_len = orig_output_len; + + unsafe { + let res = BrotliEncoderCompress( + level, + window_size, + BROTLI_MODE_GENERIC, + in_buf_len as usize, + in_slice.as_ptr(), + &mut output_len, + output.as_mut_ptr(), + ); + if (res != BrotliStatus::Success) || (output_len > orig_output_len) { + return 0; + } + } + mem.write_slice(out_buf_ptr, &output[..output_len]); + mem.write_u32(out_len_ptr, output_len as u32); + 1 +} diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs index 78bba8f13..e34ced853 100644 --- a/arbitrator/callerenv/src/lib.rs +++ b/arbitrator/callerenv/src/lib.rs @@ -1,11 +1,16 @@ - #![no_std] use rand_pcg::Pcg32; +extern crate alloc; + +use alloc::vec::Vec; + #[cfg(feature = "static_caller")] pub mod static_caller; +pub mod brotli; pub mod wasip1_stub; +pub type Uptr = u32; const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; @@ -14,24 +19,30 @@ pub fn create_pcg() -> Pcg32 { Pcg32::new(PCG_INIT_STATE, PCG_INIT_STREAM) } -pub trait CallerEnv<'a> { - fn read_u8(&self, ptr: u32) -> u8; +pub trait MemAccess { + fn read_u8(&self, ptr: Uptr) -> u8; - fn read_u16(&self, ptr: u32) -> u16; + fn read_u16(&self, ptr: Uptr) -> u16; - fn read_u32(&self, ptr: u32) -> u32; + fn read_u32(&self, ptr: Uptr) -> u32; - fn read_u64(&self, ptr: u32) -> u64; + fn read_u64(&self, ptr: Uptr) -> u64; - fn write_u8(&mut self, ptr: u32, x: u8); + fn write_u8(&mut self, ptr: Uptr, x: u8); - fn write_u16(&mut self, ptr: u32, x: u16); + fn write_u16(&mut self, ptr: Uptr, x: u16); - fn write_u32(&mut self, ptr: u32, x: u32); + fn write_u32(&mut self, ptr: Uptr, x: u32); - fn write_u64(&mut self, ptr: u32, x: u64); + fn write_u64(&mut self, ptr: Uptr, x: u64); + + fn read_slice(&self, ptr: Uptr, len: usize) -> Vec; + + fn write_slice(&mut self, ptr: Uptr, data: &[u8]); +} - fn print_string(&mut self, ptr: u32, len: u32); +pub trait ExecEnv { + fn print_string(&mut self, message: &[u8]); fn get_time(&self) -> u64; diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/callerenv/src/static_caller.rs index 59f4b4ec3..239e72d15 100644 --- a/arbitrator/callerenv/src/static_caller.rs +++ b/arbitrator/callerenv/src/static_caller.rs @@ -1,15 +1,19 @@ -use crate::{CallerEnv, create_pcg, wasip1_stub::Uptr}; -use rand_pcg::Pcg32; +use crate::{create_pcg, wasip1_stub::Uptr, ExecEnv, MemAccess}; use rand::RngCore; +use rand_pcg::Pcg32; + +extern crate alloc; + +use alloc::vec::Vec; static mut TIME: u64 = 0; static mut RNG: Option = None; -#[derive(Default)] -pub struct StaticCallerEnv{} - -pub static mut STATIC_CALLER: StaticCallerEnv = StaticCallerEnv{}; +pub struct StaticMem {} +pub struct StaticExecEnv {} +pub static mut STATIC_MEM: StaticMem = StaticMem {}; +pub static mut STATIC_ENV: StaticExecEnv = StaticExecEnv {}; #[allow(dead_code)] extern "C" { @@ -20,32 +24,30 @@ extern "C" { fn wavm_halt_and_set_finished() -> !; } -impl CallerEnv<'static> for StaticCallerEnv { +impl MemAccess for StaticMem { fn read_u8(&self, ptr: u32) -> u8 { - unsafe { - wavm_caller_load8(ptr) - } + unsafe { wavm_caller_load8(ptr) } } fn read_u16(&self, ptr: u32) -> u16 { let lsb = self.read_u8(ptr); - let msb = self.read_u8(ptr+1); + let msb = self.read_u8(ptr + 1); (msb as u16) << 8 | (lsb as u16) } fn read_u32(&self, ptr: u32) -> u32 { let lsb = self.read_u16(ptr); - let msb = self.read_u16(ptr+2); + let msb = self.read_u16(ptr + 2); (msb as u32) << 16 | (lsb as u32) } fn read_u64(&self, ptr: u32) -> u64 { let lsb = self.read_u32(ptr); - let msb = self.read_u32(ptr+4); + let msb = self.read_u32(ptr + 4); (msb as u64) << 32 | (lsb as u64) } - fn write_u8(&mut self, ptr: u32, x: u8 ){ + fn write_u8(&mut self, ptr: u32, x: u8) { unsafe { wavm_caller_store8(ptr, x); } @@ -66,24 +68,50 @@ impl CallerEnv<'static> for StaticCallerEnv { self.write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); } - fn print_string(&mut self, _ptr: u32, _len: u32) {} // TODO? + fn read_slice(&self, mut ptr: u32, mut len: usize) -> Vec { + let mut data = Vec::with_capacity(len); + if len == 0 { + return data; + } + while len >= 4 { + data.extend(self.read_u32(ptr).to_le_bytes()); + ptr += 4; + len -= 4; + } + for _ in 0..len { + data.push(self.read_u8(ptr)); + ptr += 1; + } + data + } - fn get_time(&self) -> u64 { - unsafe { - TIME + fn write_slice(&mut self, mut ptr: u32, mut src: &[u8]) { + while src.len() >= 4 { + let mut arr = [0u8; 4]; + arr.copy_from_slice(&src[..4]); + self.write_u32(ptr, u32::from_le_bytes(arr)); + ptr += 4; + src = &src[4..]; + } + for &byte in src { + self.write_u8(ptr, byte); + ptr += 1; } } +} + +impl ExecEnv for StaticExecEnv { + fn print_string(&mut self, data: &[u8]) {} // TODO? + + fn get_time(&self) -> u64 { + unsafe { TIME } + } fn advance_time(&mut self, delta: u64) { - unsafe { - TIME += delta - } + unsafe { TIME += delta } } fn next_rand_u32(&mut self) -> u32 { - unsafe { - RNG.get_or_insert_with(|| create_pcg()) - } - .next_u32() + unsafe { RNG.get_or_insert_with(|| create_pcg()) }.next_u32() } } diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/callerenv/src/wasip1_stub.rs index e3661c296..4e501de8f 100644 --- a/arbitrator/callerenv/src/wasip1_stub.rs +++ b/arbitrator/callerenv/src/wasip1_stub.rs @@ -1,25 +1,27 @@ -use crate::CallerEnv; +use crate::{ExecEnv, MemAccess}; pub type Errno = u16; -pub type Uptr = u32; +pub use crate::Uptr; pub const ERRNO_SUCCESS: Errno = 0; pub const ERRNO_BADF: Errno = 8; pub const ERRNO_INTVAL: Errno = 28; -pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( - caller_env: &mut E, +pub fn environ_sizes_get( + mem: &mut M, + _env: &mut E, length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { - caller_env.write_u32(length_ptr, 0); - caller_env.write_u32(data_size_ptr, 0); + mem.write_u32(length_ptr, 0); + mem.write_u32(data_size_ptr, 0); ERRNO_SUCCESS } -pub fn fd_write<'a, E: CallerEnv<'a>>( - caller_env: &mut E, +pub fn fd_write( + mem: &mut M, + env: &mut E, fd: u32, iovecs_ptr: Uptr, iovecs_len: u32, @@ -31,29 +33,38 @@ pub fn fd_write<'a, E: CallerEnv<'a>>( let mut size = 0; for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; - let iovec = caller_env.read_u32(ptr); - let len = caller_env.read_u32(ptr + 4); - caller_env.print_string(iovec, len); + // let iovec = mem.read_u32(ptr); + let len = mem.read_u32(ptr + 4); + let data = mem.read_slice(ptr, len as usize); + env.print_string(&data); size += len; } - caller_env.write_u32(ret_ptr, size); + mem.write_u32(ret_ptr, size); ERRNO_SUCCESS } -pub fn environ_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { +pub fn environ_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_INTVAL } -pub fn fd_close<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32) -> Errno { +pub fn fd_close(_: &mut M, _: &mut E, _: u32) -> Errno { ERRNO_BADF } -pub fn fd_read<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32, _: u32, _: u32) -> Errno { +pub fn fd_read( + _: &mut M, + _: &mut E, + _: u32, + _: u32, + _: u32, + _: u32, +) -> Errno { ERRNO_BADF } -pub fn fd_readdir<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_readdir( + _: &mut M, + _: &mut E, _fd: u32, _: u32, _: u32, @@ -63,12 +74,13 @@ pub fn fd_readdir<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_sync<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32) -> Errno { +pub fn fd_sync(_: &mut M, _: &mut E, _: u32) -> Errno { ERRNO_SUCCESS } -pub fn fd_seek<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_seek( + _: &mut M, + _: &mut E, _fd: u32, _offset: u64, _whence: u8, @@ -77,12 +89,13 @@ pub fn fd_seek<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_datasync<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32) -> Errno { +pub fn fd_datasync(_: &mut M, _: &mut E, _fd: u32) -> Errno { ERRNO_BADF } -pub fn path_open<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_open( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -96,8 +109,9 @@ pub fn path_open<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_create_directory<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_create_directory( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -105,8 +119,9 @@ pub fn path_create_directory<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_remove_directory<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_remove_directory( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -114,8 +129,9 @@ pub fn path_remove_directory<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_readlink<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_readlink( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -126,8 +142,9 @@ pub fn path_readlink<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_rename<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_rename( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -138,8 +155,9 @@ pub fn path_rename<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_filestat_get<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn path_filestat_get( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -149,16 +167,23 @@ pub fn path_filestat_get<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn path_unlink_file<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32, _: u32) -> Errno { +pub fn path_unlink_file( + _: &mut M, + _: &mut E, + _: u32, + _: u32, + _: u32, +) -> Errno { ERRNO_BADF } -pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { +pub fn fd_prestat_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } -pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_prestat_dir_name( + _: &mut M, + _: &mut E, _: u32, _: u32, _: u32, @@ -166,20 +191,27 @@ pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_filestat_get<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_filestat_get( + _: &mut M, + _: &mut E, _fd: u32, _filestat: u32, ) -> Errno { ERRNO_BADF } -pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32, _: u64) -> Errno { +pub fn fd_filestat_set_size( + _: &mut M, + _: &mut E, + _fd: u32, + _: u64, +) -> Errno { ERRNO_BADF } -pub fn fd_pread<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_pread( + _: &mut M, + _: &mut E, _fd: u32, _: u32, _: u32, @@ -189,8 +221,9 @@ pub fn fd_pread<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn fd_pwrite<'a, E: CallerEnv<'a>>( - _caller_env: &mut E, +pub fn fd_pwrite( + _: &mut M, + _: &mut E, _fd: u32, _: u32, _: u32, @@ -200,42 +233,54 @@ pub fn fd_pwrite<'a, E: CallerEnv<'a>>( ERRNO_BADF } -pub fn sock_accept<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _fd: u32, _: u32, _: u32) -> Errno { +pub fn sock_accept( + _: &mut M, + _: &mut E, + _fd: u32, + _: u32, + _: u32, +) -> Errno { ERRNO_BADF } -pub fn sock_shutdown<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { +pub fn sock_shutdown(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } -pub fn sched_yield<'a, E: CallerEnv<'a>>(_caller_env: &mut E) -> Errno { +pub fn sched_yield(_: &mut M, _: &mut E) -> Errno { ERRNO_SUCCESS } static TIME_INTERVAL: u64 = 10_000_000; -pub fn clock_time_get<'a, E: CallerEnv<'a>>( - caller_env: &mut E, +pub fn clock_time_get( + mem: &mut M, + env: &mut E, _clock_id: u32, _precision: u64, time_ptr: Uptr, ) -> Errno { - caller_env.advance_time(TIME_INTERVAL); - caller_env.write_u64(time_ptr, caller_env.get_time()); + env.advance_time(TIME_INTERVAL); + mem.write_u64(time_ptr, env.get_time()); ERRNO_SUCCESS } -pub fn random_get<'a, E: CallerEnv<'a>>(caller_env: &mut E, mut buf: u32, mut len: u32) -> Errno { +pub fn random_get( + mem: &mut M, + env: &mut E, + mut buf: u32, + mut len: u32, +) -> Errno { while len >= 4 { - let next_rand = caller_env.next_rand_u32(); - caller_env.write_u32(buf, next_rand); + let next_rand = env.next_rand_u32(); + mem.write_u32(buf, next_rand); buf += 4; len -= 4; } if len > 0 { - let mut rem = caller_env.next_rand_u32(); + let mut rem = env.next_rand_u32(); for _ in 0..len { - caller_env.write_u8(buf, rem as u8); + mem.write_u8(buf, rem as u8); buf += 1; rem >>= 8; } @@ -243,25 +288,32 @@ pub fn random_get<'a, E: CallerEnv<'a>>(caller_env: &mut E, mut buf: u32, mut le ERRNO_SUCCESS } -pub fn args_sizes_get<'a, E: CallerEnv<'a>>( - caller_env: &mut E, +pub fn args_sizes_get( + mem: &mut M, + _: &mut E, length_ptr: Uptr, data_size_ptr: Uptr, ) -> Errno { - caller_env.write_u32(length_ptr, 1); - caller_env.write_u32(data_size_ptr, 4); + mem.write_u32(length_ptr, 1); + mem.write_u32(data_size_ptr, 4); ERRNO_SUCCESS } -pub fn args_get<'a, E: CallerEnv<'a>>(caller_env: &mut E, argv_buf: Uptr, data_buf: Uptr) -> Errno { - caller_env.write_u32(argv_buf, data_buf as u32); - caller_env.write_u32(data_buf, 0x6E6962); // "bin\0" +pub fn args_get( + mem: &mut M, + _: &mut E, + argv_buf: Uptr, + data_buf: Uptr, +) -> Errno { + mem.write_u32(argv_buf, data_buf as u32); + mem.write_u32(data_buf, 0x6E6962); // "bin\0" ERRNO_SUCCESS } // we always simulate a timeout -pub fn poll_oneoff<'a, E: CallerEnv<'a>>( - caller_env: &mut E, +pub fn poll_oneoff( + mem: &mut M, + _: &mut E, in_subs: Uptr, out_evt: Uptr, nsubscriptions: u32, @@ -270,24 +322,29 @@ pub fn poll_oneoff<'a, E: CallerEnv<'a>>( const SUBSCRIPTION_SIZE: u32 = 48; for i in 0..nsubscriptions { let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); - let subs_type = caller_env.read_u32(subs_base + 8); + let subs_type = mem.read_u32(subs_base + 8); if subs_type != 0 { // not a clock subscription type continue; } - let user_data = caller_env.read_u32(subs_base); - caller_env.write_u32(out_evt, user_data); - caller_env.write_u32(out_evt + 8, 0); - caller_env.write_u32(nevents_ptr, 1); + let user_data = mem.read_u32(subs_base); + mem.write_u32(out_evt, user_data); + mem.write_u32(out_evt + 8, 0); + mem.write_u32(nevents_ptr, 1); return ERRNO_SUCCESS; } ERRNO_INTVAL } -pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { +pub fn fd_fdstat_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_INTVAL } -pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(_caller_env: &mut E, _: u32, _: u32) -> Errno { +pub fn fd_fdstat_set_flags( + _: &mut M, + _: &mut E, + _: u32, + _: u32, +) -> Errno { ERRNO_INTVAL } diff --git a/arbitrator/jit/src/arbcompress.rs b/arbitrator/jit/src/arbcompress.rs index 2c14a095d..cbf7c7364 100644 --- a/arbitrator/jit/src/arbcompress.rs +++ b/arbitrator/jit/src/arbcompress.rs @@ -1,107 +1,32 @@ // Copyright 2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::callerenv::JitCallerEnv; +use crate::callerenv::jit_env; use crate::machine::Escape; use crate::machine::WasmEnvMut; -use callerenv::CallerEnv; +use callerenv::{self, Uptr}; -extern "C" { - pub fn BrotliDecoderDecompress( - encoded_size: usize, - encoded_buffer: *const u8, - decoded_size: *mut usize, - decoded_buffer: *mut u8, - ) -> BrotliStatus; +macro_rules! wrap { + ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { + let (mut mem, mut env) = jit_env(&mut src); - pub fn BrotliEncoderCompress( - quality: u32, - lgwin: u32, - mode: u32, - input_size: usize, - input_buffer: *const u8, - encoded_size: *mut usize, - encoded_buffer: *mut u8, - ) -> BrotliStatus; -} - -const BROTLI_MODE_GENERIC: u32 = 0; - -#[derive(PartialEq)] -#[repr(u32)] -pub enum BrotliStatus { - Failure, - Success, + Ok(callerenv::brotli::$func_name(&mut mem, &mut env, $($arg_name),*)) + } + }; } -type Uptr = u32; - -/// Brotli decompresses a go slice -/// -/// # Safety -/// -/// The output buffer must be sufficiently large enough. -pub fn brotli_decompress( - mut env: WasmEnvMut, +wrap!(brotli_decompress( in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, - out_len_ptr: Uptr, -) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); - let in_slice = caller_env.read_slice(in_buf_ptr, in_buf_len); - let orig_output_len = caller_env.read_u32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len as usize]; - let mut output_len = orig_output_len; - unsafe { - let res = BrotliDecoderDecompress( - in_buf_len as usize, - in_slice.as_ptr(), - &mut output_len, - output.as_mut_ptr(), - ); - if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return Ok(0); - } - } - caller_env.write_slice(out_buf_ptr, &output[..output_len]); - caller_env.write_u32(out_len_ptr, output_len as u32); - Ok(1) -} + out_len_ptr: Uptr) -> u32); -/// Brotli compresses a go slice -/// -/// The output buffer must be sufficiently large enough. -pub fn brotli_compress( - mut env: WasmEnvMut, +wrap!(brotli_compress( in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, out_len_ptr: Uptr, level: u32, - window_size: u32, -) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); - let in_slice = caller_env.read_slice(in_buf_ptr, in_buf_len); - let orig_output_len = caller_env.read_u32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len]; - let mut output_len = orig_output_len; - - unsafe { - let res = BrotliEncoderCompress( - level, - window_size, - BROTLI_MODE_GENERIC, - in_buf_len as usize, - in_slice.as_ptr(), - &mut output_len, - output.as_mut_ptr(), - ); - if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return Ok(0); - } - } - caller_env.write_slice(out_buf_ptr, &output[..output_len]); - caller_env.write_u32(out_len_ptr, output_len as u32); - Ok(1) -} + window_size: u32 +) -> u32); diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index b85e9ee5e..6d48432a0 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -4,40 +4,39 @@ #![allow(clippy::useless_transmute)] use crate::machine::{WasmEnv, WasmEnvMut}; -use callerenv::CallerEnv; use arbutil::{Bytes20, Bytes32}; -use rand_pcg::Pcg32; +use callerenv::{ExecEnv, MemAccess}; use rand::RngCore; +use rand_pcg::Pcg32; use std::{ collections::{BTreeSet, BinaryHeap}, fmt::Debug, }; use wasmer::{Memory, MemoryView, StoreMut, WasmPtr}; -pub struct JitCallerEnv<'s> { +pub struct JitMemAccess<'s> { pub memory: Memory, pub store: StoreMut<'s>, +} + +pub struct JitExecEnv<'s> { pub wenv: &'s mut WasmEnv, } +pub fn jit_env<'s>(env: &'s mut WasmEnvMut) -> (JitMemAccess<'s>, JitExecEnv<'s>) { + let memory = env.data().memory.clone().unwrap(); + let (wenv, store) = env.data_and_store_mut(); + (JitMemAccess { memory, store }, JitExecEnv { wenv }) +} + #[allow(dead_code)] -impl<'s> JitCallerEnv<'s> { +impl<'s> JitMemAccess<'s> { /// Returns the memory size, in bytes. /// note: wasmer measures memory in 65536-byte pages. fn memory_size(&self) -> u64 { self.view().size().0 as u64 * 65536 } - pub fn new(env: &'s mut WasmEnvMut) -> Self { - let memory = env.data().memory.clone().unwrap(); - let (data, store) = env.data_and_store_mut(); - Self { - memory, - store, - wenv: data, - } - } - fn view(&self) -> MemoryView { self.memory.view(&self.store) } @@ -59,7 +58,7 @@ impl<'s> JitCallerEnv<'s> { } pub fn read_string(&mut self, ptr: u32, len: u32) -> String { - let bytes = self.read_slice(ptr, len); + let bytes = self.read_slice(ptr, len as usize); match String::from_utf8(bytes) { Ok(s) => s, Err(e) => { @@ -69,27 +68,9 @@ impl<'s> JitCallerEnv<'s> { } } } - - pub fn read_slice(&self, ptr: u32, len: u32) -> Vec { - u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency - let len = u32::try_from(len).expect("length isn't a u32") as usize; - let mut data = vec![0; len]; - self.view() - .read(ptr.into(), &mut data) - .expect("failed to read"); - data - } - - pub fn write_slice>(&self, ptr: T, src: &[u8]) - where - T::Error: Debug, - { - let ptr: u32 = ptr.try_into().expect("Go pointer not a u32"); - self.view().write(ptr.into(), src).unwrap(); - } } -impl CallerEnv<'_> for JitCallerEnv<'_> { +impl MemAccess for JitMemAccess<'_> { fn read_u8(&self, ptr: u32) -> u8 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() @@ -130,9 +111,30 @@ impl CallerEnv<'_> for JitCallerEnv<'_> { ptr.deref(&self.view()).write(x).unwrap(); } - fn print_string(&mut self, ptr: u32, len: u32) { - let data = self.read_string(ptr, len); - eprintln!("JIT: WASM says: {data}"); + fn read_slice(&self, ptr: u32, len: usize) -> Vec { + u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency + let len = u32::try_from(len).expect("length isn't a u32") as usize; + let mut data = vec![0; len]; + self.view() + .read(ptr.into(), &mut data) + .expect("failed to read"); + data + } + + fn write_slice(&mut self, ptr: u32, src: &[u8]) { + self.view().write(ptr.into(), src).unwrap(); + } +} + +impl ExecEnv for JitExecEnv<'_> { + fn print_string(&mut self, bytes: &[u8]) { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => eprintln!("JIT: WASM says: {s}"), + Err(e) => { + let bytes = e.as_bytes(); + eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); + } + } } fn get_time(&self) -> u64 { diff --git a/arbitrator/jit/src/machine.rs b/arbitrator/jit/src/machine.rs index 903671913..b639c93ad 100644 --- a/arbitrator/jit/src/machine.rs +++ b/arbitrator/jit/src/machine.rs @@ -68,8 +68,8 @@ pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv, Sto } let imports = imports! { "arbcompress" => { - "brotliCompress" => func!(arbcompress::brotli_compress), - "brotliDecompress" => func!(arbcompress::brotli_decompress), + "brotli_compress" => func!(arbcompress::brotli_compress), + "brotli_decompress" => func!(arbcompress::brotli_decompress), }, "wavmio" => { "getGlobalStateBytes32" => func!(wavmio::get_global_state_bytes32), diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index 72eddffb2..1084b4edf 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -1,12 +1,12 @@ // Copyright 2022-2023, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::callerenv::JitCallerEnv; +use crate::callerenv::jit_env; use crate::machine::{Escape, MaybeEscape, WasmEnvMut}; use crate::stylus_backend::exec_wasm; -use callerenv::CallerEnv; use arbutil::Bytes32; use arbutil::{evm::EvmData, format::DebugBytes, heapify}; +use callerenv::MemAccess; use eyre::eyre; use prover::programs::prelude::StylusConfig; use prover::{ @@ -31,28 +31,28 @@ pub fn activate( err_buf: Uptr, err_buf_len: u32, ) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); - let wasm = caller_env.read_slice(wasm_ptr, wasm_size); + let (mut mem, _) = jit_env(&mut env); + let wasm = mem.read_slice(wasm_ptr, wasm_size as usize); let debug = debug != 0; - let page_limit = caller_env.read_u16(pages_ptr); - let gas_left = &mut caller_env.read_u64(gas_ptr); + let page_limit = mem.read_u16(pages_ptr); + let gas_left = &mut mem.read_u64(gas_ptr); match Module::activate(&wasm, version, page_limit, debug, gas_left) { Ok((module, data)) => { - caller_env.write_u64(gas_ptr, *gas_left); - caller_env.write_u16(pages_ptr, data.footprint); - caller_env.write_u32(asm_estimate_ptr, data.asm_estimate); - caller_env.write_u32(init_gas_ptr, data.init_gas); - caller_env.write_bytes32(module_hash_ptr, module.hash()); + mem.write_u64(gas_ptr, *gas_left); + mem.write_u16(pages_ptr, data.footprint); + mem.write_u32(asm_estimate_ptr, data.asm_estimate); + mem.write_u32(init_gas_ptr, data.init_gas); + mem.write_bytes32(module_hash_ptr, module.hash()); Ok(0) } Err(error) => { let mut err_bytes = error.wrap_err("failed to activate").debug_bytes(); err_bytes.truncate(err_buf_len as usize); - caller_env.write_slice(err_buf, &err_bytes); - caller_env.write_u64(gas_ptr, 0); - caller_env.write_u16(pages_ptr, 0); - caller_env.write_bytes32(module_hash_ptr, Bytes32::default()); + mem.write_slice(err_buf, &err_bytes); + mem.write_u64(gas_ptr, 0); + mem.write_u16(pages_ptr, 0); + mem.write_bytes32(module_hash_ptr, Bytes32::default()); Ok(err_bytes.len() as u32) } } @@ -70,9 +70,9 @@ pub fn new_program( evm_data_handler: u64, gas: u64, ) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); - let compiled_hash = caller_env.read_bytes32(compiled_hash_ptr); - let calldata = caller_env.read_slice(calldata_ptr, calldata_size); + let (mut mem, exec) = jit_env(&mut env); + let compiled_hash = mem.read_bytes32(compiled_hash_ptr); + let calldata = mem.read_slice(calldata_ptr, calldata_size as usize); let evm_data: EvmData = unsafe { *Box::from_raw(evm_data_handler as *mut EvmData) }; let config: JitConfig = unsafe { *Box::from_raw(stylus_config_handler as *mut JitConfig) }; @@ -80,11 +80,11 @@ pub fn new_program( let pricing = config.stylus.pricing; let ink = pricing.gas_to_ink(gas); - let Some(module) = caller_env.wenv.module_asms.get(&compiled_hash).cloned() else { + let Some(module) = exec.wenv.module_asms.get(&compiled_hash).cloned() else { return Err(Escape::Failure(format!( "module hash {:?} not found in {:?}", compiled_hash, - caller_env.wenv.module_asms.keys() + exec.wenv.module_asms.keys() ))); }; @@ -98,24 +98,24 @@ pub fn new_program( ) .unwrap(); - caller_env.wenv.threads.push(cothread); + exec.wenv.threads.push(cothread); - Ok(caller_env.wenv.threads.len() as u32) + Ok(exec.wenv.threads.len() as u32) } /// starts the program (in jit waits for first request) /// module MUST match last module number returned from new_program /// returns request_id for the first request from the program pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { - let caller_env = JitCallerEnv::new(&mut env); + let (_, exec) = jit_env(&mut env); - if caller_env.wenv.threads.len() as u32 != module || module == 0 { + if exec.wenv.threads.len() as u32 != module || module == 0 { return Escape::hostio(format!( "got request for thread {module} but len is {}", - caller_env.wenv.threads.len() + exec.wenv.threads.len() )); } - let thread = caller_env.wenv.threads.last_mut().unwrap(); + let thread = exec.wenv.threads.last_mut().unwrap(); thread.wait_next_message()?; let msg = thread.last_message()?; Ok(msg.1) @@ -124,13 +124,13 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); - let thread = caller_env.wenv.threads.last_mut().unwrap(); + let (mut mem, exec) = jit_env(&mut env); + let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { return Escape::hostio("get_request id doesn't match"); }; - caller_env.write_u32(len_ptr, msg.0.req_data.len() as u32); + mem.write_u32(len_ptr, msg.0.req_data.len() as u32); Ok(msg.0.req_type) } @@ -138,13 +138,13 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); - let thread = caller_env.wenv.threads.last_mut().unwrap(); + let (mut mem, exec) = jit_env(&mut env); + let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { return Escape::hostio("get_request id doesn't match"); }; - caller_env.write_slice(data_ptr, &msg.0.req_data); + mem.write_slice(data_ptr, &msg.0.req_data); Ok(()) } @@ -159,11 +159,11 @@ pub fn set_response( raw_data_ptr: Uptr, raw_data_len: u32, ) -> MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); - let result = caller_env.read_slice(result_ptr, result_len); - let raw_data = caller_env.read_slice(raw_data_ptr, raw_data_len); + let (mem, exec) = jit_env(&mut env); + let result = mem.read_slice(result_ptr, result_len as usize); + let raw_data = mem.read_slice(raw_data_ptr, raw_data_len as usize); - let thread = caller_env.wenv.threads.last_mut().unwrap(); + let thread = exec.wenv.threads.last_mut().unwrap(); thread.set_response(id, result, raw_data, gas) } @@ -171,8 +171,8 @@ pub fn set_response( // MUST be called right after set_response to the same id // returns request_id for the next request pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { - let caller_env = JitCallerEnv::new(&mut env); - let thread = caller_env.wenv.threads.last_mut().unwrap(); + let (_, exec) = jit_env(&mut env); + let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != req_id { return Escape::hostio("get_request id doesn't match"); @@ -184,9 +184,9 @@ pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { // removes the last created program pub fn pop(mut env: WasmEnvMut) -> MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); + let (_, exec) = jit_env(&mut env); - match caller_env.wenv.threads.pop() { + match exec.wenv.threads.pop() { None => Err(Escape::Child(eyre!("no child"))), Some(mut thread) => thread.wait_done(), } @@ -232,20 +232,20 @@ pub fn create_evm_data( tx_origin_ptr: Uptr, reentrant: u32, ) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); + let (mut mem, _) = jit_env(&mut env); let evm_data = EvmData { - block_basefee: caller_env.read_bytes32(block_basefee_ptr), + block_basefee: mem.read_bytes32(block_basefee_ptr), chainid, - block_coinbase: caller_env.read_bytes20(block_coinbase_ptr), + block_coinbase: mem.read_bytes20(block_coinbase_ptr), block_gas_limit, block_number, block_timestamp, - contract_address: caller_env.read_bytes20(contract_address_ptr), - msg_sender: caller_env.read_bytes20(msg_sender_ptr), - msg_value: caller_env.read_bytes32(msg_value_ptr), - tx_gas_price: caller_env.read_bytes32(tx_gas_price_ptr), - tx_origin: caller_env.read_bytes20(tx_origin_ptr), + contract_address: mem.read_bytes20(contract_address_ptr), + msg_sender: mem.read_bytes20(msg_sender_ptr), + msg_value: mem.read_bytes32(msg_value_ptr), + tx_gas_price: mem.read_bytes32(tx_gas_price_ptr), + tx_origin: mem.read_bytes20(tx_origin_ptr), reentrant, return_data_len: 0, tracing: false, diff --git a/arbitrator/jit/src/socket.rs b/arbitrator/jit/src/socket.rs index f8bd9c9e9..740f029f1 100644 --- a/arbitrator/jit/src/socket.rs +++ b/arbitrator/jit/src/socket.rs @@ -12,7 +12,7 @@ use arbutil::Bytes32; pub const SUCCESS: u8 = 0x0; pub const FAILURE: u8 = 0x1; -pub const PREIMAGE: u8 = 0x2; +// not used pub const PREIMAGE: u8 = 0x2; pub const ANOTHER: u8 = 0x3; pub const READY: u8 = 0x4; diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 24e19fc62..5ae4a4372 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -1,7 +1,7 @@ // Copyright 2021-2023, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::callerenv::JitCallerEnv; +use crate::callerenv::jit_env; use crate::machine::{Escape, WasmEnvMut}; use callerenv::{ self, @@ -15,9 +15,9 @@ pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { macro_rules! wrap { ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let mut caller_env = JitCallerEnv::new(&mut src); + let (mut mem, mut env) = jit_env(&mut src); - Ok(callerenv::wasip1_stub::$func_name(&mut caller_env, $($arg_name),*)) + Ok(callerenv::wasip1_stub::$func_name(&mut mem, &mut env, $($arg_name),*)) } }; } diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index 03ba014ba..4e893abf7 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -2,12 +2,12 @@ // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::{ - callerenv::JitCallerEnv, + callerenv::jit_env, machine::{Escape, MaybeEscape, WasmEnv, WasmEnvMut}, socket, }; - use arbutil::Color; +use callerenv::MemAccess; use std::{ io, io::{BufReader, BufWriter, ErrorKind}, @@ -19,25 +19,25 @@ type Uptr = u32; /// Reads 32-bytes of global state pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (mut mem, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - let global = match caller_env.wenv.large_globals.get(idx as usize) { - Some(global) => global, + let global = match exec.wenv.large_globals.get(idx as usize) { + Some(global) => global.clone(), None => return Escape::hostio("global read out of bounds in wavmio.getGlobalStateBytes32"), }; - caller_env.write_slice(out_ptr, &global[..32]); + mem.write_slice(out_ptr, &global[..32]); Ok(()) } /// Writes 32-bytes of global state pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (mem, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - let slice = caller_env.read_slice(src_ptr, 32); + let slice = mem.read_slice(src_ptr, 32); let slice = &slice.try_into().unwrap(); - match caller_env.wenv.large_globals.get_mut(idx as usize) { + match exec.wenv.large_globals.get_mut(idx as usize) { Some(global) => *global = *slice, None => { return Escape::hostio("global write out of bounds in wavmio.setGlobalStateBytes32") @@ -48,10 +48,10 @@ pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> /// Reads 8-bytes of global state pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (_, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - match caller_env.wenv.small_globals.get(idx as usize) { + match exec.wenv.small_globals.get(idx as usize) { Some(global) => Ok(*global), None => Escape::hostio("global read out of bounds in wavmio.getGlobalStateU64"), } @@ -59,10 +59,10 @@ pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result MaybeEscape { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (_, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - match caller_env.wenv.small_globals.get_mut(idx as usize) { + match exec.wenv.small_globals.get_mut(idx as usize) { Some(global) => { *global = val; Ok(()) @@ -78,17 +78,17 @@ pub fn read_inbox_message( offset: u32, out_ptr: Uptr, ) -> Result { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (mut mem, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - let message = match caller_env.wenv.sequencer_messages.get(&msg_num) { + let message = match exec.wenv.sequencer_messages.get(&msg_num) { Some(message) => message, None => return Escape::hostio(format!("missing sequencer inbox message {msg_num}")), }; let offset = offset as usize; let len = std::cmp::min(32, message.len().saturating_sub(offset)); let read = message.get(offset..(offset + len)).unwrap_or_default(); - caller_env.write_slice(out_ptr, read); + mem.write_slice(out_ptr, read); Ok(read.len() as u32) } @@ -99,17 +99,20 @@ pub fn read_delayed_inbox_message( offset: u32, out_ptr: Uptr, ) -> Result { - let caller_env = JitCallerEnv::new(&mut env); - ready_hostio(caller_env.wenv)?; + let (mut mem, exec) = jit_env(&mut env); + ready_hostio(exec.wenv)?; - let message = match caller_env.wenv.delayed_messages.get(&msg_num) { + let message = match exec.wenv.delayed_messages.get(&msg_num) { Some(message) => message, None => return Escape::hostio(format!("missing delayed inbox message {msg_num}")), }; let offset = offset as usize; let len = std::cmp::min(32, message.len().saturating_sub(offset)); - let read = message.get(offset..(offset + len)).unwrap_or_default(); - caller_env.write_slice(out_ptr, read); + let read = message + .get(offset..(offset + len)) + .unwrap_or_default() + .to_vec(); + mem.write_slice(out_ptr, &read); Ok(read.len() as u32) } @@ -120,7 +123,7 @@ pub fn resolve_preimage( offset: u32, out_ptr: Uptr, ) -> Result { - let mut caller_env = JitCallerEnv::new(&mut env); + let (mut mem, exec) = jit_env(&mut env); let name = "wavmio.resolvePreImage"; @@ -131,13 +134,13 @@ pub fn resolve_preimage( }}; } - let hash = caller_env.read_bytes32(hash_ptr); + let hash = mem.read_bytes32(hash_ptr); let hash_hex = hex::encode(hash); let mut preimage = None; // see if we've cached the preimage - if let Some((key, cached)) = &caller_env.wenv.process.last_preimage { + if let Some((key, cached)) = &exec.wenv.process.last_preimage { if *key == hash { preimage = Some(cached); } @@ -145,7 +148,7 @@ pub fn resolve_preimage( // see if this is a known preimage if preimage.is_none() { - preimage = caller_env.wenv.preimages.get(&hash); + preimage = exec.wenv.preimages.get(&hash); } let preimage = match preimage { @@ -159,7 +162,7 @@ pub fn resolve_preimage( let len = std::cmp::min(32, preimage.len().saturating_sub(offset)); let read = preimage.get(offset..(offset + len)).unwrap_or_default(); - caller_env.write_slice(out_ptr, read); + mem.write_slice(out_ptr, read); Ok(read.len() as u32) } diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 4ae060db4..772ea9f84 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -107,7 +107,8 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" name = "brotli" version = "0.1.0" dependencies = [ - "arbutil", + "callerenv", + "paste", ] [[package]] @@ -140,6 +141,12 @@ dependencies = [ "rand_pcg", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -373,7 +380,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi", ] @@ -524,6 +531,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -693,7 +706,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", @@ -1275,8 +1288,7 @@ version = "0.1.0" dependencies = [ "callerenv", "paste", - "rand", - "rand_pcg", + "wee_alloc", ] [[package]] @@ -1333,6 +1345,18 @@ dependencies = [ "wast", ] +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/arbitrator/wasm-libraries/brotli/Cargo.toml b/arbitrator/wasm-libraries/brotli/Cargo.toml index 779929a04..17a568b6d 100644 --- a/arbitrator/wasm-libraries/brotli/Cargo.toml +++ b/arbitrator/wasm-libraries/brotli/Cargo.toml @@ -8,4 +8,5 @@ publish = false crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil", features = ["wavm"] } +paste = {versoion="1.0.14"} +callerenv = { path = "../../callerenv/", features = ["static_caller"] } diff --git a/arbitrator/wasm-libraries/brotli/src/lib.rs b/arbitrator/wasm-libraries/brotli/src/lib.rs index 76715eba6..49ef09d7e 100644 --- a/arbitrator/wasm-libraries/brotli/src/lib.rs +++ b/arbitrator/wasm-libraries/brotli/src/lib.rs @@ -1,91 +1,28 @@ // Copyright 2021-2023, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use arbutil::wavm; - -extern "C" { - pub fn BrotliDecoderDecompress( - encoded_size: usize, - encoded_buffer: *const u8, - decoded_size: *mut usize, - decoded_buffer: *mut u8, - ) -> BrotliStatus; - - pub fn BrotliEncoderCompress( - quality: u32, - lgwin: u32, - mode: u32, - input_size: usize, - input_buffer: *const u8, - encoded_size: *mut usize, - encoded_buffer: *mut u8, - ) -> BrotliStatus; +use callerenv::{ + self, + MemAccess, + ExecEnv, + Uptr +}; +use paste::paste; + +macro_rules! wrap { + ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + paste! { + #[no_mangle] + pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { + callerenv::brotli::$func_name( + &mut callerenv::static_caller::STATIC_MEM, + &mut callerenv::static_caller::STATIC_ENV, + $($arg_name),*) + } + } + }; } -const BROTLI_MODE_GENERIC: u32 = 0; - -type Uptr = usize; - -#[derive(PartialEq)] -#[repr(u32)] -pub enum BrotliStatus { - Failure, - Success, -} +wrap!(brotli_decompress(in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, out_len_ptr: Uptr) -> u32); -/// Brotli decompresses a go slice -/// -/// # Safety -/// -/// The output buffer must be sufficiently large enough. -#[no_mangle] -pub unsafe extern "C" fn arbcompress__brotliDecompress(in_buf_ptr: Uptr, in_buf_len: usize, out_buf_ptr: Uptr, out_len_ptr: Uptr) -> BrotliStatus { - let in_slice = wavm::read_slice_usize(in_buf_ptr, in_buf_len); - let orig_output_len = wavm::caller_load32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len as usize]; - let mut output_len = orig_output_len; - let res = BrotliDecoderDecompress( - in_buf_len as usize, - in_slice.as_ptr(), - &mut output_len, - output.as_mut_ptr(), - ); - if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return BrotliStatus::Failure; - } - wavm::write_slice_usize(&output[..output_len], out_buf_ptr); - wavm::caller_store32(out_len_ptr, output_len as u32); - BrotliStatus::Success -} - -/// Brotli compresses a go slice -/// -/// # Safety -/// -/// The go side has the following signature, which must be respected. -/// λ(inBuf []byte, outBuf []byte, level, windowSize uint64) (outLen uint64, status BrotliStatus) -/// -/// The output buffer must be sufficiently large enough. -#[no_mangle] -pub unsafe extern "C" fn arbcompress__brotliCompress(in_buf_ptr: Uptr, in_buf_len: usize, out_buf_ptr: Uptr, out_len_ptr: Uptr, level: u32, window_size: u32) -> BrotliStatus { - let in_slice = wavm::read_slice_usize(in_buf_ptr, in_buf_len); - let orig_output_len = wavm::caller_load32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len]; - let mut output_len = orig_output_len; - - let res = BrotliEncoderCompress( - level, - window_size, - BROTLI_MODE_GENERIC, - in_buf_len as usize, - in_slice.as_ptr(), - &mut output_len, - output.as_mut_ptr(), - ); - if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return BrotliStatus::Failure; - } - wavm::write_slice_usize(&output[..output_len], out_buf_ptr); - wavm::caller_store32(out_len_ptr, output_len as u32); - BrotliStatus::Success -} +wrap!(brotli_compress(in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, out_len_ptr: Uptr, level: u32, window_size: u32) -> u32); \ No newline at end of file diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index 2d5df5edc..7ba48f646 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -10,5 +10,5 @@ crate-type = ["cdylib"] [dependencies] paste = {versoion="1.0.14"} callerenv = { path = "../../callerenv/", features = ["static_caller"] } -rand = { version = "0.8.4", default-features = false } -rand_pcg = { version = "0.3.1", default-features = false } +wee_alloc = "0.4.5" + diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 80c7bfb59..6482b02a5 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -3,13 +3,14 @@ #![no_std] -use rand::RngCore; use paste::paste; use callerenv::{ self, wasip1_stub::{Errno, Uptr}, - CallerEnv, + MemAccess, + ExecEnv, }; + #[allow(dead_code)] extern "C" { fn wavm_halt_and_set_finished() -> !; @@ -20,6 +21,9 @@ unsafe fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() } +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + #[no_mangle] pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { if code == 0 { @@ -34,7 +38,10 @@ macro_rules! wrap { paste! { #[no_mangle] pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { - callerenv::wasip1_stub::$func_name(&mut callerenv::static_caller::STATIC_CALLER, $($arg_name),*) + callerenv::wasip1_stub::$func_name( + &mut callerenv::static_caller::STATIC_MEM, + &mut callerenv::static_caller::STATIC_ENV, + $($arg_name),*) } } }; From dc85d0393193b7619dbadc7df36a6b43a0d3ac20 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Wed, 28 Feb 2024 20:01:42 -0700 Subject: [PATCH 05/28] remove unused code --- .../arbutil/src/callerenv/wasip1_stub.rs | 292 ------------------ 1 file changed, 292 deletions(-) delete mode 100644 arbitrator/arbutil/src/callerenv/wasip1_stub.rs diff --git a/arbitrator/arbutil/src/callerenv/wasip1_stub.rs b/arbitrator/arbutil/src/callerenv/wasip1_stub.rs deleted file mode 100644 index f9e10ab5d..000000000 --- a/arbitrator/arbutil/src/callerenv/wasip1_stub.rs +++ /dev/null @@ -1,292 +0,0 @@ -use crate::callerenv::CallerEnv; - -pub type Errno = u16; - -pub type Uptr = u32; - -pub const ERRNO_SUCCESS: Errno = 0; -pub const ERRNO_BADF: Errno = 8; -pub const ERRNO_INTVAL: Errno = 28; - -pub fn environ_sizes_get<'a, E: CallerEnv<'a>>( - mut caller_env: E, - length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Errno { - caller_env.write_u32(length_ptr, 0); - caller_env.write_u32(data_size_ptr, 0); - ERRNO_SUCCESS -} - -pub fn fd_write<'a, E: CallerEnv<'a>>( - mut caller_env: E, - fd: u32, - iovecs_ptr: Uptr, - iovecs_len: u32, - ret_ptr: Uptr, -) -> Errno { - if fd != 1 && fd != 2 { - return ERRNO_BADF; - } - let mut size = 0; - for i in 0..iovecs_len { - let ptr = iovecs_ptr + i * 8; - let iovec = caller_env.read_u32(ptr); - let len = caller_env.read_u32(ptr + 4); - caller_env.print_string(iovec, len); - size += len; - } - caller_env.write_u32(ret_ptr, size); - ERRNO_SUCCESS -} - -pub fn environ_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { - ERRNO_INTVAL -} - -pub fn fd_close<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn fd_read<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn fd_readdir<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn fd_sync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32) -> Errno { - ERRNO_SUCCESS -} - -pub fn fd_seek<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _fd: u32, - _offset: u64, - _whence: u8, - _filesize: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn fd_datasync<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32) -> Errno { - ERRNO_BADF -} - -pub fn path_open<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u64, - _: u64, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_create_directory<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_remove_directory<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_readlink<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_rename<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_filestat_get<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn path_unlink_file<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn fd_prestat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn fd_prestat_dir_name<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _: u32, - _: u32, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn fd_filestat_get<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _fd: u32, - _filestat: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn fd_filestat_set_size<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u64) -> Errno { - ERRNO_BADF -} - -pub fn fd_pread<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn fd_pwrite<'a, E: CallerEnv<'a>>( - mut _caller_env: E, - _fd: u32, - _: u32, - _: u32, - _: u64, - _: u32, -) -> Errno { - ERRNO_BADF -} - -pub fn sock_accept<'a, E: CallerEnv<'a>>(mut _caller_env: E, _fd: u32, _: u32, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn sock_shutdown<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { - ERRNO_BADF -} - -pub fn sched_yield<'a, E: CallerEnv<'a>>(mut _caller_env: E) -> Errno { - ERRNO_SUCCESS -} - -// pub fn clock_time_get<'a, E: CallerEnv<'a>>( -// mut caller_env: E, -// _clock_id: u32, -// _precision: u64, -// time: Uptr, -// ) -> Errno { -// caller_env.wenv.go_state.time += caller_env.wenv.go_state.time_interval; -// caller_env.write_u32(time, caller_env.wenv.go_state.time as u32); -// caller_env.write_u32(time + 4, (caller_env.wenv.go_state.time >> 32) as u32); -// ERRNO_SUCCESS -// } - -// pub fn random_get<'a, E: CallerEnv<'a>>(mut caller_env: E, mut buf: u32, mut len: u32) -> Errno { -// while len >= 4 { -// let next_rand = caller_env.wenv.go_state.rng.next_u32(); -// caller_env.write_u32(buf, next_rand); -// buf += 4; -// len -= 4; -// } -// if len > 0 { -// let mut rem = caller_env.wenv.go_state.rng.next_u32(); -// for _ in 0..len { -// caller_env.write_u8(buf, rem as u8); -// buf += 1; -// rem >>= 8; -// } -// } -// ERRNO_SUCCESS -// } - -pub fn args_sizes_get<'a, E: CallerEnv<'a>>( - mut caller_env: E, - length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Errno { - caller_env.write_u32(length_ptr, 1); - caller_env.write_u32(data_size_ptr, 4); - ERRNO_SUCCESS -} - -pub fn args_get<'a, E: CallerEnv<'a>>(mut caller_env: E, argv_buf: Uptr, data_buf: Uptr) -> Errno { - caller_env.write_u32(argv_buf, data_buf as u32); - caller_env.write_u32(data_buf, 0x6E6962); // "bin\0" - ERRNO_SUCCESS -} - -// we always simulate a timeout -pub fn poll_oneoff<'a, E: CallerEnv<'a>>( - mut caller_env: E, - in_subs: Uptr, - out_evt: Uptr, - nsubscriptions: u32, - nevents_ptr: Uptr, -) -> Errno { - const SUBSCRIPTION_SIZE: u32 = 48; - for i in 0..nsubscriptions { - let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); - let subs_type = caller_env.read_u32(subs_base + 8); - if subs_type != 0 { - // not a clock subscription type - continue; - } - let user_data = caller_env.read_u32(subs_base); - caller_env.write_u32(out_evt, user_data); - caller_env.write_u32(out_evt + 8, 0); - caller_env.write_u32(nevents_ptr, 1); - return ERRNO_SUCCESS; - } - ERRNO_INTVAL -} - -pub fn fd_fdstat_get<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { - ERRNO_INTVAL -} - -pub fn fd_fdstat_set_flags<'a, E: CallerEnv<'a>>(mut _caller_env: E, _: u32, _: u32) -> Errno { - ERRNO_INTVAL -} From 0c65c7fb202243c4ded82674d13a8b8e2ab21db1 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 15:29:44 -0700 Subject: [PATCH 06/28] callerenv bugfixes --- Makefile | 2 +- arbitrator/callerenv/Cargo.toml | 3 +-- arbitrator/callerenv/src/static_caller.rs | 6 +++--- arbitrator/callerenv/src/wasip1_stub.rs | 4 ++-- arbitrator/jit/src/wasip1_stub.rs | 5 +---- arbitrator/wasm-libraries/brotli/Cargo.toml | 2 +- arbitrator/wasm-libraries/wasi-stub/Cargo.toml | 2 +- arbitrator/wasm-libraries/wasi-stub/src/lib.rs | 5 ++--- 8 files changed, 12 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index 096668f37..1ab8bbedc 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ WASI_SYSROOT?=/opt/wasi-sdk/wasi-sysroot arbitrator_wasm_lib_flags=$(patsubst %, -l %, $(arbitrator_wasm_libs)) -rust_arbutil_files = $(wildcard arbitrator/arbutil/src/*.* arbitrator/arbutil/src/*/*.* arbitrator/arbutil/*.toml) +rust_arbutil_files = $(wildcard arbitrator/arbutil/src/*.* arbitrator/arbutil/src/*/*.* arbitrator/arbutil/*.toml arbitrator/callerenv/src/*.* arbitrator/callerenv/src/*/*.* arbitrator/callerenv/*.toml) prover_direct_includes = $(patsubst %,$(output_latest)/%.wasm, forward forward_stub) prover_src = arbitrator/prover/src diff --git a/arbitrator/callerenv/Cargo.toml b/arbitrator/callerenv/Cargo.toml index 5b5c6b6d0..15f93d603 100644 --- a/arbitrator/callerenv/Cargo.toml +++ b/arbitrator/callerenv/Cargo.toml @@ -8,5 +8,4 @@ rand_pcg = { version = "0.3.1", default-features = false } rand = { version = "0.8.4", default-features = false } [features] -wavm = [] -static_caller = [] \ No newline at end of file +static_caller = [] diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/callerenv/src/static_caller.rs index 239e72d15..08c1ebcd3 100644 --- a/arbitrator/callerenv/src/static_caller.rs +++ b/arbitrator/callerenv/src/static_caller.rs @@ -1,4 +1,4 @@ -use crate::{create_pcg, wasip1_stub::Uptr, ExecEnv, MemAccess}; +use crate::{create_pcg, ExecEnv, MemAccess, Uptr}; use rand::RngCore; use rand_pcg::Pcg32; @@ -65,7 +65,7 @@ impl MemAccess for StaticMem { fn write_u64(&mut self, ptr: u32, x: u64) { self.write_u32(ptr, (x & 0xffffffff) as u32); - self.write_u32(ptr + 4, ((x >> 16) & 0xffffffff) as u32); + self.write_u32(ptr + 4, ((x >> 32) & 0xffffffff) as u32); } fn read_slice(&self, mut ptr: u32, mut len: usize) -> Vec { @@ -101,7 +101,7 @@ impl MemAccess for StaticMem { } impl ExecEnv for StaticExecEnv { - fn print_string(&mut self, data: &[u8]) {} // TODO? + fn print_string(&mut self, _data: &[u8]) {} // TODO? fn get_time(&self) -> u64 { unsafe { TIME } diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/callerenv/src/wasip1_stub.rs index 4e501de8f..cf931eb04 100644 --- a/arbitrator/callerenv/src/wasip1_stub.rs +++ b/arbitrator/callerenv/src/wasip1_stub.rs @@ -2,7 +2,7 @@ use crate::{ExecEnv, MemAccess}; pub type Errno = u16; -pub use crate::Uptr; +use crate::Uptr; pub const ERRNO_SUCCESS: Errno = 0; pub const ERRNO_BADF: Errno = 8; @@ -268,7 +268,7 @@ pub fn clock_time_get( pub fn random_get( mem: &mut M, env: &mut E, - mut buf: u32, + mut buf: Uptr, mut len: u32, ) -> Errno { while len >= 4 { diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 5ae4a4372..ed57d9f97 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -3,10 +3,7 @@ use crate::callerenv::jit_env; use crate::machine::{Escape, WasmEnvMut}; -use callerenv::{ - self, - wasip1_stub::{Errno, Uptr}, -}; +use callerenv::{self, wasip1_stub::Errno, Uptr}; pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { Err(Escape::Exit(code)) diff --git a/arbitrator/wasm-libraries/brotli/Cargo.toml b/arbitrator/wasm-libraries/brotli/Cargo.toml index 17a568b6d..0f18eb07c 100644 --- a/arbitrator/wasm-libraries/brotli/Cargo.toml +++ b/arbitrator/wasm-libraries/brotli/Cargo.toml @@ -8,5 +8,5 @@ publish = false crate-type = ["cdylib"] [dependencies] -paste = {versoion="1.0.14"} +paste = {version="1.0.14"} callerenv = { path = "../../callerenv/", features = ["static_caller"] } diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index 7ba48f646..efff70277 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -paste = {versoion="1.0.14"} +paste = {version="1.0.14"} callerenv = { path = "../../callerenv/", features = ["static_caller"] } wee_alloc = "0.4.5" diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 6482b02a5..6b9bde8c0 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -6,9 +6,8 @@ use paste::paste; use callerenv::{ self, - wasip1_stub::{Errno, Uptr}, - MemAccess, - ExecEnv, + Uptr, + wasip1_stub::{Errno}, }; #[allow(dead_code)] From b9aa447a5905a7f8f94ab2e9e9dbb53c96485b5a Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 15:59:31 -0700 Subject: [PATCH 07/28] replace arbutil::wavm with static_env --- arbitrator/arbutil/Cargo.toml | 3 - arbitrator/arbutil/src/lib.rs | 3 - arbitrator/arbutil/src/wavm.rs | 138 ------------------ arbitrator/stylus/src/host.rs | 10 -- arbitrator/wasm-libraries/Cargo.lock | 5 +- arbitrator/wasm-libraries/host-io/Cargo.toml | 2 +- arbitrator/wasm-libraries/host-io/src/lib.rs | 16 +- .../wasm-libraries/program-exec/Cargo.toml | 2 +- .../wasm-libraries/user-host-trait/src/lib.rs | 10 +- .../wasm-libraries/user-host/Cargo.toml | 4 +- .../wasm-libraries/user-host/src/link.rs | 72 +++++---- .../wasm-libraries/user-host/src/program.rs | 30 ++-- .../wasm-libraries/user-test/Cargo.toml | 3 +- .../wasm-libraries/user-test/src/host.rs | 35 +++-- 14 files changed, 97 insertions(+), 236 deletions(-) delete mode 100644 arbitrator/arbutil/src/wavm.rs diff --git a/arbitrator/arbutil/Cargo.toml b/arbitrator/arbutil/Cargo.toml index 47f14d60a..f9404ddb8 100644 --- a/arbitrator/arbutil/Cargo.toml +++ b/arbitrator/arbutil/Cargo.toml @@ -13,6 +13,3 @@ tiny-keccak = { version = "2.0.2", features = ["keccak"] } wasmparser.workspace = true serde = { version = "1.0.130", features = ["derive", "rc"] } num_enum = "0.7.1" - -[features] -wavm = [] diff --git a/arbitrator/arbutil/src/lib.rs b/arbitrator/arbutil/src/lib.rs index 9fd2c0940..99d2173c8 100644 --- a/arbitrator/arbutil/src/lib.rs +++ b/arbitrator/arbutil/src/lib.rs @@ -14,9 +14,6 @@ pub mod types; pub use color::{Color, DebugColor}; pub use types::{Bytes20, Bytes32}; -#[cfg(feature = "wavm")] -pub mod wavm; - /// Puts an arbitrary type on the heap. /// Note: the type must be later freed or the value will be leaked. pub fn heapify(value: T) -> *mut T { diff --git a/arbitrator/arbutil/src/wavm.rs b/arbitrator/arbutil/src/wavm.rs deleted file mode 100644 index 5f7e06042..000000000 --- a/arbitrator/arbutil/src/wavm.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2022-2023, Offchain Labs, Inc. -// For license information, see https://github.com/nitro/blob/master/LICENSE - -use crate::{Bytes20, Bytes32}; - -/// WASM page size, or 2^16 bytes. -pub const PAGE_SIZE: u32 = 1 << 16; - -extern "C" { - fn wavm_caller_load8(ptr: usize) -> u8; - fn wavm_caller_load32(ptr: usize) -> u32; - fn wavm_caller_store8(ptr: usize, val: u8); - fn wavm_caller_store32(ptr: usize, val: u32); -} - -pub unsafe fn caller_load8(ptr: usize) -> u8 { - wavm_caller_load8(ptr) -} - -pub unsafe fn caller_load16(ptr: usize) -> u16 { - let lower = caller_load8(ptr); - let upper = caller_load8(ptr + 1); - lower as u16 | ((upper as u16) << 8) -} - -pub unsafe fn caller_load32(ptr: usize) -> u32 { - wavm_caller_load32(ptr) -} - -pub unsafe fn caller_store8(ptr: usize, val: u8) { - wavm_caller_store8(ptr, val) -} - -pub unsafe fn caller_store16(ptr: usize, val: u16) { - caller_store8(ptr, val as u8); - caller_store8(ptr + 1, (val >> 8) as u8); -} - -pub unsafe fn caller_store32(ptr: usize, val: u32) { - wavm_caller_store32(ptr, val) -} - -pub unsafe fn caller_load64(ptr: usize) -> u64 { - let lower = caller_load32(ptr); - let upper = caller_load32(ptr + 4); - lower as u64 | ((upper as u64) << 32) -} - -pub unsafe fn caller_store64(ptr: usize, val: u64) { - caller_store32(ptr, val as u32); - caller_store32(ptr + 4, (val >> 32) as u32); -} - -pub unsafe fn write_slice(src: &[u8], ptr: u64) { - let ptr = usize::try_from(ptr).expect("pointer doesn't fit in usize"); - write_slice_usize(src, ptr) -} - -pub unsafe fn write_slice_u32(src: &[u8], ptr: u32) { - write_slice_usize(src, ptr as usize) -} - -pub unsafe fn write_slice_usize(mut src: &[u8], mut ptr: usize) { - while src.len() >= 4 { - let mut arr = [0u8; 4]; - arr.copy_from_slice(&src[..4]); - caller_store32(ptr, u32::from_le_bytes(arr)); - ptr += 4; - src = &src[4..]; - } - for &byte in src { - caller_store8(ptr, byte); - ptr += 1; - } -} - -pub unsafe fn read_slice(ptr: u64, len: u64) -> Vec { - let ptr = usize::try_from(ptr).expect("pointer doesn't fit in usize"); - let len = usize::try_from(len).expect("length doesn't fit in usize"); - read_slice_usize(ptr, len) -} - -pub unsafe fn read_slice_u32(ptr: u32, len: u32) -> Vec { - read_slice_usize(ptr as usize, len as usize) -} - -pub unsafe fn read_slice_usize(mut ptr: usize, mut len: usize) -> Vec { - let mut data = Vec::with_capacity(len); - if len == 0 { - return data; - } - while len >= 4 { - data.extend(caller_load32(ptr).to_le_bytes()); - ptr += 4; - len -= 4; - } - for _ in 0..len { - data.push(caller_load8(ptr)); - ptr += 1; - } - data -} - -pub unsafe fn read_bytes20_usize(ptr: usize) -> Bytes20 { - let data = read_slice_usize(ptr, 20); - data.try_into().unwrap() -} - -pub unsafe fn read_bytes32_usize(ptr: usize) -> Bytes32 { - let data = read_slice_usize(ptr, 32); - data.try_into().unwrap() -} - -pub unsafe fn read_bytes20(ptr: u32) -> Bytes20 { - let data = read_slice_u32(ptr, 20); - data.try_into().unwrap() -} - -pub unsafe fn read_bytes32(ptr: u32) -> Bytes32 { - let data = read_slice_u32(ptr, 32); - data.try_into().unwrap() -} - -pub unsafe fn write_bytes20(ptr: u32, value: Bytes20) { - write_slice_u32(&value.0, ptr) -} - -pub unsafe fn write_bytes32(ptr: u32, value: Bytes32) { - write_slice_u32(&value.0, ptr) -} - -pub unsafe fn write_bytes20_usize(ptr: usize, value: Bytes20) { - write_slice_usize(&value.0, ptr) -} - -pub unsafe fn write_bytes32_usize(ptr: usize, value: Bytes32) { - write_slice_usize(&value.0, ptr) -} diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index cc738ddf1..51c4ead60 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -65,16 +65,6 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { Ok(()) } - fn write_bytes20(&self, ptr: u32, src: Bytes20) -> Result<(), Self::MemoryErr> { - self.write_slice(ptr, &src.0)?; - Ok(()) - } - - fn write_bytes32(&self, ptr: u32, src: Bytes32) -> Result<(), Self::MemoryErr> { - self.write_slice(ptr, &src.0)?; - Ok(()) - } - fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), Self::MemoryErr> { self.view().write(ptr.into(), src) } diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 772ea9f84..28d7b1765 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -428,7 +428,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "host-io" version = "0.1.0" dependencies = [ - "arbutil", + "callerenv", ] [[package]] @@ -1229,11 +1229,13 @@ name = "user-host" version = "0.1.0" dependencies = [ "arbutil", + "callerenv", "eyre", "fnv", "hex", "prover", "user-host-trait", + "wasmer-types", ] [[package]] @@ -1250,6 +1252,7 @@ name = "user-test" version = "0.1.0" dependencies = [ "arbutil", + "callerenv", "eyre", "fnv", "hex", diff --git a/arbitrator/wasm-libraries/host-io/Cargo.toml b/arbitrator/wasm-libraries/host-io/Cargo.toml index 5ad58b560..0e8a3340a 100644 --- a/arbitrator/wasm-libraries/host-io/Cargo.toml +++ b/arbitrator/wasm-libraries/host-io/Cargo.toml @@ -8,4 +8,4 @@ publish = false crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil/", features = ["wavm"] } +callerenv = { path = "../../callerenv/", features = ["static_caller"] } diff --git a/arbitrator/wasm-libraries/host-io/src/lib.rs b/arbitrator/wasm-libraries/host-io/src/lib.rs index 246294672..a792c852e 100644 --- a/arbitrator/wasm-libraries/host-io/src/lib.rs +++ b/arbitrator/wasm-libraries/host-io/src/lib.rs @@ -1,7 +1,7 @@ // Copyright 2021-2023, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use arbutil::wavm; +use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; extern "C" { pub fn wavm_get_globalstate_bytes32(idx: u32, ptr: *mut u8); @@ -16,22 +16,20 @@ extern "C" { #[repr(C, align(256))] struct MemoryLeaf([u8; 32]); -type Uptr = usize; - #[no_mangle] pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: Uptr) { let mut our_buf = MemoryLeaf([0u8; 32]); let our_ptr = our_buf.0.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); wavm_get_globalstate_bytes32(idx, our_ptr); - wavm::write_slice_usize(&our_buf.0[..32], out_ptr); + STATIC_MEM.write_slice(out_ptr, &our_buf.0[..32]); } /// Writes 32-bytes of global state #[no_mangle] pub unsafe extern "C" fn wavmio__setGlobalStateBytes32(idx: u32, src_ptr: Uptr) { let mut our_buf = MemoryLeaf([0u8; 32]); - let value = wavm::read_slice_usize(src_ptr, 32); + let value = STATIC_MEM.read_slice(src_ptr, 32); our_buf.0.copy_from_slice(&value); let our_ptr = our_buf.0.as_ptr(); assert_eq!(our_ptr as usize % 32, 0); @@ -58,7 +56,7 @@ pub unsafe extern "C" fn wavmio__readInboxMessage(msg_num: u64, offset: usize, o assert_eq!(our_ptr as usize % 32, 0); let read = wavm_read_inbox_message(msg_num, our_ptr, offset); assert!(read <= 32); - wavm::write_slice_usize(&our_buf.0[..read], out_ptr); + STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); read } @@ -70,7 +68,7 @@ pub unsafe extern "C" fn wavmio__readDelayedInboxMessage(msg_num: u64, offset: u assert_eq!(our_ptr as usize % 32, 0); let read = wavm_read_delayed_inbox_message(msg_num, our_ptr, offset as usize); assert!(read <= 32); - wavm::write_slice_usize(&our_buf.0[..read], out_ptr); + STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); read } @@ -78,12 +76,12 @@ pub unsafe extern "C" fn wavmio__readDelayedInboxMessage(msg_num: u64, offset: u #[no_mangle] pub unsafe extern "C" fn wavmio__resolvePreImage(hash_ptr: Uptr, offset: usize, out_ptr: Uptr) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); - let hash = wavm::read_slice_usize(hash_ptr, 32); + let hash = STATIC_MEM.read_slice(hash_ptr, 32); our_buf.0.copy_from_slice(&hash); let our_ptr = our_buf.0.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); let read = wavm_read_pre_image(our_ptr, offset); assert!(read <= 32); - wavm::write_slice_usize(&our_buf.0[..read], out_ptr); + STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); read } diff --git a/arbitrator/wasm-libraries/program-exec/Cargo.toml b/arbitrator/wasm-libraries/program-exec/Cargo.toml index 701b66799..baa4c4907 100644 --- a/arbitrator/wasm-libraries/program-exec/Cargo.toml +++ b/arbitrator/wasm-libraries/program-exec/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil/", features = ["wavm"] } +arbutil = { path = "../../arbutil/" } prover = { path = "../../prover/", default-features = false } eyre = "0.6.5" fnv = "1.0.7" diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index 8f13c59ba..8948f3eac 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -72,8 +72,6 @@ pub trait UserHost: GasMeteredMachine { fn read_slice(&self, ptr: u32, len: u32) -> Result, Self::MemoryErr>; fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), Self::MemoryErr>; - fn write_bytes20(&self, ptr: u32, src: Bytes20) -> Result<(), Self::MemoryErr>; - fn write_bytes32(&self, ptr: u32, src: Bytes32) -> Result<(), Self::MemoryErr>; fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), Self::MemoryErr>; // ink when call stated, only used for tracing, Err if unavailable. @@ -81,6 +79,14 @@ pub trait UserHost: GasMeteredMachine { fn say(&self, text: D); fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], start_ink: u64, end_ink: u64); + fn write_bytes20(&self, ptr: u32, src: Bytes20) -> Result<(), Self::MemoryErr> { + self.write_slice(ptr, &src.0) + } + + fn write_bytes32(&self, ptr: u32, src: Bytes32) -> Result<(), Self::MemoryErr> { + self.write_slice(ptr, &src.0) + } + /// Reads the program calldata. The semantics are equivalent to that of the EVM's /// [`CALLDATA_COPY`] opcode when requesting the entirety of the current call's calldata. /// diff --git a/arbitrator/wasm-libraries/user-host/Cargo.toml b/arbitrator/wasm-libraries/user-host/Cargo.toml index 6b9a32b64..229cdb500 100644 --- a/arbitrator/wasm-libraries/user-host/Cargo.toml +++ b/arbitrator/wasm-libraries/user-host/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil/", features = ["wavm"] } +arbutil = { path = "../../arbutil/" } +callerenv = { path = "../../callerenv/", features = ["static_caller"] } prover = { path = "../../prover/", default-features = false } user-host-trait = { path = "../user-host-trait" } +wasmer-types = { path = "../../tools/wasmer/lib/types" } eyre = "0.6.5" fnv = "1.0.7" hex = "0.4.3" diff --git a/arbitrator/wasm-libraries/user-host/src/link.rs b/arbitrator/wasm-libraries/user-host/src/link.rs index 39e487214..059ba1c71 100644 --- a/arbitrator/wasm-libraries/user-host/src/link.rs +++ b/arbitrator/wasm-libraries/user-host/src/link.rs @@ -7,15 +7,18 @@ use crate::{ use arbutil::{ evm::{user::UserOutcomeKind, EvmData}, format::DebugBytes, - heapify, wavm, Bytes32, + heapify, Bytes20, Bytes32, +}; +use callerenv::{ + Uptr, + MemAccess, + static_caller::STATIC_MEM }; use prover::{ machine::Module, programs::config::{PricingParams, StylusConfig}, }; -type Uptr = usize; - // these hostio methods allow the replay machine to modify itself #[link(wasm_import_module = "hostio")] extern "C" { @@ -56,34 +59,41 @@ pub unsafe extern "C" fn programs__activate( err_buf: Uptr, err_buf_len: usize, ) -> usize { - let wasm = wavm::read_slice_usize(wasm_ptr, wasm_size); + let wasm = STATIC_MEM.read_slice(wasm_ptr, wasm_size); let debug = debug != 0; - let page_limit = wavm::caller_load16(pages_ptr); - let gas_left = &mut wavm::caller_load64(gas_ptr); + let page_limit = STATIC_MEM.read_u16(pages_ptr); + let gas_left = &mut STATIC_MEM.read_u64(gas_ptr); match Module::activate(&wasm, version, page_limit, debug, gas_left) { Ok((module, data)) => { - wavm::caller_store64(gas_ptr, *gas_left); - wavm::caller_store16(pages_ptr, data.footprint); - wavm::caller_store32(asm_estimate_ptr, data.asm_estimate); - wavm::caller_store32(init_gas_ptr, data.init_gas); - wavm::write_bytes32_usize(module_hash_ptr, module.hash()); + STATIC_MEM.write_u64(gas_ptr, *gas_left); + STATIC_MEM.write_u16(pages_ptr, data.footprint); + STATIC_MEM.write_u32(asm_estimate_ptr, data.asm_estimate); + STATIC_MEM.write_u32(init_gas_ptr, data.init_gas); + STATIC_MEM.write_slice(module_hash_ptr, module.hash().as_slice()); 0 }, Err(error) => { let mut err_bytes = error.wrap_err("failed to activate").debug_bytes(); err_bytes.truncate(err_buf_len); - wavm::write_slice_usize(&err_bytes, err_buf); - wavm::caller_store64(gas_ptr, 0); - wavm::caller_store16(pages_ptr, 0); - wavm::caller_store32(asm_estimate_ptr, 0); - wavm::caller_store32(init_gas_ptr, 0); - wavm::write_bytes32_usize(module_hash_ptr, Bytes32::default()); + STATIC_MEM.write_slice(err_buf, &err_bytes); + STATIC_MEM.write_u64(gas_ptr, 0); + STATIC_MEM.write_u16(pages_ptr, 0); + STATIC_MEM.write_u32(asm_estimate_ptr, 0); + STATIC_MEM.write_u32(init_gas_ptr, 0); + STATIC_MEM.write_slice(module_hash_ptr, Bytes32::default().as_slice()); err_bytes.len() }, } } +unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { + STATIC_MEM.read_slice(ptr, 32).try_into().unwrap() +} + +unsafe fn read_bytes20(ptr: Uptr) -> Bytes20 { + STATIC_MEM.read_slice(ptr, 20).try_into().unwrap() +} /// Links and creates user program /// consumes both evm_data_handler and config_handler @@ -98,8 +108,8 @@ pub unsafe extern "C" fn programs__new_program( evm_data_box: u64, gas: u64, ) -> u32 { - let compiled_hash = wavm::read_bytes32_usize(compiled_hash_ptr); - let calldata = wavm::read_slice_usize(calldata_ptr, calldata_size); + let compiled_hash = read_bytes32(compiled_hash_ptr); + let calldata = STATIC_MEM.read_slice(calldata_ptr, calldata_size); let config: StylusConfig = *Box::from_raw(config_box as *mut StylusConfig); let evm_data: EvmData = *Box::from_raw(evm_data_box as *mut EvmData); @@ -121,10 +131,10 @@ pub unsafe extern "C" fn programs__new_program( // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response #[no_mangle] -pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: usize) -> u32 { +pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: Uptr) -> u32 { let (req_type, len) = Program::current().evm_api.request_handler().get_request_meta(id); if len_ptr != 0 { - wavm::caller_store32(len_ptr, len as u32); + STATIC_MEM.write_u32(len_ptr, len as u32); } req_type } @@ -133,9 +143,9 @@ pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: usize) -> u32 { // request_id MUST be last request receieved // data_ptr MUST point to a buffer of at least the length returned by get_request #[no_mangle] -pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: usize) { +pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: Uptr) { let (_, data) = Program::current().evm_api.request_handler().take_request(id); - wavm::write_slice_usize(&data, data_ptr); + STATIC_MEM.write_slice(data_ptr, &data); } // sets response for the next request made @@ -151,7 +161,7 @@ pub unsafe extern "C" fn programs__set_response( raw_data_len: usize, ) { let program = Program::current(); - program.evm_api.request_handler().set_response(id, wavm::read_slice_usize(result_ptr, result_len), wavm::read_slice_usize(raw_data_ptr, raw_data_len), gas); + program.evm_api.request_handler().set_response(id, STATIC_MEM.read_slice(result_ptr, result_len), STATIC_MEM.read_slice(raw_data_ptr, raw_data_len), gas); } // removes the last created program @@ -238,17 +248,17 @@ pub unsafe extern "C" fn programs__create_evm_data( reentrant: u32, ) -> u64 { let evm_data = EvmData { - block_basefee: wavm::read_bytes32_usize(block_basefee_ptr), + block_basefee: read_bytes32(block_basefee_ptr), chainid, - block_coinbase: wavm::read_bytes20_usize(block_coinbase_ptr), + block_coinbase: read_bytes20(block_coinbase_ptr), block_gas_limit, block_number, block_timestamp, - contract_address: wavm::read_bytes20_usize(contract_address_ptr), - msg_sender: wavm::read_bytes20_usize(msg_sender_ptr), - msg_value: wavm::read_bytes32_usize(msg_value_ptr), - tx_gas_price: wavm::read_bytes32_usize(tx_gas_price_ptr), - tx_origin: wavm::read_bytes20_usize(tx_origin_ptr), + contract_address: read_bytes20(contract_address_ptr), + msg_sender: read_bytes20(msg_sender_ptr), + msg_value: read_bytes32(msg_value_ptr), + tx_gas_price: read_bytes32(tx_gas_price_ptr), + tx_origin: read_bytes20(tx_origin_ptr), reentrant, return_data_len: 0, tracing: false, diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 50b5cf99f..8e535f96a 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -3,8 +3,10 @@ use core::sync::atomic::{compiler_fence, Ordering}; use arbutil::{ evm::{req::{EvmApiRequestor, RequestHandler}, EvmData, api::{{VecReader, EvmApiMethod, EVM_API_METHOD_REQ_OFFSET}}}, - wavm, Bytes20, Bytes32, Color, + Bytes20, Bytes32, Color, }; +use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; +use wasmer_types::WASM_PAGE_SIZE; use eyre::{bail, eyre, Result}; use prover::programs::prelude::*; use std::fmt::Display; @@ -172,8 +174,8 @@ impl Program { } /// Ensures an access is within bounds - fn check_memory_access(&self, ptr: u32, bytes: u32) -> Result<(), MemoryBoundsError> { - let last_page = ptr.saturating_add(bytes) / wavm::PAGE_SIZE; + fn check_memory_access(&self, ptr: Uptr, bytes: u32) -> Result<(), MemoryBoundsError> { + let last_page = ptr.saturating_add(bytes) / (WASM_PAGE_SIZE as Uptr); if last_page > self.memory_size() { return Err(MemoryBoundsError); } @@ -208,38 +210,26 @@ impl UserHost for Program { } fn read_bytes20(&self, ptr: u32) -> Result { - self.check_memory_access(ptr, 20)?; - unsafe { Ok(wavm::read_bytes20(ptr)) } + self.read_slice(ptr, 20).and_then(|x| Ok(x.try_into().unwrap())) } fn read_bytes32(&self, ptr: u32) -> Result { - self.check_memory_access(ptr, 32)?; - unsafe { Ok(wavm::read_bytes32(ptr)) } + self.read_slice(ptr, 32).and_then(|x| Ok(x.try_into().unwrap())) } fn read_slice(&self, ptr: u32, len: u32) -> Result, MemoryBoundsError> { self.check_memory_access(ptr, len)?; - unsafe { Ok(wavm::read_slice_u32(ptr, len)) } + unsafe { Ok(STATIC_MEM.read_slice(ptr, len as usize)) } } fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, 4)?; - unsafe { Ok(wavm::caller_store32(ptr as usize, x)) } - } - - fn write_bytes20(&self, ptr: u32, src: Bytes20) -> Result<(), MemoryBoundsError> { - self.check_memory_access(ptr, 20)?; - unsafe { Ok(wavm::write_bytes20(ptr, src)) } - } - - fn write_bytes32(&self, ptr: u32, src: Bytes32) -> Result<(), MemoryBoundsError> { - self.check_memory_access(ptr, 32)?; - unsafe { Ok(wavm::write_bytes32(ptr, src)) } + unsafe { Ok(STATIC_MEM.write_u32(ptr, x)) } } fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, src.len() as u32)?; - unsafe { Ok(wavm::write_slice_u32(src, ptr)) } + unsafe { Ok(STATIC_MEM.write_slice(ptr, src)) } } fn say(&self, text: D) { diff --git a/arbitrator/wasm-libraries/user-test/Cargo.toml b/arbitrator/wasm-libraries/user-test/Cargo.toml index e1e43117d..b86deb5a1 100644 --- a/arbitrator/wasm-libraries/user-test/Cargo.toml +++ b/arbitrator/wasm-libraries/user-test/Cargo.toml @@ -7,7 +7,8 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil/", features = ["wavm"] } +arbutil = { path = "../../arbutil/" } +callerenv = { path = "../../callerenv/", features = ["static_caller"] } prover = { path = "../../prover/", default-features = false } eyre = "0.6.5" fnv = "1.0.7" diff --git a/arbitrator/wasm-libraries/user-test/src/host.rs b/arbitrator/wasm-libraries/user-test/src/host.rs index 391d994f8..624241f9f 100644 --- a/arbitrator/wasm-libraries/user-test/src/host.rs +++ b/arbitrator/wasm-libraries/user-test/src/host.rs @@ -7,51 +7,56 @@ use crate::{Program, ARGS, EVER_PAGES, KEYS, LOGS, OPEN_PAGES, OUTS}; use arbutil::{ crypto, evm, pricing::{EVM_API_INK, HOSTIO_INK, PTR_INK}, - wavm, + Bytes20, Bytes32 }; use prover::programs::{ memory::MemoryModel, prelude::{GasMeteredMachine, MeteredMachine}, }; +use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; + +unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { + STATIC_MEM.read_slice(ptr, 32).try_into().unwrap() +} #[no_mangle] -pub unsafe extern "C" fn vm_hooks__read_args(ptr: u32) { +pub unsafe extern "C" fn vm_hooks__read_args(ptr: Uptr) { let mut program = Program::start(0); program.pay_for_write(ARGS.len() as u32).unwrap(); - wavm::write_slice_u32(&ARGS, ptr); + STATIC_MEM.write_slice(ptr, &ARGS); } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__write_result(ptr: u32, len: u32) { +pub unsafe extern "C" fn vm_hooks__write_result(ptr: Uptr, len: u32) { let mut program = Program::start(0); program.pay_for_read(len).unwrap(); program.pay_for_geth_bytes(len).unwrap(); - OUTS = wavm::read_slice_u32(ptr, len); + OUTS = STATIC_MEM.read_slice(ptr, len as usize); } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: u32, dest: u32) { +pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: Uptr, dest: Uptr) { let mut program = Program::start(2 * PTR_INK + EVM_API_INK); - let key = wavm::read_bytes32(key); + let key = read_bytes32(key); let value = KEYS.lock().get(&key).cloned().unwrap_or_default(); program.buy_gas(2100).unwrap(); // pretend it was cold - wavm::write_bytes32(dest, value); + STATIC_MEM.write_slice(dest, &value.0); } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: u32, value: u32) { +pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: Uptr, value: Uptr) { let mut program = Program::start(2 * PTR_INK + EVM_API_INK); program.require_gas(evm::SSTORE_SENTRY_GAS).unwrap(); program.buy_gas(22100).unwrap(); // pretend the worst case - let key = wavm::read_bytes32(key); - let value = wavm::read_bytes32(value); + let key = read_bytes32(key); + let value = read_bytes32(value); KEYS.lock().insert(key, value); } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__emit_log(data: u32, len: u32, topics: u32) { +pub unsafe extern "C" fn vm_hooks__emit_log(data: Uptr, len: u32, topics: u32) { let mut program = Program::start(EVM_API_INK); if topics > 4 || len < topics * 32 { panic!("bad topic data"); @@ -59,7 +64,7 @@ pub unsafe extern "C" fn vm_hooks__emit_log(data: u32, len: u32, topics: u32) { program.pay_for_read(len.into()).unwrap(); program.pay_for_evm_log(topics, len - topics * 32).unwrap(); - let data = wavm::read_slice_u32(data, len); + let data = STATIC_MEM.read_slice(data, len as usize); LOGS.push(data) } @@ -82,9 +87,9 @@ pub unsafe extern "C" fn vm_hooks__native_keccak256(bytes: u32, len: u32, output let mut program = Program::start(0); program.pay_for_keccak(len).unwrap(); - let preimage = wavm::read_slice_u32(bytes, len); + let preimage = STATIC_MEM.read_slice(bytes, len as usize); let digest = crypto::keccak(preimage); - wavm::write_slice_u32(&digest, output); + STATIC_MEM.write_slice(output, &digest); } #[no_mangle] From cd906c1605223ebac2f8f0afc16f66c7f717dd25 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 16:46:20 -0700 Subject: [PATCH 08/28] caller_env: use read_fixed --- arbitrator/callerenv/src/lib.rs | 2 ++ arbitrator/callerenv/src/static_caller.rs | 4 ++++ arbitrator/jit/src/callerenv.rs | 8 ++++++-- arbitrator/stylus/src/host.rs | 15 ++++++--------- .../wasm-libraries/user-host-trait/src/lib.rs | 11 +++++++++-- arbitrator/wasm-libraries/user-host/src/link.rs | 4 ++-- .../wasm-libraries/user-host/src/program.rs | 12 ++++-------- arbitrator/wasm-libraries/user-test/src/host.rs | 2 +- 8 files changed, 34 insertions(+), 24 deletions(-) diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs index e34ced853..82f667f7c 100644 --- a/arbitrator/callerenv/src/lib.rs +++ b/arbitrator/callerenv/src/lib.rs @@ -38,6 +38,8 @@ pub trait MemAccess { fn read_slice(&self, ptr: Uptr, len: usize) -> Vec; + fn read_fixed(&self, ptr: u32) -> [u8; N]; + fn write_slice(&mut self, ptr: Uptr, data: &[u8]); } diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/callerenv/src/static_caller.rs index 08c1ebcd3..8bbb58932 100644 --- a/arbitrator/callerenv/src/static_caller.rs +++ b/arbitrator/callerenv/src/static_caller.rs @@ -85,6 +85,10 @@ impl MemAccess for StaticMem { data } + fn read_fixed(&self, ptr: u32) -> [u8; N] { + self.read_slice(ptr, N).try_into().unwrap() + } + fn write_slice(&mut self, mut ptr: u32, mut src: &[u8]) { while src.len() >= 4 { let mut arr = [0u8; 4]; diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index 6d48432a0..c20f06d97 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -50,11 +50,11 @@ impl<'s> JitMemAccess<'s> { } pub fn read_bytes20(&mut self, ptr: u32) -> Bytes20 { - self.read_slice(ptr, 20).try_into().unwrap() + self.read_fixed(ptr).into() } pub fn read_bytes32(&mut self, ptr: u32) -> Bytes32 { - self.read_slice(ptr, 32).try_into().unwrap() + self.read_fixed(ptr).into() } pub fn read_string(&mut self, ptr: u32, len: u32) -> String { @@ -121,6 +121,10 @@ impl MemAccess for JitMemAccess<'_> { data } + fn read_fixed(&self, ptr: u32) -> [u8; N] { + self.read_slice(ptr, N).try_into().unwrap() + } + fn write_slice(&mut self, ptr: u32, src: &[u8]) { self.view().write(ptr.into(), src).unwrap(); } diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index 51c4ead60..40b905ea2 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -11,7 +11,7 @@ use arbutil::{ api::{DataReader, EvmApi}, EvmData, }, - Bytes20, Bytes32, Color, + Color, }; use eyre::{eyre, Result}; use prover::value::Value; @@ -43,14 +43,11 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { &mut self.evm_data.return_data_len } - fn read_bytes20(&self, ptr: u32) -> Result { - let data = self.read_fixed(ptr)?; - Ok(data.into()) - } - - fn read_bytes32(&self, ptr: u32) -> Result { - let data = self.read_fixed(ptr)?; - Ok(data.into()) + fn read_fixed( + &self, + ptr: u32, + ) -> std::result::Result<[u8; N], >::MemoryErr> { + HostioInfo::read_fixed(&self, ptr) } fn read_slice(&self, ptr: u32, len: u32) -> Result, Self::MemoryErr> { diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index 8948f3eac..f7c3502a7 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -67,13 +67,20 @@ pub trait UserHost: GasMeteredMachine { fn evm_data(&self) -> &EvmData; fn evm_return_data_len(&mut self) -> &mut u32; - fn read_bytes20(&self, ptr: u32) -> Result; - fn read_bytes32(&self, ptr: u32) -> Result; fn read_slice(&self, ptr: u32, len: u32) -> Result, Self::MemoryErr>; + fn read_fixed(&self, ptr: u32) -> Result<[u8; N], Self::MemoryErr>; fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), Self::MemoryErr>; fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), Self::MemoryErr>; + fn read_bytes20(&self, ptr: u32) -> Result { + self.read_fixed(ptr).and_then(|x| Ok(x.into())) + } + + fn read_bytes32(&self, ptr: u32) -> Result { + self.read_fixed(ptr).and_then(|x| Ok(x.into())) + } + // ink when call stated, only used for tracing, Err if unavailable. fn start_ink(&self) -> Result; fn say(&self, text: D); diff --git a/arbitrator/wasm-libraries/user-host/src/link.rs b/arbitrator/wasm-libraries/user-host/src/link.rs index 059ba1c71..a875f871d 100644 --- a/arbitrator/wasm-libraries/user-host/src/link.rs +++ b/arbitrator/wasm-libraries/user-host/src/link.rs @@ -88,11 +88,11 @@ pub unsafe extern "C" fn programs__activate( } unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { - STATIC_MEM.read_slice(ptr, 32).try_into().unwrap() + STATIC_MEM.read_fixed(ptr).into() } unsafe fn read_bytes20(ptr: Uptr) -> Bytes20 { - STATIC_MEM.read_slice(ptr, 20).try_into().unwrap() + STATIC_MEM.read_fixed(ptr).into() } /// Links and creates user program diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 8e535f96a..3c3aa2787 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -209,19 +209,15 @@ impl UserHost for Program { &mut self.evm_data.return_data_len } - fn read_bytes20(&self, ptr: u32) -> Result { - self.read_slice(ptr, 20).and_then(|x| Ok(x.try_into().unwrap())) - } - - fn read_bytes32(&self, ptr: u32) -> Result { - self.read_slice(ptr, 32).and_then(|x| Ok(x.try_into().unwrap())) - } - fn read_slice(&self, ptr: u32, len: u32) -> Result, MemoryBoundsError> { self.check_memory_access(ptr, len)?; unsafe { Ok(STATIC_MEM.read_slice(ptr, len as usize)) } } + fn read_fixed(&self, ptr: u32) -> Result<[u8; N], MemoryBoundsError> { + self.read_slice(ptr, N as u32).and_then(|x| Ok(x.try_into().unwrap())) + } + fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, 4)?; unsafe { Ok(STATIC_MEM.write_u32(ptr, x)) } diff --git a/arbitrator/wasm-libraries/user-test/src/host.rs b/arbitrator/wasm-libraries/user-test/src/host.rs index 624241f9f..3e7f40c68 100644 --- a/arbitrator/wasm-libraries/user-test/src/host.rs +++ b/arbitrator/wasm-libraries/user-test/src/host.rs @@ -16,7 +16,7 @@ use prover::programs::{ use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { - STATIC_MEM.read_slice(ptr, 32).try_into().unwrap() + STATIC_MEM.read_fixed(ptr).into() } #[no_mangle] From c3a602702b889d88ee0de9f84aadef87c7ef3dec Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 17:12:53 -0700 Subject: [PATCH 09/28] converge Uptr --- arbitrator/callerenv/src/brotli.rs | 4 +-- arbitrator/callerenv/src/lib.rs | 2 +- arbitrator/callerenv/src/static_caller.rs | 22 +++++++-------- arbitrator/jit/src/callerenv.rs | 34 +++++++++++------------ arbitrator/jit/src/program.rs | 8 ++---- arbitrator/jit/src/wavmio.rs | 4 +-- 6 files changed, 34 insertions(+), 40 deletions(-) diff --git a/arbitrator/callerenv/src/brotli.rs b/arbitrator/callerenv/src/brotli.rs index 8c5629d6c..59ba9d847 100644 --- a/arbitrator/callerenv/src/brotli.rs +++ b/arbitrator/callerenv/src/brotli.rs @@ -1,6 +1,6 @@ // Copyright 2021-2023, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::{ExecEnv, MemAccess}; +use crate::{ExecEnv, MemAccess, Uptr}; use alloc::vec; #[derive(PartialEq)] @@ -29,8 +29,6 @@ extern "C" { ) -> BrotliStatus; } -type Uptr = u32; - const BROTLI_MODE_GENERIC: u32 = 0; /// Brotli decompresses a go slice1 diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs index 82f667f7c..b056c0f23 100644 --- a/arbitrator/callerenv/src/lib.rs +++ b/arbitrator/callerenv/src/lib.rs @@ -38,7 +38,7 @@ pub trait MemAccess { fn read_slice(&self, ptr: Uptr, len: usize) -> Vec; - fn read_fixed(&self, ptr: u32) -> [u8; N]; + fn read_fixed(&self, ptr: Uptr) -> [u8; N]; fn write_slice(&mut self, ptr: Uptr, data: &[u8]); } diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/callerenv/src/static_caller.rs index 8bbb58932..78a57d4df 100644 --- a/arbitrator/callerenv/src/static_caller.rs +++ b/arbitrator/callerenv/src/static_caller.rs @@ -25,50 +25,50 @@ extern "C" { } impl MemAccess for StaticMem { - fn read_u8(&self, ptr: u32) -> u8 { + fn read_u8(&self, ptr: Uptr) -> u8 { unsafe { wavm_caller_load8(ptr) } } - fn read_u16(&self, ptr: u32) -> u16 { + fn read_u16(&self, ptr: Uptr) -> u16 { let lsb = self.read_u8(ptr); let msb = self.read_u8(ptr + 1); (msb as u16) << 8 | (lsb as u16) } - fn read_u32(&self, ptr: u32) -> u32 { + fn read_u32(&self, ptr: Uptr) -> u32 { let lsb = self.read_u16(ptr); let msb = self.read_u16(ptr + 2); (msb as u32) << 16 | (lsb as u32) } - fn read_u64(&self, ptr: u32) -> u64 { + fn read_u64(&self, ptr: Uptr) -> u64 { let lsb = self.read_u32(ptr); let msb = self.read_u32(ptr + 4); (msb as u64) << 32 | (lsb as u64) } - fn write_u8(&mut self, ptr: u32, x: u8) { + fn write_u8(&mut self, ptr: Uptr, x: u8) { unsafe { wavm_caller_store8(ptr, x); } } - fn write_u16(&mut self, ptr: u32, x: u16) { + fn write_u16(&mut self, ptr: Uptr, x: u16) { self.write_u8(ptr, (x & 0xff) as u8); self.write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); } - fn write_u32(&mut self, ptr: u32, x: u32) { + fn write_u32(&mut self, ptr: Uptr, x: u32) { self.write_u16(ptr, (x & 0xffff) as u16); self.write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); } - fn write_u64(&mut self, ptr: u32, x: u64) { + fn write_u64(&mut self, ptr: Uptr, x: u64) { self.write_u32(ptr, (x & 0xffffffff) as u32); self.write_u32(ptr + 4, ((x >> 32) & 0xffffffff) as u32); } - fn read_slice(&self, mut ptr: u32, mut len: usize) -> Vec { + fn read_slice(&self, mut ptr: Uptr, mut len: usize) -> Vec { let mut data = Vec::with_capacity(len); if len == 0 { return data; @@ -85,11 +85,11 @@ impl MemAccess for StaticMem { data } - fn read_fixed(&self, ptr: u32) -> [u8; N] { + fn read_fixed(&self, ptr: Uptr) -> [u8; N] { self.read_slice(ptr, N).try_into().unwrap() } - fn write_slice(&mut self, mut ptr: u32, mut src: &[u8]) { + fn write_slice(&mut self, mut ptr: Uptr, mut src: &[u8]) { while src.len() >= 4 { let mut arr = [0u8; 4]; arr.copy_from_slice(&src[..4]); diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/callerenv.rs index c20f06d97..8a2027eee 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/callerenv.rs @@ -5,7 +5,7 @@ use crate::machine::{WasmEnv, WasmEnvMut}; use arbutil::{Bytes20, Bytes32}; -use callerenv::{ExecEnv, MemAccess}; +use callerenv::{ExecEnv, MemAccess, Uptr}; use rand::RngCore; use rand_pcg::Pcg32; use std::{ @@ -41,23 +41,23 @@ impl<'s> JitMemAccess<'s> { self.memory.view(&self.store) } - pub fn write_bytes20(&mut self, ptr: u32, val: Bytes20) { + pub fn write_bytes20(&mut self, ptr: Uptr, val: Bytes20) { self.write_slice(ptr, val.as_slice()) } - pub fn write_bytes32(&mut self, ptr: u32, val: Bytes32) { + pub fn write_bytes32(&mut self, ptr: Uptr, val: Bytes32) { self.write_slice(ptr, val.as_slice()) } - pub fn read_bytes20(&mut self, ptr: u32) -> Bytes20 { + pub fn read_bytes20(&mut self, ptr: Uptr) -> Bytes20 { self.read_fixed(ptr).into() } - pub fn read_bytes32(&mut self, ptr: u32) -> Bytes32 { + pub fn read_bytes32(&mut self, ptr: Uptr) -> Bytes32 { self.read_fixed(ptr).into() } - pub fn read_string(&mut self, ptr: u32, len: u32) -> String { + pub fn read_string(&mut self, ptr: Uptr, len: u32) -> String { let bytes = self.read_slice(ptr, len as usize); match String::from_utf8(bytes) { Ok(s) => s, @@ -71,47 +71,47 @@ impl<'s> JitMemAccess<'s> { } impl MemAccess for JitMemAccess<'_> { - fn read_u8(&self, ptr: u32) -> u8 { + fn read_u8(&self, ptr: Uptr) -> u8 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn read_u16(&self, ptr: u32) -> u16 { + fn read_u16(&self, ptr: Uptr) -> u16 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn read_u32(&self, ptr: u32) -> u32 { + fn read_u32(&self, ptr: Uptr) -> u32 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn read_u64(&self, ptr: u32) -> u64 { + fn read_u64(&self, ptr: Uptr) -> u64 { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).read().unwrap() } - fn write_u8(&mut self, ptr: u32, x: u8) { + fn write_u8(&mut self, ptr: Uptr, x: u8) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u16(&mut self, ptr: u32, x: u16) { + fn write_u16(&mut self, ptr: Uptr, x: u16) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u32(&mut self, ptr: u32, x: u32) { + fn write_u32(&mut self, ptr: Uptr, x: u32) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u64(&mut self, ptr: u32, x: u64) { + fn write_u64(&mut self, ptr: Uptr, x: u64) { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x).unwrap(); } - fn read_slice(&self, ptr: u32, len: usize) -> Vec { + fn read_slice(&self, ptr: Uptr, len: usize) -> Vec { u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency let len = u32::try_from(len).expect("length isn't a u32") as usize; let mut data = vec![0; len]; @@ -121,11 +121,11 @@ impl MemAccess for JitMemAccess<'_> { data } - fn read_fixed(&self, ptr: u32) -> [u8; N] { + fn read_fixed(&self, ptr: Uptr) -> [u8; N] { self.read_slice(ptr, N).try_into().unwrap() } - fn write_slice(&mut self, ptr: u32, src: &[u8]) { + fn write_slice(&mut self, ptr: Uptr, src: &[u8]) { self.view().write(ptr.into(), src).unwrap(); } } diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index 1084b4edf..6a258b466 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -6,7 +6,7 @@ use crate::machine::{Escape, MaybeEscape, WasmEnvMut}; use crate::stylus_backend::exec_wasm; use arbutil::Bytes32; use arbutil::{evm::EvmData, format::DebugBytes, heapify}; -use callerenv::MemAccess; +use callerenv::{MemAccess, Uptr}; use eyre::eyre; use prover::programs::prelude::StylusConfig; use prover::{ @@ -14,8 +14,6 @@ use prover::{ programs::{config::PricingParams, prelude::*}, }; -type Uptr = u32; - /// activates a user program pub fn activate( mut env: WasmEnvMut, @@ -123,7 +121,7 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response -pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result { +pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: Uptr) -> Result { let (mut mem, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; @@ -137,7 +135,7 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: u32) -> Result MaybeEscape { +pub fn get_request_data(mut env: WasmEnvMut, id: u32, data_ptr: Uptr) -> MaybeEscape { let (mut mem, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index 4e893abf7..5c2f909ac 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -7,7 +7,7 @@ use crate::{ socket, }; use arbutil::Color; -use callerenv::MemAccess; +use callerenv::{MemAccess, Uptr}; use std::{ io, io::{BufReader, BufWriter, ErrorKind}, @@ -15,8 +15,6 @@ use std::{ time::Instant, }; -type Uptr = u32; - /// Reads 32-bytes of global state pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> MaybeEscape { let (mut mem, exec) = jit_env(&mut env); From 77eb0731fcc908ce445e9e279ea335563d787bf4 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 18:05:27 -0700 Subject: [PATCH 10/28] converge more on Uptr --- arbitrator/Cargo.lock | 1 + arbitrator/stylus/src/host.rs | 48 ++++---- arbitrator/wasm-libraries/Cargo.lock | 1 + .../wasm-libraries/user-host-trait/Cargo.toml | 1 + .../wasm-libraries/user-host-trait/src/lib.rs | 111 +++++++++--------- .../wasm-libraries/user-host/src/host.rs | 74 ++++++------ .../wasm-libraries/user-host/src/program.rs | 10 +- 7 files changed, 125 insertions(+), 121 deletions(-) diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index 42c7bc888..b4e7ebc7b 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -1851,6 +1851,7 @@ name = "user-host-trait" version = "0.1.0" dependencies = [ "arbutil", + "callerenv", "eyre", "prover", ] diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index 40b905ea2..bed09f686 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -15,7 +15,7 @@ use arbutil::{ }; use eyre::{eyre, Result}; use prover::value::Value; -use user_host_trait::UserHost; +use user_host_trait::{Uptr, UserHost}; use wasmer::{MemoryAccessError, WasmPtr}; impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { @@ -45,24 +45,24 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { fn read_fixed( &self, - ptr: u32, + ptr: Uptr, ) -> std::result::Result<[u8; N], >::MemoryErr> { HostioInfo::read_fixed(&self, ptr) } - fn read_slice(&self, ptr: u32, len: u32) -> Result, Self::MemoryErr> { + fn read_slice(&self, ptr: Uptr, len: u32) -> Result, Self::MemoryErr> { let mut data = vec![0; len as usize]; self.view().read(ptr.into(), &mut data)?; Ok(data) } - fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), Self::MemoryErr> { + fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), Self::MemoryErr> { let ptr: WasmPtr = WasmPtr::new(ptr); ptr.deref(&self.view()).write(x)?; Ok(()) } - fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), Self::MemoryErr> { + fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), Self::MemoryErr> { self.view().write(ptr.into(), src) } @@ -91,14 +91,14 @@ macro_rules! hostio { pub(crate) fn read_args>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, read_args(ptr)) } pub(crate) fn write_result>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, len: u32, ) -> MaybeEscape { hostio!(env, write_result(ptr, len)) @@ -151,8 +151,8 @@ pub(crate) fn delegate_call_contract>( pub(crate) fn static_call_contract>( mut env: WasmEnvMut, - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, gas: u64, ret_len: u32, @@ -218,16 +218,16 @@ pub(crate) fn emit_log>( pub(crate) fn account_balance>( mut env: WasmEnvMut, - address: u32, - ptr: u32, + address: Uptr, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, account_balance(address, ptr)) } pub(crate) fn account_code>( mut env: WasmEnvMut, - address: u32, - offset: u32, + address: Uptr, + offset: Uptr, size: u32, code: u32, ) -> Result { @@ -244,21 +244,21 @@ pub(crate) fn account_code_size>( pub(crate) fn account_codehash>( mut env: WasmEnvMut, address: u32, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, account_codehash(address, ptr)) } pub(crate) fn block_basefee>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, block_basefee(ptr)) } pub(crate) fn block_coinbase>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, block_coinbase(ptr)) } @@ -289,7 +289,7 @@ pub(crate) fn chainid>( pub(crate) fn contract_address>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, contract_address(ptr)) } @@ -314,30 +314,30 @@ pub(crate) fn msg_reentrant>( pub(crate) fn msg_sender>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, msg_sender(ptr)) } pub(crate) fn msg_value>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, msg_value(ptr)) } pub(crate) fn native_keccak256>( mut env: WasmEnvMut, - input: u32, + input: Uptr, len: u32, - output: u32, + output: Uptr, ) -> MaybeEscape { hostio!(env, native_keccak256(input, len, output)) } pub(crate) fn tx_gas_price>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, tx_gas_price(ptr)) } @@ -350,7 +350,7 @@ pub(crate) fn tx_ink_price>( pub(crate) fn tx_origin>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, ) -> MaybeEscape { hostio!(env, tx_origin(ptr)) } @@ -364,7 +364,7 @@ pub(crate) fn pay_for_memory_grow>( pub(crate) fn console_log_text>( mut env: WasmEnvMut, - ptr: u32, + ptr: Uptr, len: u32, ) -> MaybeEscape { hostio!(env, console_log_text(ptr, len)) diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 28d7b1765..074e9f850 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -1243,6 +1243,7 @@ name = "user-host-trait" version = "0.1.0" dependencies = [ "arbutil", + "callerenv", "eyre", "prover", ] diff --git a/arbitrator/wasm-libraries/user-host-trait/Cargo.toml b/arbitrator/wasm-libraries/user-host-trait/Cargo.toml index b9f971220..6ee53bd47 100644 --- a/arbitrator/wasm-libraries/user-host-trait/Cargo.toml +++ b/arbitrator/wasm-libraries/user-host-trait/Cargo.toml @@ -5,5 +5,6 @@ edition = "2021" [dependencies] arbutil = { path = "../../arbutil/" } +callerenv = { path = "../../callerenv/" } prover = { path = "../../prover/", default-features = false } eyre = "0.6.5" diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index f7c3502a7..e1009cde7 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -12,6 +12,7 @@ use arbutil::{ pricing::{EVM_API_INK, HOSTIO_INK, PTR_INK}, Bytes20, Bytes32, }; +pub use callerenv::Uptr; use eyre::{eyre, Result}; use prover::{ programs::{meter::OutOfInkError, prelude::*}, @@ -67,17 +68,17 @@ pub trait UserHost: GasMeteredMachine { fn evm_data(&self) -> &EvmData; fn evm_return_data_len(&mut self) -> &mut u32; - fn read_slice(&self, ptr: u32, len: u32) -> Result, Self::MemoryErr>; - fn read_fixed(&self, ptr: u32) -> Result<[u8; N], Self::MemoryErr>; + fn read_slice(&self, ptr: Uptr, len: u32) -> Result, Self::MemoryErr>; + fn read_fixed(&self, ptr: Uptr) -> Result<[u8; N], Self::MemoryErr>; - fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), Self::MemoryErr>; - fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), Self::MemoryErr>; + fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), Self::MemoryErr>; + fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), Self::MemoryErr>; - fn read_bytes20(&self, ptr: u32) -> Result { + fn read_bytes20(&self, ptr: Uptr) -> Result { self.read_fixed(ptr).and_then(|x| Ok(x.into())) } - fn read_bytes32(&self, ptr: u32) -> Result { + fn read_bytes32(&self, ptr: Uptr) -> Result { self.read_fixed(ptr).and_then(|x| Ok(x.into())) } @@ -86,11 +87,11 @@ pub trait UserHost: GasMeteredMachine { fn say(&self, text: D); fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], start_ink: u64, end_ink: u64); - fn write_bytes20(&self, ptr: u32, src: Bytes20) -> Result<(), Self::MemoryErr> { + fn write_bytes20(&self, ptr: Uptr, src: Bytes20) -> Result<(), Self::MemoryErr> { self.write_slice(ptr, &src.0) } - fn write_bytes32(&self, ptr: u32, src: Bytes32) -> Result<(), Self::MemoryErr> { + fn write_bytes32(&self, ptr: Uptr, src: Bytes32) -> Result<(), Self::MemoryErr> { self.write_slice(ptr, &src.0) } @@ -98,7 +99,7 @@ pub trait UserHost: GasMeteredMachine { /// [`CALLDATA_COPY`] opcode when requesting the entirety of the current call's calldata. /// /// [`CALLDATA_COPY`]: https://www.evm.codes/#37 - fn read_args(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn read_args(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK)?; self.pay_for_write(self.args().len() as u32)?; self.write_slice(ptr, self.args())?; @@ -108,7 +109,7 @@ pub trait UserHost: GasMeteredMachine { /// Writes the final return data. If not called before the program exists, the return data will /// be 0 bytes long. Note that this hostio does not cause the program to exit, which happens /// naturally when `user_entrypoint` returns. - fn write_result(&mut self, ptr: u32, len: u32) -> Result<(), Self::Err> { + fn write_result(&mut self, ptr: Uptr, len: u32) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK)?; self.pay_for_read(len)?; self.pay_for_geth_bytes(len)?; // returned after call @@ -122,7 +123,7 @@ pub trait UserHost: GasMeteredMachine { /// set. The semantics, then, are equivalent to that of the EVM's [`SLOAD`] opcode. /// /// [`SLOAD`]: https://www.evm.codes/#54 - fn storage_load_bytes32(&mut self, key: u32, dest: u32) -> Result<(), Self::Err> { + fn storage_load_bytes32(&mut self, key: Uptr, dest: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_SLOAD_GAS)?; let key = self.read_bytes32(key)?; @@ -142,7 +143,7 @@ pub trait UserHost: GasMeteredMachine { /// may exceed this amount, but that's ok because the predominant cost is due to state bloat concerns. /// /// [`SSTORE`]: https://www.evm.codes/#55 - fn storage_store_bytes32(&mut self, key: u32, value: u32) -> Result<(), Self::Err> { + fn storage_store_bytes32(&mut self, key: Uptr, value: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::SSTORE_SENTRY_GAS)?; // see operations_acl_arbitrum.go @@ -170,12 +171,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CALL`]: https://www.evm.codes/#f1 fn call_contract( &mut self, - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, - value: u32, + value: Uptr, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> Result { let value = Some(value); let call = |api: &mut Self::A, contract, data: &_, gas, value: Option<_>| { @@ -200,11 +201,11 @@ pub trait UserHost: GasMeteredMachine { /// [`DELEGATE_CALL`]: https://www.evm.codes/#F4 fn delegate_call_contract( &mut self, - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> Result { let call = |api: &mut Self::A, contract, data: &_, gas, _| api.delegate_call(contract, data, gas); @@ -229,11 +230,11 @@ pub trait UserHost: GasMeteredMachine { /// [`STATIC_CALL`]: https://www.evm.codes/#FA fn static_call_contract( &mut self, - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> Result { let call = |api: &mut Self::A, contract, data: &_, gas, _| api.static_call(contract, data, gas); @@ -244,12 +245,12 @@ pub trait UserHost: GasMeteredMachine { /// Note that `value` must only be [`Some`] for normal calls. fn do_call( &mut self, - contract: u32, - calldata: u32, + contract: Uptr, + calldata: Uptr, calldata_len: u32, - value: Option, + value: Option, mut gas: u64, - return_data_len: u32, + return_data_len: Uptr, call: F, name: &str, ) -> Result @@ -306,11 +307,11 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE`]: https://www.evm.codes/#f0 fn create1( &mut self, - code: u32, + code: Uptr, code_len: u32, - endowment: u32, - contract: u32, - revert_data_len: u32, + endowment: Uptr, + contract: Uptr, + revert_data_len: Uptr, ) -> Result<(), Self::Err> { let call = |api: &mut Self::A, code, value, _, gas| api.create1(code, value, gas); self.do_create( @@ -343,12 +344,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE2`]: https://www.evm.codes/#f5 fn create2( &mut self, - code: u32, + code: Uptr, code_len: u32, - endowment: u32, - salt: u32, - contract: u32, - revert_data_len: u32, + endowment: Uptr, + salt: Uptr, + contract: Uptr, + revert_data_len: Uptr, ) -> Result<(), Self::Err> { let call = |api: &mut Self::A, code, value, salt: Option<_>, gas| { api.create2(code, value, salt.unwrap(), gas) @@ -372,12 +373,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE2`]: https://www.evm.codes/#f5 fn do_create( &mut self, - code: u32, + code: Uptr, code_len: u32, endowment: u32, - salt: Option, - contract: u32, - revert_data_len: u32, + salt: Option, + contract: Uptr, + revert_data_len: Uptr, cost: u64, call: F, name: &str, @@ -439,7 +440,7 @@ pub trait UserHost: GasMeteredMachine { /// Returns the number of bytes written. /// /// [`RETURN_DATA_COPY`]: https://www.evm.codes/#3e - fn read_return_data(&mut self, dest: u32, offset: u32, size: u32) -> Result { + fn read_return_data(&mut self, dest: Uptr, offset: u32, size: u32) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; // pay for only as many bytes as could possibly be written @@ -482,7 +483,7 @@ pub trait UserHost: GasMeteredMachine { /// [`LOG2`]: https://www.evm.codes/#a2 /// [`LOG3`]: https://www.evm.codes/#a3 /// [`LOG4`]: https://www.evm.codes/#a4 - fn emit_log(&mut self, data: u32, len: u32, topics: u32) -> Result<(), Self::Err> { + fn emit_log(&mut self, data: Uptr, len: u32, topics: u32) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; if topics > 4 || len < topics * 32 { Err(eyre!("bad topic data"))?; @@ -499,7 +500,7 @@ pub trait UserHost: GasMeteredMachine { /// The semantics are equivalent to that of the EVM's [`BALANCE`] opcode. /// /// [`BALANCE`]: https://www.evm.codes/#31 - fn account_balance(&mut self, address: u32, ptr: u32) -> Result<(), Self::Err> { + fn account_balance(&mut self, address: Uptr, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_ACCOUNT_GAS)?; let address = self.read_bytes20(address)?; @@ -518,10 +519,10 @@ pub trait UserHost: GasMeteredMachine { /// [`EXT_CODE_COPY`]: https://www.evm.codes/#3C fn account_code( &mut self, - address: u32, + address: Uptr, offset: u32, size: u32, - dest: u32, + dest: Uptr, ) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; let address = self.read_bytes20(address)?; @@ -552,7 +553,7 @@ pub trait UserHost: GasMeteredMachine { /// to that of the EVM's [`EXT_CODESIZE`]. /// /// [`EXT_CODESIZE`]: https://www.evm.codes/#3B - fn account_code_size(&mut self, address: u32) -> Result { + fn account_code_size(&mut self, address: Uptr) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; let address = self.read_bytes20(address)?; let gas = self.gas_left()?; @@ -571,7 +572,7 @@ pub trait UserHost: GasMeteredMachine { /// `keccak("") = c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`. /// /// [`EXT_CODEHASH`]: https://www.evm.codes/#3F - fn account_codehash(&mut self, address: u32, ptr: u32) -> Result<(), Self::Err> { + fn account_codehash(&mut self, address: Uptr, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_ACCOUNT_GAS)?; let address = self.read_bytes20(address)?; @@ -586,7 +587,7 @@ pub trait UserHost: GasMeteredMachine { /// [`BASEFEE`] opcode. /// /// [`BASEFEE`]: https://www.evm.codes/#48 - fn block_basefee(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn block_basefee(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().block_basefee)?; trace!("block_basefee", self, &[], self.evm_data().block_basefee) @@ -595,7 +596,7 @@ pub trait UserHost: GasMeteredMachine { /// Gets the coinbase of the current block, which on Arbitrum chains is the L1 batch poster's /// address. This differs from Ethereum where the validator including the transaction /// determines the coinbase. - fn block_coinbase(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn block_coinbase(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().block_coinbase)?; trace!("block_coinbase", self, &[], self.evm_data().block_coinbase) @@ -650,7 +651,7 @@ pub trait UserHost: GasMeteredMachine { /// [`ADDRESS`] opcode. /// /// [`ADDRESS`]: https://www.evm.codes/#30 - fn contract_address(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn contract_address(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().contract_address)?; trace!( @@ -700,7 +701,7 @@ pub trait UserHost: GasMeteredMachine { /// [`CALLER`]: https://www.evm.codes/#33 /// [`DELEGATE_CALL`]: https://www.evm.codes/#f4 /// [aliasing]: https://developer.arbitrum.io/arbos/l1-to-l2-messaging#address-aliasing - fn msg_sender(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn msg_sender(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().msg_sender)?; trace!("msg_sender", self, &[], self.evm_data().msg_sender) @@ -710,7 +711,7 @@ pub trait UserHost: GasMeteredMachine { /// EVM's [`CALLVALUE`] opcode. /// /// [`CALLVALUE`]: https://www.evm.codes/#34 - fn msg_value(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn msg_value(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().msg_value)?; trace!("msg_value", self, &[], self.evm_data().msg_value) @@ -721,7 +722,7 @@ pub trait UserHost: GasMeteredMachine { /// /// [`keccak256`]: https://en.wikipedia.org/wiki/SHA-3 /// [`SHA3`]: https://www.evm.codes/#20 - fn native_keccak256(&mut self, input: u32, len: u32, output: u32) -> Result<(), Self::Err> { + fn native_keccak256(&mut self, input: Uptr, len: u32, output: Uptr) -> Result<(), Self::Err> { self.pay_for_keccak(len)?; let preimage = self.read_slice(input, len)?; @@ -734,7 +735,7 @@ pub trait UserHost: GasMeteredMachine { /// semantics are equivalent to that of the EVM's [`GAS_PRICE`] opcode. /// /// [`GAS_PRICE`]: https://www.evm.codes/#3A - fn tx_gas_price(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn tx_gas_price(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().tx_gas_price)?; trace!("tx_gas_price", self, &[], self.evm_data().tx_gas_price) @@ -754,7 +755,7 @@ pub trait UserHost: GasMeteredMachine { /// EVM's [`ORIGIN`] opcode. /// /// [`ORIGIN`]: https://www.evm.codes/#32 - fn tx_origin(&mut self, ptr: u32) -> Result<(), Self::Err> { + fn tx_origin(&mut self, ptr: Uptr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().tx_origin)?; trace!("tx_origin", self, &[], self.evm_data().tx_origin) @@ -772,7 +773,7 @@ pub trait UserHost: GasMeteredMachine { } /// Prints a UTF-8 encoded string to the console. Only available in debug mode. - fn console_log_text(&mut self, ptr: u32, len: u32) -> Result<(), Self::Err> { + fn console_log_text(&mut self, ptr: Uptr, len: u32) -> Result<(), Self::Err> { let text = self.read_slice(ptr, len)?; self.say(String::from_utf8_lossy(&text)); trace!("console_log_text", self, text, &[]) diff --git a/arbitrator/wasm-libraries/user-host/src/host.rs b/arbitrator/wasm-libraries/user-host/src/host.rs index bcf48e4f9..efee356bf 100644 --- a/arbitrator/wasm-libraries/user-host/src/host.rs +++ b/arbitrator/wasm-libraries/user-host/src/host.rs @@ -2,7 +2,7 @@ // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::program::Program; -use user_host_trait::UserHost; +use user_host_trait::{UserHost, Uptr}; #[link(wasm_import_module = "forward")] extern "C" { @@ -22,44 +22,44 @@ macro_rules! hostio { } #[no_mangle] -pub unsafe extern "C" fn user_host__read_args(ptr: u32) { +pub unsafe extern "C" fn user_host__read_args(ptr: Uptr) { hostio!(read_args(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__write_result(ptr: u32, len: u32) { +pub unsafe extern "C" fn user_host__write_result(ptr: Uptr, len: u32) { hostio!(write_result(ptr, len)) } #[no_mangle] -pub unsafe extern "C" fn user_host__storage_load_bytes32(key: u32, dest: u32) { +pub unsafe extern "C" fn user_host__storage_load_bytes32(key: Uptr, dest: Uptr) { hostio!(storage_load_bytes32(key, dest)) } #[no_mangle] -pub unsafe extern "C" fn user_host__storage_store_bytes32(key: u32, value: u32) { +pub unsafe extern "C" fn user_host__storage_store_bytes32(key: Uptr, value: Uptr) { hostio!(storage_store_bytes32(key, value)) } #[no_mangle] pub unsafe extern "C" fn user_host__call_contract( - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, value: u32, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> u8 { hostio!(call_contract(contract, data, data_len, value, gas, ret_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__delegate_call_contract( - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> u8 { hostio!(delegate_call_contract( contract, data, data_len, gas, ret_len @@ -68,40 +68,40 @@ pub unsafe extern "C" fn user_host__delegate_call_contract( #[no_mangle] pub unsafe extern "C" fn user_host__static_call_contract( - contract: u32, - data: u32, + contract: Uptr, + data: Uptr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: Uptr, ) -> u8 { hostio!(static_call_contract(contract, data, data_len, gas, ret_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__create1( - code: u32, + code: Uptr, code_len: u32, value: u32, - contract: u32, - revert_len: u32, + contract: Uptr, + revert_len: Uptr, ) { hostio!(create1(code, code_len, value, contract, revert_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__create2( - code: u32, + code: Uptr, code_len: u32, - value: u32, - salt: u32, - contract: u32, - revert_len: u32, + value: Uptr, + salt: Uptr, + contract: Uptr, + revert_len: Uptr, ) { hostio!(create2(code, code_len, value, salt, contract, revert_len)) } #[no_mangle] -pub unsafe extern "C" fn user_host__read_return_data(dest: u32, offset: u32, size: u32) -> u32 { +pub unsafe extern "C" fn user_host__read_return_data(dest: Uptr, offset: u32, size: u32) -> u32 { hostio!(read_return_data(dest, offset, size)) } @@ -111,41 +111,41 @@ pub unsafe extern "C" fn user_host__return_data_size() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__emit_log(data: u32, len: u32, topics: u32) { +pub unsafe extern "C" fn user_host__emit_log(data: Uptr, len: u32, topics: u32) { hostio!(emit_log(data, len, topics)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_balance(address: u32, ptr: u32) { +pub unsafe extern "C" fn user_host__account_balance(address: u32, ptr: Uptr) { hostio!(account_balance(address, ptr)) } #[no_mangle] pub unsafe extern "C" fn user_host__account_code( - address: u32, + address: Uptr, offset: u32, size: u32, - dest: u32, + dest: Uptr, ) -> u32 { hostio!(account_code(address, offset, size, dest)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_code_size(address: u32) -> u32 { +pub unsafe extern "C" fn user_host__account_code_size(address: Uptr) -> u32 { hostio!(account_code_size(address)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_codehash(address: u32, ptr: u32) { +pub unsafe extern "C" fn user_host__account_codehash(address: Uptr, ptr: Uptr) { hostio!(account_codehash(address, ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__block_basefee(ptr: u32) { +pub unsafe extern "C" fn user_host__block_basefee(ptr: Uptr) { hostio!(block_basefee(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__block_coinbase(ptr: u32) { +pub unsafe extern "C" fn user_host__block_coinbase(ptr: Uptr) { hostio!(block_coinbase(ptr)) } @@ -170,7 +170,7 @@ pub unsafe extern "C" fn user_host__chainid() -> u64 { } #[no_mangle] -pub unsafe extern "C" fn user_host__contract_address(ptr: u32) { +pub unsafe extern "C" fn user_host__contract_address(ptr: Uptr) { hostio!(contract_address(ptr)) } @@ -190,22 +190,22 @@ pub unsafe extern "C" fn user_host__msg_reentrant() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__msg_sender(ptr: u32) { +pub unsafe extern "C" fn user_host__msg_sender(ptr: Uptr) { hostio!(msg_sender(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__msg_value(ptr: u32) { +pub unsafe extern "C" fn user_host__msg_value(ptr: Uptr) { hostio!(msg_value(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__native_keccak256(input: u32, len: u32, output: u32) { +pub unsafe extern "C" fn user_host__native_keccak256(input: Uptr, len: u32, output: Uptr) { hostio!(native_keccak256(input, len, output)) } #[no_mangle] -pub unsafe extern "C" fn user_host__tx_gas_price(ptr: u32) { +pub unsafe extern "C" fn user_host__tx_gas_price(ptr: Uptr) { hostio!(tx_gas_price(ptr)) } @@ -215,7 +215,7 @@ pub unsafe extern "C" fn user_host__tx_ink_price() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__tx_origin(ptr: u32) { +pub unsafe extern "C" fn user_host__tx_origin(ptr: Uptr) { hostio!(tx_origin(ptr)) } diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 3c3aa2787..3b5fa84de 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -3,7 +3,7 @@ use core::sync::atomic::{compiler_fence, Ordering}; use arbutil::{ evm::{req::{EvmApiRequestor, RequestHandler}, EvmData, api::{{VecReader, EvmApiMethod, EVM_API_METHOD_REQ_OFFSET}}}, - Bytes20, Bytes32, Color, + Color, }; use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; use wasmer_types::WASM_PAGE_SIZE; @@ -209,21 +209,21 @@ impl UserHost for Program { &mut self.evm_data.return_data_len } - fn read_slice(&self, ptr: u32, len: u32) -> Result, MemoryBoundsError> { + fn read_slice(&self, ptr: Uptr, len: u32) -> Result, MemoryBoundsError> { self.check_memory_access(ptr, len)?; unsafe { Ok(STATIC_MEM.read_slice(ptr, len as usize)) } } - fn read_fixed(&self, ptr: u32) -> Result<[u8; N], MemoryBoundsError> { + fn read_fixed(&self, ptr: Uptr) -> Result<[u8; N], MemoryBoundsError> { self.read_slice(ptr, N as u32).and_then(|x| Ok(x.try_into().unwrap())) } - fn write_u32(&mut self, ptr: u32, x: u32) -> Result<(), MemoryBoundsError> { + fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, 4)?; unsafe { Ok(STATIC_MEM.write_u32(ptr, x)) } } - fn write_slice(&self, ptr: u32, src: &[u8]) -> Result<(), MemoryBoundsError> { + fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, src.len() as u32)?; unsafe { Ok(STATIC_MEM.write_slice(ptr, src)) } } From a186fc3c680267254d8b6cc059dd1d319430089c Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Mon, 4 Mar 2024 18:28:40 -0700 Subject: [PATCH 11/28] fix dockerfile --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Dockerfile b/Dockerfile index 7652527c4..1986b735c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,6 +46,7 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --de COPY ./Makefile ./ COPY arbitrator/Cargo.* arbitrator/ COPY arbitrator/arbutil arbitrator/arbutil +COPY arbitrator/callerenv arbitrator/callerenv COPY arbitrator/prover arbitrator/prover COPY arbitrator/wasm-libraries arbitrator/wasm-libraries COPY arbitrator/tools/wasmer arbitrator/tools/wasmer @@ -92,6 +93,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ COPY arbitrator/Cargo.* arbitrator/ COPY ./Makefile ./ COPY arbitrator/arbutil arbitrator/arbutil +COPY arbitrator/callerenv arbitrator/callerenv COPY arbitrator/prover arbitrator/prover COPY arbitrator/wasm-libraries arbitrator/wasm-libraries COPY arbitrator/jit arbitrator/jit @@ -113,6 +115,7 @@ RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ apt-get install -y llvm-15-dev libclang-common-15-dev libpolly-15-dev COPY arbitrator/Cargo.* arbitrator/ COPY arbitrator/arbutil arbitrator/arbutil +COPY arbitrator/callerenv arbitrator/callerenv COPY arbitrator/prover/Cargo.toml arbitrator/prover/ COPY arbitrator/jit/Cargo.toml arbitrator/jit/ COPY arbitrator/stylus/Cargo.toml arbitrator/stylus/ @@ -153,6 +156,7 @@ COPY --from=wasm-libs-builder /workspace/arbitrator/prover/ arbitrator/prover/ COPY --from=wasm-libs-builder /workspace/arbitrator/tools/wasmer/ arbitrator/tools/wasmer/ COPY --from=wasm-libs-builder /workspace/arbitrator/wasm-libraries/ arbitrator/wasm-libraries/ COPY --from=wasm-libs-builder /workspace/arbitrator/arbutil arbitrator/arbutil +COPY --from=wasm-libs-builder /workspace/arbitrator/callerenv arbitrator/callerenv COPY --from=wasm-libs-builder /workspace/.make/ .make/ COPY ./Makefile ./ COPY ./arbitrator ./arbitrator From 5170ae3e345d2a496aac78265bd61ff7c6274199 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Thu, 7 Mar 2024 18:10:26 -0700 Subject: [PATCH 12/28] GuestPtr, speed up read/write, docstrings, debug prints, wrap macro, other tweaks --- Makefile | 2 +- arbitrator/Cargo.lock | 17 +- arbitrator/arbutil/src/evm/req.rs | 2 +- .../{callerenv => caller-env}/Cargo.toml | 5 +- .../{callerenv => caller-env}/src/brotli.rs | 42 +-- arbitrator/caller-env/src/guest_ptr.rs | 49 +++ arbitrator/caller-env/src/lib.rs | 66 ++++ .../src/static_caller.rs | 67 ++-- .../src/wasip1_stub.rs | 179 ++++++---- arbitrator/caller-env/src/wasmer_traits.rs | 47 +++ arbitrator/callerenv/src/lib.rs | 54 ---- arbitrator/jit/Cargo.toml | 2 +- arbitrator/jit/src/arbcompress.rs | 48 +-- .../jit/src/{callerenv.rs => caller_env.rs} | 67 ++-- arbitrator/jit/src/machine.rs | 4 +- arbitrator/jit/src/main.rs | 15 +- arbitrator/jit/src/program.rs | 48 +-- arbitrator/jit/src/wasip1_stub.rs | 296 ++++++++--------- arbitrator/jit/src/wavmio.rs | 33 +- arbitrator/prover/src/host.rs | 2 +- arbitrator/prover/src/machine.rs | 128 ++++---- arbitrator/stylus/Cargo.toml | 1 + arbitrator/stylus/src/env.rs | 3 +- arbitrator/stylus/src/host.rs | 143 ++++---- arbitrator/stylus/src/lib.rs | 2 +- arbitrator/wasm-libraries/Cargo.lock | 23 +- arbitrator/wasm-libraries/Cargo.toml | 4 +- arbitrator/wasm-libraries/brotli/Cargo.toml | 4 +- arbitrator/wasm-libraries/brotli/src/lib.rs | 36 ++- arbitrator/wasm-libraries/host-io/Cargo.toml | 2 +- arbitrator/wasm-libraries/host-io/src/lib.rs | 30 +- .../wasm-libraries/program-exec/src/lib.rs | 10 +- .../wasm-libraries/user-host-trait/Cargo.toml | 2 +- .../wasm-libraries/user-host-trait/src/lib.rs | 130 ++++---- .../wasm-libraries/user-host/Cargo.toml | 2 +- .../wasm-libraries/user-host/src/host.rs | 85 ++--- .../wasm-libraries/user-host/src/link.rs | 88 ++--- .../wasm-libraries/user-host/src/program.rs | 79 +++-- .../wasm-libraries/user-test/Cargo.toml | 2 +- .../wasm-libraries/user-test/src/host.rs | 20 +- .../wasm-libraries/wasi-stub/Cargo.toml | 6 +- .../wasm-libraries/wasi-stub/src/lib.rs | 306 +++++++++--------- arbutil/correspondingl1blocknumber.go | 5 +- arbutil/format.go | 3 + arbutil/wait_for_l1.go | 5 +- 45 files changed, 1222 insertions(+), 942 deletions(-) rename arbitrator/{callerenv => caller-env}/Cargo.toml (54%) rename arbitrator/{callerenv => caller-env}/src/brotli.rs (75%) create mode 100644 arbitrator/caller-env/src/guest_ptr.rs create mode 100644 arbitrator/caller-env/src/lib.rs rename arbitrator/{callerenv => caller-env}/src/static_caller.rs (53%) rename arbitrator/{callerenv => caller-env}/src/wasip1_stub.rs (61%) create mode 100644 arbitrator/caller-env/src/wasmer_traits.rs delete mode 100644 arbitrator/callerenv/src/lib.rs rename arbitrator/jit/src/{callerenv.rs => caller_env.rs} (68%) diff --git a/Makefile b/Makefile index 1ab8bbedc..6649f1e54 100644 --- a/Makefile +++ b/Makefile @@ -74,7 +74,7 @@ WASI_SYSROOT?=/opt/wasi-sdk/wasi-sysroot arbitrator_wasm_lib_flags=$(patsubst %, -l %, $(arbitrator_wasm_libs)) -rust_arbutil_files = $(wildcard arbitrator/arbutil/src/*.* arbitrator/arbutil/src/*/*.* arbitrator/arbutil/*.toml arbitrator/callerenv/src/*.* arbitrator/callerenv/src/*/*.* arbitrator/callerenv/*.toml) +rust_arbutil_files = $(wildcard arbitrator/arbutil/src/*.* arbitrator/arbutil/src/*/*.* arbitrator/arbutil/*.toml arbitrator/caller-env/src/*.* arbitrator/caller-env/src/*/*.* arbitrator/caller-env/*.toml) prover_direct_includes = $(patsubst %,$(output_latest)/%.wasm, forward forward_stub) prover_src = arbitrator/prover/src diff --git a/arbitrator/Cargo.lock b/arbitrator/Cargo.lock index b4e7ebc7b..d54403153 100644 --- a/arbitrator/Cargo.lock +++ b/arbitrator/Cargo.lock @@ -203,11 +203,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] -name = "callerenv" +name = "caller-env" version = "0.1.0" dependencies = [ + "num_enum", "rand", "rand_pcg", + "wasmer", ] [[package]] @@ -787,7 +789,7 @@ name = "jit" version = "0.1.0" dependencies = [ "arbutil", - "callerenv", + "caller-env", "eyre", "hex", "libc", @@ -1065,18 +1067,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1641,6 +1643,7 @@ version = "0.1.0" dependencies = [ "arbutil", "bincode", + "caller-env", "derivative", "eyre", "fnv", @@ -1851,7 +1854,7 @@ name = "user-host-trait" version = "0.1.0" dependencies = [ "arbutil", - "callerenv", + "caller-env", "eyre", "prover", ] diff --git a/arbitrator/arbutil/src/evm/req.rs b/arbitrator/arbutil/src/evm/req.rs index 98b5cd09c..670309ae4 100644 --- a/arbitrator/arbutil/src/evm/req.rs +++ b/arbitrator/arbutil/src/evm/req.rs @@ -75,7 +75,7 @@ impl> EvmApiRequestor { let (mut res, data, cost) = self.handle_request(create_type, &request); if res.len() != 21 || res[0] == 0 { - if res.len() > 0 { + if !res.is_empty() { res.drain(0..=0); } let err_string = diff --git a/arbitrator/callerenv/Cargo.toml b/arbitrator/caller-env/Cargo.toml similarity index 54% rename from arbitrator/callerenv/Cargo.toml rename to arbitrator/caller-env/Cargo.toml index 15f93d603..8b278f606 100644 --- a/arbitrator/callerenv/Cargo.toml +++ b/arbitrator/caller-env/Cargo.toml @@ -1,11 +1,14 @@ [package] -name = "callerenv" +name = "caller-env" version = "0.1.0" edition = "2021" [dependencies] +num_enum = { version = "0.7.2", default-features = false } rand_pcg = { version = "0.3.1", default-features = false } rand = { version = "0.8.4", default-features = false } +wasmer = { path = "../tools/wasmer/lib/api", optional = true } [features] static_caller = [] +wasmer_traits = ["dep:wasmer"] diff --git a/arbitrator/callerenv/src/brotli.rs b/arbitrator/caller-env/src/brotli.rs similarity index 75% rename from arbitrator/callerenv/src/brotli.rs rename to arbitrator/caller-env/src/brotli.rs index 59ba9d847..9f6f47e7e 100644 --- a/arbitrator/callerenv/src/brotli.rs +++ b/arbitrator/caller-env/src/brotli.rs @@ -1,9 +1,13 @@ -// Copyright 2021-2023, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::{ExecEnv, MemAccess, Uptr}; + +#![allow(clippy::too_many_arguments)] + +use crate::{ExecEnv, GuestPtr, MemAccess}; use alloc::vec; +use num_enum::{IntoPrimitive, TryFromPrimitive}; -#[derive(PartialEq)] +#[derive(PartialEq, IntoPrimitive, TryFromPrimitive)] #[repr(u32)] pub enum BrotliStatus { Failure, @@ -31,7 +35,7 @@ extern "C" { const BROTLI_MODE_GENERIC: u32 = 0; -/// Brotli decompresses a go slice1 +/// Brotli decompresses a go slice. /// /// # Safety /// @@ -39,14 +43,14 @@ const BROTLI_MODE_GENERIC: u32 = 0; pub fn brotli_decompress( mem: &mut M, _env: &mut E, - in_buf_ptr: Uptr, + in_buf_ptr: GuestPtr, in_buf_len: u32, - out_buf_ptr: Uptr, - out_len_ptr: Uptr, -) -> u32 { + out_buf_ptr: GuestPtr, + out_len_ptr: GuestPtr, +) -> BrotliStatus { let in_slice = mem.read_slice(in_buf_ptr, in_buf_len as usize); let orig_output_len = mem.read_u32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len as usize]; + let mut output = vec![0; orig_output_len]; let mut output_len = orig_output_len; unsafe { let res = BrotliDecoderDecompress( @@ -56,30 +60,30 @@ pub fn brotli_decompress( output.as_mut_ptr(), ); if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return 0; + return BrotliStatus::Failure; } } mem.write_slice(out_buf_ptr, &output[..output_len]); mem.write_u32(out_len_ptr, output_len as u32); - 1 + BrotliStatus::Success } /// Brotli compresses a go slice /// -/// The output buffer must be sufficiently large enough. +/// The output buffer must be large enough. pub fn brotli_compress( mem: &mut M, _env: &mut E, - in_buf_ptr: Uptr, + in_buf_ptr: GuestPtr, in_buf_len: u32, - out_buf_ptr: Uptr, - out_len_ptr: Uptr, + out_buf_ptr: GuestPtr, + out_len_ptr: GuestPtr, level: u32, window_size: u32, -) -> u32 { +) -> BrotliStatus { let in_slice = mem.read_slice(in_buf_ptr, in_buf_len as usize); let orig_output_len = mem.read_u32(out_len_ptr) as usize; - let mut output = vec![0u8; orig_output_len]; + let mut output = vec![0; orig_output_len]; let mut output_len = orig_output_len; unsafe { @@ -93,10 +97,10 @@ pub fn brotli_compress( output.as_mut_ptr(), ); if (res != BrotliStatus::Success) || (output_len > orig_output_len) { - return 0; + return BrotliStatus::Failure; } } mem.write_slice(out_buf_ptr, &output[..output_len]); mem.write_u32(out_len_ptr, output_len as u32); - 1 + BrotliStatus::Success } diff --git a/arbitrator/caller-env/src/guest_ptr.rs b/arbitrator/caller-env/src/guest_ptr.rs new file mode 100644 index 000000000..a5926394e --- /dev/null +++ b/arbitrator/caller-env/src/guest_ptr.rs @@ -0,0 +1,49 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + +use core::ops::{Add, AddAssign, Deref, DerefMut}; + +/// Represents a pointer to a Guest WASM's memory. +#[derive(Clone, Copy, Eq, PartialEq)] +#[repr(transparent)] +pub struct GuestPtr(pub u32); + +impl Add for GuestPtr { + type Output = Self; + + fn add(self, rhs: u32) -> Self::Output { + Self(self.0 + rhs) + } +} + +impl AddAssign for GuestPtr { + fn add_assign(&mut self, rhs: u32) { + *self = *self + rhs; + } +} + +impl From for u32 { + fn from(value: GuestPtr) -> Self { + value.0 + } +} + +impl From for u64 { + fn from(value: GuestPtr) -> Self { + value.0.into() + } +} + +impl Deref for GuestPtr { + type Target = u32; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for GuestPtr { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/arbitrator/caller-env/src/lib.rs b/arbitrator/caller-env/src/lib.rs new file mode 100644 index 000000000..39ee65e59 --- /dev/null +++ b/arbitrator/caller-env/src/lib.rs @@ -0,0 +1,66 @@ +// Copyright 2021-2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + +#![no_std] + +extern crate alloc; + +use alloc::vec::Vec; +use rand_pcg::Pcg32; + +pub use brotli::BrotliStatus; +pub use guest_ptr::GuestPtr; +pub use wasip1_stub::Errno; + +#[cfg(feature = "static_caller")] +pub mod static_caller; + +#[cfg(feature = "wasmer_traits")] +pub mod wasmer_traits; + +pub mod brotli; +mod guest_ptr; +pub mod wasip1_stub; + +/// Initializes a deterministic, psuedo-random number generator with a fixed seed. +pub fn create_pcg() -> Pcg32 { + const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; + const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; + Pcg32::new(PCG_INIT_STATE, PCG_INIT_STREAM) +} + +/// Access Guest memory. +pub trait MemAccess { + fn read_u8(&self, ptr: GuestPtr) -> u8; + + fn read_u16(&self, ptr: GuestPtr) -> u16; + + fn read_u32(&self, ptr: GuestPtr) -> u32; + + fn read_u64(&self, ptr: GuestPtr) -> u64; + + fn write_u8(&mut self, ptr: GuestPtr, x: u8); + + fn write_u16(&mut self, ptr: GuestPtr, x: u16); + + fn write_u32(&mut self, ptr: GuestPtr, x: u32); + + fn write_u64(&mut self, ptr: GuestPtr, x: u64); + + fn read_slice(&self, ptr: GuestPtr, len: usize) -> Vec; + + fn read_fixed(&self, ptr: GuestPtr) -> [u8; N]; + + fn write_slice(&mut self, ptr: GuestPtr, data: &[u8]); +} + +/// Update the Host environment. +pub trait ExecEnv { + fn advance_time(&mut self, ns: u64); + + fn get_time(&self) -> u64; + + fn next_rand_u32(&mut self) -> u32; + + fn print_string(&mut self, message: &[u8]); +} diff --git a/arbitrator/callerenv/src/static_caller.rs b/arbitrator/caller-env/src/static_caller.rs similarity index 53% rename from arbitrator/callerenv/src/static_caller.rs rename to arbitrator/caller-env/src/static_caller.rs index 78a57d4df..5b4765c7c 100644 --- a/arbitrator/callerenv/src/static_caller.rs +++ b/arbitrator/caller-env/src/static_caller.rs @@ -1,74 +1,69 @@ -use crate::{create_pcg, ExecEnv, MemAccess, Uptr}; +// Copyright 2021-2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + +use crate::{create_pcg, ExecEnv, GuestPtr, MemAccess}; +use alloc::vec::Vec; use rand::RngCore; use rand_pcg::Pcg32; extern crate alloc; -use alloc::vec::Vec; - static mut TIME: u64 = 0; static mut RNG: Option = None; -pub struct StaticMem {} -pub struct StaticExecEnv {} +pub struct StaticMem; +pub struct StaticExecEnv; -pub static mut STATIC_MEM: StaticMem = StaticMem {}; -pub static mut STATIC_ENV: StaticExecEnv = StaticExecEnv {}; +pub static mut STATIC_MEM: StaticMem = StaticMem; +pub static mut STATIC_ENV: StaticExecEnv = StaticExecEnv; -#[allow(dead_code)] extern "C" { - fn wavm_caller_load8(ptr: Uptr) -> u8; - fn wavm_caller_load32(ptr: Uptr) -> u32; - fn wavm_caller_store8(ptr: Uptr, val: u8); - fn wavm_caller_store32(ptr: Uptr, val: u32); - fn wavm_halt_and_set_finished() -> !; + fn wavm_caller_load8(ptr: GuestPtr) -> u8; + fn wavm_caller_load32(ptr: GuestPtr) -> u32; + fn wavm_caller_store8(ptr: GuestPtr, val: u8); + fn wavm_caller_store32(ptr: GuestPtr, val: u32); } impl MemAccess for StaticMem { - fn read_u8(&self, ptr: Uptr) -> u8 { + fn read_u8(&self, ptr: GuestPtr) -> u8 { unsafe { wavm_caller_load8(ptr) } } - fn read_u16(&self, ptr: Uptr) -> u16 { + fn read_u16(&self, ptr: GuestPtr) -> u16 { let lsb = self.read_u8(ptr); let msb = self.read_u8(ptr + 1); (msb as u16) << 8 | (lsb as u16) } - fn read_u32(&self, ptr: Uptr) -> u32 { - let lsb = self.read_u16(ptr); - let msb = self.read_u16(ptr + 2); - (msb as u32) << 16 | (lsb as u32) + fn read_u32(&self, ptr: GuestPtr) -> u32 { + unsafe { wavm_caller_load32(ptr) } } - fn read_u64(&self, ptr: Uptr) -> u64 { + fn read_u64(&self, ptr: GuestPtr) -> u64 { let lsb = self.read_u32(ptr); let msb = self.read_u32(ptr + 4); (msb as u64) << 32 | (lsb as u64) } - fn write_u8(&mut self, ptr: Uptr, x: u8) { - unsafe { - wavm_caller_store8(ptr, x); - } + fn write_u8(&mut self, ptr: GuestPtr, x: u8) { + unsafe { wavm_caller_store8(ptr, x) } } - fn write_u16(&mut self, ptr: Uptr, x: u16) { + fn write_u16(&mut self, ptr: GuestPtr, x: u16) { self.write_u8(ptr, (x & 0xff) as u8); self.write_u8(ptr + 1, ((x >> 8) & 0xff) as u8); } - fn write_u32(&mut self, ptr: Uptr, x: u32) { - self.write_u16(ptr, (x & 0xffff) as u16); - self.write_u16(ptr + 2, ((x >> 16) & 0xffff) as u16); + fn write_u32(&mut self, ptr: GuestPtr, x: u32) { + unsafe { wavm_caller_store32(ptr, x) } } - fn write_u64(&mut self, ptr: Uptr, x: u64) { + fn write_u64(&mut self, ptr: GuestPtr, x: u64) { self.write_u32(ptr, (x & 0xffffffff) as u32); self.write_u32(ptr + 4, ((x >> 32) & 0xffffffff) as u32); } - fn read_slice(&self, mut ptr: Uptr, mut len: usize) -> Vec { + fn read_slice(&self, mut ptr: GuestPtr, mut len: usize) -> Vec { let mut data = Vec::with_capacity(len); if len == 0 { return data; @@ -85,13 +80,13 @@ impl MemAccess for StaticMem { data } - fn read_fixed(&self, ptr: Uptr) -> [u8; N] { + fn read_fixed(&self, ptr: GuestPtr) -> [u8; N] { self.read_slice(ptr, N).try_into().unwrap() } - fn write_slice(&mut self, mut ptr: Uptr, mut src: &[u8]) { + fn write_slice(&mut self, mut ptr: GuestPtr, mut src: &[u8]) { while src.len() >= 4 { - let mut arr = [0u8; 4]; + let mut arr = [0; 4]; arr.copy_from_slice(&src[..4]); self.write_u32(ptr, u32::from_le_bytes(arr)); ptr += 4; @@ -105,7 +100,9 @@ impl MemAccess for StaticMem { } impl ExecEnv for StaticExecEnv { - fn print_string(&mut self, _data: &[u8]) {} // TODO? + fn print_string(&mut self, _data: &[u8]) { + // To print, call the debug-only `console::log_txt` Host I/O + } fn get_time(&self) -> u64 { unsafe { TIME } @@ -116,6 +113,6 @@ impl ExecEnv for StaticExecEnv { } fn next_rand_u32(&mut self) -> u32 { - unsafe { RNG.get_or_insert_with(|| create_pcg()) }.next_u32() + unsafe { RNG.get_or_insert_with(create_pcg) }.next_u32() } } diff --git a/arbitrator/callerenv/src/wasip1_stub.rs b/arbitrator/caller-env/src/wasip1_stub.rs similarity index 61% rename from arbitrator/callerenv/src/wasip1_stub.rs rename to arbitrator/caller-env/src/wasip1_stub.rs index cf931eb04..41f136c5e 100644 --- a/arbitrator/callerenv/src/wasip1_stub.rs +++ b/arbitrator/caller-env/src/wasip1_stub.rs @@ -1,31 +1,80 @@ -use crate::{ExecEnv, MemAccess}; +// Copyright 2021-2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -pub type Errno = u16; +//! A stub impl of [WASI Preview 1][Wasi] for proving fraud. +//! +//! [Wasi]: https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md -use crate::Uptr; +#![allow(clippy::too_many_arguments)] -pub const ERRNO_SUCCESS: Errno = 0; -pub const ERRNO_BADF: Errno = 8; -pub const ERRNO_INTVAL: Errno = 28; +use crate::{ExecEnv, GuestPtr, MemAccess}; +#[repr(transparent)] +pub struct Errno(pub(crate) u16); + +pub const ERRNO_SUCCESS: Errno = Errno(0); +pub const ERRNO_BADF: Errno = Errno(8); +pub const ERRNO_INVAL: Errno = Errno(28); + +/// Writes the number and total size of args passed by the OS. +/// Note that this currently consists of just the program name `bin`. +pub fn args_sizes_get( + mem: &mut M, + _: &mut E, + length_ptr: GuestPtr, + data_size_ptr: GuestPtr, +) -> Errno { + mem.write_u32(length_ptr, 1); + mem.write_u32(data_size_ptr, 4); + ERRNO_SUCCESS +} + +/// Writes the args passed by the OS. +/// Note that this currently consists of just the program name `bin`. +pub fn args_get( + mem: &mut M, + _: &mut E, + argv_buf: GuestPtr, + data_buf: GuestPtr, +) -> Errno { + mem.write_u32(argv_buf, data_buf.into()); + mem.write_u32(data_buf, 0x6E6962); // "bin\0" + ERRNO_SUCCESS +} + +/// Writes the number and total size of OS environment variables. +/// Note that none exist in Nitro. pub fn environ_sizes_get( mem: &mut M, _env: &mut E, - length_ptr: Uptr, - data_size_ptr: Uptr, + length_ptr: GuestPtr, + data_size_ptr: GuestPtr, ) -> Errno { mem.write_u32(length_ptr, 0); mem.write_u32(data_size_ptr, 0); ERRNO_SUCCESS } +/// Writes the number and total size of OS environment variables. +/// Note that none exist in Nitro. +pub fn environ_get( + _: &mut M, + _: &mut E, + _: GuestPtr, + _: GuestPtr, +) -> Errno { + ERRNO_SUCCESS +} + +/// Writes to the given file descriptor. +/// Note that we only support stdout and stderr. pub fn fd_write( mem: &mut M, env: &mut E, fd: u32, - iovecs_ptr: Uptr, + iovecs_ptr: GuestPtr, iovecs_len: u32, - ret_ptr: Uptr, + ret_ptr: GuestPtr, ) -> Errno { if fd != 1 && fd != 2 { return ERRNO_BADF; @@ -33,7 +82,6 @@ pub fn fd_write( let mut size = 0; for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; - // let iovec = mem.read_u32(ptr); let len = mem.read_u32(ptr + 4); let data = mem.read_slice(ptr, len as usize); env.print_string(&data); @@ -43,14 +91,12 @@ pub fn fd_write( ERRNO_SUCCESS } -pub fn environ_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { - ERRNO_INTVAL -} - +/// Closes the given file descriptor. Unsupported. pub fn fd_close(_: &mut M, _: &mut E, _: u32) -> Errno { ERRNO_BADF } +/// Reads from the given file descriptor. Unsupported. pub fn fd_read( _: &mut M, _: &mut E, @@ -62,6 +108,7 @@ pub fn fd_read( ERRNO_BADF } +/// Reads the contents of a directory. Unsupported. pub fn fd_readdir( _: &mut M, _: &mut E, @@ -74,10 +121,12 @@ pub fn fd_readdir( ERRNO_BADF } +/// Syncs a file to disk. Unsupported. pub fn fd_sync(_: &mut M, _: &mut E, _: u32) -> Errno { ERRNO_SUCCESS } +/// Move within a file. Unsupported. pub fn fd_seek( _: &mut M, _: &mut E, @@ -89,10 +138,27 @@ pub fn fd_seek( ERRNO_BADF } +/// Syncs file contents to disk. Unsupported. pub fn fd_datasync(_: &mut M, _: &mut E, _fd: u32) -> Errno { ERRNO_BADF } +/// Retrieves attributes about a file descriptor. Unsupported. +pub fn fd_fdstat_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { + ERRNO_INVAL +} + +/// Sets the attributes of a file descriptor. Unsupported. +pub fn fd_fdstat_set_flags( + _: &mut M, + _: &mut E, + _: u32, + _: u32, +) -> Errno { + ERRNO_INVAL +} + +/// Opens the file or directory at the given path. Unsupported. pub fn path_open( _: &mut M, _: &mut E, @@ -109,6 +175,7 @@ pub fn path_open( ERRNO_BADF } +/// Creates a directory. Unsupported. pub fn path_create_directory( _: &mut M, _: &mut E, @@ -119,6 +186,7 @@ pub fn path_create_directory( ERRNO_BADF } +/// Unlinks a directory. Unsupported. pub fn path_remove_directory( _: &mut M, _: &mut E, @@ -129,6 +197,7 @@ pub fn path_remove_directory( ERRNO_BADF } +/// Resolves a symbolic link. Unsupported. pub fn path_readlink( _: &mut M, _: &mut E, @@ -142,6 +211,7 @@ pub fn path_readlink( ERRNO_BADF } +/// Moves a file. Unsupported. pub fn path_rename( _: &mut M, _: &mut E, @@ -155,6 +225,7 @@ pub fn path_rename( ERRNO_BADF } +/// Retrieves info about an open file. Unsupported. pub fn path_filestat_get( _: &mut M, _: &mut E, @@ -167,6 +238,7 @@ pub fn path_filestat_get( ERRNO_BADF } +/// Unlinks the file at the given path. Unsupported. pub fn path_unlink_file( _: &mut M, _: &mut E, @@ -177,10 +249,12 @@ pub fn path_unlink_file( ERRNO_BADF } +/// Retrieves info about a file. Unsupported. pub fn fd_prestat_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } +/// Retrieves info about a directory. Unsupported. pub fn fd_prestat_dir_name( _: &mut M, _: &mut E, @@ -191,6 +265,7 @@ pub fn fd_prestat_dir_name( ERRNO_BADF } +/// Retrieves info about a file. Unsupported. pub fn fd_filestat_get( _: &mut M, _: &mut E, @@ -200,6 +275,7 @@ pub fn fd_filestat_get( ERRNO_BADF } +/// Sets the size of an open file. Unsupported. pub fn fd_filestat_set_size( _: &mut M, _: &mut E, @@ -209,6 +285,7 @@ pub fn fd_filestat_set_size( ERRNO_BADF } +/// Peaks within a descriptor without modifying its state. Unsupported. pub fn fd_pread( _: &mut M, _: &mut E, @@ -221,6 +298,7 @@ pub fn fd_pread( ERRNO_BADF } +/// Writes to a descriptor without modifying the current offset. Unsupported. pub fn fd_pwrite( _: &mut M, _: &mut E, @@ -233,6 +311,7 @@ pub fn fd_pwrite( ERRNO_BADF } +/// Accepts a new connection. Unsupported. pub fn sock_accept( _: &mut M, _: &mut E, @@ -243,32 +322,40 @@ pub fn sock_accept( ERRNO_BADF } +/// Shuts down a socket. Unsupported. pub fn sock_shutdown(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { ERRNO_BADF } +/// Yields execution to the OS scheduler. Effectively does nothing in Nitro due to the lack of threads. pub fn sched_yield(_: &mut M, _: &mut E) -> Errno { ERRNO_SUCCESS } +/// 10ms in ns static TIME_INTERVAL: u64 = 10_000_000; +/// Retrieves the time in ns of the given clock. +/// Note that in Nitro, all clocks point to the same deterministic counter that advances 10ms whenever +/// this function is called. pub fn clock_time_get( mem: &mut M, env: &mut E, _clock_id: u32, _precision: u64, - time_ptr: Uptr, + time_ptr: GuestPtr, ) -> Errno { env.advance_time(TIME_INTERVAL); mem.write_u64(time_ptr, env.get_time()); ERRNO_SUCCESS } +/// Fills a slice with psuedo-random bytes. +/// Note that in Nitro, the bytes are deterministically generated from a common seed. pub fn random_get( mem: &mut M, env: &mut E, - mut buf: Uptr, + mut buf: GuestPtr, mut len: u32, ) -> Errno { while len >= 4 { @@ -288,40 +375,19 @@ pub fn random_get( ERRNO_SUCCESS } -pub fn args_sizes_get( - mem: &mut M, - _: &mut E, - length_ptr: Uptr, - data_size_ptr: Uptr, -) -> Errno { - mem.write_u32(length_ptr, 1); - mem.write_u32(data_size_ptr, 4); - ERRNO_SUCCESS -} - -pub fn args_get( - mem: &mut M, - _: &mut E, - argv_buf: Uptr, - data_buf: Uptr, -) -> Errno { - mem.write_u32(argv_buf, data_buf as u32); - mem.write_u32(data_buf, 0x6E6962); // "bin\0" - ERRNO_SUCCESS -} - -// we always simulate a timeout +/// Poll for events. +/// Note that we always simulate a timeout and skip all others. pub fn poll_oneoff( mem: &mut M, _: &mut E, - in_subs: Uptr, - out_evt: Uptr, - nsubscriptions: u32, - nevents_ptr: Uptr, + in_subs: GuestPtr, + out_evt: GuestPtr, + num_subscriptions: u32, + num_events_ptr: GuestPtr, ) -> Errno { - const SUBSCRIPTION_SIZE: u32 = 48; - for i in 0..nsubscriptions { - let subs_base = in_subs + (SUBSCRIPTION_SIZE * (i as u32)); + const SUBSCRIPTION_SIZE: u32 = 48; // user data + 40-byte union + for index in 0..num_subscriptions { + let subs_base = in_subs + (SUBSCRIPTION_SIZE * index); let subs_type = mem.read_u32(subs_base + 8); if subs_type != 0 { // not a clock subscription type @@ -329,22 +395,9 @@ pub fn poll_oneoff( } let user_data = mem.read_u32(subs_base); mem.write_u32(out_evt, user_data); - mem.write_u32(out_evt + 8, 0); - mem.write_u32(nevents_ptr, 1); + mem.write_u32(out_evt + 8, subs_type); + mem.write_u32(num_events_ptr, 1); return ERRNO_SUCCESS; } - ERRNO_INTVAL -} - -pub fn fd_fdstat_get(_: &mut M, _: &mut E, _: u32, _: u32) -> Errno { - ERRNO_INTVAL -} - -pub fn fd_fdstat_set_flags( - _: &mut M, - _: &mut E, - _: u32, - _: u32, -) -> Errno { - ERRNO_INTVAL + ERRNO_INVAL } diff --git a/arbitrator/caller-env/src/wasmer_traits.rs b/arbitrator/caller-env/src/wasmer_traits.rs new file mode 100644 index 000000000..5cc6f9e67 --- /dev/null +++ b/arbitrator/caller-env/src/wasmer_traits.rs @@ -0,0 +1,47 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + +use crate::{BrotliStatus, Errno, GuestPtr}; +use wasmer::{FromToNativeWasmType, WasmPtr}; + +unsafe impl FromToNativeWasmType for GuestPtr { + type Native = i32; + + fn from_native(native: i32) -> Self { + Self(u32::from_native(native)) + } + + fn to_native(self) -> i32 { + self.0.to_native() + } +} + +unsafe impl FromToNativeWasmType for Errno { + type Native = i32; + + fn from_native(native: i32) -> Self { + Self(u16::from_native(native)) + } + + fn to_native(self) -> i32 { + self.0.to_native() + } +} + +unsafe impl FromToNativeWasmType for BrotliStatus { + type Native = i32; + + fn from_native(native: i32) -> Self { + Self::try_from(u32::from_native(native)).expect("unknown brotli status") + } + + fn to_native(self) -> i32 { + (self as u32).to_native() + } +} + +impl From for WasmPtr { + fn from(value: GuestPtr) -> Self { + WasmPtr::new(value.0) + } +} diff --git a/arbitrator/callerenv/src/lib.rs b/arbitrator/callerenv/src/lib.rs deleted file mode 100644 index b056c0f23..000000000 --- a/arbitrator/callerenv/src/lib.rs +++ /dev/null @@ -1,54 +0,0 @@ -#![no_std] -use rand_pcg::Pcg32; - -extern crate alloc; - -use alloc::vec::Vec; - -#[cfg(feature = "static_caller")] -pub mod static_caller; - -pub mod brotli; -pub mod wasip1_stub; -pub type Uptr = u32; - -const PCG_INIT_STATE: u64 = 0xcafef00dd15ea5e5; -const PCG_INIT_STREAM: u64 = 0xa02bdbf7bb3c0a7; - -pub fn create_pcg() -> Pcg32 { - Pcg32::new(PCG_INIT_STATE, PCG_INIT_STREAM) -} - -pub trait MemAccess { - fn read_u8(&self, ptr: Uptr) -> u8; - - fn read_u16(&self, ptr: Uptr) -> u16; - - fn read_u32(&self, ptr: Uptr) -> u32; - - fn read_u64(&self, ptr: Uptr) -> u64; - - fn write_u8(&mut self, ptr: Uptr, x: u8); - - fn write_u16(&mut self, ptr: Uptr, x: u16); - - fn write_u32(&mut self, ptr: Uptr, x: u32); - - fn write_u64(&mut self, ptr: Uptr, x: u64); - - fn read_slice(&self, ptr: Uptr, len: usize) -> Vec; - - fn read_fixed(&self, ptr: Uptr) -> [u8; N]; - - fn write_slice(&mut self, ptr: Uptr, data: &[u8]); -} - -pub trait ExecEnv { - fn print_string(&mut self, message: &[u8]); - - fn get_time(&self) -> u64; - - fn advance_time(&mut self, delta: u64); - - fn next_rand_u32(&mut self) -> u32; -} diff --git a/arbitrator/jit/Cargo.toml b/arbitrator/jit/Cargo.toml index 33bb00f81..58861e873 100644 --- a/arbitrator/jit/Cargo.toml +++ b/arbitrator/jit/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] arbutil = { path = "../arbutil/" } -callerenv = { path = "../callerenv/" } +caller-env = { path = "../caller-env/", features = ["wasmer_traits"] } prover = { path = "../prover/", default-features = false, features = ["native"] } stylus = { path = "../stylus/", default-features = false } wasmer = { path = "../tools/wasmer/lib/api/" } diff --git a/arbitrator/jit/src/arbcompress.rs b/arbitrator/jit/src/arbcompress.rs index cbf7c7364..5b751b594 100644 --- a/arbitrator/jit/src/arbcompress.rs +++ b/arbitrator/jit/src/arbcompress.rs @@ -1,32 +1,38 @@ -// Copyright 2022, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::callerenv::jit_env; +use crate::caller_env::jit_env; use crate::machine::Escape; use crate::machine::WasmEnvMut; -use callerenv::{self, Uptr}; +use caller_env::brotli::BrotliStatus; +use caller_env::{self, GuestPtr}; macro_rules! wrap { - ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { - pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let (mut mem, mut env) = jit_env(&mut src); + ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { + $( + pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { + let (mut mem, mut env) = jit_env(&mut src); - Ok(callerenv::brotli::$func_name(&mut mem, &mut env, $($arg_name),*)) - } + Ok(caller_env::brotli::$func_name(&mut mem, &mut env, $($arg_name),*)) + } + )* }; } -wrap!(brotli_decompress( - in_buf_ptr: Uptr, - in_buf_len: u32, - out_buf_ptr: Uptr, - out_len_ptr: Uptr) -> u32); +wrap! { + fn brotli_decompress( + in_buf_ptr: GuestPtr, + in_buf_len: u32, + out_buf_ptr: GuestPtr, + out_len_ptr: GuestPtr + ) -> BrotliStatus; -wrap!(brotli_compress( - in_buf_ptr: Uptr, - in_buf_len: u32, - out_buf_ptr: Uptr, - out_len_ptr: Uptr, - level: u32, - window_size: u32 -) -> u32); + fn brotli_compress( + in_buf_ptr: GuestPtr, + in_buf_len: u32, + out_buf_ptr: GuestPtr, + out_len_ptr: GuestPtr, + level: u32, + window_size: u32 + ) -> BrotliStatus +} diff --git a/arbitrator/jit/src/callerenv.rs b/arbitrator/jit/src/caller_env.rs similarity index 68% rename from arbitrator/jit/src/callerenv.rs rename to arbitrator/jit/src/caller_env.rs index 8a2027eee..93cf6bad9 100644 --- a/arbitrator/jit/src/callerenv.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -1,11 +1,9 @@ -// Copyright 2022, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -#![allow(clippy::useless_transmute)] - use crate::machine::{WasmEnv, WasmEnvMut}; use arbutil::{Bytes20, Bytes32}; -use callerenv::{ExecEnv, MemAccess, Uptr}; +use caller_env::{ExecEnv, GuestPtr, MemAccess}; use rand::RngCore; use rand_pcg::Pcg32; use std::{ @@ -41,23 +39,23 @@ impl<'s> JitMemAccess<'s> { self.memory.view(&self.store) } - pub fn write_bytes20(&mut self, ptr: Uptr, val: Bytes20) { + pub fn write_bytes20(&mut self, ptr: GuestPtr, val: Bytes20) { self.write_slice(ptr, val.as_slice()) } - pub fn write_bytes32(&mut self, ptr: Uptr, val: Bytes32) { + pub fn write_bytes32(&mut self, ptr: GuestPtr, val: Bytes32) { self.write_slice(ptr, val.as_slice()) } - pub fn read_bytes20(&mut self, ptr: Uptr) -> Bytes20 { + pub fn read_bytes20(&mut self, ptr: GuestPtr) -> Bytes20 { self.read_fixed(ptr).into() } - pub fn read_bytes32(&mut self, ptr: Uptr) -> Bytes32 { + pub fn read_bytes32(&mut self, ptr: GuestPtr) -> Bytes32 { self.read_fixed(ptr).into() } - pub fn read_string(&mut self, ptr: Uptr, len: u32) -> String { + pub fn read_string(&mut self, ptr: GuestPtr, len: u32) -> String { let bytes = self.read_slice(ptr, len as usize); match String::from_utf8(bytes) { Ok(s) => s, @@ -71,61 +69,60 @@ impl<'s> JitMemAccess<'s> { } impl MemAccess for JitMemAccess<'_> { - fn read_u8(&self, ptr: Uptr) -> u8 { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn read_u8(&self, ptr: GuestPtr) -> u8 { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).read().unwrap() } - fn read_u16(&self, ptr: Uptr) -> u16 { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn read_u16(&self, ptr: GuestPtr) -> u16 { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).read().unwrap() } - fn read_u32(&self, ptr: Uptr) -> u32 { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn read_u32(&self, ptr: GuestPtr) -> u32 { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).read().unwrap() } - fn read_u64(&self, ptr: Uptr) -> u64 { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn read_u64(&self, ptr: GuestPtr) -> u64 { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).read().unwrap() } - fn write_u8(&mut self, ptr: Uptr, x: u8) { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn write_u8(&mut self, ptr: GuestPtr, x: u8) { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u16(&mut self, ptr: Uptr, x: u16) { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn write_u16(&mut self, ptr: GuestPtr, x: u16) { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u32(&mut self, ptr: Uptr, x: u32) { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn write_u32(&mut self, ptr: GuestPtr, x: u32) { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).write(x).unwrap(); } - fn write_u64(&mut self, ptr: Uptr, x: u64) { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn write_u64(&mut self, ptr: GuestPtr, x: u64) { + let ptr: WasmPtr = ptr.into(); ptr.deref(&self.view()).write(x).unwrap(); } - fn read_slice(&self, ptr: Uptr, len: usize) -> Vec { - u32::try_from(ptr).expect("Go pointer not a u32"); // kept for consistency - let len = u32::try_from(len).expect("length isn't a u32") as usize; - let mut data = vec![0; len]; - self.view() - .read(ptr.into(), &mut data) - .expect("failed to read"); + fn read_slice(&self, ptr: GuestPtr, len: usize) -> Vec { + let mut data = Vec::with_capacity(len); + unsafe { + self.view().read(ptr.into(), &mut data).expect("bad read"); + data.set_len(len); + } data } - fn read_fixed(&self, ptr: Uptr) -> [u8; N] { + fn read_fixed(&self, ptr: GuestPtr) -> [u8; N] { self.read_slice(ptr, N).try_into().unwrap() } - fn write_slice(&mut self, ptr: Uptr, src: &[u8]) { + fn write_slice(&mut self, ptr: GuestPtr, src: &[u8]) { self.view().write(ptr.into(), src).unwrap(); } } @@ -165,7 +162,7 @@ impl Default for GoRuntimeState { fn default() -> Self { Self { time: 0, - rng: callerenv::create_pcg(), + rng: caller_env::create_pcg(), } } } diff --git a/arbitrator/jit/src/machine.rs b/arbitrator/jit/src/machine.rs index b639c93ad..ffdaabad0 100644 --- a/arbitrator/jit/src/machine.rs +++ b/arbitrator/jit/src/machine.rs @@ -1,8 +1,8 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::{ - arbcompress, callerenv::GoRuntimeState, program, socket, stylus_backend::CothreadHandler, + arbcompress, caller_env::GoRuntimeState, program, socket, stylus_backend::CothreadHandler, wasip1_stub, wavmio, Opts, }; // runtime, socket, syscall, user diff --git a/arbitrator/jit/src/main.rs b/arbitrator/jit/src/main.rs index ecc5ee7d3..5aa762313 100644 --- a/arbitrator/jit/src/main.rs +++ b/arbitrator/jit/src/main.rs @@ -1,16 +1,14 @@ -// Copyright 2022, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::machine::{Escape, WasmEnv}; - use arbutil::{color, Color}; use eyre::Result; -use structopt::StructOpt; - use std::path::PathBuf; +use structopt::StructOpt; mod arbcompress; -mod callerenv; +mod caller_env; mod machine; mod program; mod socket; @@ -52,19 +50,18 @@ pub struct Opts { fn main() -> Result<()> { let opts = Opts::from_args(); - let env = match WasmEnv::cli(&opts) { Ok(env) => env, - Err(err) => panic!("{}", err), + Err(err) => panic!("{err}"), }; let (instance, env, mut store) = machine::create(&opts, env); let main = instance.exports.get_function("_start").unwrap(); - let outcome = main.call(&mut store, &vec![]); + let outcome = main.call(&mut store, &[]); let escape = match outcome { Ok(outcome) => { - println!("Go returned values {:?}", outcome); + println!("Go returned values {outcome:?}"); None } Err(outcome) => { diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index 6a258b466..c0808bb67 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -1,12 +1,14 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::callerenv::jit_env; +#![allow(clippy::too_many_arguments)] + +use crate::caller_env::jit_env; use crate::machine::{Escape, MaybeEscape, WasmEnvMut}; use crate::stylus_backend::exec_wasm; use arbutil::Bytes32; use arbutil::{evm::EvmData, format::DebugBytes, heapify}; -use callerenv::{MemAccess, Uptr}; +use caller_env::{GuestPtr, MemAccess}; use eyre::eyre; use prover::programs::prelude::StylusConfig; use prover::{ @@ -17,16 +19,16 @@ use prover::{ /// activates a user program pub fn activate( mut env: WasmEnvMut, - wasm_ptr: Uptr, + wasm_ptr: GuestPtr, wasm_size: u32, - pages_ptr: Uptr, - asm_estimate_ptr: Uptr, - init_gas_ptr: Uptr, + pages_ptr: GuestPtr, + asm_estimate_ptr: GuestPtr, + init_gas_ptr: GuestPtr, version: u16, debug: u32, - module_hash_ptr: Uptr, - gas_ptr: Uptr, - err_buf: Uptr, + module_hash_ptr: GuestPtr, + gas_ptr: GuestPtr, + err_buf: GuestPtr, err_buf_len: u32, ) -> Result { let (mut mem, _) = jit_env(&mut env); @@ -61,8 +63,8 @@ pub fn activate( /// returns module number pub fn new_program( mut env: WasmEnvMut, - compiled_hash_ptr: Uptr, - calldata_ptr: Uptr, + compiled_hash_ptr: GuestPtr, + calldata_ptr: GuestPtr, calldata_size: u32, stylus_config_handler: u64, evm_data_handler: u64, @@ -121,7 +123,7 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response -pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: Uptr) -> Result { +pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: GuestPtr) -> Result { let (mut mem, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; @@ -135,7 +137,7 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: Uptr) -> Result MaybeEscape { +pub fn get_request_data(mut env: WasmEnvMut, id: u32, data_ptr: GuestPtr) -> MaybeEscape { let (mut mem, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); let msg = thread.last_message()?; @@ -152,9 +154,9 @@ pub fn set_response( mut env: WasmEnvMut, id: u32, gas: u64, - result_ptr: Uptr, + result_ptr: GuestPtr, result_len: u32, - raw_data_ptr: Uptr, + raw_data_ptr: GuestPtr, raw_data_len: u32, ) -> MaybeEscape { let (mem, exec) = jit_env(&mut env); @@ -217,17 +219,17 @@ pub fn create_stylus_config( /// pub fn create_evm_data( mut env: WasmEnvMut, - block_basefee_ptr: Uptr, + block_basefee_ptr: GuestPtr, chainid: u64, - block_coinbase_ptr: Uptr, + block_coinbase_ptr: GuestPtr, block_gas_limit: u64, block_number: u64, block_timestamp: u64, - contract_address_ptr: Uptr, - msg_sender_ptr: Uptr, - msg_value_ptr: Uptr, - tx_gas_price_ptr: Uptr, - tx_origin_ptr: Uptr, + contract_address_ptr: GuestPtr, + msg_sender_ptr: GuestPtr, + msg_value_ptr: GuestPtr, + tx_gas_price_ptr: GuestPtr, + tx_origin_ptr: GuestPtr, reentrant: u32, ) -> Result { let (mut mem, _) = jit_env(&mut env); diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index ed57d9f97..e1e91366e 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -1,158 +1,162 @@ -// Copyright 2021-2023, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::callerenv::jit_env; +#![allow(clippy::too_many_arguments)] + +use crate::caller_env::jit_env; use crate::machine::{Escape, WasmEnvMut}; -use callerenv::{self, wasip1_stub::Errno, Uptr}; +use caller_env::{self, wasip1_stub::Errno, GuestPtr}; pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { Err(Escape::Exit(code)) } macro_rules! wrap { - ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { - pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let (mut mem, mut env) = jit_env(&mut src); - - Ok(callerenv::wasip1_stub::$func_name(&mut mem, &mut env, $($arg_name),*)) - } + ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { + $( + pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { + let (mut mem, mut env) = jit_env(&mut src); + + Ok(caller_env::wasip1_stub::$func_name(&mut mem, &mut env, $($arg_name),*)) + } + )* }; } -wrap!(clock_time_get( - clock_id: u32, - precision: u64, - time_ptr: Uptr -) -> Errno); - -wrap!(random_get(buf: Uptr, len: u32) -> Errno); - -wrap!(environ_sizes_get(length_ptr: Uptr, data_size_ptr: Uptr) -> Errno); -wrap!(fd_write( - fd: u32, - iovecs_ptr: Uptr, - iovecs_len: u32, - ret_ptr: Uptr -) -> Errno); -wrap!(environ_get(a: u32, b: u32) -> Errno); -wrap!(fd_close(fd: u32) -> Errno); -wrap!(fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno); -wrap!(fd_readdir( - fd: u32, - a: u32, - b: u32, - c: u64, - d: u32 -) -> Errno); - -wrap!(fd_sync(a: u32) -> Errno); - -wrap!(fd_seek( - _fd: u32, - _offset: u64, - _whence: u8, - _filesize: u32 -) -> Errno); - -wrap!(fd_datasync(_fd: u32) -> Errno); - -wrap!(path_open( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u64, - g: u64, - h: u32, - i: u32 -) -> Errno); - -wrap!(path_create_directory( - a: u32, - b: u32, - c: u32 -) -> Errno); - -wrap!(path_remove_directory( - a: u32, - b: u32, - c: u32 -) -> Errno); - -wrap!(path_readlink( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u32 -) -> Errno); - -wrap!(path_rename( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u32 -) -> Errno); - -wrap!(path_filestat_get( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32 -) -> Errno); - -wrap!(path_unlink_file(a: u32, b: u32, c: u32) -> Errno); - -wrap!(fd_prestat_get(a: u32, b: u32) -> Errno); - -wrap!(fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno); - -wrap!(fd_filestat_get(_fd: u32, _filestat: u32) -> Errno); - -wrap!(fd_filestat_set_size(_fd: u32, size: u64) -> Errno); - -wrap!(fd_pread( - _fd: u32, - _a: u32, - _b: u32, - _c: u64, - _d: u32 -) -> Errno); - -wrap!(fd_pwrite( - _fd: u32, - _a: u32, - _b: u32, - _c: u64, - _d: u32 -) -> Errno); - -wrap!(sock_accept(_fd: u32, a: u32, b: u32) -> Errno); - -wrap!(sock_shutdown(a: u32, b: u32) -> Errno); - -wrap!(sched_yield() -> Errno); - -wrap!(args_sizes_get( - length_ptr: Uptr, - data_size_ptr: Uptr -) -> Errno); - -wrap!(args_get(argv_buf: Uptr, data_buf: Uptr) -> Errno); - -// we always simulate a timeout -wrap!(poll_oneoff( - in_subs: Uptr, - out_evt: Uptr, - nsubscriptions: u32, - nevents_ptr: Uptr -) -> Errno); - -wrap!(fd_fdstat_get(a: u32, b: u32) -> Errno); - -wrap!(fd_fdstat_set_flags(a: u32, b: u32) -> Errno); +wrap! { + fn clock_time_get( + clock_id: u32, + precision: u64, + time_ptr: GuestPtr + ) -> Errno; + + fn random_get(buf: GuestPtr, len: u32) -> Errno; + + fn environ_get(a: GuestPtr, b: GuestPtr) -> Errno; + fn environ_sizes_get(length_ptr: GuestPtr, data_size_ptr: GuestPtr) -> Errno; + + fn fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno; + fn fd_close(fd: u32) -> Errno; + fn fd_write( + fd: u32, + iovecs_ptr: GuestPtr, + iovecs_len: u32, + ret_ptr: GuestPtr + ) -> Errno; + + fn fd_readdir( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn fd_sync(a: u32) -> Errno; + + fn fd_seek( + fd: u32, + offset: u64, + whence: u8, + filesize: u32 + ) -> Errno; + + fn fd_datasync(_fd: u32) -> Errno; + + fn path_open( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u64, + g: u64, + h: u32, + i: u32 + ) -> Errno; + + fn path_create_directory( + a: u32, + b: u32, + c: u32 + ) -> Errno; + + fn path_remove_directory( + a: u32, + b: u32, + c: u32 + ) -> Errno; + + fn path_readlink( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 + ) -> Errno; + + fn path_rename( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 + ) -> Errno; + + fn path_filestat_get( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32 + ) -> Errno; + + fn path_unlink_file(a: u32, b: u32, c: u32) -> Errno; + + fn fd_prestat_get(a: u32, b: u32) -> Errno; + fn fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno; + + fn fd_filestat_get(fd: u32, _filestat: u32) -> Errno; + fn fd_filestat_set_size(fd: u32, size: u64) -> Errno; + + fn fd_pread( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn fd_pwrite( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn sock_accept(_fd: u32, a: u32, b: u32) -> Errno; + fn sock_shutdown(a: u32, b: u32) -> Errno; + + fn sched_yield() -> Errno; + + fn args_sizes_get( + length_ptr: GuestPtr, + data_size_ptr: GuestPtr + ) -> Errno; + + fn args_get(argv_buf: GuestPtr, data_buf: GuestPtr) -> Errno; + + fn fd_fdstat_get(a: u32, b: u32) -> Errno; + fn fd_fdstat_set_flags(a: u32, b: u32) -> Errno; + + // we always simulate a timeout + fn poll_oneoff( + in_subs: GuestPtr, + out_evt: GuestPtr, + nsubscriptions: u32, + nevents_ptr: GuestPtr + ) -> Errno +} diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index 5c2f909ac..d74c4c789 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -1,13 +1,13 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::{ - callerenv::jit_env, + caller_env::jit_env, machine::{Escape, MaybeEscape, WasmEnv, WasmEnvMut}, socket, }; use arbutil::Color; -use callerenv::{MemAccess, Uptr}; +use caller_env::{GuestPtr, MemAccess}; use std::{ io, io::{BufReader, BufWriter, ErrorKind}, @@ -16,20 +16,19 @@ use std::{ }; /// Reads 32-bytes of global state -pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: Uptr) -> MaybeEscape { +pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: GuestPtr) -> MaybeEscape { let (mut mem, exec) = jit_env(&mut env); ready_hostio(exec.wenv)?; - let global = match exec.wenv.large_globals.get(idx as usize) { - Some(global) => global.clone(), - None => return Escape::hostio("global read out of bounds in wavmio.getGlobalStateBytes32"), + let Some(global) = exec.wenv.large_globals.get(idx as usize) else { + return Escape::hostio("global read out of bounds in wavmio.getGlobalStateBytes32"); }; mem.write_slice(out_ptr, &global[..32]); Ok(()) } /// Writes 32-bytes of global state -pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: Uptr) -> MaybeEscape { +pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: GuestPtr) -> MaybeEscape { let (mem, exec) = jit_env(&mut env); ready_hostio(exec.wenv)?; @@ -74,7 +73,7 @@ pub fn read_inbox_message( mut env: WasmEnvMut, msg_num: u64, offset: u32, - out_ptr: Uptr, + out_ptr: GuestPtr, ) -> Result { let (mut mem, exec) = jit_env(&mut env); ready_hostio(exec.wenv)?; @@ -95,7 +94,7 @@ pub fn read_delayed_inbox_message( mut env: WasmEnvMut, msg_num: u64, offset: u32, - out_ptr: Uptr, + out_ptr: GuestPtr, ) -> Result { let (mut mem, exec) = jit_env(&mut env); ready_hostio(exec.wenv)?; @@ -117,9 +116,9 @@ pub fn read_delayed_inbox_message( /// Retrieves the preimage of the given hash. pub fn resolve_preimage( mut env: WasmEnvMut, - hash_ptr: Uptr, + hash_ptr: GuestPtr, offset: u32, - out_ptr: Uptr, + out_ptr: GuestPtr, ) -> Result { let (mut mem, exec) = jit_env(&mut env); @@ -149,13 +148,11 @@ pub fn resolve_preimage( preimage = exec.wenv.preimages.get(&hash); } - let preimage = match preimage { - Some(preimage) => preimage, - None => error!("Missing requested preimage for hash {hash_hex} in {name}"), + let Some(preimage) = preimage else { + error!("Missing requested preimage for hash {hash_hex} in {name}") }; - let offset = match u32::try_from(offset) { - Ok(offset) => offset as usize, - Err(_) => error!("bad offset {offset} in {name}"), + let Ok(offset) = usize::try_from(offset) else { + error!("bad offset {offset} in {name}") }; let len = std::cmp::min(32, preimage.len().saturating_sub(offset)); diff --git a/arbitrator/prover/src/host.rs b/arbitrator/prover/src/host.rs index 78f4e9dd6..35344e85c 100644 --- a/arbitrator/prover/src/host.rs +++ b/arbitrator/prover/src/host.rs @@ -207,7 +207,7 @@ impl Hostio { ty } - pub fn body(&self, prior: usize) -> Vec { + pub fn body(&self, _prior: usize) -> Vec { let mut body = vec![]; macro_rules! opcode { diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index e03405463..c65b8c7f5 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -718,10 +718,35 @@ pub struct ModuleState<'a> { memory: Cow<'a, Memory>, } +/// Represents if the machine can recover and where to jump back if so. +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum ThreadState { + /// Execution is in the main thread. Errors are fatal. + Main, + /// Execution is in a cothread. Errors recover to the associated pc with the main thread. + CoThread(ProgramCounter), +} + +impl ThreadState { + fn is_cothread(&self) -> bool { + match self { + ThreadState::Main => false, + ThreadState::CoThread(_) => true, + } + } + + fn serialize(&self) -> Bytes32 { + match self { + ThreadState::Main => Bytes32([0xff; 32]), + ThreadState::CoThread(pc) => (*pc).serialize(), + } + } +} + #[derive(Serialize, Deserialize)] pub struct MachineState<'a> { steps: u64, // Not part of machine hash - main_thread_recovery: Option, + thread_state: ThreadState, status: MachineStatus, value_stacks: Cow<'a, Vec>>, internal_stack: Cow<'a, Vec>, @@ -785,11 +810,7 @@ impl PreimageResolverWrapper { #[derive(Clone, Debug)] pub struct Machine { steps: u64, // Not part of machine hash - // This has double use: - // If None - we are not in a cothread. - // Otherwise - it holds the recovery PC which we'll jump to - // in case the cothread reaches a machine error - main_thread_recovery: Option, + thread_state: ThreadState, status: MachineStatus, value_stacks: Vec>, internal_stack: Vec, @@ -1348,7 +1369,7 @@ impl Machine { let mut mach = Machine { status: MachineStatus::Running, - main_thread_recovery: None, + thread_state: ThreadState::Main, steps: 0, value_stacks: vec![vec![Value::RefNull, Value::I32(0), Value::I32(0)]], internal_stack: Vec::new(), @@ -1403,7 +1424,7 @@ impl Machine { } let mut mach = Machine { status: MachineStatus::Running, - main_thread_recovery: None, + thread_state: ThreadState::Main, steps: 0, value_stacks: vec![vec![Value::RefNull, Value::I32(0), Value::I32(0)]], internal_stack: Vec::new(), @@ -1453,7 +1474,7 @@ impl Machine { .collect(); let state = MachineState { steps: self.steps, - main_thread_recovery: self.main_thread_recovery, + thread_state: self.thread_state, status: self.status, value_stacks: Cow::Borrowed(&self.value_stacks), internal_stack: Cow::Borrowed(&self.internal_stack), @@ -1589,7 +1610,7 @@ impl Machine { } pub fn get_final_result(&self) -> Result> { - if self.main_thread_recovery.is_some() { + if self.thread_state.is_cothread() { bail!("machine in cothread when expecting final result") } if !self.frame_stacks[0].is_empty() { @@ -1701,9 +1722,9 @@ impl Machine { if self.is_halted() { return Ok(()); } - let (mut value_stack, mut frame_stack) = match self.main_thread_recovery { - None => (&mut self.value_stacks[0], &mut self.frame_stacks[0]), - Some(_) => ( + let (mut value_stack, mut frame_stack) = match self.thread_state { + ThreadState::Main => (&mut self.value_stacks[0], &mut self.frame_stacks[0]), + ThreadState::CoThread(_) => ( self.value_stacks.last_mut().unwrap(), self.frame_stacks.last_mut().unwrap(), ), @@ -1713,9 +1734,9 @@ impl Machine { macro_rules! reset_refs { () => { - (value_stack, frame_stack) = match self.main_thread_recovery { - None => (&mut self.value_stacks[0], &mut self.frame_stacks[0]), - Some(_) => ( + (value_stack, frame_stack) = match self.thread_state { + ThreadState::Main => (&mut self.value_stacks[0], &mut self.frame_stacks[0]), + ThreadState::CoThread(_) => ( self.value_stacks.last_mut().unwrap(), self.frame_stacks.last_mut().unwrap(), ), @@ -1737,21 +1758,23 @@ impl Machine { }; ($format:expr $(, $message:expr)*) => {{ flush_module!(); - let print_debug_info = |machine: &Self| { + + if self.debug_info { println!("\n{} {}", "error on line".grey(), line!().pink()); println!($format, $($message.pink()),*); - println!("{}", "Backtrace:".grey()); - machine.print_backtrace(true); - }; + println!("{}", "backtrace:".grey()); + self.print_backtrace(true); + } - if let Some(recovery_pc) = self.main_thread_recovery.take() { - println!("\n{}", "switching to main thread".grey()); + if let ThreadState::CoThread(recovery_pc) = self.thread_state { self.pc = recovery_pc; reset_refs!(); - println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); + if self.debug_info { + println!("\n{}", "switching to main thread".grey()); + println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); + } + self.thread_state = ThreadState::Main; continue; - } else { - print_debug_info(self); } self.status = MachineStatus::Errored; module = &mut self.modules[self.pc.module()]; @@ -1790,7 +1813,7 @@ impl Machine { .and_then(|h| h.as_ref()) { if let Err(err) = Self::host_call_hook( - &value_stack, + value_stack, module, &mut self.stdio_output, &hook.0, @@ -2328,7 +2351,7 @@ impl Machine { break; } Opcode::NewCoThread => { - if self.main_thread_recovery.is_some() { + if self.thread_state.is_cothread() { error!("called NewCoThread from cothread") } self.value_stacks.push(Vec::new()); @@ -2336,7 +2359,7 @@ impl Machine { reset_refs!(); } Opcode::PopCoThread => { - if self.main_thread_recovery.is_some() { + if self.thread_state.is_cothread() { error!("called PopCoThread from cothread") } self.value_stacks.pop(); @@ -2344,17 +2367,17 @@ impl Machine { reset_refs!(); } Opcode::SwitchThread => { - let next_recovery = match inst.argument_data { - 0 => None, - offset => { - let offset: u32 = (offset - 1).try_into().unwrap(); - Some(self.pc.add(offset)) - } - }; - if next_recovery.xor(self.main_thread_recovery).is_none() { - error!("switchthread doesn't switch") + let next_recovery = (inst.argument_data != 0) + .then(|| inst.argument_data - 1) + .map(|x| self.pc.add(x.try_into().unwrap())); + + if next_recovery.is_some() == self.thread_state.is_cothread() { + error!("SwitchThread doesn't switch") } - self.main_thread_recovery = next_recovery; + self.thread_state = match next_recovery { + Some(pc) => ThreadState::CoThread(pc), + None => ThreadState::Main, + }; reset_refs!(); } } @@ -2561,13 +2584,6 @@ impl Machine { (frame_stacks, value_stacks, inter_stack) } - pub fn main_thread_recovery_serialized(&self) -> Bytes32 { - match self.main_thread_recovery { - Some(recovery_pc) => recovery_pc.serialize(), - None => Bytes32([255; 32]), - } - } - pub fn hash(&self) -> Bytes32 { let mut h = Keccak256::new(); match self.status { @@ -2582,7 +2598,7 @@ impl Machine { h.update(self.pc.module.to_be_bytes()); h.update(self.pc.func.to_be_bytes()); h.update(self.pc.inst.to_be_bytes()); - h.update(self.main_thread_recovery_serialized()); + h.update(self.thread_state.serialize()); h.update(self.get_modules_root()); } MachineStatus::Finished => { @@ -2617,7 +2633,7 @@ impl Machine { }}; } out!(prove_multistack( - self.main_thread_recovery.is_some(), + self.thread_state.is_cothread(), self.get_data_stacks(), hash_value_stack, hash_multistack, @@ -2633,7 +2649,7 @@ impl Machine { )); out!(prove_multistack( - self.main_thread_recovery.is_some(), + self.thread_state.is_cothread(), self.get_frame_stacks(), hash_stack_frame_stack, hash_multistack, @@ -2650,7 +2666,7 @@ impl Machine { out!(self.pc.func.to_be_bytes()); out!(self.pc.inst.to_be_bytes()); - out!(self.main_thread_recovery_serialized()); + out!(self.thread_state.serialize()); let mod_merkle = self.get_modules_merkle(); out!(mod_merkle.root()); @@ -2880,9 +2896,9 @@ impl Machine { } pub fn get_data_stack(&self) -> &[Value] { - match self.main_thread_recovery { - None => &self.value_stacks[0], - Some(_) => self.value_stacks.last().unwrap(), + match self.thread_state { + ThreadState::Main => &self.value_stacks[0], + ThreadState::CoThread(_) => self.value_stacks.last().unwrap(), } } @@ -2891,16 +2907,16 @@ impl Machine { } fn get_frame_stack(&self) -> &[StackFrame] { - match self.main_thread_recovery { - None => &self.frame_stacks[0], - Some(_) => self.frame_stacks.last().unwrap(), + match self.thread_state { + ThreadState::Main => &self.frame_stacks[0], + ThreadState::CoThread(_) => self.frame_stacks.last().unwrap(), } } fn get_frame_stacks(&self) -> Vec<&[StackFrame]> { self.frame_stacks .iter() - .map(|v: &Vec| v.as_slice()) + .map(|v: &Vec<_>| v.as_slice()) .collect() } diff --git a/arbitrator/stylus/Cargo.toml b/arbitrator/stylus/Cargo.toml index f57f200f3..01867e307 100644 --- a/arbitrator/stylus/Cargo.toml +++ b/arbitrator/stylus/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] arbutil = { path = "../arbutil/" } +caller-env = { path = "../caller-env", features = ["wasmer_traits"] } prover = { path = "../prover/", default-features = false, features = ["native"] } wasmer = { path = "../tools/wasmer/lib/api" } wasmer-vm = { path = "../tools/wasmer/lib/vm/" } diff --git a/arbitrator/stylus/src/env.rs b/arbitrator/stylus/src/env.rs index 6599026b8..5922d84b0 100644 --- a/arbitrator/stylus/src/env.rs +++ b/arbitrator/stylus/src/env.rs @@ -8,6 +8,7 @@ use arbutil::{ }, pricing, }; +use caller_env::GuestPtr; use derivative::Derivative; use eyre::{eyre, ErrReport}; use prover::programs::{config::PricingParams, meter::OutOfInkError, prelude::*}; @@ -160,7 +161,7 @@ impl<'a, D: DataReader, E: EvmApi> HostioInfo<'a, D, E> { } // TODO: use the unstable array_assum_init - pub fn read_fixed(&self, ptr: u32) -> Result<[u8; N], MemoryAccessError> { + pub fn read_fixed(&self, ptr: GuestPtr) -> Result<[u8; N], MemoryAccessError> { let mut data = [MaybeUninit::uninit(); N]; self.view().read_uninit(ptr.into(), &mut data)?; Ok(data.map(|x| unsafe { x.assume_init() })) diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index bed09f686..d362ca80c 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -3,8 +3,6 @@ #![allow(clippy::too_many_arguments)] -use std::fmt::Display; - use crate::env::{Escape, HostioInfo, MaybeEscape, WasmEnv, WasmEnvMut}; use arbutil::{ evm::{ @@ -13,10 +11,45 @@ use arbutil::{ }, Color, }; +use caller_env::GuestPtr; use eyre::{eyre, Result}; use prover::value::Value; -use user_host_trait::{Uptr, UserHost}; -use wasmer::{MemoryAccessError, WasmPtr}; +use std::{ + fmt::Display, + ops::{Deref, DerefMut}, +}; +use user_host_trait::UserHost; +use wasmer::{FromToNativeWasmType, MemoryAccessError, WasmPtr}; + +#[derive(Clone, Copy)] +#[repr(transparent)] +pub(crate) struct ClientPtr(pub GuestPtr); + +unsafe impl FromToNativeWasmType for ClientPtr { + type Native = i32; + + fn from_native(native: i32) -> Self { + Self(GuestPtr(u32::from_native(native))) + } + + fn to_native(self) -> Self::Native { + self.0 .0.to_native() + } +} + +impl Deref for ClientPtr { + type Target = GuestPtr; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for ClientPtr { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { type Err = Escape; @@ -45,24 +78,24 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { fn read_fixed( &self, - ptr: Uptr, + ptr: GuestPtr, ) -> std::result::Result<[u8; N], >::MemoryErr> { - HostioInfo::read_fixed(&self, ptr) + HostioInfo::read_fixed(self, ptr) } - fn read_slice(&self, ptr: Uptr, len: u32) -> Result, Self::MemoryErr> { + fn read_slice(&self, ptr: GuestPtr, len: u32) -> Result, Self::MemoryErr> { let mut data = vec![0; len as usize]; self.view().read(ptr.into(), &mut data)?; Ok(data) } - fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), Self::MemoryErr> { - let ptr: WasmPtr = WasmPtr::new(ptr); + fn write_u32(&mut self, ptr: GuestPtr, x: u32) -> Result<(), Self::MemoryErr> { + let ptr: WasmPtr = WasmPtr::new(ptr.into()); ptr.deref(&self.view()).write(x)?; Ok(()) } - fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), Self::MemoryErr> { + fn write_slice(&self, ptr: GuestPtr, src: &[u8]) -> Result<(), Self::MemoryErr> { self.view().write(ptr.into(), src) } @@ -91,14 +124,14 @@ macro_rules! hostio { pub(crate) fn read_args>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, read_args(ptr)) } pub(crate) fn write_result>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, len: u32, ) -> MaybeEscape { hostio!(env, write_result(ptr, len)) @@ -106,28 +139,28 @@ pub(crate) fn write_result>( pub(crate) fn storage_load_bytes32>( mut env: WasmEnvMut, - key: u32, - dest: u32, + key: GuestPtr, + dest: GuestPtr, ) -> MaybeEscape { hostio!(env, storage_load_bytes32(key, dest)) } pub(crate) fn storage_store_bytes32>( mut env: WasmEnvMut, - key: u32, - value: u32, + key: GuestPtr, + value: GuestPtr, ) -> MaybeEscape { hostio!(env, storage_store_bytes32(key, value)) } pub(crate) fn call_contract>( mut env: WasmEnvMut, - contract: u32, - data: u32, + contract: GuestPtr, + data: GuestPtr, data_len: u32, - value: u32, + value: GuestPtr, gas: u64, - ret_len: u32, + ret_len: GuestPtr, ) -> Result { hostio!( env, @@ -137,11 +170,11 @@ pub(crate) fn call_contract>( pub(crate) fn delegate_call_contract>( mut env: WasmEnvMut, - contract: u32, - data: u32, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: GuestPtr, ) -> Result { hostio!( env, @@ -151,11 +184,11 @@ pub(crate) fn delegate_call_contract>( pub(crate) fn static_call_contract>( mut env: WasmEnvMut, - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: u32, + ret_len: GuestPtr, ) -> Result { hostio!( env, @@ -165,11 +198,11 @@ pub(crate) fn static_call_contract>( pub(crate) fn create1>( mut env: WasmEnvMut, - code: u32, + code: GuestPtr, code_len: u32, - endowment: u32, - contract: u32, - revert_len: u32, + endowment: GuestPtr, + contract: GuestPtr, + revert_len: GuestPtr, ) -> MaybeEscape { hostio!( env, @@ -179,12 +212,12 @@ pub(crate) fn create1>( pub(crate) fn create2>( mut env: WasmEnvMut, - code: u32, + code: GuestPtr, code_len: u32, - endowment: u32, - salt: u32, - contract: u32, - revert_len: u32, + endowment: GuestPtr, + salt: GuestPtr, + contract: GuestPtr, + revert_len: GuestPtr, ) -> MaybeEscape { hostio!( env, @@ -194,7 +227,7 @@ pub(crate) fn create2>( pub(crate) fn read_return_data>( mut env: WasmEnvMut, - dest: u32, + dest: GuestPtr, offset: u32, size: u32, ) -> Result { @@ -209,7 +242,7 @@ pub(crate) fn return_data_size>( pub(crate) fn emit_log>( mut env: WasmEnvMut, - data: u32, + data: GuestPtr, len: u32, topics: u32, ) -> MaybeEscape { @@ -218,47 +251,47 @@ pub(crate) fn emit_log>( pub(crate) fn account_balance>( mut env: WasmEnvMut, - address: Uptr, - ptr: Uptr, + address: GuestPtr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, account_balance(address, ptr)) } pub(crate) fn account_code>( mut env: WasmEnvMut, - address: Uptr, - offset: Uptr, + address: GuestPtr, + offset: u32, size: u32, - code: u32, + code: GuestPtr, ) -> Result { hostio!(env, account_code(address, offset, size, code)) } pub(crate) fn account_code_size>( mut env: WasmEnvMut, - address: u32, + address: GuestPtr, ) -> Result { hostio!(env, account_code_size(address)) } pub(crate) fn account_codehash>( mut env: WasmEnvMut, - address: u32, - ptr: Uptr, + address: GuestPtr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, account_codehash(address, ptr)) } pub(crate) fn block_basefee>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, block_basefee(ptr)) } pub(crate) fn block_coinbase>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, block_coinbase(ptr)) } @@ -289,7 +322,7 @@ pub(crate) fn chainid>( pub(crate) fn contract_address>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, contract_address(ptr)) } @@ -314,30 +347,30 @@ pub(crate) fn msg_reentrant>( pub(crate) fn msg_sender>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, msg_sender(ptr)) } pub(crate) fn msg_value>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, msg_value(ptr)) } pub(crate) fn native_keccak256>( mut env: WasmEnvMut, - input: Uptr, + input: GuestPtr, len: u32, - output: Uptr, + output: GuestPtr, ) -> MaybeEscape { hostio!(env, native_keccak256(input, len, output)) } pub(crate) fn tx_gas_price>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, tx_gas_price(ptr)) } @@ -350,7 +383,7 @@ pub(crate) fn tx_ink_price>( pub(crate) fn tx_origin>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, ) -> MaybeEscape { hostio!(env, tx_origin(ptr)) } @@ -364,7 +397,7 @@ pub(crate) fn pay_for_memory_grow>( pub(crate) fn console_log_text>( mut env: WasmEnvMut, - ptr: Uptr, + ptr: GuestPtr, len: u32, ) -> MaybeEscape { hostio!(env, console_log_text(ptr, len)) diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 2835ee246..b7a44a4f4 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -67,7 +67,7 @@ pub struct SendGoSliceData { } #[allow(dead_code)] -const fn assert_go_slices_match() -> () { +const fn assert_go_slices_match() { // TODO: this will be stabilized on rust 1.77 // assert_eq!(mem::offset_of!(GoSliceData, ptr), mem::offset_of!(SendGoSliceData, ptr)); // assert_eq!(mem::offset_of!(GoSliceData, len), mem::offset_of!(SendGoSliceData, len)); diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 074e9f850..e6c876103 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -107,7 +107,7 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" name = "brotli" version = "0.1.0" dependencies = [ - "callerenv", + "caller-env", "paste", ] @@ -134,9 +134,10 @@ dependencies = [ ] [[package]] -name = "callerenv" +name = "caller-env" version = "0.1.0" dependencies = [ + "num_enum", "rand", "rand_pcg", ] @@ -428,7 +429,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "host-io" version = "0.1.0" dependencies = [ - "callerenv", + "caller-env", ] [[package]] @@ -659,18 +660,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683751d591e6d81200c39fb0d1032608b77724f34114db54f571ff1317b337c0" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -1229,7 +1230,7 @@ name = "user-host" version = "0.1.0" dependencies = [ "arbutil", - "callerenv", + "caller-env", "eyre", "fnv", "hex", @@ -1243,7 +1244,7 @@ name = "user-host-trait" version = "0.1.0" dependencies = [ "arbutil", - "callerenv", + "caller-env", "eyre", "prover", ] @@ -1253,7 +1254,7 @@ name = "user-test" version = "0.1.0" dependencies = [ "arbutil", - "callerenv", + "caller-env", "eyre", "fnv", "hex", @@ -1290,7 +1291,7 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" name = "wasi-stub" version = "0.1.0" dependencies = [ - "callerenv", + "caller-env", "paste", "wee_alloc", ] diff --git a/arbitrator/wasm-libraries/Cargo.toml b/arbitrator/wasm-libraries/Cargo.toml index aae12537f..e9e5aa4b8 100644 --- a/arbitrator/wasm-libraries/Cargo.toml +++ b/arbitrator/wasm-libraries/Cargo.toml @@ -4,9 +4,9 @@ members = [ "wasi-stub", "host-io", "user-host", - "user-host-trait", + "user-host-trait", "user-test", "program-exec", - "forward", + "forward", ] resolver = "2" diff --git a/arbitrator/wasm-libraries/brotli/Cargo.toml b/arbitrator/wasm-libraries/brotli/Cargo.toml index 0f18eb07c..640db7230 100644 --- a/arbitrator/wasm-libraries/brotli/Cargo.toml +++ b/arbitrator/wasm-libraries/brotli/Cargo.toml @@ -8,5 +8,5 @@ publish = false crate-type = ["cdylib"] [dependencies] -paste = {version="1.0.14"} -callerenv = { path = "../../callerenv/", features = ["static_caller"] } +paste = { version = "1.0.14" } +caller-env = { path = "../../caller-env/", features = ["static_caller"] } diff --git a/arbitrator/wasm-libraries/brotli/src/lib.rs b/arbitrator/wasm-libraries/brotli/src/lib.rs index 49ef09d7e..86456bfec 100644 --- a/arbitrator/wasm-libraries/brotli/src/lib.rs +++ b/arbitrator/wasm-libraries/brotli/src/lib.rs @@ -1,28 +1,30 @@ -// Copyright 2021-2023, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use callerenv::{ - self, - MemAccess, - ExecEnv, - Uptr -}; +#![allow(clippy::missing_safety_doc)] // TODO: add safety docs + +use caller_env::{self, brotli::BrotliStatus, GuestPtr}; use paste::paste; macro_rules! wrap { - ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { paste! { - #[no_mangle] - pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { - callerenv::brotli::$func_name( - &mut callerenv::static_caller::STATIC_MEM, - &mut callerenv::static_caller::STATIC_ENV, - $($arg_name),*) - } + $( + #[no_mangle] + pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { + caller_env::brotli::$func_name( + &mut caller_env::static_caller::STATIC_MEM, + &mut caller_env::static_caller::STATIC_ENV, + $($arg_name),* + ) + } + )* } }; } -wrap!(brotli_decompress(in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, out_len_ptr: Uptr) -> u32); +wrap! { + fn brotli_decompress(in_buf_ptr: GuestPtr, in_buf_len: u32, out_buf_ptr: GuestPtr, out_len_ptr: GuestPtr) -> BrotliStatus; -wrap!(brotli_compress(in_buf_ptr: Uptr, in_buf_len: u32, out_buf_ptr: Uptr, out_len_ptr: Uptr, level: u32, window_size: u32) -> u32); \ No newline at end of file + fn brotli_compress(in_buf_ptr: GuestPtr, in_buf_len: u32, out_buf_ptr: GuestPtr, out_len_ptr: GuestPtr, level: u32, window_size: u32) -> BrotliStatus +} diff --git a/arbitrator/wasm-libraries/host-io/Cargo.toml b/arbitrator/wasm-libraries/host-io/Cargo.toml index 0e8a3340a..1743b1017 100644 --- a/arbitrator/wasm-libraries/host-io/Cargo.toml +++ b/arbitrator/wasm-libraries/host-io/Cargo.toml @@ -8,4 +8,4 @@ publish = false crate-type = ["cdylib"] [dependencies] -callerenv = { path = "../../callerenv/", features = ["static_caller"] } +caller-env = { path = "../../caller-env/", features = ["static_caller"] } diff --git a/arbitrator/wasm-libraries/host-io/src/lib.rs b/arbitrator/wasm-libraries/host-io/src/lib.rs index a792c852e..796f6db66 100644 --- a/arbitrator/wasm-libraries/host-io/src/lib.rs +++ b/arbitrator/wasm-libraries/host-io/src/lib.rs @@ -1,7 +1,7 @@ -// Copyright 2021-2023, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; +use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; extern "C" { pub fn wavm_get_globalstate_bytes32(idx: u32, ptr: *mut u8); @@ -17,7 +17,7 @@ extern "C" { struct MemoryLeaf([u8; 32]); #[no_mangle] -pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: Uptr) { +pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: GuestPtr) { let mut our_buf = MemoryLeaf([0u8; 32]); let our_ptr = our_buf.0.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); @@ -27,7 +27,7 @@ pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: Uptr) /// Writes 32-bytes of global state #[no_mangle] -pub unsafe extern "C" fn wavmio__setGlobalStateBytes32(idx: u32, src_ptr: Uptr) { +pub unsafe extern "C" fn wavmio__setGlobalStateBytes32(idx: u32, src_ptr: GuestPtr) { let mut our_buf = MemoryLeaf([0u8; 32]); let value = STATIC_MEM.read_slice(src_ptr, 32); our_buf.0.copy_from_slice(&value); @@ -38,7 +38,7 @@ pub unsafe extern "C" fn wavmio__setGlobalStateBytes32(idx: u32, src_ptr: Uptr) /// Reads 8-bytes of global state #[no_mangle] -pub unsafe extern "C" fn wavmio__getGlobalStateU64(idx: u32) -> u64{ +pub unsafe extern "C" fn wavmio__getGlobalStateU64(idx: u32) -> u64 { wavm_get_globalstate_u64(idx) } @@ -50,7 +50,11 @@ pub unsafe extern "C" fn wavmio__setGlobalStateU64(idx: u32, val: u64) { /// Reads an inbox message #[no_mangle] -pub unsafe extern "C" fn wavmio__readInboxMessage(msg_num: u64, offset: usize, out_ptr: Uptr) -> usize { +pub unsafe extern "C" fn wavmio__readInboxMessage( + msg_num: u64, + offset: usize, + out_ptr: GuestPtr, +) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); let our_ptr = our_buf.0.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); @@ -62,11 +66,15 @@ pub unsafe extern "C" fn wavmio__readInboxMessage(msg_num: u64, offset: usize, o /// Reads a delayed inbox message #[no_mangle] -pub unsafe extern "C" fn wavmio__readDelayedInboxMessage(msg_num: u64, offset: usize, out_ptr: Uptr) -> usize { +pub unsafe extern "C" fn wavmio__readDelayedInboxMessage( + msg_num: u64, + offset: usize, + out_ptr: GuestPtr, +) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); let our_ptr = our_buf.0.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); - let read = wavm_read_delayed_inbox_message(msg_num, our_ptr, offset as usize); + let read = wavm_read_delayed_inbox_message(msg_num, our_ptr, offset); assert!(read <= 32); STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); read @@ -74,7 +82,11 @@ pub unsafe extern "C" fn wavmio__readDelayedInboxMessage(msg_num: u64, offset: u /// Retrieves the preimage of the given hash. #[no_mangle] -pub unsafe extern "C" fn wavmio__resolvePreImage(hash_ptr: Uptr, offset: usize, out_ptr: Uptr) -> usize { +pub unsafe extern "C" fn wavmio__resolvePreImage( + hash_ptr: GuestPtr, + offset: usize, + out_ptr: GuestPtr, +) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); let hash = STATIC_MEM.read_slice(hash_ptr, 32); our_buf.0.copy_from_slice(&hash); diff --git a/arbitrator/wasm-libraries/program-exec/src/lib.rs b/arbitrator/wasm-libraries/program-exec/src/lib.rs index 98b3123f0..700d1a7cf 100644 --- a/arbitrator/wasm-libraries/program-exec/src/lib.rs +++ b/arbitrator/wasm-libraries/program-exec/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE #[link(wasm_import_module = "hostio")] @@ -42,9 +42,7 @@ fn check_program_done(mut req_id: u32) -> u32 { /// module MUST match last module number returned from new_program /// returns request_id for the first request from the program #[no_mangle] -pub unsafe extern "C" fn programs__start_program( - module: u32, -) -> u32 { +pub unsafe extern "C" fn programs__start_program(module: u32) -> u32 { // call the program let args_len = args_len(module); check_program_done(program_call_main(module, args_len)) @@ -54,9 +52,7 @@ pub unsafe extern "C" fn programs__start_program( // MUST be called right after set_response to the same id // returns request_id for the next request #[no_mangle] -pub unsafe extern "C" fn programs__send_response( - req_id: u32, -) -> u32 { +pub unsafe extern "C" fn programs__send_response(req_id: u32) -> u32 { // call the program check_program_done(program_continue(req_id)) } diff --git a/arbitrator/wasm-libraries/user-host-trait/Cargo.toml b/arbitrator/wasm-libraries/user-host-trait/Cargo.toml index 6ee53bd47..7e40868f4 100644 --- a/arbitrator/wasm-libraries/user-host-trait/Cargo.toml +++ b/arbitrator/wasm-libraries/user-host-trait/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] arbutil = { path = "../../arbutil/" } -callerenv = { path = "../../callerenv/" } +caller-env = { path = "../../caller-env/" } prover = { path = "../../prover/", default-features = false } eyre = "0.6.5" diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index e1009cde7..d2b17cece 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -12,7 +12,7 @@ use arbutil::{ pricing::{EVM_API_INK, HOSTIO_INK, PTR_INK}, Bytes20, Bytes32, }; -pub use callerenv::Uptr; +pub use caller_env::GuestPtr; use eyre::{eyre, Result}; use prover::{ programs::{meter::OutOfInkError, prelude::*}, @@ -68,18 +68,18 @@ pub trait UserHost: GasMeteredMachine { fn evm_data(&self) -> &EvmData; fn evm_return_data_len(&mut self) -> &mut u32; - fn read_slice(&self, ptr: Uptr, len: u32) -> Result, Self::MemoryErr>; - fn read_fixed(&self, ptr: Uptr) -> Result<[u8; N], Self::MemoryErr>; + fn read_slice(&self, ptr: GuestPtr, len: u32) -> Result, Self::MemoryErr>; + fn read_fixed(&self, ptr: GuestPtr) -> Result<[u8; N], Self::MemoryErr>; - fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), Self::MemoryErr>; - fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), Self::MemoryErr>; + fn write_u32(&mut self, ptr: GuestPtr, x: u32) -> Result<(), Self::MemoryErr>; + fn write_slice(&self, ptr: GuestPtr, src: &[u8]) -> Result<(), Self::MemoryErr>; - fn read_bytes20(&self, ptr: Uptr) -> Result { - self.read_fixed(ptr).and_then(|x| Ok(x.into())) + fn read_bytes20(&self, ptr: GuestPtr) -> Result { + self.read_fixed(ptr).map(|x| x.into()) } - fn read_bytes32(&self, ptr: Uptr) -> Result { - self.read_fixed(ptr).and_then(|x| Ok(x.into())) + fn read_bytes32(&self, ptr: GuestPtr) -> Result { + self.read_fixed(ptr).map(|x| x.into()) } // ink when call stated, only used for tracing, Err if unavailable. @@ -87,11 +87,11 @@ pub trait UserHost: GasMeteredMachine { fn say(&self, text: D); fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], start_ink: u64, end_ink: u64); - fn write_bytes20(&self, ptr: Uptr, src: Bytes20) -> Result<(), Self::MemoryErr> { + fn write_bytes20(&self, ptr: GuestPtr, src: Bytes20) -> Result<(), Self::MemoryErr> { self.write_slice(ptr, &src.0) } - fn write_bytes32(&self, ptr: Uptr, src: Bytes32) -> Result<(), Self::MemoryErr> { + fn write_bytes32(&self, ptr: GuestPtr, src: Bytes32) -> Result<(), Self::MemoryErr> { self.write_slice(ptr, &src.0) } @@ -99,7 +99,7 @@ pub trait UserHost: GasMeteredMachine { /// [`CALLDATA_COPY`] opcode when requesting the entirety of the current call's calldata. /// /// [`CALLDATA_COPY`]: https://www.evm.codes/#37 - fn read_args(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn read_args(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK)?; self.pay_for_write(self.args().len() as u32)?; self.write_slice(ptr, self.args())?; @@ -109,7 +109,7 @@ pub trait UserHost: GasMeteredMachine { /// Writes the final return data. If not called before the program exists, the return data will /// be 0 bytes long. Note that this hostio does not cause the program to exit, which happens /// naturally when `user_entrypoint` returns. - fn write_result(&mut self, ptr: Uptr, len: u32) -> Result<(), Self::Err> { + fn write_result(&mut self, ptr: GuestPtr, len: u32) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK)?; self.pay_for_read(len)?; self.pay_for_geth_bytes(len)?; // returned after call @@ -123,7 +123,7 @@ pub trait UserHost: GasMeteredMachine { /// set. The semantics, then, are equivalent to that of the EVM's [`SLOAD`] opcode. /// /// [`SLOAD`]: https://www.evm.codes/#54 - fn storage_load_bytes32(&mut self, key: Uptr, dest: Uptr) -> Result<(), Self::Err> { + fn storage_load_bytes32(&mut self, key: GuestPtr, dest: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_SLOAD_GAS)?; let key = self.read_bytes32(key)?; @@ -143,7 +143,7 @@ pub trait UserHost: GasMeteredMachine { /// may exceed this amount, but that's ok because the predominant cost is due to state bloat concerns. /// /// [`SSTORE`]: https://www.evm.codes/#55 - fn storage_store_bytes32(&mut self, key: Uptr, value: Uptr) -> Result<(), Self::Err> { + fn storage_store_bytes32(&mut self, key: GuestPtr, value: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::SSTORE_SENTRY_GAS)?; // see operations_acl_arbitrum.go @@ -171,12 +171,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CALL`]: https://www.evm.codes/#f1 fn call_contract( &mut self, - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, - value: Uptr, + value: GuestPtr, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> Result { let value = Some(value); let call = |api: &mut Self::A, contract, data: &_, gas, value: Option<_>| { @@ -201,11 +201,11 @@ pub trait UserHost: GasMeteredMachine { /// [`DELEGATE_CALL`]: https://www.evm.codes/#F4 fn delegate_call_contract( &mut self, - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> Result { let call = |api: &mut Self::A, contract, data: &_, gas, _| api.delegate_call(contract, data, gas); @@ -230,11 +230,11 @@ pub trait UserHost: GasMeteredMachine { /// [`STATIC_CALL`]: https://www.evm.codes/#FA fn static_call_contract( &mut self, - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> Result { let call = |api: &mut Self::A, contract, data: &_, gas, _| api.static_call(contract, data, gas); @@ -245,12 +245,12 @@ pub trait UserHost: GasMeteredMachine { /// Note that `value` must only be [`Some`] for normal calls. fn do_call( &mut self, - contract: Uptr, - calldata: Uptr, + contract: GuestPtr, + calldata: GuestPtr, calldata_len: u32, - value: Option, + value: Option, mut gas: u64, - return_data_len: Uptr, + return_data_len: GuestPtr, call: F, name: &str, ) -> Result @@ -307,11 +307,11 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE`]: https://www.evm.codes/#f0 fn create1( &mut self, - code: Uptr, + code: GuestPtr, code_len: u32, - endowment: Uptr, - contract: Uptr, - revert_data_len: Uptr, + endowment: GuestPtr, + contract: GuestPtr, + revert_data_len: GuestPtr, ) -> Result<(), Self::Err> { let call = |api: &mut Self::A, code, value, _, gas| api.create1(code, value, gas); self.do_create( @@ -344,12 +344,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE2`]: https://www.evm.codes/#f5 fn create2( &mut self, - code: Uptr, + code: GuestPtr, code_len: u32, - endowment: Uptr, - salt: Uptr, - contract: Uptr, - revert_data_len: Uptr, + endowment: GuestPtr, + salt: GuestPtr, + contract: GuestPtr, + revert_data_len: GuestPtr, ) -> Result<(), Self::Err> { let call = |api: &mut Self::A, code, value, salt: Option<_>, gas| { api.create2(code, value, salt.unwrap(), gas) @@ -373,12 +373,12 @@ pub trait UserHost: GasMeteredMachine { /// [`CREATE2`]: https://www.evm.codes/#f5 fn do_create( &mut self, - code: Uptr, + code: GuestPtr, code_len: u32, - endowment: u32, - salt: Option, - contract: Uptr, - revert_data_len: Uptr, + endowment: GuestPtr, + salt: Option, + contract: GuestPtr, + revert_data_len: GuestPtr, cost: u64, call: F, name: &str, @@ -440,7 +440,12 @@ pub trait UserHost: GasMeteredMachine { /// Returns the number of bytes written. /// /// [`RETURN_DATA_COPY`]: https://www.evm.codes/#3e - fn read_return_data(&mut self, dest: Uptr, offset: u32, size: u32) -> Result { + fn read_return_data( + &mut self, + dest: GuestPtr, + offset: u32, + size: u32, + ) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; // pay for only as many bytes as could possibly be written @@ -483,7 +488,7 @@ pub trait UserHost: GasMeteredMachine { /// [`LOG2`]: https://www.evm.codes/#a2 /// [`LOG3`]: https://www.evm.codes/#a3 /// [`LOG4`]: https://www.evm.codes/#a4 - fn emit_log(&mut self, data: Uptr, len: u32, topics: u32) -> Result<(), Self::Err> { + fn emit_log(&mut self, data: GuestPtr, len: u32, topics: u32) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; if topics > 4 || len < topics * 32 { Err(eyre!("bad topic data"))?; @@ -500,7 +505,7 @@ pub trait UserHost: GasMeteredMachine { /// The semantics are equivalent to that of the EVM's [`BALANCE`] opcode. /// /// [`BALANCE`]: https://www.evm.codes/#31 - fn account_balance(&mut self, address: Uptr, ptr: Uptr) -> Result<(), Self::Err> { + fn account_balance(&mut self, address: GuestPtr, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_ACCOUNT_GAS)?; let address = self.read_bytes20(address)?; @@ -519,10 +524,10 @@ pub trait UserHost: GasMeteredMachine { /// [`EXT_CODE_COPY`]: https://www.evm.codes/#3C fn account_code( &mut self, - address: Uptr, + address: GuestPtr, offset: u32, size: u32, - dest: Uptr, + dest: GuestPtr, ) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; let address = self.read_bytes20(address)?; @@ -532,7 +537,7 @@ pub trait UserHost: GasMeteredMachine { let (code, gas_cost) = self.evm_api().account_code(address, gas); let code = code.slice(); self.buy_gas(gas_cost)?; - self.pay_for_write(size as u32)?; + self.pay_for_write(size)?; let out_slice = Self::sub_slice(code, offset, size); let out_len = out_slice.len() as u32; @@ -553,7 +558,7 @@ pub trait UserHost: GasMeteredMachine { /// to that of the EVM's [`EXT_CODESIZE`]. /// /// [`EXT_CODESIZE`]: https://www.evm.codes/#3B - fn account_code_size(&mut self, address: Uptr) -> Result { + fn account_code_size(&mut self, address: GuestPtr) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; let address = self.read_bytes20(address)?; let gas = self.gas_left()?; @@ -572,7 +577,7 @@ pub trait UserHost: GasMeteredMachine { /// `keccak("") = c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`. /// /// [`EXT_CODEHASH`]: https://www.evm.codes/#3F - fn account_codehash(&mut self, address: Uptr, ptr: Uptr) -> Result<(), Self::Err> { + fn account_codehash(&mut self, address: GuestPtr, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + 2 * PTR_INK + EVM_API_INK)?; self.require_gas(evm::COLD_ACCOUNT_GAS)?; let address = self.read_bytes20(address)?; @@ -587,7 +592,7 @@ pub trait UserHost: GasMeteredMachine { /// [`BASEFEE`] opcode. /// /// [`BASEFEE`]: https://www.evm.codes/#48 - fn block_basefee(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn block_basefee(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().block_basefee)?; trace!("block_basefee", self, &[], self.evm_data().block_basefee) @@ -596,7 +601,7 @@ pub trait UserHost: GasMeteredMachine { /// Gets the coinbase of the current block, which on Arbitrum chains is the L1 batch poster's /// address. This differs from Ethereum where the validator including the transaction /// determines the coinbase. - fn block_coinbase(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn block_coinbase(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().block_coinbase)?; trace!("block_coinbase", self, &[], self.evm_data().block_coinbase) @@ -651,7 +656,7 @@ pub trait UserHost: GasMeteredMachine { /// [`ADDRESS`] opcode. /// /// [`ADDRESS`]: https://www.evm.codes/#30 - fn contract_address(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn contract_address(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().contract_address)?; trace!( @@ -701,7 +706,7 @@ pub trait UserHost: GasMeteredMachine { /// [`CALLER`]: https://www.evm.codes/#33 /// [`DELEGATE_CALL`]: https://www.evm.codes/#f4 /// [aliasing]: https://developer.arbitrum.io/arbos/l1-to-l2-messaging#address-aliasing - fn msg_sender(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn msg_sender(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().msg_sender)?; trace!("msg_sender", self, &[], self.evm_data().msg_sender) @@ -711,7 +716,7 @@ pub trait UserHost: GasMeteredMachine { /// EVM's [`CALLVALUE`] opcode. /// /// [`CALLVALUE`]: https://www.evm.codes/#34 - fn msg_value(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn msg_value(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().msg_value)?; trace!("msg_value", self, &[], self.evm_data().msg_value) @@ -722,7 +727,12 @@ pub trait UserHost: GasMeteredMachine { /// /// [`keccak256`]: https://en.wikipedia.org/wiki/SHA-3 /// [`SHA3`]: https://www.evm.codes/#20 - fn native_keccak256(&mut self, input: Uptr, len: u32, output: Uptr) -> Result<(), Self::Err> { + fn native_keccak256( + &mut self, + input: GuestPtr, + len: u32, + output: GuestPtr, + ) -> Result<(), Self::Err> { self.pay_for_keccak(len)?; let preimage = self.read_slice(input, len)?; @@ -735,7 +745,7 @@ pub trait UserHost: GasMeteredMachine { /// semantics are equivalent to that of the EVM's [`GAS_PRICE`] opcode. /// /// [`GAS_PRICE`]: https://www.evm.codes/#3A - fn tx_gas_price(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn tx_gas_price(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes32(ptr, self.evm_data().tx_gas_price)?; trace!("tx_gas_price", self, &[], self.evm_data().tx_gas_price) @@ -755,7 +765,7 @@ pub trait UserHost: GasMeteredMachine { /// EVM's [`ORIGIN`] opcode. /// /// [`ORIGIN`]: https://www.evm.codes/#32 - fn tx_origin(&mut self, ptr: Uptr) -> Result<(), Self::Err> { + fn tx_origin(&mut self, ptr: GuestPtr) -> Result<(), Self::Err> { self.buy_ink(HOSTIO_INK + PTR_INK)?; self.write_bytes20(ptr, self.evm_data().tx_origin)?; trace!("tx_origin", self, &[], self.evm_data().tx_origin) @@ -773,7 +783,7 @@ pub trait UserHost: GasMeteredMachine { } /// Prints a UTF-8 encoded string to the console. Only available in debug mode. - fn console_log_text(&mut self, ptr: Uptr, len: u32) -> Result<(), Self::Err> { + fn console_log_text(&mut self, ptr: GuestPtr, len: u32) -> Result<(), Self::Err> { let text = self.read_slice(ptr, len)?; self.say(String::from_utf8_lossy(&text)); trace!("console_log_text", self, text, &[]) diff --git a/arbitrator/wasm-libraries/user-host/Cargo.toml b/arbitrator/wasm-libraries/user-host/Cargo.toml index 229cdb500..15174397e 100644 --- a/arbitrator/wasm-libraries/user-host/Cargo.toml +++ b/arbitrator/wasm-libraries/user-host/Cargo.toml @@ -8,7 +8,7 @@ crate-type = ["cdylib"] [dependencies] arbutil = { path = "../../arbutil/" } -callerenv = { path = "../../callerenv/", features = ["static_caller"] } +caller-env = { path = "../../caller-env/", features = ["static_caller"] } prover = { path = "../../prover/", default-features = false } user-host-trait = { path = "../user-host-trait" } wasmer-types = { path = "../../tools/wasmer/lib/types" } diff --git a/arbitrator/wasm-libraries/user-host/src/host.rs b/arbitrator/wasm-libraries/user-host/src/host.rs index efee356bf..39fd89c1c 100644 --- a/arbitrator/wasm-libraries/user-host/src/host.rs +++ b/arbitrator/wasm-libraries/user-host/src/host.rs @@ -1,8 +1,9 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::program::Program; -use user_host_trait::{UserHost, Uptr}; +use caller_env::GuestPtr; +use user_host_trait::UserHost; #[link(wasm_import_module = "forward")] extern "C" { @@ -22,44 +23,44 @@ macro_rules! hostio { } #[no_mangle] -pub unsafe extern "C" fn user_host__read_args(ptr: Uptr) { +pub unsafe extern "C" fn user_host__read_args(ptr: GuestPtr) { hostio!(read_args(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__write_result(ptr: Uptr, len: u32) { +pub unsafe extern "C" fn user_host__write_result(ptr: GuestPtr, len: u32) { hostio!(write_result(ptr, len)) } #[no_mangle] -pub unsafe extern "C" fn user_host__storage_load_bytes32(key: Uptr, dest: Uptr) { +pub unsafe extern "C" fn user_host__storage_load_bytes32(key: GuestPtr, dest: GuestPtr) { hostio!(storage_load_bytes32(key, dest)) } #[no_mangle] -pub unsafe extern "C" fn user_host__storage_store_bytes32(key: Uptr, value: Uptr) { +pub unsafe extern "C" fn user_host__storage_store_bytes32(key: GuestPtr, value: GuestPtr) { hostio!(storage_store_bytes32(key, value)) } #[no_mangle] pub unsafe extern "C" fn user_host__call_contract( - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, - value: u32, + value: GuestPtr, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> u8 { hostio!(call_contract(contract, data, data_len, value, gas, ret_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__delegate_call_contract( - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> u8 { hostio!(delegate_call_contract( contract, data, data_len, gas, ret_len @@ -68,40 +69,44 @@ pub unsafe extern "C" fn user_host__delegate_call_contract( #[no_mangle] pub unsafe extern "C" fn user_host__static_call_contract( - contract: Uptr, - data: Uptr, + contract: GuestPtr, + data: GuestPtr, data_len: u32, gas: u64, - ret_len: Uptr, + ret_len: GuestPtr, ) -> u8 { hostio!(static_call_contract(contract, data, data_len, gas, ret_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__create1( - code: Uptr, + code: GuestPtr, code_len: u32, - value: u32, - contract: Uptr, - revert_len: Uptr, + value: GuestPtr, + contract: GuestPtr, + revert_len: GuestPtr, ) { hostio!(create1(code, code_len, value, contract, revert_len)) } #[no_mangle] pub unsafe extern "C" fn user_host__create2( - code: Uptr, + code: GuestPtr, code_len: u32, - value: Uptr, - salt: Uptr, - contract: Uptr, - revert_len: Uptr, + value: GuestPtr, + salt: GuestPtr, + contract: GuestPtr, + revert_len: GuestPtr, ) { hostio!(create2(code, code_len, value, salt, contract, revert_len)) } #[no_mangle] -pub unsafe extern "C" fn user_host__read_return_data(dest: Uptr, offset: u32, size: u32) -> u32 { +pub unsafe extern "C" fn user_host__read_return_data( + dest: GuestPtr, + offset: u32, + size: u32, +) -> u32 { hostio!(read_return_data(dest, offset, size)) } @@ -111,41 +116,41 @@ pub unsafe extern "C" fn user_host__return_data_size() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__emit_log(data: Uptr, len: u32, topics: u32) { +pub unsafe extern "C" fn user_host__emit_log(data: GuestPtr, len: u32, topics: u32) { hostio!(emit_log(data, len, topics)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_balance(address: u32, ptr: Uptr) { +pub unsafe extern "C" fn user_host__account_balance(address: GuestPtr, ptr: GuestPtr) { hostio!(account_balance(address, ptr)) } #[no_mangle] pub unsafe extern "C" fn user_host__account_code( - address: Uptr, + address: GuestPtr, offset: u32, size: u32, - dest: Uptr, + dest: GuestPtr, ) -> u32 { hostio!(account_code(address, offset, size, dest)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_code_size(address: Uptr) -> u32 { +pub unsafe extern "C" fn user_host__account_code_size(address: GuestPtr) -> u32 { hostio!(account_code_size(address)) } #[no_mangle] -pub unsafe extern "C" fn user_host__account_codehash(address: Uptr, ptr: Uptr) { +pub unsafe extern "C" fn user_host__account_codehash(address: GuestPtr, ptr: GuestPtr) { hostio!(account_codehash(address, ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__block_basefee(ptr: Uptr) { +pub unsafe extern "C" fn user_host__block_basefee(ptr: GuestPtr) { hostio!(block_basefee(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__block_coinbase(ptr: Uptr) { +pub unsafe extern "C" fn user_host__block_coinbase(ptr: GuestPtr) { hostio!(block_coinbase(ptr)) } @@ -170,7 +175,7 @@ pub unsafe extern "C" fn user_host__chainid() -> u64 { } #[no_mangle] -pub unsafe extern "C" fn user_host__contract_address(ptr: Uptr) { +pub unsafe extern "C" fn user_host__contract_address(ptr: GuestPtr) { hostio!(contract_address(ptr)) } @@ -190,22 +195,22 @@ pub unsafe extern "C" fn user_host__msg_reentrant() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__msg_sender(ptr: Uptr) { +pub unsafe extern "C" fn user_host__msg_sender(ptr: GuestPtr) { hostio!(msg_sender(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__msg_value(ptr: Uptr) { +pub unsafe extern "C" fn user_host__msg_value(ptr: GuestPtr) { hostio!(msg_value(ptr)) } #[no_mangle] -pub unsafe extern "C" fn user_host__native_keccak256(input: Uptr, len: u32, output: Uptr) { +pub unsafe extern "C" fn user_host__native_keccak256(input: GuestPtr, len: u32, output: GuestPtr) { hostio!(native_keccak256(input, len, output)) } #[no_mangle] -pub unsafe extern "C" fn user_host__tx_gas_price(ptr: Uptr) { +pub unsafe extern "C" fn user_host__tx_gas_price(ptr: GuestPtr) { hostio!(tx_gas_price(ptr)) } @@ -215,7 +220,7 @@ pub unsafe extern "C" fn user_host__tx_ink_price() -> u32 { } #[no_mangle] -pub unsafe extern "C" fn user_host__tx_origin(ptr: Uptr) { +pub unsafe extern "C" fn user_host__tx_origin(ptr: GuestPtr) { hostio!(tx_origin(ptr)) } diff --git a/arbitrator/wasm-libraries/user-host/src/link.rs b/arbitrator/wasm-libraries/user-host/src/link.rs index a875f871d..f2a0f624c 100644 --- a/arbitrator/wasm-libraries/user-host/src/link.rs +++ b/arbitrator/wasm-libraries/user-host/src/link.rs @@ -1,19 +1,13 @@ // Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::{ - program::Program, -}; +use crate::program::Program; use arbutil::{ evm::{user::UserOutcomeKind, EvmData}, format::DebugBytes, heapify, Bytes20, Bytes32, }; -use callerenv::{ - Uptr, - MemAccess, - static_caller::STATIC_MEM -}; +use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; use prover::{ machine::Module, programs::config::{PricingParams, StylusConfig}, @@ -47,16 +41,16 @@ struct MemoryLeaf([u8; 32]); // pages_ptr: starts pointing to max allowed pages, returns number of pages used #[no_mangle] pub unsafe extern "C" fn programs__activate( - wasm_ptr: Uptr, + wasm_ptr: GuestPtr, wasm_size: usize, - pages_ptr: Uptr, - asm_estimate_ptr: Uptr, - init_gas_ptr: Uptr, + pages_ptr: GuestPtr, + asm_estimate_ptr: GuestPtr, + init_gas_ptr: GuestPtr, version: u16, debug: u32, - module_hash_ptr: Uptr, - gas_ptr: Uptr, - err_buf: Uptr, + module_hash_ptr: GuestPtr, + gas_ptr: GuestPtr, + err_buf: GuestPtr, err_buf_len: usize, ) -> usize { let wasm = STATIC_MEM.read_slice(wasm_ptr, wasm_size); @@ -72,7 +66,7 @@ pub unsafe extern "C" fn programs__activate( STATIC_MEM.write_u32(init_gas_ptr, data.init_gas); STATIC_MEM.write_slice(module_hash_ptr, module.hash().as_slice()); 0 - }, + } Err(error) => { let mut err_bytes = error.wrap_err("failed to activate").debug_bytes(); err_bytes.truncate(err_buf_len); @@ -83,15 +77,15 @@ pub unsafe extern "C" fn programs__activate( STATIC_MEM.write_u32(init_gas_ptr, 0); STATIC_MEM.write_slice(module_hash_ptr, Bytes32::default().as_slice()); err_bytes.len() - }, + } } } -unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { +unsafe fn read_bytes32(ptr: GuestPtr) -> Bytes32 { STATIC_MEM.read_fixed(ptr).into() } -unsafe fn read_bytes20(ptr: Uptr) -> Bytes20 { +unsafe fn read_bytes20(ptr: GuestPtr) -> Bytes20 { STATIC_MEM.read_fixed(ptr).into() } @@ -101,8 +95,8 @@ unsafe fn read_bytes20(ptr: Uptr) -> Bytes20 { /// see program-exec for starting the user program #[no_mangle] pub unsafe extern "C" fn programs__new_program( - compiled_hash_ptr: Uptr, - calldata_ptr: Uptr, + compiled_hash_ptr: GuestPtr, + calldata_ptr: GuestPtr, calldata_size: usize, config_box: u64, evm_data_box: u64, @@ -131,9 +125,12 @@ pub unsafe extern "C" fn programs__new_program( // gets information about request according to id // request_id MUST be last request id returned from start_program or send_response #[no_mangle] -pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: Uptr) -> u32 { - let (req_type, len) = Program::current().evm_api.request_handler().get_request_meta(id); - if len_ptr != 0 { +pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: GuestPtr) -> u32 { + let (req_type, len) = Program::current() + .evm_api + .request_handler() + .get_request_meta(id); + if len_ptr != GuestPtr(0) { STATIC_MEM.write_u32(len_ptr, len as u32); } req_type @@ -143,8 +140,11 @@ pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: Uptr) -> u32 { // request_id MUST be last request receieved // data_ptr MUST point to a buffer of at least the length returned by get_request #[no_mangle] -pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: Uptr) { - let (_, data) = Program::current().evm_api.request_handler().take_request(id); +pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: GuestPtr) { + let (_, data) = Program::current() + .evm_api + .request_handler() + .take_request(id); STATIC_MEM.write_slice(data_ptr, &data); } @@ -155,13 +155,18 @@ pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: Uptr) { pub unsafe extern "C" fn programs__set_response( id: u32, gas: u64, - result_ptr: Uptr, + result_ptr: GuestPtr, result_len: usize, - raw_data_ptr: Uptr, + raw_data_ptr: GuestPtr, raw_data_len: usize, ) { let program = Program::current(); - program.evm_api.request_handler().set_response(id, STATIC_MEM.read_slice(result_ptr, result_len), STATIC_MEM.read_slice(raw_data_ptr, raw_data_len), gas); + program.evm_api.request_handler().set_response( + id, + STATIC_MEM.read_slice(result_ptr, result_len), + STATIC_MEM.read_slice(raw_data_ptr, raw_data_len), + gas, + ); } // removes the last created program @@ -209,7 +214,10 @@ pub unsafe extern "C" fn program_internal__set_done(mut status: u8) -> u32 { let gas_left = program.config.pricing.ink_to_gas(ink_left); let mut output = gas_left.to_be_bytes().to_vec(); output.extend(outs.iter()); - program.evm_api.request_handler().set_request(status as u32, &output) + program + .evm_api + .request_handler() + .set_request(status as u32, &output) } /// Creates a `StylusConfig` from its component parts. @@ -223,9 +231,7 @@ pub unsafe extern "C" fn programs__create_stylus_config( let config = StylusConfig { version, max_depth, - pricing: PricingParams { - ink_price, - }, + pricing: PricingParams { ink_price }, }; heapify(config) as u64 } @@ -234,17 +240,17 @@ pub unsafe extern "C" fn programs__create_stylus_config( /// #[no_mangle] pub unsafe extern "C" fn programs__create_evm_data( - block_basefee_ptr: Uptr, + block_basefee_ptr: GuestPtr, chainid: u64, - block_coinbase_ptr: Uptr, + block_coinbase_ptr: GuestPtr, block_gas_limit: u64, block_number: u64, block_timestamp: u64, - contract_address_ptr: Uptr, - msg_sender_ptr: Uptr, - msg_value_ptr: Uptr, - tx_gas_price_ptr: Uptr, - tx_origin_ptr: Uptr, + contract_address_ptr: GuestPtr, + msg_sender_ptr: GuestPtr, + msg_value_ptr: GuestPtr, + tx_gas_price_ptr: GuestPtr, + tx_origin_ptr: GuestPtr, reentrant: u32, ) -> u64 { let evm_data = EvmData { @@ -257,7 +263,7 @@ pub unsafe extern "C" fn programs__create_evm_data( contract_address: read_bytes20(contract_address_ptr), msg_sender: read_bytes20(msg_sender_ptr), msg_value: read_bytes32(msg_value_ptr), - tx_gas_price: read_bytes32(tx_gas_price_ptr), + tx_gas_price: read_bytes32(tx_gas_price_ptr), tx_origin: read_bytes20(tx_origin_ptr), reentrant, return_data_len: 0, diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 3b5fa84de..ff6584e00 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -1,16 +1,21 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use core::sync::atomic::{compiler_fence, Ordering}; + use arbutil::{ - evm::{req::{EvmApiRequestor, RequestHandler}, EvmData, api::{{VecReader, EvmApiMethod, EVM_API_METHOD_REQ_OFFSET}}}, + evm::{ + api::{EvmApiMethod, VecReader, EVM_API_METHOD_REQ_OFFSET}, + req::{EvmApiRequestor, RequestHandler}, + EvmData, + }, Color, }; -use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; -use wasmer_types::WASM_PAGE_SIZE; +use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; +use core::sync::atomic::{compiler_fence, Ordering}; use eyre::{bail, eyre, Result}; use prover::programs::prelude::*; use std::fmt::Display; use user_host_trait::UserHost; +use wasmer_types::WASM_PAGE_SIZE; // allows introspection into user modules #[link(wasm_import_module = "hostio")] @@ -41,7 +46,7 @@ static mut PROGRAMS: Vec> = vec![]; static mut LAST_REQUEST_ID: u32 = 0x10000; #[derive(Clone)] -pub (crate) struct UserHostRequester { +pub(crate) struct UserHostRequester { data: Option>, answer: Option<(Vec, VecReader, u64)>, req_type: u32, @@ -82,7 +87,13 @@ extern "C" { impl UserHostRequester { #[no_mangle] - pub unsafe fn set_response(&mut self, req_id: u32, result: Vec, raw_data:Vec, gas: u64) { + pub unsafe fn set_response( + &mut self, + req_id: u32, + result: Vec, + raw_data: Vec, + gas: u64, + ) { self.answer = Some((result, VecReader::new(raw_data), gas)); if req_id != self.id { panic!("bad req id returning from send_request") @@ -103,14 +114,23 @@ impl UserHostRequester { if self.id != id { panic!("get_request got wrong id"); } - (self.req_type, self.data.as_ref().expect("no request on get_request_meta").len()) + ( + self.req_type, + self.data + .as_ref() + .expect("no request on get_request_meta") + .len(), + ) } pub unsafe fn take_request(&mut self, id: u32) -> (u32, Vec) { if self.id != id { panic!("get_request got wrong id"); } - (self.req_type, self.data.take().expect("no request on take_request")) + ( + self.req_type, + self.data.take().expect("no request on take_request"), + ) } #[no_mangle] @@ -127,21 +147,23 @@ impl UserHostRequester { } impl RequestHandler for UserHostRequester { - fn handle_request(&mut self, req_type: EvmApiMethod, req_data: &[u8]) -> (Vec, VecReader, u64) { + fn handle_request( + &mut self, + req_type: EvmApiMethod, + req_data: &[u8], + ) -> (Vec, VecReader, u64) { unsafe { - self.send_request(req_type as u32 + EVM_API_METHOD_REQ_OFFSET, req_data.to_vec()) + self.send_request( + req_type as u32 + EVM_API_METHOD_REQ_OFFSET, + req_data.to_vec(), + ) } } } impl Program { /// Adds a new program, making it current. - pub fn push_new( - args: Vec, - evm_data: EvmData, - module: u32, - config: StylusConfig, - ) { + pub fn push_new(args: Vec, evm_data: EvmData, module: u32, config: StylusConfig) { let program = Self { args, outs: vec![], @@ -155,7 +177,9 @@ impl Program { /// Removes the current program pub fn pop() { - unsafe { PROGRAMS.pop().expect("no program"); } + unsafe { + PROGRAMS.pop().expect("no program"); + } } /// Provides a reference to the current program. @@ -170,12 +194,12 @@ impl Program { /// Reads the program's memory size in pages pub fn args_len(&self) -> usize { - return self.args.len() + self.args.len() } /// Ensures an access is within bounds - fn check_memory_access(&self, ptr: Uptr, bytes: u32) -> Result<(), MemoryBoundsError> { - let last_page = ptr.saturating_add(bytes) / (WASM_PAGE_SIZE as Uptr); + fn check_memory_access(&self, ptr: GuestPtr, bytes: u32) -> Result<(), MemoryBoundsError> { + let last_page = ptr.saturating_add(bytes) / (WASM_PAGE_SIZE as u32); if last_page > self.memory_size() { return Err(MemoryBoundsError); } @@ -209,21 +233,22 @@ impl UserHost for Program { &mut self.evm_data.return_data_len } - fn read_slice(&self, ptr: Uptr, len: u32) -> Result, MemoryBoundsError> { + fn read_slice(&self, ptr: GuestPtr, len: u32) -> Result, MemoryBoundsError> { self.check_memory_access(ptr, len)?; unsafe { Ok(STATIC_MEM.read_slice(ptr, len as usize)) } } - fn read_fixed(&self, ptr: Uptr) -> Result<[u8; N], MemoryBoundsError> { - self.read_slice(ptr, N as u32).and_then(|x| Ok(x.try_into().unwrap())) + fn read_fixed(&self, ptr: GuestPtr) -> Result<[u8; N], MemoryBoundsError> { + self.read_slice(ptr, N as u32) + .map(|x| x.try_into().unwrap()) } - fn write_u32(&mut self, ptr: Uptr, x: u32) -> Result<(), MemoryBoundsError> { + fn write_u32(&mut self, ptr: GuestPtr, x: u32) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, 4)?; unsafe { Ok(STATIC_MEM.write_u32(ptr, x)) } } - fn write_slice(&self, ptr: Uptr, src: &[u8]) -> Result<(), MemoryBoundsError> { + fn write_slice(&self, ptr: GuestPtr, src: &[u8]) -> Result<(), MemoryBoundsError> { self.check_memory_access(ptr, src.len() as u32)?; unsafe { Ok(STATIC_MEM.write_slice(ptr, src)) } } @@ -238,7 +263,7 @@ impl UserHost for Program { println!("Error: unexpected hostio tracing info for {name} while proving: {args}, {outs}"); } - fn start_ink(&self) -> Result { + fn start_ink(&self) -> Result { bail!("recording start ink while proving") } } diff --git a/arbitrator/wasm-libraries/user-test/Cargo.toml b/arbitrator/wasm-libraries/user-test/Cargo.toml index b86deb5a1..ee4577d4b 100644 --- a/arbitrator/wasm-libraries/user-test/Cargo.toml +++ b/arbitrator/wasm-libraries/user-test/Cargo.toml @@ -8,7 +8,7 @@ crate-type = ["cdylib"] [dependencies] arbutil = { path = "../../arbutil/" } -callerenv = { path = "../../callerenv/", features = ["static_caller"] } +caller-env = { path = "../../caller-env/", features = ["static_caller"] } prover = { path = "../../prover/", default-features = false } eyre = "0.6.5" fnv = "1.0.7" diff --git a/arbitrator/wasm-libraries/user-test/src/host.rs b/arbitrator/wasm-libraries/user-test/src/host.rs index 3e7f40c68..9b8c99857 100644 --- a/arbitrator/wasm-libraries/user-test/src/host.rs +++ b/arbitrator/wasm-libraries/user-test/src/host.rs @@ -7,27 +7,27 @@ use crate::{Program, ARGS, EVER_PAGES, KEYS, LOGS, OPEN_PAGES, OUTS}; use arbutil::{ crypto, evm, pricing::{EVM_API_INK, HOSTIO_INK, PTR_INK}, - Bytes20, Bytes32 + Bytes32, }; +use caller_env::{static_caller::STATIC_MEM, MemAccess, GuestPtr}; use prover::programs::{ memory::MemoryModel, prelude::{GasMeteredMachine, MeteredMachine}, }; -use callerenv::{Uptr, MemAccess, static_caller::STATIC_MEM}; -unsafe fn read_bytes32(ptr: Uptr) -> Bytes32 { +unsafe fn read_bytes32(ptr: GuestPtr) -> Bytes32 { STATIC_MEM.read_fixed(ptr).into() } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__read_args(ptr: Uptr) { +pub unsafe extern "C" fn vm_hooks__read_args(ptr: GuestPtr) { let mut program = Program::start(0); program.pay_for_write(ARGS.len() as u32).unwrap(); STATIC_MEM.write_slice(ptr, &ARGS); } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__write_result(ptr: Uptr, len: u32) { +pub unsafe extern "C" fn vm_hooks__write_result(ptr: GuestPtr, len: u32) { let mut program = Program::start(0); program.pay_for_read(len).unwrap(); program.pay_for_geth_bytes(len).unwrap(); @@ -35,7 +35,7 @@ pub unsafe extern "C" fn vm_hooks__write_result(ptr: Uptr, len: u32) { } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: Uptr, dest: Uptr) { +pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: GuestPtr, dest: GuestPtr) { let mut program = Program::start(2 * PTR_INK + EVM_API_INK); let key = read_bytes32(key); @@ -45,7 +45,7 @@ pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: Uptr, dest: Uptr) { } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: Uptr, value: Uptr) { +pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: GuestPtr, value: GuestPtr) { let mut program = Program::start(2 * PTR_INK + EVM_API_INK); program.require_gas(evm::SSTORE_SENTRY_GAS).unwrap(); program.buy_gas(22100).unwrap(); // pretend the worst case @@ -56,12 +56,12 @@ pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: Uptr, value: Uptr) } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__emit_log(data: Uptr, len: u32, topics: u32) { +pub unsafe extern "C" fn vm_hooks__emit_log(data: GuestPtr, len: u32, topics: u32) { let mut program = Program::start(EVM_API_INK); if topics > 4 || len < topics * 32 { panic!("bad topic data"); } - program.pay_for_read(len.into()).unwrap(); + program.pay_for_read(len).unwrap(); program.pay_for_evm_log(topics, len - topics * 32).unwrap(); let data = STATIC_MEM.read_slice(data, len as usize); @@ -83,7 +83,7 @@ pub unsafe extern "C" fn vm_hooks__pay_for_memory_grow(pages: u16) { } #[no_mangle] -pub unsafe extern "C" fn vm_hooks__native_keccak256(bytes: u32, len: u32, output: u32) { +pub unsafe extern "C" fn vm_hooks__native_keccak256(bytes: GuestPtr, len: u32, output: GuestPtr) { let mut program = Program::start(0); program.pay_for_keccak(len).unwrap(); diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index efff70277..beaba4301 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -paste = {version="1.0.14"} -callerenv = { path = "../../callerenv/", features = ["static_caller"] } +paste = { version = "1.0.14" } +caller-env = { path = "../../caller-env/", features = ["static_caller"] } +#mini-alloc = "0.4.2" wee_alloc = "0.4.5" - diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 6b9bde8c0..5699fc878 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -1,16 +1,13 @@ -// Copyright 2021-2023, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE +#![allow(clippy::missing_safety_doc)] // TODO: require safety docs #![no_std] +use caller_env::{self, wasip1_stub::Errno, GuestPtr}; +//use mini_alloc::MiniAlloc; use paste::paste; -use callerenv::{ - self, - Uptr, - wasip1_stub::{Errno}, -}; -#[allow(dead_code)] extern "C" { fn wavm_halt_and_set_finished() -> !; } @@ -20,6 +17,9 @@ unsafe fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() } +/*#[global_allocator] +static ALLOC: MiniAlloc = MiniAlloc::INIT;*/ + #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; @@ -33,152 +33,156 @@ pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { } macro_rules! wrap { - ($func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty) => { + ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { paste! { - #[no_mangle] - pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { - callerenv::wasip1_stub::$func_name( - &mut callerenv::static_caller::STATIC_MEM, - &mut callerenv::static_caller::STATIC_ENV, - $($arg_name),*) - } + $( + #[no_mangle] + pub unsafe extern "C" fn []($($arg_name : $arg_type),*) -> $return_type { + caller_env::wasip1_stub::$func_name( + &mut caller_env::static_caller::STATIC_MEM, + &mut caller_env::static_caller::STATIC_ENV, + $($arg_name),* + ) + } + )* } }; } -wrap!(clock_time_get( - clock_id: u32, - precision: u64, - time_ptr: Uptr -) -> Errno); - -wrap!(random_get(buf: Uptr, len: u32) -> Errno); - -wrap!(environ_sizes_get(length_ptr: Uptr, data_size_ptr: Uptr) -> Errno); -wrap!(fd_write( - fd: u32, - iovecs_ptr: Uptr, - iovecs_len: u32, - ret_ptr: Uptr -) -> Errno); -wrap!(environ_get(a: u32, b: u32) -> Errno); -wrap!(fd_close(fd: u32) -> Errno); -wrap!(fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno); -wrap!(fd_readdir( - fd: u32, - a: u32, - b: u32, - c: u64, - d: u32 -) -> Errno); - -wrap!(fd_sync(a: u32) -> Errno); - -wrap!(fd_seek( - _fd: u32, - _offset: u64, - _whence: u8, - _filesize: u32 -) -> Errno); - -wrap!(fd_datasync(_fd: u32) -> Errno); - -wrap!(path_open( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u64, - g: u64, - h: u32, - i: u32 -) -> Errno); - -wrap!(path_create_directory( - a: u32, - b: u32, - c: u32 -) -> Errno); - -wrap!(path_remove_directory( - a: u32, - b: u32, - c: u32 -) -> Errno); - -wrap!(path_readlink( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u32 -) -> Errno); - -wrap!(path_rename( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32, - f: u32 -) -> Errno); - -wrap!(path_filestat_get( - a: u32, - b: u32, - c: u32, - d: u32, - e: u32 -) -> Errno); - -wrap!(path_unlink_file(a: u32, b: u32, c: u32) -> Errno); - -wrap!(fd_prestat_get(a: u32, b: u32) -> Errno); - -wrap!(fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno); - -wrap!(fd_filestat_get(_fd: u32, _filestat: u32) -> Errno); - -wrap!(fd_filestat_set_size(_fd: u32, size: u64) -> Errno); - -wrap!(fd_pread( - _fd: u32, - _a: u32, - _b: u32, - _c: u64, - _d: u32 -) -> Errno); - -wrap!(fd_pwrite( - _fd: u32, - _a: u32, - _b: u32, - _c: u64, - _d: u32 -) -> Errno); - -wrap!(sock_accept(_fd: u32, a: u32, b: u32) -> Errno); - -wrap!(sock_shutdown(a: u32, b: u32) -> Errno); - -wrap!(sched_yield() -> Errno); - -wrap!(args_sizes_get( - length_ptr: Uptr, - data_size_ptr: Uptr -) -> Errno); - -wrap!(args_get(argv_buf: Uptr, data_buf: Uptr) -> Errno); - -wrap!(poll_oneoff( - in_subs: Uptr, - out_evt: Uptr, - nsubscriptions: u32, - nevents_ptr: Uptr -) -> Errno); - -wrap!(fd_fdstat_get(a: u32, b: u32) -> Errno); - -wrap!(fd_fdstat_set_flags(a: u32, b: u32) -> Errno); +wrap! { + fn clock_time_get( + clock_id: u32, + precision: u64, + time_ptr: GuestPtr + ) -> Errno; + + fn random_get(buf: GuestPtr, len: u32) -> Errno; + + fn environ_sizes_get(length_ptr: GuestPtr, data_size_ptr: GuestPtr) -> Errno; + + fn fd_write( + fd: u32, + iovecs_ptr: GuestPtr, + iovecs_len: u32, + ret_ptr: GuestPtr + ) -> Errno; + + fn environ_get(a: GuestPtr, b: GuestPtr) -> Errno; + + fn fd_close(fd: u32) -> Errno; + fn fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno; + fn fd_readdir( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn fd_sync(a: u32) -> Errno; + + fn fd_seek( + fd: u32, + offset: u64, + whence: u8, + filesize: u32 + ) -> Errno; + + fn fd_datasync(fd: u32) -> Errno; + + fn path_open( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u64, + g: u64, + h: u32, + i: u32 + ) -> Errno; + + fn path_create_directory( + a: u32, + b: u32, + c: u32 + ) -> Errno; + + fn path_remove_directory( + a: u32, + b: u32, + c: u32 + ) -> Errno; + + fn path_readlink( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 + ) -> Errno; + + fn path_rename( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32, + f: u32 + ) -> Errno; + + fn path_filestat_get( + a: u32, + b: u32, + c: u32, + d: u32, + e: u32 + ) -> Errno; + + fn path_unlink_file(a: u32, b: u32, c: u32) -> Errno; + + fn fd_prestat_get(a: u32, b: u32) -> Errno; + fn fd_prestat_dir_name(a: u32, b: u32, c: u32) -> Errno; + + fn fd_filestat_get(fd: u32, filestat: u32) -> Errno; + fn fd_filestat_set_size(fd: u32, size: u64) -> Errno; + + fn fd_pread( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn fd_pwrite( + fd: u32, + a: u32, + b: u32, + c: u64, + d: u32 + ) -> Errno; + + fn sock_accept(fd: u32, a: u32, b: u32) -> Errno; + fn sock_shutdown(a: u32, b: u32) -> Errno; + + fn sched_yield() -> Errno; + + fn args_sizes_get( + length_ptr: GuestPtr, + data_size_ptr: GuestPtr + ) -> Errno; + + fn args_get(argv_buf: GuestPtr, data_buf: GuestPtr) -> Errno; + + fn fd_fdstat_get(a: u32, b: u32) -> Errno; + fn fd_fdstat_set_flags(a: u32, b: u32) -> Errno; + + fn poll_oneoff( + in_subs: GuestPtr, + out_evt: GuestPtr, + nsubscriptions: u32, + nevents_ptr: GuestPtr + ) -> Errno +} diff --git a/arbutil/correspondingl1blocknumber.go b/arbutil/correspondingl1blocknumber.go index 5127684be..05323ed18 100644 --- a/arbutil/correspondingl1blocknumber.go +++ b/arbutil/correspondingl1blocknumber.go @@ -1,9 +1,6 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -//go:build !wasm -// +build !wasm - package arbutil import ( diff --git a/arbutil/format.go b/arbutil/format.go index 9cb79aeac..041866e4c 100644 --- a/arbutil/format.go +++ b/arbutil/format.go @@ -1,3 +1,6 @@ +// Copyright 2023-2024, Offchain Labs, Inc. +// For license information, see https://github.com/nitro/blob/master/LICENSE + package arbutil import ( diff --git a/arbutil/wait_for_l1.go b/arbutil/wait_for_l1.go index c2a5e38bb..ce82501e8 100644 --- a/arbutil/wait_for_l1.go +++ b/arbutil/wait_for_l1.go @@ -1,9 +1,6 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -//go:build !wasm -// +build !wasm - package arbutil import ( From 7d60088cb9f82edf0b41b4dd57a28511790399cc Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Thu, 7 Mar 2024 18:29:25 -0700 Subject: [PATCH 13/28] fix set_len order --- arbitrator/jit/src/caller_env.rs | 2 +- arbitrator/stylus/src/host.rs | 37 ++------------------------------ 2 files changed, 3 insertions(+), 36 deletions(-) diff --git a/arbitrator/jit/src/caller_env.rs b/arbitrator/jit/src/caller_env.rs index 93cf6bad9..1737ad2ea 100644 --- a/arbitrator/jit/src/caller_env.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -112,8 +112,8 @@ impl MemAccess for JitMemAccess<'_> { fn read_slice(&self, ptr: GuestPtr, len: usize) -> Vec { let mut data = Vec::with_capacity(len); unsafe { - self.view().read(ptr.into(), &mut data).expect("bad read"); data.set_len(len); + self.view().read(ptr.into(), &mut data).expect("bad read"); } data } diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index d362ca80c..bd905a61d 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -14,42 +14,9 @@ use arbutil::{ use caller_env::GuestPtr; use eyre::{eyre, Result}; use prover::value::Value; -use std::{ - fmt::Display, - ops::{Deref, DerefMut}, -}; +use std::fmt::Display; use user_host_trait::UserHost; -use wasmer::{FromToNativeWasmType, MemoryAccessError, WasmPtr}; - -#[derive(Clone, Copy)] -#[repr(transparent)] -pub(crate) struct ClientPtr(pub GuestPtr); - -unsafe impl FromToNativeWasmType for ClientPtr { - type Native = i32; - - fn from_native(native: i32) -> Self { - Self(GuestPtr(u32::from_native(native))) - } - - fn to_native(self) -> Self::Native { - self.0 .0.to_native() - } -} - -impl Deref for ClientPtr { - type Target = GuestPtr; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for ClientPtr { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +use wasmer::{MemoryAccessError, WasmPtr}; impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { type Err = Escape; From d76b35581457b5e45d998c57a5014127cf257bae Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 02:35:33 -0700 Subject: [PATCH 14/28] fixed, simplifications, and MiniAlloc --- Makefile | 2 +- arbcompress/compress_wasm.go | 13 +++- arbitrator/arbutil/src/evm/api.rs | 10 +-- arbitrator/arbutil/src/evm/req.rs | 2 +- arbitrator/arbutil/src/lib.rs | 25 ++++--- arbitrator/jit/src/program.rs | 17 +++-- arbitrator/jit/src/stylus_backend.rs | 2 +- arbitrator/prover/src/wavm.rs | 2 +- arbitrator/prover/test-cases/go/main.go | 2 +- arbitrator/stylus/cbindgen.toml | 2 +- arbitrator/stylus/src/evm_api.rs | 16 ++--- arbitrator/stylus/src/host.rs | 12 +--- arbitrator/stylus/src/lib.rs | 68 ++++--------------- arbitrator/wasm-libraries/Cargo.lock | 19 +++--- .../wasm-libraries/program-exec/Cargo.toml | 5 -- .../wasm-libraries/program-exec/src/lib.rs | 2 +- .../wasm-libraries/user-host-trait/src/lib.rs | 33 +++------ .../wasm-libraries/user-host/src/program.rs | 10 +-- .../user-test/src/caller_env.rs | 21 ++++++ .../wasm-libraries/user-test/src/host.rs | 29 ++++---- .../wasm-libraries/user-test/src/lib.rs | 3 +- .../wasm-libraries/wasi-stub/Cargo.toml | 3 +- .../wasm-libraries/wasi-stub/src/lib.rs | 7 +- arbos/programs/constant_test.go | 3 + arbos/programs/native.go | 43 ++---------- arbos/programs/native_api.go | 30 +++++--- arbos/programs/testconstants.go | 19 ++++-- arbos/programs/wasm_api.go | 5 +- arbutil/transaction_data.go | 3 - arbutil/unsafe.go | 2 +- wavmio/higher.go | 2 +- wavmio/raw.go | 2 +- 32 files changed, 180 insertions(+), 234 deletions(-) create mode 100644 arbitrator/wasm-libraries/user-test/src/caller_env.rs diff --git a/Makefile b/Makefile index 6649f1e54..f99318399 100644 --- a/Makefile +++ b/Makefile @@ -341,7 +341,7 @@ $(output_latest)/user_host.wasm: $(DEP_PREDICATE) $(wasm_lib_user_host) $(rust_p cargo build --manifest-path arbitrator/wasm-libraries/Cargo.toml --release --target wasm32-wasi --package user-host install arbitrator/wasm-libraries/$(wasm32_wasi)/user_host.wasm $@ -$(output_latest)/program_exec.wasm: $(DEP_PREDICATE) $(call wasm_lib_deps,user-host) $(rust_prover_files) .make/machines +$(output_latest)/program_exec.wasm: $(DEP_PREDICATE) $(call wasm_lib_deps,program-exec) $(rust_prover_files) .make/machines cargo build --manifest-path arbitrator/wasm-libraries/Cargo.toml --release --target wasm32-wasi --package program-exec install arbitrator/wasm-libraries/$(wasm32_wasi)/program_exec.wasm $@ diff --git a/arbcompress/compress_wasm.go b/arbcompress/compress_wasm.go index c99c3ebb2..250b46705 100644 --- a/arbcompress/compress_wasm.go +++ b/arbcompress/compress_wasm.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE //go:build wasm @@ -22,7 +22,9 @@ func brotliDecompress(inBuf unsafe.Pointer, inBufLen uint32, outBuf unsafe.Point func Decompress(input []byte, maxSize int) ([]byte, error) { outBuf := make([]byte, maxSize) outLen := uint32(len(outBuf)) - status := brotliDecompress(arbutil.SliceToUnsafePointer(input), uint32(len(input)), arbutil.SliceToUnsafePointer(outBuf), unsafe.Pointer(&outLen)) + status := brotliDecompress( + arbutil.SliceToUnsafePointer(input), uint32(len(input)), arbutil.SliceToUnsafePointer(outBuf), unsafe.Pointer(&outLen), + ) if status != BrotliSuccess { return nil, fmt.Errorf("failed decompression") } @@ -33,7 +35,12 @@ func compressLevel(input []byte, level uint32) ([]byte, error) { maxOutSize := compressedBufferSizeFor(len(input)) outBuf := make([]byte, maxOutSize) outLen := uint32(len(outBuf)) - status := brotliCompress(arbutil.SliceToUnsafePointer(input), uint32(len(input)), arbutil.SliceToUnsafePointer(outBuf), unsafe.Pointer(&outLen), level, WINDOW_SIZE) + status := brotliCompress( + arbutil.SliceToUnsafePointer(input), uint32(len(input)), + arbutil.SliceToUnsafePointer(outBuf), unsafe.Pointer(&outLen), + level, + WINDOW_SIZE, + ) if status != BrotliSuccess { return nil, fmt.Errorf("failed compression") } diff --git a/arbitrator/arbutil/src/evm/api.rs b/arbitrator/arbutil/src/evm/api.rs index 26fc149a9..d4196b684 100644 --- a/arbitrator/arbutil/src/evm/api.rs +++ b/arbitrator/arbutil/src/evm/api.rs @@ -48,17 +48,17 @@ pub enum EvmApiMethod { CaptureHostIO, } -// This offset is added to EvmApiMethod when sending a request -// in WASM - program done is also indicated by a "request", with the -// id below that offset, indicating program status +/// This offset is added to EvmApiMethod when sending a request +/// in WASM - program done is also indicated by a "request", with the +/// id below that offset, indicating program status pub const EVM_API_METHOD_REQ_OFFSET: u32 = 0x10000000; -// note: clone should not clone actual data, just the reader +/// note: clone should not clone actual data, just the reader pub trait DataReader: Clone + Send + 'static { fn slice(&self) -> &[u8]; } -// simple implementation for DataReader, in case data comes from a Vec +/// simple implementation for DataReader, in case data comes from a Vec #[derive(Clone, Debug)] pub struct VecReader(Arc>); diff --git a/arbitrator/arbutil/src/evm/req.rs b/arbitrator/arbutil/src/evm/req.rs index 670309ae4..e3efc40d2 100644 --- a/arbitrator/arbutil/src/evm/req.rs +++ b/arbitrator/arbutil/src/evm/req.rs @@ -11,7 +11,7 @@ use crate::{ use eyre::{bail, eyre, Result}; pub trait RequestHandler: Send + 'static { - fn handle_request(&mut self, _req_type: EvmApiMethod, _req_data: &[u8]) -> (Vec, D, u64); + fn handle_request(&mut self, req_type: EvmApiMethod, req_data: &[u8]) -> (Vec, D, u64); } pub struct EvmApiRequestor> { diff --git a/arbitrator/arbutil/src/lib.rs b/arbitrator/arbutil/src/lib.rs index 99d2173c8..5315a7e1a 100644 --- a/arbitrator/arbutil/src/lib.rs +++ b/arbitrator/arbutil/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE /// cbindgen:ignore @@ -12,6 +12,7 @@ pub mod pricing; pub mod types; pub use color::{Color, DebugColor}; +use num_traits::Unsigned; pub use types::{Bytes20, Bytes32}; /// Puts an arbitrary type on the heap. @@ -21,7 +22,13 @@ pub fn heapify(value: T) -> *mut T { } /// Equivalent to &[start..offset], but truncates when out of bounds rather than panicking. -pub fn slice_with_runoff(data: &impl AsRef<[T]>, start: usize, end: usize) -> &[T] { +pub fn slice_with_runoff(data: &impl AsRef<[T]>, start: I, end: I) -> &[T] +where + I: TryInto + Unsigned, +{ + let start = start.try_into().unwrap_or(usize::MAX); + let end = end.try_into().unwrap_or(usize::MAX); + let data = data.as_ref(); if start >= data.len() || end < start { return &[]; @@ -32,12 +39,12 @@ pub fn slice_with_runoff(data: &impl AsRef<[T]>, start: usize, end: usize) -> #[test] fn test_limit_vec() { let testvec = vec![0, 1, 2, 3]; - assert_eq!(slice_with_runoff(&testvec, 4, 4), &testvec[0..0]); - assert_eq!(slice_with_runoff(&testvec, 1, 0), &testvec[0..0]); - assert_eq!(slice_with_runoff(&testvec, 0, 0), &testvec[0..0]); - assert_eq!(slice_with_runoff(&testvec, 0, 1), &testvec[0..1]); - assert_eq!(slice_with_runoff(&testvec, 1, 3), &testvec[1..3]); - assert_eq!(slice_with_runoff(&testvec, 0, 4), &testvec[0..4]); - assert_eq!(slice_with_runoff(&testvec, 0, 5), &testvec[0..4]); + assert_eq!(slice_with_runoff(&testvec, 4_u32, 4), &testvec[0..0]); + assert_eq!(slice_with_runoff(&testvec, 1_u16, 0), &testvec[0..0]); + assert_eq!(slice_with_runoff(&testvec, 0_u64, 0), &testvec[0..0]); + assert_eq!(slice_with_runoff(&testvec, 0_u32, 1), &testvec[0..1]); + assert_eq!(slice_with_runoff(&testvec, 1_u64, 3), &testvec[1..3]); + assert_eq!(slice_with_runoff(&testvec, 0_u16, 4), &testvec[0..4]); + assert_eq!(slice_with_runoff(&testvec, 0_u8, 5), &testvec[0..4]); assert_eq!(slice_with_runoff(&testvec, 2, usize::MAX), &testvec[2..4]); } diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index c0808bb67..65dcb92eb 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -121,8 +121,8 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { Ok(msg.1) } -// gets information about request according to id -// request_id MUST be last request id returned from start_program or send_response +/// gets information about request according to id +/// request_id MUST be last request id returned from start_program or send_response pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: GuestPtr) -> Result { let (mut mem, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); @@ -148,8 +148,8 @@ pub fn get_request_data(mut env: WasmEnvMut, id: u32, data_ptr: GuestPtr) -> May Ok(()) } -// sets response for the next request made -// id MUST be the id of last request made +/// sets response for the next request made +/// id MUST be the id of last request made pub fn set_response( mut env: WasmEnvMut, id: u32, @@ -167,9 +167,9 @@ pub fn set_response( thread.set_response(id, result, raw_data, gas) } -// sends previos response -// MUST be called right after set_response to the same id -// returns request_id for the next request +/// sends previos response +/// MUST be called right after set_response to the same id +/// returns request_id for the next request pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { let (_, exec) = jit_env(&mut env); let thread = exec.wenv.threads.last_mut().unwrap(); @@ -182,7 +182,7 @@ pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { Ok(msg.1) } -// removes the last created program +/// removes the last created program pub fn pop(mut env: WasmEnvMut) -> MaybeEscape { let (_, exec) = jit_env(&mut env); @@ -216,7 +216,6 @@ pub fn create_stylus_config( } /// Creates an `EvmData` handler from its component parts. -/// pub fn create_evm_data( mut env: WasmEnvMut, block_basefee_ptr: GuestPtr, diff --git a/arbitrator/jit/src/stylus_backend.rs b/arbitrator/jit/src/stylus_backend.rs index 6b0495a0c..6144fb834 100644 --- a/arbitrator/jit/src/stylus_backend.rs +++ b/arbitrator/jit/src/stylus_backend.rs @@ -1,4 +1,4 @@ -// Copyright 2023, Offchain Labs, Inc. +// Copyright 2023-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE #![allow(clippy::too_many_arguments)] diff --git a/arbitrator/prover/src/wavm.rs b/arbitrator/prover/src/wavm.rs index 6f6b8137b..2507ff403 100644 --- a/arbitrator/prover/src/wavm.rs +++ b/arbitrator/prover/src/wavm.rs @@ -171,7 +171,7 @@ pub enum Opcode { NewCoThread, /// pop cothread (cannot be called from cothread) PopCoThread, - /// switch to/from create cothread + /// switch between main and a cothread SwitchThread, } diff --git a/arbitrator/prover/test-cases/go/main.go b/arbitrator/prover/test-cases/go/main.go index d886bd591..ebfe1496c 100644 --- a/arbitrator/prover/test-cases/go/main.go +++ b/arbitrator/prover/test-cases/go/main.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE package main diff --git a/arbitrator/stylus/cbindgen.toml b/arbitrator/stylus/cbindgen.toml index 62a040040..b9afbe840 100644 --- a/arbitrator/stylus/cbindgen.toml +++ b/arbitrator/stylus/cbindgen.toml @@ -10,4 +10,4 @@ extra_bindings = ["arbutil", "prover"] prefix_with_name = true [export] -include = ["EvmApiMethod", "EvmApiMethodOffset"] \ No newline at end of file +include = ["EvmApiMethod"] diff --git a/arbitrator/stylus/src/evm_api.rs b/arbitrator/stylus/src/evm_api.rs index d31fefac2..752410d32 100644 --- a/arbitrator/stylus/src/evm_api.rs +++ b/arbitrator/stylus/src/evm_api.rs @@ -1,7 +1,7 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use crate::{GoSliceData, RustSlice, SendGoSliceData}; +use crate::{GoSliceData, RustSlice}; use arbutil::evm::{ api::{EvmApiMethod, EvmApiStatus, EVM_API_METHOD_REQ_OFFSET}, req::RequestHandler, @@ -15,8 +15,8 @@ pub struct NativeRequestHandler { data: *mut RustSlice, gas_cost: *mut u64, result: *mut GoSliceData, - raw_data: *mut SendGoSliceData, - ) -> EvmApiStatus, // value + raw_data: *mut GoSliceData, + ) -> EvmApiStatus, pub id: usize, } @@ -26,14 +26,14 @@ macro_rules! ptr { }; } -impl RequestHandler for NativeRequestHandler { +impl RequestHandler for NativeRequestHandler { fn handle_request( &mut self, req_type: EvmApiMethod, req_data: &[u8], - ) -> (Vec, SendGoSliceData, u64) { - let mut result = GoSliceData::default(); - let mut raw_data = SendGoSliceData::default(); + ) -> (Vec, GoSliceData, u64) { + let mut result = GoSliceData::null(); + let mut raw_data = GoSliceData::null(); let mut cost = 0; let status = unsafe { (self.handle_request_fptr)( diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index bd905a61d..918bf1f02 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -12,7 +12,7 @@ use arbutil::{ Color, }; use caller_env::GuestPtr; -use eyre::{eyre, Result}; +use eyre::Result; use prover::value::Value; use std::fmt::Display; use user_host_trait::UserHost; @@ -70,17 +70,11 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { println!("{} {text}", "Stylus says:".yellow()); } - fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], start_ink: u64, end_ink: u64) { + fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], end_ink: u64) { + let start_ink = self.start_ink; self.evm_api .capture_hostio(name, args, outs, start_ink, end_ink); } - - fn start_ink(&self) -> Result { - if !self.env.evm_data.tracing { - return Err(eyre!("recording start ink when not captured").into()); - } - Ok(self.start_ink) - } } macro_rules! hostio { diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index b7a44a4f4..3a84f3f2d 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -1,5 +1,6 @@ // Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + use arbutil::{ evm::{ api::DataReader, @@ -15,7 +16,7 @@ use eyre::ErrReport; use native::NativeInstance; use prover::programs::{prelude::*, StylusData}; use run::RunProgram; -use std::{marker::PhantomData, mem, ptr::null}; +use std::{marker::PhantomData, mem, ptr}; pub use prover; @@ -34,20 +35,23 @@ mod benchmarks; #[derive(Clone, Copy)] #[repr(C)] pub struct GoSliceData { - ptr: *const u8, // stored as pointer for GO + /// Points to data owned by Go. + ptr: *const u8, + /// The length in bytes. len: usize, } -impl Default for GoSliceData { - fn default() -> Self { - GoSliceData { - ptr: null(), +/// The data we're pointing to is owned by Go and has a lifetime no shorter than the current program. +unsafe impl Send for GoSliceData {} + +impl GoSliceData { + pub fn null() -> Self { + Self { + ptr: ptr::null(), len: 0, } } -} -impl GoSliceData { fn slice(&self) -> &[u8] { if self.len == 0 { return &[]; @@ -56,32 +60,12 @@ impl GoSliceData { } } -// same as above, with Send semantics using dirty trickery -// GO will always use GoSliceData so these types must have -// exact same representation, see assert_go_slices_match -#[derive(Clone, Copy, Default)] -#[repr(C)] -pub struct SendGoSliceData { - ptr: usize, // not stored as pointer because rust won't let that be Send - len: usize, -} - -#[allow(dead_code)] -const fn assert_go_slices_match() { - // TODO: this will be stabilized on rust 1.77 - // assert_eq!(mem::offset_of!(GoSliceData, ptr), mem::offset_of!(SendGoSliceData, ptr)); - // assert_eq!(mem::offset_of!(GoSliceData, len), mem::offset_of!(SendGoSliceData, len)); - assert!(mem::size_of::() == mem::size_of::()); -} - -const _: () = assert_go_slices_match(); - -impl DataReader for SendGoSliceData { +impl DataReader for GoSliceData { fn slice(&self) -> &[u8] { if self.len == 0 { return &[]; } - unsafe { std::slice::from_raw_parts(self.ptr as *const u8, self.len) } + unsafe { std::slice::from_raw_parts(self.ptr, self.len) } } } @@ -110,16 +94,6 @@ pub struct RustBytes { } impl RustBytes { - fn new(vec: Vec) -> Self { - let mut rust_vec = Self { - ptr: std::ptr::null_mut(), - len: 0, - cap: 0, - }; - unsafe { rust_vec.write(vec) }; - rust_vec - } - unsafe fn into_vec(self) -> Vec { Vec::from_raw_parts(self.ptr, self.len, self.cap) } @@ -241,17 +215,3 @@ pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) { mem::drop(vec.into_vec()) } } - -/// Overwrites the bytes of the vector. -/// -/// # Safety -/// -/// `rust` must not be null. -#[no_mangle] -pub unsafe extern "C" fn stylus_vec_set_bytes(rust: *mut RustBytes, data: GoSliceData) { - let rust = &mut *rust; - let mut vec = Vec::from_raw_parts(rust.ptr, rust.len, rust.cap); - vec.clear(); - vec.extend(data.slice()); - rust.write(vec); -} diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index e6c876103..1ce51f996 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -538,6 +538,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" +[[package]] +name = "mini-alloc" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9993556d3850cdbd0da06a3dc81297edcfa050048952d84d75e8b944e8f5af" +dependencies = [ + "cfg-if 1.0.0", + "wee_alloc", +] + [[package]] name = "minimal-lexical" version = "0.2.1" @@ -772,13 +782,6 @@ dependencies = [ [[package]] name = "program-exec" version = "0.1.0" -dependencies = [ - "arbutil", - "eyre", - "fnv", - "hex", - "prover", -] [[package]] name = "prover" @@ -1292,8 +1295,8 @@ name = "wasi-stub" version = "0.1.0" dependencies = [ "caller-env", + "mini-alloc", "paste", - "wee_alloc", ] [[package]] diff --git a/arbitrator/wasm-libraries/program-exec/Cargo.toml b/arbitrator/wasm-libraries/program-exec/Cargo.toml index baa4c4907..d45f5fe61 100644 --- a/arbitrator/wasm-libraries/program-exec/Cargo.toml +++ b/arbitrator/wasm-libraries/program-exec/Cargo.toml @@ -7,8 +7,3 @@ edition = "2021" crate-type = ["cdylib"] [dependencies] -arbutil = { path = "../../arbutil/" } -prover = { path = "../../prover/", default-features = false } -eyre = "0.6.5" -fnv = "1.0.7" -hex = "0.4.3" diff --git a/arbitrator/wasm-libraries/program-exec/src/lib.rs b/arbitrator/wasm-libraries/program-exec/src/lib.rs index 700d1a7cf..841da1349 100644 --- a/arbitrator/wasm-libraries/program-exec/src/lib.rs +++ b/arbitrator/wasm-libraries/program-exec/src/lib.rs @@ -48,7 +48,7 @@ pub unsafe extern "C" fn programs__start_program(module: u32) -> u32 { check_program_done(program_call_main(module, args_len)) } -// sends previos response and transfers control to program +// sends previous response and transfers control to program // MUST be called right after set_response to the same id // returns request_id for the next request #[no_mangle] diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index d2b17cece..d24c7ba6b 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -30,12 +30,11 @@ macro_rules! trace { ($name:expr, $env:expr, [$($args:expr),+], [$($outs:expr),+], $ret:expr) => {{ if $env.evm_data().tracing { let end_ink = $env.ink_ready()?; - let start_ink = $env.start_ink()?; let mut args = vec![]; $(args.extend($args);)* let mut outs = vec![]; $(outs.extend($outs);)* - $env.trace($name, &args, &outs, start_ink, end_ink); + $env.trace($name, &args, &outs, end_ink); } Ok($ret) }}; @@ -82,10 +81,8 @@ pub trait UserHost: GasMeteredMachine { self.read_fixed(ptr).map(|x| x.into()) } - // ink when call stated, only used for tracing, Err if unavailable. - fn start_ink(&self) -> Result; fn say(&self, text: D); - fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], start_ink: u64, end_ink: u64); + fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], end_ink: u64); fn write_bytes20(&self, ptr: GuestPtr, src: Bytes20) -> Result<(), Self::MemoryErr> { self.write_slice(ptr, &src.0) @@ -416,23 +413,6 @@ pub trait UserHost: GasMeteredMachine { ) } - fn sub_slice(mut slice: &[u8], offset: u32, size: u32) -> &[u8] { - let slice_len = slice.len() as u32; - let out_size = if offset > slice_len { - 0 - } else if offset + size > slice_len { - slice_len - offset - } else { - size - }; - if out_size > 0 { - slice = &slice[offset as usize..(offset + out_size) as usize]; - } else { - slice = &[]; - } - slice - } - /// Copies the bytes of the last EVM call or deployment return result. Does not revert if out of /// bounds, but rather copies the overlapping portion. The semantics are otherwise equivalent /// to that of the EVM's [`RETURN_DATA_COPY`] opcode. @@ -453,7 +433,9 @@ pub trait UserHost: GasMeteredMachine { self.pay_for_write(size.min(max))?; let ret_data = self.evm_api().get_return_data(); - let out_slice = Self::sub_slice(ret_data.slice(), offset, size); + let ret_data = ret_data.slice(); + let out_slice = arbutil::slice_with_runoff(&ret_data, offset, offset.saturating_add(size)); + let out_len = out_slice.len() as u32; if out_len > 0 { self.write_slice(dest, out_slice)?; @@ -530,6 +512,8 @@ pub trait UserHost: GasMeteredMachine { dest: GuestPtr, ) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; + self.require_gas(evm::COLD_ACCOUNT_GAS)?; // not necessary since we also check in Go + let address = self.read_bytes20(address)?; let gas = self.gas_left()?; @@ -539,7 +523,7 @@ pub trait UserHost: GasMeteredMachine { self.buy_gas(gas_cost)?; self.pay_for_write(size)?; - let out_slice = Self::sub_slice(code, offset, size); + let out_slice = arbutil::slice_with_runoff(&code, offset, offset.saturating_add(size)); let out_len = out_slice.len() as u32; if out_len > 0 { self.write_slice(dest, out_slice)?; @@ -560,6 +544,7 @@ pub trait UserHost: GasMeteredMachine { /// [`EXT_CODESIZE`]: https://www.evm.codes/#3B fn account_code_size(&mut self, address: GuestPtr) -> Result { self.buy_ink(HOSTIO_INK + EVM_API_INK)?; + self.require_gas(evm::COLD_ACCOUNT_GAS)?; // not necessary since we also check in Go let address = self.read_bytes20(address)?; let gas = self.gas_left()?; diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index ff6584e00..9d2d3fa1e 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -11,7 +11,7 @@ use arbutil::{ }; use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; use core::sync::atomic::{compiler_fence, Ordering}; -use eyre::{bail, eyre, Result}; +use eyre::{eyre, Result}; use prover::programs::prelude::*; use std::fmt::Display; use user_host_trait::UserHost; @@ -192,7 +192,7 @@ impl Program { unsafe { program_memory_size(self.module) } } - /// Reads the program's memory size in pages + /// Provides the length of the program's calldata in bytes. pub fn args_len(&self) -> usize { self.args.len() } @@ -257,13 +257,9 @@ impl UserHost for Program { println!("{} {text}", "Stylus says:".yellow()); } - fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], _start_ink: u64, _end_ink: u64) { + fn trace(&mut self, name: &str, args: &[u8], outs: &[u8], _end_ink: u64) { let args = hex::encode(args); let outs = hex::encode(outs); println!("Error: unexpected hostio tracing info for {name} while proving: {args}, {outs}"); } - - fn start_ink(&self) -> Result { - bail!("recording start ink while proving") - } } diff --git a/arbitrator/wasm-libraries/user-test/src/caller_env.rs b/arbitrator/wasm-libraries/user-test/src/caller_env.rs new file mode 100644 index 000000000..04555d579 --- /dev/null +++ b/arbitrator/wasm-libraries/user-test/src/caller_env.rs @@ -0,0 +1,21 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + +use arbutil::Bytes32; +use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; + +pub struct UserMem; + +impl UserMem { + pub fn read_bytes32(ptr: GuestPtr) -> Bytes32 { + unsafe { STATIC_MEM.read_fixed(ptr).into() } + } + + pub fn read_slice(ptr: GuestPtr, len: u32) -> Vec { + unsafe { STATIC_MEM.read_slice(ptr, len as usize) } + } + + pub fn write_slice(ptr: GuestPtr, src: &[u8]) { + unsafe { STATIC_MEM.write_slice(ptr, src) } + } +} diff --git a/arbitrator/wasm-libraries/user-test/src/host.rs b/arbitrator/wasm-libraries/user-test/src/host.rs index 9b8c99857..d7b4869d5 100644 --- a/arbitrator/wasm-libraries/user-test/src/host.rs +++ b/arbitrator/wasm-libraries/user-test/src/host.rs @@ -1,29 +1,24 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE #![allow(clippy::missing_safety_doc)] -use crate::{Program, ARGS, EVER_PAGES, KEYS, LOGS, OPEN_PAGES, OUTS}; +use crate::{caller_env::UserMem, Program, ARGS, EVER_PAGES, KEYS, LOGS, OPEN_PAGES, OUTS}; use arbutil::{ crypto, evm, pricing::{EVM_API_INK, HOSTIO_INK, PTR_INK}, - Bytes32, }; -use caller_env::{static_caller::STATIC_MEM, MemAccess, GuestPtr}; +use caller_env::GuestPtr; use prover::programs::{ memory::MemoryModel, prelude::{GasMeteredMachine, MeteredMachine}, }; -unsafe fn read_bytes32(ptr: GuestPtr) -> Bytes32 { - STATIC_MEM.read_fixed(ptr).into() -} - #[no_mangle] pub unsafe extern "C" fn vm_hooks__read_args(ptr: GuestPtr) { let mut program = Program::start(0); program.pay_for_write(ARGS.len() as u32).unwrap(); - STATIC_MEM.write_slice(ptr, &ARGS); + UserMem::write_slice(ptr, &ARGS); } #[no_mangle] @@ -31,17 +26,17 @@ pub unsafe extern "C" fn vm_hooks__write_result(ptr: GuestPtr, len: u32) { let mut program = Program::start(0); program.pay_for_read(len).unwrap(); program.pay_for_geth_bytes(len).unwrap(); - OUTS = STATIC_MEM.read_slice(ptr, len as usize); + OUTS = UserMem::read_slice(ptr, len); } #[no_mangle] pub unsafe extern "C" fn vm_hooks__storage_load_bytes32(key: GuestPtr, dest: GuestPtr) { let mut program = Program::start(2 * PTR_INK + EVM_API_INK); - let key = read_bytes32(key); + let key = UserMem::read_bytes32(key); let value = KEYS.lock().get(&key).cloned().unwrap_or_default(); program.buy_gas(2100).unwrap(); // pretend it was cold - STATIC_MEM.write_slice(dest, &value.0); + UserMem::write_slice(dest, &value.0); } #[no_mangle] @@ -50,8 +45,8 @@ pub unsafe extern "C" fn vm_hooks__storage_store_bytes32(key: GuestPtr, value: G program.require_gas(evm::SSTORE_SENTRY_GAS).unwrap(); program.buy_gas(22100).unwrap(); // pretend the worst case - let key = read_bytes32(key); - let value = read_bytes32(value); + let key = UserMem::read_bytes32(key); + let value = UserMem::read_bytes32(value); KEYS.lock().insert(key, value); } @@ -64,7 +59,7 @@ pub unsafe extern "C" fn vm_hooks__emit_log(data: GuestPtr, len: u32, topics: u3 program.pay_for_read(len).unwrap(); program.pay_for_evm_log(topics, len - topics * 32).unwrap(); - let data = STATIC_MEM.read_slice(data, len as usize); + let data = UserMem::read_slice(data, len); LOGS.push(data) } @@ -87,9 +82,9 @@ pub unsafe extern "C" fn vm_hooks__native_keccak256(bytes: GuestPtr, len: u32, o let mut program = Program::start(0); program.pay_for_keccak(len).unwrap(); - let preimage = STATIC_MEM.read_slice(bytes, len as usize); + let preimage = UserMem::read_slice(bytes, len); let digest = crypto::keccak(preimage); - STATIC_MEM.write_slice(output, &digest); + UserMem::write_slice(output, &digest); } #[no_mangle] diff --git a/arbitrator/wasm-libraries/user-test/src/lib.rs b/arbitrator/wasm-libraries/user-test/src/lib.rs index b93f8c02a..21464d658 100644 --- a/arbitrator/wasm-libraries/user-test/src/lib.rs +++ b/arbitrator/wasm-libraries/user-test/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE #![allow(clippy::missing_safety_doc)] @@ -9,6 +9,7 @@ use lazy_static::lazy_static; use parking_lot::Mutex; use prover::programs::prelude::StylusConfig; +mod caller_env; pub mod host; mod ink; diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index beaba4301..87741ee4b 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -10,5 +10,4 @@ crate-type = ["cdylib"] [dependencies] paste = { version = "1.0.14" } caller-env = { path = "../../caller-env/", features = ["static_caller"] } -#mini-alloc = "0.4.2" -wee_alloc = "0.4.5" +mini-alloc = "0.4.2" diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index 5699fc878..e75369aea 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -5,7 +5,7 @@ #![no_std] use caller_env::{self, wasip1_stub::Errno, GuestPtr}; -//use mini_alloc::MiniAlloc; +use mini_alloc::MiniAlloc; use paste::paste; extern "C" { @@ -17,11 +17,8 @@ unsafe fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() } -/*#[global_allocator] -static ALLOC: MiniAlloc = MiniAlloc::INIT;*/ - #[global_allocator] -static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; +static ALLOC: MiniAlloc = MiniAlloc::INIT; #[no_mangle] pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { diff --git a/arbos/programs/constant_test.go b/arbos/programs/constant_test.go index 294798846..fe29bcf3d 100644 --- a/arbos/programs/constant_test.go +++ b/arbos/programs/constant_test.go @@ -1,3 +1,6 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + package programs import "testing" diff --git a/arbos/programs/native.go b/arbos/programs/native.go index d3e34a56d..198e3cb80 100644 --- a/arbos/programs/native.go +++ b/arbos/programs/native.go @@ -21,8 +21,6 @@ import "C" import ( "errors" "fmt" - "math/big" - "runtime" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/state" @@ -113,8 +111,8 @@ func callProgram( } asm := db.GetActivatedAsm(moduleHash) - evmApi, id := newApi(interpreter, tracingInfo, scope, memoryModel) - defer dropApi(id) + evmApi := newApi(interpreter, tracingInfo, scope, memoryModel) + defer evmApi.drop() output := &rustBytes{} status := userStatus(C.stylus_call( @@ -142,37 +140,18 @@ type apiStatus = C.EvmApiStatus const apiSuccess C.EvmApiStatus = C.EvmApiStatus_Success const apiFailure C.EvmApiStatus = C.EvmApiStatus_Failure -func pinAndRef(pinner *runtime.Pinner, data []byte, goSlice *C.GoSliceData) { - if len(data) > 0 { - dataPointer := arbutil.SliceToPointer(data) - pinner.Pin(dataPointer) - goSlice.ptr = (*u8)(dataPointer) - } else { - goSlice.ptr = (*u8)(nil) - } - goSlice.len = usize(len(data)) -} - //export handleReqImpl -func handleReqImpl(apiId usize, req_type u32, data *rustBytes, costPtr *u64, out_response *C.GoSliceData, out_raw_data *C.GoSliceData) apiStatus { +func handleReqImpl(apiId usize, req_type u32, data *rustSlice, costPtr *u64, out_response *C.GoSliceData, out_raw_data *C.GoSliceData) apiStatus { api := getApi(apiId) reqData := data.read() reqType := RequestType(req_type - EvmApiMethodReqOffset) response, raw_data, cost := api.handler(reqType, reqData) *costPtr = u64(cost) - pinAndRef(&api.pinner, response, out_response) - pinAndRef(&api.pinner, raw_data, out_raw_data) + api.pinAndRef(response, out_response) + api.pinAndRef(raw_data, out_raw_data) return apiSuccess } -func (value bytes20) toAddress() common.Address { - addr := common.Address{} - for index, b := range value.bytes { - addr[index] = byte(b) - } - return addr -} - func (value bytes32) toHash() common.Hash { hash := common.Hash{} for index, b := range value.bytes { @@ -181,10 +160,6 @@ func (value bytes32) toHash() common.Hash { return hash } -func (value bytes32) toBig() *big.Int { - return value.toHash().Big() -} - func hashToBytes32(hash common.Hash) bytes32 { value := bytes32{} for index, b := range hash.Bytes() { @@ -219,14 +194,6 @@ func (vec *rustBytes) drop() { C.stylus_drop_vec(*vec) } -func (vec *rustBytes) setString(data string) { - vec.setBytes([]byte(data)) -} - -func (vec *rustBytes) setBytes(data []byte) { - C.stylus_vec_set_bytes(vec, goSlice(data)) -} - func goSlice(slice []byte) C.GoSliceData { return C.GoSliceData{ ptr: (*u8)(arbutil.SliceToPointer(slice)), diff --git a/arbos/programs/native_api.go b/arbos/programs/native_api.go index 03def554c..e66cf07fc 100644 --- a/arbos/programs/native_api.go +++ b/arbos/programs/native_api.go @@ -16,8 +16,8 @@ typedef uint32_t u32; typedef uint64_t u64; typedef size_t usize; -EvmApiStatus handleReqImpl(usize api, u32 req_type, RustBytes *data, u64 *out_cost, GoSliceData *out_result, GoSliceData *out_raw_data); -EvmApiStatus handleReqWrap(usize api, u32 req_type, RustBytes *data, u64 *out_cost, GoSliceData *out_result, GoSliceData *out_raw_data) { +EvmApiStatus handleReqImpl(usize api, u32 req_type, RustSlice *data, u64 *out_cost, GoSliceData *out_result, GoSliceData *out_raw_data); +EvmApiStatus handleReqWrap(usize api, u32 req_type, RustSlice *data, u64 *out_cost, GoSliceData *out_result, GoSliceData *out_raw_data) { return handleReqImpl(api, req_type, data, out_cost, out_result, out_raw_data); } */ @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/offchainlabs/nitro/arbos/util" + "github.com/offchainlabs/nitro/arbutil" ) var apiObjects sync.Map @@ -46,7 +47,7 @@ func newApi( tracingInfo *util.TracingInfo, scope *vm.ScopeContext, memoryModel *MemoryModel, -) (NativeApi, usize) { +) NativeApi { handler := newApiClosures(interpreter, tracingInfo, scope, memoryModel) apiId := atomic.AddUintptr(&apiIds, 1) id := usize(apiId) @@ -56,11 +57,11 @@ func newApi( handle_request_fptr: (*[0]byte)(C.handleReqWrap), id: id, }, - // TODO: doesn't seem like pinner needs to be initialized? + pinner: runtime.Pinner{}, } api.pinner.Pin(&api) apiObjects.Store(apiId, api) - return api, id + return api } func getApi(id usize) NativeApi { @@ -75,9 +76,20 @@ func getApi(id usize) NativeApi { return api } -func dropApi(id usize) { - uid := uintptr(id) - api := getApi(id) +// Free the API object, and any saved request payloads. +func (api *NativeApi) drop() { api.pinner.Unpin() - apiObjects.Delete(uid) + apiObjects.Delete(uintptr(api.cNative.id)) +} + +// Pins a slice until program exit during the call to `drop`. +func (api *NativeApi) pinAndRef(data []byte, goSlice *C.GoSliceData) { + if len(data) > 0 { + dataPointer := arbutil.SliceToPointer(data) + api.pinner.Pin(dataPointer) + goSlice.ptr = (*u8)(dataPointer) + } else { + goSlice.ptr = (*u8)(nil) + } + goSlice.len = usize(len(data)) } diff --git a/arbos/programs/testconstants.go b/arbos/programs/testconstants.go index d189f025f..04f40395d 100644 --- a/arbos/programs/testconstants.go +++ b/arbos/programs/testconstants.go @@ -1,5 +1,10 @@ +// Copyright 2024, Offchain Labs, Inc. +// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE + package programs +// This file exists because cgo isn't allowed in tests + /* #cgo CFLAGS: -g -Wall -I../../target/include/ #include "arbitrator.h" @@ -7,14 +12,16 @@ package programs import "C" import "fmt" -func errIfNotEq(index int, a RequestType, b uint32) error { - if uint32(a) != b { - return fmt.Errorf("constant test %d failed! %d != %d", index, a, b) +func testConstants() error { + + // this closure exists to avoid polluting the package namespace + errIfNotEq := func(index int, a RequestType, b uint32) error { + if uint32(a) != b { + return fmt.Errorf("constant test %d failed! %d != %d", index, a, b) + } + return nil } - return nil -} -func testConstants() error { if err := errIfNotEq(1, GetBytes32, C.EvmApiMethod_GetBytes32); err != nil { return err } diff --git a/arbos/programs/wasm_api.go b/arbos/programs/wasm_api.go index 5b4c6c1db..301f5283a 100644 --- a/arbos/programs/wasm_api.go +++ b/arbos/programs/wasm_api.go @@ -1,4 +1,4 @@ -// Copyright 2023, Offchain Labs, Inc. +// Copyright 2023-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE //go:build wasm @@ -52,5 +52,6 @@ func (data *evmData) createHandler() evmDataHandler { arbutil.SliceToUnsafePointer(data.msgValue[:]), arbutil.SliceToUnsafePointer(data.txGasPrice[:]), arbutil.SliceToUnsafePointer(data.txOrigin[:]), - data.reentrant) + data.reentrant, + ) } diff --git a/arbutil/transaction_data.go b/arbutil/transaction_data.go index 80d150fb9..7741af6e9 100644 --- a/arbutil/transaction_data.go +++ b/arbutil/transaction_data.go @@ -1,9 +1,6 @@ // Copyright 2021-2022, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -//go:build !wasm -// +build !wasm - package arbutil import ( diff --git a/arbutil/unsafe.go b/arbutil/unsafe.go index 5aa1ad422..341aa12c1 100644 --- a/arbutil/unsafe.go +++ b/arbutil/unsafe.go @@ -1,4 +1,4 @@ -// Copyright 2022-2023, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE package arbutil diff --git a/wavmio/higher.go b/wavmio/higher.go index d9db344db..147b4e6c8 100644 --- a/wavmio/higher.go +++ b/wavmio/higher.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE //go:build wasm diff --git a/wavmio/raw.go b/wavmio/raw.go index 26d7fdf46..2e415350f 100644 --- a/wavmio/raw.go +++ b/wavmio/raw.go @@ -1,4 +1,4 @@ -// Copyright 2021-2022, Offchain Labs, Inc. +// Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE //go:build wasm From efc02e0d06d7a5a987134aaa4a4bc15a0d43d577 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 06:10:59 -0700 Subject: [PATCH 15/28] safer message & response parsing --- arbitrator/arbutil/src/evm/api.rs | 7 +- arbitrator/arbutil/src/evm/req.rs | 72 ++++---- arbitrator/jit/src/caller_env.rs | 78 ++++---- arbitrator/jit/src/machine.rs | 18 +- arbitrator/jit/src/program.rs | 44 ++--- arbitrator/jit/src/socket.rs | 8 +- arbitrator/jit/src/wavmio.rs | 73 ++++---- arbitrator/stylus/src/host.rs | 24 ++- arbitrator/stylus/src/lib.rs | 5 +- arbitrator/stylus/src/run.rs | 4 +- .../wasm-libraries/user-host-trait/src/lib.rs | 4 +- arbos/programs/api.go | 170 ++++++++---------- 12 files changed, 241 insertions(+), 266 deletions(-) diff --git a/arbitrator/arbutil/src/evm/api.rs b/arbitrator/arbutil/src/evm/api.rs index d4196b684..a7968fcc8 100644 --- a/arbitrator/arbutil/src/evm/api.rs +++ b/arbitrator/arbutil/src/evm/api.rs @@ -1,4 +1,4 @@ -// Copyright 2023, Offchain Labs, Inc. +// Copyright 2023-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE use crate::{evm::user::UserOutcomeKind, Bytes20, Bytes32}; @@ -53,12 +53,13 @@ pub enum EvmApiMethod { /// id below that offset, indicating program status pub const EVM_API_METHOD_REQ_OFFSET: u32 = 0x10000000; -/// note: clone should not clone actual data, just the reader +/// Copies data from Go into Rust. +/// Note: clone should not clone actual data, just the reader. pub trait DataReader: Clone + Send + 'static { fn slice(&self) -> &[u8]; } -/// simple implementation for DataReader, in case data comes from a Vec +/// Simple implementation for `DataReader`, in case data comes from a `Vec`. #[derive(Clone, Debug)] pub struct VecReader(Arc>); diff --git a/arbitrator/arbutil/src/evm/req.rs b/arbitrator/arbutil/src/evm/req.rs index e3efc40d2..bafd0eb73 100644 --- a/arbitrator/arbutil/src/evm/req.rs +++ b/arbitrator/arbutil/src/evm/req.rs @@ -1,4 +1,4 @@ -// Copyright 2023, Offchain Labs, Inc. +// Copyright 2023-2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE use crate::{ @@ -33,6 +33,7 @@ impl> EvmApiRequestor { self.handler.handle_request(req_type, req_data) } + /// Call out to a contract. fn call_request( &mut self, call_type: EvmApiMethod, @@ -41,13 +42,14 @@ impl> EvmApiRequestor { gas: u64, value: Bytes32, ) -> (u32, u64, UserOutcomeKind) { - let mut request = vec![]; - request.extend(contract.as_slice()); - request.extend(value.as_slice()); - request.extend(&gas.to_be_bytes()); + let mut request = Vec::with_capacity(20 + 32 + 8 + input.len()); + request.extend(contract); + request.extend(value); + request.extend(gas.to_be_bytes()); request.extend(input); + let (res, data, cost) = self.handle_request(call_type, &request); - let status: UserOutcomeKind = res[0].try_into().unwrap(); + let status: UserOutcomeKind = res[0].try_into().expect("unknown outcome"); let data_len = data.slice().len() as u32; self.last_return_data = Some(data); (data_len, cost, status) @@ -65,24 +67,23 @@ impl> EvmApiRequestor { salt: Option, gas: u64, ) -> (Result, u32, u64) { - let mut request = vec![]; - request.extend(&gas.to_be_bytes()); - request.extend(endowment.as_slice()); + let mut request = Vec::with_capacity(8 + 2 * 32 + code.len()); + request.extend(gas.to_be_bytes()); + request.extend(endowment); if let Some(salt) = salt { - request.extend(salt.as_slice()); + request.extend(salt); } - request.extend(&code); + request.extend(code); let (mut res, data, cost) = self.handle_request(create_type, &request); if res.len() != 21 || res[0] == 0 { if !res.is_empty() { - res.drain(0..=0); + res.remove(0); } - let err_string = - String::from_utf8(res).unwrap_or(String::from("create_response_malformed")); + let err_string = String::from_utf8(res).unwrap_or("create_response_malformed".into()); return (Err(eyre!(err_string)), 0, cost); } - res.drain(0..=0); + res.remove(0); let address = res.try_into().unwrap(); let data_len = data.slice().len() as u32; self.last_return_data = Some(data); @@ -97,9 +98,9 @@ impl> EvmApi for EvmApiRequestor { } fn set_bytes32(&mut self, key: Bytes32, value: Bytes32) -> Result { - let mut request = vec![]; - request.extend(key.as_slice()); - request.extend(value.as_slice()); + let mut request = Vec::with_capacity(64); + request.extend(key); + request.extend(value); let (res, _, cost) = self.handle_request(EvmApiMethod::SetBytes32, &request); if res.len() != 1 { bail!("bad response from set_bytes32") @@ -170,18 +171,17 @@ impl> EvmApi for EvmApiRequestor { } fn get_return_data(&self) -> D { - self.last_return_data - .as_ref() - .expect("get return data when no data") - .clone() + self.last_return_data.clone().expect("missing return data") } fn emit_log(&mut self, data: Vec, topics: u32) -> Result<()> { - let mut request = topics.to_be_bytes().to_vec(); - request.extend(data.iter()); + let mut request = Vec::with_capacity(4 + data.len()); + request.extend(topics.to_be_bytes()); + request.extend(data); + let (res, _, _) = self.handle_request(EvmApiMethod::EmitLog, &request); if !res.is_empty() { - bail!(String::from_utf8(res).unwrap_or(String::from("malformed emit-log response"))) + bail!(String::from_utf8(res).unwrap_or("malformed emit-log response".into())) } Ok(()) } @@ -197,10 +197,11 @@ impl> EvmApi for EvmApiRequestor { return (data.clone(), 0); } } - let mut req: Vec = address.as_slice().into(); + let mut req = Vec::with_capacity(20 + 8); + req.extend(address); req.extend(gas_left.to_be_bytes()); - let (_, data, cost) = self.handle_request(EvmApiMethod::AccountCode, &req); + let (_, data, cost) = self.handle_request(EvmApiMethod::AccountCode, &req); self.last_code = Some((address, data.clone())); (data, cost) } @@ -211,8 +212,8 @@ impl> EvmApi for EvmApiRequestor { } fn add_pages(&mut self, pages: u16) -> u64 { - let (_, _, cost) = self.handle_request(EvmApiMethod::AddPages, &pages.to_be_bytes()); - cost + self.handle_request(EvmApiMethod::AddPages, &pages.to_be_bytes()) + .2 } fn capture_hostio( @@ -223,13 +224,12 @@ impl> EvmApi for EvmApiRequestor { start_ink: u64, end_ink: u64, ) { - let mut request = vec![]; - - request.extend(&start_ink.to_be_bytes()); - request.extend(&end_ink.to_be_bytes()); - request.extend(&(name.len() as u16).to_be_bytes()); - request.extend(&(args.len() as u16).to_be_bytes()); - request.extend(&(outs.len() as u16).to_be_bytes()); + let mut request = Vec::with_capacity(2 * 8 + 3 * 2 + name.len() + args.len() + outs.len()); + request.extend(start_ink.to_be_bytes()); + request.extend(end_ink.to_be_bytes()); + request.extend((name.len() as u16).to_be_bytes()); + request.extend((args.len() as u16).to_be_bytes()); + request.extend((outs.len() as u16).to_be_bytes()); request.extend(name.as_bytes()); request.extend(args); request.extend(outs); diff --git a/arbitrator/jit/src/caller_env.rs b/arbitrator/jit/src/caller_env.rs index 1737ad2ea..ed61f52db 100644 --- a/arbitrator/jit/src/caller_env.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -7,8 +7,10 @@ use caller_env::{ExecEnv, GuestPtr, MemAccess}; use rand::RngCore; use rand_pcg::Pcg32; use std::{ + cmp::Ordering, collections::{BTreeSet, BinaryHeap}, fmt::Debug, + mem::{self, MaybeUninit}, }; use wasmer::{Memory, MemoryView, StoreMut, WasmPtr}; @@ -21,28 +23,29 @@ pub struct JitExecEnv<'s> { pub wenv: &'s mut WasmEnv, } +pub(crate) trait JitEnv<'a> { + fn jit_env(&mut self) -> (JitMemAccess<'_>, &mut WasmEnv); +} + +impl<'a> JitEnv<'a> for WasmEnvMut<'a> { + fn jit_env(&mut self) -> (JitMemAccess<'_>, &mut WasmEnv) { + let memory = self.data().memory.clone().unwrap(); + let (wenv, store) = self.data_and_store_mut(); + (JitMemAccess { memory, store }, wenv) + } +} + pub fn jit_env<'s>(env: &'s mut WasmEnvMut) -> (JitMemAccess<'s>, JitExecEnv<'s>) { let memory = env.data().memory.clone().unwrap(); let (wenv, store) = env.data_and_store_mut(); (JitMemAccess { memory, store }, JitExecEnv { wenv }) } -#[allow(dead_code)] impl<'s> JitMemAccess<'s> { - /// Returns the memory size, in bytes. - /// note: wasmer measures memory in 65536-byte pages. - fn memory_size(&self) -> u64 { - self.view().size().0 as u64 * 65536 - } - fn view(&self) -> MemoryView { self.memory.view(&self.store) } - pub fn write_bytes20(&mut self, ptr: GuestPtr, val: Bytes20) { - self.write_slice(ptr, val.as_slice()) - } - pub fn write_bytes32(&mut self, ptr: GuestPtr, val: Bytes32) { self.write_slice(ptr, val.as_slice()) } @@ -54,18 +57,6 @@ impl<'s> JitMemAccess<'s> { pub fn read_bytes32(&mut self, ptr: GuestPtr) -> Bytes32 { self.read_fixed(ptr).into() } - - pub fn read_string(&mut self, ptr: GuestPtr, len: u32) -> String { - let bytes = self.read_slice(ptr, len as usize); - match String::from_utf8(bytes) { - Ok(s) => s, - Err(e) => { - let bytes = e.as_bytes(); - eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); - String::from_utf8_lossy(bytes).into_owned() - } - } - } } impl MemAccess for JitMemAccess<'_> { @@ -110,12 +101,15 @@ impl MemAccess for JitMemAccess<'_> { } fn read_slice(&self, ptr: GuestPtr, len: usize) -> Vec { - let mut data = Vec::with_capacity(len); + let mut data: Vec> = Vec::with_capacity(len); + // SAFETY: read_uninit fills all available space unsafe { data.set_len(len); - self.view().read(ptr.into(), &mut data).expect("bad read"); + self.view() + .read_uninit(ptr.into(), &mut data) + .expect("bad read"); + mem::transmute(data) } - data } fn read_fixed(&self, ptr: GuestPtr) -> [u8; N] { @@ -128,33 +122,33 @@ impl MemAccess for JitMemAccess<'_> { } impl ExecEnv for JitExecEnv<'_> { - fn print_string(&mut self, bytes: &[u8]) { - match String::from_utf8(bytes.to_vec()) { - Ok(s) => eprintln!("JIT: WASM says: {s}"), - Err(e) => { - let bytes = e.as_bytes(); - eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); - } - } + fn advance_time(&mut self, ns: u64) { + self.wenv.go_state.time += ns; } fn get_time(&self) -> u64 { self.wenv.go_state.time } - fn advance_time(&mut self, delta: u64) { - self.wenv.go_state.time += delta - } - fn next_rand_u32(&mut self) -> u32 { self.wenv.go_state.rng.next_u32() } + + fn print_string(&mut self, bytes: &[u8]) { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => eprintln!("JIT: WASM says: {s}"), + Err(e) => { + let bytes = e.as_bytes(); + eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); + } + } + } } pub struct GoRuntimeState { - /// An increasing clock used when Go asks for time, measured in nanoseconds + /// An increasing clock used when Go asks for time, measured in nanoseconds. pub time: u64, - /// Deterministic source of random data + /// Deterministic source of random data. pub rng: Pcg32, } @@ -174,7 +168,7 @@ pub struct TimeoutInfo { } impl Ord for TimeoutInfo { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { + fn cmp(&self, other: &Self) -> Ordering { other .time .cmp(&self.time) @@ -183,7 +177,7 @@ impl Ord for TimeoutInfo { } impl PartialOrd for TimeoutInfo { - fn partial_cmp(&self, other: &Self) -> Option { + fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } diff --git a/arbitrator/jit/src/machine.rs b/arbitrator/jit/src/machine.rs index ffdaabad0..a15c0256e 100644 --- a/arbitrator/jit/src/machine.rs +++ b/arbitrator/jit/src/machine.rs @@ -5,17 +5,9 @@ use crate::{ arbcompress, caller_env::GoRuntimeState, program, socket, stylus_backend::CothreadHandler, wasip1_stub, wavmio, Opts, }; -// runtime, socket, syscall, user use arbutil::{Bytes32, Color}; use eyre::{bail, ErrReport, Result, WrapErr}; use sha3::{Digest, Keccak256}; -use thiserror::Error; -use wasmer::{ - imports, CompilerConfig, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, Module, - RuntimeError, Store, -}; -use wasmer_compiler_cranelift::Cranelift; - use std::{ collections::{BTreeMap, HashMap}, fs::File, @@ -25,6 +17,12 @@ use std::{ sync::Arc, time::{Duration, Instant}, }; +use thiserror::Error; +use wasmer::{ + imports, CompilerConfig, Function, FunctionEnv, FunctionEnvMut, Instance, Memory, Module, + RuntimeError, Store, +}; +use wasmer_compiler_cranelift::Cranelift; pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv, Store) { let file = &opts.binary; @@ -167,10 +165,6 @@ impl Escape { pub fn hostio>(message: S) -> Result { Err(Self::HostIO(message.as_ref().to_string())) } - - pub fn failure>(message: S) -> Result { - Err(Self::Failure(message.as_ref().to_string())) - } } impl From for Escape { diff --git a/arbitrator/jit/src/program.rs b/arbitrator/jit/src/program.rs index 65dcb92eb..193e6bbc2 100644 --- a/arbitrator/jit/src/program.rs +++ b/arbitrator/jit/src/program.rs @@ -3,7 +3,7 @@ #![allow(clippy::too_many_arguments)] -use crate::caller_env::jit_env; +use crate::caller_env::JitEnv; use crate::machine::{Escape, MaybeEscape, WasmEnvMut}; use crate::stylus_backend::exec_wasm; use arbutil::Bytes32; @@ -31,7 +31,7 @@ pub fn activate( err_buf: GuestPtr, err_buf_len: u32, ) -> Result { - let (mut mem, _) = jit_env(&mut env); + let (mut mem, _) = env.jit_env(); let wasm = mem.read_slice(wasm_ptr, wasm_size as usize); let debug = debug != 0; @@ -70,7 +70,7 @@ pub fn new_program( evm_data_handler: u64, gas: u64, ) -> Result { - let (mut mem, exec) = jit_env(&mut env); + let (mut mem, exec) = env.jit_env(); let compiled_hash = mem.read_bytes32(compiled_hash_ptr); let calldata = mem.read_slice(calldata_ptr, calldata_size as usize); let evm_data: EvmData = unsafe { *Box::from_raw(evm_data_handler as *mut EvmData) }; @@ -80,11 +80,11 @@ pub fn new_program( let pricing = config.stylus.pricing; let ink = pricing.gas_to_ink(gas); - let Some(module) = exec.wenv.module_asms.get(&compiled_hash).cloned() else { + let Some(module) = exec.module_asms.get(&compiled_hash).cloned() else { return Err(Escape::Failure(format!( "module hash {:?} not found in {:?}", compiled_hash, - exec.wenv.module_asms.keys() + exec.module_asms.keys() ))); }; @@ -98,24 +98,24 @@ pub fn new_program( ) .unwrap(); - exec.wenv.threads.push(cothread); + exec.threads.push(cothread); - Ok(exec.wenv.threads.len() as u32) + Ok(exec.threads.len() as u32) } /// starts the program (in jit waits for first request) /// module MUST match last module number returned from new_program /// returns request_id for the first request from the program pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { - let (_, exec) = jit_env(&mut env); + let (_, exec) = env.jit_env(); - if exec.wenv.threads.len() as u32 != module || module == 0 { + if exec.threads.len() as u32 != module || module == 0 { return Escape::hostio(format!( "got request for thread {module} but len is {}", - exec.wenv.threads.len() + exec.threads.len() )); } - let thread = exec.wenv.threads.last_mut().unwrap(); + let thread = exec.threads.last_mut().unwrap(); thread.wait_next_message()?; let msg = thread.last_message()?; Ok(msg.1) @@ -124,8 +124,8 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result { /// gets information about request according to id /// request_id MUST be last request id returned from start_program or send_response pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: GuestPtr) -> Result { - let (mut mem, exec) = jit_env(&mut env); - let thread = exec.wenv.threads.last_mut().unwrap(); + let (mut mem, exec) = env.jit_env(); + let thread = exec.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { return Escape::hostio("get_request id doesn't match"); @@ -138,8 +138,8 @@ pub fn get_request(mut env: WasmEnvMut, id: u32, len_ptr: GuestPtr) -> Result MaybeEscape { - let (mut mem, exec) = jit_env(&mut env); - let thread = exec.wenv.threads.last_mut().unwrap(); + let (mut mem, exec) = env.jit_env(); + let thread = exec.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != id { return Escape::hostio("get_request id doesn't match"); @@ -159,11 +159,11 @@ pub fn set_response( raw_data_ptr: GuestPtr, raw_data_len: u32, ) -> MaybeEscape { - let (mem, exec) = jit_env(&mut env); + let (mem, exec) = env.jit_env(); let result = mem.read_slice(result_ptr, result_len as usize); let raw_data = mem.read_slice(raw_data_ptr, raw_data_len as usize); - let thread = exec.wenv.threads.last_mut().unwrap(); + let thread = exec.threads.last_mut().unwrap(); thread.set_response(id, result, raw_data, gas) } @@ -171,8 +171,8 @@ pub fn set_response( /// MUST be called right after set_response to the same id /// returns request_id for the next request pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { - let (_, exec) = jit_env(&mut env); - let thread = exec.wenv.threads.last_mut().unwrap(); + let (_, exec) = env.jit_env(); + let thread = exec.threads.last_mut().unwrap(); let msg = thread.last_message()?; if msg.1 != req_id { return Escape::hostio("get_request id doesn't match"); @@ -184,9 +184,9 @@ pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result { /// removes the last created program pub fn pop(mut env: WasmEnvMut) -> MaybeEscape { - let (_, exec) = jit_env(&mut env); + let (_, exec) = env.jit_env(); - match exec.wenv.threads.pop() { + match exec.threads.pop() { None => Err(Escape::Child(eyre!("no child"))), Some(mut thread) => thread.wait_done(), } @@ -231,7 +231,7 @@ pub fn create_evm_data( tx_origin_ptr: GuestPtr, reentrant: u32, ) -> Result { - let (mut mem, _) = jit_env(&mut env); + let (mut mem, _) = env.jit_env(); let evm_data = EvmData { block_basefee: mem.read_bytes32(block_basefee_ptr), diff --git a/arbitrator/jit/src/socket.rs b/arbitrator/jit/src/socket.rs index 740f029f1..004b8eb44 100644 --- a/arbitrator/jit/src/socket.rs +++ b/arbitrator/jit/src/socket.rs @@ -1,18 +1,16 @@ -// Copyright 2022, Offchain Labs, Inc. +// Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -//use core::slice::SlicePattern; +use arbutil::Bytes32; use std::{ io, io::{BufReader, BufWriter, Read, Write}, net::TcpStream, }; -use arbutil::Bytes32; - pub const SUCCESS: u8 = 0x0; pub const FAILURE: u8 = 0x1; -// not used pub const PREIMAGE: u8 = 0x2; +// pub const PREIMAGE: u8 = 0x2; // not used pub const ANOTHER: u8 = 0x3; pub const READY: u8 = 0x4; diff --git a/arbitrator/jit/src/wavmio.rs b/arbitrator/jit/src/wavmio.rs index d74c4c789..e1611d432 100644 --- a/arbitrator/jit/src/wavmio.rs +++ b/arbitrator/jit/src/wavmio.rs @@ -2,7 +2,7 @@ // For license information, see https://github.com/nitro/blob/master/LICENSE use crate::{ - caller_env::jit_env, + caller_env::JitEnv, machine::{Escape, MaybeEscape, WasmEnv, WasmEnvMut}, socket, }; @@ -15,40 +15,38 @@ use std::{ time::Instant, }; -/// Reads 32-bytes of global state +/// Reads 32-bytes of global state. pub fn get_global_state_bytes32(mut env: WasmEnvMut, idx: u32, out_ptr: GuestPtr) -> MaybeEscape { - let (mut mem, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (mut mem, exec) = env.jit_env(); + ready_hostio(exec)?; - let Some(global) = exec.wenv.large_globals.get(idx as usize) else { + let Some(global) = exec.large_globals.get(idx as usize) else { return Escape::hostio("global read out of bounds in wavmio.getGlobalStateBytes32"); }; mem.write_slice(out_ptr, &global[..32]); Ok(()) } -/// Writes 32-bytes of global state +/// Writes 32-bytes of global state. pub fn set_global_state_bytes32(mut env: WasmEnvMut, idx: u32, src_ptr: GuestPtr) -> MaybeEscape { - let (mem, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (mem, exec) = env.jit_env(); + ready_hostio(exec)?; let slice = mem.read_slice(src_ptr, 32); let slice = &slice.try_into().unwrap(); - match exec.wenv.large_globals.get_mut(idx as usize) { + match exec.large_globals.get_mut(idx as usize) { Some(global) => *global = *slice, - None => { - return Escape::hostio("global write out of bounds in wavmio.setGlobalStateBytes32") - } - } + None => return Escape::hostio("global write oob in wavmio.setGlobalStateBytes32"), + }; Ok(()) } /// Reads 8-bytes of global state pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result { - let (_, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (_, exec) = env.jit_env(); + ready_hostio(exec)?; - match exec.wenv.small_globals.get(idx as usize) { + match exec.small_globals.get(idx as usize) { Some(global) => Ok(*global), None => Escape::hostio("global read out of bounds in wavmio.getGlobalStateU64"), } @@ -56,29 +54,27 @@ pub fn get_global_state_u64(mut env: WasmEnvMut, idx: u32) -> Result MaybeEscape { - let (_, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (_, exec) = env.jit_env(); + ready_hostio(exec)?; - match exec.wenv.small_globals.get_mut(idx as usize) { - Some(global) => { - *global = val; - Ok(()) - } - None => Escape::hostio("global write out of bounds in wavmio.setGlobalStateU64"), + match exec.small_globals.get_mut(idx as usize) { + Some(global) => *global = val, + None => return Escape::hostio("global write out of bounds in wavmio.setGlobalStateU64"), } + Ok(()) } -/// Reads an inbox message +/// Reads an inbox message. pub fn read_inbox_message( mut env: WasmEnvMut, msg_num: u64, offset: u32, out_ptr: GuestPtr, ) -> Result { - let (mut mem, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (mut mem, exec) = env.jit_env(); + ready_hostio(exec)?; - let message = match exec.wenv.sequencer_messages.get(&msg_num) { + let message = match exec.sequencer_messages.get(&msg_num) { Some(message) => message, None => return Escape::hostio(format!("missing sequencer inbox message {msg_num}")), }; @@ -89,27 +85,24 @@ pub fn read_inbox_message( Ok(read.len() as u32) } -/// Reads a delayed inbox message +/// Reads a delayed inbox message. pub fn read_delayed_inbox_message( mut env: WasmEnvMut, msg_num: u64, offset: u32, out_ptr: GuestPtr, ) -> Result { - let (mut mem, exec) = jit_env(&mut env); - ready_hostio(exec.wenv)?; + let (mut mem, exec) = env.jit_env(); + ready_hostio(exec)?; - let message = match exec.wenv.delayed_messages.get(&msg_num) { + let message = match exec.delayed_messages.get(&msg_num) { Some(message) => message, None => return Escape::hostio(format!("missing delayed inbox message {msg_num}")), }; let offset = offset as usize; let len = std::cmp::min(32, message.len().saturating_sub(offset)); - let read = message - .get(offset..(offset + len)) - .unwrap_or_default() - .to_vec(); - mem.write_slice(out_ptr, &read); + let read = message.get(offset..(offset + len)).unwrap_or_default(); + mem.write_slice(out_ptr, read); Ok(read.len() as u32) } @@ -120,7 +113,7 @@ pub fn resolve_preimage( offset: u32, out_ptr: GuestPtr, ) -> Result { - let (mut mem, exec) = jit_env(&mut env); + let (mut mem, exec) = env.jit_env(); let name = "wavmio.resolvePreImage"; @@ -137,7 +130,7 @@ pub fn resolve_preimage( let mut preimage = None; // see if we've cached the preimage - if let Some((key, cached)) = &exec.wenv.process.last_preimage { + if let Some((key, cached)) = &exec.process.last_preimage { if *key == hash { preimage = Some(cached); } @@ -145,7 +138,7 @@ pub fn resolve_preimage( // see if this is a known preimage if preimage.is_none() { - preimage = exec.wenv.preimages.get(&hash); + preimage = exec.preimages.get(&hash); } let Some(preimage) = preimage else { diff --git a/arbitrator/stylus/src/host.rs b/arbitrator/stylus/src/host.rs index 918bf1f02..c7a038818 100644 --- a/arbitrator/stylus/src/host.rs +++ b/arbitrator/stylus/src/host.rs @@ -14,11 +14,18 @@ use arbutil::{ use caller_env::GuestPtr; use eyre::Result; use prover::value::Value; -use std::fmt::Display; +use std::{ + fmt::Display, + mem::{self, MaybeUninit}, +}; use user_host_trait::UserHost; use wasmer::{MemoryAccessError, WasmPtr}; -impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { +impl<'a, DR, A> UserHost for HostioInfo<'a, DR, A> +where + DR: DataReader, + A: EvmApi, +{ type Err = Escape; type MemoryErr = MemoryAccessError; type A = A; @@ -46,14 +53,19 @@ impl<'a, DR: DataReader, A: EvmApi> UserHost for HostioInfo<'a, DR, A> { fn read_fixed( &self, ptr: GuestPtr, - ) -> std::result::Result<[u8; N], >::MemoryErr> { + ) -> std::result::Result<[u8; N], Self::MemoryErr> { HostioInfo::read_fixed(self, ptr) } fn read_slice(&self, ptr: GuestPtr, len: u32) -> Result, Self::MemoryErr> { - let mut data = vec![0; len as usize]; - self.view().read(ptr.into(), &mut data)?; - Ok(data) + let len = len as usize; + let mut data: Vec> = Vec::with_capacity(len); + // SAFETY: read_uninit fills all available space + unsafe { + data.set_len(len); + self.view().read_uninit(ptr.into(), &mut data)?; + Ok(mem::transmute(data)) + } } fn write_u32(&mut self, ptr: GuestPtr, x: u32) -> Result<(), Self::MemoryErr> { diff --git a/arbitrator/stylus/src/lib.rs b/arbitrator/stylus/src/lib.rs index 3a84f3f2d..2e681725f 100644 --- a/arbitrator/stylus/src/lib.rs +++ b/arbitrator/stylus/src/lib.rs @@ -179,14 +179,13 @@ pub unsafe extern "C" fn stylus_call( let module = module.slice(); let calldata = calldata.slice().to_vec(); let compile = CompileConfig::version(config.version, debug_chain != 0); + let evm_api = EvmApiRequestor::new(req_handler); let pricing = config.pricing; let output = &mut *output; let ink = pricing.gas_to_ink(*gas); // Safety: module came from compile_user_wasm and we've paid for memory expansion - let instance = unsafe { - NativeInstance::deserialize(module, compile, EvmApiRequestor::new(req_handler), evm_data) - }; + let instance = unsafe { NativeInstance::deserialize(module, compile, evm_api, evm_data) }; let mut instance = match instance { Ok(instance) => instance, Err(error) => panic!("failed to instantiate program: {error:?}"), diff --git a/arbitrator/stylus/src/run.rs b/arbitrator/stylus/src/run.rs index e7cac9051..3b20aba82 100644 --- a/arbitrator/stylus/src/run.rs +++ b/arbitrator/stylus/src/run.rs @@ -107,13 +107,13 @@ impl> RunProgram for NativeInstance { } }; - let env = self.env.as_mut(store); + let env = self.env_mut(); if env.evm_data.tracing { env.evm_api .capture_hostio("user_returned", &[], &status.to_be_bytes(), ink, ink); } - let outs = self.env().outs.clone(); + let outs = env.outs.clone(); Ok(match status { 0 => UserOutcome::Success(outs), _ => UserOutcome::Revert(outs), diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index d24c7ba6b..2cfaa5dba 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -74,11 +74,11 @@ pub trait UserHost: GasMeteredMachine { fn write_slice(&self, ptr: GuestPtr, src: &[u8]) -> Result<(), Self::MemoryErr>; fn read_bytes20(&self, ptr: GuestPtr) -> Result { - self.read_fixed(ptr).map(|x| x.into()) + self.read_fixed(ptr).map(Into::into) } fn read_bytes32(&self, ptr: GuestPtr) -> Result { - self.read_fixed(ptr).map(|x| x.into()) + self.read_fixed(ptr).map(Into::into) } fn say(&self, text: D); diff --git a/arbos/programs/api.go b/arbos/programs/api.go index 7251b633c..edc2bb0cd 100644 --- a/arbos/programs/api.go +++ b/arbos/programs/api.go @@ -4,7 +4,6 @@ package programs import ( - "encoding/binary" "errors" "math/big" @@ -236,33 +235,66 @@ func newApiClosures( } return func(req RequestType, input []byte) ([]byte, []byte, uint64) { - switch req { - case GetBytes32: - if len(input) != 32 { - log.Crit("bad API call", "request", req, "len", len(input)) + original := input + + crash := func(reason string) { + log.Crit("bad API call", "reason", reason, "request", req, "len", len(original), "remaining", len(input)) + } + takeInput := func(needed int, reason string) []byte { + if len(input) < needed { + crash(reason) + } + data := input[:needed] + input = input[needed:] + return data + } + defer func() { + if len(input) > 0 { + crash("extra input") } - key := common.BytesToHash(input) + }() - out, cost := getBytes32(key) + takeAddress := func() common.Address { + return common.BytesToAddress(takeInput(20, "expected address")) + } + takeHash := func() common.Hash { + return common.BytesToHash(takeInput(32, "expected hash")) + } + takeBig := func() *big.Int { + return common.BytesToHash(takeInput(32, "expected big")).Big() + } + takeU64 := func() uint64 { + return am.BytesToUint(takeInput(8, "expected u64")) + } + takeU32 := func() uint32 { + return am.BytesToUint32(takeInput(4, "expected u32")) + } + takeU16 := func() uint16 { + return am.BytesToUint16(takeInput(2, "expected u16")) + } + takeFixed := func(needed int) []byte { + return takeInput(needed, "expected value with known length") + } + takeRest := func() []byte { + data := input + input = []byte{} + return data + } + switch req { + case GetBytes32: + key := takeHash() + out, cost := getBytes32(key) return out[:], nil, cost case SetBytes32: - if len(input) != 64 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - key := common.BytesToHash(input[:32]) - value := common.BytesToHash(input[32:]) - + key := takeHash() + value := takeHash() cost, err := setBytes32(key, value) - if err != nil { return []byte{0}, nil, 0 } return []byte{1}, nil, cost case ContractCall, DelegateCall, StaticCall: - if len(input) < 60 { - log.Crit("bad API call", "request", req, "len", len(input)) - } var opcode vm.OpCode switch req { case ContractCall: @@ -274,41 +306,27 @@ func newApiClosures( default: log.Crit("unsupported call type", "opcode", opcode) } - contract := common.BytesToAddress(input[:20]) - value := common.BytesToHash(input[20:52]).Big() - gas := binary.BigEndian.Uint64(input[52:60]) - input = input[60:] - - ret, cost, err := doCall(contract, opcode, input, gas, value) + contract := takeAddress() + value := takeBig() + gas := takeU64() + calldata := takeRest() + ret, cost, err := doCall(contract, opcode, calldata, gas, value) statusByte := byte(0) if err != nil { - statusByte = 2 //TODO: err value + statusByte = 2 // TODO: err value } return []byte{statusByte}, ret, cost case Create1, Create2: - if len(input) < 40 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - gas := binary.BigEndian.Uint64(input[0:8]) - endowment := common.BytesToHash(input[8:40]).Big() - var code []byte + gas := takeU64() + endowment := takeBig() var salt *big.Int - switch req { - case Create1: - code = input[40:] - case Create2: - if len(input) < 72 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - salt = common.BytesToHash(input[40:72]).Big() - code = input[72:] - default: - log.Crit("unsupported create opcode", "request", req) + if req == Create2 { + salt = takeBig() } + code := takeRest() address, retVal, cost, err := create(code, endowment, salt, gas) - if err != nil { res := append([]byte{0}, []byte(err.Error())...) return res, nil, gas @@ -316,83 +334,49 @@ func newApiClosures( res := append([]byte{1}, address.Bytes()...) return res, retVal, cost case EmitLog: - if len(input) < 4 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - topics := binary.BigEndian.Uint32(input[0:4]) - input = input[4:] + topics := takeU32() hashes := make([]common.Hash, topics) - if len(input) < int(topics*32) { - log.Crit("bad API call", "request", req, "len", len(input)) - } for i := uint32(0); i < topics; i++ { - hashes[i] = common.BytesToHash(input[i*32 : (i+1)*32]) + hashes[i] = takeHash() } - err := emitLog(hashes, input[topics*32:]) - + err := emitLog(hashes, takeRest()) if err != nil { return []byte(err.Error()), nil, 0 } return []byte{}, nil, 0 case AccountBalance: - if len(input) != 20 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - address := common.BytesToAddress(input) - + address := takeAddress() balance, cost := accountBalance(address) - return balance[:], nil, cost case AccountCode: - if len(input) != 28 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - address := common.BytesToAddress(input[0:20]) - gas := binary.BigEndian.Uint64(input[20:28]) - + address := takeAddress() + gas := takeU64() code, cost := accountCode(address, gas) - return nil, code, cost case AccountCodeHash: - if len(input) != 20 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - address := common.BytesToAddress(input) - + address := takeAddress() codeHash, cost := accountCodehash(address) - return codeHash[:], nil, cost case AddPages: - if len(input) != 2 { - log.Crit("bad API call", "request", req, "len", len(input)) - } - pages := binary.BigEndian.Uint16(input) - + pages := takeU16() cost := addPages(pages) - return []byte{}, nil, cost case CaptureHostIO: - if len(input) < 22 { - log.Crit("bad API call", "request", req, "len", len(input)) - } if tracingInfo == nil { + takeRest() // drop any input return []byte{}, nil, 0 } - startInk := binary.BigEndian.Uint64(input[:8]) - endInk := binary.BigEndian.Uint64(input[8:16]) - nameLen := binary.BigEndian.Uint16(input[16:18]) - argsLen := binary.BigEndian.Uint16(input[18:20]) - outsLen := binary.BigEndian.Uint16(input[20:22]) - if len(input) != 22+int(nameLen+argsLen+outsLen) { - log.Error("bad API call", "request", req, "len", len(input), "expected", nameLen+argsLen+outsLen) - } - name := string(input[22 : 22+nameLen]) - args := input[22+nameLen : 22+nameLen+argsLen] - outs := input[22+nameLen+argsLen:] + startInk := takeU64() + endInk := takeU64() + nameLen := takeU16() + argsLen := takeU16() + outsLen := takeU16() + name := string(takeFixed(int(nameLen))) + args := takeFixed(int(argsLen)) + outs := takeFixed(int(outsLen)) captureHostio(name, args, outs, startInk, endInk) - return []byte{}, nil, 0 default: log.Crit("unsupported call type", "req", req) From a4adb6315dc1abc640c372bcc747f5b708e6a11b Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 07:24:28 -0700 Subject: [PATCH 16/28] more cleanup --- arbitrator/jit/src/stylus_backend.rs | 64 +++++++-------- arbitrator/prover/src/host.rs | 2 +- arbitrator/wasm-libraries/host-io/src/lib.rs | 52 +++++++++--- .../wasm-libraries/user-host-trait/src/lib.rs | 11 ++- .../wasm-libraries/user-host/src/link.rs | 79 +++++++++---------- .../wasm-libraries/user-host/src/program.rs | 23 +++--- arbos/programs/wasm.go | 18 +++-- 7 files changed, 134 insertions(+), 115 deletions(-) diff --git a/arbitrator/jit/src/stylus_backend.rs b/arbitrator/jit/src/stylus_backend.rs index 6144fb834..74a8d6ae1 100644 --- a/arbitrator/jit/src/stylus_backend.rs +++ b/arbitrator/jit/src/stylus_backend.rs @@ -48,15 +48,13 @@ impl RequestHandler for CothreadRequestor { req_type: EvmApiMethod, req_data: &[u8], ) -> (Vec, VecReader, u64) { - if self - .tx - .send(MessageFromCothread { - req_type: req_type as u32 + EVM_API_METHOD_REQ_OFFSET, - req_data: req_data.to_vec(), - }) - .is_err() - { - panic!("failed sending request from cothread"); + let msg = MessageFromCothread { + req_type: req_type as u32 + EVM_API_METHOD_REQ_OFFSET, + req_data: req_data.to_vec(), + }; + + if let Err(error) = self.tx.send(msg) { + panic!("failed sending request from cothread: {error}"); } match self.rx.recv_timeout(Duration::from_secs(5)) { Ok(response) => ( @@ -80,28 +78,25 @@ impl CothreadHandler { pub fn wait_next_message(&mut self) -> MaybeEscape { let msg = self.rx.recv_timeout(Duration::from_secs(10)); let Ok(msg) = msg else { - return Err(Escape::HostIO("did not receive message".to_string())); + return Escape::hostio("did not receive message"); }; self.last_request = Some((msg, 0x33333333)); // TODO: Ids Ok(()) } pub fn wait_done(&mut self) -> MaybeEscape { - let status = self - .thread - .take() - .ok_or(Escape::Child(eyre!("no child")))? - .join(); + let error = || Escape::Child(eyre!("no child")); + let status = self.thread.take().ok_or_else(error)?.join(); match status { Ok(res) => res, - Err(_) => Err(Escape::HostIO("failed joining child process".to_string())), + Err(_) => Escape::hostio("failed joining child process"), } } pub fn last_message(&self) -> Result<(MessageFromCothread, u32), Escape> { self.last_request .clone() - .ok_or(Escape::HostIO("no message waiting".to_string())) + .ok_or_else(|| Escape::HostIO("no message waiting".to_string())) } pub fn set_response( @@ -117,16 +112,13 @@ impl CothreadHandler { if msg.1 != id { return Escape::hostio("trying to set response for wrong message id"); }; - if self - .tx - .send(MessageToCothread { - result, - raw_data, - cost, - }) - .is_err() - { - return Escape::hostio("failed sending response to stylus thread"); + let msg = MessageToCothread { + result, + raw_data, + cost, + }; + if let Err(err) = self.tx.send(msg) { + return Escape::hostio(format!("failed to send response to stylus thread: {err:?}")); }; Ok(()) } @@ -168,21 +160,23 @@ pub fn exec_wasm( }; let (out_kind, data) = outcome.into_data(); - let gas_left = config.pricing.ink_to_gas(ink_left); - let mut output = gas_left.to_be_bytes().to_vec(); - output.extend(data.iter()); + let mut output = Vec::with_capacity(8 + data.len()); + output.extend(gas_left.to_be_bytes()); + output.extend(data); + + let msg = MessageFromCothread { + req_data: output, + req_type: out_kind as u32, + }; instance .env_mut() .evm_api .request_handler() .tx - .send(MessageFromCothread { - req_data: output, - req_type: out_kind as u32, - }) - .or(Escape::hostio("failed sending messaage to thread")) + .send(msg) + .or_else(|_| Escape::hostio("failed sending messaage to thread")) }); Ok(CothreadHandler { diff --git a/arbitrator/prover/src/host.rs b/arbitrator/prover/src/host.rs index 35344e85c..d5ec9154a 100644 --- a/arbitrator/prover/src/host.rs +++ b/arbitrator/prover/src/host.rs @@ -359,7 +359,7 @@ impl Hostio { opcode!(I32Const, UserOutcomeKind::Failure as u32) } ProgramRequest => { - // caller sees: λ(status)->response + // caller sees: λ(status) → response // code returns status of either ProgramContinue or ProgramCallMain opcode!(LocalGet, 0); // return_data opcode!(MoveFromStackToInternal); diff --git a/arbitrator/wasm-libraries/host-io/src/lib.rs b/arbitrator/wasm-libraries/host-io/src/lib.rs index 796f6db66..90c735c8f 100644 --- a/arbitrator/wasm-libraries/host-io/src/lib.rs +++ b/arbitrator/wasm-libraries/host-io/src/lib.rs @@ -1,7 +1,10 @@ // Copyright 2021-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE +#![allow(clippy::missing_safety_doc)] // TODO: add safety docs + use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; +use core::ops::{Deref, DerefMut, Index, RangeTo}; extern "C" { pub fn wavm_get_globalstate_bytes32(idx: u32, ptr: *mut u8); @@ -16,13 +19,35 @@ extern "C" { #[repr(C, align(256))] struct MemoryLeaf([u8; 32]); +impl Deref for MemoryLeaf { + type Target = [u8; 32]; + + fn deref(&self) -> &[u8; 32] { + &self.0 + } +} + +impl DerefMut for MemoryLeaf { + fn deref_mut(&mut self) -> &mut [u8; 32] { + &mut self.0 + } +} + +impl Index> for MemoryLeaf { + type Output = [u8]; + + fn index(&self, index: RangeTo) -> &[u8] { + &self.0[index] + } +} + #[no_mangle] pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: GuestPtr) { let mut our_buf = MemoryLeaf([0u8; 32]); - let our_ptr = our_buf.0.as_mut_ptr(); + let our_ptr = our_buf.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); wavm_get_globalstate_bytes32(idx, our_ptr); - STATIC_MEM.write_slice(out_ptr, &our_buf.0[..32]); + STATIC_MEM.write_slice(out_ptr, &our_buf[..32]); } /// Writes 32-bytes of global state @@ -30,8 +55,9 @@ pub unsafe extern "C" fn wavmio__getGlobalStateBytes32(idx: u32, out_ptr: GuestP pub unsafe extern "C" fn wavmio__setGlobalStateBytes32(idx: u32, src_ptr: GuestPtr) { let mut our_buf = MemoryLeaf([0u8; 32]); let value = STATIC_MEM.read_slice(src_ptr, 32); - our_buf.0.copy_from_slice(&value); - let our_ptr = our_buf.0.as_ptr(); + our_buf.copy_from_slice(&value); + + let our_ptr = our_buf.as_ptr(); assert_eq!(our_ptr as usize % 32, 0); wavm_set_globalstate_bytes32(idx, our_ptr); } @@ -56,11 +82,12 @@ pub unsafe extern "C" fn wavmio__readInboxMessage( out_ptr: GuestPtr, ) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); - let our_ptr = our_buf.0.as_mut_ptr(); + let our_ptr = our_buf.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); + let read = wavm_read_inbox_message(msg_num, our_ptr, offset); assert!(read <= 32); - STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); + STATIC_MEM.write_slice(out_ptr, &our_buf[..read]); read } @@ -72,11 +99,12 @@ pub unsafe extern "C" fn wavmio__readDelayedInboxMessage( out_ptr: GuestPtr, ) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); - let our_ptr = our_buf.0.as_mut_ptr(); + let our_ptr = our_buf.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); + let read = wavm_read_delayed_inbox_message(msg_num, our_ptr, offset); assert!(read <= 32); - STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); + STATIC_MEM.write_slice(out_ptr, &our_buf[..read]); read } @@ -89,11 +117,13 @@ pub unsafe extern "C" fn wavmio__resolvePreImage( ) -> usize { let mut our_buf = MemoryLeaf([0u8; 32]); let hash = STATIC_MEM.read_slice(hash_ptr, 32); - our_buf.0.copy_from_slice(&hash); - let our_ptr = our_buf.0.as_mut_ptr(); + our_buf.copy_from_slice(&hash); + + let our_ptr = our_buf.as_mut_ptr(); assert_eq!(our_ptr as usize % 32, 0); + let read = wavm_read_pre_image(our_ptr, offset); assert!(read <= 32); - STATIC_MEM.write_slice(out_ptr, &our_buf.0[..read]); + STATIC_MEM.write_slice(out_ptr, &our_buf[..read]); read } diff --git a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs index 2cfaa5dba..cd9c35653 100644 --- a/arbitrator/wasm-libraries/user-host-trait/src/lib.rs +++ b/arbitrator/wasm-libraries/user-host-trait/src/lib.rs @@ -519,15 +519,14 @@ pub trait UserHost: GasMeteredMachine { // we pass `gas` to check if there's enough before loading from the db let (code, gas_cost) = self.evm_api().account_code(address, gas); - let code = code.slice(); self.buy_gas(gas_cost)?; - self.pay_for_write(size)?; + + let code = code.slice(); + self.pay_for_write(code.len() as u32)?; let out_slice = arbutil::slice_with_runoff(&code, offset, offset.saturating_add(size)); let out_len = out_slice.len() as u32; - if out_len > 0 { - self.write_slice(dest, out_slice)?; - } + self.write_slice(dest, out_slice)?; trace!( "account_code", @@ -551,8 +550,8 @@ pub trait UserHost: GasMeteredMachine { // we pass `gas` to check if there's enough before loading from the db let (code, gas_cost) = self.evm_api().account_code(address, gas); self.buy_gas(gas_cost)?; - let code = code.slice(); + let code = code.slice(); trace!("account_code_size", self, address, &[], code.len() as u32) } diff --git a/arbitrator/wasm-libraries/user-host/src/link.rs b/arbitrator/wasm-libraries/user-host/src/link.rs index f2a0f624c..664d19464 100644 --- a/arbitrator/wasm-libraries/user-host/src/link.rs +++ b/arbitrator/wasm-libraries/user-host/src/link.rs @@ -8,10 +8,7 @@ use arbutil::{ heapify, Bytes20, Bytes32, }; use caller_env::{static_caller::STATIC_MEM, GuestPtr, MemAccess}; -use prover::{ - machine::Module, - programs::config::{PricingParams, StylusConfig}, -}; +use prover::{machine::Module, programs::config::StylusConfig}; // these hostio methods allow the replay machine to modify itself #[link(wasm_import_module = "hostio")] @@ -33,12 +30,12 @@ extern "C" { #[repr(C, align(256))] struct MemoryLeaf([u8; 32]); -// Instruments and "activates" a user wasm, producing a unique module hash. -// -// Note that this operation costs gas and is limited by the amount supplied via the `gas` pointer. -// The amount left is written back at the end of the call. -// -// pages_ptr: starts pointing to max allowed pages, returns number of pages used +/// Instruments and "activates" a user wasm, producing a unique module hash. +/// +/// Note that this operation costs gas and is limited by the amount supplied via the `gas` pointer. +/// The amount left is written back at the end of the call. +/// +/// pages_ptr: starts pointing to max allowed pages, returns number of pages used #[no_mangle] pub unsafe extern "C" fn programs__activate( wasm_ptr: GuestPtr, @@ -95,62 +92,61 @@ unsafe fn read_bytes20(ptr: GuestPtr) -> Bytes20 { /// see program-exec for starting the user program #[no_mangle] pub unsafe extern "C" fn programs__new_program( - compiled_hash_ptr: GuestPtr, + module_hash_ptr: GuestPtr, calldata_ptr: GuestPtr, calldata_size: usize, config_box: u64, evm_data_box: u64, gas: u64, ) -> u32 { - let compiled_hash = read_bytes32(compiled_hash_ptr); + let module_hash = read_bytes32(module_hash_ptr); let calldata = STATIC_MEM.read_slice(calldata_ptr, calldata_size); - let config: StylusConfig = *Box::from_raw(config_box as *mut StylusConfig); - let evm_data: EvmData = *Box::from_raw(evm_data_box as *mut EvmData); + let config: StylusConfig = *Box::from_raw(config_box as _); + let evm_data: EvmData = *Box::from_raw(evm_data_box as _); // buy ink let pricing = config.pricing; let ink = pricing.gas_to_ink(gas); // link the program and ready its instrumentation - let module = wavm_link_module(&MemoryLeaf(*compiled_hash)); + let module = wavm_link_module(&MemoryLeaf(*module_hash)); program_set_ink(module, ink); program_set_stack(module, config.max_depth); // provide arguments Program::push_new(calldata, evm_data, module, config); - module } -// gets information about request according to id -// request_id MUST be last request id returned from start_program or send_response +/// Gets information about request according to id. +/// +/// # Safety +/// +/// `request_id` MUST be last request id returned from start_program or send_response. #[no_mangle] pub unsafe extern "C" fn programs__get_request(id: u32, len_ptr: GuestPtr) -> u32 { - let (req_type, len) = Program::current() - .evm_api - .request_handler() - .get_request_meta(id); + let (req_type, len) = Program::current().request_handler().get_request_meta(id); if len_ptr != GuestPtr(0) { STATIC_MEM.write_u32(len_ptr, len as u32); } req_type } -// gets data associated with last request. -// request_id MUST be last request receieved -// data_ptr MUST point to a buffer of at least the length returned by get_request +/// Gets data associated with last request. +/// +/// # Safety +/// +/// `request_id` MUST be last request receieved +/// `data_ptr` MUST point to a buffer of at least the length returned by `get_request` #[no_mangle] pub unsafe extern "C" fn programs__get_request_data(id: u32, data_ptr: GuestPtr) { - let (_, data) = Program::current() - .evm_api - .request_handler() - .take_request(id); + let (_, data) = Program::current().request_handler().take_request(id); STATIC_MEM.write_slice(data_ptr, &data); } -// sets response for the next request made -// id MUST be the id of last request made -// see program-exec send_response for sending this response to the program +/// sets response for the next request made +/// id MUST be the id of last request made +/// see `program-exec::send_response` for sending this response to the program #[no_mangle] pub unsafe extern "C" fn programs__set_response( id: u32, @@ -161,7 +157,7 @@ pub unsafe extern "C" fn programs__set_response( raw_data_len: usize, ) { let program = Program::current(); - program.evm_api.request_handler().set_response( + program.request_handler().set_response( id, STATIC_MEM.read_slice(result_ptr, result_len), STATIC_MEM.read_slice(raw_data_ptr, raw_data_len), @@ -188,8 +184,8 @@ pub unsafe extern "C" fn program_internal__args_len(module: u32) -> usize { program.args_len() } -// used by program-exec -// sets status of the last program and sends a program_done request +/// used by program-exec +/// sets status of the last program and sends a program_done request #[no_mangle] pub unsafe extern "C" fn program_internal__set_done(mut status: u8) -> u32 { let program = Program::current(); @@ -212,10 +208,11 @@ pub unsafe extern "C" fn program_internal__set_done(mut status: u8) -> u32 { ink_left = 0; } let gas_left = program.config.pricing.ink_to_gas(ink_left); - let mut output = gas_left.to_be_bytes().to_vec(); - output.extend(outs.iter()); + + let mut output = Vec::with_capacity(8 + outs.len()); + output.extend(gas_left.to_be_bytes()); + output.extend(outs); program - .evm_api .request_handler() .set_request(status as u32, &output) } @@ -228,11 +225,7 @@ pub unsafe extern "C" fn programs__create_stylus_config( ink_price: u32, _debug: u32, ) -> u64 { - let config = StylusConfig { - version, - max_depth, - pricing: PricingParams { ink_price }, - }; + let config = StylusConfig::new(version, max_depth, ink_price); heapify(config) as u64 } diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 9d2d3fa1e..925c09860 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -96,7 +96,7 @@ impl UserHostRequester { ) { self.answer = Some((result, VecReader::new(raw_data), gas)); if req_id != self.id { - panic!("bad req id returning from send_request") + panic!("bad eq id returning from send_request") } compiler_fence(Ordering::SeqCst); } @@ -114,31 +114,26 @@ impl UserHostRequester { if self.id != id { panic!("get_request got wrong id"); } - ( - self.req_type, - self.data - .as_ref() - .expect("no request on get_request_meta") - .len(), - ) + let size = self.data.as_ref().expect("no data get_request_meta").len(); + (self.req_type, size) } pub unsafe fn take_request(&mut self, id: u32) -> (u32, Vec) { if self.id != id { panic!("get_request got wrong id"); } - ( - self.req_type, - self.data.take().expect("no request on take_request"), - ) + let data = self.data.take().expect("no request on take_request"); + (self.req_type, data) } #[no_mangle] unsafe fn send_request(&mut self, req_type: u32, data: Vec) -> (Vec, VecReader, u64) { let req_id = self.set_request(req_type, &data); compiler_fence(Ordering::SeqCst); + let got_id = program_request(req_id); compiler_fence(Ordering::SeqCst); + if got_id != req_id { panic!("bad req id returning from send_request") } @@ -205,6 +200,10 @@ impl Program { } Ok(()) } + + pub fn request_handler(&mut self) -> &mut UserHostRequester { + self.evm_api.request_handler() + } } #[allow(clippy::unit_arg)] diff --git a/arbos/programs/wasm.go b/arbos/programs/wasm.go index 942b87b9c..0995685b0 100644 --- a/arbos/programs/wasm.go +++ b/arbos/programs/wasm.go @@ -7,7 +7,6 @@ package programs import ( - "encoding/binary" "errors" "unsafe" @@ -128,9 +127,8 @@ func callProgram( params *goParams, memoryModel *MemoryModel, ) ([]byte, error) { - // debug := arbmath.UintToBool(params.debugMode) + debug := arbmath.UintToBool(params.debugMode) reqHandler := newApiClosures(interpreter, tracingInfo, scope, memoryModel) - configHandler := params.createHandler() dataHandler := evmData.createHandler() @@ -151,17 +149,23 @@ func callProgram( if reqTypeId < EvmApiMethodReqOffset { popProgram() status := userStatus(reqTypeId) - gasLeft := binary.BigEndian.Uint64(reqData[:8]) + gasLeft := arbmath.BytesToUint(reqData[:8]) scope.Contract.Gas = gasLeft - data, msg, err := status.toResult(reqData[8:], params.debugMode != 0) - if status == userFailure && params.debugMode != 0 { + data, msg, err := status.toResult(reqData[8:], debug) + if status == userFailure && debug { log.Warn("program failure", "err", err, "msg", msg, "program", address) } return data, err } + reqType := RequestType(reqTypeId - EvmApiMethodReqOffset) result, rawData, cost := reqHandler(reqType, reqData) - setResponse(reqId, cost, arbutil.SliceToUnsafePointer(result), uint32(len(result)), arbutil.SliceToUnsafePointer(rawData), uint32(len(rawData))) + setResponse( + reqId, + cost, + arbutil.SliceToUnsafePointer(result), uint32(len(result)), + arbutil.SliceToUnsafePointer(rawData), uint32(len(rawData)), + ) reqId = sendResponse(reqId) } } From 09f7e357b29e81749a036c61d9f8062703d98c4c Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 07:28:10 -0700 Subject: [PATCH 17/28] repin contracts --- contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts b/contracts index efcc03da9..5666569dc 160000 --- a/contracts +++ b/contracts @@ -1 +1 @@ -Subproject commit efcc03da9a274147e263b58aba8c12f046ebd870 +Subproject commit 5666569dc3e83903de28fb73cf558535cfe22ecb From c61efc5371d0a5ddef8df9025d1ad1c5e3851879 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 07:48:51 -0700 Subject: [PATCH 18/28] fix docker --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1986b735c..bca9a7cc3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -46,7 +46,7 @@ RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --de COPY ./Makefile ./ COPY arbitrator/Cargo.* arbitrator/ COPY arbitrator/arbutil arbitrator/arbutil -COPY arbitrator/callerenv arbitrator/callerenv +COPY arbitrator/caller-env arbitrator/caller-env COPY arbitrator/prover arbitrator/prover COPY arbitrator/wasm-libraries arbitrator/wasm-libraries COPY arbitrator/tools/wasmer arbitrator/tools/wasmer @@ -93,7 +93,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \ COPY arbitrator/Cargo.* arbitrator/ COPY ./Makefile ./ COPY arbitrator/arbutil arbitrator/arbutil -COPY arbitrator/callerenv arbitrator/callerenv +COPY arbitrator/caller-env arbitrator/caller-env COPY arbitrator/prover arbitrator/prover COPY arbitrator/wasm-libraries arbitrator/wasm-libraries COPY arbitrator/jit arbitrator/jit @@ -115,7 +115,7 @@ RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - && \ apt-get install -y llvm-15-dev libclang-common-15-dev libpolly-15-dev COPY arbitrator/Cargo.* arbitrator/ COPY arbitrator/arbutil arbitrator/arbutil -COPY arbitrator/callerenv arbitrator/callerenv +COPY arbitrator/caller-env arbitrator/caller-env COPY arbitrator/prover/Cargo.toml arbitrator/prover/ COPY arbitrator/jit/Cargo.toml arbitrator/jit/ COPY arbitrator/stylus/Cargo.toml arbitrator/stylus/ @@ -156,7 +156,7 @@ COPY --from=wasm-libs-builder /workspace/arbitrator/prover/ arbitrator/prover/ COPY --from=wasm-libs-builder /workspace/arbitrator/tools/wasmer/ arbitrator/tools/wasmer/ COPY --from=wasm-libs-builder /workspace/arbitrator/wasm-libraries/ arbitrator/wasm-libraries/ COPY --from=wasm-libs-builder /workspace/arbitrator/arbutil arbitrator/arbutil -COPY --from=wasm-libs-builder /workspace/arbitrator/callerenv arbitrator/callerenv +COPY --from=wasm-libs-builder /workspace/arbitrator/caller-env arbitrator/caller-env COPY --from=wasm-libs-builder /workspace/.make/ .make/ COPY ./Makefile ./ COPY ./arbitrator ./arbitrator From e99b3fff830ad6ae4705437c810a41c7e604d706 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 07:57:15 -0700 Subject: [PATCH 19/28] revert back to WeeAlloc --- arbitrator/wasm-libraries/Cargo.lock | 12 +----------- arbitrator/wasm-libraries/wasi-stub/Cargo.toml | 2 +- arbitrator/wasm-libraries/wasi-stub/src/lib.rs | 8 ++++---- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/arbitrator/wasm-libraries/Cargo.lock b/arbitrator/wasm-libraries/Cargo.lock index 1ce51f996..67beb7c93 100644 --- a/arbitrator/wasm-libraries/Cargo.lock +++ b/arbitrator/wasm-libraries/Cargo.lock @@ -538,16 +538,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" -[[package]] -name = "mini-alloc" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9993556d3850cdbd0da06a3dc81297edcfa050048952d84d75e8b944e8f5af" -dependencies = [ - "cfg-if 1.0.0", - "wee_alloc", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1295,8 +1285,8 @@ name = "wasi-stub" version = "0.1.0" dependencies = [ "caller-env", - "mini-alloc", "paste", + "wee_alloc", ] [[package]] diff --git a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml index 87741ee4b..f6079ce2f 100644 --- a/arbitrator/wasm-libraries/wasi-stub/Cargo.toml +++ b/arbitrator/wasm-libraries/wasi-stub/Cargo.toml @@ -10,4 +10,4 @@ crate-type = ["cdylib"] [dependencies] paste = { version = "1.0.14" } caller-env = { path = "../../caller-env/", features = ["static_caller"] } -mini-alloc = "0.4.2" +wee_alloc = "0.4.2" diff --git a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs index e75369aea..2f237dcb4 100644 --- a/arbitrator/wasm-libraries/wasi-stub/src/lib.rs +++ b/arbitrator/wasm-libraries/wasi-stub/src/lib.rs @@ -5,21 +5,21 @@ #![no_std] use caller_env::{self, wasip1_stub::Errno, GuestPtr}; -use mini_alloc::MiniAlloc; use paste::paste; +use wee_alloc::WeeAlloc; extern "C" { fn wavm_halt_and_set_finished() -> !; } +#[global_allocator] +static ALLOC: WeeAlloc = WeeAlloc::INIT; + #[panic_handler] unsafe fn panic(_: &core::panic::PanicInfo) -> ! { core::arch::wasm32::unreachable() } -#[global_allocator] -static ALLOC: MiniAlloc = MiniAlloc::INIT; - #[no_mangle] pub unsafe extern "C" fn wasi_snapshot_preview1__proc_exit(code: u32) -> ! { if code == 0 { From 8ec6f2154756e6fef8c710e66393f9ab64c1cc19 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 11:25:26 -0700 Subject: [PATCH 20/28] fix refs & debug printing --- arbitrator/prover/src/lib.rs | 2 +- arbitrator/prover/src/machine.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arbitrator/prover/src/lib.rs b/arbitrator/prover/src/lib.rs index e1fb64cc7..c8504a397 100644 --- a/arbitrator/prover/src/lib.rs +++ b/arbitrator/prover/src/lib.rs @@ -112,7 +112,7 @@ pub unsafe extern "C" fn arbitrator_load_wavm_binary(binary_path: *const c_char) match Machine::new_from_wavm(binary_path) { Ok(mach) => Box::into_raw(Box::new(mach)), Err(err) => { - eprintln!("Error loading binary: {}", err); + eprintln!("Error loading binary: {err}"); ptr::null_mut() } } diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index c65b8c7f5..b96042fcf 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -1129,6 +1129,11 @@ impl Machine { let config = CompileConfig::version(version, debug_funcs); let stylus_data = bin.instrument(&config)?; + // enable debug mode if debug funcs are available + if debug_funcs { + self.debug_info = true; + } + let module = Module::from_user_binary(&bin, debug_funcs, Some(stylus_data))?; let hash = module.hash(); self.add_stylus_module(module, hash); @@ -1767,13 +1772,13 @@ impl Machine { } if let ThreadState::CoThread(recovery_pc) = self.thread_state { + self.thread_state = ThreadState::Main; self.pc = recovery_pc; reset_refs!(); if self.debug_info { println!("\n{}", "switching to main thread".grey()); println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); } - self.thread_state = ThreadState::Main; continue; } self.status = MachineStatus::Errored; @@ -1785,7 +1790,7 @@ impl Machine { for _ in 0..n { self.steps += 1; if self.steps == Self::MAX_STEPS { - error!(); + error!(); // TODO: make this irrecoverable } let inst = func.code[self.pc.inst()]; self.pc.inst += 1; From 546a47173abccb1a56c128cc2a184aadb72c4eaf Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 8 Mar 2024 13:19:39 -0700 Subject: [PATCH 21/28] remove print_string from ExecEnv --- arbitrator/caller-env/src/lib.rs | 2 -- arbitrator/caller-env/src/static_caller.rs | 4 --- arbitrator/caller-env/src/wasip1_stub.rs | 5 +-- arbitrator/jit/src/caller_env.rs | 10 ------ arbitrator/jit/src/machine.rs | 2 +- arbitrator/jit/src/wasip1_stub.rs | 41 ++++++++++++++++++---- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/arbitrator/caller-env/src/lib.rs b/arbitrator/caller-env/src/lib.rs index 39ee65e59..65700081f 100644 --- a/arbitrator/caller-env/src/lib.rs +++ b/arbitrator/caller-env/src/lib.rs @@ -61,6 +61,4 @@ pub trait ExecEnv { fn get_time(&self) -> u64; fn next_rand_u32(&mut self) -> u32; - - fn print_string(&mut self, message: &[u8]); } diff --git a/arbitrator/caller-env/src/static_caller.rs b/arbitrator/caller-env/src/static_caller.rs index 5b4765c7c..21547c143 100644 --- a/arbitrator/caller-env/src/static_caller.rs +++ b/arbitrator/caller-env/src/static_caller.rs @@ -100,10 +100,6 @@ impl MemAccess for StaticMem { } impl ExecEnv for StaticExecEnv { - fn print_string(&mut self, _data: &[u8]) { - // To print, call the debug-only `console::log_txt` Host I/O - } - fn get_time(&self) -> u64 { unsafe { TIME } } diff --git a/arbitrator/caller-env/src/wasip1_stub.rs b/arbitrator/caller-env/src/wasip1_stub.rs index 41f136c5e..973b4e6f3 100644 --- a/arbitrator/caller-env/src/wasip1_stub.rs +++ b/arbitrator/caller-env/src/wasip1_stub.rs @@ -68,6 +68,9 @@ pub fn environ_get( /// Writes to the given file descriptor. /// Note that we only support stdout and stderr. +/// Writing to output doesn't happen here. +/// in arbitrator that's in host_call_hook, +/// in jit it's in fd_write_wrapper pub fn fd_write( mem: &mut M, env: &mut E, @@ -83,8 +86,6 @@ pub fn fd_write( for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; let len = mem.read_u32(ptr + 4); - let data = mem.read_slice(ptr, len as usize); - env.print_string(&data); size += len; } mem.write_u32(ret_ptr, size); diff --git a/arbitrator/jit/src/caller_env.rs b/arbitrator/jit/src/caller_env.rs index ed61f52db..f81fedc79 100644 --- a/arbitrator/jit/src/caller_env.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -133,16 +133,6 @@ impl ExecEnv for JitExecEnv<'_> { fn next_rand_u32(&mut self) -> u32 { self.wenv.go_state.rng.next_u32() } - - fn print_string(&mut self, bytes: &[u8]) { - match String::from_utf8(bytes.to_vec()) { - Ok(s) => eprintln!("JIT: WASM says: {s}"), - Err(e) => { - let bytes = e.as_bytes(); - eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); - } - } - } } pub struct GoRuntimeState { diff --git a/arbitrator/jit/src/machine.rs b/arbitrator/jit/src/machine.rs index a15c0256e..b6ebcd282 100644 --- a/arbitrator/jit/src/machine.rs +++ b/arbitrator/jit/src/machine.rs @@ -81,7 +81,7 @@ pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv, Sto "wasi_snapshot_preview1" => { "proc_exit" => func!(wasip1_stub::proc_exit), "environ_sizes_get" => func!(wasip1_stub::environ_sizes_get), - "fd_write" => func!(wasip1_stub::fd_write), + "fd_write" => func!(wasip1_stub::fd_write_wrapper), "environ_get" => func!(wasip1_stub::environ_get), "fd_close" => func!(wasip1_stub::fd_close), "fd_read" => func!(wasip1_stub::fd_read), diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index e1e91366e..8f90b8ae8 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -5,12 +5,45 @@ use crate::caller_env::jit_env; use crate::machine::{Escape, WasmEnvMut}; -use caller_env::{self, wasip1_stub::Errno, GuestPtr}; +use caller_env::{ + self, + wasip1_stub::{Errno, ERRNO_BADF, ERRNO_SUCCESS}, + GuestPtr, MemAccess, +}; pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { Err(Escape::Exit(code)) } +// implements arbitrator machine's host-call hook around fd_write +pub fn fd_write_wrapper( + mut src: WasmEnvMut, + fd: u32, + iovecs_ptr: GuestPtr, + iovecs_len: u32, + ret_ptr: GuestPtr, +) -> Errno { + if fd != 1 && fd != 2 { + return ERRNO_BADF; + } + let (mut mem, mut env) = jit_env(&mut src); + let mut size = 0; + for i in 0..iovecs_len { + let ptr = iovecs_ptr + i * 8; + let len = mem.read_u32(ptr + 4); + let data = mem.read_slice(ptr, len as usize); + match String::from_utf8(data) { + Ok(s) => eprintln!("JIT: WASM says: {s}"), + Err(e) => { + let bytes = e.as_bytes(); + eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); + } + } + size += len; + } + caller_env::wasip1_stub::fd_write(&mut mem, &mut env, fd, iovecs_ptr, iovecs_len, ret_ptr) +} + macro_rules! wrap { ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { $( @@ -37,12 +70,6 @@ wrap! { fn fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno; fn fd_close(fd: u32) -> Errno; - fn fd_write( - fd: u32, - iovecs_ptr: GuestPtr, - iovecs_len: u32, - ret_ptr: GuestPtr - ) -> Errno; fn fd_readdir( fd: u32, From d18bec5da7d817bc904835ae1a59940262c642f0 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 8 Mar 2024 13:27:39 -0700 Subject: [PATCH 22/28] fix wasip1_stub warnings --- arbitrator/caller-env/src/wasip1_stub.rs | 2 +- arbitrator/jit/src/wasip1_stub.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/arbitrator/caller-env/src/wasip1_stub.rs b/arbitrator/caller-env/src/wasip1_stub.rs index 973b4e6f3..75db9de47 100644 --- a/arbitrator/caller-env/src/wasip1_stub.rs +++ b/arbitrator/caller-env/src/wasip1_stub.rs @@ -73,7 +73,7 @@ pub fn environ_get( /// in jit it's in fd_write_wrapper pub fn fd_write( mem: &mut M, - env: &mut E, + _env: &mut E, fd: u32, iovecs_ptr: GuestPtr, iovecs_len: u32, diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 8f90b8ae8..7ded4f000 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -27,7 +27,6 @@ pub fn fd_write_wrapper( return ERRNO_BADF; } let (mut mem, mut env) = jit_env(&mut src); - let mut size = 0; for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; let len = mem.read_u32(ptr + 4); From fff788721084fe9f9bfff9c4f7939e5c1388fc78 Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 8 Mar 2024 13:29:00 -0700 Subject: [PATCH 23/28] don't recover from error if over max steps --- arbitrator/prover/src/machine.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index b96042fcf..800d79cfb 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -1772,14 +1772,16 @@ impl Machine { } if let ThreadState::CoThread(recovery_pc) = self.thread_state { - self.thread_state = ThreadState::Main; - self.pc = recovery_pc; - reset_refs!(); - if self.debug_info { - println!("\n{}", "switching to main thread".grey()); - println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); + if self.steps < Self::MAX_STEPS { + self.thread_state = ThreadState::Main; + self.pc = recovery_pc; + reset_refs!(); + if self.debug_info { + println!("\n{}", "switching to main thread".grey()); + println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); + } + continue; } - continue; } self.status = MachineStatus::Errored; module = &mut self.modules[self.pc.module()]; @@ -1790,7 +1792,7 @@ impl Machine { for _ in 0..n { self.steps += 1; if self.steps == Self::MAX_STEPS { - error!(); // TODO: make this irrecoverable + error!(); } let inst = func.code[self.pc.inst()]; self.pc.inst += 1; From c3f5aeac132952901a10a6e738bc28734ca6e071 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 14:13:28 -0700 Subject: [PATCH 24/28] fix loop & print out of steps --- arbitrator/jit/src/wasip1_stub.rs | 1 - arbitrator/prover/src/machine.rs | 23 +++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 7ded4f000..61ff1bc25 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -38,7 +38,6 @@ pub fn fd_write_wrapper( eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); } } - size += len; } caller_env::wasip1_stub::fd_write(&mut mem, &mut env, fd, iovecs_ptr, iovecs_len, ret_ptr) } diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index 800d79cfb..998803f8c 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -1772,16 +1772,14 @@ impl Machine { } if let ThreadState::CoThread(recovery_pc) = self.thread_state { - if self.steps < Self::MAX_STEPS { - self.thread_state = ThreadState::Main; - self.pc = recovery_pc; - reset_refs!(); - if self.debug_info { - println!("\n{}", "switching to main thread".grey()); - println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); - } - continue; + self.thread_state = ThreadState::Main; + self.pc = recovery_pc; + reset_refs!(); + if self.debug_info { + println!("\n{}", "switching to main thread".grey()); + println!("\n{} {:?}", "next opcode: ".grey(), func.code[self.pc.inst()]); } + continue; } self.status = MachineStatus::Errored; module = &mut self.modules[self.pc.module()]; @@ -1792,8 +1790,13 @@ impl Machine { for _ in 0..n { self.steps += 1; if self.steps == Self::MAX_STEPS { - error!(); + println!("\n{}", "Machine out of steps".red()); + self.status = MachineStatus::Errored; + self.print_backtrace(true); + module = &mut self.modules[self.pc.module()]; + break; } + let inst = func.code[self.pc.inst()]; self.pc.inst += 1; match inst.opcode { From 33789de71d535bae4ec442c39a9dfdc4d2797638 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 14:17:20 -0700 Subject: [PATCH 25/28] pass time each poll_oneoff --- arbitrator/caller-env/src/wasip1_stub.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arbitrator/caller-env/src/wasip1_stub.rs b/arbitrator/caller-env/src/wasip1_stub.rs index 75db9de47..075f05971 100644 --- a/arbitrator/caller-env/src/wasip1_stub.rs +++ b/arbitrator/caller-env/src/wasip1_stub.rs @@ -380,12 +380,15 @@ pub fn random_get( /// Note that we always simulate a timeout and skip all others. pub fn poll_oneoff( mem: &mut M, - _: &mut E, + env: &mut E, in_subs: GuestPtr, out_evt: GuestPtr, num_subscriptions: u32, num_events_ptr: GuestPtr, ) -> Errno { + // simulate the passage of time each poll request + env.advance_time(TIME_INTERVAL); + const SUBSCRIPTION_SIZE: u32 = 48; // user data + 40-byte union for index in 0..num_subscriptions { let subs_base = in_subs + (SUBSCRIPTION_SIZE * index); From b69e276b56c94917e7ff44c37722fc2538bb8de5 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 14:29:09 -0700 Subject: [PATCH 26/28] address review comments: cleanup --- arbitrator/prover/src/machine.rs | 15 ++++++--------- .../wasm-libraries/user-host/src/program.rs | 2 +- arbos/programs/api.go | 8 ++++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/arbitrator/prover/src/machine.rs b/arbitrator/prover/src/machine.rs index 998803f8c..a4601f845 100644 --- a/arbitrator/prover/src/machine.rs +++ b/arbitrator/prover/src/machine.rs @@ -2377,17 +2377,14 @@ impl Machine { reset_refs!(); } Opcode::SwitchThread => { - let next_recovery = (inst.argument_data != 0) - .then(|| inst.argument_data - 1) - .map(|x| self.pc.add(x.try_into().unwrap())); - - if next_recovery.is_some() == self.thread_state.is_cothread() { + let next_recovery = match inst.argument_data { + 0 => ThreadState::Main, + x => ThreadState::CoThread(self.pc.add((x - 1).try_into().unwrap())), + }; + if next_recovery.is_cothread() == self.thread_state.is_cothread() { error!("SwitchThread doesn't switch") } - self.thread_state = match next_recovery { - Some(pc) => ThreadState::CoThread(pc), - None => ThreadState::Main, - }; + self.thread_state = next_recovery; reset_refs!(); } } diff --git a/arbitrator/wasm-libraries/user-host/src/program.rs b/arbitrator/wasm-libraries/user-host/src/program.rs index 925c09860..d456fe198 100644 --- a/arbitrator/wasm-libraries/user-host/src/program.rs +++ b/arbitrator/wasm-libraries/user-host/src/program.rs @@ -96,7 +96,7 @@ impl UserHostRequester { ) { self.answer = Some((result, VecReader::new(raw_data), gas)); if req_id != self.id { - panic!("bad eq id returning from send_request") + panic!("bad req id returning from send_request") } compiler_fence(Ordering::SeqCst); } diff --git a/arbos/programs/api.go b/arbos/programs/api.go index edc2bb0cd..9369cc626 100644 --- a/arbos/programs/api.go +++ b/arbos/programs/api.go @@ -260,7 +260,7 @@ func newApiClosures( takeHash := func() common.Hash { return common.BytesToHash(takeInput(32, "expected hash")) } - takeBig := func() *big.Int { + takeU256 := func() *big.Int { return common.BytesToHash(takeInput(32, "expected big")).Big() } takeU64 := func() uint64 { @@ -307,7 +307,7 @@ func newApiClosures( log.Crit("unsupported call type", "opcode", opcode) } contract := takeAddress() - value := takeBig() + value := takeU256() gas := takeU64() calldata := takeRest() @@ -319,10 +319,10 @@ func newApiClosures( return []byte{statusByte}, ret, cost case Create1, Create2: gas := takeU64() - endowment := takeBig() + endowment := takeU256() var salt *big.Int if req == Create2 { - salt = takeBig() + salt = takeU256() } code := takeRest() From 134b103aec8b52ee865926a981df7e9040ea341b Mon Sep 17 00:00:00 2001 From: Tsahi Zidenberg Date: Fri, 8 Mar 2024 14:23:47 -0700 Subject: [PATCH 27/28] reintroduce execEnv print_string --- arbitrator/caller-env/src/lib.rs | 2 ++ arbitrator/caller-env/src/static_caller.rs | 5 +++ arbitrator/caller-env/src/wasip1_stub.rs | 7 ++-- arbitrator/jit/src/caller_env.rs | 10 ++++++ arbitrator/jit/src/machine.rs | 2 +- arbitrator/jit/src/wasip1_stub.rs | 39 ++++------------------ 6 files changed, 28 insertions(+), 37 deletions(-) diff --git a/arbitrator/caller-env/src/lib.rs b/arbitrator/caller-env/src/lib.rs index 65700081f..39ee65e59 100644 --- a/arbitrator/caller-env/src/lib.rs +++ b/arbitrator/caller-env/src/lib.rs @@ -61,4 +61,6 @@ pub trait ExecEnv { fn get_time(&self) -> u64; fn next_rand_u32(&mut self) -> u32; + + fn print_string(&mut self, message: &[u8]); } diff --git a/arbitrator/caller-env/src/static_caller.rs b/arbitrator/caller-env/src/static_caller.rs index 21547c143..46a2a3f48 100644 --- a/arbitrator/caller-env/src/static_caller.rs +++ b/arbitrator/caller-env/src/static_caller.rs @@ -100,6 +100,11 @@ impl MemAccess for StaticMem { } impl ExecEnv for StaticExecEnv { + fn print_string(&mut self, _data: &[u8]) { + // printing is done by arbitrator machine host_call_hook + // capturing the fd_write call directly + } + fn get_time(&self) -> u64 { unsafe { TIME } } diff --git a/arbitrator/caller-env/src/wasip1_stub.rs b/arbitrator/caller-env/src/wasip1_stub.rs index 075f05971..75fc03e73 100644 --- a/arbitrator/caller-env/src/wasip1_stub.rs +++ b/arbitrator/caller-env/src/wasip1_stub.rs @@ -68,12 +68,9 @@ pub fn environ_get( /// Writes to the given file descriptor. /// Note that we only support stdout and stderr. -/// Writing to output doesn't happen here. -/// in arbitrator that's in host_call_hook, -/// in jit it's in fd_write_wrapper pub fn fd_write( mem: &mut M, - _env: &mut E, + env: &mut E, fd: u32, iovecs_ptr: GuestPtr, iovecs_len: u32, @@ -86,6 +83,8 @@ pub fn fd_write( for i in 0..iovecs_len { let ptr = iovecs_ptr + i * 8; let len = mem.read_u32(ptr + 4); + let data = mem.read_slice(ptr, len as usize); + env.print_string(&data); size += len; } mem.write_u32(ret_ptr, size); diff --git a/arbitrator/jit/src/caller_env.rs b/arbitrator/jit/src/caller_env.rs index f81fedc79..ed61f52db 100644 --- a/arbitrator/jit/src/caller_env.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -133,6 +133,16 @@ impl ExecEnv for JitExecEnv<'_> { fn next_rand_u32(&mut self) -> u32 { self.wenv.go_state.rng.next_u32() } + + fn print_string(&mut self, bytes: &[u8]) { + match String::from_utf8(bytes.to_vec()) { + Ok(s) => eprintln!("JIT: WASM says: {s}"), + Err(e) => { + let bytes = e.as_bytes(); + eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); + } + } + } } pub struct GoRuntimeState { diff --git a/arbitrator/jit/src/machine.rs b/arbitrator/jit/src/machine.rs index b6ebcd282..a15c0256e 100644 --- a/arbitrator/jit/src/machine.rs +++ b/arbitrator/jit/src/machine.rs @@ -81,7 +81,7 @@ pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv, Sto "wasi_snapshot_preview1" => { "proc_exit" => func!(wasip1_stub::proc_exit), "environ_sizes_get" => func!(wasip1_stub::environ_sizes_get), - "fd_write" => func!(wasip1_stub::fd_write_wrapper), + "fd_write" => func!(wasip1_stub::fd_write), "environ_get" => func!(wasip1_stub::environ_get), "fd_close" => func!(wasip1_stub::fd_close), "fd_read" => func!(wasip1_stub::fd_read), diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index 61ff1bc25..e1e91366e 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -5,43 +5,12 @@ use crate::caller_env::jit_env; use crate::machine::{Escape, WasmEnvMut}; -use caller_env::{ - self, - wasip1_stub::{Errno, ERRNO_BADF, ERRNO_SUCCESS}, - GuestPtr, MemAccess, -}; +use caller_env::{self, wasip1_stub::Errno, GuestPtr}; pub fn proc_exit(mut _env: WasmEnvMut, code: u32) -> Result<(), Escape> { Err(Escape::Exit(code)) } -// implements arbitrator machine's host-call hook around fd_write -pub fn fd_write_wrapper( - mut src: WasmEnvMut, - fd: u32, - iovecs_ptr: GuestPtr, - iovecs_len: u32, - ret_ptr: GuestPtr, -) -> Errno { - if fd != 1 && fd != 2 { - return ERRNO_BADF; - } - let (mut mem, mut env) = jit_env(&mut src); - for i in 0..iovecs_len { - let ptr = iovecs_ptr + i * 8; - let len = mem.read_u32(ptr + 4); - let data = mem.read_slice(ptr, len as usize); - match String::from_utf8(data) { - Ok(s) => eprintln!("JIT: WASM says: {s}"), - Err(e) => { - let bytes = e.as_bytes(); - eprintln!("Go string {} is not valid utf8: {e:?}", hex::encode(bytes)); - } - } - } - caller_env::wasip1_stub::fd_write(&mut mem, &mut env, fd, iovecs_ptr, iovecs_len, ret_ptr) -} - macro_rules! wrap { ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { $( @@ -68,6 +37,12 @@ wrap! { fn fd_read(a: u32, b: u32, c: u32, d: u32) -> Errno; fn fd_close(fd: u32) -> Errno; + fn fd_write( + fd: u32, + iovecs_ptr: GuestPtr, + iovecs_len: u32, + ret_ptr: GuestPtr + ) -> Errno; fn fd_readdir( fd: u32, From 8cfb8c433bfc74cd9d47e21a8f8919e90af5f315 Mon Sep 17 00:00:00 2001 From: Rachel Bousfield Date: Fri, 8 Mar 2024 14:44:16 -0700 Subject: [PATCH 28/28] cleanup & remove guestptr DerefMut --- arbitrator/caller-env/src/guest_ptr.rs | 8 +------- arbitrator/jit/src/arbcompress.rs | 6 +++--- arbitrator/jit/src/caller_env.rs | 6 ------ arbitrator/jit/src/wasip1_stub.rs | 6 +++--- 4 files changed, 7 insertions(+), 19 deletions(-) diff --git a/arbitrator/caller-env/src/guest_ptr.rs b/arbitrator/caller-env/src/guest_ptr.rs index a5926394e..566d2d61d 100644 --- a/arbitrator/caller-env/src/guest_ptr.rs +++ b/arbitrator/caller-env/src/guest_ptr.rs @@ -1,7 +1,7 @@ // Copyright 2024, Offchain Labs, Inc. // For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE -use core::ops::{Add, AddAssign, Deref, DerefMut}; +use core::ops::{Add, AddAssign, Deref}; /// Represents a pointer to a Guest WASM's memory. #[derive(Clone, Copy, Eq, PartialEq)] @@ -41,9 +41,3 @@ impl Deref for GuestPtr { &self.0 } } - -impl DerefMut for GuestPtr { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} diff --git a/arbitrator/jit/src/arbcompress.rs b/arbitrator/jit/src/arbcompress.rs index 5b751b594..6815a480e 100644 --- a/arbitrator/jit/src/arbcompress.rs +++ b/arbitrator/jit/src/arbcompress.rs @@ -1,7 +1,7 @@ // Copyright 2022-2024, Offchain Labs, Inc. // For license information, see https://github.com/nitro/blob/master/LICENSE -use crate::caller_env::jit_env; +use crate::caller_env::{JitEnv, JitExecEnv}; use crate::machine::Escape; use crate::machine::WasmEnvMut; use caller_env::brotli::BrotliStatus; @@ -11,9 +11,9 @@ macro_rules! wrap { ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { $( pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let (mut mem, mut env) = jit_env(&mut src); + let (mut mem, wenv) = src.jit_env(); - Ok(caller_env::brotli::$func_name(&mut mem, &mut env, $($arg_name),*)) + Ok(caller_env::brotli::$func_name(&mut mem, &mut JitExecEnv { wenv }, $($arg_name),*)) } )* }; diff --git a/arbitrator/jit/src/caller_env.rs b/arbitrator/jit/src/caller_env.rs index ed61f52db..ac1b8d70d 100644 --- a/arbitrator/jit/src/caller_env.rs +++ b/arbitrator/jit/src/caller_env.rs @@ -35,12 +35,6 @@ impl<'a> JitEnv<'a> for WasmEnvMut<'a> { } } -pub fn jit_env<'s>(env: &'s mut WasmEnvMut) -> (JitMemAccess<'s>, JitExecEnv<'s>) { - let memory = env.data().memory.clone().unwrap(); - let (wenv, store) = env.data_and_store_mut(); - (JitMemAccess { memory, store }, JitExecEnv { wenv }) -} - impl<'s> JitMemAccess<'s> { fn view(&self) -> MemoryView { self.memory.view(&self.store) diff --git a/arbitrator/jit/src/wasip1_stub.rs b/arbitrator/jit/src/wasip1_stub.rs index e1e91366e..0b525e6a9 100644 --- a/arbitrator/jit/src/wasip1_stub.rs +++ b/arbitrator/jit/src/wasip1_stub.rs @@ -3,7 +3,7 @@ #![allow(clippy::too_many_arguments)] -use crate::caller_env::jit_env; +use crate::caller_env::{JitEnv, JitExecEnv}; use crate::machine::{Escape, WasmEnvMut}; use caller_env::{self, wasip1_stub::Errno, GuestPtr}; @@ -15,9 +15,9 @@ macro_rules! wrap { ($(fn $func_name:ident ($($arg_name:ident : $arg_type:ty),* ) -> $return_type:ty);*) => { $( pub fn $func_name(mut src: WasmEnvMut, $($arg_name : $arg_type),*) -> Result<$return_type, Escape> { - let (mut mem, mut env) = jit_env(&mut src); + let (mut mem, wenv) = src.jit_env(); - Ok(caller_env::wasip1_stub::$func_name(&mut mem, &mut env, $($arg_name),*)) + Ok(caller_env::wasip1_stub::$func_name(&mut mem, &mut JitExecEnv { wenv }, $($arg_name),*)) } )* };