switch to the new storage API (#396)

This PR switches to the new `get_storage_or_zero` and
`set_storage_or_clear` syscalls which are more tailored towards
Solidity.

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
xermicus
2025-10-30 14:13:37 +01:00
committed by GitHub
parent 42cac55be8
commit 84018c18ae
5 changed files with 20 additions and 38 deletions
+2 -2
View File
@@ -2,9 +2,9 @@
"Baseline": 914, "Baseline": 914,
"Computation": 2295, "Computation": 2295,
"DivisionArithmetics": 14510, "DivisionArithmetics": 14510,
"ERC20": 17499, "ERC20": 17482,
"Events": 1674, "Events": 1674,
"FibonacciIterative": 1490, "FibonacciIterative": 1490,
"Flipper": 2102, "Flipper": 2086,
"SHA1": 8158 "SHA1": 8158
} }
@@ -157,6 +157,10 @@ fn emit_load<'ctx>(
key: BasicValueEnum<'ctx>, key: BasicValueEnum<'ctx>,
transient: bool, transient: bool,
) -> anyhow::Result<BasicValueEnum<'ctx>> { ) -> anyhow::Result<BasicValueEnum<'ctx>> {
let is_transient = context.xlen_type().const_int(transient as u64, false);
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let mut key = context.build_load( let mut key = context.build_load(
super::Pointer::new( super::Pointer::new(
context.word_type(), context.word_type(),
@@ -168,33 +172,17 @@ fn emit_load<'ctx>(
if !transient { if !transient {
key = context.build_byte_swap(key)?; key = context.build_byte_swap(key)?;
} }
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let length_pointer = context.build_alloca_at_entry(context.xlen_type(), "length_pointer");
context.builder().build_store(key_pointer.value, key)?; context.builder().build_store(key_pointer.value, key)?;
context.build_store(value_pointer, context.word_const(0))?;
context.build_store(
length_pointer,
context
.xlen_type()
.const_int(revive_common::BYTE_LENGTH_WORD as u64, false),
)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [ let arguments = [
is_transient.into(), is_transient.into(),
key_pointer.to_int(context).into(), key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(), value_pointer.to_int(context).into(),
length_pointer.to_int(context).into(),
]; ];
context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments); context.build_runtime_call(revive_runtime_api::polkavm_imports::GET_STORAGE, &arguments);
// We do not to check the return value: Solidity assumes infallible loads. // We do not to check the return value: Solidity assumes infallible loads.
// If a key doesn't exist the "zero" value is returned (ensured by above write). // If a key doesn't exist the syscall returns zero.
let value = context.build_load(value_pointer, "storage_value")?; let value = context.build_load(value_pointer, "storage_value")?;
Ok(if transient { Ok(if transient {
@@ -210,6 +198,10 @@ fn emit_store<'ctx>(
value: BasicValueEnum<'ctx>, value: BasicValueEnum<'ctx>,
transient: bool, transient: bool,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
let is_transient = context.xlen_type().const_int(transient as u64, false);
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
let mut key = context.build_load( let mut key = context.build_load(
super::Pointer::new( super::Pointer::new(
context.word_type(), context.word_type(),
@@ -224,27 +216,20 @@ fn emit_store<'ctx>(
Default::default(), Default::default(),
value.into_pointer_value(), value.into_pointer_value(),
), ),
"key", "value",
)?; )?;
if !transient { if !transient {
key = context.build_byte_swap(key)?; key = context.build_byte_swap(key)?;
value = context.build_byte_swap(value)?; value = context.build_byte_swap(value)?;
} }
let key_pointer = context.build_alloca_at_entry(context.word_type(), "key_pointer");
let value_pointer = context.build_alloca_at_entry(context.word_type(), "value_pointer");
context.build_store(key_pointer, key)?; context.build_store(key_pointer, key)?;
context.build_store(value_pointer, value)?; context.build_store(value_pointer, value)?;
let is_transient = context.xlen_type().const_int(transient as u64, false);
let arguments = [ let arguments = [
is_transient.into(), is_transient.into(),
key_pointer.to_int(context).into(), key_pointer.to_int(context).into(),
context.xlen_type().const_all_ones().into(),
value_pointer.to_int(context).into(), value_pointer.to_int(context).into(),
context.integer_const(crate::polkavm::XLEN, 32).into(),
]; ];
context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments); context.build_runtime_call(revive_runtime_api::polkavm_imports::SET_STORAGE, &arguments);
+4 -7
View File
@@ -510,13 +510,10 @@ impl Specs {
expected, expected,
} => { } => {
let address = contract.to_eth_addr(&results); let address = contract.to_eth_addr(&results);
let Ok(value) = Contracts::get_storage(address, key) else { let value = Contracts::get_storage(address, key)
panic!("error reading storage for address {address}"); .unwrap_or_else(|error| panic!("at {address}: {error:?}"))
}; .unwrap_or_else(|| vec![0; 32]);
let Some(value) = value else { assert_eq!(value, expected, "at {address} key 0x{}", hex::encode(key));
panic!("no value at {address} key 0x{}", hex::encode(key));
};
assert_eq!(value, expected, "at key 0x{}", hex::encode(key));
} }
} }
} }
+2 -2
View File
@@ -79,7 +79,7 @@ POLKAVM_IMPORT(uint64_t, gas_price);
POLKAVM_IMPORT(void, get_immutable_data, uint32_t, uint32_t); POLKAVM_IMPORT(void, get_immutable_data, uint32_t, uint32_t);
POLKAVM_IMPORT(uint64_t, get_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) POLKAVM_IMPORT(uint64_t, get_storage_or_zero, uint32_t, uint32_t, uint32_t)
POLKAVM_IMPORT(void, hash_keccak_256, uint32_t, uint32_t, uint32_t) POLKAVM_IMPORT(void, hash_keccak_256, uint32_t, uint32_t, uint32_t)
@@ -99,7 +99,7 @@ POLKAVM_IMPORT(uint64_t, return_data_size)
POLKAVM_IMPORT(void, set_immutable_data, uint32_t, uint32_t); POLKAVM_IMPORT(void, set_immutable_data, uint32_t, uint32_t);
POLKAVM_IMPORT(uint64_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t) POLKAVM_IMPORT(uint64_t, set_storage_or_clear, uint32_t, uint32_t, uint32_t)
POLKAVM_IMPORT(void, value_transferred, uint32_t) POLKAVM_IMPORT(void, value_transferred, uint32_t)
+2 -2
View File
@@ -42,7 +42,7 @@ pub static GAS_PRICE: &str = "gas_price";
pub static GET_IMMUTABLE_DATA: &str = "get_immutable_data"; pub static GET_IMMUTABLE_DATA: &str = "get_immutable_data";
pub static GET_STORAGE: &str = "get_storage"; pub static GET_STORAGE: &str = "get_storage_or_zero";
pub static HASH_KECCAK_256: &str = "hash_keccak_256"; pub static HASH_KECCAK_256: &str = "hash_keccak_256";
@@ -62,7 +62,7 @@ pub static RETURNDATASIZE: &str = "return_data_size";
pub static SET_IMMUTABLE_DATA: &str = "set_immutable_data"; pub static SET_IMMUTABLE_DATA: &str = "set_immutable_data";
pub static SET_STORAGE: &str = "set_storage"; pub static SET_STORAGE: &str = "set_storage_or_clear";
pub static VALUE_TRANSFERRED: &str = "value_transferred"; pub static VALUE_TRANSFERRED: &str = "value_transferred";