diff --git a/crates/integration/contracts/ExtCode.sol b/crates/integration/contracts/ExtCode.sol new file mode 100644 index 0000000..89249c9 --- /dev/null +++ b/crates/integration/contracts/ExtCode.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8; + +contract ExtCode { + function ExtCodeSize(address who) public view returns (uint ret) { + assembly { + ret := extcodesize(who) + } + } +} diff --git a/crates/integration/src/cases.rs b/crates/integration/src/cases.rs index 6abd94c..19c1f75 100644 --- a/crates/integration/src/cases.rs +++ b/crates/integration/src/cases.rs @@ -1,4 +1,4 @@ -use alloy_primitives::{I256, U256}; +use alloy_primitives::{Address, I256, U256}; use alloy_sol_types::{sol, SolCall, SolConstructor}; use crate::mock_runtime::{CallOutput, State}; @@ -123,6 +123,12 @@ sol!( } ); +sol!( + contract ExtCode { + function ExtCodeSize(address who) public view returns (uint ret); + } +); + impl Contract { /// Execute the contract. /// @@ -405,6 +411,18 @@ impl Contract { calldata: vec![0; 4], } } + + pub fn ext_code_size(address: Address) -> Self { + let code = include_str!("../contracts/ExtCode.sol"); + let name = "ExtCode"; + + Self { + name, + evm_runtime: crate::compile_evm_bin_runtime(name, code), + pvm_runtime: crate::compile_blob(name, code), + calldata: ExtCode::ExtCodeSizeCall::new((address,)).abi_encode(), + } + } } #[cfg(test)] diff --git a/crates/integration/src/mock_runtime.rs b/crates/integration/src/mock_runtime.rs index a380983..e29828f 100644 --- a/crates/integration/src/mock_runtime.rs +++ b/crates/integration/src/mock_runtime.rs @@ -730,6 +730,30 @@ fn link_host_functions(engine: &Engine) -> Linker { ) .unwrap(); + linker + .func_wrap( + runtime_api::CODE_SIZE, + |caller: Caller, address_ptr: u32| { + let (caller, transaction) = caller.split(); + + let bytes = caller.read_memory_into_vec(address_ptr, 32)?; + let word = U256::from_le_slice(&bytes); + let address = Address::from_word(word.into()); + + log::info!("{}", address); + + Ok(transaction + .state + .accounts + .get(&address) + .and_then(|account| account.contract) + .and_then(|blob_hash| transaction.state.blobs.get(&blob_hash)) + .map(|code| code.len()) + .unwrap_or_default() as u32) + }, + ) + .unwrap(); + linker } diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index c746433..96916c6 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -507,3 +507,18 @@ fn create_with_value() { } } } + +#[test] +fn ext_code_size() { + let contract = Contract::ext_code_size(Transaction::default_address()); + let (_, output) = assert_success(&contract, false); + let received = U256::from_be_slice(&output.data); + let expected = U256::from(contract.pvm_runtime.len()); + assert_eq!(received, expected); + + let contract = Contract::ext_code_size(Default::default()); + let (_, output) = assert_success(&contract, false); + let received = U256::from_be_slice(&output.data); + let expected = U256::ZERO; + assert_eq!(received, expected); +} diff --git a/crates/llvm-context/src/polkavm/const/runtime_api.rs b/crates/llvm-context/src/polkavm/const/runtime_api.rs index 3f9891d..c4c4b61 100644 --- a/crates/llvm-context/src/polkavm/const/runtime_api.rs +++ b/crates/llvm-context/src/polkavm/const/runtime_api.rs @@ -16,6 +16,8 @@ pub static BLOCK_NUMBER: &str = "block_number"; pub static CALLER: &str = "caller"; +pub static CODE_SIZE: &str = "code_size"; + pub static DEPOSIT_EVENT: &str = "deposit_event"; pub static GET_STORAGE: &str = "get_storage"; @@ -36,7 +38,7 @@ pub static VALUE_TRANSFERRED: &str = "value_transferred"; /// All imported runtime API symbols.. /// Useful for configuring common attributes and linkage. -pub static IMPORTS: [&str; 11] = [ +pub static IMPORTS: [&str; 12] = [ ADDRESS, BLOCK_NUMBER, CALLER, @@ -44,6 +46,7 @@ pub static IMPORTS: [&str; 11] = [ GET_STORAGE, HASH_KECCAK_256, INPUT, + INSTANTIATE, NOW, RETURN, SET_STORAGE, diff --git a/crates/llvm-context/src/polkavm/evm/ext_code.rs b/crates/llvm-context/src/polkavm/evm/ext_code.rs index 7d7c66a..ae619ab 100644 --- a/crates/llvm-context/src/polkavm/evm/ext_code.rs +++ b/crates/llvm-context/src/polkavm/evm/ext_code.rs @@ -1,17 +1,36 @@ //! Translates the external code operations. +use inkwell::values::BasicValue; + use crate::polkavm::context::Context; use crate::polkavm::Dependency; +use crate::polkavm_const::runtime_api; /// Translates the `extcodesize` instruction. pub fn size<'ctx, D>( - _context: &mut Context<'ctx, D>, - _address: inkwell::values::IntValue<'ctx>, + context: &mut Context<'ctx, D>, + address: inkwell::values::IntValue<'ctx>, ) -> anyhow::Result> where D: Dependency + Clone, { - todo!() + let address_pointer = context.build_alloca(context.word_type(), "value"); + context.build_store(address_pointer, address)?; + + let address_pointer_casted = context.builder().build_ptr_to_int( + address_pointer.value, + context.xlen_type(), + "address_pointer", + )?; + let value = context + .build_runtime_call(runtime_api::CODE_SIZE, &[address_pointer_casted.into()]) + .unwrap_or_else(|| panic!("{} should return a value", runtime_api::CODE_SIZE)) + .into_int_value(); + + Ok(context + .builder() + .build_int_z_extend(value, context.word_type(), "extcodesize")? + .as_basic_value_enum()) } /// Translates the `extcodehash` instruction. diff --git a/crates/pallet-contracts-pvm-llapi/src/polkavm_guest.c b/crates/pallet-contracts-pvm-llapi/src/polkavm_guest.c index dc92241..0317ba3 100644 --- a/crates/pallet-contracts-pvm-llapi/src/polkavm_guest.c +++ b/crates/pallet-contracts-pvm-llapi/src/polkavm_guest.c @@ -73,6 +73,8 @@ POLKAVM_IMPORT(uint32_t, is_contract, uint32_t) POLKAVM_IMPORT(uint32_t, code_hash, uint32_t, uint32_t, uint32_t) +POLKAVM_IMPORT(uint32_t, code_size, uint32_t) + POLKAVM_IMPORT(void, own_code_hash, uint32_t, uint32_t) POLKAVM_IMPORT(uint32_t, caller_is_origin) diff --git a/crates/solidity/src/solc/standard_json/output/error/mod.rs b/crates/solidity/src/solc/standard_json/output/error/mod.rs index 80311ee..d8ef002 100644 --- a/crates/solidity/src/solc/standard_json/output/error/mod.rs +++ b/crates/solidity/src/solc/standard_json/output/error/mod.rs @@ -87,9 +87,9 @@ impl Error { │ usually needed in the following cases: │ │ 1. To detect whether an address belongs to a smart contract. │ │ 2. To detect whether the deploy code execution has finished. │ -│ zkSync Era comes with native account abstraction support (so accounts are smart contracts, │ -│ including private-key controlled EOAs), and you should avoid differentiating between contracts │ -│ and non-contract addresses. │ +│ Polkadot comes with native account abstraction support (so smart contracts are just accounts │ +│ coverned by code), and you should avoid differentiating between contracts and non-contract | +| addresses. │ └──────────────────────────────────────────────────────────────────────────────────────────────────┘"# .to_owned();