From 199f36585a90c59c5a90296a20c001198a90e7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 8 Nov 2022 21:48:56 +0100 Subject: [PATCH] test: Improve precision of SSTORE cost in EVMHost Add "original" field to storage_value to precise track "dirty" state of a storage slot as defined in EIP-2200. In case a current storage value is restored to original (after multiple modifications in a single transaction), the storage slot is not considered "dirty" any more. Previously, we only had a bool dirty flag to model this and a storage slot was always considered "dirty" after first modification. --- test/EVMHost.cpp | 4 ++-- test/ExecutionFramework.cpp | 2 +- test/evmc/mocked_host.hpp | 33 +++++++++++---------------------- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/test/EVMHost.cpp b/test/EVMHost.cpp index 3e62a39de..e997c394a 100644 --- a/test/EVMHost.cpp +++ b/test/EVMHost.cpp @@ -179,7 +179,7 @@ void EVMHost::newTransactionFrame() for (auto& [slot, value]: account.storage) { value.access_status = EVMC_ACCESS_COLD; // Clear EIP-2929 storage access indicator - value.dirty = false; // Clear EIP-2200 dirty slot flag + value.original = value.current; // Clear EIP-2200 dirty slot } // Process selfdestruct list for (auto& [address, _]: recorded_selfdestructs) @@ -1195,7 +1195,7 @@ void EVMHostPrinter::storage() m_stateStream << " " << m_host.convertFromEVMC(slot) << ": " - << m_host.convertFromEVMC(value.value) + << m_host.convertFromEVMC(value.current) << endl; } diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index be2a283f7..ff0838c09 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -282,7 +282,7 @@ bool ExecutionFramework::storageEmpty(h160 const& _addr) const if (it != m_evmcHost->accounts.end()) { for (auto const& entry: it->second.storage) - if (!(entry.second.value == evmc::bytes32{})) + if (entry.second.current != evmc::bytes32{}) return false; } return true; diff --git a/test/evmc/mocked_host.hpp b/test/evmc/mocked_host.hpp index c7d99e6ad..5aee8ab05 100644 --- a/test/evmc/mocked_host.hpp +++ b/test/evmc/mocked_host.hpp @@ -15,30 +15,20 @@ namespace evmc /// The string of bytes. using bytes = std::basic_string; -/// Extended value (by dirty flag) for account storage. +/// Extended value (with original value and access flag) for account storage. struct storage_value { - /// The storage value. - bytes32 value; + /// The current storage value. + bytes32 current; - /// True means this value has been modified already by the current transaction. - bool dirty{false}; + /// The original storage value. + bytes32 original; /// Is the storage key cold or warm. - evmc_access_status access_status{EVMC_ACCESS_COLD}; + evmc_access_status access_status = EVMC_ACCESS_COLD; /// Default constructor. storage_value() noexcept = default; - - /// Constructor. - storage_value(const bytes32& _value, bool _dirty = false) noexcept // NOLINT - : value{_value}, dirty{_dirty} - {} - - /// Constructor with initial access status. - storage_value(const bytes32& _value, evmc_access_status _access_status) noexcept - : value{_value}, access_status{_access_status} - {} }; /// Mocked account. @@ -176,7 +166,7 @@ public: const auto storage_iter = account_iter->second.storage.find(key); if (storage_iter != account_iter->second.storage.end()) - return storage_iter->second.value; + return storage_iter->second.current; return {}; } @@ -195,14 +185,13 @@ public: // Follow https://eips.ethereum.org/EIPS/eip-1283 specification. // WARNING! This is not complete implementation as refund is not handled here. - if (old.value == value) + if (old.current == value) return EVMC_STORAGE_UNCHANGED; evmc_storage_status status{}; - if (!old.dirty) + if (old.original == old.current) // Storage slot not dirty { - old.dirty = true; - if (!old.value) + if (!old.current) status = EVMC_STORAGE_ADDED; else if (value) status = EVMC_STORAGE_MODIFIED; @@ -212,7 +201,7 @@ public: else status = EVMC_STORAGE_MODIFIED_AGAIN; - old.value = value; + old.current = value; return status; }