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

rpcdaemon: StateReader using only txn_number #2623

Merged
merged 2 commits into from
Dec 24, 2024
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
20 changes: 4 additions & 16 deletions silkworm/db/kv/state_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,14 @@

namespace silkworm::db::kv {

StateReader::StateReader(kv::api::Transaction& tx, std::optional<BlockNum> block_num, std::optional<TxnId> txn_id) : tx_(tx), block_num_(block_num), txn_number_(txn_id) {
SILKWORM_ASSERT((txn_id && !block_num) || (!txn_id && block_num));
StateReader::StateReader(kv::api::Transaction& tx, TxnId txn_id) : tx_(tx), txn_number_(txn_id) {
}

Task<std::optional<Account>> StateReader::read_account(const evmc::address& address) const {
if (!txn_number_) {
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
}

db::kv::api::GetAsOfQuery query{
.table = table::kAccountDomain,
.key = db::account_domain_key(address),
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
};
const auto result = co_await tx_.get_as_of(std::move(query));
if (!result.success) {
Expand All @@ -53,14 +48,10 @@ Task<std::optional<Account>> StateReader::read_account(const evmc::address& addr
Task<evmc::bytes32> StateReader::read_storage(const evmc::address& address,
uint64_t /* incarnation */,
const evmc::bytes32& location_hash) const {
if (!txn_number_) {
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
}

db::kv::api::GetAsOfQuery query{
.table = table::kStorageDomain,
.key = db::storage_domain_key(address, location_hash),
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
};
const auto result = co_await tx_.get_as_of(std::move(query));
if (!result.success) {
Expand All @@ -73,14 +64,11 @@ Task<std::optional<Bytes>> StateReader::read_code(const evmc::address& address,
if (code_hash == kEmptyHash) {
co_return std::nullopt;
}
if (!txn_number_) {
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
}

db::kv::api::GetAsOfQuery query{
.table = table::kCodeDomain,
.key = db::code_domain_key(address),
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
};
const auto result = co_await tx_.get_as_of(std::move(query));
if (!result.success) {
Expand Down
5 changes: 2 additions & 3 deletions silkworm/db/kv/state_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace silkworm::db::kv {

class StateReader {
public:
StateReader(kv::api::Transaction& tx, std::optional<BlockNum> block_num, std::optional<TxnId> txn_id = std::nullopt);
StateReader(kv::api::Transaction& tx, TxnId txn_id);

StateReader(const StateReader&) = delete;
StateReader& operator=(const StateReader&) = delete;
Expand All @@ -49,8 +49,7 @@ class StateReader {

private:
kv::api::Transaction& tx_;
std::optional<BlockNum> block_num_;
mutable std::optional<TxnId> txn_number_;
TxnId txn_number_;
};

} // namespace silkworm::db::kv
9 changes: 4 additions & 5 deletions silkworm/execution/remote_state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ class AsyncRemoteState {
explicit AsyncRemoteState(
db::kv::api::Transaction& tx,
const db::chain::ChainStorage& storage,
std::optional<BlockNum> block_num,
std::optional<TxnId> txn_id = std::nullopt)
: storage_(storage), state_reader_(tx, block_num ? *block_num + 1 : block_num, txn_id) {}
TxnId txn_id)
: storage_(storage), state_reader_(tx, txn_id) {}

Task<std::optional<Account>> read_account(const evmc::address& address) const noexcept;

Expand Down Expand Up @@ -76,8 +75,8 @@ class RemoteState : public State {
boost::asio::any_io_executor& executor,
db::kv::api::Transaction& tx,
const db::chain::ChainStorage& storage,
std::optional<BlockNum> block_num, std::optional<TxnId> txn_id = std::nullopt)
: executor_(executor), async_state_{tx, storage, block_num, txn_id} {}
TxnId txn_id)
: executor_(executor), async_state_{tx, storage, txn_id} {}

std::optional<Account> read_account(const evmc::address& address) const noexcept override;

Expand Down
45 changes: 23 additions & 22 deletions silkworm/execution/remote_state_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
.WillRepeatedly(InvokeWithoutArgs([]() -> Task<Bytes> {
co_return Bytes{};
}));
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, block_num, std::nullopt};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto code_read{spawn_and_wait(state.read_code(address, kEmptyHash))};
CHECK(code_read.empty());
}
Expand All @@ -73,8 +73,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
co_return response;
}));

const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const evmc::bytes32 code_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
const auto code_read{spawn_and_wait(state.read_code(address, code_hash))};
CHECK(code_read == ByteView{kCode});
Expand All @@ -101,9 +101,6 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
}

SECTION("read_storage with empty response from db") {
EXPECT_CALL(transaction, first_txn_num_in_block(1'000'001)).WillOnce(Invoke([]() -> Task<TxnId> {
co_return 0;
}));
EXPECT_CALL(transaction, get_as_of(_)).WillOnce(Invoke([=](Unused) -> Task<db::kv::api::GetAsOfResult> {
db::kv::api::GetAsOfResult response{
.success = true,
Expand Down Expand Up @@ -280,8 +277,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
.value = Bytes{}};
co_return response;
}));
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto account_read{spawn_and_wait(state.read_account(address))};
CHECK(account_read == std::nullopt);
}
Expand All @@ -296,9 +293,9 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
.value = Bytes{}};
co_return response;
}));
const BlockNum block_num = 1'000'000;
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const evmc::bytes32 code_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
AsyncRemoteState state{transaction, chain_storage, block_num};
const auto code_read{spawn_and_wait(state.read_code(address, code_hash))};
CHECK(code_read.empty());
}
Expand All @@ -313,16 +310,16 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
.value = Bytes{}};
co_return response;
}));
const BlockNum block_num = 1'000'000;
const evmc::bytes32 location{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto storage_read{spawn_and_wait(state.read_storage(address, 0, location))};
CHECK(storage_read == 0x0000000000000000000000000000000000000000000000000000000000000000_bytes32);
}

