Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for storage and overhead price #750

Merged
merged 12 commits into from
Aug 8, 2024
Merged
2 changes: 1 addition & 1 deletion .github/workflows/contract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
with:
owner: AntelopeIO
repo: cdt
target: 'v3.1.0'
target: 'v4.0.1'
prereleases: false
file: 'cdt_.*amd64.deb'

Expand Down
13 changes: 11 additions & 2 deletions include/evm_runtime/config_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once
#include <eosio/eosio.hpp>

#include <evm_runtime/tables.hpp>
#include <eosio/asset.hpp>
#include <eosio/time.hpp>
#include <eosio/singleton.hpp>
#include <evm_runtime/tables.hpp>
namespace evm_runtime {

struct fee_parameters;
Expand All @@ -27,10 +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_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
5 changes: 4 additions & 1 deletion include/evm_runtime/evm_contract.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <eosio/eosio.hpp>
#include <eosio/asset.hpp>
#include <eosio/binary_extension.hpp>
#include <eosio/singleton.hpp>
Expand All @@ -18,6 +17,8 @@ using namespace eosio;

namespace evm_runtime {

struct gas_prices_type;

class [[eosio::contract]] evm_contract : public contract
{
public:
Expand Down Expand Up @@ -88,6 +89,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(const gas_prices_type& prices);

// Events
[[eosio::action]] void evmtx(eosio::ignore<evm_runtime::evmtx_type> event){
eosio::check(get_sender() == get_self(), "forbidden to call");
Expand Down
114 changes: 24 additions & 90 deletions include/evm_runtime/tables.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <evm_runtime/value_promoter.hpp>

#include <eosio/eosio.hpp>
#include <eosio/fixed_bytes.hpp>
Expand All @@ -8,9 +9,11 @@

#include <evm_runtime/types.hpp>
#include <evm_runtime/runtime_config.hpp>

#include <eosevm/block_mapping.hpp>

#include <silkworm/core/common/base.hpp>

namespace evm_runtime {

using namespace eosio;
Expand Down Expand Up @@ -243,95 +246,15 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] config2
EOSLIB_SERIALIZE(config2, (next_account_id));
};

struct evm_version_type {
struct pending {
uint64_t version;
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;
}
};

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;
}
return current_version;
}

std::pair<uint64_t, bool> get_version_and_maybe_promote(time_point_sec genesis_time, time_point current_time) {
uint64_t current_version = cached_version;
bool promoted = false;
if(pending_version.has_value() && pending_version->is_active(genesis_time, current_time)) {
current_version = pending_version->version;
promote_pending();
promoted = true;
}
return std::make_pair(current_version, 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> pending_version;
uint64_t cached_version=0;
};

struct pending_consensus_parameter_data_type {
consensus_parameter_data_type data;
time_point pending_time;
struct gas_prices_type {
uint64_t overhead_price{0};
uint64_t storage_price{0};
};
struct consensus_parameter_type {

consensus_parameter_data_type current;
std::optional<pending_consensus_parameter_data_type> 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;
}
using evm_version_type = uint64_t;

// 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;
}

std::pair<const consensus_parameter_data_type &, bool> 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<const consensus_parameter_data_type &, bool>(current, true);
}
return std::pair<const consensus_parameter_data_type &, bool>(current, false);
}

template <typename Visitor>
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
};
}
};
VALUE_PROMOTER(evm_version_type);
VALUE_PROMOTER_REV(consensus_parameter_data_type);

struct [[eosio::table]] [[eosio::contract("evm_contract")]] config
{
Expand All @@ -342,12 +265,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_type> evm_version;
binary_extension<consensus_parameter_type> consensus_parameter;
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<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));
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
Expand All @@ -359,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 include/evm_runtime/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,24 @@ namespace evm_runtime {

using bridge_message = std::variant<bridge_message_v0>;

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_v3 : evmtx_base {
uint64_t overhead_price;
uint64_t storage_price;
EOSLIB_SERIALIZE_DERIVED(evmtx_v3, evmtx_base, (overhead_price)(storage_price));
};

using evmtx_type = std::variant<evmtx_v0>;
using evmtx_type = std::variant<evmtx_v1, evmtx_v3>;

struct fee_parameters
{
Expand Down
65 changes: 65 additions & 0 deletions include/evm_runtime/value_promoter.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once
#include <eosio/time.hpp>
#include <eosio/print.hpp>
#include <eosevm/block_mapping.hpp>

#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<T, bool> 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<T, bool>(current_value, promoted);\
}\
template <typename Visitor>\
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<T##_pending> 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<T##_pending> pending_value;\
VALUE_PROMOTER_IMPL(T)\
};
2 changes: 1 addition & 1 deletion silkworm
Submodule silkworm updated 1 files
+2 −1 eosevm/version.hpp
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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=35984)
endif()
31 changes: 24 additions & 7 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,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 All @@ -493,8 +498,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");
Expand All @@ -503,6 +506,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 {
Expand All @@ -522,10 +527,12 @@ void evm_contract::process_tx(const runtime_config& rc, eosio::name miner, const
act.send(gas_param_pair.first);
}

if (current_version >= 1) {
auto event = evmtx_type{evmtx_v0{current_version, txn.get_rlptx(), *base_fee_per_gas}};
action(std::vector<permission_level>{}, get_self(), "evmtx"_n, event)
.send();
if(current_version >= 3) {
auto event = evmtx_type{evmtx_v3{current_version, txn.get_rlptx(), gas_prices.overhead_price, gas_prices.storage_price}};
action(std::vector<permission_level>{}, get_self(), "evmtx"_n, event).send();
} else if (current_version >= 1) {
auto event = evmtx_type{evmtx_v1{current_version, txn.get_rlptx(), *base_fee_per_gas}};
action(std::vector<permission_level>{}, get_self(), "evmtx"_n, event).send();
}
LOGTIME("EVM END");
}
Expand Down Expand Up @@ -899,4 +906,14 @@ void evm_contract::setgasparam(uint64_t gas_txnewaccount,
gas_sset);
}

void evm_contract::setgasprices(const gas_prices_type& prices) {
require_auth(get_self());
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
Loading