Skip to content

Commit

Permalink
Merge pull request #677 from eosnetworkfoundation/elmato/support-for-…
Browse files Browse the repository at this point in the history
…eosevm-version

Add support for EOSEVM version
  • Loading branch information
elmato authored Jan 19, 2024
2 parents 44a7460 + a248501 commit 7e1fb46
Show file tree
Hide file tree
Showing 19 changed files with 1,089 additions and 179 deletions.
62 changes: 62 additions & 0 deletions include/evm_runtime/config_wrapper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once
#include <eosio/eosio.hpp>
#include <eosio/asset.hpp>
#include <eosio/time.hpp>
#include <eosio/singleton.hpp>
#include <evm_runtime/tables.hpp>
namespace evm_runtime {

struct fee_parameters;
struct config_wrapper {

config_wrapper(eosio::name self);
~config_wrapper();

void flush();
bool exists();

eosio::unsigned_int get_version()const;
void set_version(const eosio::unsigned_int version);

uint64_t get_chainid()const;
void set_chainid(uint64_t chainid);

const eosio::time_point_sec& get_genesis_time()const;
void set_genesis_time(eosio::time_point_sec genesis_time);

const eosio::asset& get_ingress_bridge_fee()const;
void set_ingress_bridge_fee(const eosio::asset& ingress_bridge_fee);

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

uint32_t get_miner_cut()const;
void set_miner_cut(uint32_t miner_cut);

uint32_t get_status()const;
void set_status(uint32_t status);

uint64_t get_evm_version()const;
uint64_t get_evm_version_and_maybe_promote();
void set_evm_version(uint64_t new_version);

void set_fee_parameters(const fee_parameters& fee_params,
bool allow_any_to_be_unspecified);

private:
bool is_dirty()const;
void set_dirty();
void clear_dirty();

eosio::time_point get_current_time()const;

bool _dirty = false;
bool _exists = false;
config _cached_config;

eosio::name _self;
eosio::singleton<"config"_n, config> _config;
mutable std::optional<eosio::time_point> current_time_point;
};

} //namespace evm_runtime
82 changes: 24 additions & 58 deletions include/evm_runtime/evm_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
#include <eosio/asset.hpp>
#include <eosio/binary_extension.hpp>
#include <eosio/singleton.hpp>
#include <eosio/ignore.hpp>

#include <evm_runtime/types.hpp>

#include <evm_runtime/transaction.hpp>
#include <evm_runtime/runtime_config.hpp>
#include <silkworm/core/types/block.hpp>
#include <silkworm/core/execution/processor.hpp>