SECTION("AsyncRemoteState::previous_incarnation returns ok") {
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto prev_incarnation{spawn_and_wait(state.previous_incarnation(address))};
CHECK(prev_incarnation == 0);
}
Expand All @@ -335,36 +332,39 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
}

SECTION("AsyncRemoteState::current_canonical_block returns ok") {
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto current_canonical_block{spawn_and_wait(state.current_canonical_block())};
CHECK(current_canonical_block == 0);
}

SECTION("AsyncRemoteState::total_difficulty with empty response from chain storage") {
const TxnId txn_id = 244087591818874;
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const Hash block_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
AsyncRemoteState state{transaction, chain_storage, block_num};
EXPECT_CALL(chain_storage, read_total_difficulty(block_hash, block_num))
.WillOnce(Invoke([](Unused, Unused) -> Task<std::optional<intx::uint256>> { co_return std::nullopt; }));
const auto total_difficulty{spawn_and_wait(state.total_difficulty(block_num, block_hash))};
CHECK(total_difficulty == std::nullopt);
}

SECTION("AsyncRemoteState::read_header with empty response from chain storage") {
const TxnId txn_id = 244087591818874;
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, txn_id};
const Hash block_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
AsyncRemoteState state{transaction, chain_storage, block_num};
EXPECT_CALL(chain_storage, read_header(block_num, block_hash))
.WillOnce(Invoke([](Unused, Unused) -> Task<std::optional<BlockHeader>> { co_return std::nullopt; }));
const auto block_header{spawn_and_wait(state.read_header(block_num, block_hash))};
CHECK(block_header == std::nullopt);
}

