Skip to content

Commit

Permalink
implement hostio caching
Browse files Browse the repository at this point in the history
  • Loading branch information
rachel-bousfield committed Sep 5, 2023
1 parent cf0d64c commit 9e037b8
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 62 deletions.
12 changes: 6 additions & 6 deletions stylus-sdk/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,23 @@ use alloy_primitives::{Address, B256, U256};

wrap_hostio!(
/// Gets the basefee of the current block.
basefee block_basefee U256
basefee BASEFEE block_basefee U256
);

wrap_hostio!(
/// Gets the unique chain identifier of the Arbitrum chain.
chainid chainid u64
chainid CHAINID chainid u64
);

wrap_hostio!(
/// Gets the coinbase of the current block, which on Arbitrum chains is the L1 batch poster's
/// address.
coinbase block_coinbase Address
coinbase COINBASE block_coinbase Address
);

wrap_hostio!(
/// Gets the gas limit of the current block.
gas_limit block_gas_limit u64
gas_limit GAS_LIMIT block_gas_limit u64
);

wrap_hostio!(
Expand All @@ -31,7 +31,7 @@ wrap_hostio!(
/// determined.
///
/// [`Block Numbers and Time`]: https://developer.arbitrum.io/time
number block_number u64
number NUMBER block_number u64
);

wrap_hostio!(
Expand All @@ -40,5 +40,5 @@ wrap_hostio!(
/// determined.
///
/// [`Block Numbers and Time`]: https://developer.arbitrum.io/time
timestamp block_timestamp u64
timestamp TIMESTAMP block_timestamp u64
);
6 changes: 3 additions & 3 deletions stylus-sdk/src/call/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/stylus/licenses/COPYRIGHT.md

use crate::{
contract::read_return_data,
hostio::{self, RETURN_DATA_SIZE},
contract::{read_return_data, RETURN_DATA_LEN},
hostio,
storage::StorageCache,
tx, ArbResult,
};
Expand Down Expand Up @@ -180,7 +180,7 @@ impl RawCall {
};

unsafe {
RETURN_DATA_SIZE.set(outs_len);
RETURN_DATA_LEN.set(outs_len);
}

let outs = read_return_data(self.offset, self.size);
Expand Down
8 changes: 4 additions & 4 deletions stylus-sdk/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// For licensing, see https://github.com/OffchainLabs/stylus-sdk-rs/blob/stylus/licenses/COPYRIGHT.md

use crate::{
hostio::{self, wrap_hostio, RETURN_DATA_SIZE},
hostio::{self, wrap_hostio},
types::AddressVM,
};
use alloy_primitives::{Address, U256};
Expand All @@ -29,7 +29,7 @@ pub fn output(data: &[u8]) {
/// Copies the bytes of the last EVM call or deployment return result.
/// Note: this function does not revert if out of bounds, but rather will copy the overlapping portion.
pub fn read_return_data(offset: usize, size: Option<usize>) -> Vec<u8> {
let size = unsafe { size.unwrap_or_else(|| RETURN_DATA_SIZE.get().saturating_sub(offset)) };
let size = size.unwrap_or_else(|| return_data_len().saturating_sub(offset));

let mut data = Vec::with_capacity(size);
if size > 0 {
Expand All @@ -45,12 +45,12 @@ pub fn read_return_data(offset: usize, size: Option<usize>) -> Vec<u8> {
wrap_hostio!(
/// Returns the length of the last EVM call or deployment return result, or `0` if neither have
/// happened during the program's execution.
return_data_len return_data_size usize
return_data_len RETURN_DATA_LEN return_data_size usize
);

wrap_hostio!(
/// Gets the address of the current program.
address contract_address Address
address ADDRESS contract_address Address
);

/// Gets the balance of the current program.
Expand Down
6 changes: 3 additions & 3 deletions stylus-sdk/src/deploy/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
use alloy_primitives::{Address, B256, U256};

use crate::{
contract::read_return_data,
hostio::{self, RETURN_DATA_SIZE},
contract::{read_return_data, RETURN_DATA_LEN},
hostio,
};

/// Mechanism for performing raw deploys of other contracts.
Expand Down Expand Up @@ -89,7 +89,7 @@ impl RawDeploy {
&mut revert_data_len as *mut _,
);
}
RETURN_DATA_SIZE.set(revert_data_len);
RETURN_DATA_LEN.set(revert_data_len);

if contract.is_zero() {
return Err(read_return_data(0, None));
Expand Down
66 changes: 31 additions & 35 deletions stylus-sdk/src/hostio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,79 +323,75 @@ extern "C" {
}

macro_rules! wrap_hostio {
($(#[$meta:meta])* $name:ident $hostio:ident bool) => {
wrap_hostio!(@simple $(#[$meta])* $name, $hostio, bool);
($(#[$meta:meta])* $name:ident $hostio:ident u64) => {
wrap_hostio!(@simple $(#[$meta])* $name, $hostio, u64); // uncached
};
($(#[$meta:meta])* $name:ident $hostio:ident usize) => {
wrap_hostio!(@simple $(#[$meta])* $name, $hostio, usize);
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident bool) => {
wrap_hostio!(@simple $(#[$meta])* $name, $cache, $hostio, bool);
};
($(#[$meta:meta])* $name:ident $hostio:ident u64) => {
wrap_hostio!(@simple $(#[$meta])* $name, $hostio, u64);
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident u32) => {
wrap_hostio!(@simple $(#[$meta])* $name, $cache, $hostio, u32);
};
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident u64) => {
wrap_hostio!(@simple $(#[$meta])* $name, $cache, $hostio, u64);
};
($(#[$meta:meta])* $name:ident $hostio:ident Address) => {
wrap_hostio!(@arg $(#[$meta])* $name, $hostio, Address);
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident usize) => {
wrap_hostio!(@simple $(#[$meta])* $name, $cache, $hostio, usize);
};
($(#[$meta:meta])* $name:ident $hostio:ident B256) => {
wrap_hostio!(@arg $(#[$meta])* $name, $hostio, B256);
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident Address) => {
wrap_hostio!(@convert $(#[$meta])* $name, $cache, $hostio, Address, Address);
};
($(#[$meta:meta])* $name:ident $hostio:ident U256) => {
wrap_hostio!(@convert $(#[$meta])* $name, $hostio, B256, U256);
($(#[$meta:meta])* $name:ident $cache:ident $hostio:ident U256) => {
wrap_hostio!(@convert $(#[$meta])* $name, $cache, $hostio, B256, U256);
};
(@simple $(#[$meta:meta])* $name:ident, $hostio:ident, $ty:ident) => {
$(#[$meta])*
pub fn $name() -> $ty {
unsafe { $ty::from(hostio::$hostio()) }
}
};
(@arg $(#[$meta:meta])* $name:ident, $hostio:ident, $ty:ident) => {
(@simple $(#[$meta:meta])* $name:ident, $cache:ident, $hostio:ident, $ty:ident) => {
$(#[$meta])*
pub fn $name() -> $ty {
let mut data = $ty::ZERO;
unsafe { hostio::$hostio(data.as_mut_ptr()) };
data
unsafe{ $cache.get() }
}
pub(crate) static mut $cache: hostio::CachedOption<$ty> = hostio::CachedOption::new(|| unsafe { hostio::$hostio() });
};
(@convert $(#[$meta:meta])* $name:ident, $hostio:ident, $from:ident, $ty:ident) => {
(@convert $(#[$meta:meta])* $name:ident, $cache:ident, $hostio:ident, $from:ident, $ty:ident) => {
$(#[$meta])*
pub fn $name() -> $ty {
unsafe{ $cache.get() }
}
pub(crate) static mut $cache: hostio::CachedOption<$ty> = hostio::CachedOption::new(|| {
let mut data = $from::ZERO;
unsafe { hostio::$hostio(data.as_mut_ptr()) };
data.into()
}
});
};
}

pub(crate) use wrap_hostio;

/// Caches the length of the most recent EVM return data
pub(crate) static mut RETURN_DATA_SIZE: CachedOption<usize> = CachedOption::new(return_data_size);

/// Caches the current price of ink
pub(crate) static mut CACHED_INK_PRICE: CachedOption<u32> = CachedOption::new(tx_ink_price);

/// Caches a value to avoid paying for hostio invocations.
pub(crate) struct CachedOption<T: Copy> {
value: Option<T>,
loader: unsafe extern "C" fn() -> T,
loader: fn() -> T,
}

impl<T: Copy> CachedOption<T> {
const fn new(loader: unsafe extern "C" fn() -> T) -> Self {
/// Creates a new [`CachedOption`], which will use the `loader` during `get`.
pub const fn new(loader: fn() -> T) -> Self {
let value = None;
Self { value, loader }
}

pub(crate) fn set(&mut self, value: T) {
/// Sets and overwrites the cached value.
pub fn set(&mut self, value: T) {
self.value = Some(value);
}

pub(crate) fn get(&mut self) -> T {
if let Some(value) = &self.value {
return *value;
}

let value = unsafe { (self.loader)() };
self.value = Some(value);
value
/// Gets the value, writing it to the cache if necessary.
pub fn get(&mut self) -> T {
*self.value.get_or_insert_with(|| (self.loader)())
}
}
6 changes: 3 additions & 3 deletions stylus-sdk/src/msg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use alloy_primitives::{Address, B256, U256};

wrap_hostio!(
/// Whether the current call is reentrant.
reentrant msg_reentrant bool
reentrant REENTRANT msg_reentrant bool
);

wrap_hostio!(
Expand All @@ -20,10 +20,10 @@ wrap_hostio!(
/// [`CALLER`]: https://www.evm.codes/#33
/// [`DELEGATE_CALL`]: https://www.evm.codes/#f4
/// [`Retryable Ticket Address Aliasing`]: https://developer.arbitrum.io/arbos/l1-to-l2-messaging#address-aliasing
sender msg_sender Address
sender SENDER msg_sender Address
);

wrap_hostio!(
/// Get the ETH value in wei sent to the program.
value msg_value U256
value VALUE msg_value U256
);
16 changes: 8 additions & 8 deletions stylus-sdk/src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
use crate::hostio::{self, wrap_hostio};
use alloy_primitives::{Address, B256, U256};

/// Gets the price of ink in evm gas basis points. See [`Ink and Gas`] for more information on
/// Stylus's compute-pricing model.
///
/// [`Ink and Gas`]: https://developer.arbitrum.io/TODO
pub fn ink_price() -> u32 {
unsafe { hostio::CACHED_INK_PRICE.get() }
wrap_hostio! {
/// Gets the price of ink in evm gas basis points. See [`Ink and Gas`] for more information on
/// Stylus's compute-pricing model.
///
/// [`Ink and Gas`]: https://developer.arbitrum.io/TODO
ink_price INK_PRICE tx_ink_price u32
}

/// Converts evm gas to ink. See [`Ink and Gas`] for more information on
Expand All @@ -30,13 +30,13 @@ pub fn ink_to_gas(ink: u64) -> u64 {

wrap_hostio!(
/// Gets the gas price in wei per gas, which on Arbitrum chains equals the basefee.
gas_price tx_gas_price U256
gas_price GAS_PRICE tx_gas_price U256
);

wrap_hostio!(
/// Gets the top-level sender of the transaction. The semantics are equivalent to that of the
/// EVM's [`ORIGIN`] opcode.
///
/// [`ORIGIN`]: https://www.evm.codes/#32
origin tx_origin Address
origin ORIGIN tx_origin Address
);

0 comments on commit 9e037b8

Please sign in to comment.