#ifdef WITH_TEST_ACTIONS
#include <evm_runtime/test/block_info.hpp>
#endif
Expand All @@ -19,20 +22,7 @@ class [[eosio::contract]] evm_contract : public contract
{
public:
using contract::contract;

struct fee_parameters
{
std::optional<uint64_t> gas_price; ///< Minimum gas price (in 10^-18 EOS, aka wei) that is enforced on all
///< transactions. Required during initialization.

std::optional<uint32_t> miner_cut; ///< Percentage cut (maximum allowed value of 100,000 which equals 100%) of the
///< gas fee collected for a transaction that is sent to the indicated miner of
///< that transaction. Required during initialization.

std::optional<asset> ingress_bridge_fee; ///< Fee (in EOS) deducted from ingress transfers of EOS across bridge.
///< Symbol must be in EOS and quantity must be non-negative. If not
///< provided during initialization, the default fee of 0 will be used.
};
evm_contract(eosio::name receiver, eosio::name code, const datastream<const char*>& ds);

/**
* @brief Initialize EVM contract
Expand Down Expand Up @@ -70,7 +60,7 @@ class [[eosio::contract]] evm_contract : public contract

[[eosio::action]] void exec(const exec_input& input, const std::optional<exec_callback>& callback);

[[eosio::action]] void pushtx(eosio::name miner, const bytes& rlptx);
[[eosio::action]] void pushtx(eosio::name miner, bytes rlptx);

[[eosio::action]] void open(eosio::name owner);

Expand All @@ -93,6 +83,13 @@ class [[eosio::contract]] evm_contract : public contract

[[eosio::action]] void assertnonce(eosio::name account, uint64_t next_nonce);

[[eosio::action]] void setversion(uint64_t version);

// Events
[[eosio::action]] void evmtx(eosio::ignore<evm_runtime::evmtx_type> event){
eosio::check(get_sender() == get_self(), "forbidden to call");
};

#ifdef WITH_ADMIN_ACTIONS
[[eosio::action]] void rmgcstore(uint64_t id);
[[eosio::action]] void setkvstore(uint64_t account_id, const bytes& key, const std::optional<bytes>& value);
Expand All @@ -116,40 +113,19 @@ class [[eosio::contract]] evm_contract : public contract
[[eosio::action]] void testbaldust(const name test);
#endif

struct [[eosio::table]] [[eosio::contract("evm_contract")]] config
{
unsigned_int version; // placeholder for future variant index
uint64_t chainid = 0;
time_point_sec genesis_time;
asset ingress_bridge_fee = asset(0, token_symbol);
uint64_t gas_price = 0;
uint32_t miner_cut = 0;
uint32_t status = 0; // <- bit mask values from status_flags

EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status));
};

private:
void open_internal_balance(eosio::name owner);
std::shared_ptr<struct config_wrapper> _config;

enum class status_flags : uint32_t
{
frozen = 0x1
};

eosio::singleton<"config"_n, config> _config{get_self(), get_self().value};

void assert_inited()
{
check(_config.exists(), "contract not initialized");
check(_config.get().version == 0u, "unsupported configuration singleton");
}

void assert_unfrozen()
{
assert_inited();
check((_config.get().status & static_cast<uint32_t>(status_flags::frozen)) == 0, "contract is frozen");
}
void assert_inited();
void assert_unfrozen();

silkworm::Receipt execute_tx(eosio::name miner, silkworm::Block& block, silkworm::Transaction& tx, silkworm::ExecutionProcessor& ep, bool enforce_chain_id);
silkworm::Receipt execute_tx(const runtime_config& rc, eosio::name miner, silkworm::Block& block, const transaction& tx, silkworm::ExecutionProcessor& ep);
void process_filtered_messages(const std::vector<silkworm::FilteredMessage>& filtered_messages);

uint64_t get_and_increment_nonce(const name owner);
Expand All @@ -159,23 +135,13 @@ class [[eosio::contract]] evm_contract : public contract
void handle_account_transfer(const eosio::asset& quantity, const std::string& memo);
void handle_evm_transfer(eosio::asset quantity, const std::string& memo);

void call_(intx::uint256 s, const bytes& to, intx::uint256 value, const bytes& data, uint64_t gas_limit, uint64_t nonce);
void call_(const runtime_config& rc, intx::uint256 s, const bytes& to, intx::uint256 value, const bytes& data, uint64_t gas_limit, uint64_t nonce);

// to allow sending through a Bytes (basic_string<uint8_t>) w/o copying over to a std::vector<char>
void pushtx_bytes(eosio::name miner, const std::basic_string<uint8_t>& rlptx);
using pushtx_action = eosio::action_wrapper<"pushtx"_n, &evm_contract::pushtx_bytes>;
};
using pushtx_action = eosio::action_wrapper<"pushtx"_n, &evm_contract::pushtx>;

void process_tx(const runtime_config& rc, eosio::name miner, const transaction& tx);
void dispatch_tx(const runtime_config& rc, const transaction& tx);
};

} // namespace evm_runtime

namespace std {
template <typename DataStream>
DataStream& operator<<(DataStream& ds, const std::basic_string<uint8_t>& bs)
{
ds << (unsigned_int)bs.size();
if (bs.size())
ds.write((const char*)bs.data(), bs.size());
return ds;
}
} // namespace std
12 changes: 12 additions & 0 deletions include/evm_runtime/runtime_config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

namespace evm_runtime {

struct runtime_config {
bool allow_special_signature = false;
bool abort_on_failure = false;
bool enforce_chain_id = true;
bool allow_non_self_miner = true;
};

} //namespace evm_runtime
58 changes: 58 additions & 0 deletions include/evm_runtime/tables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <eosio/binary_extension.hpp>

#include <evm_runtime/types.hpp>
#include <eosevm/block_mapping.hpp>

#include <silkworm/core/common/base.hpp>
namespace evm_runtime {

Expand Down Expand Up @@ -229,4 +231,60 @@ 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 [[eosio::table]] [[eosio::contract("evm_contract")]] config
{
unsigned_int version; // placeholder for future variant index
uint64_t chainid = 0;
time_point_sec genesis_time;
asset ingress_bridge_fee = asset(0, token_symbol);
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;

EOSLIB_SERIALIZE(config, (version)(chainid)(genesis_time)(ingress_bridge_fee)(gas_price)(miner_cut)(status)(evm_version));
};

} //namespace evm_runtime
16 changes: 8 additions & 8 deletions include/evm_runtime/test/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ namespace test {
inline constexpr ChainConfig kTestNetwork{
.chain_id = 1,
.protocol_rule_set = protocol::RuleSetType::kNoProof,
.homestead_block = 0,
.dao_block = 0,
.tangerine_whistle_block = 0,
.spurious_dragon_block = 0,
.byzantium_block = 0,
.constantinople_block = 0,
.petersburg_block = 0,
.istanbul_block = 0,
._homestead_block = 0,
._dao_block = 0,
._tangerine_whistle_block = 0,
._spurious_dragon_block = 0,
._byzantium_block = 0,
._constantinople_block = 0,
._petersburg_block = 0,
._istanbul_block = 0,
};

} //namespace test
Expand Down
2 changes: 1 addition & 1 deletion include/evm_runtime/test/engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class engine : public silkworm::protocol::IRuleSet {

void finalize(IntraBlockState& state, const Block& block) override {
intx::uint256 block_reward;
const evmc_revision revision{config.revision(block.header.number, block.header.timestamp)};
const evmc_revision revision{config.revision(block.header)};
if (revision >= EVMC_CONSTANTINOPLE) {
block_reward = silkworm::protocol::kBlockRewardConstantinople;
} else if (revision >= EVMC_BYZANTIUM) {
Expand Down
53 changes: 53 additions & 0 deletions include/evm_runtime/transaction.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include <optional>
#include <eosio/eosio.hpp>
#include <evm_runtime/types.hpp>
#include <silkworm/core/rlp/encode.hpp>
#include <silkworm/core/types/transaction.hpp>

namespace evm_runtime {

using silkworm::Bytes;
using silkworm::ByteView;

struct transaction {

transaction() = delete;
explicit transaction(bytes rlptx) : rlptx_(std::move(rlptx)) {}
explicit transaction(silkworm::Transaction tx) : tx_(std::move(tx)) {}

const bytes& get_rlptx()const {
if(!rlptx_) {
eosio::check(tx_.has_value(), "no tx");
Bytes rlp;
silkworm::rlp::encode(rlp, tx_.value());
rlptx_.emplace(bytes{rlp.begin(), rlp.end()});
}
return rlptx_.value();
}

const silkworm::Transaction& get_tx()const {
if(!tx_) {
eosio::check(rlptx_.has_value(), "no rlptx");
ByteView bv{(const uint8_t*)rlptx_->data(), rlptx_->size()};
silkworm::Transaction tmp;
eosio::check(silkworm::rlp::decode(bv, tmp) && bv.empty(), "unable to decode transaction");
tx_.emplace(tmp);
}
return tx_.value();
}

void recover_sender()const {
eosio::check(tx_.has_value(), "no tx");
auto& tx = tx_.value();
tx.from.reset();
tx.recover_sender();
}

private:
mutable std::optional<bytes> rlptx_;
mutable std::optional<silkworm::Transaction> tx_;
};

} //namespace evm_runtime
Loading

0 comments on commit 7e1fb46

Please sign in to comment.