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
8 changes: 6 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,6 +27,10 @@ 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);

uint64_t get_gas_price()const;
void set_gas_price(uint64_t gas_price);

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;

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& prices);

// Events
[[eosio::action]] void evmtx(eosio::ignore<evm_runtime::evmtx_type> event){
eosio::check(get_sender() == get_self(), "forbidden to call");
Expand Down
103 changes: 13 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,14 @@ 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 gas_prices {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe rename to gas_prices_type to make it consistent with consensus_parameter_data_type

Also, consider change the name "gas_prices" everywhere to avoid confusion with gas_price (no s)

uint64_t overhead_price{0};
uint64_t storage_price{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_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;
}

// 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(uint64_t);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about
typedef uint64_t evm_version_type;
VALUE_PROMOTER(evm_version_type);
to reduce potential ambiguity.

VALUE_PROMOTER_REV(consensus_parameter_data_type);
VALUE_PROMOTER(gas_prices);

struct [[eosio::table]] [[eosio::contract("evm_contract")]] config
{
Expand All @@ -342,12 +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_type> evm_version;
binary_extension<consensus_parameter_type> consensus_parameter;
binary_extension<value_promoter_uint64_t> 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;

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 Down
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()
20 changes: 14 additions & 6 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const consensus_parameter_data_type &, bool> gas_param_pair = _config->get_consensus_param_and_maybe_promote();
if (gas_param_pair.second) {
Expand Down Expand Up @@ -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");
Expand All @@ -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 {
Expand All @@ -522,10 +523,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 +902,9 @@ void evm_contract::setgasparam(uint64_t gas_txnewaccount,
gas_sset);
}

void evm_contract::setgasprices(const gas_prices& prices) {
require_auth(get_self());
_config->set_gas_prices(prices);
}

} //evm_runtime
Loading