Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mocked_host: create account in set_storage if non-existent #594

Merged
merged 3 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ include(CableCompilerSettings)
include(CablePackage)
include(CMakeDependentOption)
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)

option(EVMC_JAVA "Enable building Java Native Interface (JNI) bindings" OFF)

Expand Down Expand Up @@ -47,6 +46,8 @@ cable_set_build_type(DEFAULT Release CONFIGURATION_TYPES Debug Release)
project(evmc)
set(PROJECT_VERSION 8.1.0-alpha.0)

include(GNUInstallDirs) # Must be included after any language is enabled.

cable_configure_compiler(NO_STACK_PROTECTION)
if(CABLE_COMPILER_GNULIKE)
# TODO: Resolve issues or remove "result optional storage" and enable -Wcast-align.
Expand Down
9 changes: 5 additions & 4 deletions include/evmc/mocked_host.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,11 +185,12 @@ class MockedHost : public Host
const bytes32& value) noexcept override
{
record_account_access(addr);
const auto it = accounts.find(addr);
if (it == accounts.end())
return EVMC_STORAGE_UNCHANGED;

auto& old = it->second.storage[key];
// Get the reference to the old value.
// This will create the account in case it was not present.
// This is convenient for unit testing and standalone EVM execution to preserve the
// storage values after the execution terminates.
auto& old = accounts[addr].storage[key];

// Follow https://eips.ethereum.org/EIPS/eip-1283 specification.
// WARNING! This is not complete implementation as refund is not handled here.
Expand Down
7 changes: 5 additions & 2 deletions test/unittests/mocked_host_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ TEST(mocked_host, storage)
EXPECT_EQ(chost.get_storage(addr1, {}), evmc::bytes32{});
EXPECT_EQ(chost.get_storage(addr2, {}), evmc::bytes32{});

// Set storage on non-existing account has no effect.
EXPECT_EQ(host.set_storage(addr2, val1, val2), EVMC_STORAGE_UNCHANGED);
// Set storage on non-existing account creates the account.
EXPECT_EQ(host.set_storage(addr1, val1, val2), EVMC_STORAGE_ADDED);
EXPECT_EQ(chost.accounts.count(addr1), 1u);
EXPECT_EQ(host.accounts[addr1].storage.count(val1), 1u);
EXPECT_EQ(host.accounts[addr1].storage[val1].value, val2);

auto& acc2 = host.accounts[addr2];
EXPECT_EQ(chost.get_storage(addr2, val1), evmc::bytes32{});
Expand Down
14 changes: 14 additions & 0 deletions test/unittests/tool_commands_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,17 @@ TEST(tool_commands, create_failure_stack_underflow)
"Creating and executing on Petersburg with 0 gas limit\n"
"Contract creation failed: undefined instruction\n");
}

TEST(tool_commands, create_preserve_storage)
{
// Contract: sload(0) mstore(0) return(31, 1) 6000 54 6000 52 6001 601f f3
// Create: sstore(0, 0xbb) mstore(0, "6000546000526001601ff3") return(21, 11)
auto vm = evmc::VM{evmc_create_example_vm()};
std::ostringstream out;

const auto exit_code =
cmd::run(vm, EVMC_BERLIN, 200, "60bb 6000 55 6a6000546000526001601ff3 6000 52 600b 6015 f3",
"", true, out);
EXPECT_EQ(exit_code, 0);
EXPECT_EQ(out.str(), out_pattern("Berlin", 200, "success", 7, "bb", true));
}