Skip to content

Commit

Permalink
Merge pull request #47 from OffchainLabs/stylus-contract-calls
Browse files Browse the repository at this point in the history
Contract Calls
  • Loading branch information
rachel-bousfield authored Mar 29, 2023
2 parents 4e803ef + be6de5d commit 1a886bc
Show file tree
Hide file tree
Showing 43 changed files with 1,188 additions and 216 deletions.
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,12 @@ stylus_test_fallible_wasm = $(call get_stylus_test_wasm,fallible)
stylus_test_fallible_src = $(call get_stylus_test_rust,fallible)
stylus_test_storage_wasm = $(call get_stylus_test_wasm,storage)
stylus_test_storage_src = $(call get_stylus_test_rust,storage)
stylus_test_calls_wasm = $(call get_stylus_test_wasm,calls)
stylus_test_calls_src = $(call get_stylus_test_rust,calls)
stylus_test_siphash_wasm = $(stylus_test_dir)/siphash/siphash.wasm
stylus_test_siphash_src = $(call get_stylus_test_c,siphash)

stylus_test_wasms = $(stylus_test_keccak_wasm) $(stylus_test_keccak-100_wasm) $(stylus_test_fallible_wasm) $(stylus_test_storage_wasm) $(stylus_test_siphash_wasm)
stylus_test_wasms = $(stylus_test_keccak_wasm) $(stylus_test_keccak-100_wasm) $(stylus_test_fallible_wasm) $(stylus_test_storage_wasm) $(stylus_test_siphash_wasm) $(stylus_test_calls_wasm)
stylus_benchmarks = $(wildcard $(stylus_dir)/*.toml $(stylus_dir)/src/*.rs) $(stylus_test_wasms)
stylus_files = $(wildcard $(stylus_dir)/*.toml $(stylus_dir)/src/*.rs) $(rust_prover_files)

Expand Down Expand Up @@ -342,6 +344,10 @@ $(stylus_test_storage_wasm): $(stylus_test_storage_src)
cargo build --manifest-path $< --release --target wasm32-unknown-unknown
@touch -c $@ # cargo might decide to not rebuild the binary

$(stylus_test_calls_wasm): $(stylus_test_calls_src)
cargo build --manifest-path $< --release --target wasm32-unknown-unknown
@touch -c $@ # cargo might decide to not rebuild the binary

$(stylus_test_siphash_wasm): $(stylus_test_siphash_src)
clang $(filter %.c, $^) -o $@ --target=wasm32 --no-standard-libraries -Wl,--no-entry -Oz

Expand Down
22 changes: 22 additions & 0 deletions arbitrator/Cargo.lock

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

33 changes: 14 additions & 19 deletions arbitrator/jit/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,28 @@ pub fn call_user_wasm(env: WasmEnvMut, sp: u32) {
// skip the root since we don't use these
sp.skip_u64();

macro_rules! error {
($msg:expr, $report:expr) => {{
let outs = format!("{:?}", $report.wrap_err(eyre!($msg))).into_bytes();
sp.write_u8(UserOutcomeKind::Failure as u8).skip_space();
sp.write_ptr(heapify(outs));
if pricing.wasm_gas_price != 0 {
sp.write_u64_raw(evm_gas, pricing.wasm_to_evm(wasm_gas));
}
return;
}};
}

// Safety: module came from compile_user_wasm
let instance = unsafe { NativeInstance::deserialize(&module, config.clone()) };

let mut instance = match instance {
Ok(instance) => instance,
Err(error) => error!("failed to instantiate program", error),
Err(error) => panic!("failed to instantiate program {error:?}"),
};
instance.set_gas(wasm_gas);
instance.set_stack(config.depth.max_depth);

let (status, outs) = match instance.run_main(&calldata, &config) {
Err(err) | Ok(UserOutcome::Failure(err)) => error!("failed to execute program", err),
Ok(outcome) => outcome.into_data(),
let status = match instance.run_main(&calldata, &config) {
Err(err) | Ok(UserOutcome::Failure(err)) => {
let outs = format!("{:?}", err.wrap_err(eyre!("failed to execute program")));
sp.write_u8(UserOutcomeKind::Failure as u8).skip_space();
sp.write_ptr(heapify(outs.into_bytes()));
UserOutcomeKind::Failure
}
Ok(outcome) => {
let (status, outs) = outcome.into_data();
sp.write_u8(status as u8).skip_space();
sp.write_ptr(heapify(outs));
status
}
};
if pricing.wasm_gas_price != 0 {
let wasm_gas = match status {
Expand All @@ -83,8 +80,6 @@ pub fn call_user_wasm(env: WasmEnvMut, sp: u32) {
};
sp.write_u64_raw(evm_gas, pricing.wasm_to_evm(wasm_gas));
}
sp.write_u8(status as u8).skip_space();
sp.write_ptr(heapify(outs));
}

/// Reads the length of a rust `Vec`
Expand Down
65 changes: 65 additions & 0 deletions arbitrator/langs/rust/src/contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright 2023, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

use super::util::{Bytes20, Bytes32};

#[derive(Copy, Clone)]
#[repr(C)]
struct RustVec {
ptr: *mut u8,
len: usize,
cap: usize,
}

impl Default for RustVec {
fn default() -> Self {
Self {
ptr: std::ptr::null_mut(),
len: 0,
cap: 0,
}
}
}

#[link(wasm_import_module = "forward")]
extern "C" {
fn call_contract(
contract: *const u8,
calldata: *const u8,
calldata_len: usize,
value: *const u8,
gas: u64,
return_data_len: *mut usize,
) -> u8;

/// A noop when there's never been a call
fn read_return_data(dest: *mut u8);
}

/// Calls the contract at the given address, with options for passing value or limiting the amount of gas provided.
/// On failure, the output consists of the call's revert data.
pub fn call(contract: Bytes20, calldata: &[u8], value: Option<Bytes32>, gas: Option<u64>) -> Result<Vec<u8>, Vec<u8>> {
let mut outs_len = 0;
let value = value.unwrap_or_default();
let gas = gas.unwrap_or(u64::MAX); // will be clamped by 63/64 rule
let status = unsafe {
call_contract(
contract.ptr(),
calldata.as_ptr(),
calldata.len(),
value.ptr(),
gas,
&mut outs_len as *mut _,
)
};
let outs = unsafe {
let mut outs = Vec::with_capacity(outs_len);
read_return_data(outs.as_mut_ptr());
outs.set_len(outs_len);
outs
};
match status {
0 => Ok(outs),
_ => Err(outs),
}
}
1 change: 1 addition & 0 deletions arbitrator/langs/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

pub use util::{Bytes20, Bytes32};

pub mod contract;
pub mod debug;
mod util;

Expand Down
15 changes: 11 additions & 4 deletions arbitrator/langs/rust/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
use std::{array::TryFromSliceError, borrow::Borrow, fmt::{self, Debug, Display, Formatter}, ops::{Deref, DerefMut}};
// Copyright 2023, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

#[derive(Default)]
use std::{
array::TryFromSliceError,
borrow::Borrow,
fmt::{self, Debug, Display, Formatter},
ops::{Deref, DerefMut},
};

#[derive(Copy, Clone, Default)]
#[repr(C)]
pub struct Bytes20(pub [u8; 20]);

Expand Down Expand Up @@ -82,7 +90,7 @@ impl Debug for Bytes20 {
}
}

#[derive(Default)]
#[derive(Copy, Clone, Default)]
#[repr(C)]
pub struct Bytes32(pub [u8; 32]);

Expand Down Expand Up @@ -163,4 +171,3 @@ impl Debug for Bytes32 {
write!(f, "{}", hex::encode(self))
}
}

2 changes: 1 addition & 1 deletion arbitrator/prover/src/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ impl<'a> WasmBinary<'a> {
bound.update_module(self)?;
start.update_module(self)?;

let count = config.debug.count_ops.then(|| Counter::new());
let count = config.debug.count_ops.then(Counter::new);
if let Some(count) = &count {
count.update_module(self)?;
}
Expand Down
4 changes: 2 additions & 2 deletions arbitrator/prover/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::{
machine::{Function, InboxIdentifier},
programs::StylusGlobals,
programs::{run::UserOutcomeKind, StylusGlobals},
value::{ArbValueType, FunctionType, IntegerValType},
wavm::{IBinOpType, Instruction, Opcode},
};
Expand Down Expand Up @@ -202,7 +202,7 @@ pub fn get_host_impl(module: &str, name: &str) -> eyre::Result<Function> {
// λ(module, main, args_len) -> status
opcode!(PushErrorGuard);
opcode!(ArbitraryJumpIf, code.len() + 3);
opcode!(I32Const, 1);
opcode!(I32Const, UserOutcomeKind::Failure as u32);
opcode!(Return);

// jumps here in the happy case
Expand Down
2 changes: 2 additions & 0 deletions arbitrator/prover/src/programs/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2022-2023, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE

#![allow(clippy::field_reassign_with_default)]

use eyre::{bail, Result};
use std::fmt::Debug;
use wasmer_types::Bytes;
Expand Down
8 changes: 7 additions & 1 deletion arbitrator/prover/src/programs/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ impl Counter {
}
}

impl Default for Counter {
fn default() -> Self {
Self::new()
}
}

impl<M> Middleware<M> for Counter
where
M: ModuleMod,
Expand Down Expand Up @@ -115,7 +121,7 @@ impl<'a> FuncMiddleware<'a> for FuncCounter<'a> {
for (op, count) in increments {
let opslen = operators.len();
let offset = *operators.entry(op).or_insert(opslen);
let global = *counters.get(offset).ok_or(eyre!("no global"))?;
let global = *counters.get(offset).ok_or_else(|| eyre!("no global"))?;
out.extend(update(global.as_u32(), count));
}

Expand Down
11 changes: 10 additions & 1 deletion arbitrator/prover/src/programs/meter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::Machine;
use arbutil::operator::OperatorInfo;
use eyre::Result;
use parking_lot::Mutex;
use std::fmt::Debug;
use std::fmt::{Debug, Display};
use wasmer_types::{GlobalIndex, GlobalInit, LocalFunctionIndex, Type};
use wasmparser::{Operator, Type as WpType, TypeOrFuncType};

Expand Down Expand Up @@ -191,6 +191,15 @@ impl Into<u64> for MachineMeter {
}
}

impl Display for MachineMeter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ready(gas) => write!(f, "{gas} gas"),
Self::Exhausted => write!(f, "exhausted"),
}
}
}

/// Note: implementers may panic if uninstrumented
pub trait MeteredMachine {
fn gas_left(&mut self) -> MachineMeter;
Expand Down
16 changes: 15 additions & 1 deletion arbitrator/prover/src/programs/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,23 @@ impl Display for UserOutcome {
OutOfGas => write!(f, "out of gas"),
OutOfStack => write!(f, "out of stack"),
Revert(data) => {
let text = String::from_utf8(data.clone()).unwrap_or(hex::encode(data));
let text = String::from_utf8(data.clone()).unwrap_or_else(|_| hex::encode(data));
write!(f, "revert {text}")
}
}
}
}

impl Display for UserOutcomeKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let as_u8 = *self as u8;
use UserOutcomeKind::*;
match self {
Success => write!(f, "success ({as_u8})"),
Revert => write!(f, "revert ({as_u8})"),
Failure => write!(f, "failure ({as_u8})"),
OutOfGas => write!(f, "out of gas ({as_u8})"),
OutOfStack => write!(f, "out of stack ({as_u8})"),
}
}
}
1 change: 1 addition & 0 deletions arbitrator/stylus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ parking_lot = "0.12.1"
thiserror = "1.0.33"
libc = "0.2.108"
eyre = "0.6.5"
rand = "0.8.5"
fnv = "1.0.7"
sha3 = "0.10.5"
hex = "0.4.3"
Expand Down
3 changes: 3 additions & 0 deletions arbitrator/stylus/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ include_guard = "arbitrator_bindings"
parse_deps = true
include = ["prover"]
extra_bindings = ["prover"]

[enum]
prefix_with_name = true
Loading

0 comments on commit 1a886bc

Please sign in to comment.