diff --git a/src/eth_client/libethereum/ExtVM.cpp b/src/eth_client/libethereum/ExtVM.cpp index 5b450e1724..5c977cea13 100644 --- a/src/eth_client/libethereum/ExtVM.cpp +++ b/src/eth_client/libethereum/ExtVM.cpp @@ -134,6 +134,11 @@ void ExtVM::setStore(u256 _n, u256 _v) m_s.setStorage(myAddress, _n, _v); } +void ExtVM::setTransientStore(u256 _n, u256 _v) +{ + m_s.setTransientStorage(myAddress, _n, _v); +} + CreateResult ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, Instruction _op, u256 _salt, OnOpFunc const& _onOp) { Executive e{m_s, envInfo(), m_sealEngine, depth + 1}; diff --git a/src/eth_client/libethereum/ExtVM.h b/src/eth_client/libethereum/ExtVM.h index 8d0d882cc8..fce7659924 100644 --- a/src/eth_client/libethereum/ExtVM.h +++ b/src/eth_client/libethereum/ExtVM.h @@ -48,6 +48,12 @@ class ExtVM : public ExtVMFace /// Write a value in storage. void setStore(u256 _n, u256 _v) final; + /// Read transient storage location. + u256 transientStore(u256 _n) final { return m_s.transientStorage(myAddress, _n); } + + /// Write a value in transient storage. + void setTransientStore(u256 _n, u256 _v) final; + /// Read original storage value (before modifications in the current transaction). u256 originalStorageValue(u256 const& _key) final { diff --git a/src/eth_client/libethereum/State.cpp b/src/eth_client/libethereum/State.cpp index 4c91fcc41c..487703ff81 100644 --- a/src/eth_client/libethereum/State.cpp +++ b/src/eth_client/libethereum/State.cpp @@ -443,6 +443,23 @@ void State::setStorage(Address const& _contract, u256 const& _key, u256 const& _ m_cache[_contract].setStorage(_key, _value); } +u256 State::transientStorage(Address const& _id, u256 const& _key) const +{ + const auto accountIter = m_transientCache.find(_id); + if (accountIter == m_transientCache.end()) + return {}; + + const auto storageIter = accountIter->second.transientStorage.find(_key); + if (storageIter != accountIter->second.transientStorage.end()) + return storageIter->second; + return {}; +} + +void State::setTransientStorage(Address const& _contract, u256 const& _key, u256 const& _value) +{ + m_transientCache[_contract].transientStorage[_key] = _value; +} + u256 State::originalStorageValue(Address const& _contract, u256 const& _key) const { if (Account const* a = account(_contract)) @@ -460,6 +477,11 @@ void State::clearStorage(Address const& _contract) m_cache[_contract].clearStorage(); } +void State::clearTransientStorage() +{ + m_transientCache.clear(); +} + map> State::storage(Address const& _id) const { #if ETH_FATDB diff --git a/src/eth_client/libethereum/State.h b/src/eth_client/libethereum/State.h index b9133386f3..e1bf06f96e 100644 --- a/src/eth_client/libethereum/State.h +++ b/src/eth_client/libethereum/State.h @@ -121,6 +121,13 @@ struct Change using ChangeLog = std::vector; +class TransientAccount +{ +public: + /// The account transient storage. + std::unordered_map transientStorage; +}; + /** * Model of an Ethereum state, essentially a facade for the trie. * @@ -233,6 +240,13 @@ class State /// Set the value of a storage position of an account. void setStorage(Address const& _contract, u256 const& _location, u256 const& _value); + /// Get the value of a transient storage position of an account. + /// @returns 0 if no account exists at that address. + u256 transientStorage(Address const& _contract, u256 const& _memory) const; + + /// Set the value of a transient storage position of an account. + void setTransientStorage(Address const& _contract, u256 const& _location, u256 const& _value); + /// Get the original value of a storage position of an account (before modifications saved in /// account cache). /// @returns 0 if no account exists at that address. @@ -241,6 +255,9 @@ class State /// Clear the storage root hash of an account to the hash of the empty trie. void clearStorage(Address const& _contract); + /// Clear the transient storage. + void clearTransientStorage(); + /// Create a contract at the given address (with unset code and unchanged balance). void createContract(Address const& _address); @@ -340,6 +357,8 @@ class State /// Our address cache. This stores the states of each address that has (or at least might have) /// been changed. mutable std::unordered_map m_cache; + /// Our address cache. This stores the states of each address that has transient storage. + mutable std::unordered_map m_transientCache; /// Tracks entries in m_cache that can potentially be purged if it grows too large. mutable std::vector
m_unchangedCacheEntries; /// Tracks addresses that are known to not exist. diff --git a/src/eth_client/libevm/ExtVMFace.cpp b/src/eth_client/libevm/ExtVMFace.cpp index 47582e3496..5024aa666f 100644 --- a/src/eth_client/libevm/ExtVMFace.cpp +++ b/src/eth_client/libevm/ExtVMFace.cpp @@ -239,26 +239,22 @@ evmc_access_status EvmCHost::access_storage(const evmc::address& addr, return access_status; } -evmc::bytes32 EvmCHost::get_transient_storage(const evmc::address& addr, const evmc::bytes32& key) const noexcept +evmc::bytes32 EvmCHost::get_transient_storage(const evmc::address& _addr, const evmc::bytes32& _key) const noexcept { - record_account_access(addr); - - const auto account_iter = accounts.find(addr); - if (account_iter == accounts.end()) - return {}; - - const auto storage_iter = account_iter->second.transient_storage.find(key); - if (storage_iter != account_iter->second.transient_storage.end()) - return storage_iter->second; - return {}; + assert(fromEvmC(_addr) == m_extVM.myAddress); + record_account_access(_addr); + return toEvmC(m_extVM.transientStore(fromEvmC(_key))); } -void EvmCHost::set_transient_storage(const evmc::address& addr, - const evmc::bytes32& key, - const evmc::bytes32& value) noexcept +void EvmCHost::set_transient_storage(const evmc::address& _addr, + const evmc::bytes32& _key, + const evmc::bytes32& _value) noexcept { - record_account_access(addr); - accounts[addr].transient_storage[key] = value; + assert(fromEvmC(_addr) == m_extVM.myAddress); + record_account_access(_addr); + u256 const index = fromEvmC(_key); + u256 const newValue = fromEvmC(_value); + m_extVM.setTransientStore(index, newValue); } void EvmCHost::record_account_access(const evmc::address& addr) const diff --git a/src/eth_client/libevm/ExtVMFace.h b/src/eth_client/libevm/ExtVMFace.h index af174aa207..cbd5ee7cf5 100644 --- a/src/eth_client/libevm/ExtVMFace.h +++ b/src/eth_client/libevm/ExtVMFace.h @@ -210,6 +210,12 @@ class ExtVMFace /// Write a value in storage. virtual void setStore(u256, u256) {} + /// Read transient storage location. + virtual u256 transientStore(u256) { return 0; } + + /// Write a value in transient storage. + virtual void setTransientStore(u256, u256) {} + /// Read original storage value (before modifications in the current transaction). virtual u256 originalStorageValue(u256 const&) { return 0; } @@ -308,9 +314,6 @@ struct AccessAccount /// The account storage map. std::map storage; - /// The account transient storage. - std::unordered_map transient_storage; - /// Default constructor. AccessAccount() noexcept = default; }; diff --git a/src/validation.cpp b/src/validation.cpp index a0beb996f8..0e911990fb 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2936,7 +2936,20 @@ void LastHashes::clear() m_lastHashes.clear(); } +class ExecTransientStorage +{ +public: + void init() { + globalState->clearTransientStorage(); + } + ~ExecTransientStorage() { + globalState->clearTransientStorage(); + } +}; + bool ByteCodeExec::performByteCode(dev::eth::Permanence type){ + ExecTransientStorage storage; + storage.init(); for(QtumTransaction& tx : txs){ //validate VM version if(tx.getVersion().toRaw() != VersionVM::GetEVMDefault().toRaw()){