From 194b79c346bc6550b73433865088f4294e04ddb0 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 24 Jul 2023 12:09:06 -0300 Subject: [PATCH 01/11] Add bridgereg/bridgeunreg actions --- include/evm_runtime/evm_contract.hpp | 3 +++ include/evm_runtime/tables.hpp | 11 +++++++++ src/actions.cpp | 35 ++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index e52669fa..70487b01 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -88,6 +88,9 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void call(eosio::name from, const bytes& to, const bytes& value, const bytes& data, uint64_t gas_limit); [[eosio::action]] void admincall(const bytes& from, const bytes& to, const bytes& value, const bytes& data, uint64_t gas_limit); + [[eosio::action]] void bridgereg(eosio::name receiver, const eosio::asset& min_fee); + [[eosio::action]] void bridgeunreg(eosio::name receiver); + #ifdef WITH_TEST_ACTIONS [[eosio::action]] void testtx(const std::optional& orlptx, const evm_runtime::test::block_info& bi); [[eosio::action]] void diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index 205a2d4c..174f9bb4 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -182,4 +182,15 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] allowed_egress_accou typedef eosio::multi_index<"egresslist"_n, allowed_egress_account> egresslist; +struct [[eosio::table]] [[eosio::contract("evm_contract")]] message_receiver { + name account; + asset min_fee; + + uint64_t primary_key() const { return account.value; } + + EOSLIB_SERIALIZE(message_receiver, (account)(min_fee)); +}; + +typedef eosio::multi_index<"msgreceiver"_n, message_receiver> message_receiver_table; + } //namespace evm_runtime \ No newline at end of file diff --git a/src/actions.cpp b/src/actions.cpp index 116bf5c9..b59985f8 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -634,6 +634,41 @@ void evm_contract::admincall(const bytes& from, const bytes& to, const bytes& va call_(s, to, v, data, gas_limit, nonce); } +void evm_contract::bridgereg(eosio::name receiver, const eosio::asset& min_fee) { + assert_unfrozen(); + require_auth(receiver); + require_auth(get_self()); // to temporarily prevent registration of unauthorized accounts + + eosio::check(min_fee.symbol == token_symbol, "unexpected symbol"); + eosio::check(min_fee.amount >= 0, "min_fee cannot be negative"); + + auto update_row = [&](auto& row) { + row.account = receiver; + row.min_fee = min_fee; + }; + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + + if(it == message_receivers.end()) { + message_receivers.emplace(receiver, update_row); + } else { + message_receivers.modify(*it, eosio::same_payer, update_row); + } + + open(receiver); +} + +void evm_contract::bridgeunreg(eosio::name receiver) { + assert_unfrozen(); + require_auth(receiver); + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + eosio::check(it != message_receivers.end(), "receiver not found"); + message_receivers.erase(*it); +} + #ifdef WITH_TEST_ACTIONS [[eosio::action]] void evm_contract::testtx( const std::optional& orlptx, const evm_runtime::test::block_info& bi ) { assert_unfrozen(); From 0a69556866ed35c470051efce5bde1528ba3e304 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 24 Jul 2023 12:26:08 -0300 Subject: [PATCH 02/11] Handle 'emit' EVM call messages --- include/evm_runtime/bridge.hpp | 75 ++++++++++++++++++++++++++++++++++ include/evm_runtime/types.hpp | 12 +++++- silkworm | 2 +- src/CMakeLists.txt | 2 +- src/actions.cpp | 54 ++++++++++++++++++++++++ 5 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 include/evm_runtime/bridge.hpp diff --git a/include/evm_runtime/bridge.hpp b/include/evm_runtime/bridge.hpp new file mode 100644 index 00000000..28489a74 --- /dev/null +++ b/include/evm_runtime/bridge.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include + +namespace evm_runtime { namespace bridge { + +struct emit { + static constexpr uint32_t id = 0x7e95a247; //sha3('emit_(string,bytes)')[:4] + + string account; + bytes data; + + name get_account_as_name() const { + if(!account_.has_value()) { + account_ = name{account}; + eosio::check(account_.value().to_string() == account, "invalid account name"); + } + return *account_; + } + + eosio::time_point timestamp; + evmc_message message; + mutable std::optional account_; +}; + +using call = std::variant; + +std::optional decode_emit_message(eosio::datastream& ds) { + // offset_p1 (32) + offset_p2 (32) + // p1_len (32) + p1_data ((p1_len+31)/32*32) + // p2_len (32) + p1_data ((p2_len+31)/32*32) + uint256 offset_p1, offset_p2; + uint32_t p1_len, p2_len; + + ds >> offset_p1; + eosio::check(offset_p1 == 0x40, "invalid p1 offset"); + ds >> offset_p2; + eosio::check(offset_p2 == 0x80, "invalid p2 offset"); + + emit res; + + auto get_length=[&]() -> uint32_t { + uint256 len; + ds >> len; + eosio::check(len < std::numeric_limits::max(), "invalid length"); + return static_cast(len); + }; + + p1_len = get_length(); + auto p1_len_32 = (p1_len+31)/32*32; + res.account.resize(p1_len_32); + ds.read(res.account.data(), p1_len_32); + res.account.resize(p1_len); + + p2_len = get_length(); + auto p2_len_32 = (p2_len+31)/32*32; + res.data.resize(p2_len_32); + ds.read(res.data.data(), p2_len_32); + res.data.resize(p2_len); + + return res; +} + +std::optional decode_call_message(ByteView bv) { + // method_id (4) + eosio::datastream ds(bv.data(), bv.size()); + uint32_t method_id; + ds >> method_id; + + if(method_id == __builtin_bswap32(emit::id)) return decode_emit_message(ds); + return {}; +} + +} //namespace bridge +} //namespace evm_runtime diff --git a/include/evm_runtime/types.hpp b/include/evm_runtime/types.hpp index aa050640..09605bff 100644 --- a/include/evm_runtime/types.hpp +++ b/include/evm_runtime/types.hpp @@ -29,7 +29,7 @@ namespace evm_runtime { eosio::checksum256 make_key(bytes data); eosio::checksum256 make_key(const evmc::address& addr); eosio::checksum256 make_key(const evmc::bytes32& data); - + bytes to_bytes(const uint256& val); bytes to_bytes(const evmc::bytes32& val); bytes to_bytes(const evmc::address& addr); @@ -63,6 +63,16 @@ namespace evm_runtime { EOSLIB_SERIALIZE(exec_output, (status)(data)(context)); }; + struct bridge_emit_message { + eosio::name receiver; + bytes sender; + eosio::time_point timestamp; + bytes value; + bytes data; + + EOSLIB_SERIALIZE(bridge_emit_message, (receiver)(sender)(timestamp)(value)(data)); + }; + } //namespace evm_runtime namespace eosio { diff --git a/silkworm b/silkworm index d661be9a..df5d9ca3 160000 --- a/silkworm +++ b/silkworm @@ -1 +1 @@ -Subproject commit d661be9a624505fb769e9c964ab5ba995e56c94a +Subproject commit df5d9ca396b4a85ace6b85aa16bbb0e5e0f90e50 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 32f09944..dc6bb7da 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,5 +85,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=38560) + target_link_options(evm_runtime PUBLIC --stack-size=32768) endif() diff --git a/src/actions.cpp b/src/actions.cpp index b59985f8..ff9cc1f6 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -415,8 +416,61 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { check(tx.max_priority_fee_per_gas == tx.max_fee_per_gas, "max_priority_fee_per_gas must be equal to max_fee_per_gas"); check(tx.max_fee_per_gas >= current_config.gas_price, "gas price is too low"); + // handler for all EVM call messages + std::vector emit_messages; + ep.set_evm_call_hook([&](const evmc_message& message, const evmc::Result& result){ + static auto me = make_reserved_address(get_self().value); + if (message.recipient != me || message.input_size == 0) return; + + eosio::check(result.status_code == EVMC_SUCCESS, "error calling reserved address"); + + auto call = bridge::decode_call_message(ByteView{message.input_data, message.input_size}); + eosio::check(call.has_value(), "unable to decode call message"); + + auto& emit = std::get(call.value()); + emit.message = message; + emit.timestamp = eosio::current_time_point(); + + const auto& receiver = emit.get_account_as_name(); + eosio::check(eosio::is_account(receiver), "receiver is not account"); + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + eosio::check(it != message_receivers.end(), "receiver not registered"); + + intx::uint256 min_fee((uint64_t)it->min_fee.amount); + min_fee *= minimum_natively_representable; + + auto value = intx::be::unsafe::load(message.value.bytes); + eosio::check(value >= min_fee, "min_fee not covered"); + + emit_messages.push_back(emit); + }); + auto receipt = execute_tx(miner, block, tx, ep, true); + // Process emit messages + for(const auto& emit : emit_messages) { + balances balance_table(get_self(), get_self().value); + const balance& receiver_account = balance_table.get(emit.get_account_as_name().value, "receiver account is not open"); + + bridge_emit_message msg { + .receiver = emit.get_account_as_name(), + .sender = to_bytes(emit.message.sender), + .timestamp = emit.timestamp, + .value = to_bytes(emit.message.value), + .data = emit.data + }; + + action(std::vector{}, emit.get_account_as_name(), "onbridgemsg"_n, msg + ).send(); + + auto value = intx::be::unsafe::load(emit.message.value.bytes); + balance_table.modify(receiver_account, eosio::same_payer, [&](balance& a) { + a.balance += value; + }); + } + engine.finalize(ep.state(), ep.evm().block()); ep.state().write_to_db(ep.evm().block().header.number); LOGTIME("EVM END"); From d22c0af0206c8d049346ad4aa8e7fb40058e07bd Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 24 Jul 2023 12:30:36 -0300 Subject: [PATCH 03/11] Add tests for 'emit' message functionality --- tests/CMakeLists.txt | 1 + tests/basic_evm_tester.cpp | 26 +- tests/basic_evm_tester.hpp | 23 +- tests/bridge_emit_tests.cpp | 239 ++++++++++++++++++ tests/contracts.hpp.in | 3 + .../contracts/evm_bridge_receiver/README.txt | 4 + .../evm_bridge_receiver.abi | 44 ++++ .../evm_bridge_receiver.contracts.md | 3 + .../evm_bridge_receiver.cpp | 30 +++ .../evm_bridge_receiver.hpp | 11 + .../evm_bridge_receiver.wasm | Bin 0 -> 3112 bytes tests/utils.hpp | 46 ++++ 12 files changed, 425 insertions(+), 5 deletions(-) create mode 100644 tests/bridge_emit_tests.cpp create mode 100644 tests/contracts/evm_bridge_receiver/README.txt create mode 100644 tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi create mode 100644 tests/contracts/evm_bridge_receiver/evm_bridge_receiver.contracts.md create mode 100644 tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp create mode 100644 tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp create mode 100755 tests/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm create mode 100644 tests/utils.hpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d0c91558..06e48110 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,6 +32,7 @@ add_eosio_test_executable( unit_test ${CMAKE_SOURCE_DIR}/exec_tests.cpp ${CMAKE_SOURCE_DIR}/call_tests.cpp ${CMAKE_SOURCE_DIR}/chainid_tests.cpp + ${CMAKE_SOURCE_DIR}/bridge_emit_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 diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 5f7121ca..5314dc06 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -139,6 +139,10 @@ evmc::address basic_evm_tester::make_reserved_address(uint64_t account) // clang-format on } +evmc::address basic_evm_tester::make_reserved_address(name account) { + return make_reserved_address(account.to_uint64_t()); +} + basic_evm_tester::basic_evm_tester(std::string native_symbol_str) : native_symbol(symbol::from_string(native_symbol_str)) { @@ -329,7 +333,23 @@ void basic_evm_tester::admincall(const evmc::bytes& from, const evmc::bytes& to, push_action(evm_account_name, "admincall"_n, actor, mvo()("from", from_bytes)("to", to_bytes)("value", value_bytes)("data", data_bytes)("gas_limit", gas_limit)); } -void basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) +transaction_trace_ptr basic_evm_tester::bridgereg(name receiver, asset min_fee, vector extra_signers) { + extra_signers.push_back(receiver); + return basic_evm_tester::push_action(evm_account_name, "bridgereg"_n, extra_signers, + mvo()("receiver", receiver)("min_fee", min_fee)); +} + +transaction_trace_ptr basic_evm_tester::bridgeunreg(name receiver) { + return basic_evm_tester::push_action(evm_account_name, "bridgeunreg"_n, receiver, + mvo()("receiver", receiver)); +} + +transaction_trace_ptr basic_evm_tester::exec(const exec_input& input, const std::optional& callback) { + auto binary_data = fc::raw::pack>(input, callback); + return basic_evm_tester::push_action(evm_account_name, "exec"_n, evm_account_name, bytes{binary_data.begin(), binary_data.end()}); +} + +transaction_trace_ptr basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) { silkworm::Bytes rlp; silkworm::rlp::encode(rlp, trx); @@ -338,7 +358,7 @@ void basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) rlp_bytes.resize(rlp.size()); memcpy(rlp_bytes.data(), rlp.data(), rlp.size()); - push_action(evm_account_name, "pushtx"_n, miner, mvo()("miner", miner)("rlptx", rlp_bytes)); + return push_action(evm_account_name, "pushtx"_n, miner, mvo()("miner", miner)("rlptx", rlp_bytes)); } evmc::address basic_evm_tester::deploy_contract(evm_eoa& eoa, evmc::bytes bytecode) @@ -525,4 +545,4 @@ bool basic_evm_tester::scan_account_storage(uint64_t account_id, std::function context; }; +struct message_receiver { + name account; + asset min_fee; +}; + +struct bridge_emit_message { + name receiver; + bytes sender; + time_point timestamp; + bytes value; + bytes data; +}; + } // namespace evm_test @@ -123,6 +136,9 @@ FC_REFLECT(evm_test::exec_input, (context)(from)(to)(data)(value)) FC_REFLECT(evm_test::exec_callback, (contract)(action)) FC_REFLECT(evm_test::exec_output, (status)(data)(context)) +FC_REFLECT(evm_test::message_receiver, (account)(min_fee)); +FC_REFLECT(evm_test::bridge_emit_message, (receiver)(sender)(timestamp)(value)(data)); + namespace evm_test { class evm_eoa { @@ -166,6 +182,7 @@ class basic_evm_tester : public testing::validating_tester const symbol native_symbol; static evmc::address make_reserved_address(uint64_t account); + static evmc::address make_reserved_address(name account); explicit basic_evm_tester(std::string native_symbol_str = "4,EOS"); @@ -198,8 +215,10 @@ class basic_evm_tester : public testing::validating_tester silkworm::Transaction generate_tx(const evmc::address& to, const intx::uint256& value, uint64_t gas_limit = 21000) const; + transaction_trace_ptr bridgereg(name receiver, asset min_fee, vector extra_signers={evm_account_name}); + transaction_trace_ptr bridgeunreg(name receiver); transaction_trace_ptr exec(const exec_input& input, const std::optional& callback); - void pushtx(const silkworm::Transaction& trx, name miner = evm_account_name); + transaction_trace_ptr pushtx(const silkworm::Transaction& trx, name miner = evm_account_name); void call(name from, const evmc::bytes& to, const evmc::bytes& value, evmc::bytes& data, uint64_t gas_limit, name actor); void admincall(const evmc::bytes& from, const evmc::bytes& to, const evmc::bytes& value, evmc::bytes& data, uint64_t gas_limit, name actor); evmc::address deploy_contract(evm_eoa& eoa, evmc::bytes bytecode); @@ -310,4 +329,4 @@ class speculative_block_starter bool canceled = false; }; -} // namespace evm_test \ No newline at end of file +} // namespace evm_test diff --git a/tests/bridge_emit_tests.cpp b/tests/bridge_emit_tests.cpp new file mode 100644 index 00000000..6a4f78c4 --- /dev/null +++ b/tests/bridge_emit_tests.cpp @@ -0,0 +1,239 @@ +#include "basic_evm_tester.hpp" +#include + +#include "utils.hpp" + +using intx::operator""_u256; + +using namespace evm_test; +using eosio::testing::eosio_assert_message_is; +using eosio::testing::expect_assert_message; + +struct bridge_emit_evm_tester : basic_evm_tester { + bridge_emit_evm_tester() { + create_accounts({"alice"_n}); + transfer_token(faucet_account_name, "alice"_n, make_asset(10000'0000)); + init(); + } + + std::string int_str32(uint32_t x) { + std::stringstream hex_ss; + hex_ss << std::hex << x; + int hex_length = hex_ss.str().length(); + + std::stringstream ss; + ss << std::setfill('0') << std::setw(64 - hex_length) << 0 << std::hex << std::uppercase << x; + return ss.str(); + } + + std::string str_to_hex(const std::string& str) { + std::stringstream ss; + for (char c : str) { + ss << std::hex << std::setw(2) << std::setfill('0') << static_cast(c); + } + return ss.str(); + } + + std::string data_str32(const std::string& str) { + std::stringstream ss; + ss << str; + int ps = 64 - (str.length() % 64); + if (ps == 64) {ps = 0;} + ss << std::setw(ps) << std::setfill('0') << ""; + return ss.str(); + } + + transaction_trace_ptr send_emit_message(evm_eoa& eoa, const std::string& receiver, const intx::uint256& value, const std::string& str_data) { + + silkworm::Bytes data; + data += evmc::from_hex("7e95a247").value(); + data += evmc::from_hex(int_str32(64)).value(); + data += evmc::from_hex(int_str32(128)).value(); + data += evmc::from_hex(int_str32(receiver.length())).value(); + data += evmc::from_hex(data_str32(str_to_hex(receiver))).value(); + data += evmc::from_hex(int_str32(str_data.size()/2)).value(); + data += evmc::from_hex(data_str32(str_data)).value(); + + return send_raw_message(eoa, make_reserved_address("evm"_n), value, data); + } + + transaction_trace_ptr send_raw_message(evm_eoa& eoa, const evmc::address& dest, const intx::uint256& value, const silkworm::Bytes& data) { + auto txn = generate_tx(dest, value, 250'000); + txn.data = data; + eoa.sign(txn); + return pushtx(txn); + } +}; + +BOOST_AUTO_TEST_SUITE(bridge_emit_tests) +BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_emit_evm_tester) try { + + create_accounts({"rec1"_n}); + + // evm auth is needed + BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, make_asset(-1), {}), + missing_auth_exception, [](const missing_auth_exception& e) { return expect_assert_message(e, "missing authority of evm"); }); + + // min fee only accepts EOS + BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, asset::from_string("1.0000 TST")), + eosio_assert_message_exception, eosio_assert_message_is("unexpected symbol")); + + // min fee must be non-negative + BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, make_asset(-1)), + eosio_assert_message_exception, eosio_assert_message_is("min_fee cannot be negative")); + + bridgereg("rec1"_n, make_asset(0)); + + auto row = fc::raw::unpack(get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n)); + BOOST_REQUIRE(row.account == "rec1"_n); + BOOST_REQUIRE(row.min_fee == make_asset(0)); + + // Register again changing min fee + bridgereg("rec1"_n, make_asset(1)); + + row = fc::raw::unpack(get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n)); + BOOST_REQUIRE(row.account == "rec1"_n); + BOOST_REQUIRE(row.min_fee == make_asset(1)); + + // Unregister rec1 + bridgeunreg("rec1"_n); + const auto& d = get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n); + BOOST_REQUIRE(d.size() == 0); + produce_block(); + + // Try to unregister again + BOOST_REQUIRE_EXCEPTION(bridgeunreg("rec1"_n), + eosio_assert_message_exception, eosio_assert_message_is("receiver not found")); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(basic_tests, bridge_emit_evm_tester) try { + + // Create destination account + create_accounts({"rec1"_n}); + set_code("rec1"_n, testing::contracts::evm_bridge_receiver_wasm()); + set_abi("rec1"_n, testing::contracts::evm_bridge_receiver_abi().data()); + + // Register rec1 with 1.0000 EOS as min_fee + bridgereg("rec1"_n, make_asset(10000)); + + // Fund evm1 address with 100 EOS + evm_eoa evm1; + const int64_t to_bridge = 1000000; + transfer_token("alice"_n, "evm"_n, make_asset(to_bridge), evm1.address_0x()); + + // Emit message + auto res = send_emit_message(evm1, "rec1", 1_ether, "0102030405060708090a"); + + // Recover message form the return value of rec1 contract + BOOST_CHECK(res->action_traces[1].receiver == "rec1"_n); + auto out = fc::raw::unpack(res->action_traces[1].return_value); + + BOOST_CHECK(out.receiver == "rec1"_n); + BOOST_CHECK(out.sender == to_bytes(evm1.address)); + BOOST_CHECK(out.timestamp.time_since_epoch() == control->pending_block_time().time_since_epoch()); + BOOST_CHECK(out.value == to_bytes(1_ether)); + BOOST_CHECK(out.data == to_bytes(evmc::from_hex("0102030405060708090a").value())); + +} FC_LOG_AND_RETHROW() + +BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { + + auto emv_reserved_address = make_reserved_address("evm"_n); + + // Fund evm1 address with 100 EOS + evm_eoa evm1; + const int64_t to_bridge = 1000000; + transfer_token("alice"_n, "evm"_n, make_asset(to_bridge), evm1.address_0x()); + + // Send message without call data [ok] + send_raw_message(evm1, emv_reserved_address, 0, silkworm::Bytes{}); + + // Send message with 1 byte call data (we need at least 4 bytes for the function signature) + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("01").value()), + eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); + evm1.next_nonce--; + + // Send message with 4 bytes NOT matching the 'emit_(string,bytes)' signature + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("01020304").value()), + eosio_assert_message_exception, eosio_assert_message_is("unable to decode call message")); + evm1.next_nonce--; + + // Send message with 4 bytes matching the 'emit_(string,bytes)' signature + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("7e95a247").value()), + eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); + evm1.next_nonce--; + + // Wrong p1 offset + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(11)).value()), + eosio_assert_message_exception, eosio_assert_message_is("invalid p1 offset")); + evm1.next_nonce--; + + // Wrong p2 offset + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, + evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(int_str32(11)).value()), + eosio_assert_message_exception, eosio_assert_message_is("invalid p2 offset")); + evm1.next_nonce--; + + // abcd is not an account + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, + evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("data"))).value()), + eosio_assert_message_exception, eosio_assert_message_is("receiver is not account")); + evm1.next_nonce--; + + // Create destination account + create_accounts({"abcd"_n}); + + // abcd not registered + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, + evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("data"))).value()), + eosio_assert_message_exception, eosio_assert_message_is("receiver not registered")); + evm1.next_nonce--; + + // Register rec1 with 0 EOS as min_fee + bridgereg("abcd"_n, make_asset(1)); + + // min fee not covered + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, + evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("data"))).value()), + eosio_assert_message_exception, eosio_assert_message_is("min_fee not covered")); + evm1.next_nonce--; + + // Close abcd balance + close("abcd"_n); + + // receiver account is not open + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 1e14, + evmc::from_hex("7e95a247").value() + + evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + + evmc::from_hex(int_str32(4)).value() + + evmc::from_hex(data_str32(str_to_hex("data"))).value()), + eosio_assert_message_exception, eosio_assert_message_is("receiver account is not open")); + +} FC_LOG_AND_RETHROW() + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/tests/contracts.hpp.in b/tests/contracts.hpp.in index 7b308181..7610a3f9 100644 --- a/tests/contracts.hpp.in +++ b/tests/contracts.hpp.in @@ -40,6 +40,9 @@ struct contracts { static std::vector evm_read_callback_wasm() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/contracts/evm_read_callback/evm_read_callback.wasm"); } static std::vector evm_read_callback_abi() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/contracts/evm_read_callback/evm_read_callback.abi"); } + static std::vector evm_bridge_receiver_wasm() { return read_wasm("${CMAKE_CURRENT_SOURCE_DIR}/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm"); } + static std::vector evm_bridge_receiver_abi() { return read_abi("${CMAKE_CURRENT_SOURCE_DIR}/contracts/evm_bridge_receiver/evm_bridge_receiver.abi"); } + static std::string eth_test_folder() { return "${CMAKE_CURRENT_SOURCE_DIR}/../silkworm/third_party/tests"; } diff --git a/tests/contracts/evm_bridge_receiver/README.txt b/tests/contracts/evm_bridge_receiver/README.txt new file mode 100644 index 00000000..5bd9b7bb --- /dev/null +++ b/tests/contracts/evm_bridge_receiver/README.txt @@ -0,0 +1,4 @@ + --- evm_bridge_receiver Project --- + + - How to Build - + - run the command 'cdt-cpp -abigen -o evm_bridge_receiver.wasm evm_bridge_receiver.cpp' diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi new file mode 100644 index 00000000..95c4f868 --- /dev/null +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi @@ -0,0 +1,44 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.2", + "types": [], + "structs": [ + { + "name": "onbridgemsg", + "base": "", + "fields": [ + { + "name": "receiver", + "type": "name" + }, + { + "name": "sender", + "type": "bytes" + }, + { + "name": "timestamp", + "type": "time_point" + }, + { + "name": "value", + "type": "bytes" + }, + { + "name": "data", + "type": "bytes" + } + ] + } + ], + "actions": [ + { + "name": "onbridgemsg", + "type": "onbridgemsg", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "action_results": [] +} \ No newline at end of file diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.contracts.md b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.contracts.md new file mode 100644 index 00000000..5c7d6556 --- /dev/null +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.contracts.md @@ -0,0 +1,3 @@ +

