Skip to content

Commit 7923eb4

Browse files
authored
rpcdaemon: StateReader using only txn_number (#2623)
1 parent 13718e4 commit 7923eb4

File tree

12 files changed

+80
-74
lines changed

12 files changed

+80
-74
lines changed

silkworm/db/kv/state_reader.cpp

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,14 @@
2626

2727
namespace silkworm::db::kv {
2828

29-
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) {
30-
SILKWORM_ASSERT((txn_id && !block_num) || (!txn_id && block_num));
29+
StateReader::StateReader(kv::api::Transaction& tx, TxnId txn_id) : tx_(tx), txn_number_(txn_id) {
3130
}
3231

3332
Task<std::optional<Account>> StateReader::read_account(const evmc::address& address) const {
34-
if (!txn_number_) {
35-
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
36-
}
37-
3833
db::kv::api::GetAsOfQuery query{
3934
.table = table::kAccountDomain,
4035
.key = db::account_domain_key(address),
41-
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
36+
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
4237
};
4338
const auto result = co_await tx_.get_as_of(std::move(query));
4439
if (!result.success) {
@@ -53,14 +48,10 @@ Task<std::optional<Account>> StateReader::read_account(const evmc::address& addr
5348
Task<evmc::bytes32> StateReader::read_storage(const evmc::address& address,
5449
uint64_t /* incarnation */,
5550
const evmc::bytes32& location_hash) const {
56-
if (!txn_number_) {
57-
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
58-
}
59-
6051
db::kv::api::GetAsOfQuery query{
6152
.table = table::kStorageDomain,
6253
.key = db::storage_domain_key(address, location_hash),
63-
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
54+
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
6455
};
6556
const auto result = co_await tx_.get_as_of(std::move(query));
6657
if (!result.success) {
@@ -73,14 +64,11 @@ Task<std::optional<Bytes>> StateReader::read_code(const evmc::address& address,
7364
if (code_hash == kEmptyHash) {
7465
co_return std::nullopt;
7566
}
76-
if (!txn_number_) {
77-
txn_number_ = co_await tx_.first_txn_num_in_block(*block_num_);
78-
}
7967

8068
db::kv::api::GetAsOfQuery query{
8169
.table = table::kCodeDomain,
8270
.key = db::code_domain_key(address),
83-
.timestamp = static_cast<kv::api::Timestamp>(*txn_number_),
71+
.timestamp = static_cast<kv::api::Timestamp>(txn_number_),
8472
};
8573
const auto result = co_await tx_.get_as_of(std::move(query));
8674
if (!result.success) {

silkworm/db/kv/state_reader.hpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ namespace silkworm::db::kv {
3434

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

3939
StateReader(const StateReader&) = delete;
4040
StateReader& operator=(const StateReader&) = delete;
@@ -49,8 +49,7 @@ class StateReader {
4949

5050
private:
5151
kv::api::Transaction& tx_;
52-
std::optional<BlockNum> block_num_;
53-
mutable std::optional<TxnId> txn_number_;
52+
TxnId txn_number_;
5453
};
5554

5655
} // namespace silkworm::db::kv

silkworm/execution/remote_state.hpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ class AsyncRemoteState {
3939
explicit AsyncRemoteState(
4040
db::kv::api::Transaction& tx,
4141
const db::chain::ChainStorage& storage,
42-
std::optional<BlockNum> block_num,
43-
std::optional<TxnId> txn_id = std::nullopt)
44-
: storage_(storage), state_reader_(tx, block_num ? *block_num + 1 : block_num, txn_id) {}
42+
TxnId txn_id)
43+
: storage_(storage), state_reader_(tx, txn_id) {}
4544

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

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

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

silkworm/execution/remote_state_test.cpp

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
5454
.WillRepeatedly(InvokeWithoutArgs([]() -> Task<Bytes> {
5555
co_return Bytes{};
5656
}));
57-
const BlockNum block_num = 1'000'000;
58-
AsyncRemoteState state{transaction, chain_storage, block_num, std::nullopt};
57+
const TxnId txn_id = 244087591818874;
58+
AsyncRemoteState state{transaction, chain_storage, txn_id};
5959
const auto code_read{spawn_and_wait(state.read_code(address, kEmptyHash))};
6060
CHECK(code_read.empty());
6161
}
@@ -73,8 +73,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
7373
co_return response;
7474
}));
7575

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

103103
SECTION("read_storage with empty response from db") {
104-
EXPECT_CALL(transaction, first_txn_num_in_block(1'000'001)).WillOnce(Invoke([]() -> Task<TxnId> {
105-
co_return 0;
106-
}));
107104
EXPECT_CALL(transaction, get_as_of(_)).WillOnce(Invoke([=](Unused) -> Task<db::kv::api::GetAsOfResult> {
108105
db::kv::api::GetAsOfResult response{
109106
.success = true,
@@ -280,8 +277,8 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
280277
.value = Bytes{}};
281278
co_return response;
282279
}));
283-
const BlockNum block_num = 1'000'000;
284-
AsyncRemoteState state{transaction, chain_storage, block_num};
280+
const TxnId txn_id = 244087591818874;
281+
AsyncRemoteState state{transaction, chain_storage, txn_id};
285282
const auto account_read{spawn_and_wait(state.read_account(address))};
286283
CHECK(account_read == std::nullopt);
287284
}
@@ -296,9 +293,9 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
296293
.value = Bytes{}};
297294
co_return response;
298295
}));
299-
const BlockNum block_num = 1'000'000;
296+
const TxnId txn_id = 244087591818874;
297+
AsyncRemoteState state{transaction, chain_storage, txn_id};
300298
const evmc::bytes32 code_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
301-
AsyncRemoteState state{transaction, chain_storage, block_num};
302299
const auto code_read{spawn_and_wait(state.read_code(address, code_hash))};
303300
CHECK(code_read.empty());
304301
}
@@ -313,16 +310,16 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
313310
.value = Bytes{}};
314311
co_return response;
315312
}));
316-
const BlockNum block_num = 1'000'000;
317313
const evmc::bytes32 location{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
318-
AsyncRemoteState state{transaction, chain_storage, block_num};
314+
const TxnId txn_id = 244087591818874;
315+
AsyncRemoteState state{transaction, chain_storage, txn_id};
319316
const auto storage_read{spawn_and_wait(state.read_storage(address, 0, location))};
320317
CHECK(storage_read == 0x0000000000000000000000000000000000000000000000000000000000000000_bytes32);
321318
}
322319

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

