Skip to content

Commit

Permalink
Merge pull request #647 from eosnetworkfoundation/yarkin/add_bridge_h…
Browse files Browse the repository at this point in the history
…andler

Add handler option to bridge message feature.
  • Loading branch information
yarkinwho authored Sep 1, 2023
2 parents 051dad8 + d6e8696 commit 7f01cf6
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 17 deletions.
2 changes: 1 addition & 1 deletion include/evm_runtime/evm_contract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ 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 bridgereg(eosio::name receiver, eosio::name handler, const eosio::asset& min_fee);
[[eosio::action]] void bridgeunreg(eosio::name receiver);

[[eosio::action]] void assertnonce(eosio::name account, uint64_t next_nonce);
Expand Down
3 changes: 2 additions & 1 deletion include/evm_runtime/tables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] message_receiver {
};

name account;
name handler;
asset min_fee;
uint32_t flags;

Expand All @@ -197,7 +198,7 @@ struct [[eosio::table]] [[eosio::contract("evm_contract")]] message_receiver {
return (flags & f) != 0;
}

EOSLIB_SERIALIZE(message_receiver, (account)(min_fee)(flags));
EOSLIB_SERIALIZE(message_receiver, (account)(handler)(min_fee)(flags));
};

typedef eosio::multi_index<"msgreceiver"_n, message_receiver> message_receiver_table;
Expand Down
7 changes: 4 additions & 3 deletions src/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -411,9 +411,9 @@ void evm_contract::process_filtered_messages(const std::vector<silkworm::Filtere
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");
const balance& receiver_account = balance_table.get(receiver.value, "receiver account is not open");

action(std::vector<permission_level>{}, msg_v0.get_account_as_name(), "onbridgemsg"_n,
action(std::vector<permission_level>{}, it->handler, "onbridgemsg"_n,
bridge_message{ bridge_message_v0 {
.receiver = msg_v0.get_account_as_name(),
.sender = to_bytes(rawmsg.sender),
Expand Down Expand Up @@ -699,7 +699,7 @@ 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) {
void evm_contract::bridgereg(eosio::name receiver, eosio::name handler, const eosio::asset& min_fee) {
assert_unfrozen();
require_auth(receiver);
require_auth(get_self()); // to temporarily prevent registration of unauthorized accounts
Expand All @@ -709,6 +709,7 @@ void evm_contract::bridgereg(eosio::name receiver, const eosio::asset& min_fee)

auto update_row = [&](auto& row) {
row.account = receiver;
row.handler = handler;
row.min_fee = min_fee;
row.flags = message_receiver::FORCE_ATOMIC;
};
Expand Down
6 changes: 4 additions & 2 deletions tests/basic_evm_tester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,10 +333,12 @@ 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));
}

transaction_trace_ptr basic_evm_tester::bridgereg(name receiver, asset min_fee, vector<account_name> extra_signers) {
transaction_trace_ptr basic_evm_tester::bridgereg(name receiver, name handler, asset min_fee, vector<account_name> extra_signers) {
extra_signers.push_back(receiver);
if (receiver != handler)
extra_signers.push_back(handler);
return basic_evm_tester::push_action(evm_account_name, "bridgereg"_n, extra_signers,
mvo()("receiver", receiver)("min_fee", min_fee));
mvo()("receiver", receiver)("handler", handler)("min_fee", min_fee));
}

transaction_trace_ptr basic_evm_tester::bridgeunreg(name receiver) {
Expand Down
5 changes: 3 additions & 2 deletions tests/basic_evm_tester.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ struct exec_output {

struct message_receiver {
name account;
name handler;
asset min_fee;
uint32_t flags;
};
Expand Down Expand Up @@ -139,7 +140,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)(flags));
FC_REFLECT(evm_test::message_receiver, (account)(handler)(min_fee)(flags));
FC_REFLECT(evm_test::bridge_message_v0, (receiver)(sender)(timestamp)(value)(data));

namespace evm_test {
Expand Down Expand Up @@ -219,7 +220,7 @@ 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<account_name> extra_signers={evm_account_name});
transaction_trace_ptr bridgereg(name receiver, name handler, asset min_fee, vector<account_name> extra_signers={evm_account_name});
transaction_trace_ptr bridgeunreg(name receiver);
transaction_trace_ptr exec(const exec_input& input, const std::optional<exec_callback>& callback);
transaction_trace_ptr assertnonce(name account, uint64_t next_nonce);
Expand Down
76 changes: 68 additions & 8 deletions tests/bridge_message_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,26 +81,26 @@ 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), {}),
BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, "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")),
BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, "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)),
BOOST_REQUIRE_EXCEPTION(bridgereg("rec1"_n, "rec1"_n, make_asset(-1)),
eosio_assert_message_exception, eosio_assert_message_is("min_fee cannot be negative"));

