Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
thirdkeyword authored Dec 19, 2024
2 parents 3a64860 + 36ac667 commit 703223a
Show file tree
Hide file tree
Showing 79 changed files with 6,305 additions and 1,005 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
redis:
image: redis
ports:
- 6379:6379
- 6379:6379

strategy:
fail-fast: false
Expand Down Expand Up @@ -192,7 +192,7 @@ jobs:
- name: run challenge tests
if: matrix.test-mode == 'challenge'
run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags challengetest --run TestChallenge --cover
run: ${{ github.workspace }}/.github/workflows/gotestsum.sh --tags challengetest --run TestChallenge --timeout 60m --cover

- name: run stylus tests
if: matrix.test-mode == 'stylus'
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
[submodule "nitro-testnode"]
path = nitro-testnode
url = https://github.com/OffchainLabs/nitro-testnode.git
[submodule "bold"]
path = bold
url = https://github.com/OffchainLabs/bold.git
[submodule "arbitrator/langs/rust"]
path = arbitrator/langs/rust
url = https://github.com/OffchainLabs/stylus-sdk-rs.git
Expand Down
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ RUN export DEBIAN_FRONTEND=noninteractive && \
COPY go.mod go.sum ./
COPY go-ethereum/go.mod go-ethereum/go.sum go-ethereum/
COPY fastcache/go.mod fastcache/go.sum fastcache/
COPY bold/go.mod bold/go.sum bold/
RUN go mod download
COPY . ./
COPY --from=contracts-builder workspace/contracts/build/ contracts/build/
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Additional Use Grant: You may use the Licensed Work in a production environment
validating the correctness of the posted chain state, or to deploy
and operate (x) a blockchain that settles to a Covered Arbitrum Chain
or (y) a blockchain in accordance with, and subject to, the [Arbitrum
Expansion Program Term of Use](https://docs.arbitrum.foundation/assets/files/Arbitrum%20Expansion%20Program%20Jan182024-4f08b0c2cb476a55dc153380fa3e64b0.pdf). For purposes of this
Expansion Program Term of Use](https://docs.arbitrum.foundation/aep/ArbitrumExpansionProgramTerms.pdf). For purposes of this
Additional Use Grant, the "Covered Arbitrum Chains" are
(a) Arbitrum One (chainid:42161), Arbitrum Nova (chainid:42170),
Arbitrum Rinkeby testnet/Rinkarby (chainid:421611),Arbitrum Nitro
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Nitro is currently licensed under a [Business Source License](./LICENSE.md), sim

The Additional Use Grant also permits the deployment of the Nitro software, in a permissionless fashion and without cost, as a new blockchain provided that the chain settles to either Arbitrum One or Arbitrum Nova.

For those that prefer to deploy the Nitro software either directly on Ethereum (i.e. an L2) or have it settle to another Layer-2 on top of Ethereum, the [Arbitrum Expansion Program (the "AEP")](https://docs.arbitrum.foundation/assets/files/Arbitrum%20Expansion%20Program%20Jan182024-4f08b0c2cb476a55dc153380fa3e64b0.pdf) was recently established. The AEP allows for the permissionless deployment in the aforementioned fashion provided that 10% of net revenue (as more fully described in the AEP) is contributed back to the Arbitrum community in accordance with the requirements of the AEP.
For those that prefer to deploy the Nitro software either directly on Ethereum (i.e. an L2) or have it settle to another Layer-2 on top of Ethereum, the [Arbitrum Expansion Program (the "AEP")](https://docs.arbitrum.foundation/aep/ArbitrumExpansionProgramTerms.pdf) was recently established. The AEP allows for the permissionless deployment in the aforementioned fashion provided that 10% of net revenue (as more fully described in the AEP) is contributed back to the Arbitrum community in accordance with the requirements of the AEP.

## Contact

Expand Down
85 changes: 68 additions & 17 deletions arbitrator/prover/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use once_cell::sync::OnceCell;
use static_assertions::const_assert_eq;
use std::{
ffi::CStr,
marker::PhantomData,
num::NonZeroUsize,
os::raw::{c_char, c_int},
path::Path,
Expand All @@ -59,11 +60,67 @@ pub struct CByteArray {
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct RustByteArray {
pub struct RustSlice<'a> {
pub ptr: *const u8,
pub len: usize,
pub phantom: PhantomData<&'a [u8]>,
}

impl<'a> RustSlice<'a> {
pub fn new(slice: &'a [u8]) -> Self {
if slice.is_empty() {
return Self {
ptr: ptr::null(),
len: 0,
phantom: PhantomData,
};
}
Self {
ptr: slice.as_ptr(),
len: slice.len(),
phantom: PhantomData,
}
}
}

#[repr(C)]
pub struct RustBytes {
pub ptr: *mut u8,
pub len: usize,
pub capacity: usize,
pub cap: usize,
}

impl RustBytes {
pub unsafe fn into_vec(self) -> Vec<u8> {
Vec::from_raw_parts(self.ptr, self.len, self.cap)
}

pub unsafe fn write(&mut self, mut vec: Vec<u8>) {
if vec.capacity() == 0 {
*self = RustBytes {
ptr: ptr::null_mut(),
len: 0,
cap: 0,
};
return;
}
self.ptr = vec.as_mut_ptr();
self.len = vec.len();
self.cap = vec.capacity();
std::mem::forget(vec);
}
}

/// Frees the vector. Does nothing when the vector is null.
///
/// # Safety
///
/// Must only be called once per vec.
#[no_mangle]
pub unsafe extern "C" fn free_rust_bytes(vec: RustBytes) {
if !vec.ptr.is_null() {
drop(vec.into_vec())
}
}

#[no_mangle]
Expand Down Expand Up @@ -127,6 +184,12 @@ pub unsafe extern "C" fn arbitrator_load_wavm_binary(binary_path: *const c_char)
}
}

#[no_mangle]
#[cfg(feature = "native")]
pub unsafe extern "C" fn arbitrator_new_finished(gs: GlobalState) -> *mut Machine {
Box::into_raw(Box::new(Machine::new_finished(gs)))
}

unsafe fn cstr_to_string(c_str: *const c_char) -> String {
CStr::from_ptr(c_str).to_string_lossy().into_owned()
}
Expand Down Expand Up @@ -404,18 +467,6 @@ pub unsafe extern "C" fn arbitrator_module_root(mach: *mut Machine) -> Bytes32 {

#[no_mangle]
#[cfg(feature = "native")]
pub unsafe extern "C" fn arbitrator_gen_proof(mach: *mut Machine) -> RustByteArray {
let mut proof = (*mach).serialize_proof();
let ret = RustByteArray {
ptr: proof.as_mut_ptr(),
len: proof.len(),
capacity: proof.capacity(),
};
std::mem::forget(proof);
ret
}

#[no_mangle]
pub unsafe extern "C" fn arbitrator_free_proof(proof: RustByteArray) {
drop(Vec::from_raw_parts(proof.ptr, proof.len, proof.capacity))
pub unsafe extern "C" fn arbitrator_gen_proof(mach: *mut Machine, out: *mut RustBytes) {
(*out).write((*mach).serialize_proof());
}
39 changes: 39 additions & 0 deletions arbitrator/prover/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1565,6 +1565,36 @@ impl Machine {
Ok(mach)
}

// new_finished returns a Machine in the Finished state at step 0.
//
// This allows the Mahine to be set up to model the final state of the
// machine at the end of the execution of a block.
pub fn new_finished(gs: GlobalState) -> Machine {
Machine {
steps: 0,
status: MachineStatus::Finished,
global_state: gs,
// The machine is in the Finished state, so nothing else really matters.
// values_stacks and frame_stacks cannot be empty for proof serialization,
// but everything else can just be entirely blank.
thread_state: ThreadState::Main,
value_stacks: vec![Vec::new()],
frame_stacks: vec![Vec::new()],
internal_stack: Default::default(),
modules: Default::default(),
modules_merkle: Default::default(),
pc: Default::default(),
stdio_output: Default::default(),
inbox_contents: Default::default(),
first_too_far: Default::default(),
preimage_resolver: PreimageResolverWrapper::new(Arc::new(|_, _, _| None)),
stylus_modules: Default::default(),
initial_hash: Default::default(),
context: Default::default(),
debug_info: Default::default(),
}
}

pub fn new_from_wavm(wavm_binary: &Path) -> Result<Machine> {
let mut modules: Vec<Module> = {
let compressed = std::fs::read(wavm_binary)?;
Expand Down Expand Up @@ -2867,6 +2897,15 @@ impl Machine {
let mod_merkle = self.get_modules_merkle();
out!(mod_merkle.root());

if self.is_halted() {
// If the machine is halted, instead of serializing the module,
// serialize the global state and return.
// This is for the "kickstart" BoLD proof, but it's backwards compatible
// with the old OSP behavior which reads no further.
out!(self.global_state.serialize());
return data;
}

// End machine serialization, serialize module

let module = &self.modules[self.pc.module()];
Expand Down
3 changes: 2 additions & 1 deletion arbitrator/stylus/src/evm_api.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Copyright 2022-2024, Offchain Labs, Inc.
// For license information, see https://github.com/OffchainLabs/nitro/blob/master/LICENSE

use crate::{GoSliceData, RustSlice};
use crate::GoSliceData;
use arbutil::evm::{
api::{EvmApiMethod, Gas, EVM_API_METHOD_REQ_OFFSET},
req::RequestHandler,
};
use prover::RustSlice;

#[repr(C)]
pub struct NativeRequestHandler {
Expand Down
90 changes: 22 additions & 68 deletions arbitrator/stylus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ use cache::{deserialize_module, CacheMetrics, InitCache};
use evm_api::NativeRequestHandler;
use eyre::ErrReport;
use native::NativeInstance;
use prover::programs::{prelude::*, StylusData};
use prover::{
programs::{prelude::*, StylusData},
RustBytes,
};
use run::RunProgram;
use std::{marker::PhantomData, mem, ptr};
use std::ptr;
use target_cache::{target_cache_get, target_cache_set};

pub use brotli;
Expand Down Expand Up @@ -76,52 +79,15 @@ impl DataReader for GoSliceData {
}
}

#[repr(C)]
pub struct RustSlice<'a> {
ptr: *const u8,
len: usize,
phantom: PhantomData<&'a [u8]>,
}

impl<'a> RustSlice<'a> {
fn new(slice: &'a [u8]) -> Self {
Self {
ptr: slice.as_ptr(),
len: slice.len(),
phantom: PhantomData,
}
}
}

#[repr(C)]
pub struct RustBytes {
ptr: *mut u8,
len: usize,
cap: usize,
unsafe fn write_err(output: &mut RustBytes, err: ErrReport) -> UserOutcomeKind {
output.write(err.debug_bytes());
UserOutcomeKind::Failure
}

impl RustBytes {
unsafe fn into_vec(self) -> Vec<u8> {
Vec::from_raw_parts(self.ptr, self.len, self.cap)
}

unsafe fn write(&mut self, mut vec: Vec<u8>) {
self.ptr = vec.as_mut_ptr();
self.len = vec.len();
self.cap = vec.capacity();
mem::forget(vec);
}

unsafe fn write_err(&mut self, err: ErrReport) -> UserOutcomeKind {
self.write(err.debug_bytes());
UserOutcomeKind::Failure
}

unsafe fn write_outcome(&mut self, outcome: UserOutcome) -> UserOutcomeKind {
let (status, outs) = outcome.into_data();
self.write(outs);
status
}
unsafe fn write_outcome(output: &mut RustBytes, outcome: UserOutcome) -> UserOutcomeKind {
let (status, outs) = outcome.into_data();
output.write(outs);
status
}

/// "activates" a user wasm.
Expand Down Expand Up @@ -164,7 +130,7 @@ pub unsafe extern "C" fn stylus_activate(
gas,
) {
Ok(val) => val,
Err(err) => return output.write_err(err),
Err(err) => return write_err(output, err),
};

*module_hash = module.hash();
Expand Down Expand Up @@ -194,16 +160,16 @@ pub unsafe extern "C" fn stylus_compile(
let output = &mut *output;
let name = match String::from_utf8(name.slice().to_vec()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
Err(err) => return write_err(output, err.into()),
};
let target = match target_cache_get(&name) {
Ok(val) => val,
Err(err) => return output.write_err(err),
Err(err) => return write_err(output, err),
};

let asm = match native::compile(wasm, version, debug, target) {
Ok(val) => val,
Err(err) => return output.write_err(err),
Err(err) => return write_err(output, err),
};

output.write(asm);
Expand All @@ -218,7 +184,7 @@ pub unsafe extern "C" fn wat_to_wasm(wat: GoSliceData, output: *mut RustBytes) -
let output = &mut *output;
let wasm = match wasmer::wat2wasm(wat.slice()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
Err(err) => return write_err(output, err.into()),
};
output.write(wasm.into_owned());
UserOutcomeKind::Success
Expand All @@ -241,16 +207,16 @@ pub unsafe extern "C" fn stylus_target_set(
let output = &mut *output;
let name = match String::from_utf8(name.slice().to_vec()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
Err(err) => return write_err(output, err.into()),
};

let desc_str = match String::from_utf8(description.slice().to_vec()) {
Ok(val) => val,
Err(err) => return output.write_err(err.into()),
Err(err) => return write_err(output, err.into()),
};

if let Err(err) = target_cache_set(name, desc_str, native) {
return output.write_err(err);
return write_err(output, err);
};

UserOutcomeKind::Success
Expand Down Expand Up @@ -298,8 +264,8 @@ pub unsafe extern "C" fn stylus_call(
};

let status = match instance.run_main(&calldata, config, ink) {
Err(e) | Ok(UserOutcome::Failure(e)) => output.write_err(e.wrap_err("call failed")),
Ok(outcome) => output.write_outcome(outcome),
Err(e) | Ok(UserOutcome::Failure(e)) => write_err(output, e.wrap_err("call failed")),
Ok(outcome) => write_outcome(output, outcome),
};
let ink_left = match status {
UserOutcomeKind::OutOfStack => Ink(0), // take all gas when out of stack
Expand Down Expand Up @@ -352,18 +318,6 @@ pub extern "C" fn stylus_reorg_vm(_block: u64, arbos_tag: u32) {
InitCache::clear_long_term(arbos_tag);
}

/// Frees the vector. Does nothing when the vector is null.
///
/// # Safety
///
/// Must only be called once per vec.
#[no_mangle]
pub unsafe extern "C" fn stylus_drop_vec(vec: RustBytes) {
if !vec.ptr.is_null() {
mem::drop(vec.into_vec())
}
}

/// Gets cache metrics.
///
/// # Safety
Expand Down
Loading

0 comments on commit 703223a

Please sign in to comment.