SECTION("AsyncRemoteState::read_body with empty response from from chain storage") {
const BlockNum block_num = 1'000'000;
const Hash block_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
AsyncRemoteState state{transaction, chain_storage, block_num};
const TxnId txn_id = 244087591818874;
const BlockNum block_num = 1'000'000;
AsyncRemoteState state{transaction, chain_storage, txn_id};
BlockBody body;
EXPECT_CALL(chain_storage, read_body(block_hash, block_num, body))
.WillOnce(Invoke([](Unused, Unused, Unused) -> Task<bool> { co_return true; }));
Expand All @@ -378,10 +378,11 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
.WillRepeatedly(InvokeWithoutArgs([=]() -> Task<Bytes> {
co_return Bytes{};
}));
const TxnId txn_id = 244087591818874;
const BlockNum block_num = 1'000'000;
EXPECT_CALL(chain_storage, read_canonical_header_hash(block_num))
.WillOnce(Invoke([](Unused) -> Task<std::optional<Hash>> { co_return std::nullopt; }));
AsyncRemoteState state{transaction, chain_storage, block_num};
AsyncRemoteState state{transaction, chain_storage, txn_id};
const auto canonical_hash{spawn_and_wait(state.canonical_hash(block_num))};
CHECK(canonical_hash == std::nullopt);
}
Expand Down
2 changes: 1 addition & 1 deletion silkworm/execution/state_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ std::shared_ptr<State> StateFactory::create_state(
auto& local_tx = dynamic_cast<db::kv::api::LocalTransaction&>(tx);
return std::make_shared<LocalState>(std::nullopt, txn_id, local_tx.data_store());
} else { // NOLINT(readability-else-after-return)
return std::make_shared<RemoteState>(executor, tx, storage, std::nullopt, txn_id);
return std::make_shared<RemoteState>(executor, tx, storage, txn_id);
}
}

Expand Down
33 changes: 23 additions & 10 deletions silkworm/rpc/commands/eth_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -918,8 +918,8 @@ Task<void> EthereumRpcApi::handle_eth_estimate_gas(const nlohmann::json& request
return chain_storage->read_canonical_header(block_num);
};

