From 99b2ab4acd6d9282b846b502cab6ffcfaf42f7e3 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Tue, 13 Aug 2024 22:28:00 -0300 Subject: [PATCH] Add support for storing overhead/storage price in the block extra data --- eosevm/block_extra_data.cpp | 7 ++++- eosevm/block_extra_data.hpp | 1 + eosevm/gas_prices.cpp | 38 +++++++++++++++++++++++ eosevm/gas_prices.hpp | 30 ++++++++++++++++++ silkworm/core/types/block.hpp | 14 +++++++++ silkworm/node/db/access_layer.cpp | 29 +++++++++++++++-- silkworm/node/db/access_layer.hpp | 6 ++++ silkworm/node/db/access_layer_test.cpp | 43 ++++++++++++++++++++++++++ silkworm/node/db/tables.hpp | 6 +++- 9 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 eosevm/gas_prices.cpp create mode 100644 eosevm/gas_prices.hpp diff --git a/eosevm/block_extra_data.cpp b/eosevm/block_extra_data.cpp index e77ad2e4..f6e803bd 100644 --- a/eosevm/block_extra_data.cpp +++ b/eosevm/block_extra_data.cpp @@ -7,7 +7,7 @@ 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; + return a.consensus_parameter_index == b.consensus_parameter_index && a.gas_prices_index == b.gas_prices_index; } } @@ -40,11 +40,16 @@ namespace silkworm { namespace rlp { silkworm::Bytes encode(const eosevm::block_extra_data& out) { silkworm::Bytes to; encode(to, out.consensus_parameter_index); + encode(to, out.gas_prices_index); return to; } DecodingResult decode(silkworm::ByteView& from, eosevm::block_extra_data& to) noexcept{ decode(from, to.consensus_parameter_index); + to.gas_prices_index.reset(); + if(from.length() > 0) { + decode(from, to.gas_prices_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 index 62699156..00b09cff 100644 --- a/eosevm/block_extra_data.hpp +++ b/eosevm/block_extra_data.hpp @@ -6,6 +6,7 @@ namespace eosevm { struct block_extra_data { std::optional consensus_parameter_index; + std::optional gas_prices_index; }; } // namespace eosevm diff --git a/eosevm/gas_prices.cpp b/eosevm/gas_prices.cpp new file mode 100644 index 00000000..545f3aa2 --- /dev/null +++ b/eosevm/gas_prices.cpp @@ -0,0 +1,38 @@ +#include "gas_prices.hpp" + +#if not defined(ANTELOPE) +#include +#include +#include +#endif + +namespace eosevm { + +bool operator==(const eosevm::gas_prices& a, const eosevm::gas_prices& b) { + return a.overhead_price == b.overhead_price && a.storage_price == b.storage_price; +} + +#if not defined(ANTELOPE) +[[nodiscard]] silkworm::Bytes gas_prices::encode() const noexcept { + silkworm::Bytes ret(16, '\0'); + silkworm::endian::store_big_u64(&ret[0], overhead_price); + silkworm::endian::store_big_u64(&ret[8], storage_price); + return ret; +} + +std::optional gas_prices::decode(silkworm::ByteView encoded) noexcept { + SILKWORM_ASSERT(encoded.length() >= 16); + gas_prices prices; + prices.overhead_price= silkworm::endian::load_big_u64(&encoded[0]); + prices.storage_price = silkworm::endian::load_big_u64(&encoded[8]); + return prices; +} + +[[nodiscard]] evmc::bytes32 gas_prices::hash() const noexcept { + auto encoded = this->encode(); + evmc::bytes32 header_hash = std::bit_cast(silkworm::keccak256(encoded)); + return header_hash; +} +#endif + +} // namespace eosevm diff --git a/eosevm/gas_prices.hpp b/eosevm/gas_prices.hpp new file mode 100644 index 00000000..a669cc22 --- /dev/null +++ b/eosevm/gas_prices.hpp @@ -0,0 +1,30 @@ +#pragma once +#include + +#if not defined(ANTELOPE) +#include +#endif + +namespace eosevm { + +struct gas_prices { + uint64_t overhead_price; + uint64_t storage_price; + + #if not defined(ANTELOPE) + // Encode for storage in db. + [[nodiscard]] silkworm::Bytes encode() const noexcept; + + // Decode from storage in db. + static std::optional decode(silkworm::ByteView encoded) noexcept; + evmc::bytes32 hash() const noexcept; + #endif + + friend bool operator==(const gas_prices&, const gas_prices&); +}; + +inline uint64_t calculate_base_fee_per_gas(uint64_t overhead_price, uint64_t storage_price) { + return std::max(overhead_price, storage_price); +} + +} // namespace eosevm diff --git a/silkworm/core/types/block.hpp b/silkworm/core/types/block.hpp index ebf380b9..b244305f 100644 --- a/silkworm/core/types/block.hpp +++ b/silkworm/core/types/block.hpp @@ -113,6 +113,20 @@ struct BlockBody { return eosevm_extra_data.value().consensus_parameter_index; } + bool has_gas_prices_index() { + return eosevm_extra_data.has_value() && eosevm_extra_data->gas_prices_index.has_value(); + } + + void set_gas_prices_index(const std::optional& index) { + if(!eosevm_extra_data.has_value()) eosevm_extra_data=eosevm::block_extra_data{}; + eosevm_extra_data->gas_prices_index = index; + } + + std::optional get_gas_prices_index() const { + if(!eosevm_extra_data.has_value()) return {}; + return eosevm_extra_data.value().gas_prices_index; + } + friend bool operator==(const BlockBody&, const BlockBody&); }; diff --git a/silkworm/node/db/access_layer.cpp b/silkworm/node/db/access_layer.cpp index 46965bc2..9282d84e 100644 --- a/silkworm/node/db/access_layer.cpp +++ b/silkworm/node/db/access_layer.cpp @@ -1265,8 +1265,6 @@ std::optional read_consensus_parameters(ROTxn& txn, return consensus_parameter; } - - void update_consensus_parameters(RWTxn& txn, const evmc::bytes32& index, const eosevm::ConsensusParameters& config) { auto cursor = txn.rw_cursor(table::kConsensusParameters); auto key{db::block_key(index.bytes)}; @@ -1274,4 +1272,31 @@ void update_consensus_parameters(RWTxn& txn, const evmc::bytes32& index, const e cursor->upsert(to_slice(key), mdbx::slice(config.encode())); } +std::optional read_gas_prices(ROTxn& txn, const evmc::bytes32& index) { + auto cursor = txn.ro_cursor(table::kGasPrices); + auto key{db::block_key(index.bytes)}; + auto data{cursor->find(to_slice(key), /*throw_notfound=*/false)}; + if (!data) { + return std::nullopt; + } + const auto encoded = from_slice(data.value); + return eosevm::gas_prices::decode(encoded); +} + +std::optional read_gas_prices(ROTxn& txn, const Block& block) { + std::optional prices; + auto gpi = block.get_gas_prices_index(); + if(gpi.has_value()) { + prices = read_gas_prices(txn, gpi.value()); + } + return prices; +} + +void update_gas_prices(RWTxn& txn, const evmc::bytes32& index, const eosevm::gas_prices& prices) { + auto cursor = txn.rw_cursor(table::kGasPrices); + auto key{db::block_key(index.bytes)}; + + cursor->upsert(to_slice(key), mdbx::slice(prices.encode())); +} + } // namespace silkworm::db diff --git a/silkworm/node/db/access_layer.hpp b/silkworm/node/db/access_layer.hpp index 9fa6887e..e8076c89 100644 --- a/silkworm/node/db/access_layer.hpp +++ b/silkworm/node/db/access_layer.hpp @@ -33,6 +33,7 @@ #include #include +#include namespace silkworm::db { @@ -262,6 +263,11 @@ std::optional read_consensus_parameters(ROTxn& txn, //! \brief Write ConsensusParameters indexed by blocknum that it is added. Can overwrite during forks. void update_consensus_parameters(RWTxn& txn, const evmc::bytes32&, const eosevm::ConsensusParameters& config); +std::optional read_gas_prices(ROTxn& txn, const evmc::bytes32& index); +std::optional read_gas_prices(ROTxn& txn, const Block& block); +void update_gas_prices(RWTxn& txn, const evmc::bytes32&, const eosevm::gas_prices& prices); + + class DataModel { public: static void set_snapshot_repository(snapshot::SnapshotRepository* repository); diff --git a/silkworm/node/db/access_layer_test.cpp b/silkworm/node/db/access_layer_test.cpp index 71fdfb9c..c693e72d 100644 --- a/silkworm/node/db/access_layer_test.cpp +++ b/silkworm/node/db/access_layer_test.cpp @@ -987,4 +987,47 @@ TEST_CASE("ConsensusParameters") { CHECK(read_consensus_parameters(txn, value2.hash()) == value2); } +TEST_CASE("gas_prices") { + test::Context context; + auto& txn{context.rw_txn()}; + + constexpr eosevm::gas_prices value1{ + .overhead_price = 1, + .storage_price = 1 + }; + + auto tmp = value1.encode(); + + ByteView bv{tmp}; + REQUIRE_NOTHROW(eosevm::gas_prices::decode(bv)); + + constexpr eosevm::gas_prices value2{ + .overhead_price = 2, + .storage_price = 2 + }; + + CHECK(read_gas_prices(txn, evmc::bytes32(0)) == std::nullopt); + + update_gas_prices(txn, evmc::bytes32(0), value1 ); + CHECK(read_gas_prices(txn, evmc::bytes32(0)) == value1); + + update_gas_prices(txn, evmc::bytes32(0), value2 ); + CHECK(read_gas_prices(txn, evmc::bytes32(0)) == value2); + + CHECK(read_gas_prices(txn, evmc::bytes32(1)) == std::nullopt); + + update_gas_prices(txn, evmc::bytes32(1), value2 ); + CHECK(read_gas_prices(txn, evmc::bytes32(1)) == value2); + + update_gas_prices(txn, evmc::bytes32(1), value1 ); + CHECK(read_gas_prices(txn, evmc::bytes32(1)) == value1); + + update_gas_prices(txn, value1.hash(), value1 ); + CHECK(read_gas_prices(txn, value1.hash()) == value1); + + update_gas_prices(txn, value2.hash(), value2 ); + CHECK(read_gas_prices(txn, value2.hash()) == value2); +} + + } // namespace silkworm::db diff --git a/silkworm/node/db/tables.hpp b/silkworm/node/db/tables.hpp index 0ebfb811..d8ec9745 100644 --- a/silkworm/node/db/tables.hpp +++ b/silkworm/node/db/tables.hpp @@ -389,6 +389,9 @@ inline constexpr db::MapConfig kRuntimeStates{kRuntimeStatesName}; inline constexpr const char* kConsensusParametersName{"ConsensusParameters"}; inline constexpr db::MapConfig kConsensusParameters{kConsensusParametersName}; +inline constexpr const char* kGasPricesName{"GasPrices"}; +inline constexpr db::MapConfig kGasPrices{kGasPricesName}; + inline constexpr db::MapConfig kChainDataTables[]{ kAccountChangeSet, kAccountHistory, @@ -435,7 +438,8 @@ inline constexpr db::MapConfig kChainDataTables[]{ kTxLookup, kRuntimeStates, kConsensusParameters, - kExtraBlockData + kExtraBlockData, + kGasPrices }; //! \brief Ensures all defined tables are present in db with consistent flags. Should a table not exist it gets created