Skip to content

Commit

Permalink
fixed, simplifications, and MiniAlloc
Browse files Browse the repository at this point in the history
  • Loading branch information
rachel-bousfield committed Mar 8, 2024
1 parent 7d60088 commit d76b355
Show file tree
Hide file tree
Showing 32 changed files with 180 additions and 234 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 $@

Expand Down
13 changes: 10 additions & 3 deletions arbcompress/compress_wasm.go
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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")
}
Expand All @@ -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")
}
Expand Down
10 changes: 5 additions & 5 deletions arbitrator/arbutil/src/evm/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>>);

Expand Down
2 changes: 1 addition & 1 deletion arbitrator/arbutil/src/evm/req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
use eyre::{bail, eyre, Result};

pub trait RequestHandler<D: DataReader>: Send + 'static {
fn handle_request(&mut self, _req_type: EvmApiMethod, _req_data: &[u8]) -> (Vec<u8>, D, u64);
fn handle_request(&mut self, req_type: EvmApiMethod, req_data: &[u8]) -> (Vec<u8>, D, u64);
}

pub struct EvmApiRequestor<D: DataReader, H: RequestHandler<D>> {
Expand Down
25 changes: 16 additions & 9 deletions arbitrator/arbutil/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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.
Expand All @@ -21,7 +22,13 @@ pub fn heapify<T>(value: T) -> *mut T {
}

/// Equivalent to &[start..offset], but truncates when out of bounds rather than panicking.
pub fn slice_with_runoff<T>(data: &impl AsRef<[T]>, start: usize, end: usize) -> &[T] {
pub fn slice_with_runoff<T, I>(data: &impl AsRef<[T]>, start: I, end: I) -> &[T]
where
I: TryInto<usize> + 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 &[];
Expand All @@ -32,12 +39,12 @@ pub fn slice_with_runoff<T>(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]);
}
17 changes: 8 additions & 9 deletions arbitrator/jit/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ pub fn start_program(mut env: WasmEnvMut, module: u32) -> Result<u32, Escape> {
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<u32, Escape> {
let (mut mem, exec) = jit_env(&mut env);
let thread = exec.wenv.threads.last_mut().unwrap();
Expand All @@ -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,
Expand All @@ -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<u32, Escape> {
let (_, exec) = jit_env(&mut env);
let thread = exec.wenv.threads.last_mut().unwrap();
Expand All @@ -182,7 +182,7 @@ pub fn send_response(mut env: WasmEnvMut, req_id: u32) -> Result<u32, Escape> {
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);

Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion arbitrator/jit/src/stylus_backend.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion arbitrator/prover/src/wavm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

Expand Down
2 changes: 1 addition & 1 deletion arbitrator/prover/test-cases/go/main.go
Original file line number Diff line number Diff line change
@@ -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
Expand Down
2 changes: 1 addition & 1 deletion arbitrator/stylus/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ extra_bindings = ["arbutil", "prover"]
prefix_with_name = true

[export]
include = ["EvmApiMethod", "EvmApiMethodOffset"]
include = ["EvmApiMethod"]
16 changes: 8 additions & 8 deletions arbitrator/stylus/src/evm_api.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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,
}

Expand All @@ -26,14 +26,14 @@ macro_rules! ptr {
};
}

impl RequestHandler<SendGoSliceData> for NativeRequestHandler {
impl RequestHandler<GoSliceData> for NativeRequestHandler {
fn handle_request(
&mut self,
req_type: EvmApiMethod,
req_data: &[u8],
) -> (Vec<u8>, SendGoSliceData, u64) {
let mut result = GoSliceData::default();
let mut raw_data = SendGoSliceData::default();
) -> (Vec<u8>, GoSliceData, u64) {
let mut result = GoSliceData::null();
let mut raw_data = GoSliceData::null();
let mut cost = 0;
let status = unsafe {
(self.handle_request_fptr)(
Expand Down
12 changes: 3 additions & 9 deletions arbitrator/stylus/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,17 +70,11 @@ impl<'a, DR: DataReader, A: EvmApi<DR>> UserHost<DR> 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<u64, Self::Err> {
if !self.env.evm_data.tracing {
return Err(eyre!("recording start ink when not captured").into());
}
Ok(self.start_ink)
}
}

macro_rules! hostio {
Expand Down
68 changes: 14 additions & 54 deletions arbitrator/stylus/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;

Expand All @@ -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 &[];
Expand All @@ -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::<GoSliceData>() == mem::size_of::<SendGoSliceData>());
}

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) }
}
}

Expand Down Expand Up @@ -110,16 +94,6 @@ pub struct RustBytes {
}

impl RustBytes {
fn new(vec: Vec<u8>) -> 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<u8> {
Vec::from_raw_parts(self.ptr, self.len, self.cap)
}
Expand Down Expand Up @@ -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);
}
Loading

0 comments on commit d76b355

Please sign in to comment.