diff --git a/core/src/opcode.rs b/core/src/opcode.rs index b6affd5d..65c90cf5 100644 --- a/core/src/opcode.rs +++ b/core/src/opcode.rs @@ -227,6 +227,10 @@ impl Opcode { pub const SLOAD: Opcode = Opcode(0x54); /// `SSTORE` pub const SSTORE: Opcode = Opcode(0x55); + /// `TLOAD` + pub const TLOAD: Opcode = Opcode(0x5c); + /// `TSTORE` + pub const TSTORE: Opcode = Opcode(0x5d); /// `GAS` pub const GAS: Opcode = Opcode(0x5a); /// `LOGn` diff --git a/runtime/src/eval/mod.rs b/runtime/src/eval/mod.rs index f39bcd1e..00d8569a 100644 --- a/runtime/src/eval/mod.rs +++ b/runtime/src/eval/mod.rs @@ -44,6 +44,8 @@ pub fn eval(state: &mut Runtime, opcode: Opcode, handler: &mut H) -> Opcode::GASLIMIT => system::gaslimit(state, handler), Opcode::SLOAD => system::sload(state, handler), Opcode::SSTORE => system::sstore(state, handler), + Opcode::TLOAD => system::tload(state, handler), + Opcode::TSTORE => system::tstore(state, handler), Opcode::GAS => system::gas(state, handler), Opcode::LOG0 => system::log(state, 0, handler), Opcode::LOG1 => system::log(state, 1, handler), diff --git a/runtime/src/eval/system.rs b/runtime/src/eval/system.rs index 131f8bd3..73342a13 100644 --- a/runtime/src/eval/system.rs +++ b/runtime/src/eval/system.rs @@ -236,6 +236,27 @@ pub fn sstore(runtime: &mut Runtime, handler: &mut H) -> Control } } +pub fn tload(runtime: &mut Runtime, handler: &H) -> Control { + pop!(runtime, index); + let value = handler.transient_storage(index); + push!(runtime, value); + + event!(TLoad { index, value }); + + Control::Continue +} + +pub fn tstore(runtime: &mut Runtime, handler: &mut H) -> Control { + pop!(runtime, index, value); + + event!(TStore { index, value }); + + match handler.set_transient_storage(index, value) { + Ok(()) => Control::Continue, + Err(e) => Control::Exit(e.into()), + } +} + pub fn gas(runtime: &mut Runtime, handler: &H) -> Control { push_u256!(runtime, handler.gas_left()); diff --git a/runtime/src/handler.rs b/runtime/src/handler.rs index 7b338134..0a94d42a 100644 --- a/runtime/src/handler.rs +++ b/runtime/src/handler.rs @@ -35,6 +35,8 @@ pub trait Handler { fn code(&self, address: H160) -> Vec; /// Get storage value of address at index. fn storage(&self, address: H160, index: H256) -> H256; + /// Get transient storage value at index. + fn transient_storage(&self, index: H256) -> H256; /// Get original storage value of address at index. fn original_storage(&self, address: H160, index: H256) -> H256; @@ -79,6 +81,8 @@ pub trait Handler { /// Set storage value of address at index. fn set_storage(&mut self, address: H160, index: H256, value: H256) -> Result<(), ExitError>; + /// Set transient storage value at index. + fn set_transient_storage(&mut self, index: H256, value: H256) -> Result<(), ExitError>; /// Create a log owned by address with given topics and data. fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError>; /// Mark an address to be deleted, with funds transferred to target. diff --git a/runtime/src/tracing.rs b/runtime/src/tracing.rs index f9fed196..62f7e974 100644 --- a/runtime/src/tracing.rs +++ b/runtime/src/tracing.rs @@ -32,6 +32,14 @@ pub enum Event<'a> { index: H256, value: H256, }, + TLoad { + index: H256, + value: H256, + }, + TStore { + index: H256, + value: H256, + }, } // Expose `listener::with` to the crate only. diff --git a/src/backend/memory.rs b/src/backend/memory.rs index 26cc1d1a..2fd94ba2 100644 --- a/src/backend/memory.rs +++ b/src/backend/memory.rs @@ -63,15 +63,21 @@ pub struct MemoryAccount { pub struct MemoryBackend<'vicinity> { vicinity: &'vicinity MemoryVicinity, state: BTreeMap, + transient_state: BTreeMap, logs: Vec, } impl<'vicinity> MemoryBackend<'vicinity> { /// Create a new memory backend. - pub fn new(vicinity: &'vicinity MemoryVicinity, state: BTreeMap) -> Self { + pub fn new( + vicinity: &'vicinity MemoryVicinity, + state: BTreeMap, + transient_state: BTreeMap, + ) -> Self { Self { vicinity, state, + transient_state, logs: Vec::new(), } } @@ -163,6 +169,13 @@ impl<'vicinity> Backend for MemoryBackend<'vicinity> { .unwrap_or_default() } + fn transient_storage(&self, index: H256) -> H256 { + self.transient_state + .get(&index) + .cloned() + .unwrap_or_default() + } + fn original_storage(&self, address: H160, index: H256) -> Option { Some(self.storage(address, index)) } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index d423c423..916cf9b4 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -85,6 +85,8 @@ pub trait Backend { fn code(&self, address: H160) -> Vec; /// Get storage value of address at index. fn storage(&self, address: H160, index: H256) -> H256; + /// Get storage value at index. + fn transient_storage(&self, index: H256) -> H256; /// Get original storage value of address at index, if available. fn original_storage(&self, address: H160, index: H256) -> Option; } diff --git a/src/executor/stack/executor.rs b/src/executor/stack/executor.rs index 3ed497b9..428be1ce 100644 --- a/src/executor/stack/executor.rs +++ b/src/executor/stack/executor.rs @@ -206,6 +206,7 @@ pub trait StackState<'config>: Backend { fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>; fn set_storage(&mut self, address: H160, key: H256, value: H256); + fn set_transient_storage(&mut self, key: H256, value: H256); fn reset_storage(&mut self, address: H160); fn log(&mut self, address: H160, topics: Vec, data: Vec); fn set_deleted(&mut self, address: H160); @@ -1047,6 +1048,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler self.state.storage(address, index) } + fn transient_storage(&self, index: H256) -> H256 { + self.state.transient_storage(index) + } + fn original_storage(&self, address: H160, index: H256) -> H256 { self.state .original_storage(address, index) @@ -1137,6 +1142,11 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler Ok(()) } + fn set_transient_storage(&mut self, index: H256, value: H256) -> Result<(), ExitError> { + self.state.set_transient_storage(index, value); + Ok(()) + } + fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { self.state.log(address, topics, data); Ok(()) diff --git a/src/executor/stack/memory.rs b/src/executor/stack/memory.rs index b865a65b..a5112736 100644 --- a/src/executor/stack/memory.rs +++ b/src/executor/stack/memory.rs @@ -23,6 +23,7 @@ pub struct MemoryStackSubstate<'config> { logs: Vec, accounts: BTreeMap, storages: BTreeMap<(H160, H256), H256>, + transient_storages: BTreeMap, deletes: BTreeSet, } @@ -34,6 +35,7 @@ impl<'config> MemoryStackSubstate<'config> { logs: Vec::new(), accounts: BTreeMap::new(), storages: BTreeMap::new(), + transient_storages: BTreeMap::new(), deletes: BTreeSet::new(), } } @@ -119,6 +121,7 @@ impl<'config> MemoryStackSubstate<'config> { logs: Vec::new(), accounts: BTreeMap::new(), storages: BTreeMap::new(), + transient_storages: BTreeMap::new(), deletes: BTreeSet::new(), }; mem::swap(&mut entering, self); @@ -231,6 +234,17 @@ impl<'config> MemoryStackSubstate<'config> { None } + pub fn known_transient_storage(&self, key: H256) -> Option { + if let Some(value) = self.transient_storages.get(&key) { + return Some(*value); + } + + if let Some(parent) = self.parent.as_ref() { + return parent.known_transient_storage(key); + } + + None + } pub fn known_original_storage(&self, address: H160) -> Option { if let Some(account) = self.accounts.get(&address) { @@ -314,6 +328,10 @@ impl<'config> MemoryStackSubstate<'config> { self.storages.insert((address, key), value); } + pub fn set_transient_storage(&mut self, key: H256, value: H256) { + self.transient_storages.insert(key, value); + } + pub fn reset_storage(&mut self, address: H160, backend: &B) { let mut removing = Vec::new(); @@ -465,6 +483,12 @@ impl<'backend, 'config, B: Backend> Backend for MemoryStackState<'backend, 'conf .unwrap_or_else(|| self.backend.storage(address, key)) } + fn transient_storage(&self, key: H256) -> H256 { + self.substate + .known_transient_storage(key) + .unwrap_or_else(|| self.backend.transient_storage(key)) + } + fn original_storage(&self, address: H160, key: H256) -> Option { if let Some(value) = self.substate.known_original_storage(address) { return Some(value); @@ -529,6 +553,10 @@ impl<'backend, 'config, B: Backend> StackState<'config> for MemoryStackState<'ba self.substate.set_storage(address, key, value) } + fn set_transient_storage(&mut self, key: H256, value: H256) { + self.substate.set_transient_storage(key, value) + } + fn reset_storage(&mut self, address: H160) { self.substate.reset_storage(address, self.backend); }