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.
This commit is contained in:
Paweł Bylica 2022-11-08 21:48:56 +01:00 committed by Paweł Bylica
parent 9db2da0385
commit 199f36585a
No known key found for this signature in database
GPG Key ID: 7A0C037434FE77EF
3 changed files with 14 additions and 25 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -15,30 +15,20 @@ namespace evmc
/// The string of bytes.
using bytes = std::basic_string<uint8_t>;
/// 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;
}