mirror of
https://github.com/pezkuwichain/revive.git
synced 2026-06-14 15:41:04 +00:00
@@ -2,9 +2,9 @@
|
|||||||
"Baseline": 934,
|
"Baseline": 934,
|
||||||
"Computation": 4360,
|
"Computation": 4360,
|
||||||
"DivisionArithmetics": 39448,
|
"DivisionArithmetics": 39448,
|
||||||
"ERC20": 52961,
|
"ERC20": 46624,
|
||||||
"Events": 1749,
|
"Events": 1749,
|
||||||
"FibonacciIterative": 2973,
|
"FibonacciIterative": 2973,
|
||||||
"Flipper": 3549,
|
"Flipper": 3563,
|
||||||
"SHA1": 32786
|
"SHA1": 32709
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
pragma solidity ^0.8;
|
||||||
|
|
||||||
|
contract Storage {
|
||||||
|
function transient(uint value) public returns (uint ret) {
|
||||||
|
assembly {
|
||||||
|
let slot := 123
|
||||||
|
tstore(slot, value)
|
||||||
|
let success := call(0, 0, 0, 0, 0, 0, 0)
|
||||||
|
ret := tload(slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -160,6 +160,12 @@ sol!(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
sol!(
|
||||||
|
contract Storage {
|
||||||
|
function transient(uint value) public returns (uint ret);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
impl Contract {
|
impl Contract {
|
||||||
/// Execute the contract.
|
/// Execute the contract.
|
||||||
///
|
///
|
||||||
@@ -526,6 +532,18 @@ impl Contract {
|
|||||||
calldata: Bitwise::opByteCall::new((index, value)).abi_encode(),
|
calldata: Bitwise::opByteCall::new((index, value)).abi_encode(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn storage_transient(value: U256) -> Self {
|
||||||
|
let code = include_str!("../contracts/Storage.sol");
|
||||||
|
let name = "Storage";
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name,
|
||||||
|
evm_runtime: crate::compile_evm_bin_runtime(name, code),
|
||||||
|
pvm_runtime: crate::compile_blob(name, code),
|
||||||
|
calldata: Storage::transientCall::new((value,)).abi_encode(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ impl Default for Frame {
|
|||||||
#[derive(Default, Clone, Debug)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
state: State,
|
state: State,
|
||||||
|
transient_state: State,
|
||||||
stack: Vec<Frame>,
|
stack: Vec<Frame>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +138,16 @@ impl Transaction {
|
|||||||
fn create2(&self, salt: B256, blob_hash: B256) -> Address {
|
fn create2(&self, salt: B256, blob_hash: B256) -> Address {
|
||||||
self.top_frame().callee.create2(salt, blob_hash)
|
self.top_frame().callee.create2(salt, blob_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn transient_account_mut(&mut self) -> &mut Account {
|
||||||
|
let address = self.top_frame().callee;
|
||||||
|
let account = self
|
||||||
|
.transient_state
|
||||||
|
.accounts_mut()
|
||||||
|
.entry(address)
|
||||||
|
.or_default();
|
||||||
|
account
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper to create valid transactions.
|
/// Helper to create valid transactions.
|
||||||
@@ -277,6 +288,7 @@ impl From<State> for TransactionBuilder {
|
|||||||
state_before: state.clone(),
|
state_before: state.clone(),
|
||||||
context: Transaction {
|
context: Transaction {
|
||||||
state,
|
state,
|
||||||
|
transient_state: Default::default(),
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -312,6 +324,7 @@ impl State {
|
|||||||
state_before: self.clone(),
|
state_before: self.clone(),
|
||||||
context: Transaction {
|
context: Transaction {
|
||||||
state: self,
|
state: self,
|
||||||
|
transient_state: Default::default(),
|
||||||
stack: vec![Default::default()],
|
stack: vec![Default::default()],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -435,6 +448,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::imports::SET_STORAGE,
|
runtime_api::imports::SET_STORAGE,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
|
transient: u32,
|
||||||
key_ptr: u32,
|
key_ptr: u32,
|
||||||
key_len: u32,
|
key_len: u32,
|
||||||
value_ptr: u32,
|
value_ptr: u32,
|
||||||
@@ -461,7 +475,12 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
|
|
||||||
log::info!("set storage {key} = {value}");
|
log::info!("set storage {key} = {value}");
|
||||||
|
|
||||||
transaction.top_account_mut().storage.insert(key, value);
|
let storage = if transient == 0 {
|
||||||
|
&mut transaction.top_account_mut().storage
|
||||||
|
} else {
|
||||||
|
&mut transaction.transient_account_mut().storage
|
||||||
|
};
|
||||||
|
storage.insert(key, value);
|
||||||
|
|
||||||
Ok(0)
|
Ok(0)
|
||||||
},
|
},
|
||||||
@@ -472,6 +491,7 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
.func_wrap(
|
.func_wrap(
|
||||||
runtime_api::imports::GET_STORAGE,
|
runtime_api::imports::GET_STORAGE,
|
||||||
|caller: Caller<Transaction>,
|
|caller: Caller<Transaction>,
|
||||||
|
transient: u32,
|
||||||
key_ptr: u32,
|
key_ptr: u32,
|
||||||
key_len: u32,
|
key_len: u32,
|
||||||
out_ptr: u32,
|
out_ptr: u32,
|
||||||
@@ -488,12 +508,13 @@ fn link_host_functions(engine: &Engine) -> Linker<Transaction> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let key = U256::from_le_bytes::<32>(key.try_into().unwrap());
|
let key = U256::from_le_bytes::<32>(key.try_into().unwrap());
|
||||||
let value = transaction
|
|
||||||
.top_account_mut()
|
let storage = if transient == 0 {
|
||||||
.storage
|
&transaction.top_account_mut().storage
|
||||||
.get(&key)
|
} else {
|
||||||
.cloned()
|
&transaction.transient_account_mut().storage
|
||||||
.unwrap_or_default();
|
};
|
||||||
|
let value = storage.get(&key).cloned().unwrap_or_default();
|
||||||
|
|
||||||
log::info!("get storage {key} = {value}");
|
log::info!("get storage {key} = {value}");
|
||||||
|
|
||||||
|
|||||||
@@ -614,3 +614,16 @@ fn bitwise_byte() {
|
|||||||
assert_eq!(expected, received)
|
assert_eq!(expected, received)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transient_storage() {
|
||||||
|
let expected = U256::MAX;
|
||||||
|
let (state, output) = assert_success(&Contract::storage_transient(expected), false);
|
||||||
|
let received = U256::abi_decode(&output.data, true).unwrap();
|
||||||
|
assert_eq!(expected, received);
|
||||||
|
|
||||||
|
assert!(state
|
||||||
|
.accounts()
|
||||||
|
.values()
|
||||||
|
.all(|account| account.storage.is_empty()));
|
||||||
|
}
|
||||||
|
|||||||
@@ -673,8 +673,7 @@ where
|
|||||||
|
|
||||||
self.build_byte_swap(value)
|
self.build_byte_swap(value)
|
||||||
}
|
}
|
||||||
AddressSpace::TransientStorage => todo!(),
|
AddressSpace::Storage | AddressSpace::TransientStorage => {
|
||||||
AddressSpace::Storage => {
|
|
||||||
let storage_key_value = self.builder().build_ptr_to_int(
|
let storage_key_value = self.builder().build_ptr_to_int(
|
||||||
pointer.value,
|
pointer.value,
|
||||||
self.word_type(),
|
self.word_type(),
|
||||||
@@ -692,9 +691,12 @@ where
|
|||||||
let (storage_value_pointer, storage_value_length_pointer) = self
|
let (storage_value_pointer, storage_value_length_pointer) = self
|
||||||
.build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer");
|
.build_stack_parameter(revive_common::BIT_LENGTH_WORD, "storage_value_pointer");
|
||||||
|
|
||||||
|
let transient = pointer.address_space == AddressSpace::TransientStorage;
|
||||||
|
|
||||||
self.build_runtime_call(
|
self.build_runtime_call(
|
||||||
runtime_api::imports::GET_STORAGE,
|
runtime_api::imports::GET_STORAGE,
|
||||||
&[
|
&[
|
||||||
|
self.xlen_type().const_int(transient as u64, false).into(),
|
||||||
storage_key_pointer_casted.into(),
|
storage_key_pointer_casted.into(),
|
||||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||||
storage_value_pointer.to_int(self).into(),
|
storage_value_pointer.to_int(self).into(),
|
||||||
@@ -758,8 +760,7 @@ where
|
|||||||
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
|
.set_alignment(revive_common::BYTE_LENGTH_BYTE as u32)
|
||||||
.expect("Alignment is valid");
|
.expect("Alignment is valid");
|
||||||
}
|
}
|
||||||
AddressSpace::TransientStorage => todo!(),
|
AddressSpace::Storage | AddressSpace::TransientStorage => {
|
||||||
AddressSpace::Storage => {
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
value.as_basic_value_enum().get_type(),
|
value.as_basic_value_enum().get_type(),
|
||||||
self.word_type().as_basic_type_enum()
|
self.word_type().as_basic_type_enum()
|
||||||
@@ -789,9 +790,12 @@ where
|
|||||||
self.builder()
|
self.builder()
|
||||||
.build_store(storage_value_pointer.value, value)?;
|
.build_store(storage_value_pointer.value, value)?;
|
||||||
|
|
||||||
|
let transient = pointer.address_space == AddressSpace::TransientStorage;
|
||||||
|
|
||||||
self.build_runtime_call(
|
self.build_runtime_call(
|
||||||
runtime_api::imports::SET_STORAGE,
|
runtime_api::imports::SET_STORAGE,
|
||||||
&[
|
&[
|
||||||
|
self.xlen_type().const_int(transient as u64, false).into(),
|
||||||
storage_key_pointer_casted.into(),
|
storage_key_pointer_casted.into(),
|
||||||
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
self.integer_const(crate::polkavm::XLEN, 32).into(),
|
||||||
storage_value_pointer_casted.into(),
|
storage_value_pointer_casted.into(),
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ POLKAVM_IMPORT(void, returndatacopy, uint32_t, uint32_t, uint32_t)
|
|||||||
|
|
||||||
POLKAVM_IMPORT(void, value_transferred, uint32_t, uint32_t)
|
POLKAVM_IMPORT(void, value_transferred, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, set_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, get_storage, uint32_t, uint32_t, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, get_storage, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t)
|
||||||
|
|
||||||
POLKAVM_IMPORT(uint32_t, clear_storage, uint32_t, uint32_t)
|
POLKAVM_IMPORT(uint32_t, clear_storage, uint32_t, uint32_t)
|
||||||
|
|
||||||
|
|||||||
@@ -742,12 +742,21 @@ where
|
|||||||
.map(|_| None)
|
.map(|_| None)
|
||||||
}
|
}
|
||||||
InstructionName::TLOAD => {
|
InstructionName::TLOAD => {
|
||||||
let _arguments = self.pop_arguments_llvm(context);
|
let arguments = self.pop_arguments_llvm(context);
|
||||||
anyhow::bail!("The `TLOAD` instruction is not supported until zkVM v1.5.0");
|
revive_llvm_context::polkavm_evm_storage::transient_load(
|
||||||
|
context,
|
||||||
|
arguments[0].into_int_value(),
|
||||||
|
)
|
||||||
|
.map(Some)
|
||||||
}
|
}
|
||||||
InstructionName::TSTORE => {
|
InstructionName::TSTORE => {
|
||||||
let _arguments = self.pop_arguments_llvm(context);
|
let arguments = self.pop_arguments_llvm(context);
|
||||||
anyhow::bail!("The `TSTORE` instruction is not supported until zkVM v1.5.0");
|
revive_llvm_context::polkavm_evm_storage::transient_store(
|
||||||
|
context,
|
||||||
|
arguments[0].into_int_value(),
|
||||||
|
arguments[1].into_int_value(),
|
||||||
|
)
|
||||||
|
.map(|_| None)
|
||||||
}
|
}
|
||||||
InstructionName::PUSHIMMUTABLE => {
|
InstructionName::PUSHIMMUTABLE => {
|
||||||
let key = self
|
let key = self
|
||||||
|
|||||||
@@ -485,18 +485,21 @@ impl FunctionCall {
|
|||||||
.map(|_| None)
|
.map(|_| None)
|
||||||
}
|
}
|
||||||
Name::TLoad => {
|
Name::TLoad => {
|
||||||
let _arguments = self.pop_arguments_llvm::<D, 1>(context)?;
|
let arguments = self.pop_arguments_llvm::<D, 1>(context)?;
|
||||||
anyhow::bail!(
|
revive_llvm_context::polkavm_evm_storage::transient_load(
|
||||||
"{} The `TLOAD` instruction is not supported until zkVM v1.5.0",
|
context,
|
||||||
location
|
arguments[0].into_int_value(),
|
||||||
);
|
)
|
||||||
|
.map(Some)
|
||||||
}
|
}
|
||||||
Name::TStore => {
|
Name::TStore => {
|
||||||
let _arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
let arguments = self.pop_arguments_llvm::<D, 2>(context)?;
|
||||||
anyhow::bail!(
|
revive_llvm_context::polkavm_evm_storage::transient_store(
|
||||||
"{} The `TSTORE` instruction is not supported until zkVM v1.5.0",
|
context,
|
||||||
location
|
arguments[0].into_int_value(),
|
||||||
);
|
arguments[1].into_int_value(),
|
||||||
|
)
|
||||||
|
.map(|_| None)
|
||||||
}
|
}
|
||||||
Name::LoadImmutable => todo!(),
|
Name::LoadImmutable => todo!(),
|
||||||
Name::SetImmutable => {
|
Name::SetImmutable => {
|
||||||
|
|||||||
Reference in New Issue
Block a user