Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arbos v32 debug #2671

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
cd1382f
turn max arbos versions to constants
tsahee Sep 10, 2024
6e29462
geth pin: add stylus_chargingfixes
tsahee Sep 13, 2024
36af58b
support arbos32 for debug chains
tsahee Sep 13, 2024
21ee5c5
revert mininitgas before arbos32
tsahee Sep 13, 2024
f70829a
contracts: take arbwasm fix
tsahee Sep 13, 2024
95160fb
arbitrator: add constant for arbos version for stylus charging fixes
tsahee Sep 13, 2024
71685cb
stylus: charge for wasm length in arbos v32
tsahee Sep 3, 2024
92ff55f
rename arbos_version param in activate and accept zero
tsahee Sep 3, 2024
c909f75
tempfix: stylus_version
tsahee Sep 13, 2024
8cd3a85
lint and reviewer input
tsahee Sep 13, 2024
48e4470
stylus: use new constant for arbos version
tsahee Sep 13, 2024
d9bcf83
move stylus arbos constant to arbutil/evm
tsahee Sep 13, 2024
de23783
Merge branch 'arbos_v32_debug' into stylus_activation_pricing
tsahee Sep 13, 2024
42e69a6
compilatio fix for constant change
tsahee Sep 13, 2024
c5bff79
cargo fmt
tsahee Sep 13, 2024
a219e3e
stylus: pass arbos_version in EvmData
tsahee Sep 13, 2024
0ca2aeb
stylus: fix gas overcharging in get_bytes32 for new arbos
tsahee Sep 13, 2024
12ac2e4
Merge remote-tracking branch 'origin/master' into arbos_v32_debug
tsahee Sep 13, 2024
f6fcf75
user-test build fix
tsahee Sep 13, 2024
e919082
Merge branch 'arbos_v32_debug' into arbwasm_revert_fix
tsahee Sep 16, 2024
8fd0ff4
Merge pull request #2677 from OffchainLabs/stylus_gas_ink_fixes
tsahee Sep 20, 2024
3befb69
Merge pull request #2672 from OffchainLabs/stylus_activation_pricing
tsahee Sep 20, 2024
6c62bf8
Merge pull request #2656 from OffchainLabs/arbwasm_revert_fix
tsahee Sep 20, 2024
70a24c3
Add JIT backwards compatibility test
PlasmaPower Sep 20, 2024
17834b0
JIT validation backwards compatibility
PlasmaPower Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion arbitrator/arbutil/src/evm/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub trait EvmApi<D: DataReader>: Send + 'static {
/// Reads the 32-byte value in the EVM state trie at offset `key`.
/// Returns the value and the access cost in gas.
/// Analogous to `vm.SLOAD`.
fn get_bytes32(&mut self, key: Bytes32) -> (Bytes32, u64);
fn get_bytes32(&mut self, key: Bytes32, evm_api_gas_to_use: u64) -> (Bytes32, u64);

/// Stores the given value at the given key in Stylus VM's cache of the EVM state trie.
/// Note that the actual values only get written after calls to `set_trie_slots`.
Expand Down
3 changes: 3 additions & 0 deletions arbitrator/arbutil/src/evm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,12 @@ pub const GASPRICE_GAS: u64 = GAS_QUICK_STEP;
// vm.GasQuickStep (see jump_table.go)
pub const ORIGIN_GAS: u64 = GAS_QUICK_STEP;

pub const ARBOS_VERSION_STYLUS_CHARGING_FIXES: u64 = 32;

#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct EvmData {
pub arbos_version: u64,
pub block_basefee: Bytes32,
pub chainid: u64,
pub block_coinbase: Bytes20,
Expand Down
5 changes: 2 additions & 3 deletions arbitrator/arbutil/src/evm/req.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
storage::{StorageCache, StorageWord},
user::UserOutcomeKind,
},
pricing::EVM_API_INK,
Bytes20, Bytes32,
};
use eyre::{bail, eyre, Result};
Expand Down Expand Up @@ -99,13 +98,13 @@ impl<D: DataReader, H: RequestHandler<D>> EvmApiRequestor<D, H> {
}

