diff --git a/eosevm/block_extra_data.cpp b/eosevm/block_extra_data.cpp new file mode 100644 index 00000000..e77ad2e4 --- /dev/null +++ b/eosevm/block_extra_data.cpp @@ -0,0 +1,50 @@ +#include +#include + +#include "block_extra_data.hpp" + +using namespace silkworm; + +namespace eosevm { + bool operator==(const eosevm::block_extra_data& a, const eosevm::block_extra_data& b) { + return a.consensus_parameter_index == b.consensus_parameter_index; + } +} + +namespace silkworm { namespace rlp { + + template + void encode(Bytes& to, const std::optional& v) noexcept { + auto has_value = v.has_value(); + rlp::encode(to, has_value); + if(has_value) { + rlp::encode(to, v.value()); + } + } + + template + DecodingResult decode(ByteView& from, std::optional& out) noexcept { + bool has_value = false; + if (DecodingResult res{decode(from, has_value, Leftover::kAllow)}; !res) { + return res; + } + if(has_value) { + out = T{}; + if (DecodingResult res{decode(from, *out, Leftover::kAllow)}; !res) { + return res; + } + } + return {}; + } + + silkworm::Bytes encode(const eosevm::block_extra_data& out) { + silkworm::Bytes to; + encode(to, out.consensus_parameter_index); + return to; + } + + DecodingResult decode(silkworm::ByteView& from, eosevm::block_extra_data& to) noexcept{ + decode(from, to.consensus_parameter_index); + return {}; + } +} } //namespace silkworm::rlp \ No newline at end of file diff --git a/eosevm/block_extra_data.hpp b/eosevm/block_extra_data.hpp new file mode 100644 index 00000000..62699156 --- /dev/null +++ b/eosevm/block_extra_data.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace eosevm { + +struct block_extra_data { + std::optional consensus_parameter_index; +}; + +} // namespace eosevm + +namespace silkworm { namespace rlp { + silkworm::Bytes encode(const eosevm::block_extra_data&); + DecodingResult decode(silkworm::ByteView& from, eosevm::block_extra_data& to) noexcept; +}} // namespace silkworm::rlp diff --git a/silkworm/core/types/block.cpp b/silkworm/core/types/block.cpp index 285446af..e28d1e65 100644 --- a/silkworm/core/types/block.cpp +++ b/silkworm/core/types/block.cpp @@ -33,7 +33,7 @@ bool operator==(const BlockHeader& a, const BlockHeader& b) { } bool operator==(const BlockBody& a, const BlockBody& b) { - return a.transactions == b.transactions && a.ommers == b.ommers && a.consensus_parameter_index == b.consensus_parameter_index; + return a.transactions == b.transactions && a.ommers == b.ommers; } BlockNum height(const BlockId& b) { return b.number; } @@ -241,9 +241,6 @@ namespace rlp { Header rlp_head{.list = true}; rlp_head.payload_length += length(b.transactions); rlp_head.payload_length += length(b.ommers); - if (b.consensus_parameter_index) { - rlp_head.payload_length += length(*b.consensus_parameter_index); - } if (b.withdrawals) { rlp_head.payload_length += length(*b.withdrawals); } @@ -259,9 +256,6 @@ namespace rlp { encode_header(to, rlp_header_body(block_body)); encode(to, block_body.transactions); encode(to, block_body.ommers); - if (block_body.consensus_parameter_index) { - encode(to, *block_body.consensus_parameter_index); - } if (block_body.withdrawals) { encode(to, *block_body.withdrawals); } @@ -284,15 +278,6 @@ namespace rlp { return res; } - to.consensus_parameter_index = std::nullopt; - if (from.length() > leftover) { - evmc::bytes32 consensus_parameter_index; - if (DecodingResult res{decode(from, consensus_parameter_index, Leftover::kAllow)}; !res) { - return res; - } - to.consensus_parameter_index = consensus_parameter_index; - } - to.withdrawals = std::nullopt; if (from.length() > leftover) { std::vector withdrawals; @@ -325,15 +310,6 @@ namespace rlp { return res; } - to.consensus_parameter_index = std::nullopt; - if (from.length() > leftover) { - evmc::bytes32 consensus_parameter_index; - if (DecodingResult res{decode(from, consensus_parameter_index, Leftover::kAllow)}; !res) { - return res; - } - to.consensus_parameter_index = consensus_parameter_index; - } - to.withdrawals = std::nullopt; if (from.length() > leftover) { std::vector withdrawals; @@ -365,9 +341,6 @@ namespace rlp { encode(to, block.header); encode(to, block.transactions); encode(to, block.ommers); - if (block.consensus_parameter_index) { - encode(to, *block.consensus_parameter_index); - } if (block.withdrawals) { encode(to, *block.withdrawals); } diff --git a/silkworm/core/types/block.hpp b/silkworm/core/types/block.hpp index bf3ecaec..ebf380b9 100644 --- a/silkworm/core/types/block.hpp +++ b/silkworm/core/types/block.hpp @@ -32,7 +32,7 @@ #include #include -#include +#include namespace silkworm { @@ -96,8 +96,22 @@ struct BlockBody { std::vector ommers; std::optional> withdrawals{std::nullopt}; - // EOS-EVM - std::optional consensus_parameter_index{std::nullopt}; + // EOS-EVM + std::optional eosevm_extra_data{std::nullopt}; + + bool has_consensus_parameter_index() { + return eosevm_extra_data.has_value() && eosevm_extra_data->consensus_parameter_index.has_value(); + } + + void set_consensus_parameter_index(const std::optional& index) { + if(!eosevm_extra_data.has_value()) eosevm_extra_data=eosevm::block_extra_data{}; + eosevm_extra_data->consensus_parameter_index = index; + } + + std::optional get_consensus_parameter_index() const { + if(!eosevm_extra_data.has_value()) return {}; + return eosevm_extra_data.value().consensus_parameter_index; + } friend bool operator==(const BlockBody&, const BlockBody&); }; @@ -105,7 +119,9 @@ struct BlockBody { struct Block : public BlockBody { BlockHeader header; + // EOS-EVM bool irreversible{false}; + void recover_senders(); }; diff --git a/silkworm/core/types/block_test.cpp b/silkworm/core/types/block_test.cpp index 60d79273..674ed942 100644 --- a/silkworm/core/types/block_test.cpp +++ b/silkworm/core/types/block_test.cpp @@ -104,8 +104,6 @@ TEST_CASE("BlockBody RLP 2") { body.ommers[0].prev_randao = 0xf0a53dfdd6c2f2a661e718ef29092de60d81d45f84044bec7bf4b36630b2bc08_bytes32; body.ommers[0].nonce[7] = 35; - body.consensus_parameter_index = evmc::bytes32(1234); - Bytes rlp{}; rlp::encode(rlp, body); diff --git a/silkworm/node/db/access_layer.cpp b/silkworm/node/db/access_layer.cpp index f625b94d..b31558bb 100644 --- a/silkworm/node/db/access_layer.cpp +++ b/silkworm/node/db/access_layer.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace silkworm::db { @@ -411,6 +412,9 @@ size_t process_blocks_at_height(ROTxn& txn, BlockNum height, std::functionconsensus_parameter_index == 0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3_bytes32); CHECK(!block.transactions[0].from); CHECK(!block.transactions[1].from); @@ -528,8 +536,15 @@ TEST_CASE("Headers and bodies") { auto [b, h] = split_block_key(key); REQUIRE(b == header.number); REQUIRE(h == header.hash()); + } + + SECTION("empty eosevm_extra_data") { + BlockBody body{sample_block_body(false)}; + CHECK_NOTHROW(write_body(txn, body, header.hash(), header.number)); - CHECK(block.consensus_parameter_index == evmc::bytes32(1234)); + Block block; + REQUIRE(read_block_by_number(txn, block_num, false, block)); + CHECK(block.eosevm_extra_data.has_value() == false); } SECTION("process_blocks_at_height") { @@ -545,6 +560,9 @@ TEST_CASE("Headers and bodies") { [&count, &height](const Block& block) { REQUIRE(block.header.number == height); count++; + CHECK(block.eosevm_extra_data.has_value() == true); + CHECK(block.eosevm_extra_data.value().consensus_parameter_index.has_value() == true); + CHECK(block.eosevm_extra_data->consensus_parameter_index == 0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3_bytes32); }); REQUIRE(processed == 1); REQUIRE(processed == count); @@ -564,6 +582,9 @@ TEST_CASE("Headers and bodies") { height, [&count, &height](const Block& block) { REQUIRE(block.header.number == height); + CHECK(block.eosevm_extra_data.has_value() == true); + CHECK(block.eosevm_extra_data.value().consensus_parameter_index.has_value() == true); + CHECK(block.eosevm_extra_data->consensus_parameter_index == 0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3_bytes32); count++; }); REQUIRE(processed == 2); diff --git a/silkworm/node/db/tables.hpp b/silkworm/node/db/tables.hpp index c8688cc2..0ebfb811 100644 --- a/silkworm/node/db/tables.hpp +++ b/silkworm/node/db/tables.hpp @@ -69,6 +69,15 @@ inline constexpr db::MapConfig kAccountHistory{kAccountHistoryName}; inline constexpr const char* kBlockBodiesName{"BlockBody"}; inline constexpr db::MapConfig kBlockBodies{kBlockBodiesName}; +//! \details Holds extra block data +//! \struct +//! \verbatim +//! key : block number (BE 8 bytes) + block header hash (32 bytes) +//! value : extra block data RLP encoded +//! \endverbatim +inline constexpr const char* kExtraBlockDataName{"ExtraBlockData"}; +inline constexpr db::MapConfig kExtraBlockData{kExtraBlockDataName}; + //! \details Stores the binding of *canonical* block number with header hash //! \struct //! \verbatim @@ -426,6 +435,7 @@ inline constexpr db::MapConfig kChainDataTables[]{ kTxLookup, kRuntimeStates, kConsensusParameters, + kExtraBlockData }; //! \brief Ensures all defined tables are present in db with consistent flags. Should a table not exist it gets created diff --git a/silkworm/node/db/util.cpp b/silkworm/node/db/util.cpp index 0eea21cb..d371b937 100644 --- a/silkworm/node/db/util.cpp +++ b/silkworm/node/db/util.cpp @@ -160,9 +160,6 @@ namespace detail { header.payload_length += rlp::length(base_txn_id); header.payload_length += rlp::length(txn_count); header.payload_length += rlp::length(ommers); - if (consensus_parameter_index) { - header.payload_length += rlp::length(*consensus_parameter_index); - } if (withdrawals) { header.payload_length += rlp::length(*withdrawals); } @@ -172,9 +169,6 @@ namespace detail { rlp::encode(to, base_txn_id); rlp::encode(to, txn_count); rlp::encode(to, ommers); - if (consensus_parameter_index) { - rlp::encode(to, *consensus_parameter_index); - } if (withdrawals) { rlp::encode(to, *withdrawals); } @@ -199,15 +193,6 @@ namespace detail { return res; } - to.consensus_parameter_index = std::nullopt; - if (from.length() > leftover) { - evmc::bytes32 consensus_parameter_index; - if (DecodingResult res{rlp::decode(from, consensus_parameter_index, rlp::Leftover::kAllow)}; !res) { - return res; - } - to.consensus_parameter_index = consensus_parameter_index; - } - to.withdrawals = std::nullopt; if (from.length() > leftover) { std::vector withdrawals; diff --git a/silkworm/node/db/util.hpp b/silkworm/node/db/util.hpp index 677cbb93..9c52230f 100644 --- a/silkworm/node/db/util.hpp +++ b/silkworm/node/db/util.hpp @@ -133,8 +133,6 @@ namespace detail { std::vector ommers; std::optional> withdrawals{std::nullopt}; // EIP-4895 - std::optional consensus_parameter_index{std::nullopt}; - [[nodiscard]] Bytes encode() const; friend bool operator==(const BlockBodyForStorage&, const BlockBodyForStorage&) = default; diff --git a/silkworm/node/db/util_test.cpp b/silkworm/node/db/util_test.cpp index 3ad55d31..ececbe24 100644 --- a/silkworm/node/db/util_test.cpp +++ b/silkworm/node/db/util_test.cpp @@ -47,7 +47,6 @@ TEST_CASE("BlockBodyForStorage encoding") { CHECK(decoded == body); // No withdrawals - body.consensus_parameter_index = evmc::bytes32(1234); encoded = body.encode(); view = encoded; decoded = decode_stored_block_body(view); diff --git a/silkworm/node/stagedsync/stages/stage.cpp b/silkworm/node/stagedsync/stages/stage.cpp index eac78826..d157d179 100644 --- a/silkworm/node/stagedsync/stages/stage.cpp +++ b/silkworm/node/stagedsync/stages/stage.cpp @@ -47,8 +47,9 @@ void Stage::throw_if_stopping() { } const evmone::gas_parameters& Stage::get_gas_params(db::ROTxn& txn, const Block& block) { - if(block.consensus_parameter_index != last_consensus_parameter_index) { - auto consensus_params = silkworm::db::read_consensus_parameters(txn, block.consensus_parameter_index.value()); + auto curr_consensus_parameter_index = block.get_consensus_parameter_index(); + if(curr_consensus_parameter_index != last_consensus_parameter_index) { + auto consensus_params = silkworm::db::read_consensus_parameters(txn, block); if(consensus_params.has_value() && consensus_params->gas_fee_parameters.has_value()) { last_gas_params = evmone::gas_parameters( consensus_params->gas_fee_parameters->gas_txnewaccount, @@ -60,7 +61,7 @@ const evmone::gas_parameters& Stage::get_gas_params(db::ROTxn& txn, const Block& } else { last_gas_params=evmone::gas_parameters{}; } - last_consensus_parameter_index = block.consensus_parameter_index; + last_consensus_parameter_index = curr_consensus_parameter_index; } return last_gas_params; } diff --git a/silkworm/silkrpc/commands/eth_api.cpp b/silkworm/silkrpc/commands/eth_api.cpp index 5eda41a2..fad37c6e 100644 --- a/silkworm/silkrpc/commands/eth_api.cpp +++ b/silkworm/silkrpc/commands/eth_api.cpp @@ -239,14 +239,14 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_hash(const nlohmann::jso try { ethdb::TransactionDatabase tx_database{*tx}; - const auto block_with_hash = co_await core::read_block_by_hash(*block_cache_, tx_database, block_hash); + if (!block_with_hash) { + reply = make_json_error(request["id"], 100, "error"); + co_return; + } 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); - std::optional consensus_parameter; - if(block_with_hash && block_with_hash->block.consensus_parameter_index.has_value()) { - consensus_parameter = co_await silkworm::rpc::core::rawdb::read_consensus_parameters(tx_database, block_with_hash->block.consensus_parameter_index.value()); - } + const auto consensus_parameter = co_await read_consensus_parameters(tx_database, block_with_hash->block.get_consensus_parameter_index()); const Block extended_block{*block_with_hash, total_difficulty, full_tx, consensus_parameter}; reply = make_json_content(request["id"], extended_block); } catch (const std::invalid_argument& iv) { @@ -292,11 +292,12 @@ awaitable EthereumRpcApi::handle_eth_get_block_by_number(const nlohmann::j reply = make_json_content(request["id"], nlohmann::detail::value_t::null); } else { const auto block_with_hash = co_await core::read_block_by_number(*block_cache_, tx_database, block_number); - const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_with_hash->hash, block_number); - std::optional consensus_parameter; - if(block_with_hash && block_with_hash->block.consensus_parameter_index.has_value()) { - consensus_parameter = co_await silkworm::rpc::core::rawdb::read_consensus_parameters(tx_database, block_with_hash->block.consensus_parameter_index.value()); + if (!block_with_hash) { + reply = make_json_error(request["id"], 100, "error"); + co_return; } + const auto total_difficulty = co_await core::rawdb::read_total_difficulty(tx_database, block_with_hash->hash, block_number); + const auto consensus_parameter = co_await read_consensus_parameters(tx_database, block_with_hash->block.get_consensus_parameter_index()); const Block extended_block{*block_with_hash, total_difficulty, full_tx, consensus_parameter}; reply = make_json_content(request["id"], extended_block); } diff --git a/silkworm/silkrpc/commands/eth_api.hpp b/silkworm/silkrpc/commands/eth_api.hpp index 34fac1dc..4a5ee712 100644 --- a/silkworm/silkrpc/commands/eth_api.hpp +++ b/silkworm/silkrpc/commands/eth_api.hpp @@ -128,6 +128,8 @@ class EthereumRpcApi { awaitable handle_eth_get_logs(const nlohmann::json& request, std::string& reply); awaitable handle_eth_call(const nlohmann::json& request, std::string& reply); + std::optional get_consensus_parameter(std::shared_ptr block_with_hash); + boost::asio::io_context& io_context_; BlockCache* block_cache_; ethdb::kv::StateCache* state_cache_; diff --git a/silkworm/silkrpc/core/account_dumper_test.cpp b/silkworm/silkrpc/core/account_dumper_test.cpp index cf98d2fb..660f3933 100644 --- a/silkworm/silkrpc/core/account_dumper_test.cpp +++ b/silkworm/silkrpc/core/account_dumper_test.cpp @@ -85,6 +85,7 @@ class DummyCursor : public ethdb::CursorDupSort { boost::asio::awaitable seek_exact(silkworm::ByteView key) override { const nlohmann::json table = json_.value(table_name_, empty); + if( table.is_null() ) co_return silkworm::KeyValue{}; const auto& entry = table.value(silkworm::to_hex(key), ""); auto value{*silkworm::from_hex(entry)}; diff --git a/silkworm/silkrpc/core/cached_chain_test.cpp b/silkworm/silkrpc/core/cached_chain_test.cpp index e2f77b60..f45bc9eb 100644 --- a/silkworm/silkrpc/core/cached_chain_test.cpp +++ b/silkworm/silkrpc/core/cached_chain_test.cpp @@ -118,6 +118,7 @@ TEST_CASE("read_block_by_number_or_hash") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_number_or_hash(cache, db_reader, bnoh), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -129,6 +130,7 @@ TEST_CASE("read_block_by_number_or_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_number_or_hash(cache, db_reader, bnoh), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -140,6 +142,7 @@ TEST_CASE("read_block_by_number_or_hash") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_number_or_hash(cache, db_reader, bnoh), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -158,6 +161,7 @@ TEST_CASE("silkworm::core::read_block_by_number") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, core::read_block_by_number(cache, db_reader, bn), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -168,6 +172,7 @@ TEST_CASE("silkworm::core::read_block_by_number") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { Bytes key{}; Bytes value{*silkworm::from_hex( @@ -194,6 +199,7 @@ TEST_CASE("silkworm::core::read_block_by_number") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, core::read_block_by_number(cache, db_reader, bn), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -202,6 +208,7 @@ TEST_CASE("silkworm::core::read_block_by_number") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([]() -> boost::asio::awaitable { co_return; })); auto result1 = boost::asio::co_spawn(pool, core::read_block_by_number(cache, db_reader, bn), boost::asio::use_future); const std::shared_ptr bwh1 = result1.get(); @@ -219,6 +226,7 @@ TEST_CASE("silkworm::core::read_block_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { Bytes key{}; Bytes value{*silkworm::from_hex( @@ -241,6 +249,7 @@ TEST_CASE("silkworm::core::read_block_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { Bytes key{}; Bytes value{*silkworm::from_hex( @@ -265,6 +274,7 @@ TEST_CASE("silkworm::core::read_block_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, core::read_block_by_hash(cache, db_reader, bh), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -273,6 +283,7 @@ TEST_CASE("silkworm::core::read_block_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([]() -> boost::asio::awaitable { co_return; })); auto result1 = boost::asio::co_spawn(pool, core::read_block_by_hash(cache, db_reader, bh), boost::asio::use_future); const std::shared_ptr bwh1 = result1.get(); @@ -348,6 +359,7 @@ TEST_CASE("read_block_by_transaction_hash") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_transaction_hash(cache, db_reader, transaction_hash), boost::asio::use_future); const silkworm::BlockWithHash bwh = result.get(); @@ -385,6 +397,7 @@ TEST_CASE("read_transaction_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_transaction_by_hash(cache, db_reader, transaction_hash), boost::asio::use_future); CHECK(result.get() == std::nullopt); @@ -396,6 +409,7 @@ TEST_CASE("read_transaction_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNotEmptyBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { Bytes key{}; Bytes value{*silkworm::from_hex( diff --git a/silkworm/silkrpc/core/evm_trace_test.cpp b/silkworm/silkrpc/core/evm_trace_test.cpp index 5b5cf3c6..ac153c0f 100644 --- a/silkworm/silkrpc/core/evm_trace_test.cpp +++ b/silkworm/silkrpc/core/evm_trace_test.cpp @@ -3841,6 +3841,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue3; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); // TransactionDatabase::walk: TABLE BlockTransaction static Bytes kBlockTransactionKey1{*silkworm::from_hex("0000000005c62e66")}; @@ -5334,6 +5335,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue2; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); BlockCache block_cache; std::shared_ptr mock_cursor = std::make_shared(); @@ -5418,6 +5420,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue2; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); BlockCache block_cache; std::shared_ptr mock_cursor = std::make_shared(); @@ -5476,6 +5479,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue2; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); BlockCache block_cache; std::shared_ptr mock_cursor = std::make_shared(); @@ -5591,6 +5595,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue2; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); BlockCache block_cache; std::shared_ptr mock_cursor = std::make_shared(); @@ -5675,6 +5680,7 @@ TEST_CASE_METHOD(TraceCallExecutorTest, "TraceCallExecutor::trace_filter") { .WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockBodyValue2; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillRepeatedly(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); BlockCache block_cache; std::shared_ptr mock_cursor = std::make_shared(); diff --git a/silkworm/silkrpc/core/gas_parameters.cpp b/silkworm/silkrpc/core/gas_parameters.cpp index 53da2796..628763e7 100644 --- a/silkworm/silkrpc/core/gas_parameters.cpp +++ b/silkworm/silkrpc/core/gas_parameters.cpp @@ -7,8 +7,8 @@ awaitable> load_gas_parameters(Tran auto eos_evm_version = chain_config_ptr->eos_evm_version(block.header); evmone::gas_parameters gas_params; - if(eos_evm_version > 0 && block.consensus_parameter_index.has_value()) { - auto consensus_params = co_await silkworm::rpc::core::rawdb::read_consensus_parameters(tx_database, block.consensus_parameter_index.value()); + if(eos_evm_version > 0) { + auto consensus_params = co_await silkworm::rpc::core::rawdb::read_consensus_parameters(tx_database, block.get_consensus_parameter_index()); if(consensus_params.has_value() && consensus_params->gas_fee_parameters.has_value()) { gas_params=evmone::gas_parameters( consensus_params->gas_fee_parameters->gas_txnewaccount, diff --git a/silkworm/silkrpc/core/rawdb/chain.cpp b/silkworm/silkrpc/core/rawdb/chain.cpp index bfdfbba1..c6c8d242 100644 --- a/silkworm/silkrpc/core/rawdb/chain.cpp +++ b/silkworm/silkrpc/core/rawdb/chain.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace silkworm::rpc::core::rawdb { @@ -125,7 +126,8 @@ boost::asio::awaitable> read_block(const Database block_with_hash_ptr->block.transactions = std::move(body.transactions); block_with_hash_ptr->block.ommers = std::move(body.ommers); block_with_hash_ptr->block.withdrawals = std::move(body.withdrawals); - block_with_hash_ptr->block.consensus_parameter_index = body.consensus_parameter_index; + block_with_hash_ptr->block.eosevm_extra_data = co_await read_extra_block_data(reader, block_hash, block_number); + block_with_hash_ptr->hash = block_hash; co_return block_with_hash_ptr; } @@ -203,7 +205,7 @@ boost::asio::awaitable read_body(const DatabaseReader& read auto stored_body{silkworm::db::detail::decode_stored_block_body(data_view)}; // If block contains no txn, we're done if (stored_body.txn_count == 0) { - co_return BlockBody{{}, std::move(stored_body.ommers), std::move(stored_body.withdrawals), stored_body.consensus_parameter_index}; + co_return BlockBody{{}, std::move(stored_body.ommers), std::move(stored_body.withdrawals)}; } // original comment: 1 system txn at the beginning of block and 1 at the end SILK_DEBUG << "base_txn_id: " << stored_body.base_txn_id << " txn_count: " << stored_body.txn_count; @@ -221,7 +223,7 @@ boost::asio::awaitable read_body(const DatabaseReader& read SILK_WARN << "#senders: " << senders.size() << " and #txns " << transactions.size() << " do not match"; } } - co_return BlockBody{std::move(transactions), std::move(stored_body.ommers), std::move(stored_body.withdrawals), stored_body.consensus_parameter_index}; + co_return BlockBody{std::move(transactions), std::move(stored_body.ommers), std::move(stored_body.withdrawals)}; } catch (const silkworm::DecodingException& error) { SILK_ERROR << "RLP decoding error for block body #" << block_number << " [" << error.what() << "]"; throw std::runtime_error{"RLP decoding error for block body [" + std::string(error.what()) + "]"}; @@ -436,8 +438,9 @@ boost::asio::awaitable read_cumulative_gas_used(const core::rawdb co_return cumulative_gas_index; } -boost::asio::awaitable> read_consensus_parameters(const core::rawdb::DatabaseReader& reader, const evmc::bytes32& index) { - const auto block_key = silkworm::db::block_key(index.bytes); +boost::asio::awaitable> read_consensus_parameters(const core::rawdb::DatabaseReader& reader, const std::optional& index) { + if(!index.has_value()) co_return std::nullopt; + const auto block_key = silkworm::db::block_key(index.value().bytes); const auto value = co_await reader.get_one(db::table::kConsensusParametersName, block_key); if (value.empty()) { co_return std::nullopt; @@ -445,4 +448,18 @@ boost::asio::awaitable> read_consensu co_return eosevm::ConsensusParameters::decode(value); } +boost::asio::awaitable> read_extra_block_data(const core::rawdb::DatabaseReader& reader, const evmc::bytes32& block_hash, uint64_t block_number) { + const auto block_key = silkworm::db::block_key(block_number, block_hash.bytes); + + const auto result = co_await reader.get_one(db::table::kExtraBlockDataName, block_key); + if (result.empty()) { + co_return std::nullopt; + } + + eosevm::block_extra_data out; + silkworm::ByteView value{result}; + rlp::decode(value, out); + co_return out; +} + } // namespace silkworm::rpc::core::rawdb diff --git a/silkworm/silkrpc/core/rawdb/chain.hpp b/silkworm/silkrpc/core/rawdb/chain.hpp index 4f97199e..e63e574d 100644 --- a/silkworm/silkrpc/core/rawdb/chain.hpp +++ b/silkworm/silkrpc/core/rawdb/chain.hpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace silkworm::rpc::core::rawdb { @@ -89,6 +90,8 @@ boost::asio::awaitable read_total_burnt(const core::rawdb::Databa boost::asio::awaitable read_cumulative_gas_used(const core::rawdb::DatabaseReader& reader, uint64_t block_number); -boost::asio::awaitable> read_consensus_parameters(const core::rawdb::DatabaseReader& reader, const evmc::bytes32& block_number); +boost::asio::awaitable> read_consensus_parameters(const core::rawdb::DatabaseReader& reader, const std::optional& index); + +boost::asio::awaitable> read_extra_block_data(const core::rawdb::DatabaseReader& reader, const evmc::bytes32& block_hash, uint64_t block_number); } // namespace silkworm::rpc::core::rawdb diff --git a/silkworm/silkrpc/core/rawdb/chain_test.cpp b/silkworm/silkrpc/core/rawdb/chain_test.cpp index ada4f739..3cda1e64 100644 --- a/silkworm/silkrpc/core/rawdb/chain_test.cpp +++ b/silkworm/silkrpc/core/rawdb/chain_test.cpp @@ -346,6 +346,7 @@ TEST_CASE("read_block_by_hash") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_hash(db_reader, block_hash), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -420,6 +421,7 @@ TEST_CASE("read_block_by_number") { EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBlockHash; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block_by_number(db_reader, block_number), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -493,6 +495,7 @@ TEST_CASE("read_block") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return silkworm::Bytes{}; })); + //EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); auto result = boost::asio::co_spawn(pool, read_block(db_reader, block_hash, block_number), boost::asio::use_future); #ifdef SILKWORM_SANITIZE // Avoid comparison against exception message: it triggers a TSAN data race seemingly related to libstdc++ string implementation CHECK_THROWS_AS(result.get(), std::runtime_error); @@ -506,6 +509,7 @@ TEST_CASE("read_block") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return silkworm::Bytes{0x00, 0x01}; })); + //EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); auto result = boost::asio::co_spawn(pool, read_block(db_reader, block_hash, block_number), boost::asio::use_future); CHECK_THROWS_AS(result.get(), std::runtime_error); } @@ -515,6 +519,7 @@ TEST_CASE("read_block") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return *silkworm::from_hex("c68369000003c0"); })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block(db_reader, block_hash, block_number), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -526,6 +531,7 @@ TEST_CASE("read_block") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return; })); auto result = boost::asio::co_spawn(pool, read_block(db_reader, block_hash, block_number), boost::asio::use_future); const std::shared_ptr bwh = result.get(); @@ -681,6 +687,7 @@ TEST_CASE("read_body") { const auto block_hash{0x439816753229fc0736bf86a5048de4bc9fcdede8c91dadf88c828c76b2281dff_bytes32}; const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return silkworm::Bytes{}; })); + //EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); auto result = boost::asio::co_spawn(pool, read_body(db_reader, block_hash, block_number), boost::asio::use_future); #ifdef SILKWORM_SANITIZE // Avoid comparison against exception message: it triggers a TSAN data race seemingly related to libstdc++ string implementation CHECK_THROWS_AS(result.get(), std::runtime_error); @@ -1008,6 +1015,7 @@ TEST_CASE("read_receipts") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { silkworm::Bytes key{}; silkworm::Bytes value{*silkworm::from_hex( @@ -1038,6 +1046,7 @@ TEST_CASE("read_receipts") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { silkworm::Bytes key{}; silkworm::Bytes value{*silkworm::from_hex( @@ -1097,7 +1106,7 @@ TEST_CASE("read_receipts") { EXPECT_CALL(db_reader, get_one(db::table::kHeaderNumbersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kNumber; })); EXPECT_CALL(db_reader, get_one(db::table::kHeadersName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kHeader; })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); - + EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); EXPECT_CALL(db_reader, walk(db::table::kBlockTransactionsName, _, _, _)).WillOnce(Invoke([](Unused, Unused, Unused, Walker w) -> boost::asio::awaitable { silkworm::Bytes key1{}; silkworm::Bytes value1{*silkworm::from_hex( @@ -1418,6 +1427,7 @@ TEST_CASE("read_cumulative_transaction_count") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return *silkworm::from_hex("9816753229fc0736bf86a5048de4bc9fcdede8c91dadf88c828c76b2281dff"); })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return kBody; })); + //EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); auto result = boost::asio::co_spawn(pool, read_cumulative_transaction_count(db_reader, block_number), boost::asio::use_future); CHECK(result.get() == 6939740); } @@ -1442,6 +1452,7 @@ TEST_CASE("read_cumulative_transaction_count") { const uint64_t block_number{4'000'000}; EXPECT_CALL(db_reader, get_one(db::table::kCanonicalHashesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return *silkworm::from_hex("9816753229fc0736bf86a5048de4bc9fcdede8c91dadf88c828c76b2281dff"); })); EXPECT_CALL(db_reader, get_one(db::table::kBlockBodiesName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return silkworm::Bytes{0x00, 0x01}; })); + //EXPECT_CALL(db_reader, get_one(db::table::kExtraBlockDataName, _)).WillOnce(InvokeWithoutArgs([]() -> boost::asio::awaitable { co_return Bytes{}; })); auto result = boost::asio::co_spawn(pool, read_cumulative_transaction_count(db_reader, block_number), boost::asio::use_future); CHECK_THROWS_AS(result.get(), std::runtime_error); } diff --git a/silkworm/silkrpc/types/block.hpp b/silkworm/silkrpc/types/block.hpp index 02af497f..3f1d38a1 100644 --- a/silkworm/silkrpc/types/block.hpp +++ b/silkworm/silkrpc/types/block.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "receipt.hpp"