Skip to content

Commit

Permalink
Use queue mechanism when changing gas_prices
Browse files Browse the repository at this point in the history
  • Loading branch information
elmato committed Aug 1, 2024
1 parent 8625534 commit 867ce30
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 63 deletions.
11 changes: 8 additions & 3 deletions include/evm_runtime/config_wrapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename Q, typename Func>
void enqueue(Func&& update_fnc);
void enqueue_gas_price(uint64_t gas_price);
void enqueue_gas_prices(const gas_prices_type& prices);

template <typename Q, typename Func>
void process_queue(Func&& update_func);
void process_price_queue();

uint32_t get_miner_cut()const;
Expand Down
4 changes: 2 additions & 2 deletions include/evm_runtime/evm_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ using namespace eosio;

namespace evm_runtime {

struct gas_prices;
struct gas_prices_type;

class [[eosio::contract]] evm_contract : public contract
{
Expand Down Expand Up @@ -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<evm_runtime::evmtx_type> event){
Expand Down
23 changes: 17 additions & 6 deletions include/evm_runtime/tables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -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<value_promoter_uint64_t> evm_version;
binary_extension<value_promoter_evm_version_type> evm_version;
binary_extension<value_promoter_consensus_parameter_data_type> consensus_parameter;
binary_extension<eosio::name> token_contract; // <- default(unset) means eosio.token
binary_extension<uint32_t> queue_front_block;
binary_extension<value_promoter_gas_prices> gas_prices;
binary_extension<gas_prices_type> 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));
};
Expand All @@ -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
17 changes: 13 additions & 4 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const consensus_parameter_data_type &, bool> gas_param_pair = _config->get_consensus_param_and_maybe_promote();
if (gas_param_pair.second) {
Expand All @@ -473,8 +472,13 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const
Block block;

std::optional<uint64_t> 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,
Expand Down Expand Up @@ -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
71 changes: 44 additions & 27 deletions src/config_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand All @@ -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{};
}
}

Expand Down Expand Up @@ -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 <typename Q, typename Func>
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());
Expand All @@ -127,28 +114,54 @@ 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;
}
}

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 ) {
set_queue_front_block(activation_block_num);
}
}

void config_wrapper::enqueue_gas_price(uint64_t gas_price) {
enqueue<price_queue_table>([&](auto& el){
el.price = gas_price;
});
}

void config_wrapper::enqueue_gas_prices(const gas_prices_type& prices) {
enqueue<prices_queue_table>([&](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<prices_queue_table>([&](const auto& row){
set_gas_prices(row.prices);
});
} else {
process_queue<price_queue_table>([&](const auto& row){
set_gas_price(row.price);
});
}
}

template <typename Q, typename Func>
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());

Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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");

Expand Down
13 changes: 12 additions & 1 deletion tests/basic_evm_tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -790,6 +790,17 @@ bool basic_evm_tester::scan_price_queue(std::function<bool(price_queue)> visitor
return true;
}

bool basic_evm_tester::scan_prices_queue(std::function<bool(prices_queue)> visitor) const
{
static constexpr eosio::chain::name prices_queue_table_name = "pricesqueue"_n;

scan_table<prices_queue>(
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<char> 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<asset>(data);
Expand Down
26 changes: 11 additions & 15 deletions tests/basic_evm_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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> pending_value;
gas_prices_t cached_value{};
};

struct config_table_row
{
unsigned_int version;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -540,6 +535,7 @@ class basic_evm_tester : public evm_validating_tester
bool scan_account_code(std::function<bool(account_code)> visitor) const;
void scan_balances(std::function<bool(evm_test::vault_balance_row)> visitor) const;
bool scan_price_queue(std::function<bool(evm_test::price_queue)> visitor) const;
bool scan_prices_queue(std::function<bool(evm_test::prices_queue)> visitor) const;

intx::uint128 tx_data_cost(const silkworm::Transaction& txn) const;

Expand Down
Loading

0 comments on commit 867ce30

Please sign in to comment.