impl<D: DataReader, H: RequestHandler<D>> EvmApi<D> for EvmApiRequestor<D, H> {
fn get_bytes32(&mut self, key: Bytes32) -> (Bytes32, u64) {
fn get_bytes32(&mut self, key: Bytes32, evm_api_gas_to_use: u64) -> (Bytes32, u64) {
let cache = &mut self.storage_cache;
let mut cost = cache.read_gas();

let value = cache.entry(key).or_insert_with(|| {
let (res, _, gas) = self.handler.request(EvmApiMethod::GetBytes32, key);
cost = cost.saturating_add(gas).saturating_add(EVM_API_INK);
cost = cost.saturating_add(gas).saturating_add(evm_api_gas_to_use);
StorageWord::known(res.try_into().unwrap())
});
(value.value, cost)
Expand Down
2 changes: 2 additions & 0 deletions arbitrator/jit/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ pub fn create(opts: &Opts, env: WasmEnv) -> (Instance, FunctionEnv<WasmEnv>, Sto
"send_response" => func!(program::send_response),
"create_stylus_config" => func!(program::create_stylus_config),
"create_evm_data" => func!(program::create_evm_data),
"create_evm_data_v2" => func!(program::create_evm_data_v2),
"activate" => func!(program::activate),
"activate_v2" => func!(program::activate_v2),
},
};

Expand Down
77 changes: 73 additions & 4 deletions arbitrator/jit/src/program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,38 @@ use prover::{
programs::{config::PricingParams, prelude::*},
};

/// activates a user program
const DEFAULT_STYLUS_ARBOS_VERSION: u64 = 31;

pub fn activate(
env: WasmEnvMut,
wasm_ptr: GuestPtr,
wasm_size: u32,
pages_ptr: GuestPtr,
asm_estimate_ptr: GuestPtr,
init_cost_ptr: GuestPtr,
cached_init_cost_ptr: GuestPtr,
stylus_version: u16,
debug: u32,
codehash: GuestPtr,
module_hash_ptr: GuestPtr,
gas_ptr: GuestPtr,
err_buf: GuestPtr,
err_buf_len: u32,
) -> Result<u32, Escape> {
activate_v2(env, wasm_ptr, wasm_size, pages_ptr, asm_estimate_ptr, init_cost_ptr, cached_init_cost_ptr, stylus_version, DEFAULT_STYLUS_ARBOS_VERSION, debug, codehash, module_hash_ptr, gas_ptr, err_buf, err_buf_len)
}

/// activates a user program
pub fn activate_v2(
mut env: WasmEnvMut,
wasm_ptr: GuestPtr,
wasm_size: u32,
pages_ptr: GuestPtr,
asm_estimate_ptr: GuestPtr,
init_cost_ptr: GuestPtr,
cached_init_cost_ptr: GuestPtr,
version: u16,
stylus_version: u16,
arbos_version_for_gas: u64,
debug: u32,
codehash: GuestPtr,
module_hash_ptr: GuestPtr,
Expand All @@ -40,7 +62,15 @@ pub fn activate(

let page_limit = mem.read_u16(pages_ptr);
let gas_left = &mut mem.read_u64(gas_ptr);
match Module::activate(&wasm, codehash, version, page_limit, debug, gas_left) {
match Module::activate(
&wasm,
codehash,
stylus_version,
arbos_version_for_gas,
page_limit,
debug,
gas_left,
) {
Ok((module, data)) => {
mem.write_u64(gas_ptr, *gas_left);
mem.write_u16(pages_ptr, data.footprint);
Expand Down Expand Up @@ -222,9 +252,47 @@ pub fn create_stylus_config(
Ok(res as u64)
}

/// Creates an `EvmData` handler from its component parts.
pub fn create_evm_data(
env: WasmEnvMut,
block_basefee_ptr: GuestPtr,
chainid: u64,
block_coinbase_ptr: GuestPtr,
block_gas_limit: u64,
block_number: u64,
block_timestamp: u64,
contract_address_ptr: GuestPtr,
module_hash_ptr: GuestPtr,
msg_sender_ptr: GuestPtr,
msg_value_ptr: GuestPtr,
tx_gas_price_ptr: GuestPtr,
tx_origin_ptr: GuestPtr,
cached: u32,
reentrant: u32,
) -> Result<u64, Escape> {
create_evm_data_v2(
env,
DEFAULT_STYLUS_ARBOS_VERSION,
block_basefee_ptr,
chainid,
block_coinbase_ptr,
block_gas_limit,
block_number,
block_timestamp,
contract_address_ptr,
module_hash_ptr,
msg_sender_ptr,
msg_value_ptr,
tx_gas_price_ptr,
tx_origin_ptr,
cached,
reentrant,
)
}

/// Creates an `EvmData` handler from its component parts.
pub fn create_evm_data_v2(
mut env: WasmEnvMut,
arbos_version: u64,
block_basefee_ptr: GuestPtr,
chainid: u64,
block_coinbase_ptr: GuestPtr,
Expand All @@ -243,6 +311,7 @@ pub fn create_evm_data(
let (mut mem, _) = env.jit_env();

let evm_data = EvmData {
arbos_version,
block_basefee: mem.read_bytes32(block_basefee_ptr),
cached: cached != 0,
chainid,
Expand Down
95 changes: 50 additions & 45 deletions arbitrator/prover/src/programs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
programs::config::CompileConfig,
value::{FunctionType as ArbFunctionType, Value},
};
use arbutil::{math::SaturatingSum, Bytes32, Color};
use arbutil::{evm::ARBOS_VERSION_STYLUS_CHARGING_FIXES, math::SaturatingSum, Bytes32, Color};
use eyre::{bail, eyre, Report, Result, WrapErr};
use fnv::FnvHashMap as HashMap;
use std::fmt::Debug;
Expand Down Expand Up @@ -418,58 +418,63 @@ impl Module {
pub fn activate(
wasm: &[u8],
codehash: &Bytes32,
version: u16,
stylus_version: u16,
arbos_version_for_gas: u64, // must only be used for activation gas
page_limit: u16,
debug: bool,
gas: &mut u64,
) -> Result<(Self, StylusData)> {
// converts a number of microseconds to gas
// TODO: collapse to a single value after finalizing factors
let us_to_gas = |us: u64| {
let fudge = 2;
let sync_rate = 1_000_000 / 2;
let speed = 7_000_000;
us.saturating_mul(fudge * speed) / sync_rate
};

macro_rules! pay {
($us:expr) => {
let amount = us_to_gas($us);
if *gas < amount {
*gas = 0;
bail!("out of gas");
}
*gas -= amount;
};
}

// pay for wasm
let wasm_len = wasm.len() as u64;
pay!(wasm_len.saturating_mul(31_733 / 100_000));

let compile = CompileConfig::version(version, debug);
let compile = CompileConfig::version(stylus_version, debug);
let (bin, stylus_data) = WasmBinary::parse_user(wasm, page_limit, &compile, codehash)
.wrap_err("failed to parse wasm")?;

// pay for funcs
let funcs = bin.functions.len() as u64;
pay!(funcs.saturating_mul(17_263) / 100_000);

// pay for data
let data = bin.datas.iter().map(|x| x.data.len()).saturating_sum() as u64;
pay!(data.saturating_mul(17_376) / 100_000);

// pay for elements
let elems = bin.elements.iter().map(|x| x.range.len()).saturating_sum() as u64;
pay!(elems.saturating_mul(17_376) / 100_000);

// pay for memory
let mem = bin.memories.first().map(|x| x.initial).unwrap_or_default();
pay!(mem.saturating_mul(2217));
if arbos_version_for_gas > 0 {
// converts a number of microseconds to gas
// TODO: collapse to a single value after finalizing factors
let us_to_gas = |us: u64| {
let fudge = 2;
let sync_rate = 1_000_000 / 2;
let speed = 7_000_000;
us.saturating_mul(fudge * speed) / sync_rate
};

// pay for code
let code = bin.codes.iter().map(|x| x.expr.len()).saturating_sum() as u64;
pay!(code.saturating_mul(535) / 1_000);
macro_rules! pay {
($us:expr) => {
let amount = us_to_gas($us);
if *gas < amount {
*gas = 0;
bail!("out of gas");
}
*gas -= amount;
};
}

// pay for wasm
if arbos_version_for_gas >= ARBOS_VERSION_STYLUS_CHARGING_FIXES {
let wasm_len = wasm.len() as u64;
pay!(wasm_len.saturating_mul(31_733) / 100_000);
}

// pay for funcs
let funcs = bin.functions.len() as u64;
pay!(funcs.saturating_mul(17_263) / 100_000);

// pay for data
let data = bin.datas.iter().map(|x| x.data.len()).saturating_sum() as u64;
pay!(data.saturating_mul(17_376) / 100_000);

// pay for elements
let elems = bin.elements.iter().map(|x| x.range.len()).saturating_sum() as u64;
pay!(elems.saturating_mul(17_376) / 100_000);

// pay for memory
let mem = bin.memories.first().map(|x| x.initial).unwrap_or_default();
pay!(mem.saturating_mul(2217));

// pay for code
let code = bin.codes.iter().map(|x| x.expr.len()).saturating_sum() as u64;
pay!(code.saturating_mul(535) / 1_000);
}

let module = Self::from_user_binary(&bin, compile.debug.debug_funcs, Some(stylus_data))
.wrap_err("failed to build user module")?;
Expand Down
13 changes: 11 additions & 2 deletions arbitrator/stylus/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ impl RustBytes {
pub unsafe extern "C" fn stylus_activate(
wasm: GoSliceData,
page_limit: u16,
version: u16,
stylus_version: u16,
arbos_version_for_gas: u64,
debug: bool,
output: *mut RustBytes,
codehash: *const Bytes32,
Expand All @@ -153,7 +154,15 @@ pub unsafe extern "C" fn stylus_activate(
let codehash = &*codehash;
let gas = &mut *gas;

let (module, info) = match native::activate(wasm, codehash, version, page_limit, debug, gas) {
let (module, info) = match native::activate(
wasm,
codehash,
stylus_version,
arbos_version_for_gas,
page_limit,
debug,
gas,
) {
Ok(val) => val,
Err(err) => return output.write_err(err),
};
Expand Down
14 changes: 11 additions & 3 deletions arbitrator/stylus/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,13 +351,21 @@ pub fn module(wasm: &[u8], compile: CompileConfig, target: Target) -> Result<Vec
pub fn activate(
wasm: &[u8],
codehash: &Bytes32,
version: u16,
stylus_version: u16,
arbos_version_for_gas: u64,
page_limit: u16,
debug: bool,
gas: &mut u64,
) -> Result<(ProverModule, StylusData)> {
let (module, stylus_data) =
ProverModule::activate(wasm, codehash, version, page_limit, debug, gas)?;
let (module, stylus_data) = ProverModule::activate(
wasm,
codehash,
stylus_version,
arbos_version_for_gas,
page_limit,
debug,
gas,
)?;

Ok((module, stylus_data))
}
Expand Down
2 changes: 1 addition & 1 deletion arbitrator/stylus/src/test/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl TestEvmApi {
}

impl EvmApi<VecReader> for TestEvmApi {
fn get_bytes32(&mut self, key: Bytes32) -> (Bytes32, u64) {
fn get_bytes32(&mut self, key: Bytes32, _evm_api_gas_to_use: u64) -> (Bytes32, u64) {
let storage = &mut self.storage.lock();
let storage = storage.get_mut(&self.program).unwrap();
let value = storage.get(&key).cloned().unwrap_or_default();
Expand Down
4 changes: 2 additions & 2 deletions arbitrator/stylus/src/test/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ fn test_storage() -> Result<()> {

let (mut native, mut evm) = TestInstance::new_with_evm(filename, &compile, config)?;
run_native(&mut native, &store_args, ink)?;
assert_eq!(evm.get_bytes32(key.into()).0, Bytes32(value));
assert_eq!(evm.get_bytes32(key.into(), 0).0, Bytes32(value));
assert_eq!(run_native(&mut native, &load_args, ink)?, value);

let mut machine = Machine::from_user_path(Path::new(filename), &compile)?;
Expand Down Expand Up @@ -465,7 +465,7 @@ fn test_calls() -> Result<()> {
run_native(&mut native, &args, ink)?;

for (key, value) in slots {
assert_eq!(evm.get_bytes32(key).0, value);
assert_eq!(evm.get_bytes32(key, 0).0, value);
}
Ok(())
}
Expand Down
15 changes: 12 additions & 3 deletions arbitrator/wasm-libraries/user-host-trait/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use arbutil::{
api::{DataReader, EvmApi},
storage::StorageCache,
user::UserOutcomeKind,
EvmData,
EvmData, ARBOS_VERSION_STYLUS_CHARGING_FIXES,
},
pricing::{self, EVM_API_INK, HOSTIO_INK, PTR_INK},
Bytes20, Bytes32,
Expand Down Expand Up @@ -143,11 +143,20 @@ pub trait UserHost<DR: DataReader>: GasMeteredMachine {
/// [`SLOAD`]: https://www.evm.codes/#54
fn storage_load_bytes32(&mut self, key: GuestPtr, dest: GuestPtr) -> Result<(), Self::Err> {
self.buy_ink(HOSTIO_INK + 2 * PTR_INK)?;
self.require_gas(evm::COLD_SLOAD_GAS + EVM_API_INK + StorageCache::REQUIRED_ACCESS_GAS)?; // cache-miss case
let arbos_version = self.evm_data().arbos_version;

// require for cache-miss case, preserve wrong behavior for old arbos
let evm_api_gas_to_use = if arbos_version < ARBOS_VERSION_STYLUS_CHARGING_FIXES {
EVM_API_INK
} else {
self.pricing().ink_to_gas(EVM_API_INK)
};
self.require_gas(
evm::COLD_SLOAD_GAS + StorageCache::REQUIRED_ACCESS_GAS + evm_api_gas_to_use,
)?;
let key = self.read_bytes32(key)?;

let (value, gas_cost) = self.evm_api().get_bytes32(key);
let (value, gas_cost) = self.evm_api().get_bytes32(key, evm_api_gas_to_use);
self.buy_gas(gas_cost)?;
self.write_bytes32(dest, value)?;
trace!("storage_load_bytes32", self, key, value)
Expand Down
Loading
Loading