From f439b521e209d29408cb00c13b00868133076f75 Mon Sep 17 00:00:00 2001 From: lupin012 <58134934+lupin012@users.noreply.github.com> Date: Sat, 22 Jul 2023 21:17:45 +0200 Subject: [PATCH] rpcdaemon: rework on eth_getUncleByBlockHashAndIndex and eth_getUncleByBlockNumberAndIndex for snapshot (#1354) --- silkworm/silkrpc/commands/eth_api.cpp | 82 ++++++++++++------- silkworm/silkrpc/core/cached_chain.cpp | 55 ++++++------- silkworm/silkrpc/core/cached_chain.hpp | 4 +- .../test_2.json | 16 ++++ .../test_4.json | 16 ++++ 5 files changed, 110 insertions(+), 63 deletions(-) create mode 100644 tests/integration/goerly/eth_getUncleByBlockHashAndIndex/test_2.json create mode 100644 tests/integration/goerly/eth_getUncleByBlockNumberAndIndex/test_4.json diff --git a/silkworm/silkrpc/commands/eth_api.cpp b/silkworm/silkrpc/commands/eth_api.cpp index 597c0dfd71..e95f0bdb02 100644 --- a/silkworm/silkrpc/commands/eth_api.cpp +++ b/silkworm/silkrpc/commands/eth_api.cpp @@ -239,7 +239,7 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_hash(const nlohmann::jso ethdb::TransactionDatabase tx_database{*tx}; const auto chain_storage = tx->create_storage(tx_database, backend_); - const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, chain_storage, block_hash); + const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, *chain_storage, block_hash); if (block_with_hash) { BlockNum block_number = block_with_hash->block.header.number; const auto total_difficulty{co_await chain_storage->read_total_difficulty(block_with_hash->hash, block_number)}; @@ -249,6 +249,8 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_hash(const nlohmann::jso } else { reply = make_json_content(request["id"], {}); } + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], {}); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -280,7 +282,7 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_number(const nlohmann::j ethdb::TransactionDatabase tx_database{*tx}; const auto block_number = co_await core::get_block_number(block_id, tx_database); const auto chain_storage = tx->create_storage(tx_database, backend_); - const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, chain_storage, tx_database, block_number); + const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, *chain_storage, tx_database, block_number); if (block_with_hash) { const auto total_difficulty{co_await chain_storage->read_total_difficulty(block_with_hash->hash, block_number)}; ensure_post_condition(total_difficulty.has_value(), "no difficulty for block number=" + std::to_string(block_number)); @@ -290,6 +292,8 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_number(const nlohmann::j } else { reply = make_json_content(request["id"], {}); } + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], {}); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -319,12 +323,14 @@ awaitable EthereumRpcApi::handle_eth_get_block_transaction_count_by_hash(c try { ethdb::TransactionDatabase tx_database{*tx}; const auto chain_storage = tx->create_storage(tx_database, backend_); - const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, chain_storage, block_hash); + const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, *chain_storage, block_hash); uint64_t tx_count{0}; if (block_with_hash) { tx_count = block_with_hash->block.transactions.size(); } reply = make_json_content(request["id"], to_quantity(tx_count)); + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], 0x0); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -356,12 +362,14 @@ awaitable EthereumRpcApi::handle_eth_get_block_transaction_count_by_number const auto block_number = co_await core::get_block_number(block_id, tx_database); const auto chain_storage = tx->create_storage(tx_database, backend_); - const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, chain_storage, tx_database, block_number); + const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, *chain_storage, tx_database, block_number); uint64_t tx_count{0}; if (block_with_hash) { tx_count = block_with_hash->block.transactions.size(); } reply = make_json_content(request["id"], to_quantity(tx_count)); + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], 0x0); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -391,24 +399,31 @@ awaitable EthereumRpcApi::handle_eth_get_uncle_by_block_hash_and_index(con try { ethdb::TransactionDatabase tx_database{*tx}; + const auto chain_storage = tx->create_storage(tx_database, backend_); - const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, tx_database, block_hash); - const auto ommers = block_with_hash->block.ommers; + const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, *chain_storage, block_hash); + if (block_with_hash) { + const auto ommers = block_with_hash->block.ommers; - const auto idx = std::stoul(index, nullptr, 16); - if (idx >= ommers.size()) { - SILK_WARN << "invalid_argument: index not found processing request: " << request.dump(); - reply = make_json_content(request["id"], nullptr); - } else { - const auto block_number = block_with_hash->block.header.number; - const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_hash, block_number); - const auto& uncle = ommers[idx]; + const auto idx = std::stoul(index, nullptr, 16); + if (idx >= ommers.size()) { + SILK_WARN << "invalid_argument: index not found processing request: " << request.dump(); + reply = make_json_content(request["id"], nullptr); + } else { + const auto block_number = block_with_hash->block.header.number; + const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_hash, block_number); + const auto& uncle = ommers[idx]; - silkworm::BlockWithHash uncle_block_with_hash{{{}, uncle}, uncle.hash()}; - const Block uncle_block_with_hash_and_td{uncle_block_with_hash, total_difficulty}; + silkworm::BlockWithHash uncle_block_with_hash{{{}, uncle}, uncle.hash()}; + const Block uncle_block_with_hash_and_td{uncle_block_with_hash, total_difficulty}; - reply = make_json_content(request["id"], uncle_block_with_hash_and_td); + reply = make_json_content(request["id"], uncle_block_with_hash_and_td); + } + } else { + reply = make_json_content(request["id"], {}); } + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], {}); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -438,24 +453,31 @@ awaitable EthereumRpcApi::handle_eth_get_uncle_by_block_number_and_index(c try { ethdb::TransactionDatabase tx_database{*tx}; + const auto chain_storage = tx->create_storage(tx_database, backend_); const auto block_number = co_await core::get_block_number(block_id, tx_database); - const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, tx_database, block_number); - const auto ommers = block_with_hash->block.ommers; + const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, *chain_storage, tx_database, block_number); + if (block_with_hash) { + const auto ommers = block_with_hash->block.ommers; - const auto idx = std::stoul(index, nullptr, 16); - if (idx >= ommers.size()) { - SILK_WARN << "invalid_argument: index not found processing request: " << request.dump(); - reply = make_json_content(request["id"], nullptr); - } else { - const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_with_hash->hash, block_number); - const auto& uncle = ommers[idx]; + const auto idx = std::stoul(index, nullptr, 16); + if (idx >= ommers.size()) { + SILK_WARN << "invalid_argument: index not found processing request: " << request.dump(); + reply = make_json_content(request["id"], nullptr); + } else { + const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_with_hash->hash, block_number); + const auto& uncle = ommers[idx]; - silkworm::BlockWithHash uncle_block_with_hash{{{}, uncle}, uncle.hash()}; - const Block uncle_block_with_hash_and_td{uncle_block_with_hash, total_difficulty}; + silkworm::BlockWithHash uncle_block_with_hash{{{}, uncle}, uncle.hash()}; + const Block uncle_block_with_hash_and_td{uncle_block_with_hash, total_difficulty}; - reply = make_json_content(request["id"], uncle_block_with_hash_and_td); + reply = make_json_content(request["id"], uncle_block_with_hash_and_td); + } + } else { + reply = make_json_content(request["id"], {}); } + } catch (const std::invalid_argument& iv) { + reply = make_json_content(request["id"], {}); } catch (const std::exception& e) { SILK_ERROR << "exception: " << e.what() << " processing request: " << request.dump(); reply = make_json_error(request["id"], 100, e.what()); @@ -1123,7 +1145,7 @@ awaitable EthereumRpcApi::handle_eth_call(const nlohmann::json& request, s const auto chain_config = lookup_chain_config(*chain_id); const auto [block_number, is_latest_block] = co_await core::get_block_number(block_id, tx_database, /*latest_required=*/true); - const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, chain_storage, tx_database, block_number); + const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, *chain_storage, tx_database, block_number); silkworm::Transaction txn{call.to_transaction()}; const core::rawdb::DatabaseReader& db_reader = diff --git a/silkworm/silkrpc/core/cached_chain.cpp b/silkworm/silkrpc/core/cached_chain.cpp index 4cc586de63..8a4d5ee8cf 100644 --- a/silkworm/silkrpc/core/cached_chain.cpp +++ b/silkworm/silkrpc/core/cached_chain.cpp @@ -27,7 +27,7 @@ awaitable> read_block_by_number(BlockCache& cache if (cached_block) { co_return cached_block.value(); } - auto block_with_hash = co_await rawdb::read_block(reader, block_hash, block_number); + const auto block_with_hash = co_await rawdb::read_block(reader, block_hash, block_number); if (block_with_hash->block.transactions.size() != 0) { // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, // but block can in the future become canonical(inserted in main chain) with its transactions @@ -36,30 +36,24 @@ awaitable> read_block_by_number(BlockCache& cache co_return block_with_hash; } -awaitable> read_block_by_number(BlockCache& cache, const std::shared_ptr storage, const rawdb::DatabaseReader& reader, uint64_t block_number) { - evmc::bytes32 block_hash; - try { - block_hash = co_await rawdb::read_canonical_block_hash(reader, block_number); - } catch (const std::invalid_argument& iv) { - co_return nullptr; - } +awaitable> read_block_by_number(BlockCache& cache, const ChainStorage& storage, const rawdb::DatabaseReader& reader, uint64_t block_number) { + auto block_hash = co_await rawdb::read_canonical_block_hash(reader, block_number); const auto cached_block = cache.get(block_hash); if (cached_block) { co_return cached_block.value(); } - auto block_with_hash = std::make_shared(); - auto block_found = co_await storage->read_block(block_hash, block_with_hash->block); - if (block_found) { - block_with_hash->hash = block_with_hash->block.header.hash(); - if (block_with_hash->block.transactions.size() != 0) { - // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, - // but block can in the future become canonical(inserted in main chain) with its transactions - cache.insert(block_hash, block_with_hash); - } - co_return block_with_hash; - } else { + const auto block_with_hash = std::make_shared(); + const auto block_found = co_await storage.read_block(block_hash, block_with_hash->block); + if (!block_found) { co_return nullptr; } + block_with_hash->hash = block_with_hash->block.header.hash(); + if (block_with_hash->block.transactions.size() != 0) { + // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, + // but block can in the future become canonical(inserted in main chain) with its transactions + cache.insert(block_hash, block_with_hash); + } + co_return block_with_hash; } awaitable> read_block_by_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const evmc::bytes32& block_hash) { @@ -67,7 +61,7 @@ awaitable> read_block_by_hash(BlockCache& cache, if (cached_block) { co_return cached_block.value(); } - auto block_with_hash = co_await rawdb::read_block_by_hash(reader, block_hash); + const auto block_with_hash = co_await rawdb::read_block_by_hash(reader, block_hash); if (block_with_hash->block.transactions.size() != 0) { // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, // but block can in the future become canonical(inserted in main chain) with its transactions @@ -76,24 +70,23 @@ awaitable> read_block_by_hash(BlockCache& cache, co_return block_with_hash; } -awaitable> read_block_by_hash(BlockCache& cache, const std::shared_ptr storage, const evmc::bytes32& block_hash) { +awaitable> read_block_by_hash(BlockCache& cache, const ChainStorage& storage, const evmc::bytes32& block_hash) { const auto cached_block = cache.get(block_hash); if (cached_block) { co_return cached_block.value(); } auto block_with_hash = std::make_shared(); - auto block_found = co_await storage->read_block(block_hash, block_with_hash->block); - if (block_found) { - block_with_hash->hash = block_with_hash->block.header.hash(); - if (block_with_hash->block.transactions.size() != 0) { - // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, - // but block can in the future become canonical(inserted in main chain) with its transactions - cache.insert(block_hash, block_with_hash); - } - co_return block_with_hash; - } else { + const auto block_found = co_await storage.read_block(block_hash, block_with_hash->block); + if (!block_found) { co_return nullptr; } + block_with_hash->hash = block_with_hash->block.header.hash(); + if (block_with_hash->block.transactions.size() != 0) { + // don't save empty (without txs) blocks to cache, if block become non-canonical (not in main chain), we remove it's transactions, + // but block can in the future become canonical(inserted in main chain) with its transactions + cache.insert(block_hash, block_with_hash); + } + co_return block_with_hash; } awaitable> read_block_by_number_or_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const BlockNumberOrHash& bnoh) { diff --git a/silkworm/silkrpc/core/cached_chain.hpp b/silkworm/silkrpc/core/cached_chain.hpp index af62ae2553..d52413c4de 100644 --- a/silkworm/silkrpc/core/cached_chain.hpp +++ b/silkworm/silkrpc/core/cached_chain.hpp @@ -32,9 +32,9 @@ namespace silkworm::rpc::core { using boost::asio::awaitable; awaitable> read_block_by_number(BlockCache& cache, const rawdb::DatabaseReader& reader, uint64_t block_number); -awaitable> read_block_by_number(BlockCache& cache, const std::shared_ptr storage, const rawdb::DatabaseReader& reader, uint64_t block_number); +awaitable> read_block_by_number(BlockCache& cache, const ChainStorage& storage, const rawdb::DatabaseReader& reader, uint64_t block_number); awaitable> read_block_by_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const evmc::bytes32& block_hash); -awaitable> read_block_by_hash(BlockCache& cache, const std::shared_ptr storage, const evmc::bytes32& block_hash); +awaitable> read_block_by_hash(BlockCache& cache, const ChainStorage& storage, const evmc::bytes32& block_hash); awaitable> read_block_by_number_or_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const BlockNumberOrHash& bnoh); awaitable read_block_by_transaction_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const evmc::bytes32& transaction_hash); awaitable> read_transaction_by_hash(BlockCache& cache, const rawdb::DatabaseReader& reader, const evmc::bytes32& transaction_hash); diff --git a/tests/integration/goerly/eth_getUncleByBlockHashAndIndex/test_2.json b/tests/integration/goerly/eth_getUncleByBlockHashAndIndex/test_2.json new file mode 100644 index 0000000000..87f884bafa --- /dev/null +++ b/tests/integration/goerly/eth_getUncleByBlockHashAndIndex/test_2.json @@ -0,0 +1,16 @@ +[ + { + "request": { + "jsonrpc":"2.0", + "method":"eth_getUncleByBlockHashAndIndex", + "params":["0xffff72e6913a3879217169c6ba461114fa032d9510a56a409d3aab19f668e299","0x0"], + "id":1 + }, + "response": { + "jsonrpc":"2.0", + "id":1, + "result":null + } + } +] + diff --git a/tests/integration/goerly/eth_getUncleByBlockNumberAndIndex/test_4.json b/tests/integration/goerly/eth_getUncleByBlockNumberAndIndex/test_4.json new file mode 100644 index 0000000000..62ab1fc3fd --- /dev/null +++ b/tests/integration/goerly/eth_getUncleByBlockNumberAndIndex/test_4.json @@ -0,0 +1,16 @@ +[ + { + "request": { + "jsonrpc":"2.0", + "method":"eth_getUncleByBlockNumberAndIndex", + "params":["0xffffff", "0x0"], + "id":1 + }, + "response": { + "jsonrpc":"2.0", + "id":1, + "result":null + } + } +] +