From b208daed7ea1dc8240230ab2117c4ea95ffa2df8 Mon Sep 17 00:00:00 2001 From: xermicus Date: Wed, 17 Apr 2024 18:05:51 +0200 Subject: [PATCH] implement the value opcode Signed-off-by: xermicus --- crates/common/src/bit_length.rs | 3 ++ crates/common/src/byte_length.rs | 5 ++- crates/integration/contracts/Value.sol | 5 +++ crates/integration/src/lib.rs | 21 ++++++++++ crates/integration/src/mock_runtime.rs | 2 +- crates/llvm-context/src/eravm/const.rs | 2 +- crates/llvm-context/src/eravm/context/mod.rs | 6 +++ .../llvm-context/src/eravm/evm/ether_gas.rs | 38 ++++++++++++++++++- 8 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 crates/integration/contracts/Value.sol diff --git a/crates/common/src/bit_length.rs b/crates/common/src/bit_length.rs index 41385bf..4e0e6d4 100644 --- a/crates/common/src/bit_length.rs +++ b/crates/common/src/bit_length.rs @@ -20,3 +20,6 @@ pub const BIT_LENGTH_ETH_ADDRESS: usize = /// The field (usually `u256` or `i256`) bit-length. pub const BIT_LENGTH_FIELD: usize = crate::byte_length::BYTE_LENGTH_FIELD * BIT_LENGTH_BYTE; + +/// Bit length of the runtime value type. +pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE; diff --git a/crates/common/src/byte_length.rs b/crates/common/src/byte_length.rs index ae7fc7a..7e59964 100644 --- a/crates/common/src/byte_length.rs +++ b/crates/common/src/byte_length.rs @@ -9,7 +9,7 @@ pub const BYTE_LENGTH_BYTE: usize = 1; pub const BYTE_LENGTH_X32: usize = 4; /// Native stack alignment size in bytes -pub const BYTE_LENGTH_STACK_ALIGN: usize = 16; +pub const BYTE_LENGTH_STACK_ALIGN: usize = 4; /// The x86_64 word byte-length. pub const BYTE_LENGTH_X64: usize = 8; @@ -19,3 +19,6 @@ pub const BYTE_LENGTH_ETH_ADDRESS: usize = 20; /// The field byte-length. pub const BYTE_LENGTH_FIELD: usize = 32; + +/// Byte length of the runtime value type. +pub const BYTE_LENGTH_VALUE: usize = 16; diff --git a/crates/integration/contracts/Value.sol b/crates/integration/contracts/Value.sol new file mode 100644 index 0000000..054671d --- /dev/null +++ b/crates/integration/contracts/Value.sol @@ -0,0 +1,5 @@ +contract Value { + function value() public payable returns (uint ret) { + ret = msg.value; + } +} diff --git a/crates/integration/src/lib.rs b/crates/integration/src/lib.rs index 8c76306..49819f0 100644 --- a/crates/integration/src/lib.rs +++ b/crates/integration/src/lib.rs @@ -188,6 +188,27 @@ mod tests { assert_eq!(received, expected); } + #[test] + fn transferred_value() { + sol!( + contract Value { + function value() public payable returns (uint); + } + ); + let code = crate::compile_blob("Value", include_str!("../contracts/Value.sol")); + let mut state = State::new(Value::valueCall::SELECTOR.to_vec()); + state.value = 0x1; + + let (mut instance, export) = mock_runtime::prepare(&code, None); + let state = crate::mock_runtime::call(state, &mut instance, export); + + assert_eq!(state.output.flags, 0); + + let expected = I256::try_from(state.value).unwrap(); + let received = I256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); + assert_eq!(received, expected); + } + #[test] fn msize_non_word_sized_access() { sol!( diff --git a/crates/integration/src/mock_runtime.rs b/crates/integration/src/mock_runtime.rs index d9e680d..c803ad3 100644 --- a/crates/integration/src/mock_runtime.rs +++ b/crates/integration/src/mock_runtime.rs @@ -88,7 +88,7 @@ fn link_host_functions(engine: &Engine) -> Linker { |caller: Caller, out_ptr: u32, out_len_ptr: u32| -> Result<(), Trap> { let (mut caller, state) = caller.split(); - let value = state.value.encode(); + let value = state.value.to_le_bytes(); caller.write_memory(out_ptr, &value)?; caller.write_memory(out_len_ptr, &(value.len() as u32).encode())?; diff --git a/crates/llvm-context/src/eravm/const.rs b/crates/llvm-context/src/eravm/const.rs index d47de5b..6d4c8cc 100644 --- a/crates/llvm-context/src/eravm/const.rs +++ b/crates/llvm-context/src/eravm/const.rs @@ -3,7 +3,7 @@ //! /// The LLVM framework version. -pub const LLVM_VERSION: semver::Version = semver::Version::new(15, 0, 4); +pub const LLVM_VERSION: semver::Version = semver::Version::new(18, 1, 4); /// The EraVM version. pub const ZKEVM_VERSION: semver::Version = semver::Version::new(1, 3, 2); diff --git a/crates/llvm-context/src/eravm/context/mod.rs b/crates/llvm-context/src/eravm/context/mod.rs index 241d021..c0ab762 100644 --- a/crates/llvm-context/src/eravm/context/mod.rs +++ b/crates/llvm-context/src/eravm/context/mod.rs @@ -1480,6 +1480,12 @@ where self.llvm.custom_width_int_type(crate::eravm::XLEN as u32) } + /// Returns the runtime value width sized type. + pub fn value_type(&self) -> inkwell::types::IntType<'ctx> { + self.llvm + .custom_width_int_type(revive_common::BIT_LENGTH_VALUE as u32) + } + /// /// Returns the default field type. /// diff --git a/crates/llvm-context/src/eravm/evm/ether_gas.rs b/crates/llvm-context/src/eravm/evm/ether_gas.rs index e7c41a5..d6e6a3f 100644 --- a/crates/llvm-context/src/eravm/evm/ether_gas.rs +++ b/crates/llvm-context/src/eravm/evm/ether_gas.rs @@ -28,7 +28,43 @@ pub fn value<'ctx, D>( where D: Dependency + Clone, { - Ok(context.integer_const(256, 0).as_basic_value_enum()) + let output_pointer = context.build_alloca(context.value_type(), "output_pointer"); + let output_pointer_casted = context.builder().build_ptr_to_int( + output_pointer.value, + context.xlen_type(), + "output_pointer_casted", + )?; + + let output_length_pointer = context.build_alloca(context.xlen_type(), "output_len_pointer"); + let output_length_pointer_casted = context.builder().build_ptr_to_int( + output_length_pointer.value, + context.xlen_type(), + "output_pointer_casted", + )?; + context.build_store( + output_length_pointer, + context.integer_const(crate::eravm::XLEN, revive_common::BYTE_LENGTH_VALUE as u64), + )?; + + context.builder().build_call( + context + .module() + .get_function("value_transferred") + .expect("is declared"), + &[ + output_pointer_casted.into(), + output_length_pointer_casted.into(), + ], + "call_seal_value_transferred", + )?; + + let value = context.build_load(output_pointer, "transferred_value")?; + let value_extended = context.builder().build_int_z_extend( + value.into_int_value(), + context.field_type(), + "transferred_value_extended", + )?; + Ok(value_extended.as_basic_value_enum()) } ///