diff --git a/stylus-sdk/src/hostio.rs b/stylus-sdk/src/hostio.rs index 7d2d861a..82792bff 100644 --- a/stylus-sdk/src/hostio.rs +++ b/stylus-sdk/src/hostio.rs @@ -28,6 +28,20 @@ extern "C" { /// [`BALANCE`]: https://www.evm.codes/#31 pub fn account_balance(address: *const u8, dest: *mut u8); + /// Gets a subset of the code from the account at the given address. The semantics are identical to that + /// of the EVM's [`EXT_CODE_COPY`] opcode, aside from one small detail: the write to the buffer `dest` will + /// stop after the last byte is written. This is unlike the EVM, which right pads with zeros in this scenario. + /// The return value is the number of bytes written, which allows the caller to detect if this has occured. + /// + /// [`EXT_CODE_COPY`]: https://www.evm.codes/#3C + pub fn account_code(address: *const u8, offset: usize, size: usize, dest: *mut u8) -> usize; + + /// Gets the size of the code in bytes at the given address. The semantics are equivalent + /// to that of the EVM's [`EXT_CODESIZE`]. + /// + /// [`EXT_CODESIZE`]: https://www.evm.codes/#3B + pub fn account_code_size(address: *const u8) -> usize; + /// Gets the code hash of the account at the given address. The semantics are equivalent /// to that of the EVM's [`EXT_CODEHASH`] opcode. Note that the code hash of an account without /// code will be the empty hash @@ -262,6 +276,8 @@ extern "C" { /// bounds, but rather copies the overlapping portion. The semantics are otherwise equivalent /// to that of the EVM's [`RETURN_DATA_COPY`] opcode. /// + /// Returns the number of bytes written. + /// /// [`RETURN_DATA_COPY`]: https://www.evm.codes/#3e pub fn read_return_data(dest: *mut u8, offset: usize, size: usize) -> usize; diff --git a/stylus-sdk/src/storage/map.rs b/stylus-sdk/src/storage/map.rs index 8b25f0cd..660ae6b1 100644 --- a/stylus-sdk/src/storage/map.rs +++ b/stylus-sdk/src/storage/map.rs @@ -186,7 +186,7 @@ impl StorageKey for String { impl StorageKey for Address { fn to_slot(&self, root: B256) -> U256 { - let int: U160 = self.0.try_into().unwrap(); + let int: U160 = self.0.into(); int.to_slot(root) } } diff --git a/stylus-sdk/src/types.rs b/stylus-sdk/src/types.rs index eb2594e7..a0ab9fb0 100644 --- a/stylus-sdk/src/types.rs +++ b/stylus-sdk/src/types.rs @@ -14,6 +14,7 @@ //! ``` use crate::hostio; +use alloc::vec::Vec; use alloy_primitives::{b256, Address, B256, U256}; /// Trait that allows the [`Address`] type to inspect the corresponding account's balance and codehash. @@ -21,6 +22,20 @@ pub trait AddressVM { /// The balance in wei of the account. fn balance(&self) -> U256; + /// The account's code. + /// + /// Returns an empty [`vec`] for [`EOAs`]. + /// + /// [`EOAs`]: https://ethereum.org/en/developers/docs/accounts/#types-of-account + fn code(&self) -> Vec; + + /// The length of the account's code in bytes. + /// + /// Returns `0` for [`EOAs`]. + /// + /// [`EOAs`]: https://ethereum.org/en/developers/docs/accounts/#types-of-account + fn code_size(&self) -> usize; + /// The codehash of the contract or [`EOA`] at the given address. /// /// [`EOA`]: https://ethereum.org/en/developers/docs/accounts/#types-of-account @@ -37,13 +52,27 @@ pub trait AddressVM { impl AddressVM for Address { fn balance(&self) -> U256 { let mut data = [0; 32]; - unsafe { hostio::account_balance(self.0.as_ptr(), data.as_mut_ptr()) }; + unsafe { hostio::account_balance(self.as_ptr(), data.as_mut_ptr()) }; U256::from_be_bytes(data) } + fn code(&self) -> Vec { + let size = self.code_size(); + let mut data = Vec::with_capacity(size); + unsafe { + hostio::account_code(self.as_ptr(), 0, size, data.as_mut_ptr()); + data.set_len(size); + } + data + } + + fn code_size(&self) -> usize { + unsafe { hostio::account_code_size(self.as_ptr()) } + } + fn codehash(&self) -> B256 { let mut data = [0; 32]; - unsafe { hostio::account_codehash(self.0.as_ptr(), data.as_mut_ptr()) }; + unsafe { hostio::account_codehash(self.as_ptr(), data.as_mut_ptr()) }; data.into() }