implement the value opcode

Signed-off-by: xermicus <cyrill@parity.io>
This commit is contained in:
xermicus
2024-04-17 18:05:51 +02:00
parent 09b905415b
commit b208daed7e
8 changed files with 78 additions and 4 deletions
+3
View File
@@ -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;
+4 -1
View File
@@ -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;
+5
View File
@@ -0,0 +1,5 @@
contract Value {
function value() public payable returns (uint ret) {
ret = msg.value;
}
}
+21
View File
@@ -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!(
+1 -1
View File
@@ -88,7 +88,7 @@ fn link_host_functions(engine: &Engine) -> Linker<State> {
|caller: Caller<State>, 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())?;
+1 -1
View File
@@ -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);
@@ -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.
///
+37 -1
View File
@@ -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())
}
///