Implement CODESIZE

Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
xermicus
2024-06-06 15:10:21 +02:00
parent 39d78179d4
commit 10c7045e15
10 changed files with 73 additions and 24 deletions
+6
View File
@@ -8,4 +8,10 @@ contract ExtCode {
ret := extcodesize(who) ret := extcodesize(who)
} }
} }
function CodeSize() public pure returns (uint ret) {
assembly {
ret := codesize()
}
}
} }
+14
View File
@@ -126,6 +126,8 @@ sol!(
sol!( sol!(
contract ExtCode { contract ExtCode {
function ExtCodeSize(address who) public view returns (uint ret); 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<u8>) -> Self { pub fn memcpy(payload: Vec<u8>) -> Self {
let code = include_str!("../contracts/MCopy.sol"); let code = include_str!("../contracts/MCopy.sol");
let name = "MCopy"; let name = "MCopy";
+13 -7
View File
@@ -884,20 +884,26 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|caller: Caller<Transaction>, address_ptr: u32| { |caller: Caller<Transaction>, address_ptr: u32| {
let (caller, transaction) = caller.split(); let (caller, transaction) = caller.split();
let bytes = caller.read_memory_into_vec(address_ptr, 32)?; let address = if address_ptr == u32::MAX {
let word = U256::from_le_slice(&bytes); transaction.top_frame().callee
let address = Address::from_word(word.into()); } 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); let code_size = transaction
Ok(transaction
.state .state
.accounts .accounts
.get(&address) .get(&address)
.and_then(|account| account.contract) .and_then(|account| account.contract)
.and_then(|blob_hash| transaction.state.blobs.get(&blob_hash)) .and_then(|blob_hash| transaction.state.blobs.get(&blob_hash))
.map(|code| code.len()) .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(); .unwrap();
+9
View File
@@ -525,6 +525,15 @@ fn ext_code_size() {
assert_eq!(received, expected); 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] #[test]
fn value_transfer() { fn value_transfer() {
// Succeeds in remix (shanghai) but traps the interpreter // Succeeds in remix (shanghai) but traps the interpreter
+10 -3
View File
@@ -1234,10 +1234,17 @@ where
} }
/// Returns the register witdh sized type. /// Returns the register witdh sized type.
pub fn sentinel_pointer(&self) -> inkwell::values::PointerValue<'ctx> { pub fn sentinel_pointer(&self) -> Pointer<'ctx> {
self.xlen_type() let sentinel_pointer = self
.xlen_type()
.const_all_ones() .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. /// Returns the runtime value width sized type.
+3 -3
View File
@@ -35,7 +35,7 @@ where
let value_pointer = if let Some(value) = value { let value_pointer = if let Some(value) = value {
let value_pointer = context.build_alloca(context.value_type(), "value"); let value_pointer = context.build_alloca(context.value_type(), "value");
context.build_store(value_pointer, value)?; context.build_store(value_pointer, value)?;
value_pointer.value value_pointer
} else { } else {
context.sentinel_pointer() context.sentinel_pointer()
}; };
@@ -66,8 +66,8 @@ where
.next(address_pointer.value)? .next(address_pointer.value)?
.next(gas)? .next(gas)?
.skip() .skip()
.next(context.sentinel_pointer())? .next(context.sentinel_pointer().value)?
.next(value_pointer)? .next(value_pointer.value)?
.next(input_pointer.value)? .next(input_pointer.value)?
.next(input_length)? .next(input_length)?
.next(output_pointer.value)? .next(output_pointer.value)?
@@ -66,14 +66,14 @@ where
.next(code_hash_pointer.value)? .next(code_hash_pointer.value)?
.skip() .skip()
.skip() .skip()
.next(context.sentinel_pointer())? .next(context.sentinel_pointer().value)?
.next(value_pointer.value)? .next(value_pointer.value)?
.next(input_data_pointer.value)? .next(input_data_pointer.value)?
.next(input_length)? .next(input_length)?
.next(address_pointer.value)? .next(address_pointer.value)?
.next(address_length_pointer.value)? .next(address_length_pointer.value)?
.next(context.sentinel_pointer())? .next(context.sentinel_pointer().value)?
.next(context.sentinel_pointer())? .next(context.sentinel_pointer().value)?
.next(salt_pointer.value)? .next(salt_pointer.value)?
.next( .next(
context context
@@ -6,16 +6,23 @@ use crate::polkavm::context::Context;
use crate::polkavm::Dependency; use crate::polkavm::Dependency;
use crate::polkavm_const::runtime_api; 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>( pub fn size<'ctx, D>(
context: &mut Context<'ctx, D>, context: &mut Context<'ctx, D>,
address: inkwell::values::IntValue<'ctx>, address: Option<inkwell::values::IntValue<'ctx>>,
) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>> ) -> anyhow::Result<inkwell::values::BasicValueEnum<'ctx>>
where where
D: Dependency + Clone, D: Dependency + Clone,
{ {
let address_pointer = context.build_alloca(context.word_type(), "value"); let address_pointer = match address {
context.build_store(address_pointer, 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( let address_pointer_casted = context.builder().build_ptr_to_int(
address_pointer.value, address_pointer.value,
@@ -857,7 +857,7 @@ where
revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) revive_llvm_context::polkavm_evm_calldata::size(context).map(Some)
} }
revive_llvm_context::PolkaVMCodeType::Runtime => { 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); let arguments = self.pop_arguments_llvm(context);
revive_llvm_context::polkavm_evm_ext_code::size( revive_llvm_context::polkavm_evm_ext_code::size(
context, context,
arguments[0].into_int_value(), Some(arguments[0].into_int_value()),
) )
.map(Some) .map(Some)
} }
@@ -591,7 +591,7 @@ impl FunctionCall {
revive_llvm_context::polkavm_evm_calldata::size(context).map(Some) revive_llvm_context::polkavm_evm_calldata::size(context).map(Some)
} }
revive_llvm_context::PolkaVMCodeType::Runtime => { 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::<D, 1>(context)?; let arguments = self.pop_arguments_llvm::<D, 1>(context)?;
revive_llvm_context::polkavm_evm_ext_code::size( revive_llvm_context::polkavm_evm_ext_code::size(
context, context,
arguments[0].into_int_value(), Some(arguments[0].into_int_value()),
) )
.map(Some) .map(Some)
} }