337334
SECTION("AsyncRemoteState::current_canonical_block returns ok") {
338-
const BlockNum block_num = 1'000'000;
339-
AsyncRemoteState state{transaction, chain_storage, block_num};
335+
const TxnId txn_id = 244087591818874;
336+
AsyncRemoteState state{transaction, chain_storage, txn_id};
340337
const auto current_canonical_block{spawn_and_wait(state.current_canonical_block())};
341338
CHECK(current_canonical_block == 0);
342339
}
343340

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

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

364363
SECTION("AsyncRemoteState::read_body with empty response from from chain storage") {
365-
const BlockNum block_num = 1'000'000;
366364
const Hash block_hash{0x04491edcd115127caedbd478e2e7895ed80c7847e903431f94f9cfa579cad47f_bytes32};
367-
AsyncRemoteState state{transaction, chain_storage, block_num};
365+
const TxnId txn_id = 244087591818874;
366+
const BlockNum block_num = 1'000'000;
367+
AsyncRemoteState state{transaction, chain_storage, txn_id};
368368
BlockBody body;
369369
EXPECT_CALL(chain_storage, read_body(block_hash, block_num, body))
370370
.WillOnce(Invoke([](Unused, Unused, Unused) -> Task<bool> { co_return true; }));
@@ -378,10 +378,11 @@ TEST_CASE_METHOD(RemoteStateTest, "async remote buffer", "[rpc][core][remote_buf
378378
.WillRepeatedly(InvokeWithoutArgs([=]() -> Task<Bytes> {
379379
co_return Bytes{};
380380
}));
381+
const TxnId txn_id = 244087591818874;
381382
const BlockNum block_num = 1'000'000;
382383
EXPECT_CALL(chain_storage, read_canonical_header_hash(block_num))
383384
.WillOnce(Invoke([](Unused) -> Task<std::optional<Hash>> { co_return std::nullopt; }));
384-
AsyncRemoteState state{transaction, chain_storage, block_num};
385+
AsyncRemoteState state{transaction, chain_storage, txn_id};
385386
const auto canonical_hash{spawn_and_wait(state.canonical_hash(block_num))};
386387
CHECK(canonical_hash == std::nullopt);
387388
}

silkworm/execution/state_factory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ std::shared_ptr<State> StateFactory::create_state(
3232
auto& local_tx = dynamic_cast<db::kv::api::LocalTransaction&>(tx);
3333
return std::make_shared<LocalState>(std::nullopt, txn_id, local_tx.data_store());
3434
} else { // NOLINT(readability-else-after-return)
35-
return std::make_shared<RemoteState>(executor, tx, storage, std::nullopt, txn_id);
35+
return std::make_shared<RemoteState>(executor, tx, storage, txn_id);
3636
}
3737
}
3838

silkworm/rpc/commands/eth_api.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -918,8 +918,8 @@ Task<void> EthereumRpcApi::handle_eth_estimate_gas(const nlohmann::json& request
918918
return chain_storage->read_canonical_header(block_num);
919919
};
920920

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

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

