Skip to content

Commit

Permalink
rework StateReaderTest
Browse files Browse the repository at this point in the history
  • Loading branch information
yperbasis committed Sep 18, 2024
1 parent 1e369c9 commit 3d44821
Showing 1 changed file with 31 additions and 32 deletions.
63 changes: 31 additions & 32 deletions silkworm/db/state/state_reader_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

#include "state_reader.hpp"

#include <silkworm/infra/concurrency/task.hpp>

#include <catch2/catch_test_macros.hpp>
#include <evmc/evmc.hpp>
#include <gmock/gmock.h>
Expand Down Expand Up @@ -56,43 +54,44 @@ static const Bytes kEncodedStorageHistory{*from_hex(
static const Bytes kBinaryCode{*from_hex("0x60045e005c60016000555d")};
static const evmc::bytes32 kCodeHash{0xef722d9baf50b9983c2fce6329c5a43a15b8d5ba79cd792e7199d615be88284d_bytes32};

struct StateReaderTest : public silkworm::test_util::ContextTestBase {
db::test_util::MockTransaction transaction;
StateReader state_reader{transaction, kEarliestBlockNumber};
class StateReaderTest : public silkworm::test_util::ContextTestBase {
protected:
db::test_util::MockTransaction transaction_;
StateReader state_reader_{transaction_, kEarliestBlockNumber};
};

TEST_CASE_METHOD(StateReaderTest, "StateReader::read_account") {
SECTION("no account for history empty and current state empty") {
// Set the call expectations:
// 1. DatabaseReader::get call on kAccountHistory returns empty key-value
EXPECT_CALL(transaction, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{};
}));
// 2. DatabaseReader::get_one call on kPlainState returns empty value
EXPECT_CALL(transaction, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return Bytes{};
}));

// Execute the test: calling read_account should return no account
std::optional<Account> account;
CHECK_NOTHROW(account = spawn_and_wait(state_reader.read_account(kZeroAddress)));
CHECK_NOTHROW(account = spawn_and_wait(state_reader_.read_account(kZeroAddress)));
CHECK(!account);
}

SECTION("account found in current state") {
// Set the call expectations:
// 1. DatabaseReader::get call on kAccountHistory returns empty key-value
EXPECT_CALL(transaction, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{};
}));
// 2. DatabaseReader::get_one call on kPlainState returns account data
EXPECT_CALL(transaction, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return kEncodedAccount;
}));

// Execute the test: calling read_account should return the expected account
std::optional<Account> account;
CHECK_NOTHROW(account = spawn_and_wait(state_reader.read_account(kZeroAddress)));
CHECK_NOTHROW(account = spawn_and_wait(state_reader_.read_account(kZeroAddress)));
CHECK(account);
if (account) {
CHECK(account->nonce == 2);
Expand All @@ -105,17 +104,17 @@ TEST_CASE_METHOD(StateReaderTest, "StateReader::read_account") {
SECTION("account found in history") {
// Set the call expectations:
// 1. DatabaseReader::get call on kAccountHistory returns the account bitmap
EXPECT_CALL(transaction, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{Bytes{ByteView{kZeroAddress.bytes}}, kEncodedAccountHistory};
}));
// 2. DatabaseReader::get_both_range call on kPlainAccountChangeSet returns the account data
EXPECT_CALL(transaction, get_both_range(db::table::kAccountChangeSetName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
EXPECT_CALL(transaction_, get_both_range(db::table::kAccountChangeSetName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
co_return kEncodedAccount;
}));

// Execute the test: calling read_account should return expected account
std::optional<Account> account;
CHECK_NOTHROW(account = spawn_and_wait(state_reader.read_account(kZeroAddress)));
CHECK_NOTHROW(account = spawn_and_wait(state_reader_.read_account(kZeroAddress)));
CHECK(account);
if (account) {
CHECK(account->nonce == 2);
Expand All @@ -128,21 +127,21 @@ TEST_CASE_METHOD(StateReaderTest, "StateReader::read_account") {
SECTION("account w/o code hash found current state") {
// Set the call expectations:
// 1. DatabaseReader::get call on kAccountHistory returns empty key-value
EXPECT_CALL(transaction, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kAccountHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{};
}));
// 2. DatabaseReader::get_one call on kPlainState returns account data
EXPECT_CALL(transaction, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kPlainStateName, ByteView{kZeroAddress.bytes})).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return kEncodedAccountWithoutCodeHash;
}));
// 3. DatabaseReader::get_one call on kPlainContractCode returns account code hash
EXPECT_CALL(transaction, get_one(db::table::kPlainCodeHashName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kPlainCodeHashName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return Bytes{kCodeHash.bytes, kHashLength};
}));

