diff --git a/crates/integration/contracts/ExtCode.sol b/crates/integration/contracts/ExtCode.sol index 89249c9..7d3223e 100644 --- a/crates/integration/contracts/ExtCode.sol +++ b/crates/integration/contracts/ExtCode.sol @@ -8,4 +8,10 @@ contract ExtCode { ret := extcodesize(who) } } + + function CodeSize() public pure returns (uint ret) { + assembly { + ret := codesize() + } + } } diff --git a/crates/integration/src/cases.rs b/crates/integration/src/cases.rs index 5d9ccec..15100c2 100644 --- a/crates/integration/src/cases.rs +++ b/crates/integration/src/cases.rs @@ -126,6 +126,8 @@ sol!( sol!( contract ExtCode { function ExtCodeSize(address who) public view returns (uint ret); + + function CodeSize() public pure returns (uint ret); } ); @@ -461,6 +463,18 @@ impl Contract { } } + pub fn code_size() -> 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::CodeSizeCall::new(()).abi_encode(), + } + } + pub fn memcpy(payload: Vec) -> Self { let code = include_str!("../contracts/MCopy.sol"); let name = "MCopy"; diff --git a/crates/integration/src/mock_runtime.rs b/crates/integration/src/mock_runtime.rs index 89b81f2..e89bdb5 100644 --- a/crates/integration/src/mock_runtime.rs +++ b/crates/integration/src/mock_runtime.rs @@ -884,20 +884,26 @@ fn link_host_functions(engine: &Engine) -> Linker { |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()); + let address = if address_ptr == u32::MAX { + transaction.top_frame().callee + } else { + let bytes = caller.read_memory_into_vec(address_ptr, 32)?; + let word = U256::from_le_slice(&bytes); + Address::from_word(word.into()) + }; - log::info!("{}", address); - - Ok(transaction + let code_size = 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_or_default() as u32; + + log::info!("code size of {address} = {code_size}"); + + Ok(code_size) }, ) .unwrap(); diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index fa8d836..f9c25c5 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -525,6 +525,15 @@ fn ext_code_size() { assert_eq!(received, expected); } +#[test] +fn code_size() { + let contract = Contract::code_size(); + let (_, output) = assert_success(&contract, false); + let expected = U256::from(contract.pvm_runtime.len()); + let received = U256::from_be_slice(&output.data); + assert_eq!(expected, received); +} + #[test] fn value_transfer() { // Succeeds in remix (shanghai) but traps the interpreter diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 7fddf22..931f9da 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -1234,10 +1234,17 @@ where } /// Returns the register witdh sized type. - pub fn sentinel_pointer(&self) -> inkwell::values::PointerValue<'ctx> { - self.xlen_type() + pub fn sentinel_pointer(&self) -> Pointer<'ctx> { + let sentinel_pointer = self + .xlen_type() .const_all_ones() - .const_to_pointer(self.llvm().ptr_type(Default::default())) + .const_to_pointer(self.llvm().ptr_type(Default::default())); + + Pointer::new( + sentinel_pointer.get_type(), + AddressSpace::Stack, + sentinel_pointer, + ) } /// Returns the runtime value width sized type. diff --git a/crates/llvm-context/src/polkavm/evm/call.rs b/crates/llvm-context/src/polkavm/evm/call.rs index f715324..1215400 100644 --- a/crates/llvm-context/src/polkavm/evm/call.rs +++ b/crates/llvm-context/src/polkavm/evm/call.rs @@ -35,7 +35,7 @@ where let value_pointer = if let Some(value) = value { let value_pointer = context.build_alloca(context.value_type(), "value"); context.build_store(value_pointer, value)?; - value_pointer.value + value_pointer } else { context.sentinel_pointer() }; @@ -66,8 +66,8 @@ where .next(address_pointer.value)? .next(gas)? .skip() - .next(context.sentinel_pointer())? - .next(value_pointer)? + .next(context.sentinel_pointer().value)? + .next(value_pointer.value)? .next(input_pointer.value)? .next(input_length)? .next(output_pointer.value)? diff --git a/crates/llvm-context/src/polkavm/evm/create.rs b/crates/llvm-context/src/polkavm/evm/create.rs index 8508e04..ecb1967 100644 --- a/crates/llvm-context/src/polkavm/evm/create.rs +++ b/crates/llvm-context/src/polkavm/evm/create.rs @@ -66,14 +66,14 @@ where .next(code_hash_pointer.value)? .skip() .skip() - .next(context.sentinel_pointer())? + .next(context.sentinel_pointer().value)? .next(value_pointer.value)? .next(input_data_pointer.value)? .next(input_length)? .next(address_pointer.value)? .next(address_length_pointer.value)? - .next(context.sentinel_pointer())? - .next(context.sentinel_pointer())? + .next(context.sentinel_pointer().value)? + .next(context.sentinel_pointer().value)? .next(salt_pointer.value)? .next( context diff --git a/crates/llvm-context/src/polkavm/evm/ext_code.rs b/crates/llvm-context/src/polkavm/evm/ext_code.rs index 3a8d251..b34bdd8 100644 --- a/crates/llvm-context/src/polkavm/evm/ext_code.rs +++ b/crates/llvm-context/src/polkavm/evm/ext_code.rs @@ -6,16 +6,23 @@ use crate::polkavm::context::Context; use crate::polkavm::Dependency; use crate::polkavm_const::runtime_api; -/// Translates the `extcodesize` instruction. +/// Translates the `extcodesize` instruction if `address` is `Some`. +/// Otherwise, translates the `codesize` instruction. pub fn size<'ctx, D>( context: &mut Context<'ctx, D>, - address: inkwell::values::IntValue<'ctx>, + address: Option>, ) -> anyhow::Result> where D: Dependency + Clone, { - let address_pointer = context.build_alloca(context.word_type(), "value"); - context.build_store(address_pointer, address)?; + let address_pointer = match address { + Some(address) => { + let address_pointer = context.build_alloca(context.word_type(), "value"); + context.build_store(address_pointer, address)?; + address_pointer + } + None => context.sentinel_pointer(), + }; let address_pointer_casted = context.builder().build_ptr_to_int( address_pointer.value, diff --git a/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs b/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs index b7626b9..b285fde 100644 --- a/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs +++ b/crates/solidity/src/evmla/ethereal_ir/function/block/element/mod.rs @@ -857,7 +857,7 @@ where revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) } revive_llvm_context::PolkaVMCodeType::Runtime => { - todo!() + revive_llvm_context::polkavm_evm_ext_code::size(context, None).map(Some) } } } @@ -930,7 +930,7 @@ where let arguments = self.pop_arguments_llvm(context); revive_llvm_context::polkavm_evm_ext_code::size( context, - arguments[0].into_int_value(), + Some(arguments[0].into_int_value()), ) .map(Some) } diff --git a/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs b/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs index ffdc3ee..3e87bc8 100644 --- a/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs +++ b/crates/solidity/src/yul/parser/statement/expression/function_call/mod.rs @@ -591,7 +591,7 @@ impl FunctionCall { revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) } revive_llvm_context::PolkaVMCodeType::Runtime => { - todo!() + revive_llvm_context::polkavm_evm_ext_code::size(context, None).map(Some) } } } @@ -632,7 +632,7 @@ impl FunctionCall { let arguments = self.pop_arguments_llvm::(context)?; revive_llvm_context::polkavm_evm_ext_code::size( context, - arguments[0].into_int_value(), + Some(arguments[0].into_int_value()), ) .map(Some) }