From 656646e7997b83628b58773097b8811b38a092d6 Mon Sep 17 00:00:00 2001 From: yarkin Date: Sun, 4 Feb 2024 12:33:53 +0800 Subject: [PATCH 1/7] Storage for new consensus paramters. --- eosevm/consensus_parameters.hpp | 114 ++++++++++++++++++++++++++++++ silkworm/node/db/access_layer.cpp | 21 ++++++ silkworm/node/db/access_layer.hpp | 8 +++ silkworm/node/db/tables.hpp | 4 ++ 4 files changed, 147 insertions(+) create mode 100644 eosevm/consensus_parameters.hpp diff --git a/eosevm/consensus_parameters.hpp b/eosevm/consensus_parameters.hpp new file mode 100644 index 00000000..1e03b987 --- /dev/null +++ b/eosevm/consensus_parameters.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include + +#if not defined(ANTELOPE) +#include +#endif + +#include +#include +#include + +namespace eosevm { + +struct GasFeeParameters { + // gas_txnewaccount = account_bytes * gas_per_byte + uint64_t gas_txnewaccount; + // gas_newaccount = account_bytes * gas_per_byte + uint64_t gas_newaccount; + // gas_txcreate = gas_create = contract_fixed_bytes * gas_per_byte + uint64_t gas_txcreate; + // gas_codedeposit = gas_per_byte + uint64_t gas_codedeposit; + // gas_sset = 100 + storage_slot_bytes * gas_per_byte + uint64_t gas_sset; + + #if not defined(ANTELOPE) + [[nodiscard]] nlohmann::json to_json() const noexcept { + nlohmann::json ret; + ret["gasTxnewaccount"] = gas_txnewaccount; + ret["gasNewaccount"] = gas_newaccount; + ret["gasTxcreate"] = gas_txcreate; + ret["gasCodedeposit"] = gas_codedeposit; + ret["gasSset"] = gas_sset; + + return ret; + } + #endif + + //! \brief Try parse a JSON object into strongly typed ChainConfig + //! \remark Should this return std::nullopt the parsing has failed + #if not defined(ANTELOPE) + + static std::optional from_json(const nlohmann::json& json) noexcept { + GasFeeParameters feeParams; + + if (!json.contains("gasTxnewaccount") || !json.contains("gasNewaccount") || !json.contains("gasTxcreate") || + !json.contains("gasCodedeposit") || !json.contains("gasSset")) { + // Faii if any of the parameters are missing. + return std::nullopt; + } + + feeParams.gas_txnewaccount = json["gasTxnewaccount"].get(); + feeParams.gas_newaccount = json["gasNewaccount"].get(); + feeParams.gas_txcreate = json["gasTxcreate"].get(); + feeParams.gas_codedeposit = json["gasCodedeposit"].get(); + feeParams.gas_sset = json["gasSset"].get(); + + return feeParams; + } + + #endif + + friend bool operator==(const GasFeeParameters&, const GasFeeParameters&); +}; + +struct ConsensusParameters { + std::optional min_gas_price; + std::optional gas_fee_parameters; + + //! \brief Return the JSON representation of this object + #if not defined(ANTELOPE) + [[nodiscard]] nlohmann::json to_json() const noexcept { + + nlohmann::json ret; + if (min_gas_price) { + ret["minGasPrice"] = intx::to_string(min_gas_price.value()); + } + if (gas_fee_parameters) { + ret["gasFeeParameters"] = gas_fee_parameters.value().to_json(); + } + + return ret; + }; + #endif + + //! \brief Try parse a JSON object into strongly typed ChainConfig + //! \remark Should this return std::nullopt the parsing has failed + #if not defined(ANTELOPE) + static std::optional from_json(const nlohmann::json& json) noexcept { + ConsensusParameters config{}; + if (json.contains("minGasPrice")) { + config.min_gas_price = intx::from_string(json["minGasPrice"].get()); + } + + if (json.contains("gasFeeParameters")) { + // Can be nullopt if parsing GasFeeParameters failed. + config.gas_fee_parameters = GasFeeParameters::from_json(json["gasFeeParameters"]); + } + + return config; + } + #endif + + friend bool operator==(const ConsensusParameters&, const ConsensusParameters&); +}; +} // namespace eosevm \ No newline at end of file diff --git a/silkworm/node/db/access_layer.cpp b/silkworm/node/db/access_layer.cpp index 1d616a5a..6a8dda69 100644 --- a/silkworm/node/db/access_layer.cpp +++ b/silkworm/node/db/access_layer.cpp @@ -1217,4 +1217,25 @@ void write_runtime_states_u64(RWTxn& txn, uint64_t num, RuntimeState runtime_sta write_runtime_states_bytes(txn, value, runtime_state); } +std::optional read_consensus_parameters(ROTxn& txn, BlockNum index) { + auto cursor = txn.ro_cursor(table::kConsensusParameters); + auto key{db::block_key(index)}; + auto data{cursor->find(to_slice(key), /*throw_notfound=*/false)}; + if (!data) { + return std::nullopt; + } + + // https://github.com/nlohmann/json/issues/2204 + const auto json = nlohmann::json::parse(data.value.as_string(), nullptr, false); + return eosevm::ConsensusParameters::from_json(json); +} + +void update_consensus_parameters(RWTxn& txn, BlockNum index, const eosevm::ConsensusParameters& config) { + auto cursor = txn.rw_cursor(table::kConsensusParameters); + auto key{db::block_key(index)}; + + auto config_data{config.to_json().dump()}; + cursor->upsert(to_slice(key), mdbx::slice(config_data.data())); +} + } // namespace silkworm::db diff --git a/silkworm/node/db/access_layer.hpp b/silkworm/node/db/access_layer.hpp index 8d0131ee..5ad62635 100644 --- a/silkworm/node/db/access_layer.hpp +++ b/silkworm/node/db/access_layer.hpp @@ -32,6 +32,8 @@ #include #include +#include + namespace silkworm::db { //! \brief Pulls database schema version @@ -249,6 +251,12 @@ std::optional read_runtime_states_u64(ROTxn& txn, RuntimeState runtime //! \brief Write uint64_t as runtime states by index void write_runtime_states_u64(RWTxn& txn, uint64_t num, RuntimeState runtime_state); +//! \brief Read ConsensusParameters indexed by blocknum that it is added. +std::optional read_consensus_parameters(ROTxn& txn, BlockNum index); + +//! \brief Write ConsensusParameters indexed by blocknum that it is added. Can overwrite during forks. +void update_consensus_parameters(RWTxn& txn, BlockNum index, const eosevm::ConsensusParameters& config); + class DataModel { public: static void set_snapshot_repository(snapshot::SnapshotRepository* repository); diff --git a/silkworm/node/db/tables.hpp b/silkworm/node/db/tables.hpp index b39afbd2..c8688cc2 100644 --- a/silkworm/node/db/tables.hpp +++ b/silkworm/node/db/tables.hpp @@ -377,6 +377,9 @@ inline constexpr db::MapConfig kCumulativeGasIndex{kCumulativeGasIndexName}; inline constexpr const char* kRuntimeStatesName{"RuntimeStates"}; inline constexpr db::MapConfig kRuntimeStates{kRuntimeStatesName}; +inline constexpr const char* kConsensusParametersName{"ConsensusParameters"}; +inline constexpr db::MapConfig kConsensusParameters{kConsensusParametersName}; + inline constexpr db::MapConfig kChainDataTables[]{ kAccountChangeSet, kAccountHistory, @@ -422,6 +425,7 @@ inline constexpr db::MapConfig kChainDataTables[]{ kTrieOfStorage, kTxLookup, kRuntimeStates, + kConsensusParameters, }; //! \brief Ensures all defined tables are present in db with consistent flags. Should a table not exist it gets created From 660190a793ee611639bedd832d4d2eb06c7d111c Mon Sep 17 00:00:00 2001 From: yarkin Date: Sun, 4 Feb 2024 17:54:59 +0800 Subject: [PATCH 2/7] Add tests and config cmake. --- CMakeLists.txt | 1 + eosevm/CMakeLists.txt | 35 ++++++++++++++++++++ eosevm/consensus_parameters.cpp | 6 ++++ eosevm/consensus_parameters.hpp | 12 +++---- silkworm/node/CMakeLists.txt | 1 + silkworm/node/db/access_layer_test.cpp | 44 ++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 eosevm/CMakeLists.txt create mode 100644 eosevm/consensus_parameters.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8d5ac0ad..37ab7848 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,6 +92,7 @@ endif() # Silkworm itself add_subdirectory(silkworm) +add_subdirectory(eosevm) if(NOT SILKWORM_HAS_PARENT) add_subdirectory(cmd) diff --git a/eosevm/CMakeLists.txt b/eosevm/CMakeLists.txt new file mode 100644 index 00000000..28516b6f --- /dev/null +++ b/eosevm/CMakeLists.txt @@ -0,0 +1,35 @@ + +find_package(Microsoft.GSL REQUIRED) +find_package(nlohmann_json REQUIRED) +find_package(tl-expected REQUIRED) + +if(MSVC) + add_compile_options(/EHsc) +else() + add_compile_options(-fno-exceptions) +endif() + +file( + GLOB_RECURSE + EOS_EVM_SRC + CONFIGURE_DEPENDS + "*.cpp" + "*.hpp" + "*.c" + "*.h" +) +list(FILTER EOS_EVM_SRC EXCLUDE REGEX "_test\\.cpp$") +list(FILTER EOS_EVM_SRC EXCLUDE REGEX "_benchmark\\.cpp$") + +add_library(eos_evm ${EOS_EVM_SRC}) +target_include_directories(eos_evm PUBLIC ${SILKWORM_MAIN_DIR}) + +set(EOS_EVM_PUBLIC_LIBS + intx::intx + nlohmann_json::nlohmann_json +) + +target_link_libraries( + eos_evm + PUBLIC ${EOS_EVM_PUBLIC_LIBS} +) diff --git a/eosevm/consensus_parameters.cpp b/eosevm/consensus_parameters.cpp new file mode 100644 index 00000000..2d37fc99 --- /dev/null +++ b/eosevm/consensus_parameters.cpp @@ -0,0 +1,6 @@ +#include "consensus_parameters.hpp" + +namespace eosevm { +bool operator==(const eosevm::GasFeeParameters& a, const eosevm::GasFeeParameters& b) { return a.to_json() == b.to_json(); } +bool operator==(const eosevm::ConsensusParameters& a, const eosevm::ConsensusParameters& b) { return a.to_json() == b.to_json(); } +} // namespace eosevm diff --git a/eosevm/consensus_parameters.hpp b/eosevm/consensus_parameters.hpp index 1e03b987..1bb4e6ea 100644 --- a/eosevm/consensus_parameters.hpp +++ b/eosevm/consensus_parameters.hpp @@ -1,10 +1,7 @@ #pragma once #include -#include #include -#include -#include #include #include @@ -13,9 +10,6 @@ #include #endif -#include -#include -#include namespace eosevm { @@ -68,7 +62,7 @@ struct GasFeeParameters { #endif - friend bool operator==(const GasFeeParameters&, const GasFeeParameters&); + friend bool operator==(const GasFeeParameters&, const GasFeeParameters&); }; struct ConsensusParameters { @@ -110,5 +104,7 @@ struct ConsensusParameters { #endif friend bool operator==(const ConsensusParameters&, const ConsensusParameters&); + }; -} // namespace eosevm \ No newline at end of file + +} // namespace eosevm diff --git a/silkworm/node/CMakeLists.txt b/silkworm/node/CMakeLists.txt index adb2cac0..f36efc26 100644 --- a/silkworm/node/CMakeLists.txt +++ b/silkworm/node/CMakeLists.txt @@ -87,6 +87,7 @@ endif() target_include_directories(silkworm_node PUBLIC "${SILKWORM_MAIN_DIR}") set(SILKWORM_NODE_PUBLIC_LIBS + eos_evm silkworm_core silkworm_infra silkworm_sentry diff --git a/silkworm/node/db/access_layer_test.cpp b/silkworm/node/db/access_layer_test.cpp index 0fa09055..74ded4b1 100644 --- a/silkworm/node/db/access_layer_test.cpp +++ b/silkworm/node/db/access_layer_test.cpp @@ -911,4 +911,48 @@ TEST_CASE("RuntimeStates_bytes") { CHECK(read_runtime_states_bytes(txn, RuntimeState(1)) == value1); } +TEST_CASE("ConsensusParameters") { + test::Context context; + auto& txn{context.rw_txn()}; + + constexpr eosevm::ConsensusParameters value1{ + .min_gas_price = 1, + .gas_fee_parameters = eosevm::GasFeeParameters{ + .gas_txnewaccount = 1, + .gas_newaccount = 1, + .gas_txcreate = 1, + .gas_codedeposit = 1, + .gas_sset = 1 + } + }; + + constexpr eosevm::ConsensusParameters value2{ + .min_gas_price = 2, + .gas_fee_parameters = eosevm::GasFeeParameters{ + .gas_txnewaccount = 2, + .gas_newaccount = 2, + .gas_txcreate = 2, + .gas_codedeposit = 2, + .gas_sset = 2, + }, + }; + + CHECK(read_consensus_parameters(txn, 0) == std::nullopt); + + update_consensus_parameters(txn, 0, value1 ); + CHECK(read_consensus_parameters(txn, 0) == value1); + + update_consensus_parameters(txn, 0, value2 ); + CHECK(read_consensus_parameters(txn, 0) == value2); + + CHECK(read_consensus_parameters(txn, 1) == std::nullopt); + + update_consensus_parameters(txn, 1, value2 ); + CHECK(read_consensus_parameters(txn, 1) == value2); + + update_consensus_parameters(txn, 1, value1 ); + CHECK(read_consensus_parameters(txn, 1) == value1); +} + + } // namespace silkworm::db From 14ee5d25f2a71c9265faf8f772770c7938dcca16 Mon Sep 17 00:00:00 2001 From: yarkin Date: Mon, 5 Feb 2024 11:47:54 +0800 Subject: [PATCH 3/7] Add consensus_parameter_index field to block --- silkworm/core/types/block.cpp | 17 ++++++++- silkworm/core/types/block.hpp | 3 ++ silkworm/core/types/block_test.cpp | 19 ++++++++++ silkworm/node/db/util_test.cpp | 1 + silkworm/silkrpc/json/types.cpp | 5 +++ silkworm/silkrpc/json/types_test.cpp | 55 +++++++++++++++++++++++++++- 6 files changed, 98 insertions(+), 2 deletions(-) diff --git a/silkworm/core/types/block.cpp b/silkworm/core/types/block.cpp index e28d1e65..ad48ab96 100644 --- a/silkworm/core/types/block.cpp +++ b/silkworm/core/types/block.cpp @@ -29,7 +29,7 @@ bool operator==(const BlockHeader& a, const BlockHeader& b) { a.receipts_root == b.receipts_root && a.logs_bloom == b.logs_bloom && a.difficulty == b.difficulty && a.number == b.number && a.gas_limit == b.gas_limit && a.gas_used == b.gas_used && a.timestamp == b.timestamp && a.extra_data == b.extra_data && a.prev_randao == b.prev_randao && - a.nonce == b.nonce && a.base_fee_per_gas == b.base_fee_per_gas; + a.nonce == b.nonce && a.base_fee_per_gas == b.base_fee_per_gas && a.consensus_parameter_index == b.consensus_parameter_index; } bool operator==(const BlockBody& a, const BlockBody& b) { @@ -110,6 +110,9 @@ namespace rlp { rlp_head.payload_length += kHashLength + 1; // prev_randao rlp_head.payload_length += 8 + 1; // nonce } + if (header.consensus_parameter_index) { + rlp_head.payload_length += length(*header.consensus_parameter_index); + } if (header.base_fee_per_gas) { rlp_head.payload_length += length(*header.base_fee_per_gas); } @@ -155,6 +158,9 @@ namespace rlp { encode(to, header.prev_randao); encode(to, header.nonce); } + if (header.consensus_parameter_index) { + encode(to, *header.consensus_parameter_index); + } if (header.base_fee_per_gas) { encode(to, *header.base_fee_per_gas); } @@ -202,6 +208,15 @@ namespace rlp { return res; } + if (from.length() > leftover) { + to.consensus_parameter_index = 0; + if (DecodingResult res{decode(from, *to.consensus_parameter_index, Leftover::kAllow)}; !res) { + return res; + } + } else { + to.consensus_parameter_index = std::nullopt; + } + if (from.length() > leftover) { to.base_fee_per_gas = 0; if (DecodingResult res{decode(from, *to.base_fee_per_gas, Leftover::kAllow)}; !res) { diff --git a/silkworm/core/types/block.hpp b/silkworm/core/types/block.hpp index 74e97a96..67757f9c 100644 --- a/silkworm/core/types/block.hpp +++ b/silkworm/core/types/block.hpp @@ -70,6 +70,9 @@ struct BlockHeader { evmc::bytes32 prev_randao{}; // mix hash prior to EIP-4399 NonceType nonce{}; + // EOS-EVM + std::optional consensus_parameter_index{std::nullopt}; + std::optional base_fee_per_gas{std::nullopt}; // EIP-1559 std::optional withdrawals_root{std::nullopt}; // EIP-4895 diff --git a/silkworm/core/types/block_test.cpp b/silkworm/core/types/block_test.cpp index 674ed942..7b4c9843 100644 --- a/silkworm/core/types/block_test.cpp +++ b/silkworm/core/types/block_test.cpp @@ -172,9 +172,27 @@ TEST_CASE("EIP-2718 Block RLP") { CHECK(block.transactions[1].access_list.size() == 1); } +TEST_CASE("Consensus Parameters Header RLP") { + BlockHeader h{ + .number = 13'500'000, + .consensus_parameter_index= 1234, + }; + + Bytes rlp; + rlp::encode(rlp, h); + + ByteView view{rlp}; + BlockHeader decoded; + REQUIRE(rlp::decode(view, decoded)); + + CHECK(view.empty()); + CHECK(decoded == h); +} + TEST_CASE("EIP-1559 Header RLP") { BlockHeader h{ .number = 13'500'000, + .consensus_parameter_index= 0, .base_fee_per_gas = 2'700'000'000, }; @@ -194,6 +212,7 @@ TEST_CASE("EIP-4844 Header RLP") { .ommers_hash = kEmptyListHash, .number = 17'000'000, .prev_randao = 0xd01681d2b3acdebff0288a02a1648b3910500961982d5ecdbef064af7c34090b_bytes32, + .consensus_parameter_index= 0, .base_fee_per_gas = 2'700'000'000, .withdrawals_root = 0xbac9348581b0ee244d6eb61076b63c4e4afa70430c804ab0e6a0ab69d9a9d323_bytes32, .data_gas_used = 456, diff --git a/silkworm/node/db/util_test.cpp b/silkworm/node/db/util_test.cpp index 0d28ec8f..38a4c24c 100644 --- a/silkworm/node/db/util_test.cpp +++ b/silkworm/node/db/util_test.cpp @@ -36,6 +36,7 @@ TEST_CASE("BlockBodyForStorage encoding") { .extra_data = *from_hex("0001FF0100"), .prev_randao = 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, .nonce = {0, 0, 0, 0, 0, 0, 0, 255}, + .consensus_parameter_index = 0x1234, .base_fee_per_gas = 0x244428, }; diff --git a/silkworm/silkrpc/json/types.cpp b/silkworm/silkrpc/json/types.cpp index 34c7776c..2359b6f1 100644 --- a/silkworm/silkrpc/json/types.cpp +++ b/silkworm/silkrpc/json/types.cpp @@ -211,6 +211,11 @@ void to_json(nlohmann::json& json, const BlockHeader& header) { json["gasLimit"] = rpc::to_quantity(header.gas_limit); json["gasUsed"] = rpc::to_quantity(header.gas_used); json["timestamp"] = rpc::to_quantity(header.timestamp); + if (header.consensus_parameter_index.has_value()) { + json["consensusParameterIndex"] = rpc::to_quantity(header.consensus_parameter_index.value_or(0)); + } else { + json["consensusParameterIndex"] = nullptr; + } if (header.base_fee_per_gas.has_value()) { json["baseFeePerGas"] = rpc::to_quantity(header.base_fee_per_gas.value_or(0)); } else { diff --git a/silkworm/silkrpc/json/types_test.cpp b/silkworm/silkrpc/json/types_test.cpp index 593f75d0..749f9d6d 100644 --- a/silkworm/silkrpc/json/types_test.cpp +++ b/silkworm/silkrpc/json/types_test.cpp @@ -164,6 +164,7 @@ TEST_CASE("serialize empty block header", "[silkrpc][to_json]") { nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":null, + "consensusParameterIndex":null, "hash": "0xc3bd2d00745c03048a5616146a96f5ff78e54efb9e5b04af208cdaff6f3830ee", "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000", @@ -210,6 +211,7 @@ TEST_CASE("serialize block header", "[silkrpc][to_json]") { nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":null, + "consensusParameterIndex":null, "hash": "0x5e053b099d472a3fc02394243961937ffa008bad0daa81a984a0830ba0beee01", "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", @@ -236,6 +238,55 @@ TEST_CASE("serialize block header", "[silkrpc][to_json]") { })"_json); } +TEST_CASE("serialize block header with consensus parameter index", "[silkrpc][to_json]") { + silkworm::BlockHeader header{ + 0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c_bytes32, + 0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d_bytes32, + 0x0715a7794a1dc8e42615f059dd6e406a6594651a_address, + 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126d_bytes32, + 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126e_bytes32, + 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126f_bytes32, + silkworm::Bloom{}, + intx::uint256{0}, + uint64_t(5), + uint64_t(1000000), + uint64_t(1000000), + uint64_t(5405021), + *silkworm::from_hex("0001FF0100"), // extradata + 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, // mixhash + {1, 2, 3, 4, 5, 6, 7, 8}, // nonce + std::optional(1001), // consensus_parameter_index // base_fee_per_gas + }; + nlohmann::json j = header; + CHECK(j == R"({ + "baseFeePerGas":null, + "hash": "0x74b164b2a76408c5c0a69c99325438a90ece1353817ef6e239fc0dcb7ac76d09", + "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", + "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", + "miner":"0x0715a7794a1dc8e42615f059dd6e406a6594651a", + "stateRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126d", + "transactionsRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126e", + "receiptsRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126f", + "logsBloom":"0x000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(000000000000000000000000000000000000000000000000000000000000000000000000)" + R"(00000000000000000000000000000000000000000000000000000000000000000000000000000000", + "difficulty":"0x0", + "number":"0x5", + "gasLimit":"0xf4240", + "gasUsed":"0xf4240", + "timestamp":"0x52795d", + "extraData":"0x0001ff0100", + "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000001", + "nonce":"0x0102030405060708", + "consensusParameterIndex":"0x3e9", + "withdrawalsRoot":null + })"_json); +} + TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { silkworm::BlockHeader header{ 0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c_bytes32, @@ -253,12 +304,13 @@ TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { *silkworm::from_hex("0001FF0100"), // extradata 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, // mixhash {1, 2, 3, 4, 5, 6, 7, 8}, // nonce + std::optional(1001), // consensus_parameter_index std::optional(1000), // base_fee_per_gas }; nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":"0x3e8", - "hash": "0x5e3a9484b3ee70cc9ae7673051efd0369cfa4126430075921c70255cbdefbe6", + "hash": "0xa88494b78d8cb3ad596637990fa04fd4e9068a9271f044e4d3cdb313a24973b9", "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", "miner":"0x0715a7794a1dc8e42615f059dd6e406a6594651a", @@ -280,6 +332,7 @@ TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { "extraData":"0x0001ff0100", "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000001", "nonce":"0x0102030405060708", + "consensusParameterIndex":"0x3e9", "baseFeePerGas":"0x3e8", "withdrawalsRoot":null })"_json); From eb3f48270070ec05089a21c1458fab7a4c0aaa81 Mon Sep 17 00:00:00 2001 From: yarkin Date: Fri, 9 Feb 2024 01:15:15 +0800 Subject: [PATCH 4/7] Move consensus index from header to body. --- eosevm/consensus_parameters.hpp | 6 +-- silkworm/core/types/block.cpp | 43 +++++++++++++--------- silkworm/core/types/block.hpp | 9 +++-- silkworm/core/types/block_test.cpp | 19 ---------- silkworm/node/db/util_test.cpp | 1 - silkworm/silkrpc/json/types.cpp | 5 --- silkworm/silkrpc/json/types_test.cpp | 55 +--------------------------- 7 files changed, 36 insertions(+), 102 deletions(-) diff --git a/eosevm/consensus_parameters.hpp b/eosevm/consensus_parameters.hpp index 1bb4e6ea..7abb068d 100644 --- a/eosevm/consensus_parameters.hpp +++ b/eosevm/consensus_parameters.hpp @@ -66,7 +66,7 @@ struct GasFeeParameters { }; struct ConsensusParameters { - std::optional min_gas_price; + std::optional min_gas_price; std::optional gas_fee_parameters; //! \brief Return the JSON representation of this object @@ -75,7 +75,7 @@ struct ConsensusParameters { nlohmann::json ret; if (min_gas_price) { - ret["minGasPrice"] = intx::to_string(min_gas_price.value()); + ret["minGasPrice"] = min_gas_price.value(); } if (gas_fee_parameters) { ret["gasFeeParameters"] = gas_fee_parameters.value().to_json(); @@ -91,7 +91,7 @@ struct ConsensusParameters { static std::optional from_json(const nlohmann::json& json) noexcept { ConsensusParameters config{}; if (json.contains("minGasPrice")) { - config.min_gas_price = intx::from_string(json["minGasPrice"].get()); + config.min_gas_price = json["minGasPrice"].get(); } if (json.contains("gasFeeParameters")) { diff --git a/silkworm/core/types/block.cpp b/silkworm/core/types/block.cpp index ad48ab96..08b6139f 100644 --- a/silkworm/core/types/block.cpp +++ b/silkworm/core/types/block.cpp @@ -29,11 +29,11 @@ bool operator==(const BlockHeader& a, const BlockHeader& b) { a.receipts_root == b.receipts_root && a.logs_bloom == b.logs_bloom && a.difficulty == b.difficulty && a.number == b.number && a.gas_limit == b.gas_limit && a.gas_used == b.gas_used && a.timestamp == b.timestamp && a.extra_data == b.extra_data && a.prev_randao == b.prev_randao && - a.nonce == b.nonce && a.base_fee_per_gas == b.base_fee_per_gas && a.consensus_parameter_index == b.consensus_parameter_index; + a.nonce == b.nonce && a.base_fee_per_gas == b.base_fee_per_gas; } bool operator==(const BlockBody& a, const BlockBody& b) { - return a.transactions == b.transactions && a.ommers == b.ommers; + return a.transactions == b.transactions && a.ommers == b.ommers && a.consensus_parameter_index == b.consensus_parameter_index; } BlockNum height(const BlockId& b) { return b.number; } @@ -110,9 +110,6 @@ namespace rlp { rlp_head.payload_length += kHashLength + 1; // prev_randao rlp_head.payload_length += 8 + 1; // nonce } - if (header.consensus_parameter_index) { - rlp_head.payload_length += length(*header.consensus_parameter_index); - } if (header.base_fee_per_gas) { rlp_head.payload_length += length(*header.base_fee_per_gas); } @@ -158,9 +155,6 @@ namespace rlp { encode(to, header.prev_randao); encode(to, header.nonce); } - if (header.consensus_parameter_index) { - encode(to, *header.consensus_parameter_index); - } if (header.base_fee_per_gas) { encode(to, *header.base_fee_per_gas); } @@ -208,15 +202,6 @@ namespace rlp { return res; } - if (from.length() > leftover) { - to.consensus_parameter_index = 0; - if (DecodingResult res{decode(from, *to.consensus_parameter_index, Leftover::kAllow)}; !res) { - return res; - } - } else { - to.consensus_parameter_index = std::nullopt; - } - if (from.length() > leftover) { to.base_fee_per_gas = 0; if (DecodingResult res{decode(from, *to.base_fee_per_gas, Leftover::kAllow)}; !res) { @@ -271,6 +256,9 @@ 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); } @@ -293,6 +281,15 @@ namespace rlp { return res; } + to.consensus_parameter_index = std::nullopt; + if (from.length() > leftover) { + uint64_t 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,6 +322,15 @@ namespace rlp { return res; } + to.consensus_parameter_index = std::nullopt; + if (from.length() > leftover) { + uint64_t 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; @@ -356,6 +362,9 @@ 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 67757f9c..3472d66a 100644 --- a/silkworm/core/types/block.hpp +++ b/silkworm/core/types/block.hpp @@ -32,6 +32,8 @@ #include #include +#include + namespace silkworm { using TotalDifficulty = intx::uint256; @@ -70,9 +72,6 @@ struct BlockHeader { evmc::bytes32 prev_randao{}; // mix hash prior to EIP-4399 NonceType nonce{}; - // EOS-EVM - std::optional consensus_parameter_index{std::nullopt}; - std::optional base_fee_per_gas{std::nullopt}; // EIP-1559 std::optional withdrawals_root{std::nullopt}; // EIP-4895 @@ -97,6 +96,9 @@ struct BlockBody { std::vector ommers; std::optional> withdrawals{std::nullopt}; + // EOS-EVM + std::optional consensus_parameter_index{std::nullopt}; + friend bool operator==(const BlockBody&, const BlockBody&); }; @@ -104,6 +106,7 @@ struct Block : public BlockBody { BlockHeader header; bool irreversible{false}; + std::optional consensus_parameters_cache; void recover_senders(); }; diff --git a/silkworm/core/types/block_test.cpp b/silkworm/core/types/block_test.cpp index 7b4c9843..674ed942 100644 --- a/silkworm/core/types/block_test.cpp +++ b/silkworm/core/types/block_test.cpp @@ -172,27 +172,9 @@ TEST_CASE("EIP-2718 Block RLP") { CHECK(block.transactions[1].access_list.size() == 1); } -TEST_CASE("Consensus Parameters Header RLP") { - BlockHeader h{ - .number = 13'500'000, - .consensus_parameter_index= 1234, - }; - - Bytes rlp; - rlp::encode(rlp, h); - - ByteView view{rlp}; - BlockHeader decoded; - REQUIRE(rlp::decode(view, decoded)); - - CHECK(view.empty()); - CHECK(decoded == h); -} - TEST_CASE("EIP-1559 Header RLP") { BlockHeader h{ .number = 13'500'000, - .consensus_parameter_index= 0, .base_fee_per_gas = 2'700'000'000, }; @@ -212,7 +194,6 @@ TEST_CASE("EIP-4844 Header RLP") { .ommers_hash = kEmptyListHash, .number = 17'000'000, .prev_randao = 0xd01681d2b3acdebff0288a02a1648b3910500961982d5ecdbef064af7c34090b_bytes32, - .consensus_parameter_index= 0, .base_fee_per_gas = 2'700'000'000, .withdrawals_root = 0xbac9348581b0ee244d6eb61076b63c4e4afa70430c804ab0e6a0ab69d9a9d323_bytes32, .data_gas_used = 456, diff --git a/silkworm/node/db/util_test.cpp b/silkworm/node/db/util_test.cpp index 38a4c24c..0d28ec8f 100644 --- a/silkworm/node/db/util_test.cpp +++ b/silkworm/node/db/util_test.cpp @@ -36,7 +36,6 @@ TEST_CASE("BlockBodyForStorage encoding") { .extra_data = *from_hex("0001FF0100"), .prev_randao = 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, .nonce = {0, 0, 0, 0, 0, 0, 0, 255}, - .consensus_parameter_index = 0x1234, .base_fee_per_gas = 0x244428, }; diff --git a/silkworm/silkrpc/json/types.cpp b/silkworm/silkrpc/json/types.cpp index 2359b6f1..34c7776c 100644 --- a/silkworm/silkrpc/json/types.cpp +++ b/silkworm/silkrpc/json/types.cpp @@ -211,11 +211,6 @@ void to_json(nlohmann::json& json, const BlockHeader& header) { json["gasLimit"] = rpc::to_quantity(header.gas_limit); json["gasUsed"] = rpc::to_quantity(header.gas_used); json["timestamp"] = rpc::to_quantity(header.timestamp); - if (header.consensus_parameter_index.has_value()) { - json["consensusParameterIndex"] = rpc::to_quantity(header.consensus_parameter_index.value_or(0)); - } else { - json["consensusParameterIndex"] = nullptr; - } if (header.base_fee_per_gas.has_value()) { json["baseFeePerGas"] = rpc::to_quantity(header.base_fee_per_gas.value_or(0)); } else { diff --git a/silkworm/silkrpc/json/types_test.cpp b/silkworm/silkrpc/json/types_test.cpp index 749f9d6d..593f75d0 100644 --- a/silkworm/silkrpc/json/types_test.cpp +++ b/silkworm/silkrpc/json/types_test.cpp @@ -164,7 +164,6 @@ TEST_CASE("serialize empty block header", "[silkrpc][to_json]") { nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":null, - "consensusParameterIndex":null, "hash": "0xc3bd2d00745c03048a5616146a96f5ff78e54efb9e5b04af208cdaff6f3830ee", "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", "sha3Uncles":"0x0000000000000000000000000000000000000000000000000000000000000000", @@ -211,7 +210,6 @@ TEST_CASE("serialize block header", "[silkrpc][to_json]") { nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":null, - "consensusParameterIndex":null, "hash": "0x5e053b099d472a3fc02394243961937ffa008bad0daa81a984a0830ba0beee01", "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", @@ -238,55 +236,6 @@ TEST_CASE("serialize block header", "[silkrpc][to_json]") { })"_json); } -TEST_CASE("serialize block header with consensus parameter index", "[silkrpc][to_json]") { - silkworm::BlockHeader header{ - 0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c_bytes32, - 0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d_bytes32, - 0x0715a7794a1dc8e42615f059dd6e406a6594651a_address, - 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126d_bytes32, - 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126e_bytes32, - 0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126f_bytes32, - silkworm::Bloom{}, - intx::uint256{0}, - uint64_t(5), - uint64_t(1000000), - uint64_t(1000000), - uint64_t(5405021), - *silkworm::from_hex("0001FF0100"), // extradata - 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, // mixhash - {1, 2, 3, 4, 5, 6, 7, 8}, // nonce - std::optional(1001), // consensus_parameter_index // base_fee_per_gas - }; - nlohmann::json j = header; - CHECK(j == R"({ - "baseFeePerGas":null, - "hash": "0x74b164b2a76408c5c0a69c99325438a90ece1353817ef6e239fc0dcb7ac76d09", - "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", - "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", - "miner":"0x0715a7794a1dc8e42615f059dd6e406a6594651a", - "stateRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126d", - "transactionsRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126e", - "receiptsRoot":"0xb02a3b0ee16c858afaa34bcd6770b3c20ee56aa2f75858733eb0e927b5b7126f", - "logsBloom":"0x000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(000000000000000000000000000000000000000000000000000000000000000000000000)" - R"(00000000000000000000000000000000000000000000000000000000000000000000000000000000", - "difficulty":"0x0", - "number":"0x5", - "gasLimit":"0xf4240", - "gasUsed":"0xf4240", - "timestamp":"0x52795d", - "extraData":"0x0001ff0100", - "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000001", - "nonce":"0x0102030405060708", - "consensusParameterIndex":"0x3e9", - "withdrawalsRoot":null - })"_json); -} - TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { silkworm::BlockHeader header{ 0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c_bytes32, @@ -304,13 +253,12 @@ TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { *silkworm::from_hex("0001FF0100"), // extradata 0x0000000000000000000000000000000000000000000000000000000000000001_bytes32, // mixhash {1, 2, 3, 4, 5, 6, 7, 8}, // nonce - std::optional(1001), // consensus_parameter_index std::optional(1000), // base_fee_per_gas }; nlohmann::json j = header; CHECK(j == R"({ "baseFeePerGas":"0x3e8", - "hash": "0xa88494b78d8cb3ad596637990fa04fd4e9068a9271f044e4d3cdb313a24973b9", + "hash": "0x5e3a9484b3ee70cc9ae7673051efd0369cfa4126430075921c70255cbdefbe6", "parentHash":"0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c", "sha3Uncles":"0x474f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126d", "miner":"0x0715a7794a1dc8e42615f059dd6e406a6594651a", @@ -332,7 +280,6 @@ TEST_CASE("serialize block header with baseFeePerGas", "[silkrpc][to_json]") { "extraData":"0x0001ff0100", "mixHash":"0x0000000000000000000000000000000000000000000000000000000000000001", "nonce":"0x0102030405060708", - "consensusParameterIndex":"0x3e9", "baseFeePerGas":"0x3e8", "withdrawalsRoot":null })"_json); From 9eab6dd9af40a27aafb396a0fcd7c9bd9076881b Mon Sep 17 00:00:00 2001 From: yarkin Date: Fri, 9 Feb 2024 09:19:45 +0800 Subject: [PATCH 5/7] Add missing parts and tests. --- silkworm/core/types/block_test.cpp | 2 ++ silkworm/node/db/access_layer.cpp | 2 ++ silkworm/node/db/access_layer_test.cpp | 3 +++ silkworm/node/db/util.cpp | 15 +++++++++++++++ silkworm/node/db/util.hpp | 2 ++ silkworm/node/db/util_test.cpp | 9 ++++++++- 6 files changed, 32 insertions(+), 1 deletion(-) diff --git a/silkworm/core/types/block_test.cpp b/silkworm/core/types/block_test.cpp index 674ed942..bc86ddb3 100644 --- a/silkworm/core/types/block_test.cpp +++ b/silkworm/core/types/block_test.cpp @@ -104,6 +104,8 @@ TEST_CASE("BlockBody RLP 2") { body.ommers[0].prev_randao = 0xf0a53dfdd6c2f2a661e718ef29092de60d81d45f84044bec7bf4b36630b2bc08_bytes32; body.ommers[0].nonce[7] = 35; + body.consensus_parameter_index = 1234; + Bytes rlp{}; rlp::encode(rlp, body); diff --git a/silkworm/node/db/access_layer.cpp b/silkworm/node/db/access_layer.cpp index 6a8dda69..c1a18ba4 100644 --- a/silkworm/node/db/access_layer.cpp +++ b/silkworm/node/db/access_layer.cpp @@ -443,6 +443,7 @@ bool read_body(ROTxn& txn, const Bytes& key, bool read_senders, BlockBody& out) if (!out.transactions.empty() && read_senders) { parse_senders(txn, key, out.transactions); } + out.consensus_parameter_index = body.consensus_parameter_index; return true; } @@ -498,6 +499,7 @@ void write_body(RWTxn& txn, const BlockBody& body, const uint8_t (&hash)[kHashLe body_for_storage.txn_count = body.transactions.size(); body_for_storage.base_txn_id = increment_map_sequence(txn, table::kBlockTransactions.name, body_for_storage.txn_count); + body_for_storage.consensus_parameter_index = body.consensus_parameter_index; Bytes value{body_for_storage.encode()}; auto key{db::block_key(number, hash)}; diff --git a/silkworm/node/db/access_layer_test.cpp b/silkworm/node/db/access_layer_test.cpp index 74ded4b1..c67c76c7 100644 --- a/silkworm/node/db/access_layer_test.cpp +++ b/silkworm/node/db/access_layer_test.cpp @@ -81,6 +81,7 @@ static BlockBody sample_block_body() { body.ommers[0].prev_randao = 0xf0a53dfdd6c2f2a661e718ef29092de60d81d45f84044bec7bf4b36630b2bc08_bytes32; body.ommers[0].nonce[7] = 35; + body.consensus_parameter_index = 1234; return body; } @@ -527,6 +528,8 @@ TEST_CASE("Headers and bodies") { auto [b, h] = split_block_key(key); REQUIRE(b == header.number); REQUIRE(h == header.hash()); + + CHECK(block.consensus_parameter_index == 1234); } SECTION("process_blocks_at_height") { diff --git a/silkworm/node/db/util.cpp b/silkworm/node/db/util.cpp index 2758728a..fa0cbc73 100644 --- a/silkworm/node/db/util.cpp +++ b/silkworm/node/db/util.cpp @@ -154,6 +154,9 @@ 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); } @@ -163,6 +166,9 @@ 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); } @@ -187,6 +193,15 @@ namespace detail { return res; } + to.consensus_parameter_index = std::nullopt; + if (from.length() > leftover) { + uint64_t 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 ff63210d..89f17462 100644 --- a/silkworm/node/db/util.hpp +++ b/silkworm/node/db/util.hpp @@ -131,6 +131,8 @@ 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 0d28ec8f..82dce395 100644 --- a/silkworm/node/db/util_test.cpp +++ b/silkworm/node/db/util_test.cpp @@ -39,13 +39,20 @@ TEST_CASE("BlockBodyForStorage encoding") { .base_fee_per_gas = 0x244428, }; - // No withdrawals + // No consensus_parameter_index and withdraws BlockBodyForStorage body{.base_txn_id = 15, .txn_count = 3, .ommers = {header}}; Bytes encoded{body.encode()}; ByteView view{encoded}; BlockBodyForStorage decoded{decode_stored_block_body(view)}; CHECK(decoded == body); + // No withdrawals + body.consensus_parameter_index = 1234; + encoded = body.encode(); + view = encoded; + decoded = decode_stored_block_body(view); + CHECK(decoded == body); + // With withdrawals body.ommers.clear(); // no uncles after The Merge body.withdrawals = {{ From 621ab33c1ca95ffd2f81479e231e9347e41e83fc Mon Sep 17 00:00:00 2001 From: yarkin Date: Thu, 22 Feb 2024 13:01:10 +0800 Subject: [PATCH 6/7] Fix error and make changes according to reviews. --- eosevm/consensus_parameters.cpp | 9 +++++++-- silkworm/core/types/block.cpp | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/eosevm/consensus_parameters.cpp b/eosevm/consensus_parameters.cpp index 2d37fc99..7b811796 100644 --- a/eosevm/consensus_parameters.cpp +++ b/eosevm/consensus_parameters.cpp @@ -1,6 +1,11 @@ #include "consensus_parameters.hpp" namespace eosevm { -bool operator==(const eosevm::GasFeeParameters& a, const eosevm::GasFeeParameters& b) { return a.to_json() == b.to_json(); } -bool operator==(const eosevm::ConsensusParameters& a, const eosevm::ConsensusParameters& b) { return a.to_json() == b.to_json(); } +bool operator==(const eosevm::GasFeeParameters& a, const eosevm::GasFeeParameters& b) { + return a.gas_codedeposit == b.gas_codedeposit && a.gas_newaccount == b.gas_newaccount && + a.gas_sset == b.gas_sset && a.gas_txcreate == b.gas_txcreate && a.gas_txnewaccount == b.gas_txnewaccount; +} + +bool operator==(const eosevm::ConsensusParameters& a, const eosevm::ConsensusParameters& b) { + return a.min_gas_price == b.min_gas_price && a.gas_fee_parameters == b.gas_fee_parameters; } } // namespace eosevm diff --git a/silkworm/core/types/block.cpp b/silkworm/core/types/block.cpp index 08b6139f..fa686d70 100644 --- a/silkworm/core/types/block.cpp +++ b/silkworm/core/types/block.cpp @@ -241,6 +241,9 @@ 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); } From 19a18d515613d935c3938560bd7e13dc2bc287a3 Mon Sep 17 00:00:00 2001 From: yarkin Date: Mon, 26 Feb 2024 15:39:55 +0800 Subject: [PATCH 7/7] Do not use json to encode for better performance. --- eosevm/CMakeLists.txt | 2 + eosevm/consensus_parameters.cpp | 69 ++++++++++++++++++++++++++- eosevm/consensus_parameters.hpp | 77 +++++-------------------------- silkworm/node/db/access_layer.cpp | 9 ++-- 4 files changed, 85 insertions(+), 72 deletions(-) diff --git a/eosevm/CMakeLists.txt b/eosevm/CMakeLists.txt index 28516b6f..912b68d0 100644 --- a/eosevm/CMakeLists.txt +++ b/eosevm/CMakeLists.txt @@ -26,6 +26,8 @@ target_include_directories(eos_evm PUBLIC ${SILKWORM_MAIN_DIR}) set(EOS_EVM_PUBLIC_LIBS intx::intx + evmc + tl::expected nlohmann_json::nlohmann_json ) diff --git a/eosevm/consensus_parameters.cpp b/eosevm/consensus_parameters.cpp index 7b811796..86c30db1 100644 --- a/eosevm/consensus_parameters.cpp +++ b/eosevm/consensus_parameters.cpp @@ -1,5 +1,10 @@ #include "consensus_parameters.hpp" +#if not defined(ANTELOPE) +#include +#include +#endif + namespace eosevm { bool operator==(const eosevm::GasFeeParameters& a, const eosevm::GasFeeParameters& b) { return a.gas_codedeposit == b.gas_codedeposit && a.gas_newaccount == b.gas_newaccount && @@ -8,4 +13,66 @@ bool operator==(const eosevm::GasFeeParameters& a, const eosevm::GasFeeParameter bool operator==(const eosevm::ConsensusParameters& a, const eosevm::ConsensusParameters& b) { return a.min_gas_price == b.min_gas_price && a.gas_fee_parameters == b.gas_fee_parameters; } -} // namespace eosevm + + +#if not defined(ANTELOPE) +[[nodiscard]] silkworm::Bytes GasFeeParameters::encode() const noexcept { + silkworm::Bytes ret(40, '\0'); + silkworm::endian::store_big_u64(&ret[0], gas_txnewaccount); + silkworm::endian::store_big_u64(&ret[8], gas_newaccount); + silkworm::endian::store_big_u64(&ret[16], gas_txcreate); + silkworm::endian::store_big_u64(&ret[24], gas_codedeposit); + silkworm::endian::store_big_u64(&ret[32], gas_sset); + + return ret; +} + +std::optional GasFeeParameters::decode(silkworm::ByteView encoded) noexcept { + SILKWORM_ASSERT(encoded.length() >= 40); + GasFeeParameters feeParams; + feeParams.gas_txnewaccount = silkworm::endian::load_big_u64(&encoded[0]); + feeParams.gas_newaccount = silkworm::endian::load_big_u64(&encoded[8]); + feeParams.gas_txcreate = silkworm::endian::load_big_u64(&encoded[16]); + feeParams.gas_codedeposit = silkworm::endian::load_big_u64(&encoded[24]); + feeParams.gas_sset = silkworm::endian::load_big_u64(&encoded[32]); + + return feeParams; +} +#endif + +#if not defined(ANTELOPE) +[[nodiscard]] silkworm::Bytes ConsensusParameters::encode() const noexcept { + SILKWORM_ASSERT(min_gas_price.has_value()); + SILKWORM_ASSERT(gas_fee_parameters.has_value()); + constexpr size_t size_before_fee_param = 2 * sizeof(uint64_t); + auto value = gas_fee_parameters->encode(); + silkworm::Bytes ret(value.length() + size_before_fee_param, '\0'); + // Always store as latest supported version: currently 0. + silkworm::endian::store_big_u64(&ret[0], 0); + silkworm::endian::store_big_u64(&ret[sizeof(uint64_t)], *min_gas_price); + std::memcpy(&ret[size_before_fee_param], &value[0], value.length()); + return ret; +}; + +std::optional ConsensusParameters::decode(silkworm::ByteView encoded) noexcept { + SILKWORM_ASSERT(encoded.length() > sizeof(uint64_t)); + ConsensusParameters config{}; + const auto version = silkworm::endian::load_big_u64(&encoded[0]); + + // Parse according to version. For now, only 0. + switch (version) { + case 0: { + constexpr size_t size_before_fee_param = 2 * sizeof(uint64_t); + SILKWORM_ASSERT(encoded.length() > size_before_fee_param); + config.min_gas_price = silkworm::endian::load_big_u64(&encoded[sizeof(uint64_t)]); + config.gas_fee_parameters = GasFeeParameters::decode(silkworm::ByteView{&encoded[size_before_fee_param], encoded.length() - size_before_fee_param}); + break; + } + default: SILKWORM_ASSERT(version <= 0); + } + + return config; +} +#endif + +} // namespace eosevm \ No newline at end of file diff --git a/eosevm/consensus_parameters.hpp b/eosevm/consensus_parameters.hpp index 7abb068d..5342bbb9 100644 --- a/eosevm/consensus_parameters.hpp +++ b/eosevm/consensus_parameters.hpp @@ -6,13 +6,16 @@ #include + #if not defined(ANTELOPE) -#include +#include #endif namespace eosevm { +// Note: GasFeeParameters struct is NOT versioned, version will be handled by ConsensusParameters. +// If we want to change this struct, create GasFeeParametersV2 and let ConsensusParameters use it. struct GasFeeParameters { // gas_txnewaccount = account_bytes * gas_per_byte uint64_t gas_txnewaccount; @@ -26,40 +29,11 @@ struct GasFeeParameters { uint64_t gas_sset; #if not defined(ANTELOPE) - [[nodiscard]] nlohmann::json to_json() const noexcept { - nlohmann::json ret; - ret["gasTxnewaccount"] = gas_txnewaccount; - ret["gasNewaccount"] = gas_newaccount; - ret["gasTxcreate"] = gas_txcreate; - ret["gasCodedeposit"] = gas_codedeposit; - ret["gasSset"] = gas_sset; - - return ret; - } - #endif - - //! \brief Try parse a JSON object into strongly typed ChainConfig - //! \remark Should this return std::nullopt the parsing has failed - #if not defined(ANTELOPE) - - static std::optional from_json(const nlohmann::json& json) noexcept { - GasFeeParameters feeParams; - - if (!json.contains("gasTxnewaccount") || !json.contains("gasNewaccount") || !json.contains("gasTxcreate") || - !json.contains("gasCodedeposit") || !json.contains("gasSset")) { - // Faii if any of the parameters are missing. - return std::nullopt; - } - - feeParams.gas_txnewaccount = json["gasTxnewaccount"].get(); - feeParams.gas_newaccount = json["gasNewaccount"].get(); - feeParams.gas_txcreate = json["gasTxcreate"].get(); - feeParams.gas_codedeposit = json["gasCodedeposit"].get(); - feeParams.gas_sset = json["gasSset"].get(); - - return feeParams; - } + // Encode for storage in db. + [[nodiscard]] silkworm::Bytes encode() const noexcept; + // Decode from storage in db. + static std::optional decode(silkworm::ByteView encoded) noexcept; #endif friend bool operator==(const GasFeeParameters&, const GasFeeParameters&); @@ -69,42 +43,15 @@ struct ConsensusParameters { std::optional min_gas_price; std::optional gas_fee_parameters; - //! \brief Return the JSON representation of this object - #if not defined(ANTELOPE) - [[nodiscard]] nlohmann::json to_json() const noexcept { - - nlohmann::json ret; - if (min_gas_price) { - ret["minGasPrice"] = min_gas_price.value(); - } - if (gas_fee_parameters) { - ret["gasFeeParameters"] = gas_fee_parameters.value().to_json(); - } - - return ret; - }; - #endif - - //! \brief Try parse a JSON object into strongly typed ChainConfig - //! \remark Should this return std::nullopt the parsing has failed #if not defined(ANTELOPE) - static std::optional from_json(const nlohmann::json& json) noexcept { - ConsensusParameters config{}; - if (json.contains("minGasPrice")) { - config.min_gas_price = json["minGasPrice"].get(); - } - - if (json.contains("gasFeeParameters")) { - // Can be nullopt if parsing GasFeeParameters failed. - config.gas_fee_parameters = GasFeeParameters::from_json(json["gasFeeParameters"]); - } + // Encode for storage in db. + [[nodiscard]] silkworm::Bytes encode() const noexcept; - return config; - } + // Decode from storage in db. + static std::optional decode(silkworm::ByteView encoded) noexcept; #endif friend bool operator==(const ConsensusParameters&, const ConsensusParameters&); - }; } // namespace eosevm diff --git a/silkworm/node/db/access_layer.cpp b/silkworm/node/db/access_layer.cpp index c1a18ba4..937acb63 100644 --- a/silkworm/node/db/access_layer.cpp +++ b/silkworm/node/db/access_layer.cpp @@ -1226,18 +1226,15 @@ std::optional read_consensus_parameters(ROTxn& txn, if (!data) { return std::nullopt; } - - // https://github.com/nlohmann/json/issues/2204 - const auto json = nlohmann::json::parse(data.value.as_string(), nullptr, false); - return eosevm::ConsensusParameters::from_json(json); + const auto encoded = from_slice(data.value); + return eosevm::ConsensusParameters::decode(encoded); } void update_consensus_parameters(RWTxn& txn, BlockNum index, const eosevm::ConsensusParameters& config) { auto cursor = txn.rw_cursor(table::kConsensusParameters); auto key{db::block_key(index)}; - auto config_data{config.to_json().dump()}; - cursor->upsert(to_slice(key), mdbx::slice(config_data.data())); + cursor->upsert(to_slice(key), mdbx::slice(config.encode())); } } // namespace silkworm::db