diff --git a/crates/integration/codesize.json b/crates/integration/codesize.json index 41a8ab4..dae0305 100644 --- a/crates/integration/codesize.json +++ b/crates/integration/codesize.json @@ -2,9 +2,9 @@ "Baseline": 914, "Computation": 2295, "DivisionArithmetics": 14510, - "ERC20": 17499, + "ERC20": 17482, "Events": 1674, "FibonacciIterative": 1490, - "Flipper": 2102, + "Flipper": 2086, "SHA1": 8158 } \ No newline at end of file diff --git a/crates/llvm-context/src/polkavm/context/pointer/storage.rs b/crates/llvm-context/src/polkavm/context/pointer/storage.rs index 36a45ed..c7293c5 100644 --- a/crates/llvm-context/src/polkavm/context/pointer/storage.rs +++ b/crates/llvm-context/src/polkavm/context/pointer/storage.rs @@ -157,6 +157,10 @@ fn emit_load<'ctx>( key: BasicValueEnum<'ctx>, transient: bool, ) -> 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( super::Pointer::new( context.word_type(), @@ -168,33 +172,17 @@ fn emit_load<'ctx>( if !transient { 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.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 = [ is_transient.into(), key_pointer.to_int(context).into(), - context.xlen_type().const_all_ones().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); // 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")?; Ok(if transient { @@ -210,6 +198,10 @@ fn emit_store<'ctx>( value: BasicValueEnum<'ctx>, transient: bool, ) -> 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( super::Pointer::new( context.word_type(), @@ -224,27 +216,20 @@ fn emit_store<'ctx>( Default::default(), value.into_pointer_value(), ), - "key", + "value", )?; if !transient { key = context.build_byte_swap(key)?; 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(value_pointer, value)?; - let is_transient = context.xlen_type().const_int(transient as u64, false); - let arguments = [ is_transient.into(), key_pointer.to_int(context).into(), - context.xlen_type().const_all_ones().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); diff --git a/crates/runner/src/specs.rs b/crates/runner/src/specs.rs index 1a4e90a..bf808d5 100644 --- a/crates/runner/src/specs.rs +++ b/crates/runner/src/specs.rs @@ -510,13 +510,10 @@ impl Specs { expected, } => { let address = contract.to_eth_addr(&results); - let Ok(value) = Contracts::get_storage(address, key) else { - panic!("error reading storage for address {address}"); - }; - let Some(value) = value else { - panic!("no value at {address} key 0x{}", hex::encode(key)); - }; - assert_eq!(value, expected, "at key 0x{}", hex::encode(key)); + let value = Contracts::get_storage(address, key) + .unwrap_or_else(|error| panic!("at {address}: {error:?}")) + .unwrap_or_else(|| vec![0; 32]); + assert_eq!(value, expected, "at {address} key 0x{}", hex::encode(key)); } } } diff --git a/crates/runtime-api/src/polkavm_imports.c b/crates/runtime-api/src/polkavm_imports.c index 10f974d..0c4c73a 100644 --- a/crates/runtime-api/src/polkavm_imports.c +++ b/crates/runtime-api/src/polkavm_imports.c @@ -79,7 +79,7 @@ POLKAVM_IMPORT(uint64_t, gas_price); 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) @@ -99,7 +99,7 @@ POLKAVM_IMPORT(uint64_t, return_data_size) 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) diff --git a/crates/runtime-api/src/polkavm_imports.rs b/crates/runtime-api/src/polkavm_imports.rs index 42ca88a..e88e4df 100644 --- a/crates/runtime-api/src/polkavm_imports.rs +++ b/crates/runtime-api/src/polkavm_imports.rs @@ -42,7 +42,7 @@ pub static GAS_PRICE: &str = "gas_price"; 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"; @@ -62,7 +62,7 @@ pub static RETURNDATASIZE: &str = "return_data_size"; 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";