diff --git a/Cargo.lock b/Cargo.lock index a9ce84e..304d45c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1745,6 +1745,7 @@ dependencies = [ "env_logger", "hex", "polkavm", + "revive-common", "revive-differential", "revive-llvm-context", "revive-solidity", diff --git a/crates/common/src/bit_length.rs b/crates/common/src/bit_length.rs index 7af0e61..521be3c 100644 --- a/crates/common/src/bit_length.rs +++ b/crates/common/src/bit_length.rs @@ -21,3 +21,11 @@ pub const BIT_LENGTH_WORD: usize = crate::byte_length::BYTE_LENGTH_WORD * BIT_LE /// Bit length of the runtime value type. pub const BIT_LENGTH_VALUE: usize = crate::byte_length::BYTE_LENGTH_VALUE * BIT_LENGTH_BYTE; + +/// Bit length of thre runimte block number type. +pub const BIT_LENGTH_BLOCK_NUMBER: usize = + crate::byte_length::BYTE_LENGTH_BLOCK_NUMBER * BIT_LENGTH_BYTE; + +/// Bit length of thre runimte block timestamp type. +pub const BIT_LENGTH_BLOCK_TIMESTAMP: usize = + crate::byte_length::BYTE_LENGTH_BLOCK_TIMESTAMP * BIT_LENGTH_BYTE; diff --git a/crates/common/src/byte_length.rs b/crates/common/src/byte_length.rs index 84a0113..3f75eef 100644 --- a/crates/common/src/byte_length.rs +++ b/crates/common/src/byte_length.rs @@ -20,3 +20,9 @@ pub const BYTE_LENGTH_WORD: usize = 32; /// Byte length of the runtime value type. pub const BYTE_LENGTH_VALUE: usize = 16; + +/// Byte length of the runtime block number type. +pub const BYTE_LENGTH_BLOCK_NUMBER: usize = 8; + +/// Byte length of the runtime block timestamp type. +pub const BYTE_LENGTH_BLOCK_TIMESTAMP: usize = 8; diff --git a/crates/differential/Cargo.toml b/crates/differential/Cargo.toml index 7d94a62..60f0ffe 100644 --- a/crates/differential/Cargo.toml +++ b/crates/differential/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" [dependencies] evm-interpreter = { workspace = true } -primitive-types = { workspace = true } +primitive-types = { workspace = true } \ No newline at end of file diff --git a/crates/differential/src/lib.rs b/crates/differential/src/lib.rs index 99fbea4..74e91f8 100644 --- a/crates/differential/src/lib.rs +++ b/crates/differential/src/lib.rs @@ -16,13 +16,13 @@ impl RuntimeEnvironment for UnimplementedHandler { unimplemented!() } fn block_number(&self) -> U256 { - unimplemented!() + U256::from(123) } fn block_coinbase(&self) -> H160 { unimplemented!() } fn block_timestamp(&self) -> U256 { - unimplemented!() + U256::from(456) } fn block_difficulty(&self) -> U256 { unimplemented!() diff --git a/crates/integration/Cargo.toml b/crates/integration/Cargo.toml index c910792..7e772d6 100644 --- a/crates/integration/Cargo.toml +++ b/crates/integration/Cargo.toml @@ -15,6 +15,7 @@ env_logger = { workspace = true } revive-solidity = { path = "../solidity" } revive-differential = { path = "../differential" } revive-llvm-context = { path = "../llvm-context" } +revive-common = { path = "../common" } [dev-dependencies] sha1 = { workspace = true } diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index a1a84b4..e8178c9 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -1,7 +1,7 @@ { - "ERC20": 53171, - "Baseline": 3912, - "Flipper": 4353, - "Fibonacci": 5971, - "Computation": 7380 + "Baseline": 3917, + "Computation": 7363, + "ERC20": 52714, + "Fibonacci": 5965, + "Flipper": 4336 } \ No newline at end of file diff --git a/crates/integration/contracts/Block.sol b/crates/integration/contracts/Block.sol new file mode 100644 index 0000000..08b5bb6 --- /dev/null +++ b/crates/integration/contracts/Block.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +contract Block { + function timestamp() public view returns (uint ret) { + ret = block.timestamp; + } + + function number() public view returns (uint ret) { + ret = block.number; + } +} diff --git a/crates/integration/src/cases.rs b/crates/integration/src/cases.rs index d4da243..27a6353 100644 --- a/crates/integration/src/cases.rs +++ b/crates/integration/src/cases.rs @@ -67,6 +67,14 @@ sol!( } ); +sol!( + contract Block { + function timestamp() public view returns (uint ret); + + function number() public view returns (uint ret); + } +); + impl Contract { pub fn baseline() -> Self { let code = include_str!("../contracts/Baseline.sol"); @@ -166,12 +174,34 @@ impl Contract { calldata: IERC20::totalSupplyCall::new(()).abi_encode(), } } + + pub fn block_number() -> Self { + let code = include_str!("../contracts/Block.sol"); + let name = "Block"; + + Self { + evm_runtime: crate::compile_evm_bin_runtime(name, code), + pvm_runtime: crate::compile_blob(name, code), + calldata: Block::numberCall::new(()).abi_encode(), + } + } + + pub fn block_timestamp() -> Self { + let code = include_str!("../contracts/Block.sol"); + let name = "Block"; + + Self { + evm_runtime: crate::compile_evm_bin_runtime(name, code), + pvm_runtime: crate::compile_blob(name, code), + calldata: Block::timestampCall::new(()).abi_encode(), + } + } } #[cfg(test)] mod tests { use serde::{de::Deserialize, Serialize}; - use std::{collections::HashMap, fs::File}; + use std::{collections::BTreeMap, fs::File}; use super::Contract; @@ -181,14 +211,14 @@ mod tests { let existing = File::open(path) .map(|file| { - HashMap::::deserialize(&mut serde_json::Deserializer::from_reader( + BTreeMap::::deserialize(&mut serde_json::Deserializer::from_reader( file, )) .expect("should be able to deserialze codesize data") }) .ok(); - let sizes = HashMap::from([ + let sizes = BTreeMap::from([ ("Baseline", Contract::baseline().pvm_runtime.len()), ("Flipper", Contract::flipper().pvm_runtime.len()), ("Computation", Contract::odd_product(0).pvm_runtime.len()), diff --git a/crates/integration/src/mock_runtime.rs b/crates/integration/src/mock_runtime.rs index 56d14a3..a15a04e 100644 --- a/crates/integration/src/mock_runtime.rs +++ b/crates/integration/src/mock_runtime.rs @@ -33,6 +33,9 @@ impl Default for CallOutput { } impl State { + pub const BLOCK_NUMBER: u64 = 123; + pub const BLOCK_TIMESTAMP: u64 = 456; + pub fn new(input: Vec) -> Self { Self { input, @@ -88,8 +91,12 @@ 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 out_len = caller.read_u32(out_len_ptr)?; - assert_eq!(out_len, 16, "spurious output buffer size: {out_len}"); + let out_len = caller.read_u32(out_len_ptr)? as usize; + assert_eq!( + out_len, + revive_common::BYTE_LENGTH_VALUE, + "spurious output buffer size: {out_len}" + ); let value = state.value.to_le_bytes(); @@ -126,8 +133,16 @@ fn link_host_functions(engine: &Engine) -> Linker { -> Result { let (caller, state) = caller.split(); - assert_eq!(key_len, 32, "storage key must be 32 bytes"); - assert_eq!(value_len, 32, "storage value must be 32 bytes"); + assert_eq!( + key_len as usize, + revive_common::BYTE_LENGTH_WORD, + "storage key must be 32 bytes" + ); + assert_eq!( + value_len as usize, + revive_common::BYTE_LENGTH_WORD, + "storage value must be 32 bytes" + ); let key = caller.read_memory_into_vec(key_ptr, key_len)?; let value = caller.read_memory_into_vec(value_ptr, value_len)?; @@ -154,8 +169,12 @@ fn link_host_functions(engine: &Engine) -> Linker { let (mut caller, state) = caller.split(); let key = caller.read_memory_into_vec(key_ptr, key_len)?; - let out_len = caller.read_u32(out_len_ptr)?; - assert_eq!(out_len, 32, "spurious output buffer size: {out_len}"); + let out_len = caller.read_u32(out_len_ptr)? as usize; + assert_eq!( + out_len, + revive_common::BYTE_LENGTH_WORD, + "spurious output buffer size: {out_len}" + ); let value = state .storage @@ -192,6 +211,48 @@ fn link_host_functions(engine: &Engine) -> Linker { ) .unwrap(); + linker + .func_wrap( + runtime_api::NOW, + |caller: Caller, out_ptr: u32, out_len_ptr: u32| { + let (mut caller, _) = caller.split(); + + let out_len = caller.read_u32(out_len_ptr)? as usize; + assert_eq!( + out_len, + revive_common::BYTE_LENGTH_BLOCK_TIMESTAMP, + "spurious output buffer size: {out_len}" + ); + + caller.write_memory(out_ptr, &State::BLOCK_TIMESTAMP.to_le_bytes())?; + caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?; + + Ok(()) + }, + ) + .unwrap(); + + linker + .func_wrap( + runtime_api::BLOCK_NUMBER, + |caller: Caller, out_ptr: u32, out_len_ptr: u32| { + let (mut caller, _) = caller.split(); + + let out_len = caller.read_u32(out_len_ptr)? as usize; + assert_eq!( + out_len, + revive_common::BYTE_LENGTH_BLOCK_NUMBER, + "spurious output buffer size: {out_len}" + ); + + caller.write_memory(out_ptr, &State::BLOCK_NUMBER.to_le_bytes())?; + caller.write_memory(out_len_ptr, &64u32.to_le_bytes())?; + + Ok(()) + }, + ) + .unwrap(); + linker } diff --git a/crates/integration/src/tests.rs b/crates/integration/src/tests.rs index d9f1b0b..56b6244 100644 --- a/crates/integration/src/tests.rs +++ b/crates/integration/src/tests.rs @@ -126,7 +126,7 @@ fn transferred_value() { ); let code = crate::compile_blob("Value", include_str!("../contracts/Value.sol")); let mut state = State::new(Value::valueCall::SELECTOR.to_vec()); - state.value = 0x1; + state.value = 123; let (mut instance, export) = mock_runtime::prepare(&code, None); let state = crate::mock_runtime::call(state, &mut instance, export); @@ -264,3 +264,19 @@ fn sha1() { let received = FixedBytes::<20>::from_slice(&state.output.data[..20]); assert_eq!(received, expected); } + +#[test] +fn block_number() { + let state = assert_success(Contract::block_number(), true); + let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); + let expected = U256::from(mock_runtime::State::BLOCK_NUMBER); + assert_eq!(received, expected); +} + +#[test] +fn block_timestamp() { + let state = assert_success(Contract::block_timestamp(), true); + let received = U256::from_be_bytes::<32>(state.output.data.try_into().unwrap()); + let expected = U256::from(mock_runtime::State::BLOCK_TIMESTAMP); + assert_eq!(received, expected); +} diff --git a/crates/llvm-context/src/polkavm/const/mod.rs b/crates/llvm-context/src/polkavm/const/mod.rs index e6a7eb3..ee8a8c7 100644 --- a/crates/llvm-context/src/polkavm/const/mod.rs +++ b/crates/llvm-context/src/polkavm/const/mod.rs @@ -43,7 +43,13 @@ pub static GLOBAL_CONST_ARRAY_PREFIX: &str = "const_array_"; pub static GLOBAL_VERBATIM_GETTER_PREFIX: &str = "get_global::"; /// The static word size. -pub static GLOBAL_WORD_SIZE: &str = "word_size"; +pub static GLOBAL_I256_SIZE: &str = "i256_size"; + +/// The static value size. +pub static GLOBAL_I128_SIZE: &str = "i128_size"; + +/// The static i64 size. +pub static GLOBAL_I64_SIZE: &str = "i64_size"; /// The external call data offset in the auxiliary heap. pub const HEAP_AUX_OFFSET_EXTERNAL_CALL: u64 = 0; diff --git a/crates/llvm-context/src/polkavm/const/runtime_api.rs b/crates/llvm-context/src/polkavm/const/runtime_api.rs index c66990d..a098f12 100644 --- a/crates/llvm-context/src/polkavm/const/runtime_api.rs +++ b/crates/llvm-context/src/polkavm/const/runtime_api.rs @@ -10,12 +10,16 @@ pub static DEPLOY: &str = "deploy"; /// Useful for configuring common attributes and linkage. pub static EXPORTS: [&str; 2] = [CALL, DEPLOY]; +pub static BLOCK_NUMBER: &str = "block_number"; + pub static GET_STORAGE: &str = "get_storage"; pub static HASH_KECCAK_256: &str = "hash_keccak_256"; pub static INPUT: &str = "input"; +pub static NOW: &str = "now"; + pub static RETURN: &str = "seal_return"; pub static SET_STORAGE: &str = "set_storage"; diff --git a/crates/llvm-context/src/polkavm/context/function/intrinsics.rs b/crates/llvm-context/src/polkavm/context/function/intrinsics.rs index 907c645..0611ad0 100644 --- a/crates/llvm-context/src/polkavm/context/function/intrinsics.rs +++ b/crates/llvm-context/src/polkavm/context/function/intrinsics.rs @@ -39,7 +39,7 @@ impl<'ctx> Intrinsics<'ctx> { ) -> Self { let void_type = llvm.void_type(); let bool_type = llvm.bool_type(); - let field_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32); + let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32); let _stack_field_pointer_type = llvm.ptr_type(AddressSpace::Stack.into()); let heap_field_pointer_type = llvm.ptr_type(AddressSpace::Heap.into()); let generic_byte_pointer_type = llvm.ptr_type(AddressSpace::Generic.into()); @@ -58,7 +58,7 @@ impl<'ctx> Intrinsics<'ctx> { &[ heap_field_pointer_type.as_basic_type_enum().into(), heap_field_pointer_type.as_basic_type_enum().into(), - field_type.as_basic_type_enum().into(), + word_type.as_basic_type_enum().into(), bool_type.as_basic_type_enum().into(), ], false, @@ -72,7 +72,7 @@ impl<'ctx> Intrinsics<'ctx> { &[ heap_field_pointer_type.as_basic_type_enum().into(), generic_byte_pointer_type.as_basic_type_enum().into(), - field_type.as_basic_type_enum().into(), + word_type.as_basic_type_enum().into(), bool_type.as_basic_type_enum().into(), ], false, @@ -82,7 +82,7 @@ impl<'ctx> Intrinsics<'ctx> { llvm, module, Self::FUNCTION_BYTE_SWAP, - field_type.fn_type(&[field_type.as_basic_type_enum().into()], false), + word_type.fn_type(&[word_type.as_basic_type_enum().into()], false), ); Self { @@ -114,7 +114,7 @@ impl<'ctx> Intrinsics<'ctx> { llvm: &'ctx inkwell::context::Context, name: &str, ) -> Vec> { - let field_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32); + let word_type = llvm.custom_width_int_type(revive_common::BIT_LENGTH_WORD as u32); match name { name if name == Self::FUNCTION_MEMORY_COPY => vec![ @@ -122,16 +122,16 @@ impl<'ctx> Intrinsics<'ctx> { .as_basic_type_enum(), llvm.ptr_type(AddressSpace::Heap.into()) .as_basic_type_enum(), - field_type.as_basic_type_enum(), + word_type.as_basic_type_enum(), ], name if name == Self::FUNCTION_MEMORY_COPY_FROM_GENERIC => vec![ llvm.ptr_type(AddressSpace::Heap.into()) .as_basic_type_enum(), llvm.ptr_type(AddressSpace::Generic.into()) .as_basic_type_enum(), - field_type.as_basic_type_enum(), + word_type.as_basic_type_enum(), ], - name if name == Self::FUNCTION_BYTE_SWAP => vec![field_type.as_basic_type_enum()], + name if name == Self::FUNCTION_BYTE_SWAP => vec![word_type.as_basic_type_enum()], _ => vec![], } } diff --git a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs index 81ec17b..da45fea 100644 --- a/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs +++ b/crates/llvm-context/src/polkavm/context/function/runtime/entry.rs @@ -85,10 +85,30 @@ impl Entry { ); context.set_global( - crate::polkavm::GLOBAL_WORD_SIZE, + crate::polkavm::GLOBAL_I256_SIZE, context.xlen_type(), AddressSpace::Stack, - context.integer_const(crate::polkavm::XLEN, revive_common::BYTE_LENGTH_WORD as u64), + context.integer_const( + crate::polkavm::XLEN, + revive_common::BYTE_LENGTH_X64 as u64 * 4, + ), + ); + + context.set_global( + crate::polkavm::GLOBAL_I128_SIZE, + context.xlen_type(), + AddressSpace::Stack, + context.integer_const( + crate::polkavm::XLEN, + revive_common::BYTE_LENGTH_X64 as u64 * 2, + ), + ); + + context.set_global( + crate::polkavm::GLOBAL_I64_SIZE, + context.xlen_type(), + AddressSpace::Stack, + context.integer_const(crate::polkavm::XLEN, revive_common::BYTE_LENGTH_X64 as u64), ); Ok(()) diff --git a/crates/llvm-context/src/polkavm/context/mod.rs b/crates/llvm-context/src/polkavm/context/mod.rs index 39cd53b..c16c80d 100644 --- a/crates/llvm-context/src/polkavm/context/mod.rs +++ b/crates/llvm-context/src/polkavm/context/mod.rs @@ -610,16 +610,45 @@ where Pointer::new(r#type, AddressSpace::Stack, pointer) } - /// Allocates a word-sized byte buffer on the stack. + /// Allocate an int of size `bit_length` on the stack. /// Returns the allocation pointer and the length pointer. - pub fn build_stack_word_parameter(&self, name: &str) -> (Pointer<'ctx>, Pointer<'ctx>) { - let buffer_pointer = self.build_alloca(self.word_type(), name); - let length_pointer = self - .get_global(GLOBAL_WORD_SIZE) - .expect("should be declared"); + /// + /// Useful helper for passing runtime API parameters on the stack. + pub fn build_stack_parameter( + &self, + bit_length: usize, + name: &str, + ) -> (Pointer<'ctx>, Pointer<'ctx>) { + let buffer_pointer = self.build_alloca(self.integer_type(bit_length), name); + let symbol = match bit_length { + 256 => GLOBAL_I256_SIZE, + 128 => GLOBAL_I128_SIZE, + 64 => GLOBAL_I64_SIZE, + _ => unreachable!("invalid stack parameter bit width: {bit_length}"), + }; + let length_pointer = self.get_global(symbol).expect("should be declared"); (buffer_pointer, length_pointer.into()) } + /// Load the integer at given pointer and zero extend it to the VM word size. + pub fn build_load_word( + &self, + pointer: Pointer<'ctx>, + bit_length: usize, + name: &str, + ) -> anyhow::Result> { + let value = self.build_load( + pointer.cast(self.integer_type(bit_length)), + &format!("load_{name}"), + )?; + let value_extended = self.builder().build_int_z_extend( + value.into_int_value(), + self.word_type(), + &format!("zext_{name}"), + )?; + Ok(value_extended.as_basic_value_enum()) + } + /// Builds a stack load instruction. /// Sets the alignment to 256 bits for the stack and 1 bit for the heap, parent, and child. pub fn build_load( @@ -651,7 +680,7 @@ where .set_alignment(revive_common::BYTE_LENGTH_BYTE as u32) .expect("Alignment is valid"); - Ok(self.build_byte_swap(value)) + self.build_byte_swap(value) } AddressSpace::TransientStorage => todo!(), AddressSpace::Storage => { @@ -670,8 +699,8 @@ where self.builder() .build_store(storage_key_pointer.value, storage_key_value)?; - let (storage_value_pointer, storage_value_length_pointer) = - self.build_stack_word_parameter("storage_value_pointer"); + let (storage_value_pointer, storage_value_length_pointer) = self + .build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer"); self.build_runtime_call( runtime_api::GET_STORAGE, @@ -688,13 +717,13 @@ where // If a key doesn't exist the "zero" value is returned. self.build_load(storage_value_pointer, "storage_value_load") - .map(|value| self.build_byte_swap(value)) + .and_then(|value| self.build_byte_swap(value)) } AddressSpace::Code | AddressSpace::HeapAuxiliary => todo!(), AddressSpace::Generic => Ok(self.build_byte_swap(self.build_load( pointer.address_space_cast(self, AddressSpace::Stack, &format!("{}_cast", name))?, name, - )?)), + )?)?), AddressSpace::Stack => { let value = self .builder() @@ -735,7 +764,7 @@ where let value = value.as_basic_value_enum(); let value = match value.get_type().into_int_type().get_bit_width() as usize { - revive_common::BIT_LENGTH_WORD => self.build_byte_swap(value), + revive_common::BIT_LENGTH_WORD => self.build_byte_swap(value)?, revive_common::BIT_LENGTH_BYTE => value, _ => unreachable!("Only word and byte sized values can be stored on EVM heap"), }; @@ -756,7 +785,7 @@ where self.build_alloca(storage_key_value.get_type(), "storage_key"); let storage_value_value = self - .build_byte_swap(value.as_basic_value_enum()) + .build_byte_swap(value.as_basic_value_enum())? .into_int_value(); let storage_value_pointer = self.build_alloca(storage_value_value.get_type(), "storage_value"); @@ -790,7 +819,7 @@ where AddressSpace::Code | AddressSpace::HeapAuxiliary => {} AddressSpace::Generic => self.build_store( pointer.address_space_cast(self, AddressSpace::Stack, "cast")?, - self.build_byte_swap(value.as_basic_value_enum()), + self.build_byte_swap(value.as_basic_value_enum())?, )?, AddressSpace::Stack => { let instruction = self.builder.build_store(pointer.value, value).unwrap(); @@ -807,9 +836,17 @@ where pub fn build_byte_swap( &self, value: inkwell::values::BasicValueEnum<'ctx>, - ) -> inkwell::values::BasicValueEnum<'ctx> { - self.build_call(self.intrinsics().byte_swap, &[value], "call_byte_swap") - .expect("byte_swap should return a value") + ) -> anyhow::Result> { + Ok(self + .builder() + .build_call( + self.intrinsics().byte_swap.value, + &[value.into()], + "call_byte_swap", + )? + .try_as_basic_value() + .left() + .unwrap()) } /// Builds a GEP instruction. diff --git a/crates/llvm-context/src/polkavm/evm/calldata.rs b/crates/llvm-context/src/polkavm/evm/calldata.rs index 0baf697..1540076 100644 --- a/crates/llvm-context/src/polkavm/evm/calldata.rs +++ b/crates/llvm-context/src/polkavm/evm/calldata.rs @@ -26,7 +26,7 @@ where ); context .build_load(offset, "calldata_value") - .map(|value| context.build_byte_swap(value)) + .and_then(|value| context.build_byte_swap(value)) } /// Translates the calldata size. diff --git a/crates/llvm-context/src/polkavm/evm/context.rs b/crates/llvm-context/src/polkavm/evm/context.rs index a17bc6c..da42f90 100644 --- a/crates/llvm-context/src/polkavm/evm/context.rs +++ b/crates/llvm-context/src/polkavm/evm/context.rs @@ -4,6 +4,7 @@ use inkwell::values::BasicValue; use crate::polkavm::context::Context; use crate::polkavm::Dependency; +use crate::polkavm_const::runtime_api; /// Translates the `gas_limit` instruction. pub fn gas_limit<'ctx, D>( @@ -47,22 +48,52 @@ where /// Translates the `block_number` instruction. pub fn block_number<'ctx, D>( - _context: &mut Context<'ctx, D>, + context: &mut Context<'ctx, D>, ) -> anyhow::Result> where D: Dependency + Clone, { - todo!() + let (output_pointer, output_length_pointer) = context.build_stack_parameter( + revive_common::BIT_LENGTH_BLOCK_NUMBER, + "block_timestamp_output", + ); + context.build_runtime_call( + runtime_api::BLOCK_NUMBER, + &[ + output_pointer.to_int(context).into(), + output_length_pointer.to_int(context).into(), + ], + ); + context.build_load_word( + output_pointer, + revive_common::BIT_LENGTH_BLOCK_NUMBER, + "block_number", + ) } /// Translates the `block_timestamp` instruction. pub fn block_timestamp<'ctx, D>( - _context: &mut Context<'ctx, D>, + context: &mut Context<'ctx, D>, ) -> anyhow::Result> where D: Dependency + Clone, { - todo!() + let (output_pointer, output_length_pointer) = context.build_stack_parameter( + revive_common::BIT_LENGTH_BLOCK_TIMESTAMP, + "block_timestamp_output", + ); + context.build_runtime_call( + runtime_api::NOW, + &[ + output_pointer.to_int(context).into(), + output_length_pointer.to_int(context).into(), + ], + ); + context.build_load_word( + output_pointer, + revive_common::BIT_LENGTH_BLOCK_TIMESTAMP, + "block_timestamp", + ) } /// Translates the `block_hash` instruction. diff --git a/crates/llvm-context/src/polkavm/evm/crypto.rs b/crates/llvm-context/src/polkavm/evm/crypto.rs index 47716ce..bb1d797 100644 --- a/crates/llvm-context/src/polkavm/evm/crypto.rs +++ b/crates/llvm-context/src/polkavm/evm/crypto.rs @@ -27,5 +27,5 @@ where ], ); - Ok(context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?)) + context.build_byte_swap(context.build_load(output_pointer, "sha3_output")?) } diff --git a/crates/llvm-context/src/polkavm/evm/ether_gas.rs b/crates/llvm-context/src/polkavm/evm/ether_gas.rs index 88a6032..96d9c4d 100644 --- a/crates/llvm-context/src/polkavm/evm/ether_gas.rs +++ b/crates/llvm-context/src/polkavm/evm/ether_gas.rs @@ -23,42 +23,20 @@ pub fn value<'ctx, D>( where D: Dependency + Clone, { - 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::polkavm::XLEN, - revive_common::BYTE_LENGTH_VALUE as u64, - ), - )?; - + let (output_pointer, output_length_pointer) = + context.build_stack_parameter(revive_common::BIT_LENGTH_VALUE, "value_transferred_output"); context.build_runtime_call( runtime_api::VALUE_TRANSFERRED, &[ - output_pointer_casted.into(), - output_length_pointer_casted.into(), + output_pointer.to_int(context).into(), + output_length_pointer.to_int(context).into(), ], ); - - let value = context.build_load(output_pointer, "transferred_value")?; - let value_extended = context.builder().build_int_z_extend( - value.into_int_value(), - context.word_type(), - "transferred_value_extended", - )?; - Ok(value_extended.as_basic_value_enum()) + context.build_load_word( + output_pointer, + revive_common::BIT_LENGTH_VALUE, + "value_transferred", + ) } /// Translates the `balance` instructions.