From 19dfb5f6501ff10d3fe93d64a91210a345486169 Mon Sep 17 00:00:00 2001 From: yarkin Date: Wed, 30 Aug 2023 16:33:33 +0800 Subject: [PATCH 1/2] Add assertnonce action. --- include/evm_runtime/evm_contract.hpp | 2 + src/actions.cpp | 8 ++++ tests/basic_evm_tester.cpp | 5 +++ tests/basic_evm_tester.hpp | 1 + tests/call_tests.cpp | 61 ++++++++++++++++++++++++++-- 5 files changed, 73 insertions(+), 4 deletions(-) diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index 5ae8b204..5fb5382a 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -91,6 +91,8 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void bridgereg(eosio::name receiver, const eosio::asset& min_fee); [[eosio::action]] void bridgeunreg(eosio::name receiver); + [[eosio::action]] void assertnonce(eosio::name receiver, uint64_t nonce); + #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/src/actions.cpp b/src/actions.cpp index 8f325b7f..e0584833 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -735,6 +735,14 @@ void evm_contract::bridgeunreg(eosio::name receiver) { message_receivers.erase(*it); } + +void evm_contract::assertnonce(eosio::name receiver, uint64_t nonce) { + nextnonces nextnonce_table(get_self(), get_self().value); + + const nextnonce& next_nonce = nextnonce_table.get(receiver.value, "caller account has not been opened"); + eosio::check(nonce == next_nonce.next_nonce, "wrong nonce"); +} + #ifdef WITH_TEST_ACTIONS [[eosio::action]] void evm_contract::testtx( const std::optional& orlptx, const evm_runtime::test::block_info& bi ) { assert_unfrozen(); diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 2e3e9352..0e9d1722 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -344,6 +344,11 @@ transaction_trace_ptr basic_evm_tester::bridgeunreg(name receiver) { mvo()("receiver", receiver)); } +transaction_trace_ptr basic_evm_tester::assertnonce(name receiver, uint64_t nonce) { + return basic_evm_tester::push_action(evm_account_name, "assertnonce"_n, receiver, + mvo()("receiver", receiver)("nonce", nonce)); +} + transaction_trace_ptr basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) { silkworm::Bytes rlp; diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index b6e5d1f0..d13667c3 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -222,6 +222,7 @@ class basic_evm_tester : public testing::validating_tester 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); + transaction_trace_ptr assertnonce(name receiver, uint64_t nonce); 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); diff --git a/tests/call_tests.cpp b/tests/call_tests.cpp index 085ea3f2..e14e57b1 100644 --- a/tests/call_tests.cpp +++ b/tests/call_tests.cpp @@ -471,12 +471,13 @@ BOOST_FIXTURE_TEST_CASE(deploy_contract_function, call_evm_tester) try { auto to = evmc::bytes(); auto data = evmc::from_hex(contract_bytecode); - + assertnonce("alice"_n, 0); call("alice"_n, to, silkworm::Bytes(v), *data, 1000000, "alice"_n); // nonce 0->1 auto addr = silkworm::create_address(alice_addr, 0); - + assertnonce("alice"_n, 1); call_test(addr, 1234, "alice"_n, "alice"_n); // nonce 1->2 + auto count = get_count(addr); BOOST_REQUIRE(count == 1234); @@ -484,15 +485,67 @@ BOOST_FIXTURE_TEST_CASE(deploy_contract_function, call_evm_tester) try { produce_block(); auto from = evmc::bytes{std::begin(alice_addr.bytes), std::end(alice_addr.bytes)}; - + assertnonce("alice"_n, 2); admincall(from, to, silkworm::Bytes(v), *data, 1000000, evm_account_name); // nonce 2->3 - + addr = silkworm::create_address(alice_addr, 2); + assertnonce("alice"_n, 3); call_test(addr, 2222, "alice"_n, "alice"_n); // nonce 3->4 + assertnonce("alice"_n, 4); count = get_count(addr); BOOST_REQUIRE(count == 2222); } FC_LOG_AND_RETHROW() +BOOST_FIXTURE_TEST_CASE(assetnonce_test, call_evm_tester) try { + auto alice_addr = make_reserved_address("alice"_n.to_uint64_t()); + + BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 0), + eosio_assert_message_exception, eosio_assert_message_is("caller account has not been opened")); + + open("alice"_n); + transfer_token("alice"_n, evm_account_name, make_asset(1000000), "alice"); + + evm_eoa evm1; + evmc::bytes32 v; + + auto to = evmc::bytes(); + + auto data = evmc::from_hex(contract_bytecode); + + // Fail when nonce is 0 but tested with non-zero value + BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 1), + eosio_assert_message_exception, eosio_assert_message_is("wrong nonce")); + + assertnonce("alice"_n, 0); + call("alice"_n, to, silkworm::Bytes(v), *data, 1000000, "alice"_n); // nonce 0->1 + + // Advance block so we do not generate same transaction. + produce_block(); + + assertnonce("alice"_n, 1); + assertnonce(evm_account_name, 0); + // Fund evm1 address with 100 EOS, should NOT increase alice nonce, but increase evm nonce. + transfer_token("alice"_n, evm_account_name, make_asset(1000000), evm1.address_0x()); + + // Advance block so we do not generate same transaction. + produce_block(); + assertnonce("alice"_n, 1); + assertnonce(evm_account_name, 1); + + // Advance block so we do not generate same transaction. + produce_block(); + + // Fail when nonce is non-zero but tested with another value + BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 2), + eosio_assert_message_exception, eosio_assert_message_is("wrong nonce")); + // Fail when nonce is non-zero but tested with 0 + BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 0), + eosio_assert_message_exception, eosio_assert_message_is("wrong nonce")); + + + +} FC_LOG_AND_RETHROW() + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file From 3caaa225c5c3f4e9f835a27fb012a5ed6a8c45d7 Mon Sep 17 00:00:00 2001 From: yarkin Date: Thu, 31 Aug 2023 09:58:42 +0800 Subject: [PATCH 2/2] Test nonce against 0 when account is not opened. Minor change in argument names. --- include/evm_runtime/evm_contract.hpp | 2 +- src/actions.cpp | 11 ++++++++--- tests/basic_evm_tester.cpp | 6 +++--- tests/basic_evm_tester.hpp | 2 +- tests/call_tests.cpp | 9 +++++++-- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/evm_runtime/evm_contract.hpp b/include/evm_runtime/evm_contract.hpp index 5fb5382a..b1e695f3 100644 --- a/include/evm_runtime/evm_contract.hpp +++ b/include/evm_runtime/evm_contract.hpp @@ -91,7 +91,7 @@ class [[eosio::contract]] evm_contract : public contract [[eosio::action]] void bridgereg(eosio::name receiver, const eosio::asset& min_fee); [[eosio::action]] void bridgeunreg(eosio::name receiver); - [[eosio::action]] void assertnonce(eosio::name receiver, uint64_t nonce); + [[eosio::action]] void assertnonce(eosio::name account, uint64_t next_nonce); #ifdef WITH_TEST_ACTIONS [[eosio::action]] void testtx(const std::optional& orlptx, const evm_runtime::test::block_info& bi); diff --git a/src/actions.cpp b/src/actions.cpp index e0584833..a0c1cf63 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -736,11 +736,16 @@ void evm_contract::bridgeunreg(eosio::name receiver) { } -void evm_contract::assertnonce(eosio::name receiver, uint64_t nonce) { +void evm_contract::assertnonce(eosio::name account, uint64_t next_nonce) { nextnonces nextnonce_table(get_self(), get_self().value); - const nextnonce& next_nonce = nextnonce_table.get(receiver.value, "caller account has not been opened"); - eosio::check(nonce == next_nonce.next_nonce, "wrong nonce"); + auto next_nonce_iter = nextnonce_table.find(account.value); + if (next_nonce_iter == nextnonce_table.end()) { + eosio::check(0 == next_nonce, "wrong nonce"); + } + else { + eosio::check(next_nonce_iter->next_nonce == next_nonce, "wrong nonce"); + } } #ifdef WITH_TEST_ACTIONS diff --git a/tests/basic_evm_tester.cpp b/tests/basic_evm_tester.cpp index 0e9d1722..fc1c5d2a 100644 --- a/tests/basic_evm_tester.cpp +++ b/tests/basic_evm_tester.cpp @@ -344,9 +344,9 @@ transaction_trace_ptr basic_evm_tester::bridgeunreg(name receiver) { mvo()("receiver", receiver)); } -transaction_trace_ptr basic_evm_tester::assertnonce(name receiver, uint64_t nonce) { - return basic_evm_tester::push_action(evm_account_name, "assertnonce"_n, receiver, - mvo()("receiver", receiver)("nonce", nonce)); +transaction_trace_ptr basic_evm_tester::assertnonce(name account, uint64_t next_nonce) { + return basic_evm_tester::push_action(evm_account_name, "assertnonce"_n, account, + mvo()("account", account)("next_nonce", next_nonce)); } transaction_trace_ptr basic_evm_tester::pushtx(const silkworm::Transaction& trx, name miner) diff --git a/tests/basic_evm_tester.hpp b/tests/basic_evm_tester.hpp index d13667c3..9adc416e 100644 --- a/tests/basic_evm_tester.hpp +++ b/tests/basic_evm_tester.hpp @@ -222,7 +222,7 @@ class basic_evm_tester : public testing::validating_tester 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); - transaction_trace_ptr assertnonce(name receiver, uint64_t nonce); + transaction_trace_ptr assertnonce(name account, uint64_t next_nonce); 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); diff --git a/tests/call_tests.cpp b/tests/call_tests.cpp index e14e57b1..9fcad062 100644 --- a/tests/call_tests.cpp +++ b/tests/call_tests.cpp @@ -499,8 +499,13 @@ BOOST_FIXTURE_TEST_CASE(deploy_contract_function, call_evm_tester) try { BOOST_FIXTURE_TEST_CASE(assetnonce_test, call_evm_tester) try { auto alice_addr = make_reserved_address("alice"_n.to_uint64_t()); - BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 0), - eosio_assert_message_exception, eosio_assert_message_is("caller account has not been opened")); + // nonce for not opened account is zero. + assertnonce("alice"_n, 0); + BOOST_REQUIRE_EXCEPTION(assertnonce("alice"_n, 1), + eosio_assert_message_exception, eosio_assert_message_is("wrong nonce")); + + // Advance block so we do not generate same transaction. + produce_block(); open("alice"_n); transfer_token("alice"_n, evm_account_name, make_asset(1000000), "alice");