976-
StateReader state_reader{*tx, block_num + 1};
976+
execution::StateFactory state_factory{*tx};
977+
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
978+
StateReader state_reader{*tx, txn_id};
979+
977980
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};
978981

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

1015-
StateReader state_reader{*tx, block_num + 1};
1018+
execution::StateFactory state_factory{*tx};
1019+
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
1020+
1021+
StateReader state_reader{*tx, txn_id};
10161022
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};
10171023

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

1056-
StateReader state_reader{*tx, block_num + 1};
1062+
execution::StateFactory state_factory{*tx};
1063+
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
1064+
1065+
StateReader state_reader{*tx, txn_id};
1066+
10571067
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};
10581068

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

1104-
StateReader state_reader{*tx, block_num + 1};
1114+
execution::StateFactory state_factory{*tx};
1115+
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
1116+
1117+
StateReader state_reader{*tx, txn_id};
11051118
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};
11061119

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

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

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

1350-
execution::StateFactory state_factory{*tx};
1351-
const auto txn_id = co_await state_factory.user_txn_id_at(block_with_hash->block.header.number + 1);
1352-
13531366
while (true) {
13541367
const auto execution_result = co_await EVMExecutor::call(
13551368
chain_config, *chain_storage, workers_, block_with_hash->block, txn, txn_id, [&](auto& io_executor, auto curr_txn_id, auto& storage) {

silkworm/rpc/commands/ots_api.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <silkworm/db/kv/state_reader.hpp>
2929
#include <silkworm/db/kv/txn_num.hpp>
3030
#include <silkworm/db/tables.hpp>
31+
#include <silkworm/execution/state_factory.hpp>
3132
#include <silkworm/infra/common/async_binary_search.hpp>
3233
#include <silkworm/infra/common/log.hpp>
3334
#include <silkworm/rpc/core/block_reader.hpp>
@@ -80,7 +81,10 @@ Task<void> OtsRpcApi::handle_ots_has_code(const nlohmann::json& request, nlohman
8081
tx->set_state_cache_enabled(is_latest_block);
8182

8283
const auto block_num = co_await block_reader.get_block_num(block_id);
83-
StateReader state_reader{*tx, block_num + 1};
84+
execution::StateFactory state_factory{*tx};
85+
const auto txn_id = co_await state_factory.user_txn_id_at(block_num + 1);
86+
87+
StateReader state_reader{*tx, txn_id};
8488
std::optional<silkworm::Account> account{co_await state_reader.read_account(address)};
8589

8690
if (account) {
@@ -435,7 +439,10 @@ Task<void> OtsRpcApi::handle_ots_get_contract_creator(const nlohmann::json& requ
435439
const auto chain_storage = tx->create_storage();
436440
rpc::BlockReader block_reader{*chain_storage, *tx};
437441
auto block_num = co_await block_reader.get_latest_block_num();
438-
StateReader state_reader{*tx, block_num};
442+
execution::StateFactory state_factory{*tx};
443+
const auto txn_number = co_await state_factory.user_txn_id_at(block_num);
444+
445+
StateReader state_reader{*tx, txn_number};
439446
std::optional<silkworm::Account> account_opt{co_await state_reader.read_account(contract_address)};
440447
if (!account_opt || account_opt.value().code_hash == kEmptyHash) {
441448
reply = make_json_content(request, nlohmann::detail::value_t::null);

silkworm/rpc/commands/parity_api.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <silkworm/db/kv/state_reader.hpp>
2626
#include <silkworm/db/kv/txn_num.hpp>
2727
#include <silkworm/db/tables.hpp>
28+
#include <silkworm/execution/state_factory.hpp>
2829
#include <silkworm/infra/common/log.hpp>
2930
#include <silkworm/rpc/common/util.hpp>
3031
#include <silkworm/rpc/core/block_reader.hpp>
@@ -67,11 +68,14 @@ Task<void> ParityRpcApi::handle_parity_list_storage_keys(const nlohmann::json& r
6768

6869
const auto block_num = co_await block_reader.get_block_num(block_id);
6970
SILK_DEBUG << "read account with address: " << address << " block number: " << block_num;
70-
StateReader state_reader{*tx, block_num};
71+
72+
execution::StateFactory state_factory{*tx};
73+
const auto txn_number = co_await state_factory.user_txn_id_at(block_num);
74+
75+
StateReader state_reader{*tx, txn_number};
7176
std::optional<Account> account = co_await state_reader.read_account(address);
7277
if (!account) throw std::domain_error{"account not found"};
7378

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

7781
if (offset) {

0 commit comments

Comments
 (0)