rpc::AccountReader account_reader = [&tx](const evmc::address& address, BlockNum block_num) -> Task<std::optional<Account>> {
StateReader state_reader{*tx, block_num + 1};
rpc::AccountReader account_reader = [&tx](const evmc::address& address, TxnId txn_id) -> Task<std::optional<Account>> {
StateReader state_reader{*tx, txn_id};
co_return co_await state_reader.read_account(address);
};

Expand Down Expand Up @@ -973,7 +973,10 @@ Task<void> EthereumRpcApi::handle_eth_get_balance(const nlohmann::json& request,
const auto [block_num, is_latest_block] = co_await block_reader.get_block_num(block_num_or_hash);
tx->set_state_cache_enabled(is_latest_block);

StateReader state_reader{*tx, block_num + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
StateReader state_reader{*tx, txn_id};

std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};

reply = make_json_content(request, "0x" + (account ? intx::hex(account->balance) : "0"));
Expand Down Expand Up @@ -1012,7 +1015,10 @@ Task<void> EthereumRpcApi::handle_eth_get_code(const nlohmann::json& request, nl
const auto [block_num, is_latest_block] = co_await block_reader.get_block_num(block_id, /*latest_required=*/true);
tx->set_state_cache_enabled(is_latest_block);

StateReader state_reader{*tx, block_num + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);

StateReader state_reader{*tx, txn_id};
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};

if (account) {
Expand Down Expand Up @@ -1053,7 +1059,11 @@ Task<void> EthereumRpcApi::handle_eth_get_transaction_count(const nlohmann::json
const auto [block_num, is_latest_block] = co_await block_reader.get_block_num(block_id, /*latest_required=*/true);
tx->set_state_cache_enabled(is_latest_block);

StateReader state_reader{*tx, block_num + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);

StateReader state_reader{*tx, txn_id};

std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};

if (account) {
Expand Down Expand Up @@ -1101,7 +1111,10 @@ Task<void> EthereumRpcApi::handle_eth_get_storage_at(const nlohmann::json& reque
const auto [block_num, is_latest_block] = co_await block_reader.get_block_num(block_id, /*latest_required=*/true);
tx->set_state_cache_enabled(is_latest_block);

StateReader state_reader{*tx, block_num + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);

StateReader state_reader{*tx, txn_id};
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};

if (account) {
Expand Down Expand Up @@ -1317,7 +1330,10 @@ Task<void> EthereumRpcApi::handle_eth_create_access_list(const nlohmann::json& r
const bool is_latest_block = co_await block_reader.get_latest_executed_block_num() == block_with_hash->block.header.number;
tx->set_state_cache_enabled(/*cache_enabled=*/is_latest_block);

StateReader state_reader{*tx, block_with_hash->block.header.number + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_with_hash->block.header.number + 1);

StateReader state_reader{*tx, txn_id};

std::optional<uint64_t> nonce = std::nullopt;
evmc::address to{};
Expand Down Expand Up @@ -1347,9 +1363,6 @@ Task<void> EthereumRpcApi::handle_eth_create_access_list(const nlohmann::json& r
auto txn = call.to_transaction(std::nullopt, nonce);
AccessList saved_access_list = call.access_list;

execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_with_hash->block.header.number + 1);

while (true) {
const auto execution_result = co_await EVMExecutor::call(
chain_config, *chain_storage, workers_, block_with_hash->block, txn, txn_id, [&](auto& io_executor, auto curr_txn_id, auto& storage) {
Expand Down
11 changes: 9 additions & 2 deletions silkworm/rpc/commands/ots_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <silkworm/db/kv/state_reader.hpp>
#include <silkworm/db/kv/txn_num.hpp>
#include <silkworm/db/tables.hpp>
#include <silkworm/execution/state_factory.hpp>
#include <silkworm/infra/common/async_binary_search.hpp>
#include <silkworm/infra/common/log.hpp>
#include <silkworm/rpc/core/block_reader.hpp>
Expand Down Expand Up @@ -80,7 +81,10 @@ Task<void> OtsRpcApi::handle_ots_has_code(const nlohmann::json& request, nlohman
tx->set_state_cache_enabled(is_latest_block);

const auto block_num = co_await block_reader.get_block_num(block_id);
StateReader state_reader{*tx, block_num + 1};
execution::StateFactory state_factory{*tx};
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);

StateReader state_reader{*tx, txn_id};
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};

if (account) {
Expand Down Expand Up @@ -435,7 +439,10 @@ Task<void> OtsRpcApi::handle_ots_get_contract_creator(const nlohmann::json& requ
const auto chain_storage = tx->create_storage();
rpc::BlockReader block_reader{*chain_storage, *tx};
auto block_num = co_await block_reader.get_latest_block_num();
StateReader state_reader{*tx, block_num};
execution::StateFactory state_factory{*tx};
const auto txn_number = co_await state_factory.user_txn_id_at(block_num);

StateReader state_reader{*tx, txn_number};
std::optional<silkworm::Account> account_opt{co_await state_reader.read_account(contract_address)};
if (!account_opt || account_opt.value().code_hash == kEmptyHash) {
reply = make_json_content(request, nlohmann::detail::value_t::null);
Expand Down
8 changes: 6 additions & 2 deletions silkworm/rpc/commands/parity_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <silkworm/db/kv/state_reader.hpp>
#include <silkworm/db/kv/txn_num.hpp>
#include <silkworm/db/tables.hpp>
#include <silkworm/execution/state_factory.hpp>
#include <silkworm/infra/common/log.hpp>
#include <silkworm/rpc/common/util.hpp>
#include <silkworm/rpc/core/block_reader.hpp>
Expand Down Expand Up @@ -67,11 +68,14 @@ Task<void> ParityRpcApi::handle_parity_list_storage_keys(const nlohmann::json& r

const auto block_num = co_await block_reader.get_block_num(block_id);
SILK_DEBUG << "read account with address: " << address << " block number: " << block_num;
StateReader state_reader{*tx, block_num};

execution::StateFactory state_factory{*tx};
const auto txn_number = co_await state_factory.user_txn_id_at(block_num);

StateReader state_reader{*tx, txn_number};
std::optional<Account> account = co_await state_reader.read_account(address);
if (!account) throw std::domain_error{"account not found"};

const auto txn_number = co_await tx->first_txn_num_in_block(block_num);
auto from = db::code_domain_key(address);

if (offset) {
Expand Down
Loading
Loading