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 EOSEVM version #677

Merged
merged 24 commits into from
Jan 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a3e178b
Add support for EOSEVM version
elmato Dec 27, 2023
b2b36d3
Merge branch 'main' into elmato/support-for-eosevm-version
elmato Dec 29, 2023
2af0993
Remove unused include file
elmato Jan 2, 2024
723a1d2
Change pending time to time_point
elmato Jan 10, 2024
8ec1275
Make get_version const and call promote_pending from outside
elmato Jan 10, 2024
cc048db
Refactor pushtx action call
elmato Jan 10, 2024
e844094
Add tests to check that admincall/call will promote version and exec …
elmato Jan 10, 2024
85c65f8
Make modifications to init_tests to work with the new refactored pushtx
elmato Jan 10, 2024
005b380
Fix call to execute_tx in testtx action
elmato Jan 10, 2024
f7beb99
Revert "Make modifications to init_tests to work with the new refacto…
elmato Jan 15, 2024
074ca0d
Refactoring of configuration management and transaction processing
elmato Jan 17, 2024
f0b6174
bridge.hpp: removes unnecessary directives and includes
elmato Jan 17, 2024
7d42f76
Refactor config_wrapper
elmato Jan 19, 2024
2df364a
Change kTestNetwork initialization to be compatible with the new Chai…
elmato Jan 19, 2024
547d8c7
evm_contract: update function parameters
elmato Jan 19, 2024
2ef681f
test_engine: Use new ChainConfig revision interface
elmato Jan 19, 2024
3974168
refactor evm_runtime::transaction
elmato Jan 19, 2024
047c230
Add config_wrapper.cpp to CMakeLists.txt
elmato Jan 19, 2024
c0bd3d8
Refactor evm_version_type
elmato Jan 19, 2024
a2e5dc6
Move fee_parameters into types.hpp
elmato Jan 19, 2024
cc1bb0b
Update silkworm
elmato Jan 19, 2024
8cad78a
Add recover_sender in evm_runtime::transaction
elmato Jan 19, 2024
e20075a
replace config struct raw pointer inside configwrapper, with a smart …
elmato Jan 19, 2024
a248501
Fix test_actions.cpp
elmato Jan 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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