From 229be9df91db8d7ef8e7941bb6701044d42b6a0f Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 8 Jul 2024 20:56:42 -0300 Subject: [PATCH 01/11] Add support for storage and overhead price --- include/evm_runtime/config_wrapper.hpp | 6 ++++++ include/evm_runtime/evm_contract.hpp | 2 ++ include/evm_runtime/tables.hpp | 4 +++- include/evm_runtime/types.hpp | 8 +++++++- src/CMakeLists.txt | 2 +- src/actions.cpp | 14 ++++++++++--- src/config_wrapper.cpp | 24 +++++++++++++++++++++++ tests/basic_evm_tester.cpp | 11 ++++++----- tests/basic_evm_tester.hpp | 19 +++++++++++++++++- tests/version_tests.cpp | 27 +++++++++++++++++++++++++- 10 files changed, 104 insertions(+), 13 deletions(-) diff --git a/include/evm_runtime/config_wrapper.hpp b/include/evm_runtime/config_wrapper.hpp index 14993d25..1774adcb 100644 --- a/include/evm_runtime/config_wrapper.hpp +++ b/include/evm_runtime/config_wrapper.hpp @@ -27,6 +27,12 @@ struct config_wrapper { const eosio::asset& get_ingress_bridge_fee()const; void set_ingress_bridge_fee(const eosio::asset& ingress_bridge_fee); + uint64_t get_overhead_price()const; + void set_overhead_price(uint64_t price); + + uint64_t get_storage_price()const; + void set_storage_price(uint64_t price); + uint64_t get_gas_price()const; void set_gas_price(uint64_t gas_price); diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index 4a761a97..22bed68f 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -88,6 +88,8 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void updtgasparam(eosio::asset ram_price_mb, uint64_t gas_price); [[eosio::action]] void setgasparam(uint64_t gas_txnewaccount, uint64_t gas_newaccount, uint64_t gas_txcreate, uint64_t gas_codedeposit, uint64_t gas_sset); + [[eosio::action]] void setgasprices(uint64_t storage_price, uint64_t overhead_price); + // Events [[eosio::action]] void evmtx(eosio::ignore event){ eosio::check(get_sender() == get_self(), "forbidden to call"); diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index 94ed03e4..b763b2b1 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -346,8 +346,10 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config binary_extension consensus_parameter; binary_extension token_contract; // <- default(unset) means eosio.token binary_extension queue_front_block; + binary_extension overhead_price; + binary_extension storage_price; - EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)); + EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)(overhead_price)(storage_price)); }; struct [[eosio::table]] [[eosio::contract("evm_contract")]] price_queue diff --git a/include/evm_runtime/types.hpp b/include/evm_runtime/types.hpp index 410204d4..e34c766f 100644 --- a/include/evm_runtime/types.hpp +++ b/include/evm_runtime/types.hpp @@ -86,7 +86,13 @@ namespace evm_runtime { EOSLIB_SERIALIZE(evmtx_v0, (eos_evm_version)(rlptx)(base_fee_per_gas)); }; - using evmtx_type = std::variant; + struct evmtx_v1 : evmtx_v0 { + uint64_t overhead_price; + uint64_t storage_price; + EOSLIB_SERIALIZE_DERIVED(evmtx_v1, evmtx_v0, (overhead_price)(storage_price)); + }; + + using evmtx_type = std::variant; struct fee_parameters { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 07090f2e..473e81fc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,5 +92,5 @@ target_compile_options(evm_runtime PUBLIC --no-missing-ricardian-clause) if (WITH_LARGE_STACK) target_link_options(evm_runtime PUBLIC --stack-size=50000000) else() - target_link_options(evm_runtime PUBLIC --stack-size=34720) + target_link_options(evm_runtime PUBLIC --stack-size=33952) endif() diff --git a/src/actions.cpp b/src/actions.cpp index e552f735..052cd7e4 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -522,10 +522,12 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const act.send(gas_param_pair.first); } - if (current_version >= 1) { + if(current_version >= 3) { + auto event = evmtx_type{evmtx_v1{current_version, txn.get_rlptx(), *base_fee_per_gas, _config->get_overhead_price(), _config->get_storage_price()}}; + action(std::vector{}, get_self(), "evmtx"_n, event).send(); + } else if (current_version >= 1) { auto event = evmtx_type{evmtx_v0{current_version, txn.get_rlptx(), *base_fee_per_gas}}; - action(std::vector{}, get_self(), "evmtx"_n, event) - .send(); + action(std::vector{}, get_self(), "evmtx"_n, event).send(); } LOGTIME("EVM END"); } @@ -899,4 +901,10 @@ void evm_contract::setgasparam(uint64_t gas_txnewaccount, gas_sset); } +void evm_contract::setgasprices(uint64_t storage_price, uint64_t overhead_price) { + require_auth(get_self()); + _config->set_storage_price(storage_price); + _config->set_overhead_price(overhead_price); +} + } //evm_runtime diff --git a/src/config_wrapper.cpp b/src/config_wrapper.cpp index 9d1b3647..fc2eb44e 100644 --- a/src/config_wrapper.cpp +++ b/src/config_wrapper.cpp @@ -20,6 +20,12 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se if (!_cached_config.queue_front_block.has_value()) { _cached_config.queue_front_block = 0; } + if (!_cached_config.overhead_price.has_value()) { + _cached_config.overhead_price = 0; + } + if (!_cached_config.storage_price.has_value()) { + _cached_config.storage_price = 0; + } } config_wrapper::~config_wrapper() { @@ -85,6 +91,24 @@ void config_wrapper::set_gas_price(uint64_t gas_price) { set_dirty(); } +uint64_t config_wrapper::get_overhead_price()const { + return *_cached_config.overhead_price; +} + +void config_wrapper::set_overhead_price(uint64_t price) { + _cached_config.overhead_price = price; + set_dirty(); +} + +uint64_t config_wrapper::get_storage_price()const { + return *_cached_config.storage_price; +} + +void config_wrapper::set_storage_price(uint64_t price) { + _cached_config.storage_price = price; + set_dirty(); +} + void config_wrapper::enqueue_gas_price(uint64_t gas_price) { price_queue_table queue(_self, _self.value); auto activation_time = get_current_time() + eosio::seconds(grace_period_seconds); diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 2fcd6844..c372c76a 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -508,6 +508,11 @@ transaction_trace_ptr basic_evm_tester::addopenbal(name account, const intx::uin mvo()("account", account)("delta",d)("subtract",subtract)); } +transaction_trace_ptr basic_evm_tester::setgasprices(uint64_t storage_price, uint64_t overhead_price, name actor) { + return basic_evm_tester::push_action(evm_account_name, "setgasprices"_n, actor, + mvo()("storage_price", storage_price)("overhead_price",overhead_price)); +} + evmc::address basic_evm_tester::deploy_contract(evm_eoa& eoa, evmc::bytes bytecode) { uint64_t nonce = eoa.next_nonce; @@ -810,11 +815,7 @@ void basic_evm_tester::check_balances() { } silkworm::Transaction basic_evm_tester::get_tx_from_trace(const bytes& v) { - auto evmtx_v = fc::raw::unpack(v.data(), v.size()); - - BOOST_REQUIRE(std::holds_alternative(evmtx_v)); - - const auto& evmtx = std::get(evmtx_v); + auto evmtx = get_event_from_trace(v); BOOST_REQUIRE(evmtx.eos_evm_version == 1); silkworm::Transaction tx; diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index 88de6f1e..e27935fc 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -60,7 +60,13 @@ struct evmtx_v0 { uint64_t base_fee_per_gas; }; -using evmtx_type = std::variant; +struct evmtx_v1 : evmtx_v0 { + uint64_t overhead_price; + uint64_t storage_price; +}; + + +using evmtx_type = std::variant; struct evm_version_type { struct pending { @@ -227,6 +233,7 @@ FC_REFLECT(evm_test::bridge_message_v0, (receiver)(sender)(timestamp)(value)(dat FC_REFLECT(evm_test::gcstore, (id)(storage_id)); FC_REFLECT(evm_test::account_code, (id)(ref_count)(code)(code_hash)); FC_REFLECT(evm_test::evmtx_v0, (eos_evm_version)(rlptx)(base_fee_per_gas)); +FC_REFLECT_DERIVED(evm_test::evmtx_v1, (evm_test::evmtx_v0), (overhead_price)(storage_price)); FC_REFLECT(evm_test::consensus_parameter_type, (current)(pending)); FC_REFLECT(evm_test::pending_consensus_parameter_data_type, (data)(pending_time)); @@ -459,6 +466,8 @@ class basic_evm_tester : public evm_validating_tester transaction_trace_ptr addevmbal(uint64_t id, const intx::uint256& delta, bool subtract, name actor=evm_account_name); transaction_trace_ptr addopenbal(name account, const intx::uint256& delta, bool subtract, name actor=evm_account_name); + transaction_trace_ptr setgasprices(uint64_t storage_price, uint64_t overhead_price, name actor=evm_account_name); + void open(name owner); void close(name owner); void withdraw(name owner, asset quantity); @@ -509,7 +518,15 @@ class basic_evm_tester : public evm_validating_tester bool scan_price_queue(std::function visitor) const; intx::uint128 tx_data_cost(const silkworm::Transaction& txn) const; + silkworm::Transaction get_tx_from_trace(const bytes& v); + + template + T get_event_from_trace(const bytes& v) { + auto evmtx_v = fc::raw::unpack(v.data(), v.size()); + BOOST_REQUIRE(std::holds_alternative(evmtx_v)); + return std::get(evmtx_v); + } }; inline constexpr intx::uint256 operator"" _wei(const char* s) { return intx::from_string(s); } diff --git a/tests/version_tests.cpp b/tests/version_tests.cpp index 1e8a8180..85a38c07 100644 --- a/tests/version_tests.cpp +++ b/tests/version_tests.cpp @@ -94,7 +94,7 @@ BOOST_FIXTURE_TEST_CASE(set_version, version_tester) try { eosio_assert_message_exception, eosio_assert_message_is("new version must be greater than the active one")); - BOOST_REQUIRE_EXCEPTION(setversion(3, evm_account_name), + BOOST_REQUIRE_EXCEPTION(setversion(4, evm_account_name), eosio_assert_message_exception, eosio_assert_message_is("Unsupported version")); @@ -297,6 +297,31 @@ BOOST_FIXTURE_TEST_CASE(traces_in_different_eosevm_version, version_tester) try // Check 4 times call to `increment` from alice_addr BOOST_REQUIRE(retrieve(contract_address, alice_addr) == intx::uint256(4)); + ///////////////////////////////////// + /// change EOS EVM VERSION => 3 /// + ///////////////////////////////////// + + setgasprices(5, 6); + setversion(3, evm_account_name); + produce_blocks(2); + + // Test traces of `handle_evm_transfer` (EVM VERSION=3) + trace = transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x()); + BOOST_REQUIRE(trace->action_traces.size() == 4); + BOOST_REQUIRE(trace->action_traces[0].act.account == token_account_name); + BOOST_REQUIRE(trace->action_traces[0].act.name == "transfer"_n); + BOOST_REQUIRE(trace->action_traces[1].act.account == token_account_name); + BOOST_REQUIRE(trace->action_traces[1].act.name == "transfer"_n); + BOOST_REQUIRE(trace->action_traces[2].act.account == token_account_name); + BOOST_REQUIRE(trace->action_traces[2].act.name == "transfer"_n); + BOOST_REQUIRE(trace->action_traces[3].act.account == evm_account_name); + BOOST_REQUIRE(trace->action_traces[3].act.name == "evmtx"_n); + + auto event_v1 = get_event_from_trace(trace->action_traces[3].act.data); + BOOST_REQUIRE(event_v1.eos_evm_version == 3); + BOOST_REQUIRE(event_v1.storage_price == 5); + BOOST_REQUIRE(event_v1.overhead_price == 6); + } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(exec_does_not_update_version, version_tester) try { From bd1b6a091935a2e38bd2bb13e8740787913c2de6 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 11 Jul 2024 03:13:26 -0300 Subject: [PATCH 02/11] Use value_promoter to handle evm_version, consensus_parameter, overhead_price and storage_price --- include/evm_runtime/tables.hpp | 99 +++++++++++----------------------- src/CMakeLists.txt | 2 +- src/config_wrapper.cpp | 66 ++++++++++++++--------- tests/basic_evm_tester.cpp | 12 +++++ tests/basic_evm_tester.hpp | 7 ++- 5 files changed, 89 insertions(+), 97 deletions(-) diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index b763b2b1..fbb913c5 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -243,9 +243,10 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config2 EOSLIB_SERIALIZE(config2, (next_account_id)); }; -struct evm_version_type { +template +struct value_promoter { struct pending { - uint64_t version; + T value; time_point time; bool is_active(time_point_sec genesis_time, time_point current_time)const { @@ -256,81 +257,43 @@ struct evm_version_type { } }; - uint64_t get_version(time_point_sec genesis_time, time_point current_time)const { - uint64_t current_version = cached_version; - if(pending_version.has_value() && pending_version->is_active(genesis_time, current_time)) { - current_version = pending_version->version; + T get_value(time_point_sec genesis_time, time_point current_time)const { + T current_value = cached_value; + if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) { + current_value = pending_value->value; } - return current_version; + return current_value; } - std::pair get_version_and_maybe_promote(time_point_sec genesis_time, time_point current_time) { - uint64_t current_version = cached_version; + std::pair get_value_and_maybe_promote(time_point_sec genesis_time, time_point current_time) { + T current_value = cached_value; bool promoted = false; - if(pending_version.has_value() && pending_version->is_active(genesis_time, current_time)) { - current_version = pending_version->version; + if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) { + current_value = pending_value->value; promote_pending(); promoted = true; } - return std::make_pair(current_version, promoted); + return std::make_pair(current_value, promoted); } - void promote_pending() { - eosio::check(pending_version.has_value(), "no pending version"); - cached_version = pending_version.value().version; - pending_version.reset(); - } - - std::optional pending_version; - uint64_t cached_version=0; -}; - -struct pending_consensus_parameter_data_type { - consensus_parameter_data_type data; - time_point pending_time; -}; -struct consensus_parameter_type { - - consensus_parameter_data_type current; - std::optional pending; - - bool is_pending_active(time_point_sec genesis_time, time_point current_time)const { - if (!pending.has_value()) return false; - eosevm::block_mapping bm(genesis_time.sec_since_epoch()); - auto current_block_num = bm.timestamp_to_evm_block_num(current_time.time_since_epoch().count()); - auto pending_block_num = bm.timestamp_to_evm_block_num(pending->pending_time.time_since_epoch().count()); - return current_block_num > pending_block_num; - } - - // Reference invalidated by get_consensus_param_and_maybe_promote and update_consensus_param. - const consensus_parameter_data_type& get_consensus_param( - time_point_sec genesis_time, time_point current_time) const { - if (is_pending_active(genesis_time, current_time)) { - return pending->data; - } - return current; + template + void update(Visitor&& visitor_fn, time_point_sec genesis_time, time_point current_time) { + auto value = get_value_and_maybe_promote(genesis_time, current_time); + visitor_fn(value.first); + pending_value.emplace(pending{ + .value = value.first, + .time = current_time + }); } - std::pair get_consensus_param_and_maybe_promote( - time_point_sec genesis_time, time_point current_time) { - if (is_pending_active(genesis_time, current_time)) { - current = pending->data; - pending.reset(); - // don't use make_pair as it create ref to temp objects - return std::pair(current, true); - } - return std::pair(current, false); + void promote_pending() { + eosio::check(pending_value.has_value(), "no pending value"); + cached_value = pending_value.value().value; + pending_value.reset(); } - template - void update_consensus_param(Visitor visitor_fn, time_point current_time) { - consensus_parameter_data_type new_pending = (pending.has_value() ? pending->data : current); - std::visit(visitor_fn, new_pending); - pending = pending_consensus_parameter_data_type{ - .data = new_pending, - .pending_time = current_time - }; - } + std::optional pending_value; + T cached_value=T{}; }; struct [[eosio::table]] [[eosio::contract("evm_contract")]] config @@ -342,12 +305,12 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config uint64_t gas_price = 0; uint32_t miner_cut = 0; uint32_t status = 0; // <- bit mask values from status_flags - binary_extension evm_version; - binary_extension consensus_parameter; + binary_extension> evm_version; + binary_extension> consensus_parameter; binary_extension token_contract; // <- default(unset) means eosio.token binary_extension queue_front_block; - binary_extension overhead_price; - binary_extension storage_price; + binary_extension> overhead_price; + binary_extension> storage_price; EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)(overhead_price)(storage_price)); }; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a00c1a0..5db9c825 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,5 +92,5 @@ target_compile_options(evm_runtime PUBLIC --no-missing-ricardian-clause) if (WITH_LARGE_STACK) target_link_options(evm_runtime PUBLIC --stack-size=50000000) else() - target_link_options(evm_runtime PUBLIC --stack-size=37328) + target_link_options(evm_runtime PUBLIC --stack-size=35504) endif() diff --git a/src/config_wrapper.cpp b/src/config_wrapper.cpp index fc2eb44e..18e7e9cc 100644 --- a/src/config_wrapper.cpp +++ b/src/config_wrapper.cpp @@ -9,8 +9,12 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se if(_exists) { _cached_config = _config.get(); } + if (!_cached_config.evm_version.has_value()) { + _cached_config.evm_version = value_promoter{}; + // Don't set dirty because action can be read-only. + } if (!_cached_config.consensus_parameter.has_value()) { - _cached_config.consensus_parameter = consensus_parameter_type(); + _cached_config.consensus_parameter = value_promoter{}; // Don't set dirty because action can be read-only. } if (!_cached_config.token_contract.has_value()) { @@ -21,10 +25,10 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se _cached_config.queue_front_block = 0; } if (!_cached_config.overhead_price.has_value()) { - _cached_config.overhead_price = 0; + _cached_config.overhead_price = value_promoter{}; } if (!_cached_config.storage_price.has_value()) { - _cached_config.storage_price = 0; + _cached_config.storage_price = value_promoter{}; } } @@ -92,20 +96,28 @@ void config_wrapper::set_gas_price(uint64_t gas_price) { } uint64_t config_wrapper::get_overhead_price()const { - return *_cached_config.overhead_price; + // should not happen + eosio::check(_cached_config.overhead_price.has_value(), "overhead_price not exist"); + return _cached_config.overhead_price->get_value(_cached_config.genesis_time, get_current_time()); } void config_wrapper::set_overhead_price(uint64_t price) { - _cached_config.overhead_price = price; + _cached_config.overhead_price->update([&](auto& v) { + v = price; + }, _cached_config.genesis_time, get_current_time()); set_dirty(); } uint64_t config_wrapper::get_storage_price()const { - return *_cached_config.storage_price; + // should not happen + eosio::check(_cached_config.storage_price.has_value(), "storage_price not exist"); + return _cached_config.storage_price->get_value(_cached_config.genesis_time, get_current_time()); } void config_wrapper::set_storage_price(uint64_t price) { - _cached_config.storage_price = price; + _cached_config.storage_price->update([&](auto& v) { + v = price; + }, _cached_config.genesis_time, get_current_time()); set_dirty(); } @@ -181,18 +193,16 @@ void config_wrapper::set_status(uint32_t status) { } uint64_t config_wrapper::get_evm_version()const { - uint64_t current_version = 0; - if(_cached_config.evm_version.has_value()) { - current_version = _cached_config.evm_version->get_version(_cached_config.genesis_time, get_current_time()); - } - return current_version; + // should not happen + eosio::check(_cached_config.evm_version.has_value(), "evm_version not exist"); + return _cached_config.evm_version->get_value(_cached_config.genesis_time, get_current_time()); } uint64_t config_wrapper::get_evm_version_and_maybe_promote() { uint64_t current_version = 0; bool promoted = false; if(_cached_config.evm_version.has_value()) { - std::tie(current_version, promoted) = _cached_config.evm_version->get_version_and_maybe_promote(_cached_config.genesis_time, get_current_time()); + std::tie(current_version, promoted) = _cached_config.evm_version->get_value_and_maybe_promote(_cached_config.genesis_time, get_current_time()); } if(promoted) { if(current_version >=1 && _cached_config.miner_cut != 0) _cached_config.miner_cut = 0; @@ -205,7 +215,9 @@ void config_wrapper::set_evm_version(uint64_t new_version) { eosio::check(new_version <= eosevm::max_eos_evm_version, "Unsupported version"); auto current_version = get_evm_version_and_maybe_promote(); eosio::check(new_version > current_version, "new version must be greater than the active one"); - _cached_config.evm_version.emplace(evm_version_type{evm_version_type::pending{new_version, get_current_time()}, current_version}); + _cached_config.evm_version->update([&](auto& v) { + v = new_version; + }, _cached_config.genesis_time, get_current_time()); set_dirty(); } @@ -285,16 +297,18 @@ void config_wrapper::update_consensus_parameters2(std::optional gas_tx // should not happen eosio::check(_cached_config.consensus_parameter.has_value(), "consensus_parameter not exist"); - _cached_config.consensus_parameter->update_consensus_param([&](auto & v) { - if (gas_txnewaccount.has_value()) v.gas_parameter.gas_txnewaccount = *gas_txnewaccount; - if (gas_newaccount.has_value()) v.gas_parameter.gas_newaccount = *gas_newaccount; - if (gas_txcreate.has_value()) v.gas_parameter.gas_txcreate = *gas_txcreate; - if (gas_codedeposit.has_value()) v.gas_parameter.gas_codedeposit = *gas_codedeposit; - if (gas_sset.has_value()) { - eosio::check(*gas_sset >= gas_sset_min, "gas_sset too small"); - v.gas_parameter.gas_sset = *gas_sset; - } - }, get_current_time()); + _cached_config.consensus_parameter->update([&](auto& p) { + std::visit([&](auto& v){ + if (gas_txnewaccount.has_value()) v.gas_parameter.gas_txnewaccount = *gas_txnewaccount; + if (gas_newaccount.has_value()) v.gas_parameter.gas_newaccount = *gas_newaccount; + if (gas_txcreate.has_value()) v.gas_parameter.gas_txcreate = *gas_txcreate; + if (gas_codedeposit.has_value()) v.gas_parameter.gas_codedeposit = *gas_codedeposit; + if (gas_sset.has_value()) { + eosio::check(*gas_sset >= gas_sset_min, "gas_sset too small"); + v.gas_parameter.gas_sset = *gas_sset; + } + }, p); + }, _cached_config.genesis_time, get_current_time()); set_dirty(); } @@ -302,7 +316,7 @@ void config_wrapper::update_consensus_parameters2(std::optional gas_tx const consensus_parameter_data_type& config_wrapper::get_consensus_param() { // should not happen eosio::check(_cached_config.consensus_parameter.has_value(), "consensus_parameter not exist"); - return _cached_config.consensus_parameter->get_consensus_param(_cached_config.genesis_time, get_current_time()); + return _cached_config.consensus_parameter->get_value(_cached_config.genesis_time, get_current_time()); } std::pair config_wrapper::get_consensus_param_and_maybe_promote() { @@ -310,7 +324,7 @@ std::pair config_wrapper::get_conse // should not happen eosio::check(_cached_config.consensus_parameter.has_value(), "consensus_parameter not exist"); - auto pair = _cached_config.consensus_parameter->get_consensus_param_and_maybe_promote(_cached_config.genesis_time, get_current_time()); + auto pair = _cached_config.consensus_parameter->get_value_and_maybe_promote(_cached_config.genesis_time, get_current_time()); if (pair.second) { set_dirty(); } diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index c372c76a..fc186cdf 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -103,6 +103,17 @@ namespace fc { namespace raw { fc::raw::unpack(ds, queue_front_block); tmp.queue_front_block.emplace(queue_front_block); } + if(ds.remaining()) { + uint32_t overhead_price; + fc::raw::unpack(ds, overhead_price); + tmp.overhead_price.emplace(overhead_price); + } + if(ds.remaining()) { + uint32_t storage_price; + fc::raw::unpack(ds, storage_price); + tmp.storage_price.emplace(storage_price); + } + } FC_RETHROW_EXCEPTIONS(warn, "error unpacking partial_account_table_row") } }} @@ -317,6 +328,7 @@ config_table_row basic_evm_tester::get_config() const static constexpr eosio::chain::name config_singleton_name = "config"_n; const vector d = get_row_by_account(evm_account_name, evm_account_name, config_singleton_name, config_singleton_name); + return fc::raw::unpack(d); } diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index e27935fc..aff241ce 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -93,8 +93,8 @@ struct pending_consensus_parameter_data_type { fc::time_point pending_time; }; struct consensus_parameter_type { - consensus_parameter_data_type current; std::optional pending; + consensus_parameter_data_type current; }; struct config_table_row { @@ -109,6 +109,9 @@ struct config_table_row std::optional consensus_parameter; std::optional token_contract; std::optional queue_front_block; + std::optional overhead_price; + std::optional storage_price; + }; struct config2_table_row @@ -235,7 +238,7 @@ FC_REFLECT(evm_test::account_code, (id)(ref_count)(code)(code_hash)); FC_REFLECT(evm_test::evmtx_v0, (eos_evm_version)(rlptx)(base_fee_per_gas)); FC_REFLECT_DERIVED(evm_test::evmtx_v1, (evm_test::evmtx_v0), (overhead_price)(storage_price)); -FC_REFLECT(evm_test::consensus_parameter_type, (current)(pending)); +FC_REFLECT(evm_test::consensus_parameter_type, (pending)(current)); FC_REFLECT(evm_test::pending_consensus_parameter_data_type, (data)(pending_time)); FC_REFLECT(evm_test::consensus_parameter_data_v0, (gas_parameter)); FC_REFLECT(evm_test::gas_parameter_type, (gas_txnewaccount)(gas_newaccount)(gas_txcreate)(gas_codedeposit)(gas_sset)); From 800309d35780abc0371c8db2eedfe21e3ad6b093 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 11 Jul 2024 03:13:47 -0300 Subject: [PATCH 03/11] Update silkworm with v3 support --- silkworm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/silkworm b/silkworm index c4da9c73..c21967a6 160000 --- a/silkworm +++ b/silkworm @@ -1 +1 @@ -Subproject commit c4da9c735207b8d2a2a018ebfc6bb9f3bfd3add4 +Subproject commit c21967a63932f5e3dd09ce5b68c9d5c7267d45f3 From 2eab90b489234b643d20a3ac9009864985e8a217 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 11 Jul 2024 03:30:15 -0300 Subject: [PATCH 04/11] github: Use cdt 4.0.1 --- .github/workflows/contract.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index 41490cb7..caeb6ed2 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -39,11 +39,11 @@ jobs: submodules: 'recursive' - name: Download CDT - uses: AntelopeIO/asset-artifact-download-action@v3 + uses: AntelopeIO/asset-artifact-download-action@v4 with: owner: AntelopeIO repo: cdt - target: 'v3.1.0' + target: 'v4.0.1' prereleases: false file: 'cdt_.*amd64.deb' @@ -63,7 +63,7 @@ jobs: if-no-files-found: error - name: Download Leap - dev binary - uses: AntelopeIO/asset-artifact-download-action@v3 + uses: AntelopeIO/asset-artifact-download-action@v4 with: owner: AntelopeIO repo: leap From 9bcabe9a174d8fb25ff01467f3c8dda364121023 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 11 Jul 2024 03:32:22 -0300 Subject: [PATCH 05/11] fix contract.yml --- .github/workflows/contract.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index caeb6ed2..8ab8b550 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -39,7 +39,7 @@ jobs: submodules: 'recursive' - name: Download CDT - uses: AntelopeIO/asset-artifact-download-action@v4 + uses: AntelopeIO/asset-artifact-download-action@v3 with: owner: AntelopeIO repo: cdt @@ -63,7 +63,7 @@ jobs: if-no-files-found: error - name: Download Leap - dev binary - uses: AntelopeIO/asset-artifact-download-action@v4 + uses: AntelopeIO/asset-artifact-download-action@v3 with: owner: AntelopeIO repo: leap From 86255346e2c4b6c14fe604c181669eb3a1b45d15 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 29 Jul 2024 18:16:35 -0300 Subject: [PATCH 06/11] Use MACROS to implement value_promoter to circumvent cdt limitations when generating contract abi --- include/evm_runtime/config_wrapper.hpp | 12 ++--- include/evm_runtime/evm_contract.hpp | 5 +- include/evm_runtime/tables.hpp | 70 ++++++-------------------- include/evm_runtime/types.hpp | 15 +++--- include/evm_runtime/value_promoter.hpp | 65 ++++++++++++++++++++++++ src/CMakeLists.txt | 2 +- src/actions.cpp | 14 +++--- src/config_wrapper.cpp | 43 +++++++--------- tests/basic_evm_tester.cpp | 17 +++---- tests/basic_evm_tester.hpp | 43 ++++++++++++---- tests/version_tests.cpp | 20 +++++--- 11 files changed, 173 insertions(+), 133 deletions(-) create mode 100644 include/evm_runtime/value_promoter.hpp diff --git a/include/evm_runtime/config_wrapper.hpp b/include/evm_runtime/config_wrapper.hpp index 1774adcb..1299b428 100644 --- a/include/evm_runtime/config_wrapper.hpp +++ b/include/evm_runtime/config_wrapper.hpp @@ -1,9 +1,9 @@ #pragma once -#include + +#include #include #include #include -#include namespace evm_runtime { struct fee_parameters; @@ -27,11 +27,9 @@ struct config_wrapper { const eosio::asset& get_ingress_bridge_fee()const; void set_ingress_bridge_fee(const eosio::asset& ingress_bridge_fee); - uint64_t get_overhead_price()const; - void set_overhead_price(uint64_t price); - - uint64_t get_storage_price()const; - void set_storage_price(uint64_t price); + gas_prices get_gas_prices()const; + gas_prices get_gas_prices_and_maybe_promote(); + void set_gas_prices(const gas_prices& price); uint64_t get_gas_price()const; void set_gas_price(uint64_t gas_price); diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index 22bed68f..dfaa1d11 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -1,4 +1,3 @@ -#include #include #include #include @@ -18,6 +17,8 @@ using namespace eosio; namespace evm_runtime { +struct gas_prices; + class [[eosio::contract]] evm_contract : public contract { public: @@ -88,7 +89,7 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void updtgasparam(eosio::asset ram_price_mb, uint64_t gas_price); [[eosio::action]] void setgasparam(uint64_t gas_txnewaccount, uint64_t gas_newaccount, uint64_t gas_txcreate, uint64_t gas_codedeposit, uint64_t gas_sset); - [[eosio::action]] void setgasprices(uint64_t storage_price, uint64_t overhead_price); + [[eosio::action]] void setgasprices(const gas_prices& prices); // Events [[eosio::action]] void evmtx(eosio::ignore event){ diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index fbb913c5..e0ed0e5c 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include #include @@ -8,9 +9,11 @@ #include #include + #include #include + namespace evm_runtime { using namespace eosio; @@ -243,59 +246,15 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config2 EOSLIB_SERIALIZE(config2, (next_account_id)); }; -template -struct value_promoter { - struct pending { - T value; - time_point time; - - bool is_active(time_point_sec genesis_time, time_point current_time)const { - eosevm::block_mapping bm(genesis_time.sec_since_epoch()); - auto current_block_num = bm.timestamp_to_evm_block_num(current_time.time_since_epoch().count()); - auto pending_block_num = bm.timestamp_to_evm_block_num(time.time_since_epoch().count()); - return current_block_num > pending_block_num; - } - }; - - T get_value(time_point_sec genesis_time, time_point current_time)const { - T current_value = cached_value; - if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) { - current_value = pending_value->value; - } - return current_value; - } - - std::pair get_value_and_maybe_promote(time_point_sec genesis_time, time_point current_time) { - T current_value = cached_value; - bool promoted = false; - if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) { - current_value = pending_value->value; - promote_pending(); - promoted = true; - } - return std::make_pair(current_value, promoted); - } - - template - void update(Visitor&& visitor_fn, time_point_sec genesis_time, time_point current_time) { - auto value = get_value_and_maybe_promote(genesis_time, current_time); - visitor_fn(value.first); - pending_value.emplace(pending{ - .value = value.first, - .time = current_time - }); - } - - void promote_pending() { - eosio::check(pending_value.has_value(), "no pending value"); - cached_value = pending_value.value().value; - pending_value.reset(); - } - - std::optional pending_value; - T cached_value=T{}; +struct gas_prices { + uint64_t overhead_price{0}; + uint64_t storage_price{0}; }; +VALUE_PROMOTER(uint64_t); +VALUE_PROMOTER_REV(consensus_parameter_data_type); +VALUE_PROMOTER(gas_prices); + struct [[eosio::table]] [[eosio::contract("evm_contract")]] config { unsigned_int version; // placeholder for future variant index @@ -305,14 +264,13 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config uint64_t gas_price = 0; uint32_t miner_cut = 0; uint32_t status = 0; // <- bit mask values from status_flags - binary_extension> evm_version; - binary_extension> consensus_parameter; + binary_extension evm_version; + binary_extension consensus_parameter; binary_extension token_contract; // <- default(unset) means eosio.token binary_extension queue_front_block; - binary_extension> overhead_price; - binary_extension> storage_price; + binary_extension gas_prices; - EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)(overhead_price)(storage_price)); + EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)(gas_prices)); }; struct [[eosio::table]] [[eosio::contract("evm_contract")]] price_queue diff --git a/include/evm_runtime/types.hpp b/include/evm_runtime/types.hpp index e34c766f..b0e83a7c 100644 --- a/include/evm_runtime/types.hpp +++ b/include/evm_runtime/types.hpp @@ -78,21 +78,24 @@ namespace evm_runtime { using bridge_message = std::variant; - struct evmtx_v0 { + struct evmtx_base { uint64_t eos_evm_version; bytes rlptx; + EOSLIB_SERIALIZE(evmtx_base, (eos_evm_version)(rlptx)); + }; + + struct evmtx_v1 : evmtx_base { uint64_t base_fee_per_gas; - - EOSLIB_SERIALIZE(evmtx_v0, (eos_evm_version)(rlptx)(base_fee_per_gas)); + EOSLIB_SERIALIZE_DERIVED(evmtx_v1, evmtx_base, (base_fee_per_gas)); }; - struct evmtx_v1 : evmtx_v0 { + struct evmtx_v3 : evmtx_base { uint64_t overhead_price; uint64_t storage_price; - EOSLIB_SERIALIZE_DERIVED(evmtx_v1, evmtx_v0, (overhead_price)(storage_price)); + EOSLIB_SERIALIZE_DERIVED(evmtx_v3, evmtx_base, (overhead_price)(storage_price)); }; - using evmtx_type = std::variant; + using evmtx_type = std::variant; struct fee_parameters { diff --git a/include/evm_runtime/value_promoter.hpp b/include/evm_runtime/value_promoter.hpp new file mode 100644 index 00000000..e7d58f13 --- /dev/null +++ b/include/evm_runtime/value_promoter.hpp @@ -0,0 +1,65 @@ +#pragma once +#include +#include +#include + +#define VALUE_PROMOTER_PENDING(T)\ + struct T##_pending {\ + T value;\ + time_point time;\ + bool is_active(time_point_sec genesis_time, time_point current_time)const {\ + eosevm::block_mapping bm(genesis_time.sec_since_epoch());\ + auto current_block_num = bm.timestamp_to_evm_block_num(current_time.time_since_epoch().count());\ + auto pending_block_num = bm.timestamp_to_evm_block_num(time.time_since_epoch().count());\ + return current_block_num > pending_block_num;\ + }\ + }; + +#define VALUE_PROMOTER_IMPL(T)\ + T get_value(time_point_sec genesis_time, time_point current_time)const {\ + T current_value = cached_value;\ + if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) {\ + current_value = pending_value->value;\ + }\ + return current_value;\ + }\ + std::pair get_value_and_maybe_promote(time_point_sec genesis_time, time_point current_time) {\ + T current_value = cached_value;\ + bool promoted = false;\ + if(pending_value.has_value() && pending_value->is_active(genesis_time, current_time)) {\ + current_value = pending_value->value;\ + promote_pending();\ + promoted = true;\ + }\ + return std::pair(current_value, promoted);\ + }\ + template \ + void update(Visitor&& visitor_fn, time_point_sec genesis_time, time_point current_time) {\ + auto value = get_value_and_maybe_promote(genesis_time, current_time);\ + visitor_fn(value.first);\ + pending_value.emplace(T##_pending{\ + .value = value.first,\ + .time = current_time\ + });\ + }\ + void promote_pending() {\ + eosio::check(pending_value.has_value(), "no pending value");\ + cached_value = pending_value.value().value;\ + pending_value.reset();\ + } + +#define VALUE_PROMOTER(T)\ +VALUE_PROMOTER_PENDING(T);\ +struct value_promoter_##T {\ + std::optional pending_value;\ + T cached_value = T{};\ + VALUE_PROMOTER_IMPL(T)\ +}; + +#define VALUE_PROMOTER_REV(T)\ +VALUE_PROMOTER_PENDING(T);\ +struct value_promoter_##T {\ + T cached_value = T{};\ + std::optional pending_value;\ + VALUE_PROMOTER_IMPL(T)\ +}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5db9c825..4a2a445e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -92,5 +92,5 @@ target_compile_options(evm_runtime PUBLIC --no-missing-ricardian-clause) if (WITH_LARGE_STACK) target_link_options(evm_runtime PUBLIC --stack-size=50000000) else() - target_link_options(evm_runtime PUBLIC --stack-size=35504) + target_link_options(evm_runtime PUBLIC --stack-size=35984) endif() diff --git a/src/actions.cpp b/src/actions.cpp index faa3c6c0..8f61efc2 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -457,6 +457,7 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const "unexpected error: EVM contract generated inline pushtx without setting itself as the miner"); auto current_version = _config->get_evm_version_and_maybe_promote(); + auto gas_prices = _config->get_gas_prices_and_maybe_promote(); std::pair gas_param_pair = _config->get_consensus_param_and_maybe_promote(); if (gas_param_pair.second) { @@ -493,8 +494,6 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const ); }, gas_param_pair.first); - silkworm::ExecutionProcessor ep{block, engine, state, *found_chain_config->second, gas_params}; - if (current_version >= 1) { auto inclusion_price = std::min(tx.max_priority_fee_per_gas, tx.max_fee_per_gas - *base_fee_per_gas); eosio::check(inclusion_price >= (min_inclusion_price.has_value() ? *min_inclusion_price : 0), "inclusion price must >= min_inclusion_price"); @@ -503,6 +502,8 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const check(tx.max_fee_per_gas >= _config->get_gas_price(), "gas price is too low"); } + silkworm::ExecutionProcessor ep{block, engine, state, *found_chain_config->second, gas_params}; + // Filter EVM messages (with data) that are sent to the reserved address // corresponding to the EOS account holding the contract (self) ep.set_evm_message_filter([&](const evmc_message& message) -> bool { @@ -523,10 +524,10 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const } if(current_version >= 3) { - auto event = evmtx_type{evmtx_v1{current_version, txn.get_rlptx(), *base_fee_per_gas, _config->get_overhead_price(), _config->get_storage_price()}}; + auto event = evmtx_type{evmtx_v3{current_version, txn.get_rlptx(), gas_prices.overhead_price, gas_prices.storage_price}}; action(std::vector{}, get_self(), "evmtx"_n, event).send(); } else if (current_version >= 1) { - auto event = evmtx_type{evmtx_v0{current_version, txn.get_rlptx(), *base_fee_per_gas}}; + auto event = evmtx_type{evmtx_v1{current_version, txn.get_rlptx(), *base_fee_per_gas}}; action(std::vector{}, get_self(), "evmtx"_n, event).send(); } LOGTIME("EVM END"); @@ -901,10 +902,9 @@ void evm_contract::setgasparam(uint64_t gas_txnewaccount, gas_sset); } -void evm_contract::setgasprices(uint64_t storage_price, uint64_t overhead_price) { +void evm_contract::setgasprices(const gas_prices& prices) { require_auth(get_self()); - _config->set_storage_price(storage_price); - _config->set_overhead_price(overhead_price); + _config->set_gas_prices(prices); } } //evm_runtime diff --git a/src/config_wrapper.cpp b/src/config_wrapper.cpp index 18e7e9cc..c0c06749 100644 --- a/src/config_wrapper.cpp +++ b/src/config_wrapper.cpp @@ -1,6 +1,5 @@ -#pragma once -#include #include +#include namespace evm_runtime { @@ -10,11 +9,11 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se _cached_config = _config.get(); } if (!_cached_config.evm_version.has_value()) { - _cached_config.evm_version = value_promoter{}; + _cached_config.evm_version = value_promoter_uint64_t{}; // Don't set dirty because action can be read-only. } if (!_cached_config.consensus_parameter.has_value()) { - _cached_config.consensus_parameter = value_promoter{}; + _cached_config.consensus_parameter = value_promoter_consensus_parameter_data_type{}; // Don't set dirty because action can be read-only. } if (!_cached_config.token_contract.has_value()) { @@ -24,11 +23,8 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se if (!_cached_config.queue_front_block.has_value()) { _cached_config.queue_front_block = 0; } - if (!_cached_config.overhead_price.has_value()) { - _cached_config.overhead_price = value_promoter{}; - } - if (!_cached_config.storage_price.has_value()) { - _cached_config.storage_price = value_promoter{}; + if (!_cached_config.gas_prices.has_value()) { + _cached_config.gas_prices = value_promoter_gas_prices{}; } } @@ -95,28 +91,25 @@ void config_wrapper::set_gas_price(uint64_t gas_price) { set_dirty(); } -uint64_t config_wrapper::get_overhead_price()const { +gas_prices config_wrapper::get_gas_prices()const { // should not happen - eosio::check(_cached_config.overhead_price.has_value(), "overhead_price not exist"); - return _cached_config.overhead_price->get_value(_cached_config.genesis_time, get_current_time()); -} - -void config_wrapper::set_overhead_price(uint64_t price) { - _cached_config.overhead_price->update([&](auto& v) { - v = price; - }, _cached_config.genesis_time, get_current_time()); - set_dirty(); + eosio::check(_cached_config.gas_prices.has_value(), "gas_prices not exist"); + return _cached_config.gas_prices->get_value(_cached_config.genesis_time, get_current_time()); } -uint64_t config_wrapper::get_storage_price()const { +gas_prices config_wrapper::get_gas_prices_and_maybe_promote() { // should not happen - eosio::check(_cached_config.storage_price.has_value(), "storage_price not exist"); - return _cached_config.storage_price->get_value(_cached_config.genesis_time, get_current_time()); + eosio::check(_cached_config.gas_prices.has_value(), "gas_prices not exist"); + auto pair = _cached_config.gas_prices->get_value_and_maybe_promote(_cached_config.genesis_time, get_current_time()); + if (pair.second) { + set_dirty(); + } + return pair.first; } -void config_wrapper::set_storage_price(uint64_t price) { - _cached_config.storage_price->update([&](auto& v) { - v = price; +void config_wrapper::set_gas_prices(const gas_prices& prices) { + _cached_config.gas_prices->update([&](gas_prices& v) { + v = prices; }, _cached_config.genesis_time, get_current_time()); set_dirty(); } diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index fc186cdf..239c8fec 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -104,14 +104,9 @@ namespace fc { namespace raw { tmp.queue_front_block.emplace(queue_front_block); } if(ds.remaining()) { - uint32_t overhead_price; - fc::raw::unpack(ds, overhead_price); - tmp.overhead_price.emplace(overhead_price); - } - if(ds.remaining()) { - uint32_t storage_price; - fc::raw::unpack(ds, storage_price); - tmp.storage_price.emplace(storage_price); + evm_test::gas_prices_type prices; + fc::raw::unpack(ds, prices); + tmp.gas_prices.emplace(prices); } } FC_RETHROW_EXCEPTIONS(warn, "error unpacking partial_account_table_row") } @@ -520,9 +515,9 @@ transaction_trace_ptr basic_evm_tester::addopenbal(name account, const intx::uin mvo()("account", account)("delta",d)("subtract",subtract)); } -transaction_trace_ptr basic_evm_tester::setgasprices(uint64_t storage_price, uint64_t overhead_price, name actor) { +transaction_trace_ptr basic_evm_tester::setgasprices(const gas_prices_t& prices, name actor) { return basic_evm_tester::push_action(evm_account_name, "setgasprices"_n, actor, - mvo()("storage_price", storage_price)("overhead_price",overhead_price)); + mvo()("prices", prices)); } evmc::address basic_evm_tester::deploy_contract(evm_eoa& eoa, evmc::bytes bytecode) @@ -827,7 +822,7 @@ void basic_evm_tester::check_balances() { } silkworm::Transaction basic_evm_tester::get_tx_from_trace(const bytes& v) { - auto evmtx = get_event_from_trace(v); + auto evmtx = get_event_from_trace(v); BOOST_REQUIRE(evmtx.eos_evm_version == 1); silkworm::Transaction tx; diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index aff241ce..a01015f6 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -54,19 +54,22 @@ void to_variant(const evmc::address& o, fc::variant& v); namespace evm_test { -struct evmtx_v0 { +struct evmtx_base { uint64_t eos_evm_version; bytes rlptx; - uint64_t base_fee_per_gas; }; -struct evmtx_v1 : evmtx_v0 { +struct evmtx_v1 : evmtx_base { + uint64_t base_fee_per_gas; +}; + +struct evmtx_v3 : evmtx_base { uint64_t overhead_price; uint64_t storage_price; }; -using evmtx_type = std::variant; +using evmtx_type = std::variant; struct evm_version_type { struct pending { @@ -96,6 +99,22 @@ struct consensus_parameter_type { std::optional pending; consensus_parameter_data_type current; }; + +struct gas_prices_t { + uint64_t overhead_price{0}; + uint64_t storage_price{0}; +}; + +struct gas_prices_type { + struct pending { + gas_prices_t value; + fc::time_point time; + }; + + std::optional pending_value; + gas_prices_t cached_value{}; +}; + struct config_table_row { unsigned_int version; @@ -109,9 +128,7 @@ struct config_table_row std::optional consensus_parameter; std::optional token_contract; std::optional queue_front_block; - std::optional overhead_price; - std::optional storage_price; - + std::optional gas_prices; }; struct config2_table_row @@ -221,6 +238,9 @@ struct price_queue { FC_REFLECT(evm_test::price_queue, (block)(price)) FC_REFLECT(evm_test::evm_version_type, (pending_version)(cached_version)) FC_REFLECT(evm_test::evm_version_type::pending, (version)(time)) +FC_REFLECT(evm_test::gas_prices_t, (overhead_price)(storage_price)) +FC_REFLECT(evm_test::gas_prices_type, (pending_value)(cached_value)) +FC_REFLECT(evm_test::gas_prices_type::pending, (value)(time)) FC_REFLECT(evm_test::config2_table_row,(next_account_id)) FC_REFLECT(evm_test::balance_and_dust, (balance)(dust)); FC_REFLECT(evm_test::account_object, (id)(address)(nonce)(balance)) @@ -235,10 +255,11 @@ FC_REFLECT(evm_test::message_receiver, (account)(handler)(min_fee)(flags)); FC_REFLECT(evm_test::bridge_message_v0, (receiver)(sender)(timestamp)(value)(data)); FC_REFLECT(evm_test::gcstore, (id)(storage_id)); FC_REFLECT(evm_test::account_code, (id)(ref_count)(code)(code_hash)); -FC_REFLECT(evm_test::evmtx_v0, (eos_evm_version)(rlptx)(base_fee_per_gas)); -FC_REFLECT_DERIVED(evm_test::evmtx_v1, (evm_test::evmtx_v0), (overhead_price)(storage_price)); +FC_REFLECT(evm_test::evmtx_base, (eos_evm_version)(rlptx)); +FC_REFLECT_DERIVED(evm_test::evmtx_v1, (evm_test::evmtx_base), (base_fee_per_gas)); +FC_REFLECT_DERIVED(evm_test::evmtx_v3, (evm_test::evmtx_base), (overhead_price)(storage_price)); -FC_REFLECT(evm_test::consensus_parameter_type, (pending)(current)); +FC_REFLECT(evm_test::consensus_parameter_type, (current)(pending)); FC_REFLECT(evm_test::pending_consensus_parameter_data_type, (data)(pending_time)); FC_REFLECT(evm_test::consensus_parameter_data_v0, (gas_parameter)); FC_REFLECT(evm_test::gas_parameter_type, (gas_txnewaccount)(gas_newaccount)(gas_txcreate)(gas_codedeposit)(gas_sset)); @@ -469,7 +490,7 @@ class basic_evm_tester : public evm_validating_tester transaction_trace_ptr addevmbal(uint64_t id, const intx::uint256& delta, bool subtract, name actor=evm_account_name); transaction_trace_ptr addopenbal(name account, const intx::uint256& delta, bool subtract, name actor=evm_account_name); - transaction_trace_ptr setgasprices(uint64_t storage_price, uint64_t overhead_price, name actor=evm_account_name); + transaction_trace_ptr setgasprices(const gas_prices_t& prices, name actor=evm_account_name); void open(name owner); void close(name owner); diff --git a/tests/version_tests.cpp b/tests/version_tests.cpp index 85a38c07..6be98773 100644 --- a/tests/version_tests.cpp +++ b/tests/version_tests.cpp @@ -155,9 +155,9 @@ BOOST_FIXTURE_TEST_CASE(set_version, version_tester) try { auto evmtx_v = fc::raw::unpack( trace->action_traces[3].act.data.data(), trace->action_traces[3].act.data.size()); - BOOST_REQUIRE(std::holds_alternative(evmtx_v)); + BOOST_REQUIRE(std::holds_alternative(evmtx_v)); - const auto &evmtx = std::get(evmtx_v); + const auto &evmtx = std::get(evmtx_v); BOOST_CHECK_EQUAL(evmtx.eos_evm_version, 1); BOOST_CHECK_EQUAL(evmtx.base_fee_per_gas, config.gas_price); @@ -301,7 +301,7 @@ BOOST_FIXTURE_TEST_CASE(traces_in_different_eosevm_version, version_tester) try /// change EOS EVM VERSION => 3 /// ///////////////////////////////////// - setgasprices(5, 6); + setgasprices(gas_prices_t{.overhead_price=5, .storage_price=6}); setversion(3, evm_account_name); produce_blocks(2); @@ -317,10 +317,16 @@ BOOST_FIXTURE_TEST_CASE(traces_in_different_eosevm_version, version_tester) try BOOST_REQUIRE(trace->action_traces[3].act.account == evm_account_name); BOOST_REQUIRE(trace->action_traces[3].act.name == "evmtx"_n); - auto event_v1 = get_event_from_trace(trace->action_traces[3].act.data); - BOOST_REQUIRE(event_v1.eos_evm_version == 3); - BOOST_REQUIRE(event_v1.storage_price == 5); - BOOST_REQUIRE(event_v1.overhead_price == 6); + auto event_v3 = get_event_from_trace(trace->action_traces[3].act.data); + BOOST_REQUIRE(event_v3.eos_evm_version == 3); + BOOST_REQUIRE(event_v3.overhead_price == 5); + BOOST_REQUIRE(event_v3.storage_price == 6); + + config = get_config(); + BOOST_REQUIRE(config.gas_prices.has_value()); + BOOST_REQUIRE(!config.gas_prices->pending_value.has_value()); + BOOST_REQUIRE(config.gas_prices->cached_value.overhead_price == 5); + BOOST_REQUIRE(config.gas_prices->cached_value.storage_price == 6); } FC_LOG_AND_RETHROW() From 867ce30f164fe4bb586a034c18a87926217a9d10 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 1 Aug 2024 20:39:41 -0300 Subject: [PATCH 07/11] Use queue mechanism when changing gas_prices --- include/evm_runtime/config_wrapper.hpp | 11 ++- include/evm_runtime/evm_contract.hpp | 4 +- include/evm_runtime/tables.hpp | 23 ++++-- src/actions.cpp | 17 +++- src/config_wrapper.cpp | 71 ++++++++++------ tests/basic_evm_tester.cpp | 13 ++- tests/basic_evm_tester.hpp | 26 +++--- tests/gas_fee_tests.cpp | 109 +++++++++++++++++++++++++ tests/version_tests.cpp | 10 +-- 9 files changed, 221 insertions(+), 63 deletions(-) diff --git a/include/evm_runtime/config_wrapper.hpp b/include/evm_runtime/config_wrapper.hpp index 1299b428..d0ab67a6 100644 --- a/include/evm_runtime/config_wrapper.hpp +++ b/include/evm_runtime/config_wrapper.hpp @@ -27,14 +27,19 @@ struct config_wrapper { const eosio::asset& get_ingress_bridge_fee()const; void set_ingress_bridge_fee(const eosio::asset& ingress_bridge_fee); - gas_prices get_gas_prices()const; - gas_prices get_gas_prices_and_maybe_promote(); - void set_gas_prices(const gas_prices& price); + gas_prices_type get_gas_prices()const; + void set_gas_prices(const gas_prices_type& price); uint64_t get_gas_price()const; void set_gas_price(uint64_t gas_price); + template + void enqueue(Func&& update_fnc); void enqueue_gas_price(uint64_t gas_price); + void enqueue_gas_prices(const gas_prices_type& prices); + + template + void process_queue(Func&& update_func); void process_price_queue(); uint32_t get_miner_cut()const; diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index dfaa1d11..b01b979b 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -17,7 +17,7 @@ using namespace eosio; namespace evm_runtime { -struct gas_prices; +struct gas_prices_type; class [[eosio::contract]] evm_contract : public contract { @@ -89,7 +89,7 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void updtgasparam(eosio::asset ram_price_mb, uint64_t gas_price); [[eosio::action]] void setgasparam(uint64_t gas_txnewaccount, uint64_t gas_newaccount, uint64_t gas_txcreate, uint64_t gas_codedeposit, uint64_t gas_sset); - [[eosio::action]] void setgasprices(const gas_prices& prices); + [[eosio::action]] void setgasprices(const gas_prices_type& prices); // Events [[eosio::action]] void evmtx(eosio::ignore event){ diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index e0ed0e5c..8bd30290 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -246,14 +246,15 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config2 EOSLIB_SERIALIZE(config2, (next_account_id)); }; -struct gas_prices { +struct gas_prices_type { uint64_t overhead_price{0}; uint64_t storage_price{0}; }; -VALUE_PROMOTER(uint64_t); +using evm_version_type = uint64_t; + +VALUE_PROMOTER(evm_version_type); VALUE_PROMOTER_REV(consensus_parameter_data_type); -VALUE_PROMOTER(gas_prices); struct [[eosio::table]] [[eosio::contract("evm_contract")]] config { @@ -264,11 +265,11 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config uint64_t gas_price = 0; uint32_t miner_cut = 0; uint32_t status = 0; // <- bit mask values from status_flags - binary_extension evm_version; + binary_extension evm_version; binary_extension consensus_parameter; binary_extension token_contract; // <- default(unset) means eosio.token binary_extension queue_front_block; - binary_extension gas_prices; + binary_extension gas_prices; EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version)(consensus_parameter)(token_contract)(queue_front_block)(gas_prices)); }; @@ -282,7 +283,17 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] price_queue EOSLIB_SERIALIZE(price_queue, (block)(price)); }; - typedef eosio::multi_index<"pricequeue"_n, price_queue> price_queue_table; +struct [[eosio::table]] [[eosio::contract("evm_contract")]] prices_queue +{ + uint64_t block; + gas_prices_type prices; + + uint64_t primary_key()const { return block; } + + EOSLIB_SERIALIZE(prices_queue, (block)(prices)); +}; +typedef eosio::multi_index<"pricesqueue"_n, prices_queue> prices_queue_table; + } //namespace evm_runtime diff --git a/src/actions.cpp b/src/actions.cpp index 8f61efc2..fd67e941 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -457,7 +457,6 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const "unexpected error: EVM contract generated inline pushtx without setting itself as the miner"); auto current_version = _config->get_evm_version_and_maybe_promote(); - auto gas_prices = _config->get_gas_prices_and_maybe_promote(); std::pair gas_param_pair = _config->get_consensus_param_and_maybe_promote(); if (gas_param_pair.second) { @@ -473,8 +472,13 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const Block block; std::optional base_fee_per_gas; + auto gas_prices = _config->get_gas_prices(); if (current_version >= 1) { - base_fee_per_gas = _config->get_gas_price(); + if( current_version >= 3) { + //base_fee_per_gas = f(gas_prices, min_inclusion_price) + } else { + base_fee_per_gas = _config->get_gas_price(); + } } eosevm::prepare_block_header(block.header, bm, get_self().value, @@ -902,9 +906,14 @@ void evm_contract::setgasparam(uint64_t gas_txnewaccount, gas_sset); } -void evm_contract::setgasprices(const gas_prices& prices) { +void evm_contract::setgasprices(const gas_prices_type& prices) { require_auth(get_self()); - _config->set_gas_prices(prices); + auto current_version = _config->get_evm_version_and_maybe_promote(); + if(current_version >= 3) { + _config->enqueue_gas_prices(prices); + } else { + _config->set_gas_prices(prices); + } } } //evm_runtime diff --git a/src/config_wrapper.cpp b/src/config_wrapper.cpp index c0c06749..66da7bec 100644 --- a/src/config_wrapper.cpp +++ b/src/config_wrapper.cpp @@ -9,7 +9,7 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se _cached_config = _config.get(); } if (!_cached_config.evm_version.has_value()) { - _cached_config.evm_version = value_promoter_uint64_t{}; + _cached_config.evm_version = value_promoter_evm_version_type{}; // Don't set dirty because action can be read-only. } if (!_cached_config.consensus_parameter.has_value()) { @@ -24,7 +24,7 @@ config_wrapper::config_wrapper(eosio::name self) : _self(self), _config(self, se _cached_config.queue_front_block = 0; } if (!_cached_config.gas_prices.has_value()) { - _cached_config.gas_prices = value_promoter_gas_prices{}; + _cached_config.gas_prices = gas_prices_type{}; } } @@ -91,31 +91,18 @@ void config_wrapper::set_gas_price(uint64_t gas_price) { set_dirty(); } -gas_prices config_wrapper::get_gas_prices()const { - // should not happen - eosio::check(_cached_config.gas_prices.has_value(), "gas_prices not exist"); - return _cached_config.gas_prices->get_value(_cached_config.genesis_time, get_current_time()); -} - -gas_prices config_wrapper::get_gas_prices_and_maybe_promote() { - // should not happen - eosio::check(_cached_config.gas_prices.has_value(), "gas_prices not exist"); - auto pair = _cached_config.gas_prices->get_value_and_maybe_promote(_cached_config.genesis_time, get_current_time()); - if (pair.second) { - set_dirty(); - } - return pair.first; +gas_prices_type config_wrapper::get_gas_prices()const { + return *_cached_config.gas_prices; } -void config_wrapper::set_gas_prices(const gas_prices& prices) { - _cached_config.gas_prices->update([&](gas_prices& v) { - v = prices; - }, _cached_config.genesis_time, get_current_time()); +void config_wrapper::set_gas_prices(const gas_prices_type& prices) { + _cached_config.gas_prices = prices; set_dirty(); } -void config_wrapper::enqueue_gas_price(uint64_t gas_price) { - price_queue_table queue(_self, _self.value); +template +void config_wrapper::enqueue(Func&& update_fnc) { + Q queue(_self, _self.value); auto activation_time = get_current_time() + eosio::seconds(grace_period_seconds); eosevm::block_mapping bm(get_genesis_time().sec_since_epoch()); @@ -127,7 +114,7 @@ void config_wrapper::enqueue_gas_price(uint64_t gas_price) { eosio::check(activation_block_num >= it->block, "internal error"); if(activation_block_num == it->block) { queue.modify(*it, eosio::same_payer, [&](auto& el) { - el.price = gas_price; + update_fnc(el); }); return; } @@ -135,7 +122,7 @@ void config_wrapper::enqueue_gas_price(uint64_t gas_price) { queue.emplace(_self, [&](auto& el) { el.block = activation_block_num; - el.price = gas_price; + update_fnc(el); }); if( _cached_config.queue_front_block.value() == 0 ) { @@ -143,12 +130,38 @@ void config_wrapper::enqueue_gas_price(uint64_t gas_price) { } } +void config_wrapper::enqueue_gas_price(uint64_t gas_price) { + enqueue([&](auto& el){ + el.price = gas_price; + }); +} + +void config_wrapper::enqueue_gas_prices(const gas_prices_type& prices) { + enqueue([&](auto& el){ + el.prices = prices; + }); +} + void config_wrapper::set_queue_front_block(uint32_t block_num) { _cached_config.queue_front_block = block_num; set_dirty(); } + void config_wrapper::process_price_queue() { + if( get_evm_version() >= 3) { + process_queue([&](const auto& row){ + set_gas_prices(row.prices); + }); + } else { + process_queue([&](const auto& row){ + set_gas_price(row.price); + }); + } +} + +template +void config_wrapper::process_queue(Func&& update_func) { eosevm::block_mapping bm(get_genesis_time().sec_since_epoch()); auto current_block_num = bm.timestamp_to_evm_block_num(get_current_time().time_since_epoch().count()); @@ -157,10 +170,10 @@ void config_wrapper::process_price_queue() { return; } - price_queue_table queue(_self, _self.value); + Q queue(_self, _self.value); auto it = queue.begin(); while( it != queue.end() && current_block_num >= it->block ) { - set_gas_price(it->price); + update_func(*it); it = queue.erase(it); set_queue_front_block(it != queue.end() ? it->block : 0); } @@ -219,7 +232,9 @@ void config_wrapper::set_fee_parameters(const fee_parameters& fee_params, { if (fee_params.gas_price.has_value()) { eosio::check(*fee_params.gas_price >= one_gwei, "gas_price must >= 1Gwei"); - if(get_evm_version() >= 1) { + auto current_version = get_evm_version_and_maybe_promote(); + if( current_version >= 1 ) { + eosio::check(current_version < 3, "can't set gas_price"); enqueue_gas_price(*fee_params.gas_price); } else { set_gas_price(*fee_params.gas_price); @@ -251,7 +266,9 @@ void config_wrapper::set_fee_parameters(const fee_parameters& fee_params, } void config_wrapper::update_consensus_parameters(eosio::asset ram_price_mb, uint64_t gas_price) { + eosio::check(get_evm_version() < 3, "unable to set params"); + //TODO: should we allow to call this when version>=3 eosio::check(ram_price_mb.symbol == get_token_symbol(), "invalid price symbol"); eosio::check(gas_price >= one_gwei, "gas_price must >= 1Gwei"); diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 239c8fec..e05a0c75 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -515,7 +515,7 @@ transaction_trace_ptr basic_evm_tester::addopenbal(name account, const intx::uin mvo()("account", account)("delta",d)("subtract",subtract)); } -transaction_trace_ptr basic_evm_tester::setgasprices(const gas_prices_t& prices, name actor) { +transaction_trace_ptr basic_evm_tester::setgasprices(const gas_prices_type& prices, name actor) { return basic_evm_tester::push_action(evm_account_name, "setgasprices"_n, actor, mvo()("prices", prices)); } @@ -790,6 +790,17 @@ bool basic_evm_tester::scan_price_queue(std::function visitor return true; } +bool basic_evm_tester::scan_prices_queue(std::function visitor) const +{ + static constexpr eosio::chain::name prices_queue_table_name = "pricesqueue"_n; + + scan_table( + prices_queue_table_name, evm_account_name, [&visitor](prices_queue&& row) { return visitor(row); } + ); + + return true; +} + asset basic_evm_tester::get_eos_balance( const account_name& act ) { vector data = get_row_by_account( "eosio.token"_n, act, "accounts"_n, name(native_symbol.to_symbol_code().value) ); return data.empty() ? asset(0, native_symbol) : fc::raw::unpack(data); diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index a01015f6..9db0f0f3 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -100,21 +100,11 @@ struct consensus_parameter_type { consensus_parameter_data_type current; }; -struct gas_prices_t { +struct gas_prices_type { uint64_t overhead_price{0}; uint64_t storage_price{0}; }; -struct gas_prices_type { - struct pending { - gas_prices_t value; - fc::time_point time; - }; - - std::optional pending_value; - gas_prices_t cached_value{}; -}; - struct config_table_row { unsigned_int version; @@ -233,14 +223,18 @@ struct price_queue { uint64_t price; }; +struct prices_queue { + uint64_t block; + gas_prices_type prices; +}; + } // namespace evm_test FC_REFLECT(evm_test::price_queue, (block)(price)) +FC_REFLECT(evm_test::prices_queue, (block)(prices)) +FC_REFLECT(evm_test::gas_prices_type, (overhead_price)(storage_price)) FC_REFLECT(evm_test::evm_version_type, (pending_version)(cached_version)) FC_REFLECT(evm_test::evm_version_type::pending, (version)(time)) -FC_REFLECT(evm_test::gas_prices_t, (overhead_price)(storage_price)) -FC_REFLECT(evm_test::gas_prices_type, (pending_value)(cached_value)) -FC_REFLECT(evm_test::gas_prices_type::pending, (value)(time)) FC_REFLECT(evm_test::config2_table_row,(next_account_id)) FC_REFLECT(evm_test::balance_and_dust, (balance)(dust)); FC_REFLECT(evm_test::account_object, (id)(address)(nonce)(balance)) @@ -420,6 +414,7 @@ class basic_evm_tester : public evm_validating_tester static constexpr uint32_t suggested_miner_cut = 10'000; // 10% static constexpr uint64_t suggested_ingress_bridge_fee_amount = 70; // 0.0070 EOS static constexpr uint64_t price_queue_grace_period = 180; // 180 seconds + static constexpr uint64_t prices_queue_grace_period = 180; // 180 seconds const symbol native_symbol; @@ -490,7 +485,7 @@ class basic_evm_tester : public evm_validating_tester transaction_trace_ptr addevmbal(uint64_t id, const intx::uint256& delta, bool subtract, name actor=evm_account_name); transaction_trace_ptr addopenbal(name account, const intx::uint256& delta, bool subtract, name actor=evm_account_name); - transaction_trace_ptr setgasprices(const gas_prices_t& prices, name actor=evm_account_name); + transaction_trace_ptr setgasprices(const gas_prices_type& prices, name actor=evm_account_name); void open(name owner); void close(name owner); @@ -540,6 +535,7 @@ class basic_evm_tester : public evm_validating_tester bool scan_account_code(std::function visitor) const; void scan_balances(std::function visitor) const; bool scan_price_queue(std::function visitor) const; + bool scan_prices_queue(std::function visitor) const; intx::uint128 tx_data_cost(const silkworm::Transaction& txn) const; diff --git a/tests/gas_fee_tests.cpp b/tests/gas_fee_tests.cpp index cbe5cebd..6698c4a6 100644 --- a/tests/gas_fee_tests.cpp +++ b/tests/gas_fee_tests.cpp @@ -406,6 +406,115 @@ try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(set_gas_prices_queue, gas_fee_evm_tester) +try { + init(); + + auto cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), 0); + + eosevm::block_mapping bm(cfg.genesis_time.sec_since_epoch()); + + setversion(3, evm_account_name); + produce_blocks(2); + + const auto one_gwei = 1'000'000'000ull; + const auto ten_gwei = 10'000'000'000ull; + + auto get_prices_queue = [&]() -> std::vector { + std::vector queue; + scan_prices_queue([&](prices_queue&& row) -> bool { + queue.push_back(row); + return false; + }); + return queue; + }; + + auto trigger_prices_queue_processing = [&](){ + transfer_token("alice"_n, evm_account_name, make_asset(1), evm_account_name.to_string()); + }; + + // Queue change of gas_prices to overhead_price=10Gwei storage_price=1Gwei + setgasprices({.overhead_price = ten_gwei, .storage_price = one_gwei}); + auto t1 = (control->pending_block_time()+fc::seconds(prices_queue_grace_period)).time_since_epoch().count(); + auto b1 = bm.timestamp_to_evm_block_num(t1)+1; + + auto q = get_prices_queue(); + BOOST_CHECK_EQUAL(q.size(), 1); + BOOST_CHECK_EQUAL(q[0].block, b1); + BOOST_CHECK_EQUAL(q[0].prices.overhead_price, ten_gwei); + BOOST_CHECK_EQUAL(q[0].prices.storage_price, one_gwei); + + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), b1); + + produce_blocks(100); + + // Queue change of gas_price to overhead_price=30Gwei storage_price=10Gwei + setgasprices({.overhead_price = 3*ten_gwei, .storage_price=ten_gwei}); + auto t2 = (control->pending_block_time()+fc::seconds(prices_queue_grace_period)).time_since_epoch().count(); + auto b2 = bm.timestamp_to_evm_block_num(t2)+1; + + q = get_prices_queue(); + BOOST_CHECK_EQUAL(q.size(), 2); + BOOST_CHECK_EQUAL(q[0].block, b1); + BOOST_CHECK_EQUAL(q[0].prices.overhead_price, ten_gwei); + BOOST_CHECK_EQUAL(q[0].prices.storage_price, one_gwei); + BOOST_CHECK_EQUAL(q[1].block, b2); + BOOST_CHECK_EQUAL(q[1].prices.overhead_price, 3*ten_gwei); + BOOST_CHECK_EQUAL(q[1].prices.storage_price, ten_gwei); + + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), b1); + + // Overwrite queue change (same block) overhead_price=20Gwei, storage_price=5Gwei + setgasprices({.overhead_price = 2*ten_gwei, .storage_price=5*one_gwei}); + + q = get_prices_queue(); + BOOST_CHECK_EQUAL(q.size(), 2); + BOOST_CHECK_EQUAL(q[0].block, b1); + BOOST_CHECK_EQUAL(q[0].prices.overhead_price, ten_gwei); + BOOST_CHECK_EQUAL(q[0].prices.storage_price, one_gwei); + BOOST_CHECK_EQUAL(q[1].block, b2); + BOOST_CHECK_EQUAL(q[1].prices.overhead_price, 2*ten_gwei); + BOOST_CHECK_EQUAL(q[1].prices.storage_price, 5*one_gwei); + + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), b1); + + while(bm.timestamp_to_evm_block_num(control->pending_block_time().time_since_epoch().count()) != b1) { + produce_blocks(1); + } + trigger_prices_queue_processing(); + + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.gas_prices->overhead_price, ten_gwei); + BOOST_CHECK_EQUAL(cfg.gas_prices->storage_price, one_gwei); + + q = get_prices_queue(); + BOOST_CHECK_EQUAL(q.size(), 1); + BOOST_CHECK_EQUAL(q[0].block, b2); + BOOST_CHECK_EQUAL(q[0].prices.overhead_price, 2*ten_gwei); + BOOST_CHECK_EQUAL(q[0].prices.storage_price, 5*one_gwei); + + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), b2); + + while(bm.timestamp_to_evm_block_num(control->pending_block_time().time_since_epoch().count()) != b2) { + produce_blocks(1); + } + trigger_prices_queue_processing(); + + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.gas_prices->overhead_price, 2*ten_gwei); + BOOST_CHECK_EQUAL(cfg.gas_prices->storage_price, 5*one_gwei); + + q = get_prices_queue(); + BOOST_CHECK_EQUAL(q.size(), 0); + + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), 0); +} +FC_LOG_AND_RETHROW() + BOOST_FIXTURE_TEST_CASE(miner_cut_calculation_v1, gas_fee_evm_tester) try { static constexpr uint64_t base_gas_price = 300'000'000'000; // 300 gwei diff --git a/tests/version_tests.cpp b/tests/version_tests.cpp index 6be98773..c052b1e9 100644 --- a/tests/version_tests.cpp +++ b/tests/version_tests.cpp @@ -301,12 +301,13 @@ BOOST_FIXTURE_TEST_CASE(traces_in_different_eosevm_version, version_tester) try /// change EOS EVM VERSION => 3 /// ///////////////////////////////////// - setgasprices(gas_prices_t{.overhead_price=5, .storage_price=6}); + setgasprices({.overhead_price=5, .storage_price=6}); setversion(3, evm_account_name); - produce_blocks(2); + produce_blocks(2*180); // Test traces of `handle_evm_transfer` (EVM VERSION=3) trace = transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x()); + BOOST_REQUIRE(trace->action_traces.size() == 4); BOOST_REQUIRE(trace->action_traces[0].act.account == token_account_name); BOOST_REQUIRE(trace->action_traces[0].act.name == "transfer"_n); @@ -324,9 +325,8 @@ BOOST_FIXTURE_TEST_CASE(traces_in_different_eosevm_version, version_tester) try config = get_config(); BOOST_REQUIRE(config.gas_prices.has_value()); - BOOST_REQUIRE(!config.gas_prices->pending_value.has_value()); - BOOST_REQUIRE(config.gas_prices->cached_value.overhead_price == 5); - BOOST_REQUIRE(config.gas_prices->cached_value.storage_price == 6); + BOOST_REQUIRE(config.gas_prices->overhead_price == 5); + BOOST_REQUIRE(config.gas_prices->storage_price == 6); } FC_LOG_AND_RETHROW() From 86f48e5da3a48a63e677349a549efff12eabc8b4 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Tue, 6 Aug 2024 21:15:53 -0300 Subject: [PATCH 08/11] Check price queue is empty when switching to v3 --- src/config_wrapper.cpp | 1 + tests/gas_fee_tests.cpp | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/config_wrapper.cpp b/src/config_wrapper.cpp index 66da7bec..274c6203 100644 --- a/src/config_wrapper.cpp +++ b/src/config_wrapper.cpp @@ -219,6 +219,7 @@ uint64_t config_wrapper::get_evm_version_and_maybe_promote() { void config_wrapper::set_evm_version(uint64_t new_version) { eosio::check(new_version <= eosevm::max_eos_evm_version, "Unsupported version"); + eosio::check(new_version != 3 || _cached_config.queue_front_block.value() == 0, "price queue must be empty"); auto current_version = get_evm_version_and_maybe_promote(); eosio::check(new_version > current_version, "new version must be greater than the active one"); _cached_config.evm_version->update([&](auto& v) { diff --git a/tests/gas_fee_tests.cpp b/tests/gas_fee_tests.cpp index 6698c4a6..3572d910 100644 --- a/tests/gas_fee_tests.cpp +++ b/tests/gas_fee_tests.cpp @@ -413,11 +413,6 @@ try { auto cfg = get_config(); BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), 0); - eosevm::block_mapping bm(cfg.genesis_time.sec_since_epoch()); - - setversion(3, evm_account_name); - produce_blocks(2); - const auto one_gwei = 1'000'000'000ull; const auto ten_gwei = 10'000'000'000ull; @@ -434,6 +429,24 @@ try { transfer_token("alice"_n, evm_account_name, make_asset(1), evm_account_name.to_string()); }; + eosevm::block_mapping bm(cfg.genesis_time.sec_since_epoch()); + + setversion(2, evm_account_name); + produce_blocks(2); + + // Price queue must be empty before switching to v3 + setfeeparams({.gas_price = ten_gwei}); + BOOST_REQUIRE_EXCEPTION(setversion(3, evm_account_name), + eosio_assert_message_exception, + eosio_assert_message_is("price queue must be empty")); + produce_blocks(400); + trigger_prices_queue_processing(); + cfg = get_config(); + BOOST_CHECK_EQUAL(cfg.queue_front_block.value(), 0); + + setversion(3, evm_account_name); + produce_blocks(2); + // Queue change of gas_prices to overhead_price=10Gwei storage_price=1Gwei setgasprices({.overhead_price = ten_gwei, .storage_price = one_gwei}); auto t1 = (control->pending_block_time()+fc::seconds(prices_queue_grace_period)).time_since_epoch().count(); From 2ebca8f0dd65796d8437a3a4bef216f52ae35b11 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 7 Aug 2024 20:10:39 -0300 Subject: [PATCH 09/11] Add --fix-missing when installing cdt and leap deb packages --- .github/workflows/contract.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index 8ab8b550..e178063d 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -48,7 +48,7 @@ jobs: file: 'cdt_.*amd64.deb' - name: Install CDT - run: sudo apt-get install -y ./cdt*.deb + run: sudo apt-get install -y --fix-missing ./cdt*.deb - name: Build EOS EVM Contract run: .github/workflows/build-contract.sh @@ -74,7 +74,7 @@ jobs: artifact-name: leap-dev-ubuntu22-amd64 - name: Install Leap - run: sudo apt-get install -y ./leap*.deb + run: sudo apt-get install -y --fix-missing ./leap*.deb - name: Build EOS EVM Contract Tests run: .github/workflows/build-contract-test.sh From 46604b265450becae59b43bfc92cf64745ac1c96 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 7 Aug 2024 21:30:20 -0300 Subject: [PATCH 10/11] apt-get update and apt-get upgrade to contract workflow --- .github/workflows/contract.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index e178063d..90aa76e6 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -48,7 +48,9 @@ jobs: file: 'cdt_.*amd64.deb' - name: Install CDT - run: sudo apt-get install -y --fix-missing ./cdt*.deb + run: | + sudo apt-get update && apt-get upgrade -y + sudo apt-get install -y ./cdt*.deb - name: Build EOS EVM Contract run: .github/workflows/build-contract.sh @@ -74,7 +76,9 @@ jobs: artifact-name: leap-dev-ubuntu22-amd64 - name: Install Leap - run: sudo apt-get install -y --fix-missing ./leap*.deb + run: | + sudo apt-get update && apt-get upgrade -y + sudo apt-get install -y ./leap*.deb - name: Build EOS EVM Contract Tests run: .github/workflows/build-contract-test.sh From d50cf93388f29bd823cb5394087652ad9f58fbf2 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 7 Aug 2024 21:36:26 -0300 Subject: [PATCH 11/11] Fix contract workflow --- .github/workflows/contract.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/contract.yml b/.github/workflows/contract.yml index 90aa76e6..b3b55016 100644 --- a/.github/workflows/contract.yml +++ b/.github/workflows/contract.yml @@ -49,7 +49,7 @@ jobs: - name: Install CDT run: | - sudo apt-get update && apt-get upgrade -y + sudo apt-get update && sudo apt-get upgrade -y sudo apt-get install -y ./cdt*.deb - name: Build EOS EVM Contract @@ -77,7 +77,7 @@ jobs: - name: Install Leap run: | - sudo apt-get update && apt-get upgrade -y + sudo apt-get update && sudo apt-get upgrade -y sudo apt-get install -y ./leap*.deb - name: Build EOS EVM Contract Tests