bridgereg("rec1"_n, make_asset(0));
bridgereg("rec1"_n, "rec1"_n, make_asset(0));

auto row = fc::raw::unpack<message_receiver>(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));
bridgereg("rec1"_n, "rec1"_n, make_asset(1));

row = fc::raw::unpack<message_receiver>(get_row_by_account( evm_account_name, evm_account_name, "msgreceiver"_n, "rec1"_n));
BOOST_REQUIRE(row.account == "rec1"_n);
Expand All @@ -127,7 +127,7 @@ 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(1000'0000));
bridgereg("rec1"_n, "rec1"_n, make_asset(1000'0000));

// Fund evm1 address with 1001 EOS
evm_eoa evm1;
Expand Down Expand Up @@ -235,7 +235,7 @@ BOOST_FIXTURE_TEST_CASE(test_bridge_errors, bridge_message_tester) try {
evm1.next_nonce--;

// Register abcd
bridgereg("abcd"_n, make_asset(1));
bridgereg("abcd"_n, "abcd"_n, make_asset(1));

// min fee not covered
BOOST_REQUIRE_EXCEPTION(send_raw_message(evm1, emv_reserved_address, 0,
Expand Down Expand Up @@ -287,7 +287,7 @@ BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester)
set_abi("rec1"_n, testing::contracts::evm_bridge_receiver_abi().data());

// Register rec1 with 0 EOS as min_fee
bridgereg("rec1"_n, make_asset(0));
bridgereg("rec1"_n, "rec1"_n, make_asset(0));

// Fund evm1 address with 100 EOS
evm_eoa evm1;
Expand Down Expand Up @@ -325,4 +325,64 @@ BOOST_FIXTURE_TEST_CASE(test_send_message_from_solidity, bridge_message_tester)
}
} FC_LOG_AND_RETHROW()

BOOST_FIXTURE_TEST_CASE(handler_tests, bridge_message_tester) try {
auto emv_reserved_address = make_reserved_address(evm_account_name);

// Fund evm1 address with 1001 EOS
evm_eoa evm1;
const int64_t to_bridge = 1001'0000;
transfer_token("alice"_n, evm_account_name, make_asset(to_bridge), evm1.address_0x());

BOOST_REQUIRE_EXCEPTION(send_bridge_message(evm1, "receiver", 0, "0102030405060708090a"),
eosio_assert_message_exception, eosio_assert_message_is("receiver is not account"));
evm1.next_nonce--;

// Create receiver account
create_accounts({"receiver"_n});

// receiver not registered
BOOST_REQUIRE_EXCEPTION(send_bridge_message(evm1, "receiver", 0, "0102030405060708090a"),
eosio_assert_message_exception, eosio_assert_message_is("receiver not registered"));
evm1.next_nonce--;

// Create handler account
create_accounts({"handler"_n});
set_code("handler"_n, testing::contracts::evm_bridge_receiver_wasm());
set_abi("handler"_n, testing::contracts::evm_bridge_receiver_abi().data());
// Register handler with 1000.0000 EOS as min_fee
bridgereg("receiver"_n, "handler"_n, make_asset(1000'0000));


// Corner case: receiver account is not open
// We can only test in this way because bridgereg will open receiver.
close("receiver"_n);

BOOST_REQUIRE_EXCEPTION(send_bridge_message(evm1, "receiver", 1000_ether, "0102030405060708090a"),
eosio_assert_message_exception, eosio_assert_message_is("receiver account is not open"));
evm1.next_nonce--;
open("receiver"_n);

// Check handler balance before sending the message
BOOST_REQUIRE(vault_balance("receiver"_n) == (balance_and_dust{make_asset(0), 0}));

// Emit message
auto res = send_bridge_message(evm1, "receiver", 1000_ether, "0102030405060708090a");

// Check handler balance after sending the message
BOOST_REQUIRE(vault_balance("receiver"_n) == (balance_and_dust{make_asset(1000'0000), 0}));

// Recover message form the return value of handler contract
// Make sure "handler" received a message sent to "receiver"
BOOST_CHECK(res->action_traces[1].receiver == "handler"_n);
auto msgout = fc::raw::unpack<bridge_message>(res->action_traces[1].return_value);
auto out = std::get<bridge_message_v0>(msgout);

BOOST_CHECK(out.receiver == "receiver"_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_ether));
BOOST_CHECK(out.data == to_bytes(evmc::from_hex("0102030405060708090a").value()));

} FC_LOG_AND_RETHROW()

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit 7f01cf6

Please sign in to comment.