// Execute the test: calling read_account should return the expected account
std::optional<Account> account;
CHECK_NOTHROW(account = spawn_and_wait(state_reader.read_account(kZeroAddress)));
CHECK_NOTHROW(account = spawn_and_wait(state_reader_.read_account(kZeroAddress)));
CHECK(account);
if (account) {
CHECK(account->nonce == 12345);
Expand All @@ -157,53 +156,53 @@ TEST_CASE_METHOD(StateReaderTest, "StateReader::read_storage") {
SECTION("empty storage for history empty and current state empty") {
// Set the call expectations:
// 1. DatabaseReader::get call on kStorageHistory returns empty key-value
EXPECT_CALL(transaction, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{};
}));
// 2. DatabaseReader::get_both_range call on kPlainState returns empty value
EXPECT_CALL(transaction, get_both_range(db::table::kPlainStateName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
EXPECT_CALL(transaction_, get_both_range(db::table::kPlainStateName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
co_return Bytes{};
}));

// Execute the test: calling read_storage should return empty storage value
evmc::bytes32 location;
CHECK_NOTHROW(location = spawn_and_wait(state_reader.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK_NOTHROW(location = spawn_and_wait(state_reader_.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK(location == evmc::bytes32{});
}

SECTION("storage found in current state") {
// Set the call expectations:
// 1. DatabaseReader::get call on kStorageHistory returns empty key-value
EXPECT_CALL(transaction, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{};
}));
// 2. DatabaseReader::get_both_range call on kPlainState returns empty value
EXPECT_CALL(transaction, get_both_range(db::table::kPlainStateName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
EXPECT_CALL(transaction_, get_both_range(db::table::kPlainStateName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
co_return kStorageLocation;
}));

// Execute the test: calling read_storage should return expected storage location
evmc::bytes32 location;
CHECK_NOTHROW(location = spawn_and_wait(state_reader.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK_NOTHROW(location = spawn_and_wait(state_reader_.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK(location == to_bytes32(kStorageLocation));
}

SECTION("storage found in history") {
// Set the call expectations:
// 1. DatabaseReader::get call on kStorageHistory returns the storage bitmap
EXPECT_CALL(transaction, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
EXPECT_CALL(transaction_, get(db::table::kStorageHistoryName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<KeyValue> {
co_return KeyValue{
db::storage_history_key(kZeroAddress, kLocationHash, kEarliestBlockNumber),
kEncodedStorageHistory};
}));
// 2. DatabaseReader::get_both_range call on kPlainAccountChangeSet the storage location value
EXPECT_CALL(transaction, get_both_range(db::table::kStorageChangeSetName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
EXPECT_CALL(transaction_, get_both_range(db::table::kStorageChangeSetName, _, _)).WillOnce(InvokeWithoutArgs([]() -> Task<std::optional<Bytes>> {
co_return kStorageLocation;
}));

// Execute the test: calling read_storage should return expected storage location
evmc::bytes32 location;
CHECK_NOTHROW(location = spawn_and_wait(state_reader.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK_NOTHROW(location = spawn_and_wait(state_reader_.read_storage(kZeroAddress, 0, kLocationHash)));
CHECK(location == to_bytes32(kStorageLocation));
}
}
Expand All @@ -212,20 +211,20 @@ TEST_CASE_METHOD(StateReaderTest, "StateReader::read_code") {
SECTION("no code for empty code hash") {
// Execute the test: calling read_code should return no code for empty hash
std::optional<Bytes> code;
CHECK_NOTHROW(code = spawn_and_wait(state_reader.read_code(kZeroAddress, kEmptyHash)));
CHECK_NOTHROW(code = spawn_and_wait(state_reader_.read_code(kZeroAddress, kEmptyHash)));
CHECK(!code);
}

SECTION("empty code found for code hash") {
// Set the call expectations:
// 1. DatabaseReader::get_one call on kCode returns the binary code
EXPECT_CALL(transaction, get_one(db::table::kCodeName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kCodeName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return Bytes{};
}));

// Execute the test: calling read_code should return an empty code
std::optional<Bytes> code;
CHECK_NOTHROW(code = spawn_and_wait(state_reader.read_code(kZeroAddress, kCodeHash)));
CHECK_NOTHROW(code = spawn_and_wait(state_reader_.read_code(kZeroAddress, kCodeHash)));
CHECK(code);
if (code) {
CHECK(code->empty());
Expand All @@ -235,13 +234,13 @@ TEST_CASE_METHOD(StateReaderTest, "StateReader::read_code") {
SECTION("non-empty code found for code hash") {
// Set the call expectations:
// 1. DatabaseReader::get_one call on kCode returns the binary code
EXPECT_CALL(transaction, get_one(db::table::kCodeName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
EXPECT_CALL(transaction_, get_one(db::table::kCodeName, _)).WillOnce(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return kBinaryCode;
}));

// Execute the test: calling read_code should return a non-empty code
std::optional<Bytes> code;
CHECK_NOTHROW(code = spawn_and_wait(state_reader.read_code(kZeroAddress, kCodeHash)));
CHECK_NOTHROW(code = spawn_and_wait(state_reader_.read_code(kZeroAddress, kCodeHash)));
CHECK(code);
if (code) {
CHECK(to_hex(*code) == to_hex(kBinaryCode));
Expand Down

0 comments on commit 3d44821

Please sign in to comment.