hi

+ +Stub for hi action's ricardian contract \ No newline at end of file diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp new file mode 100644 index 00000000..1c563064 --- /dev/null +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp @@ -0,0 +1,30 @@ +#include "evm_bridge_receiver.hpp" + +extern "C" { +__attribute__((eosio_wasm_import)) +void set_action_return_value(void*, size_t); +} + +struct msgin { + name receiver; + bytes sender; + time_point timestamp; + bytes value; + bytes data; + + EOSLIB_SERIALIZE(msgin, (receiver)(sender)(timestamp)(value)(data)); +}; + +void evm_bridge_receiver::onbridgemsg(name receiver, const bytes& sender, const time_point& timestamp, const bytes& value, const bytes& data) { + + msgin output { + .receiver = receiver, + .sender = sender, + .timestamp = timestamp, + .value = value, + .data = data + }; + + auto output_bin = eosio::pack(output); + set_action_return_value(output_bin.data(), output_bin.size()); +} diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp new file mode 100644 index 00000000..eb0f87c7 --- /dev/null +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp @@ -0,0 +1,11 @@ +#include +#include + +using namespace eosio; + +typedef std::vector bytes; +CONTRACT evm_bridge_receiver : public contract { + public: + using contract::contract; + [[eosio::action]] void onbridgemsg(name receiver, const bytes& sender, const time_point& timestamp, const bytes& value, const bytes& data); +}; \ No newline at end of file diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm new file mode 100755 index 0000000000000000000000000000000000000000..48733b0a9b5759ec7b1cd840cfdaef522d8ae810 GIT binary patch literal 3112 zcma)8ONbmr82;AWRk!oLUl0d>cG?n{9Vn-R|9;$xJ5_ z4?C;m;30zE;=!BXMJ3?D$7uzR9)b_hgAz~>1o7^{`2AJ;XfZ)|nXan8{>S$}yD6Kj z3nCJa-L*utB&SnaQq$>FOqU2hoOhm^IB(*-iTlk>JO$qfunQc*=_Z75khqec$&Si5 zE(O^O!*NB#`*uE@tPTg+WRim&v6dB>8Z3l2?Olxmq1=490nNalA3Ol&xLN zJ!`ykvyxTWV6ysZPKt%%ah|R0O7R_OCL7lE!rE}TTz)xQ-589rakidU`FMiua+$Aq zrRJsoVsqM#u(r{7I2um!72d2|T!tzN*i?J@;&_~IRD)`DJ*SXKhgmJ-y_DCuovP+& zyt+|M25TO`fqF~^%fpqN8tOny&6yU>v|3TCEp$g~9f*+-B2a=vctlNw-P)#TO7`t9 z_Ljzs2(r;=?K0if`s7foDLxQwlA-wSxMRqOXLWyZ>-zWKe*eplzrHs$5@#mI#{xr( zTl}~E`L*xpyzX0f{^6UCe}DZCirY~X)b4i_f&HUDfBJ1l5hPyQ+Nw!Jmf|DPSg5Il zl@3{&1<6uZUd7qQmr_xrvWJtWUg@XGP+?~aJGzikPhROmP};aM^f-%SFAC;20-Hoc zxE6h~(?|K%zO_xUh>VIPMLi*=_rgY*;-)9t5Qg1$SJJ-vE!Z{AjHO4gUhPK@3ONNd zVd!`wWM4slJeyKSSW2L%D?jL`@=QkGpSRUrZNZ?@bdqSx!Q|)my5)^X8Oh$Vg4Wo;+ z1zE=NRUL;s4eJs=1!Vyvzyk<0BhZXM!JY;J)X!-K)01a;fySPEqArvMdkAEr7=bjw zE&}FH6=WF!q7eI}aI9K|QH5!ircoMM+PFwGsLk@jM4&9-6BEQ@w7PczKWHVfdKGa(9>3#Tiai3Xj+{XDzhlh66(88F|V0?)Z3z6U7= zYpR`~(Phj*^dt_S6Kq5CA?_d0Py4Vs`q>(Np+?JmU;aiY~8hRA3K&Z7`8R3@5@T5*<3(+J;W3=#thu7o|=#Ns>w12?|lGzi2W z@gfe^HG#PUEgTi69%^mlF*nsd<*DX~9;dKP?w*|(HBs&yp*etL1=u!=_(b}DG^yKY zVg*Rx2`u+xiQZKh->kz?qhuI-ja5>XDbKCnoGAGHviM?K&i z2gf*pu4UbVj58fRoHdH4;R1Znw&A9|{n>f0P@wF&LOmhO&Ur||P40Z;u_sS@;Vw>? zW_Wgs`1mnTG|&hY(9ea=VZFU_Q&Y~Yb^UW*RlKJ^_WId&)88S%-nKK$BXq&xzyq2U z#s@0xsK-Knkh%z9#QQ#k&A3KCT%&hu^!pth3eoO}>Mf!0{k5s_(n2RCauE{~m8}(W zgvfFgASrk^zWK#Js^|ft1h0H9Tl5f@kTQY2MHdkLTjD}0s}HYmwrzu_T$rFQ?3TEI zDd&>*4ANO|W10Xj2AF(bqlzu14{)N2NKN4jRU-n--em0f+#CHs^_rT04)? z(Wt!BRP^Hs-el&@FAO3xfx|I;_#l^1?xyy_$;m8o9NO}?>0cVgvFY1pW7;yae$L!_@6qQ3#l(G?5; literal 0 HcmV?d00001 diff --git a/tests/utils.hpp b/tests/utils.hpp new file mode 100644 index 00000000..ce9f6a4f --- /dev/null +++ b/tests/utils.hpp @@ -0,0 +1,46 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace eosio; +using namespace std; +typedef intx::uint<256> u256; + +key256_t to_key256(const uint8_t* ptr, size_t len); +key256_t to_key256(const evmc::address& addr); +key256_t to_key256(const evmc::bytes32& data); +key256_t to_key256(const bytes& data); +bytes to_bytes(const u256& val); +bytes to_bytes(const silkworm::Bytes& b); +bytes to_bytes(const silkworm::ByteView& b); +bytes to_bytes(const evmc::bytes32& val); +bytes to_bytes(const evmc::address& addr); +bytes to_bytes(const key256_t& k); +evmc::address to_address(const bytes& addr); + \ No newline at end of file From b27d59bf5cf3a581cb59de3cc0005c58741ee1cf Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 24 Jul 2023 17:22:30 -0300 Subject: [PATCH 04/11] Add more tests for the 'emit' message functionality --- include/evm_runtime/bridge.hpp | 2 +- tests/bridge_emit_tests.cpp | 74 +++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/include/evm_runtime/bridge.hpp b/include/evm_runtime/bridge.hpp index 28489a74..41ceeab0 100644 --- a/include/evm_runtime/bridge.hpp +++ b/include/evm_runtime/bridge.hpp @@ -5,7 +5,7 @@ namespace evm_runtime { namespace bridge { struct emit { - static constexpr uint32_t id = 0x7e95a247; //sha3('emit_(string,bytes)')[:4] + static constexpr uint32_t id = 0x44282a35; //sha3('emit_(string,bytes)')[:4] string account; bytes data; diff --git a/tests/bridge_emit_tests.cpp b/tests/bridge_emit_tests.cpp index 6a4f78c4..9c8c4ea8 100644 --- a/tests/bridge_emit_tests.cpp +++ b/tests/bridge_emit_tests.cpp @@ -46,7 +46,7 @@ struct bridge_emit_evm_tester : basic_evm_tester { transaction_trace_ptr send_emit_message(evm_eoa& eoa, const std::string& receiver, const intx::uint256& value, const std::string& str_data) { silkworm::Bytes data; - data += evmc::from_hex("7e95a247").value(); + data += evmc::from_hex("44282a35").value(); data += evmc::from_hex(int_str32(64)).value(); data += evmc::from_hex(int_str32(128)).value(); data += evmc::from_hex(int_str32(receiver.length())).value(); @@ -160,19 +160,19 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { evm1.next_nonce--; // Send message with 4 bytes matching the 'emit_(string,bytes)' signature - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("7e95a247").value()), + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("44282a35").value()), eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); evm1.next_nonce--; // Wrong p1 offset - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("7e95a247").value() + + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(11)).value()), eosio_assert_message_exception, eosio_assert_message_is("invalid p1 offset")); evm1.next_nonce--; // Wrong p2 offset BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("7e95a247").value() + + evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(11)).value()), eosio_assert_message_exception, eosio_assert_message_is("invalid p2 offset")); @@ -180,7 +180,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // abcd is not an account BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("7e95a247").value() + + evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -195,7 +195,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // abcd not registered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("7e95a247").value() + + evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -205,12 +205,12 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { eosio_assert_message_exception, eosio_assert_message_is("receiver not registered")); evm1.next_nonce--; - // Register rec1 with 0 EOS as min_fee + // Register abcd bridgereg("abcd"_n, make_asset(1)); // min fee not covered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("7e95a247").value() + + evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -225,7 +225,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // receiver account is not open BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 1e14, - evmc::from_hex("7e95a247").value() + + evmc::from_hex("44282a35").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -236,4 +236,60 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(emit_from_solidity, bridge_emit_evm_tester) try { + // // SPDX-License-Identifier: GPL-3.0 + // pragma solidity >=0.7.0 <0.9.0; + // contract Emiter { + // function go(string memory destination, uint256 n) public { + // address eosevm = 0xBbBBbbBBbBbbbBBBbBbbBBbB56E4000000000000; + // for(uint i=0; i start('rec1', 3) + auto txn = generate_tx(contract_addr, 0, 500'000); + txn.data = evmc::from_hex("a5cc93e4").value(); + txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000040").value(); + txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000003").value(); + txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000004").value(); + txn.data += evmc::from_hex("7265633100000000000000000000000000000000000000000000000000000000").value(); + evm1.sign(txn); + auto res = pushtx(txn); + BOOST_CHECK(res->action_traces.size() == 4); + + for(int i=0; i<3; ++i) { + auto out = fc::raw::unpack(res->action_traces[1+i].return_value); + BOOST_CHECK(out.receiver == "rec1"_n); + BOOST_CHECK(out.sender == to_bytes(contract_addr)); + BOOST_CHECK(out.timestamp.time_since_epoch() == control->pending_block_time().time_since_epoch()); + BOOST_CHECK(out.value == to_bytes(0_ether)); + BOOST_CHECK(out.data == to_bytes(evmc::from_hex("00000000000000000000000000000000000000000000000000000000FFFFFF0"+std::to_string(i)).value())); + } + +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From ceb373ac3a6beb9b367a3cefff5e1e29ec832631 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Thu, 27 Jul 2023 20:51:47 -0300 Subject: [PATCH 05/11] Use EVM message filter functionality to process bridge messages --- include/evm_runtime/bridge.hpp | 2 -- silkworm | 2 +- src/actions.cpp | 55 ++++++++++++++++------------------ 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/include/evm_runtime/bridge.hpp b/include/evm_runtime/bridge.hpp index 41ceeab0..ea3a0ae3 100644 --- a/include/evm_runtime/bridge.hpp +++ b/include/evm_runtime/bridge.hpp @@ -18,8 +18,6 @@ struct emit { return *account_; } - eosio::time_point timestamp; - evmc_message message; mutable std::optional account_; }; diff --git a/silkworm b/silkworm index df5d9ca3..350cfc3c 160000 --- a/silkworm +++ b/silkworm @@ -1 +1 @@ -Subproject commit df5d9ca396b4a85ace6b85aa16bbb0e5e0f90e50 +Subproject commit 350cfc3c4c71f0882bceb0290a166480cdc52e2d diff --git a/src/actions.cpp b/src/actions.cpp index ff9cc1f6..6f02986f 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -416,20 +416,21 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { check(tx.max_priority_fee_per_gas == tx.max_fee_per_gas, "max_priority_fee_per_gas must be equal to max_fee_per_gas"); check(tx.max_fee_per_gas >= current_config.gas_price, "gas price is too low"); - // handler for all EVM call messages - std::vector emit_messages; - ep.set_evm_call_hook([&](const evmc_message& message, const evmc::Result& result){ - static auto me = make_reserved_address(get_self().value); - if (message.recipient != me || message.input_size == 0) return; + // 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 { + auto me = make_reserved_address(get_self().value); + return message.recipient == me && message.input_size > 0; + }); + + auto receipt = execute_tx(miner, block, tx, ep, true); - eosio::check(result.status_code == EVMC_SUCCESS, "error calling reserved address"); + for(const auto& msg : ep.state().filtered_messages()) { - auto call = bridge::decode_call_message(ByteView{message.input_data, message.input_size}); + auto call = bridge::decode_call_message(ByteView{msg.data}); eosio::check(call.has_value(), "unable to decode call message"); auto& emit = std::get(call.value()); - emit.message = message; - emit.timestamp = eosio::current_time_point(); const auto& receiver = emit.get_account_as_name(); eosio::check(eosio::is_account(receiver), "receiver is not account"); @@ -441,33 +442,29 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { intx::uint256 min_fee((uint64_t)it->min_fee.amount); min_fee *= minimum_natively_representable; - auto value = intx::be::unsafe::load(message.value.bytes); + auto value = intx::be::unsafe::load(msg.value.bytes); eosio::check(value >= min_fee, "min_fee not covered"); - emit_messages.push_back(emit); - }); - - auto receipt = execute_tx(miner, block, tx, ep, true); - - // Process emit messages - for(const auto& emit : emit_messages) { balances balance_table(get_self(), get_self().value); const balance& receiver_account = balance_table.get(emit.get_account_as_name().value, "receiver account is not open"); - bridge_emit_message msg { - .receiver = emit.get_account_as_name(), - .sender = to_bytes(emit.message.sender), - .timestamp = emit.timestamp, - .value = to_bytes(emit.message.value), - .data = emit.data - }; - - action(std::vector{}, emit.get_account_as_name(), "onbridgemsg"_n, msg + action(std::vector{}, emit.get_account_as_name(), "onbridgemsg"_n, + bridge_emit_message{ + .receiver = emit.get_account_as_name(), + .sender = to_bytes(msg.sender), + .timestamp = eosio::current_time_point(), + .value = to_bytes(msg.value), + .data = emit.data + } ).send(); - auto value = intx::be::unsafe::load(emit.message.value.bytes); - balance_table.modify(receiver_account, eosio::same_payer, [&](balance& a) { - a.balance += value; + balance_table.modify(receiver_account, eosio::same_payer, [&](balance& row) { + row.balance += value; + }); + + const balance& self_account = balance_table.get(get_self().value, "self account is not open"); + balance_table.modify(self_account, eosio::same_payer, [&](balance& row) { + row.balance -= value; }); } From ba12a9ef0be328655a7d340ab3aad06b3e59812e Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 16 Aug 2023 03:13:23 -0300 Subject: [PATCH 06/11] tests: move inevm function to base tester class --- tests/basic_evm_tester.cpp | 4 ++++ tests/basic_evm_tester.hpp | 1 + tests/native_token_tester.hpp | 5 ----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 5314dc06..e6fbe2a3 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -400,6 +400,10 @@ void basic_evm_tester::withdraw(name owner, asset quantity) push_action(evm_account_name, "withdraw"_n, owner, mvo()("owner", owner)("quantity", quantity)); } +balance_and_dust basic_evm_tester::inevm() const { + return fc::raw::unpack(get_row_by_account(evm_account_name, evm_account_name, "inevm"_n, "inevm"_n)); +} + balance_and_dust basic_evm_tester::vault_balance(name owner) const { const vector d = get_row_by_account(evm_account_name, evm_account_name, "balances"_n, owner); diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index 049c93b9..fb896199 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -230,6 +230,7 @@ class basic_evm_tester : public testing::validating_tester void close(name owner); void withdraw(name owner, asset quantity); + balance_and_dust inevm() const; balance_and_dust vault_balance(name owner) const; std::optional evm_balance(const evmc::address& address) const; std::optional evm_balance(const evm_eoa& account) const; diff --git a/tests/native_token_tester.hpp b/tests/native_token_tester.hpp index 720386ec..2f8b267f 100644 --- a/tests/native_token_tester.hpp +++ b/tests/native_token_tester.hpp @@ -51,11 +51,6 @@ struct native_token_evm_tester : basic_evm_tester { uint64_t vault_balance_dust(name owner) const { return vault_balance(owner).dust; } - - balance_and_dust inevm() const - { - return fc::raw::unpack(get_row_by_account("evm"_n, "evm"_n, "inevm"_n, "inevm"_n)); - } }; struct native_token_evm_tester_EOS : native_token_evm_tester { From 0e0cb6229f681990809bccc2f4bf5f6e47b46942 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 16 Aug 2023 19:22:35 -0300 Subject: [PATCH 07/11] Remove balance modification for the EOS EVM contract account The accounting is already being done in the execute_tx function when substracting all the final balance of any reserved address --- src/actions.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/actions.cpp b/src/actions.cpp index 6f02986f..f20484b0 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -461,11 +461,6 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { balance_table.modify(receiver_account, eosio::same_payer, [&](balance& row) { row.balance += value; }); - - const balance& self_account = balance_table.get(get_self().value, "self account is not open"); - balance_table.modify(self_account, eosio::same_payer, [&](balance& row) { - row.balance -= value; - }); } engine.finalize(ep.state(), ep.evm().block()); From 474104b9b1f07850f00063d3a28f0a96e45d549b Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Wed, 16 Aug 2023 19:28:30 -0300 Subject: [PATCH 08/11] Add versioning to the bridge message --- include/evm_runtime/bridge.hpp | 14 +- include/evm_runtime/types.hpp | 6 +- src/actions.cpp | 30 ++-- tests/CMakeLists.txt | 2 +- tests/basic_evm_tester.hpp | 6 +- ...mit_tests.cpp => bridge_message_tests.cpp} | 141 +++++++++++------- .../evm_bridge_receiver.abi | 26 +++- .../evm_bridge_receiver.cpp | 23 +-- .../evm_bridge_receiver.hpp | 16 +- .../evm_bridge_receiver.wasm | Bin 3112 -> 3685 bytes 10 files changed, 155 insertions(+), 109 deletions(-) rename tests/{bridge_emit_tests.cpp => bridge_message_tests.cpp} (74%) diff --git a/include/evm_runtime/bridge.hpp b/include/evm_runtime/bridge.hpp index ea3a0ae3..17fb3e42 100644 --- a/include/evm_runtime/bridge.hpp +++ b/include/evm_runtime/bridge.hpp @@ -4,8 +4,8 @@ namespace evm_runtime { namespace bridge { -struct emit { - static constexpr uint32_t id = 0x44282a35; //sha3('emit_(string,bytes)')[:4] +struct message_v0 { + static constexpr uint32_t id = 0x24578ea5; //sha3('bridgeMsgV0(string,bytes)')[:4] string account; bytes data; @@ -21,9 +21,9 @@ struct emit { mutable std::optional account_; }; -using call = std::variant; +using message = std::variant; -std::optional decode_emit_message(eosio::datastream& ds) { +message_v0 decode_message_v0(eosio::datastream& ds) { // offset_p1 (32) + offset_p2 (32) // p1_len (32) + p1_data ((p1_len+31)/32*32) // p2_len (32) + p1_data ((p2_len+31)/32*32) @@ -35,7 +35,7 @@ std::optional decode_emit_message(eosio::datastream& ds) { ds >> offset_p2; eosio::check(offset_p2 == 0x80, "invalid p2 offset"); - emit res; + message_v0 res; auto get_length=[&]() -> uint32_t { uint256 len; @@ -59,13 +59,13 @@ std::optional decode_emit_message(eosio::datastream& ds) { return res; } -std::optional decode_call_message(ByteView bv) { +std::optional decode_message(ByteView bv) { // method_id (4) eosio::datastream ds(bv.data(), bv.size()); uint32_t method_id; ds >> method_id; - if(method_id == __builtin_bswap32(emit::id)) return decode_emit_message(ds); + if(method_id == __builtin_bswap32(message_v0::id)) return decode_message_v0(ds); return {}; } diff --git a/include/evm_runtime/types.hpp b/include/evm_runtime/types.hpp index 09605bff..50a6293c 100644 --- a/include/evm_runtime/types.hpp +++ b/include/evm_runtime/types.hpp @@ -63,16 +63,18 @@ namespace evm_runtime { EOSLIB_SERIALIZE(exec_output, (status)(data)(context)); }; - struct bridge_emit_message { + struct bridge_message_v0 { eosio::name receiver; bytes sender; eosio::time_point timestamp; bytes value; bytes data; - EOSLIB_SERIALIZE(bridge_emit_message, (receiver)(sender)(timestamp)(value)(data)); + EOSLIB_SERIALIZE(bridge_message_v0, (receiver)(sender)(timestamp)(value)(data)); }; + using bridge_message = std::variant; + } //namespace evm_runtime namespace eosio { diff --git a/src/actions.cpp b/src/actions.cpp index f20484b0..32e26210 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -419,20 +419,20 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { // 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 { - auto me = make_reserved_address(get_self().value); + static auto me = make_reserved_address(get_self().value); return message.recipient == me && message.input_size > 0; }); auto receipt = execute_tx(miner, block, tx, ep, true); - for(const auto& msg : ep.state().filtered_messages()) { + for(const auto& rawmsg : ep.state().filtered_messages()) { - auto call = bridge::decode_call_message(ByteView{msg.data}); - eosio::check(call.has_value(), "unable to decode call message"); + auto msg = bridge::decode_message(ByteView{rawmsg.data}); + eosio::check(msg.has_value(), "unable to decode bridge message"); - auto& emit = std::get(call.value()); + auto& msg_v0 = std::get(msg.value()); - const auto& receiver = emit.get_account_as_name(); + const auto& receiver = msg_v0.get_account_as_name(); eosio::check(eosio::is_account(receiver), "receiver is not account"); message_receiver_table message_receivers(get_self(), get_self().value); @@ -442,20 +442,20 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { intx::uint256 min_fee((uint64_t)it->min_fee.amount); min_fee *= minimum_natively_representable; - auto value = intx::be::unsafe::load(msg.value.bytes); + auto value = intx::be::unsafe::load(rawmsg.value.bytes); eosio::check(value >= min_fee, "min_fee not covered"); balances balance_table(get_self(), get_self().value); - const balance& receiver_account = balance_table.get(emit.get_account_as_name().value, "receiver account is not open"); + const balance& receiver_account = balance_table.get(msg_v0.get_account_as_name().value, "receiver account is not open"); - action(std::vector{}, emit.get_account_as_name(), "onbridgemsg"_n, - bridge_emit_message{ - .receiver = emit.get_account_as_name(), - .sender = to_bytes(msg.sender), + action(std::vector{}, msg_v0.get_account_as_name(), "onbridgemsg"_n, + bridge_message{ bridge_message_v0 { + .receiver = msg_v0.get_account_as_name(), + .sender = to_bytes(rawmsg.sender), .timestamp = eosio::current_time_point(), - .value = to_bytes(msg.value), - .data = emit.data - } + .value = to_bytes(rawmsg.value), + .data = msg_v0.data + } } ).send(); balance_table.modify(receiver_account, eosio::same_payer, [&](balance& row) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06e48110..2b1ead9f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -32,7 +32,7 @@ add_eosio_test_executable( unit_test ${CMAKE_SOURCE_DIR}/exec_tests.cpp ${CMAKE_SOURCE_DIR}/call_tests.cpp ${CMAKE_SOURCE_DIR}/chainid_tests.cpp - ${CMAKE_SOURCE_DIR}/bridge_emit_tests.cpp + ${CMAKE_SOURCE_DIR}/bridge_message_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 diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index fb896199..5dfe3eae 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -114,7 +114,7 @@ struct message_receiver { asset min_fee; }; -struct bridge_emit_message { +struct bridge_message_v0 { name receiver; bytes sender; time_point timestamp; @@ -122,6 +122,8 @@ struct bridge_emit_message { bytes data; }; +using bridge_message = std::variant; + } // namespace evm_test @@ -137,7 +139,7 @@ FC_REFLECT(evm_test::exec_callback, (contract)(action)) FC_REFLECT(evm_test::exec_output, (status)(data)(context)) FC_REFLECT(evm_test::message_receiver, (account)(min_fee)); -FC_REFLECT(evm_test::bridge_emit_message, (receiver)(sender)(timestamp)(value)(data)); +FC_REFLECT(evm_test::bridge_message_v0, (receiver)(sender)(timestamp)(value)(data)); namespace evm_test { class evm_eoa diff --git a/tests/bridge_emit_tests.cpp b/tests/bridge_message_tests.cpp similarity index 74% rename from tests/bridge_emit_tests.cpp rename to tests/bridge_message_tests.cpp index 9c8c4ea8..42d3e774 100644 --- a/tests/bridge_emit_tests.cpp +++ b/tests/bridge_message_tests.cpp @@ -9,21 +9,22 @@ using namespace evm_test; using eosio::testing::eosio_assert_message_is; using eosio::testing::expect_assert_message; -struct bridge_emit_evm_tester : basic_evm_tester { - bridge_emit_evm_tester() { +struct bridge_message_tester : basic_evm_tester { + bridge_message_tester() { create_accounts({"alice"_n}); transfer_token(faucet_account_name, "alice"_n, make_asset(10000'0000)); init(); + open("alice"_n); } std::string int_str32(uint32_t x) { - std::stringstream hex_ss; - hex_ss << std::hex << x; - int hex_length = hex_ss.str().length(); + std::stringstream hex_ss; + hex_ss << std::hex << x; + int hex_length = hex_ss.str().length(); - std::stringstream ss; - ss << std::setfill('0') << std::setw(64 - hex_length) << 0 << std::hex << std::uppercase << x; - return ss.str(); + std::stringstream ss; + ss << std::setfill('0') << std::setw(64 - hex_length) << 0 << std::hex << std::uppercase << x; + return ss.str(); } std::string str_to_hex(const std::string& str) { @@ -35,18 +36,18 @@ struct bridge_emit_evm_tester : basic_evm_tester { } std::string data_str32(const std::string& str) { - std::stringstream ss; - ss << str; - int ps = 64 - (str.length() % 64); - if (ps == 64) {ps = 0;} - ss << std::setw(ps) << std::setfill('0') << ""; - return ss.str(); + std::stringstream ss; + ss << str; + int ps = 64 - (str.length() % 64); + if (ps == 64) {ps = 0;} + ss << std::setw(ps) << std::setfill('0') << ""; + return ss.str(); } - transaction_trace_ptr send_emit_message(evm_eoa& eoa, const std::string& receiver, const intx::uint256& value, const std::string& str_data) { + transaction_trace_ptr send_bridge_message(evm_eoa& eoa, const std::string& receiver, const intx::uint256& value, const std::string& str_data) { silkworm::Bytes data; - data += evmc::from_hex("44282a35").value(); + data += evmc::from_hex("24578ea5").value(); data += evmc::from_hex(int_str32(64)).value(); data += evmc::from_hex(int_str32(128)).value(); data += evmc::from_hex(int_str32(receiver.length())).value(); @@ -54,22 +55,22 @@ struct bridge_emit_evm_tester : basic_evm_tester { data += evmc::from_hex(int_str32(str_data.size()/2)).value(); data += evmc::from_hex(data_str32(str_data)).value(); - return send_raw_message(eoa, make_reserved_address("evm"_n), value, data); + return send_raw_message(eoa, make_reserved_address(evm_account_name), value, data); } transaction_trace_ptr send_raw_message(evm_eoa& eoa, const evmc::address& dest, const intx::uint256& value, const silkworm::Bytes& data) { auto txn = generate_tx(dest, value, 250'000); txn.data = data; eoa.sign(txn); - return pushtx(txn); + return pushtx(txn, "alice"_n); } }; -BOOST_AUTO_TEST_SUITE(bridge_emit_tests) -BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_emit_evm_tester) try { +BOOST_AUTO_TEST_SUITE(bridge_message_tests) +BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_message_tester) try { create_accounts({"rec1"_n}); - + // evm auth is needed BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, make_asset(-1), {}), missing_auth_exception, [](const missing_auth_exception& e) { return expect_assert_message(e, "missing authority of evm"); }); @@ -84,20 +85,20 @@ BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_emit_evm_tester) try { bridgereg("rec1"_n, make_asset(0)); - auto row = fc::raw::unpack(get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n)); + auto row = fc::raw::unpack(get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n)); BOOST_REQUIRE(row.account == "rec1"_n); BOOST_REQUIRE(row.min_fee == make_asset(0)); // Register again changing min fee bridgereg("rec1"_n, make_asset(1)); - row = fc::raw::unpack(get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n)); + row = fc::raw::unpack(get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n)); BOOST_REQUIRE(row.account == "rec1"_n); BOOST_REQUIRE(row.min_fee == make_asset(1)); // Unregister rec1 bridgeunreg("rec1"_n); - const auto& d = get_row_by_account( "evm"_n, "evm"_n, "msgreceiver"_n, "rec1"_n); + const auto& d = get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n); BOOST_REQUIRE(d.size() == 0); produce_block(); @@ -107,44 +108,67 @@ BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_emit_evm_tester) try { } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(basic_tests, bridge_emit_evm_tester) try { +BOOST_FIXTURE_TEST_CASE(basic_tests, bridge_message_tester) try { // Create destination account create_accounts({"rec1"_n}); set_code("rec1"_n, testing::contracts::evm_bridge_receiver_wasm()); set_abi("rec1"_n, testing::contracts::evm_bridge_receiver_abi().data()); - // Register rec1 with 1.0000 EOS as min_fee - bridgereg("rec1"_n, make_asset(10000)); + // Register rec1 with 1000.0000 EOS as min_fee + bridgereg("rec1"_n, make_asset(10000000)); - // Fund evm1 address with 100 EOS + // Fund evm1 address with 1001 EOS evm_eoa evm1; - const int64_t to_bridge = 1000000; - transfer_token("alice"_n, "evm"_n, make_asset(to_bridge), evm1.address_0x()); + const int64_t to_bridge = 10010000; + transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x()); + + // Get `rec1` and contract balance before sending the message + auto pre_evm_balance = inevm(); + auto pre_rec1_balance = vault_balance("rec1"_n); + BOOST_CHECK(pre_rec1_balance.balance == make_asset(0)); // 0.0000 EOS + BOOST_CHECK(pre_rec1_balance.dust == 0); // Emit message - auto res = send_emit_message(evm1, "rec1", 1_ether, "0102030405060708090a"); + auto res = send_bridge_message(evm1, "rec1", 1000*1_ether, "0102030405060708090a"); + + // Get `rec1` and contract balance after sending the message + auto post_evm_balance = inevm(); + auto post_rec1_balance = vault_balance("rec1"_n); + BOOST_CHECK(post_rec1_balance.balance == make_asset(10000000)); //1000.0000 EOS + BOOST_CHECK(post_rec1_balance.dust == 0); + + // The data length of the bridge message transaction is 196 bytes long + // 22 non zero, 174 zero => total gas is: 21000 + 174*4+22*16 + auto total_gas_fee = intx::uint256(suggested_gas_price)*intx::uint256(21000+174*4+22*16); + dlog("totalgas: ${t}", ("t",total_gas_fee)); + + // Check that the EOS `out` from the EVM is equal to the value sent in the bridge transaction (goes to rec1) + // plus the transaction fee (goes to miner) + auto diff = static_cast(pre_evm_balance)-static_cast(post_evm_balance); + BOOST_CHECK_EQUAL(diff, 1000*1_ether + total_gas_fee); // Recover message form the return value of rec1 contract BOOST_CHECK(res->action_traces[1].receiver == "rec1"_n); - auto out = fc::raw::unpack(res->action_traces[1].return_value); + auto msgout = fc::raw::unpack(res->action_traces[1].return_value); + auto out = std::get(msgout); BOOST_CHECK(out.receiver == "rec1"_n); BOOST_CHECK(out.sender == to_bytes(evm1.address)); BOOST_CHECK(out.timestamp.time_since_epoch() == control->pending_block_time().time_since_epoch()); - BOOST_CHECK(out.value == to_bytes(1_ether)); + BOOST_CHECK(out.value == to_bytes(1000*1_ether)); BOOST_CHECK(out.data == to_bytes(evmc::from_hex("0102030405060708090a").value())); } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { +BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { - auto emv_reserved_address = make_reserved_address("evm"_n); + auto emv_reserved_address = make_reserved_address(evm_account_name); // Fund evm1 address with 100 EOS evm_eoa evm1; const int64_t to_bridge = 1000000; - transfer_token("alice"_n, "evm"_n, make_asset(to_bridge), evm1.address_0x()); + transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x()); // Send message without call data [ok] send_raw_message(evm1, emv_reserved_address, 0, silkworm::Bytes{}); @@ -154,25 +178,25 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); evm1.next_nonce--; - // Send message with 4 bytes NOT matching the 'emit_(string,bytes)' signature + // Send message with 4 bytes NOT matching the 'bridgeMsgV0(string,bytes)' signature BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("01020304").value()), - eosio_assert_message_exception, eosio_assert_message_is("unable to decode call message")); + eosio_assert_message_exception, eosio_assert_message_is("unable to decode bridge message")); evm1.next_nonce--; - // Send message with 4 bytes matching the 'emit_(string,bytes)' signature - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("44282a35").value()), + // Send message with 4 bytes matching the 'bridgeMsgV0(string,bytes)' signature + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("24578ea5").value()), eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); evm1.next_nonce--; // Wrong p1 offset - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("44282a35").value() + + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(11)).value()), eosio_assert_message_exception, eosio_assert_message_is("invalid p1 offset")); evm1.next_nonce--; // Wrong p2 offset BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("44282a35").value() + + evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(11)).value()), eosio_assert_message_exception, eosio_assert_message_is("invalid p2 offset")); @@ -180,7 +204,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // abcd is not an account BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("44282a35").value() + + evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -195,7 +219,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // abcd not registered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("44282a35").value() + + evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -210,7 +234,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // min fee not covered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("44282a35").value() + + evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -225,7 +249,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { // receiver account is not open BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 1e14, - evmc::from_hex("44282a35").value() + + evmc::from_hex("24578ea5").value() + evmc::from_hex(int_str32(64)).value() + evmc::from_hex(int_str32(128)).value() + evmc::from_hex(int_str32(4)).value() + @@ -236,7 +260,7 @@ BOOST_FIXTURE_TEST_CASE(test_emit_errors, bridge_emit_evm_tester) try { } FC_LOG_AND_RETHROW() -BOOST_FIXTURE_TEST_CASE(emit_from_solidity, bridge_emit_evm_tester) try { +BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester) try { // // SPDX-License-Identifier: GPL-3.0 // pragma solidity >=0.7.0 <0.9.0; // contract Emiter { @@ -244,12 +268,12 @@ BOOST_FIXTURE_TEST_CASE(emit_from_solidity, bridge_emit_evm_tester) try { // address eosevm = 0xBbBBbbBBbBbbbBBBbBbbBBbB56E4000000000000; // for(uint i=0; i start('rec1', 3) + // Call method "go" on emiter contract (sha3('go(string,uint)') = 0xa5cc93e4) + // ===> go('rec1', 3) auto txn = generate_tx(contract_addr, 0, 500'000); txn.data = evmc::from_hex("a5cc93e4").value(); - txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000040").value(); - txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000003").value(); - txn.data += evmc::from_hex("0000000000000000000000000000000000000000000000000000000000000004").value(); - txn.data += evmc::from_hex("7265633100000000000000000000000000000000000000000000000000000000").value(); + txn.data += evmc::from_hex(int_str32(64)).value(); //offset of param1 + txn.data += evmc::from_hex(int_str32(3)).value(); //param2 + txn.data += evmc::from_hex(int_str32(4)).value(); //param1 size + txn.data += evmc::from_hex(data_str32(str_to_hex("rec1"))).value(); //param1 data evm1.sign(txn); + auto res = pushtx(txn); BOOST_CHECK(res->action_traces.size() == 4); for(int i=0; i<3; ++i) { - auto out = fc::raw::unpack(res->action_traces[1+i].return_value); + auto msgout = fc::raw::unpack(res->action_traces[1+i].return_value); + auto out = std::get(msgout); + BOOST_CHECK(out.receiver == "rec1"_n); BOOST_CHECK(out.sender == to_bytes(contract_addr)); BOOST_CHECK(out.timestamp.time_since_epoch() == control->pending_block_time().time_since_epoch()); diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi index 95c4f868..d3c52c8b 100644 --- a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.abi @@ -1,10 +1,15 @@ { "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", "version": "eosio::abi/1.2", - "types": [], + "types": [ + { + "new_type_name": "bridge_message", + "type": "variant_bridge_message_v0" + } + ], "structs": [ { - "name": "onbridgemsg", + "name": "bridge_message_v0", "base": "", "fields": [ { @@ -28,6 +33,16 @@ "type": "bytes" } ] + }, + { + "name": "onbridgemsg", + "base": "", + "fields": [ + { + "name": "msg", + "type": "bridge_message" + } + ] } ], "actions": [ @@ -39,6 +54,11 @@ ], "tables": [], "ricardian_clauses": [], - "variants": [], + "variants": [ + { + "name": "variant_bridge_message_v0", + "types": ["bridge_message_v0"] + } + ], "action_results": [] } \ No newline at end of file diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp index 1c563064..92854950 100644 --- a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.cpp @@ -5,26 +5,7 @@ __attribute__((eosio_wasm_import)) void set_action_return_value(void*, size_t); } -struct msgin { - name receiver; - bytes sender; - time_point timestamp; - bytes value; - bytes data; - - EOSLIB_SERIALIZE(msgin, (receiver)(sender)(timestamp)(value)(data)); -}; - -void evm_bridge_receiver::onbridgemsg(name receiver, const bytes& sender, const time_point& timestamp, const bytes& value, const bytes& data) { - - msgin output { - .receiver = receiver, - .sender = sender, - .timestamp = timestamp, - .value = value, - .data = data - }; - - auto output_bin = eosio::pack(output); +void evm_bridge_receiver::onbridgemsg(const bridge_message& msg) { + auto output_bin = eosio::pack(msg); set_action_return_value(output_bin.data(), output_bin.size()); } diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp index eb0f87c7..af914e11 100644 --- a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp +++ b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.hpp @@ -1,11 +1,25 @@ #include +#include #include using namespace eosio; typedef std::vector bytes; + +struct bridge_message_v0 { + name receiver; + bytes sender; + time_point timestamp; + bytes value; + bytes data; + + EOSLIB_SERIALIZE(bridge_message_v0, (receiver)(sender)(timestamp)(value)(data)); +}; + +using bridge_message = std::variant; + CONTRACT evm_bridge_receiver : public contract { public: using contract::contract; - [[eosio::action]] void onbridgemsg(name receiver, const bytes& sender, const time_point& timestamp, const bytes& value, const bytes& data); + [[eosio::action]] void onbridgemsg(const bridge_message& msg); }; \ No newline at end of file diff --git a/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm b/tests/contracts/evm_bridge_receiver/evm_bridge_receiver.wasm index 48733b0a9b5759ec7b1cd840cfdaef522d8ae810..c112091faaf80fe80b04d17c96a198119489a2e8 100755 GIT binary patch literal 3685 zcmb7HOK%(36+ZVdLs~;xW5=}>yDjcawV(kNFwm41i~`{moZ4yA)(Ntw$KurHP$Fq^ ztTbJ4)WC}@yhwKW0Rfyvofz$=$x8kO4Uhy#7HtBgfPn%*_E}W<&K;7Xfe2O!NcVN_ zd4A`dJCuyK1rdoW$FCDzmqkI>RZ$e8xK8-PdisBY^#tn)&LF0hci!}myj zDC;Wi@0=N@c{|z6yMumvl;(Fv{q|0>btfgkr(SYnFv^K|UP}k#?x3BF$0@elvA>;e zZw_B4$>-seODD;b_PG1!l$6^ZrAcQdfzL?uwqdz9wg#KM&09&g-ySBTWIN5%(HPUs zUfL-on43={bKFidx8Z0o9E{TrPdaxt!HPVm_~xC_DDCI%yt|!}&s(RME$h3JE>JsG z)#0ey&&TbpQh^hTR<}0?os=r-nUhpKwnWF4mVzZANYv_DYflV?5T3%?KdlO3clRhL z$liZ6A1cR$mkftnuha3RFVCFR6rKnsWGMVmST|(E%eu9(`|$HmKmX6a9=}@{i8XJB z=R89jyZqbx=$+5#72UFK{lzDL|K^QvDXay7w{SjX1oHR4`}cpRjBw*GySocF0!!iP zU?fx_A*D{1ma%22A@5;r!<|@Uv20>h?%r+1%1~yPGdsK;Q&Zk;;i9x*Zs@ms9dnT} zy%Cs1BEYd|ku9$9seNmYLKzqpND7)l6hDKEUW}8btl=``)*6xy*zZEFabhezkMUkB z_=S)KR1=2IMMAa|_=n3e)rF-9j2iN%7}(skM)Dti+spaw#cyQZ&col{SA7hPOuVo zYFqrej!-pZHP*1dmcf>|(ld(5D@OMo9Cn{C8Fy**|GTv2E?qdvrE4$D6jdCHNaIh{ z1pEVks9v~Y#4qJ~1ei6Xjx-M-2#hqE-64%?N?i^FFL?JOMB8}m1rJ`Z6=1;b)9ukE zT48U1r={Pxu>XU@ZY1*sLj{nmWLAXgEVBbnVrGpy-Zl6SWYtJRvB3EquEW))4B78j z>LLiAB~}Wc1JG6+FF*jStjSg>ct;8kXm$~S3DsCSgJRV);>9{^t}I<5gxT%Sq$6HM z7K=L7Bm@KG96Q~MJp=W8Tf78-?c-O8lw%FA04?@^*it~g@gZO2$PNJG#dC4#Vn~W4 zyI6%MBj6s^W)Ucjm&I_!fiCO>#@SSd0N&#$lv)S~>P74yh`0(_0GE;MJr^R5pz$4I z%MgK}DS<=88;*G?!q= zk`A@`_)%?Mb%LL6bLqUP%|M2ARf8|D9ZBo@QM9ffRqG2*aP0SD^}~_!ku(f(hcDy} zqlSsrKo3jH8S3K;j*hIoOfkw>BSms0Aern z&T_T`yO+xW;OG4;_L}nQ1_8PXjzTL?D3Z1@pM~>Tbv{GeST~AkO*yQT1M4OgN)mI1 zMredzyNU=9UXD1MeolnK3&~S#Uq(IgI749azPKIB{J~uZP}n4Hb7D(d$s*K~hP;ZK zsMoGwD!WG+`1tq3A4A=bc@dsrs%vNz7+yu$3a2TKE#~B`$37}W8R2!;$I3bS%be!I z0u7qge1FyLGk5g8`EG5xix_dtzK~_R-$TUIY8fEO(os4V9DLwvbO`tp1nkeo6K+K- z;7zn>cRl>cSttt}&lP7(^CO@{Id=~@thA4lbau3w9USp}^osIM?TG`U&Z{cNU$BiK zS6a-@D|1nyXYyX7DNQ+ht|`}$T412g%TstiU;!~$tnmU3!F4jIFHe=L(lmGL0tjJ+ zv$`RFh42cdU&ruVsS$z<@Vxz~d_{4vx#I~uiQoZLIk<$YwnWu-&oTSh;fy!A|DbIw zR4@(Kb4z#C4_yuJL{ZPepTtS18yD|AqESM^|`SlU+3kD>jx{1 z$L9w^xmRys{+M*P(vHaoCfUL#Pm-r*nA}XqH2c|ydlbAjTk%)YILCL>wn_3l-5%!U z<<~}CcXOPZ{8nnxeuwZKLx+*`hZp25Po%BxxlLGyoA^ILm C*lq*> literal 3112 zcma)8ONbmr82;AWRk!oLUl0d>cG?n{9Vn-R|9;$xJ5_ z4?C;m;30zE;=!BXMJ3?D$7uzR9)b_hgAz~>1o7^{`2AJ;XfZ)|nXan8{>S$}yD6Kj z3nCJa-L*utB&SnaQq$>FOqU2hoOhm^IB(*-iTlk>JO$qfunQc*=_Z75khqec$&Si5 zE(O^O!*NB#`*uE@tPTg+WRim&v6dB>8Z3l2?Olxmq1=490nNalA3Ol&xLN zJ!`ykvyxTWV6ysZPKt%%ah|R0O7R_OCL7lE!rE}TTz)xQ-589rakidU`FMiua+$Aq zrRJsoVsqM#u(r{7I2um!72d2|T!tzN*i?J@;&_~IRD)`DJ*SXKhgmJ-y_DCuovP+& zyt+|M25TO`fqF~^%fpqN8tOny&6yU>v|3TCEp$g~9f*+-B2a=vctlNw-P)#TO7`t9 z_Ljzs2(r;=?K0if`s7foDLxQwlA-wSxMRqOXLWyZ>-zWKe*eplzrHs$5@#mI#{xr( zTl}~E`L*xpyzX0f{^6UCe}DZCirY~X)b4i_f&HUDfBJ1l5hPyQ+Nw!Jmf|DPSg5Il zl@3{&1<6uZUd7qQmr_xrvWJtWUg@XGP+?~aJGzikPhROmP};aM^f-%SFAC;20-Hoc zxE6h~(?|K%zO_xUh>VIPMLi*=_rgY*;-)9t5Qg1$SJJ-vE!Z{AjHO4gUhPK@3ONNd zVd!`wWM4slJeyKSSW2L%D?jL`@=QkGpSRUrZNZ?@bdqSx!Q|)my5)^X8Oh$Vg4Wo;+ z1zE=NRUL;s4eJs=1!Vyvzyk<0BhZXM!JY;J)X!-K)01a;fySPEqArvMdkAEr7=bjw zE&}FH6=WF!q7eI}aI9K|QH5!ircoMM+PFwGsLk@jM4&9-6BEQ@w7PczKWHVfdKGa(9>3#Tiai3Xj+{XDzhlh66(88F|V0?)Z3z6U7= zYpR`~(Phj*^dt_S6Kq5CA?_d0Py4Vs`q>(Np+?JmU;aiY~8hRA3K&Z7`8R3@5@T5*<3(+J;W3=#thu7o|=#Ns>w12?|lGzi2W z@gfe^HG#PUEgTi69%^mlF*nsd<*DX~9;dKP?w*|(HBs&yp*etL1=u!=_(b}DG^yKY zVg*Rx2`u+xiQZKh->kz?qhuI-ja5>XDbKCnoGAGHviM?K&i z2gf*pu4UbVj58fRoHdH4;R1Znw&A9|{n>f0P@wF&LOmhO&Ur||P40Z;u_sS@;Vw>? zW_Wgs`1mnTG|&hY(9ea=VZFU_Q&Y~Yb^UW*RlKJ^_WId&)88S%-nKK$BXq&xzyq2U z#s@0xsK-Knkh%z9#QQ#k&A3KCT%&hu^!pth3eoO}>Mf!0{k5s_(n2RCauE{~m8}(W zgvfFgASrk^zWK#Js^|ft1h0H9Tl5f@kTQY2MHdkLTjD}0s}HYmwrzu_T$rFQ?3TEI zDd&>*4ANO|W10Xj2AF(bqlzu14{)N2NKN4jRU-n--em0f+#CHs^_rT04)? z(Wt!BRP^Hs-el&@FAO3xfx|I;_#l^1?xyy_$;m8o9NO}?>0cVgvFY1pW7;yae$L!_@6qQ3#l(G?5; From c80295f262dbfc69bbd6b738b55088c475683d2b Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 21 Aug 2023 15:21:02 -0300 Subject: [PATCH 09/11] Add force_atomic parameter to method bridgeMsgV0 --- include/evm_runtime/bridge.hpp | 31 ++++--- include/evm_runtime/evm_contract.hpp | 1 + include/evm_runtime/print_tracer.hpp | 18 ++-- include/evm_runtime/tables.hpp | 17 +++- silkworm | 2 +- src/actions.cpp | 129 +++++++++++++++++++-------- tests/basic_evm_tester.cpp | 34 +++++++ tests/basic_evm_tester.hpp | 13 ++- tests/bridge_message_tests.cpp | 126 +++++++++++++------------- 9 files changed, 244 insertions(+), 127 deletions(-) diff --git a/include/evm_runtime/bridge.hpp b/include/evm_runtime/bridge.hpp index 17fb3e42..d931cecd 100644 --- a/include/evm_runtime/bridge.hpp +++ b/include/evm_runtime/bridge.hpp @@ -5,9 +5,10 @@ namespace evm_runtime { namespace bridge { struct message_v0 { - static constexpr uint32_t id = 0x24578ea5; //sha3('bridgeMsgV0(string,bytes)')[:4] + static constexpr uint32_t id = 0xf781185b; //sha3('bridgeMsgV0(string,bool,bytes)')[:4] string account; + bool force_atomic; //currently only atomic is supported bytes data; name get_account_as_name() const { @@ -24,18 +25,20 @@ struct message_v0 { using message = std::variant; message_v0 decode_message_v0(eosio::datastream& ds) { - // offset_p1 (32) + offset_p2 (32) + // offset_p1 (32) + p2_value (32) + offset_p3 (32) // p1_len (32) + p1_data ((p1_len+31)/32*32) - // p2_len (32) + p1_data ((p2_len+31)/32*32) - uint256 offset_p1, offset_p2; - uint32_t p1_len, p2_len; + // p3_len (32) + p3_data ((p2_len+31)/32*32) + uint256 offset_p1, value_p2, offset_p3; ds >> offset_p1; - eosio::check(offset_p1 == 0x40, "invalid p1 offset"); - ds >> offset_p2; - eosio::check(offset_p2 == 0x80, "invalid p2 offset"); + eosio::check(offset_p1 == 0x60, "invalid p1 offset"); + ds >> value_p2; + eosio::check(value_p2 <= 1, "invalid p2 value"); + ds >> offset_p3; + eosio::check(offset_p3 == 0xA0, "invalid p3 offset"); message_v0 res; + res.force_atomic = value_p2 ? true : false; auto get_length=[&]() -> uint32_t { uint256 len; @@ -44,17 +47,17 @@ message_v0 decode_message_v0(eosio::datastream& ds) { return static_cast(len); }; - p1_len = get_length(); + uint32_t p1_len = get_length(); auto p1_len_32 = (p1_len+31)/32*32; res.account.resize(p1_len_32); ds.read(res.account.data(), p1_len_32); res.account.resize(p1_len); - p2_len = get_length(); - auto p2_len_32 = (p2_len+31)/32*32; - res.data.resize(p2_len_32); - ds.read(res.data.data(), p2_len_32); - res.data.resize(p2_len); + uint32_t p3_len = get_length(); + auto p3_len_32 = (p3_len+31)/32*32; + res.data.resize(p3_len_32); + ds.read(res.data.data(), p3_len_32); + res.data.resize(p3_len); return res; } diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index 70487b01..5ae8b204 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -139,6 +139,7 @@ class [[eosio::contract]] evm_contract : public contract } silkworm::Receipt execute_tx(eosio::name miner, silkworm::Block& block, silkworm::Transaction& tx, silkworm::ExecutionProcessor& ep, bool enforce_chain_id); + void process_filtered_messages(const std::vector& filtered_messages); uint64_t get_and_increment_nonce(const name owner); diff --git a/include/evm_runtime/print_tracer.hpp b/include/evm_runtime/print_tracer.hpp index ef92a023..6f7594ec 100644 --- a/include/evm_runtime/print_tracer.hpp +++ b/include/evm_runtime/print_tracer.hpp @@ -1,8 +1,9 @@ #pragma once #include +#include namespace evm_runtime { -struct print_tracer : EvmTracer { +struct print_tracer : silkworm::EvmTracer { const char* const* opcode_names_ = nullptr; @@ -19,27 +20,28 @@ struct print_tracer : EvmTracer { } void on_instruction_start(uint32_t pc, const intx::uint256* stack_top, int stack_height, - const evmone::ExecutionState& state, - const IntraBlockState& intra_block_state) noexcept override { - const auto opcode = state.code[pc]; + int64_t gas, const evmone::ExecutionState& state, + const silkworm::IntraBlockState& intra_block_state) override { + + const auto opcode = state.original_code[pc]; auto opcode_name = get_opcode_name(opcode_names_, opcode); eosio::print(opcode_name.c_str(), "\n"); } - void on_execution_end(const evmc_result& result, const IntraBlockState& intra_block_state) noexcept override { + void on_execution_end(const evmc_result& result, const silkworm::IntraBlockState& intra_block_state) noexcept override { eosio::print("TRACE: end\n"); } - void on_creation_completed(const evmc_result& result, const IntraBlockState& intra_block_state) noexcept override { + void on_creation_completed(const evmc_result& result, const silkworm::IntraBlockState& intra_block_state) noexcept override { } void on_precompiled_run(const evmc_result& result, int64_t gas, - const IntraBlockState& intra_block_state) noexcept override { + const silkworm::IntraBlockState& intra_block_state) noexcept override { } - void on_reward_granted(const CallResult& result, const IntraBlockState& intra_block_state) noexcept override { + void on_reward_granted(const silkworm::CallResult& result, const silkworm::IntraBlockState& intra_block_state) noexcept override { } diff --git a/include/evm_runtime/tables.hpp b/include/evm_runtime/tables.hpp index 174f9bb4..c44b6768 100644 --- a/include/evm_runtime/tables.hpp +++ b/include/evm_runtime/tables.hpp @@ -183,14 +183,23 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] allowed_egress_accou typedef eosio::multi_index<"egresslist"_n, allowed_egress_account> egresslist; struct [[eosio::table]] [[eosio::contract("evm_contract")]] message_receiver { - name account; - asset min_fee; + + enum flag : uint32_t { + FORCE_ATOMIC = 0x1 + }; + + name account; + asset min_fee; + uint32_t flags; uint64_t primary_key() const { return account.value; } + bool has_flag(flag f) const { + return (flags & f) != 0; + } - EOSLIB_SERIALIZE(message_receiver, (account)(min_fee)); + EOSLIB_SERIALIZE(message_receiver, (account)(min_fee)(flags)); }; typedef eosio::multi_index<"msgreceiver"_n, message_receiver> message_receiver_table; -} //namespace evm_runtime \ No newline at end of file +} //namespace evm_runtime diff --git a/silkworm b/silkworm index 350cfc3c..e33efe3f 160000 --- a/silkworm +++ b/silkworm @@ -1 +1 @@ -Subproject commit 350cfc3c4c71f0882bceb0290a166480cdc52e2d +Subproject commit e33efe3fd925b9f9eec8eef8b69a3cf523c7626a diff --git a/src/actions.cpp b/src/actions.cpp index 32e26210..6617d91c 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -385,6 +385,61 @@ void evm_contract::exec(const exec_input& input, const std::optional& filtered_messages ) { + + intx::uint256 accumulated_value; + for(const auto& rawmsg : filtered_messages) { + auto msg = bridge::decode_message(ByteView{rawmsg.data}); + eosio::check(msg.has_value(), "unable to decode bridge message"); + + auto& msg_v0 = std::get(msg.value()); + eosio::print("FIL MESSAGE: ", uint64_t(msg_v0.force_atomic), "\n"); + + const auto& receiver = msg_v0.get_account_as_name(); + eosio::check(eosio::is_account(receiver), "receiver is not account"); + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + eosio::check(it != message_receivers.end(), "receiver not registered"); + + eosio::check(msg_v0.force_atomic == false || it->has_flag(message_receiver::FORCE_ATOMIC), "unable to process message"); + + intx::uint256 min_fee((uint64_t)it->min_fee.amount); + min_fee *= minimum_natively_representable; + + auto value = intx::be::unsafe::load(rawmsg.value.bytes); + eosio::check(value >= min_fee, "min_fee not covered"); + + balances balance_table(get_self(), get_self().value); + const balance& receiver_account = balance_table.get(msg_v0.get_account_as_name().value, "receiver account is not open"); + + action(std::vector{}, msg_v0.get_account_as_name(), "onbridgemsg"_n, + bridge_message{ bridge_message_v0 { + .receiver = msg_v0.get_account_as_name(), + .sender = to_bytes(rawmsg.sender), + .timestamp = eosio::current_time_point(), + .value = to_bytes(rawmsg.value), + .data = msg_v0.data + } } + ).send(); + + balance_table.modify(receiver_account, eosio::same_payer, [&](balance& row) { + row.balance += value; + }); + + accumulated_value += value; + } + + if(accumulated_value > 0) { + balances balance_table(get_self(), get_self().value); + const balance& self_balance = balance_table.get(get_self().value); + balance_table.modify(self_balance, eosio::same_payer, [&](balance& row) { + row.balance -= accumulated_value; + }); + } + +} + void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { LOGTIME("EVM START"); @@ -425,43 +480,7 @@ void evm_contract::pushtx( eosio::name miner, const bytes& rlptx ) { auto receipt = execute_tx(miner, block, tx, ep, true); - for(const auto& rawmsg : ep.state().filtered_messages()) { - - auto msg = bridge::decode_message(ByteView{rawmsg.data}); - eosio::check(msg.has_value(), "unable to decode bridge message"); - - auto& msg_v0 = std::get(msg.value()); - - const auto& receiver = msg_v0.get_account_as_name(); - eosio::check(eosio::is_account(receiver), "receiver is not account"); - - message_receiver_table message_receivers(get_self(), get_self().value); - auto it = message_receivers.find(receiver.value); - eosio::check(it != message_receivers.end(), "receiver not registered"); - - intx::uint256 min_fee((uint64_t)it->min_fee.amount); - min_fee *= minimum_natively_representable; - - auto value = intx::be::unsafe::load(rawmsg.value.bytes); - eosio::check(value >= min_fee, "min_fee not covered"); - - balances balance_table(get_self(), get_self().value); - const balance& receiver_account = balance_table.get(msg_v0.get_account_as_name().value, "receiver account is not open"); - - action(std::vector{}, msg_v0.get_account_as_name(), "onbridgemsg"_n, - bridge_message{ bridge_message_v0 { - .receiver = msg_v0.get_account_as_name(), - .sender = to_bytes(rawmsg.sender), - .timestamp = eosio::current_time_point(), - .value = to_bytes(rawmsg.value), - .data = msg_v0.data - } } - ).send(); - - balance_table.modify(receiver_account, eosio::same_payer, [&](balance& row) { - row.balance += value; - }); - } + process_filtered_messages(ep.state().filtered_messages()); engine.finalize(ep.state(), ep.evm().block()); ep.state().write_to_db(ep.evm().block().header.number); @@ -610,6 +629,42 @@ bool evm_contract::gc(uint32_t max) { return state.gc(max); } +void evm_contract::bridgereg(eosio::name receiver, const eosio::asset& min_fee) { + assert_unfrozen(); + require_auth(receiver); + require_auth(get_self()); // to temporarily prevent registration of unauthorized accounts + + eosio::check(min_fee.symbol == token_symbol, "unexpected symbol"); + eosio::check(min_fee.amount >= 0, "min_fee cannot be negative"); + + auto update_row = [&](auto& row) { + row.account = receiver; + row.min_fee = min_fee; + row.flags = message_receiver::flag::FORCE_ATOMIC; + }; + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + + if(it == message_receivers.end()) { + message_receivers.emplace(receiver, update_row); + } else { + message_receivers.modify(*it, eosio::same_payer, update_row); + } + + open(receiver); +} + +void evm_contract::bridgeunreg(eosio::name receiver) { + assert_unfrozen(); + require_auth(receiver); + + message_receiver_table message_receivers(get_self(), get_self().value); + auto it = message_receivers.find(receiver.value); + eosio::check(it != message_receivers.end(), "receiver not found"); + message_receivers.erase(*it); +} + void evm_contract::call_(intx::uint256 s, const bytes& to, intx::uint256 value, const bytes& data, uint64_t gas_limit, uint64_t nonce) { const auto& current_config = _config.get(); diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index e6fbe2a3..988434db 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -549,4 +549,38 @@ bool basic_evm_tester::scan_account_storage(uint64_t account_id, std::function visitor) const { + static constexpr eosio::chain::name balances_table_name = "balances"_n; + scan_table( + balances_table_name, evm_account_name, [this, &visitor](vault_balance_row&& row) { + return visitor(row); + } + ); +} + +asset basic_evm_tester::get_eos_balance( const account_name& act ) { + vector data = get_row_by_account( "eosio.token"_n, act, "accounts"_n, name(native_symbol.to_symbol_code().value) ); + return data.empty() ? asset(0, native_symbol) : fc::raw::unpack(data); +} + +void basic_evm_tester::check_balances() { + intx::uint256 total_in_evm_accounts; + scan_accounts([&](account_object&& account) -> bool { + total_in_evm_accounts += account.balance; + return false; + }); + + auto in_evm = intx::uint256(inevm()); + BOOST_REQUIRE(total_in_evm_accounts == in_evm); + + intx::uint256 total_in_accounts; + scan_balances([&](vault_balance_row&& row) -> bool { + total_in_accounts += intx::uint256(balance_and_dust{.balance=row.balance, .dust=row.dust}); + return false; + }); + + auto evm_eos_balance = intx::uint256(balance_and_dust{.balance=get_eos_balance(evm_account_name), .dust=0}); + BOOST_REQUIRE(evm_eos_balance == total_in_accounts+total_in_evm_accounts); +} + } // namespace evm_test diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index 5dfe3eae..b6e5d1f0 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -110,8 +110,9 @@ struct exec_output { }; struct message_receiver { - name account; - asset min_fee; + name account; + asset min_fee; + uint32_t flags; }; struct bridge_message_v0 { @@ -138,7 +139,7 @@ FC_REFLECT(evm_test::exec_input, (context)(from)(to)(data)(value)) FC_REFLECT(evm_test::exec_callback, (contract)(action)) FC_REFLECT(evm_test::exec_output, (status)(data)(context)) -FC_REFLECT(evm_test::message_receiver, (account)(min_fee)); +FC_REFLECT(evm_test::message_receiver, (account)(min_fee)(flags)); FC_REFLECT(evm_test::bridge_message_v0, (receiver)(sender)(timestamp)(value)(data)); namespace evm_test { @@ -165,6 +166,7 @@ class evm_eoa std::basic_string public_key; }; +struct vault_balance_row; class basic_evm_tester : public testing::validating_tester { public: @@ -237,6 +239,10 @@ class basic_evm_tester : public testing::validating_tester std::optional evm_balance(const evmc::address& address) const; std::optional evm_balance(const evm_eoa& account) const; + asset get_eos_balance( const account_name& act ); + + void check_balances(); + template void scan_table(eosio::chain::name table_name, eosio::chain::name scope_name, Visitor&& visitor) const { @@ -266,6 +272,7 @@ class basic_evm_tester : public testing::validating_tester std::optional scan_for_account_by_address(const evmc::address& address) const; std::optional find_account_by_address(const evmc::address& address) const; bool scan_account_storage(uint64_t account_id, std::function visitor) const; + void scan_balances(std::function visitor) const; }; inline constexpr intx::uint256 operator"" _wei(const char* s) { return intx::from_string(s); } diff --git a/tests/bridge_message_tests.cpp b/tests/bridge_message_tests.cpp index 42d3e774..b2b2d10a 100644 --- a/tests/bridge_message_tests.cpp +++ b/tests/bridge_message_tests.cpp @@ -10,6 +10,9 @@ using eosio::testing::eosio_assert_message_is; using eosio::testing::expect_assert_message; struct bridge_message_tester : basic_evm_tester { + + static constexpr const char* bridgeMsgV0_method_id = "f781185b"; + bridge_message_tester() { create_accounts({"alice"_n}); transfer_token(faucet_account_name, "alice"_n, make_asset(10000'0000)); @@ -17,6 +20,11 @@ struct bridge_message_tester : basic_evm_tester { open("alice"_n); } + ~bridge_message_tester() { + dlog("~bridge_message_tester()"); + check_balances(); + } + std::string int_str32(uint32_t x) { std::stringstream hex_ss; hex_ss << std::hex << x; @@ -47,13 +55,14 @@ struct bridge_message_tester : basic_evm_tester { transaction_trace_ptr send_bridge_message(evm_eoa& eoa, const std::string& receiver, const intx::uint256& value, const std::string& str_data) { silkworm::Bytes data; - data += evmc::from_hex("24578ea5").value(); - data += evmc::from_hex(int_str32(64)).value(); - data += evmc::from_hex(int_str32(128)).value(); - data += evmc::from_hex(int_str32(receiver.length())).value(); - data += evmc::from_hex(data_str32(str_to_hex(receiver))).value(); - data += evmc::from_hex(int_str32(str_data.size()/2)).value(); - data += evmc::from_hex(data_str32(str_data)).value(); + data += evmc::from_hex(bridgeMsgV0_method_id).value(); + data += evmc::from_hex(int_str32(96)).value(); //offset param1 (receiver: string) + data += evmc::from_hex(int_str32(1)).value(); //param2 (true) (force_atomic: bool) + data += evmc::from_hex(int_str32(160)).value(); //offset param3 (data: bytes) + data += evmc::from_hex(int_str32(receiver.length())).value(); //param1 length + data += evmc::from_hex(data_str32(str_to_hex(receiver))).value(); //param1 data + data += evmc::from_hex(int_str32(str_data.size()/2)).value(); //param3 length + data += evmc::from_hex(data_str32(str_data)).value(); //param3 data return send_raw_message(eoa, make_reserved_address(evm_account_name), value, data); } @@ -88,6 +97,7 @@ BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_message_tester) try { auto row = fc::raw::unpack(get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n)); BOOST_REQUIRE(row.account == "rec1"_n); BOOST_REQUIRE(row.min_fee == make_asset(0)); + BOOST_REQUIRE(row.flags == 0x1); // Register again changing min fee bridgereg("rec1"_n, make_asset(1)); @@ -95,6 +105,7 @@ BOOST_FIXTURE_TEST_CASE(bridge_register_test, bridge_message_tester) try { row = fc::raw::unpack(get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n)); BOOST_REQUIRE(row.account == "rec1"_n); BOOST_REQUIRE(row.min_fee == make_asset(1)); + BOOST_REQUIRE(row.flags == 0x1); // Unregister rec1 bridgeunreg("rec1"_n); @@ -116,37 +127,21 @@ BOOST_FIXTURE_TEST_CASE(basic_tests, bridge_message_tester) try { set_abi("rec1"_n, testing::contracts::evm_bridge_receiver_abi().data()); // Register rec1 with 1000.0000 EOS as min_fee - bridgereg("rec1"_n, make_asset(10000000)); + bridgereg("rec1"_n, make_asset(1000'0000)); // Fund evm1 address with 1001 EOS evm_eoa evm1; - const int64_t to_bridge = 10010000; + const int64_t to_bridge = 1001'0000; transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x()); - // Get `rec1` and contract balance before sending the message - auto pre_evm_balance = inevm(); - auto pre_rec1_balance = vault_balance("rec1"_n); - BOOST_CHECK(pre_rec1_balance.balance == make_asset(0)); // 0.0000 EOS - BOOST_CHECK(pre_rec1_balance.dust == 0); + // Check rec1 balance before sending the message + BOOST_REQUIRE(vault_balance("rec1"_n) == (balance_and_dust{make_asset(0), 0})); // Emit message - auto res = send_bridge_message(evm1, "rec1", 1000*1_ether, "0102030405060708090a"); + auto res = send_bridge_message(evm1, "rec1", 1000_ether, "0102030405060708090a"); - // Get `rec1` and contract balance after sending the message - auto post_evm_balance = inevm(); - auto post_rec1_balance = vault_balance("rec1"_n); - BOOST_CHECK(post_rec1_balance.balance == make_asset(10000000)); //1000.0000 EOS - BOOST_CHECK(post_rec1_balance.dust == 0); - - // The data length of the bridge message transaction is 196 bytes long - // 22 non zero, 174 zero => total gas is: 21000 + 174*4+22*16 - auto total_gas_fee = intx::uint256(suggested_gas_price)*intx::uint256(21000+174*4+22*16); - dlog("totalgas: ${t}", ("t",total_gas_fee)); - - // Check that the EOS `out` from the EVM is equal to the value sent in the bridge transaction (goes to rec1) - // plus the transaction fee (goes to miner) - auto diff = static_cast(pre_evm_balance)-static_cast(post_evm_balance); - BOOST_CHECK_EQUAL(diff, 1000*1_ether + total_gas_fee); + // Check rec1 balance after sending the message + BOOST_REQUIRE(vault_balance("rec1"_n) == (balance_and_dust{make_asset(1000'0000), 0})); // Recover message form the return value of rec1 contract BOOST_CHECK(res->action_traces[1].receiver == "rec1"_n); @@ -156,9 +151,8 @@ BOOST_FIXTURE_TEST_CASE(basic_tests, bridge_message_tester) try { BOOST_CHECK(out.receiver == "rec1"_n); BOOST_CHECK(out.sender == to_bytes(evm1.address)); BOOST_CHECK(out.timestamp.time_since_epoch() == control->pending_block_time().time_since_epoch()); - BOOST_CHECK(out.value == to_bytes(1000*1_ether)); + BOOST_CHECK(out.value == to_bytes(1000_ether)); BOOST_CHECK(out.data == to_bytes(evmc::from_hex("0102030405060708090a").value())); - } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { @@ -178,35 +172,45 @@ BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); evm1.next_nonce--; - // Send message with 4 bytes NOT matching the 'bridgeMsgV0(string,bytes)' signature + // Send message with 4 bytes NOT matching the 'bridgeMsgV0(string,bool,bytes)' signature BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("01020304").value()), eosio_assert_message_exception, eosio_assert_message_is("unable to decode bridge message")); evm1.next_nonce--; - // Send message with 4 bytes matching the 'bridgeMsgV0(string,bytes)' signature - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("24578ea5").value()), + // Send message with 4 bytes matching the 'bridgeMsgV0(string,bool,bytes)' signature + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex(bridgeMsgV0_method_id).value()), eosio_assert_message_exception, eosio_assert_message_is("datastream attempted to read past the end")); evm1.next_nonce--; // Wrong p1 offset - BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex("24578ea5").value() + + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, evmc::from_hex(bridgeMsgV0_method_id).value() + evmc::from_hex(int_str32(11)).value()), eosio_assert_message_exception, eosio_assert_message_is("invalid p1 offset")); evm1.next_nonce--; - // Wrong p2 offset + // Wrong p2 value BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("24578ea5").value() + - evmc::from_hex(int_str32(64)).value() + + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value() + evmc::from_hex(int_str32(11)).value()), - eosio_assert_message_exception, eosio_assert_message_is("invalid p2 offset")); + eosio_assert_message_exception, eosio_assert_message_is("invalid p2 value")); + evm1.next_nonce--; + + // Wrong p3 offset + BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value()+ + evmc::from_hex(int_str32(1)).value()+ + evmc::from_hex(int_str32(11)).value()), + eosio_assert_message_exception, eosio_assert_message_is("invalid p3 offset")); evm1.next_nonce--; // abcd is not an account BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("24578ea5").value() + - evmc::from_hex(int_str32(64)).value() + - evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value() + + evmc::from_hex(int_str32(1)).value() + + evmc::from_hex(int_str32(160)).value() + evmc::from_hex(int_str32(4)).value() + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + evmc::from_hex(int_str32(4)).value() + @@ -219,9 +223,10 @@ BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { // abcd not registered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("24578ea5").value() + - evmc::from_hex(int_str32(64)).value() + - evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value() + + evmc::from_hex(int_str32(1)).value() + + evmc::from_hex(int_str32(160)).value() + evmc::from_hex(int_str32(4)).value() + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + evmc::from_hex(int_str32(4)).value() + @@ -234,9 +239,10 @@ BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { // min fee not covered BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0, - evmc::from_hex("24578ea5").value() + - evmc::from_hex(int_str32(64)).value() + - evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value() + + evmc::from_hex(int_str32(1)).value() + + evmc::from_hex(int_str32(160)).value() + evmc::from_hex(int_str32(4)).value() + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + evmc::from_hex(int_str32(4)).value() + @@ -249,31 +255,31 @@ BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try { // receiver account is not open BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 1e14, - evmc::from_hex("24578ea5").value() + - evmc::from_hex(int_str32(64)).value() + - evmc::from_hex(int_str32(128)).value() + + evmc::from_hex(bridgeMsgV0_method_id).value() + + evmc::from_hex(int_str32(96)).value() + + evmc::from_hex(int_str32(1)).value() + + evmc::from_hex(int_str32(160)).value() + evmc::from_hex(int_str32(4)).value() + evmc::from_hex(data_str32(str_to_hex("abcd"))).value() + evmc::from_hex(int_str32(4)).value() + evmc::from_hex(data_str32(str_to_hex("data"))).value()), eosio_assert_message_exception, eosio_assert_message_is("receiver account is not open")); - } FC_LOG_AND_RETHROW() BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester) try { // // SPDX-License-Identifier: GPL-3.0 // pragma solidity >=0.7.0 <0.9.0; // contract Emiter { - // function go(string memory destination, uint256 n) public { + // function go(string memory destination, bool force_atomic, uint256 n) public { // address eosevm = 0xBbBBbbBBbBbbbBBBbBbbBBbB56E4000000000000; // for(uint i=0; i go('rec1', 3) auto txn = generate_tx(contract_addr, 0, 500'000); - txn.data = evmc::from_hex("a5cc93e4").value(); - txn.data += evmc::from_hex(int_str32(64)).value(); //offset of param1 - txn.data += evmc::from_hex(int_str32(3)).value(); //param2 + txn.data = evmc::from_hex("e1963a31").value(); + txn.data += evmc::from_hex(int_str32(96)).value(); //offset of param1 + txn.data += evmc::from_hex(int_str32(1)).value(); //param2 + txn.data += evmc::from_hex(int_str32(3)).value(); //param3 txn.data += evmc::from_hex(int_str32(4)).value(); //param1 size txn.data += evmc::from_hex(data_str32(str_to_hex("rec1"))).value(); //param1 data evm1.sign(txn); @@ -316,7 +323,6 @@ BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester) BOOST_CHECK(out.value == to_bytes(0_ether)); BOOST_CHECK(out.data == to_bytes(evmc::from_hex("00000000000000000000000000000000000000000000000000000000FFFFFF0"+std::to_string(i)).value())); } - } FC_LOG_AND_RETHROW() BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 02dfdc7e233bbc72999e59a4c8c6902f11cf7d64 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 21 Aug 2023 20:41:40 -0300 Subject: [PATCH 10/11] Remove action redefinition, fix tests, adjust stack size --- src/CMakeLists.txt | 2 +- src/actions.cpp | 37 +------------------------------------ tests/basic_evm_tester.cpp | 5 ----- 3 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dc6bb7da..b6256d19 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -85,5 +85,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=32768) + target_link_options(evm_runtime PUBLIC --stack-size=38432) endif() diff --git a/src/actions.cpp b/src/actions.cpp index 6617d91c..8f325b7f 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -629,42 +629,6 @@ bool evm_contract::gc(uint32_t max) { return state.gc(max); } -void evm_contract::bridgereg(eosio::name receiver, const eosio::asset& min_fee) { - assert_unfrozen(); - require_auth(receiver); - require_auth(get_self()); // to temporarily prevent registration of unauthorized accounts - - eosio::check(min_fee.symbol == token_symbol, "unexpected symbol"); - eosio::check(min_fee.amount >= 0, "min_fee cannot be negative"); - - auto update_row = [&](auto& row) { - row.account = receiver; - row.min_fee = min_fee; - row.flags = message_receiver::flag::FORCE_ATOMIC; - }; - - message_receiver_table message_receivers(get_self(), get_self().value); - auto it = message_receivers.find(receiver.value); - - if(it == message_receivers.end()) { - message_receivers.emplace(receiver, update_row); - } else { - message_receivers.modify(*it, eosio::same_payer, update_row); - } - - open(receiver); -} - -void evm_contract::bridgeunreg(eosio::name receiver) { - assert_unfrozen(); - require_auth(receiver); - - message_receiver_table message_receivers(get_self(), get_self().value); - auto it = message_receivers.find(receiver.value); - eosio::check(it != message_receivers.end(), "receiver not found"); - message_receivers.erase(*it); -} - void evm_contract::call_(intx::uint256 s, const bytes& to, intx::uint256 value, const bytes& data, uint64_t gas_limit, uint64_t nonce) { const auto& current_config = _config.get(); @@ -746,6 +710,7 @@ void evm_contract::bridgereg(eosio::name receiver, const eosio::asset& min_fee) auto update_row = [&](auto& row) { row.account = receiver; row.min_fee = min_fee; + row.flags = message_receiver::FORCE_ATOMIC; }; message_receiver_table message_receivers(get_self(), get_self().value); diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 988434db..2e3e9352 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -344,11 +344,6 @@ transaction_trace_ptr basic_evm_tester::bridgeunreg(name receiver) { mvo()("receiver", receiver)); } -transaction_trace_ptr basic_evm_tester::exec(const exec_input& input, const std::optional& callback) { - auto binary_data = fc::raw::pack>(input, callback); - return basic_evm_tester::push_action(evm_account_name, "exec"_n, evm_account_name, bytes{binary_data.begin(), binary_data.end()}); -} - transaction_trace_ptr basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) { silkworm::Bytes rlp; From cbff79db258428e5e2b8746b4b7053f327706365 Mon Sep 17 00:00:00 2001 From: Matias Romeo Date: Mon, 21 Aug 2023 20:56:44 -0300 Subject: [PATCH 11/11] Update silkworm, fix comment --- silkworm | 2 +- tests/bridge_message_tests.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/silkworm b/silkworm index e33efe3f..77e88a62 160000 --- a/silkworm +++ b/silkworm @@ -1 +1 @@ -Subproject commit e33efe3fd925b9f9eec8eef8b69a3cf523c7626a +Subproject commit 77e88a620a8ba3421c7d7ffd2080e700352e6ba1 diff --git a/tests/bridge_message_tests.cpp b/tests/bridge_message_tests.cpp index b2b2d10a..c1868dd0 100644 --- a/tests/bridge_message_tests.cpp +++ b/tests/bridge_message_tests.cpp @@ -299,8 +299,8 @@ BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester) uint64_t contract_account_id = find_account_by_address(contract_addr).value().id; produce_blocks(1); - // Call method "go" on emiter contract (sha3('go(string,uint)') = 0xa5cc93e4) - // ===> go('rec1', 3) + // Call method "go" on emiter contract (sha3('go(string,bool,uint)') = 0xe1963a31) + // ===> go('rec1', true, 3) auto txn = generate_tx(contract_addr, 0, 500'000); txn.data = evmc::from_hex("e1963a31").value(); txn.data += evmc::from_hex(int_str32(96)).value(); //offset of param1