Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into GH-271-only-one
Browse files Browse the repository at this point in the history
  • Loading branch information
heifner committed Feb 3, 2023
2 parents c96eb30 + 234654e commit a2ce23b
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 67 deletions.
45 changes: 45 additions & 0 deletions contract/include/evm_runtime/eosio.token.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#pragma once

#include <eosio/asset.hpp>
#include <eosio/eosio.hpp>

#include <string>

namespace eosio {

using std::string;

class [[eosio::contract("eosio.token")]] token : public contract {
public:
using contract::contract;

[[eosio::action]]
void create( const name& issuer,
const asset& maximum_supply);

[[eosio::action]]
void issue( const name& to, const asset& quantity, const string& memo );

[[eosio::action]]
void retire( const asset& quantity, const string& memo );

[[eosio::action]]
void transfer( const name& from,
const name& to,
const asset& quantity,
const string& memo );

[[eosio::action]]
void open( const name& owner, const symbol& symbol, const name& ram_payer );

[[eosio::action]]
void close( const name& owner, const symbol& symbol );

using create_action = eosio::action_wrapper<"create"_n, &token::create>;
using issue_action = eosio::action_wrapper<"issue"_n, &token::issue>;
using retire_action = eosio::action_wrapper<"retire"_n, &token::retire>;
using transfer_action = eosio::action_wrapper<"transfer"_n, &token::transfer>;
using open_action = eosio::action_wrapper<"open"_n, &token::open>;
using close_action = eosio::action_wrapper<"close"_n, &token::close>;
};
}
26 changes: 26 additions & 0 deletions contract/include/evm_runtime/evm_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ CONTRACT evm_contract : public contract {
[[eosio::action]]
void pushtx(eosio::name ram_payer, const bytes& rlptx);

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

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

[[eosio::on_notify("eosio.token::transfer")]]
void transfer(eosio::name from, eosio::name to, eosio::asset quantity, std::string memo);

[[eosio::action]]
void withdraw(eosio::name owner, eosio::asset quantity);

/// @return true if all garbage has been collected
[[eosio::action]]
bool gc(uint32_t max);

#ifdef WITH_TEST_ACTIONS
ACTION testtx( const bytes& rlptx, const evm_runtime::test::block_info& bi );
ACTION updatecode( const bytes& address, uint64_t incarnation, const bytes& code_hash, const bytes& code);
Expand All @@ -33,6 +49,16 @@ CONTRACT evm_contract : public contract {
ACTION setbal(const bytes& addy, const bytes& bal);
#endif
private:
struct [[eosio::table]] [[eosio::contract("evm_contract")]] account {
name owner;
asset balance;
uint64_t dust = 0;

uint64_t primary_key() const { return owner.value; }
};

typedef eosio::multi_index<"accounts"_n, account> accounts;

struct [[eosio::table]] [[eosio::contract("evm_contract")]] config {
eosio::unsigned_int version; //placeholder for future variant index
uint64_t chainid = 0;
Expand Down
3 changes: 3 additions & 0 deletions contract/include/evm_runtime/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ struct state : State {
void update_account(const evmc::address& address, std::optional<Account> initial,
std::optional<Account> current) override;

/// @return true if all garbage has been collected
bool gc(uint32_t max);

void update_account_code(const evmc::address& address, uint64_t incarnation, const evmc::bytes32& code_hash,
ByteView code) override;

Expand Down
11 changes: 11 additions & 0 deletions contract/include/evm_runtime/tables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,15 @@ typedef multi_index< "storage"_n, storage,
indexed_by<"by.key"_n, const_mem_fun<storage, checksum256, &storage::by_key>>
> storage_table;

struct [[eosio::table]] [[eosio::contract("evm_contract")]] gcstore {
uint64_t id;
uint64_t storage_id;

uint64_t primary_key()const { return id; }

EOSLIB_SERIALIZE(gcstore, (id)(storage_id));
};

typedef multi_index< "gcstore"_n, gcstore> gc_store_table;

} //namespace evm_runtime
101 changes: 96 additions & 5 deletions contract/src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <evm_runtime/state.hpp>
#include <evm_runtime/engine.hpp>
#include <evm_runtime/intrinsics.hpp>
#include <evm_runtime/eosio.token.hpp>

// included here so NDEBUG is defined to disable assert macro
#include <silkworm/execution/processor.cpp>
Expand All @@ -28,6 +29,9 @@ namespace silkworm {
}
}

static constexpr eosio::name token_account("eosio.token"_n);
static constexpr eosio::symbol token_symbol("EOS", 4u);

namespace evm_runtime {

using namespace silkworm;
Expand Down Expand Up @@ -114,6 +118,71 @@ void evm_contract::pushtx( eosio::name ram_payer, const bytes& rlptx ) {
push_trx( ram_payer, block, rlptx );
}

void evm_contract::open(eosio::name owner, eosio::name ram_payer) {
assert_inited();
require_auth(ram_payer);
check(is_account(owner), "owner account does not exist");

accounts account_table(get_self(), get_self().value);
if(account_table.find(owner.value) == account_table.end())
account_table.emplace(ram_payer, [&](account& a) {
a.owner = owner;
a.balance = asset(0, token_symbol);
});
}

void evm_contract::close(eosio::name owner) {
assert_inited();
require_auth(owner);

accounts account_table(get_self(), get_self().value);
const account& owner_account = account_table.get(owner.value, "account is not open");

eosio::check(owner_account.balance.amount == 0 && owner_account.dust == 0, "cannot close because balance is not zero");
account_table.erase(owner_account);
}

void evm_contract::transfer(eosio::name from, eosio::name to, eosio::asset quantity, std::string memo) {
assert_inited();

if(to != get_self() || from == get_self())
return;

eosio::check(!memo.empty(), "memo must be already opened account name to credit deposit to");

eosio::name receiver(memo);

accounts account_table(get_self(), get_self().value);
const account& receiver_account = account_table.get(receiver.value, "receiving account has not been opened");

account_table.modify(receiver_account, eosio::same_payer, [&](account& a) {
a.balance += quantity;
});
}

void evm_contract::withdraw(eosio::name owner, eosio::asset quantity) {
assert_inited();
require_auth(owner);

accounts account_table(get_self(), get_self().value);
const account& owner_account = account_table.get(owner.value, "account is not open");

check(owner_account.balance.amount >= quantity.amount, "overdrawn balance");
account_table.modify(owner_account, eosio::same_payer, [&](account& a) {
a.balance -= quantity;
});

token::transfer_action transfer_act(token_account, {{get_self(), "active"_n}});
transfer_act.send(get_self(), owner, quantity, std::string("Withdraw from EVM balance"));
}

bool evm_contract::gc(uint32_t max) {
assert_inited();

evm_runtime::state state{get_self(), eosio::same_payer};
return state.gc(max);
}

#ifdef WITH_TEST_ACTIONS
ACTION evm_contract::testtx( const bytes& rlptx, const evm_runtime::test::block_info& bi ) {
assert_inited();
Expand Down Expand Up @@ -165,6 +234,14 @@ ACTION evm_contract::dumpall() {

eosio::require_auth(get_self());

auto print_store = [](auto sitr) {
eosio::print(" ");
eosio::printhex(sitr->key.data(), sitr->key.size());
eosio::print(":");
eosio::printhex(sitr->value.data(), sitr->value.size());
eosio::print("\n");
};

account_table accounts(_self, _self.value);
auto itr = accounts.begin();
eosio::print("DUMPALL start\n");
Expand All @@ -175,16 +252,29 @@ ACTION evm_contract::dumpall() {
storage_table db(_self, itr->id);
auto sitr = db.begin();
while( sitr != db.end() ) {
eosio::print(" ");
eosio::printhex(sitr->key.data(), sitr->key.size());
eosio::print(":");
eosio::printhex(sitr->value.data(), sitr->value.size());
eosio::print("\n");
print_store( sitr );
sitr++;
}

itr++;
}
eosio::print(" gc:");
gc_store_table gc(_self, _self.value);
auto i = gc.begin();
while( i != gc.end() ) {
eosio::print(" storage_id:");
eosio::print(i->storage_id);
eosio::print("\n");
storage_table db(_self, i->storage_id);
auto sitr = db.begin();
while( sitr != db.end() ) {
print_store( sitr );
++sitr;
}

++i;
}

eosio::print("DUMPALL end\n");
}

Expand Down Expand Up @@ -216,6 +306,7 @@ ACTION evm_contract::clearall() {
eosio::print("db size:", uint64_t(db_size), "\n");
itr = accounts.erase(itr);
}
gc(std::numeric_limits<uint32_t>::max());

auto account_size = std::distance(accounts.cbegin(), accounts.cend());
eosio::print("accounts size:", uint64_t(account_size), "\n");
Expand Down
28 changes: 23 additions & 5 deletions contract/src/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,35 @@ void state::update_account(const evmc::address& address, std::optional<Account>
} else {
if(itr != inx.end()) {
storage_table db(_self, itr->id);
auto sitr = db.begin();
while( sitr != db.end() ) {
sitr = db.erase(sitr);
++stats.storage.remove;
}
// add to garbage collection table for later removal
gc_store_table gc(_self, _self.value);
gc.emplace(_ram_payer, [&](auto& row){
row.id = gc.available_primary_key();
row.storage_id = itr->id;
});
accounts.erase(*itr);
++stats.account.remove;
}
}
}

bool state::gc(uint32_t max) {
gc_store_table gc(_self, _self.value);
auto i = gc.begin();
while( max && i != gc.end() ) {
storage_table db(_self, i->storage_id);
auto sitr = db.begin();
while( max && sitr != db.end() ) {
sitr = db.erase(sitr);
--max;
}
if( !max ) break;
i = gc.erase(i);
--max;
}
return gc.begin() == gc.end();
}

void state::update_account_code(const evmc::address& address, uint64_t, const evmc::bytes32& code_hash, ByteView code) {
account_table accounts(_self, _self.value);
auto inx = accounts.get_index<"by.address"_n>();
Expand Down
3 changes: 1 addition & 2 deletions contract/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ include_directories(
${CMAKE_SOURCE_DIR}/../../silkworm/third_party/silkpre/third_party/secp256k1/include
)

#file(GLOB UNIT_TESTS "*.cpp" "*.hpp")

set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")

add_eosio_test( unit_test
${CMAKE_SOURCE_DIR}/evm_runtime_tests.cpp
${CMAKE_SOURCE_DIR}/init_tests.cpp
${CMAKE_SOURCE_DIR}/native_token_tests.cpp
${CMAKE_SOURCE_DIR}/main.cpp
${CMAKE_SOURCE_DIR}/silkworm/core/silkworm/rlp/encode.cpp
${CMAKE_SOURCE_DIR}/silkworm/core/silkworm/rlp/decode.cpp
Expand Down
56 changes: 1 addition & 55 deletions contract/tests/basic_evm_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,64 +11,10 @@ using namespace eosio;
using namespace eosio::chain;
using mvo = fc::mutable_variant_object;

static const char wasm_level_up_wast[] = R"=====(
(module
(import "env" "set_wasm_parameters_packed" (func $set_wasm_parameters_packed (param i32 i32)))
(memory $0 1)
(export "apply" (func $apply))
(func $apply (param $0 i64) (param $1 i64) (param $2 i64)
(call $set_wasm_parameters_packed
(i32.const 0)
(i32.const 48)
)
)
;; this is intended to be the same settings as used by eosio.system's 3.1.1 "high" setting
(data (i32.const 0) "\00\00\00\00") ;; version
(data (i32.const 4) "\00\20\00\00") ;; max_mutable_global_bytes
(data (i32.const 8) "\00\20\00\00") ;; max_table_elements
(data (i32.const 12) "\00\20\00\00") ;; max_section_elements
(data (i32.const 16) "\00\00\10\00") ;; max_linear_memory_init
(data (i32.const 20) "\00\20\00\00") ;; max_func_local_bytes
(data (i32.const 24) "\00\04\00\00") ;; max_nested_structures
(data (i32.const 28) "\00\20\00\00") ;; max_symbol_bytes
(data (i32.const 32) "\00\00\40\01") ;; max_module_bytes
(data (i32.const 36) "\00\00\40\01") ;; max_code_bytes
(data (i32.const 40) "\10\02\00\00") ;; max_pages
(data (i32.const 44) "\00\04\00\00") ;; max_call_depth
)
)=====";

static const char wasm_level_up_abi[] = R"=====(
{
"version": "eosio::abi/1.2",
"types": [],
"structs": [
{
"name": "dothedew",
"base": "",
"fields": []
}
],
"actions": [
{
"name": "dothedew",
"type": "dothedew"
}
]
}
)=====";

class basic_evm_tester : public testing::validating_tester {
public:
basic_evm_tester() {
create_accounts({"wasmlevelup"_n, "evm"_n});
push_action(config::system_account_name, "setpriv"_n, config::system_account_name, mvo()("account", "wasmlevelup"_n)("is_priv", 1));
produce_blocks(2);

set_code("wasmlevelup"_n, wasm_level_up_wast);
set_abi("wasmlevelup"_n, wasm_level_up_abi);
push_action("wasmlevelup"_n, "dothedew"_n, "wasmlevelup"_n, mvo());
produce_blocks(2);
create_accounts({"evm"_n});

set_code("evm"_n, testing::contracts::evm_runtime_wasm());
set_abi("evm"_n, testing::contracts::evm_runtime_abi().data());
Expand Down
Loading

0 comments on commit a2ce23b

Please sign in to comment.