From 2845e903f8e031a9c891f353e0c6693686592197 Mon Sep 17 00:00:00 2001 From: Emory Barlow Date: Thu, 9 Jul 2020 16:02:42 -0400 Subject: [PATCH 1/4] Add action_results to abi_serializer --- libraries/chain/abi_serializer.cpp | 15 +++++++++++++++ .../chain/include/eosio/chain/abi_serializer.hpp | 2 ++ .../chain/include/eosio/chain/exceptions.hpp | 2 ++ 3 files changed, 19 insertions(+) diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 53288432328..46725064eab 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -138,6 +138,7 @@ namespace eosio { namespace chain { tables.clear(); error_messages.clear(); variants.clear(); + action_results.clear(); for( const auto& st : abi.structs ) structs[st.name] = st; @@ -160,6 +161,9 @@ namespace eosio { namespace chain { for( const auto& v : abi.variants.value ) variants[v.name] = v; + for( const auto& r : abi.action_results ) + action_results[r.name] = r.result_type; + /** * The ABI vector may contain duplicates which would make it * an invalid ABI @@ -170,6 +174,7 @@ namespace eosio { namespace chain { EOS_ASSERT( tables.size() == abi.tables.size(), duplicate_abi_table_def_exception, "duplicate table definition detected" ); EOS_ASSERT( error_messages.size() == abi.error_messages.size(), duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" ); EOS_ASSERT( variants.size() == abi.variants.value.size(), duplicate_abi_variant_def_exception, "duplicate variant definition detected" ); + EOS_ASSERT( action_results.size() == abi.action_results.size(), duplicate_abi_action_results_def_exception, "duplicate action results definition detected" ); validate(ctx); } @@ -290,6 +295,11 @@ namespace eosio { namespace chain { ctx.check_deadline(); EOS_ASSERT(_is_type(t.second, ctx), invalid_type_inside_abi, "${type}", ("type",impl::limit_size(t.second)) ); } FC_CAPTURE_AND_RETHROW( (t) ) } + + for( const auto& r : action_results ) { try { + ctx.check_deadline(); + EOS_ASSERT(_is_type(r.second, ctx), invalid_type_inside_abi, "${type}", ("type",impl::limit_size(r.second)) ); + } FC_CAPTURE_AND_RETHROW( (r) ) } } std::string_view abi_serializer::resolve_type(const std::string_view& type)const { @@ -562,6 +572,11 @@ namespace eosio { namespace chain { if( itr != tables.end() ) return itr->second; return type_name(); } + type_name abi_serializer::get_action_result_type(name action_result)const { + auto itr = action_results.find(action_result); + if( itr != action_results.end() ) return itr->second; + return type_name(); + } optional abi_serializer::get_error_message( uint64_t error_code )const { auto itr = error_messages.find( error_code ); diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index c96a88bc853..c8a334b7ef5 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -54,6 +54,7 @@ struct abi_serializer { type_name get_action_type(name action)const; type_name get_table_type(name action)const; + type_name get_action_result_type(name action_result)const; optional get_error_message( uint64_t error_code )const; @@ -119,6 +120,7 @@ struct abi_serializer { map tables; map error_messages; map> variants; + map action_results; map, std::less<>> built_in_types; void configure_built_in_types(); diff --git a/libraries/chain/include/eosio/chain/exceptions.hpp b/libraries/chain/include/eosio/chain/exceptions.hpp index b534844ea53..5e016368994 100644 --- a/libraries/chain/include/eosio/chain/exceptions.hpp +++ b/libraries/chain/include/eosio/chain/exceptions.hpp @@ -516,6 +516,8 @@ namespace eosio { namespace chain { 3015015, "Duplicate variant definition in the ABI" ) FC_DECLARE_DERIVED_EXCEPTION( unsupported_abi_version_exception, abi_exception, 3015016, "ABI has an unsupported version" ) + FC_DECLARE_DERIVED_EXCEPTION( duplicate_abi_action_results_def_exception, abi_exception, + 3015017, "Duplicate action results definition in the ABI" ) FC_DECLARE_DERIVED_EXCEPTION( contract_exception, chain_exception, 3160000, "Contract exception" ) From 4d8bbb08dadc5f735d1480a99f092decfd9ff3c7 Mon Sep 17 00:00:00 2001 From: Emory Barlow Date: Tue, 14 Jul 2020 12:46:28 -0400 Subject: [PATCH 2/4] Fix iterator to account for eosio::chain::may_not_exist --- libraries/chain/abi_serializer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 46725064eab..023914120cf 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -161,7 +161,7 @@ namespace eosio { namespace chain { for( const auto& v : abi.variants.value ) variants[v.name] = v; - for( const auto& r : abi.action_results ) + for( const auto& r : abi.action_results.value ) action_results[r.name] = r.result_type; /** @@ -174,7 +174,7 @@ namespace eosio { namespace chain { EOS_ASSERT( tables.size() == abi.tables.size(), duplicate_abi_table_def_exception, "duplicate table definition detected" ); EOS_ASSERT( error_messages.size() == abi.error_messages.size(), duplicate_abi_err_msg_def_exception, "duplicate error message definition detected" ); EOS_ASSERT( variants.size() == abi.variants.value.size(), duplicate_abi_variant_def_exception, "duplicate variant definition detected" ); - EOS_ASSERT( action_results.size() == abi.action_results.size(), duplicate_abi_action_results_def_exception, "duplicate action results definition detected" ); + EOS_ASSERT( action_results.size() == abi.action_results.value.size(), duplicate_abi_action_results_def_exception, "duplicate action results definition detected" ); validate(ctx); } From 83501aed63bf27d1abbae5de41e5c940fdca2252 Mon Sep 17 00:00:00 2001 From: Emory Barlow Date: Tue, 14 Jul 2020 15:25:49 -0400 Subject: [PATCH 3/4] Add tests --- unittests/abi_tests.cpp | 22 ++++++++++++++ unittests/api_tests.cpp | 25 ++++++++++++++++ unittests/contracts.hpp.in | 1 + unittests/test-contracts/CMakeLists.txt | 1 + .../action_results/CMakeLists.txt | 6 ++++ .../action_results/action_results.abi | 28 ++++++++++++++++++ .../action_results/action_results.cpp | 15 ++++++++++ .../action_results/action_results.wasm | Bin 0 -> 1687 bytes 8 files changed, 98 insertions(+) create mode 100644 unittests/test-contracts/action_results/CMakeLists.txt create mode 100644 unittests/test-contracts/action_results/action_results.abi create mode 100644 unittests/test-contracts/action_results/action_results.cpp create mode 100755 unittests/test-contracts/action_results/action_results.wasm diff --git a/unittests/abi_tests.cpp b/unittests/abi_tests.cpp index 3b3d3cc35f3..4b832cdd411 100644 --- a/unittests/abi_tests.cpp +++ b/unittests/abi_tests.cpp @@ -2361,7 +2361,29 @@ BOOST_AUTO_TEST_CASE(action_results) ], })"; + auto duplicate_action_results_abi = R"({ + "version": "eosio::abi/1.2", + "action_results": [ + {"name": "act1", "result_type": "string"}, + {"name": "act1", "result_type": "string"}, + ], + })"; + + auto action_results_abi_invalid_type = R"({ + "version": "eosio::abi/1.2", + "action_results": [ + {"name": "act1", "result_type": "string"}, + {"name": "act2", "result_type": "uint9000"}, + ], + })"; + try { + // duplicate action_results definition detected + BOOST_CHECK_THROW( abi_serializer( fc::json::from_string(duplicate_action_results_abi).as(), abi_serializer::create_yield_function( max_serialization_time ) ), duplicate_abi_action_results_def_exception ); + + // invalid_type_inside_abi + BOOST_CHECK_THROW( abi_serializer( fc::json::from_string(action_results_abi_invalid_type).as(), abi_serializer::create_yield_function( max_serialization_time ) ), invalid_type_inside_abi ); + // round-trip abi through multiple formats // json -> variant -> abi_def -> bin auto bin = fc::raw::pack(fc::json::from_string(action_results_abi).as()); diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index 8588b93eafb..e61e9671266 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -3079,4 +3079,29 @@ BOOST_FIXTURE_TEST_CASE(action_ordinal_failtest3, TESTER) { try { } FC_LOG_AND_RETHROW() } +BOOST_FIXTURE_TEST_CASE(action_results_tests, TESTER) { try { + produce_blocks(2); + create_account( N(test) ); + set_code( N(test), contracts::action_results_wasm() ); + produce_blocks(1); + + auto call_autoresret_and_check = [&]( account_name contract, account_name signer, auto&& checker ) { + signed_transaction trx; + trx.actions.emplace_back( vector{{signer, config::active_name}}, contract, N(actionresret), bytes{} ); + this->set_transaction_headers( trx, this->DEFAULT_EXPIRATION_DELTA ); + trx.sign( this->get_private_key(signer, "active"), control->get_chain_id() ); + auto res = this->push_transaction(trx); + checker( res ); + }; + + call_autoresret_and_check( N(test), N(test), [&]( const transaction_trace_ptr& res ) { + BOOST_CHECK_EQUAL( res->receipt->status, transaction_receipt::executed ); + + auto &atrace = res->action_traces; + BOOST_REQUIRE_EQUAL( atrace[0].receipt.valid(), true ); + BOOST_REQUIRE_EQUAL( atrace[0].return_value.size(), 4 ); + BOOST_REQUIRE_EQUAL( fc::raw::unpack(atrace[0].return_value), unsigned_int(10) ); + } ); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() diff --git a/unittests/contracts.hpp.in b/unittests/contracts.hpp.in index 9b7d50114dc..5eeddbab1c0 100644 --- a/unittests/contracts.hpp.in +++ b/unittests/contracts.hpp.in @@ -51,6 +51,7 @@ namespace eosio { MAKE_READ_WASM_ABI(test_api_db, test_api_db, test-contracts) MAKE_READ_WASM_ABI(test_api_multi_index, test_api_multi_index, test-contracts) MAKE_READ_WASM_ABI(test_ram_limit, test_ram_limit, test-contracts) + MAKE_READ_WASM_ABI(action_results, action_results, test-contracts) }; } /// eosio::testing } /// eosio diff --git a/unittests/test-contracts/CMakeLists.txt b/unittests/test-contracts/CMakeLists.txt index 7c48729a524..3ecb2e52f5e 100644 --- a/unittests/test-contracts/CMakeLists.txt +++ b/unittests/test-contracts/CMakeLists.txt @@ -23,3 +23,4 @@ add_subdirectory( test_api ) add_subdirectory( test_api_db ) add_subdirectory( test_api_multi_index ) add_subdirectory( test_ram_limit ) +add_subdirectory( action_results ) diff --git a/unittests/test-contracts/action_results/CMakeLists.txt b/unittests/test-contracts/action_results/CMakeLists.txt new file mode 100644 index 00000000000..68dc588ca1f --- /dev/null +++ b/unittests/test-contracts/action_results/CMakeLists.txt @@ -0,0 +1,6 @@ +if( EOSIO_COMPILE_TEST_CONTRACTS ) + add_contract( action_results action_results action_results.cpp ) +else() + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/action_results.wasm ${CMAKE_CURRENT_BINARY_DIR}/action_results.wasm COPYONLY ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/action_results.abi ${CMAKE_CURRENT_BINARY_DIR}/action_results.abi COPYONLY ) +endif() diff --git a/unittests/test-contracts/action_results/action_results.abi b/unittests/test-contracts/action_results/action_results.abi new file mode 100644 index 00000000000..f5ed5924007 --- /dev/null +++ b/unittests/test-contracts/action_results/action_results.abi @@ -0,0 +1,28 @@ +{ + "____comment": "This file was generated with eosio-abigen. DO NOT EDIT ", + "version": "eosio::abi/1.2", + "types": [], + "structs": [ + { + "name": "actionresret", + "base": "", + "fields": [] + } + ], + "actions": [ + { + "name": "actionresret", + "type": "actionresret", + "ricardian_contract": "" + } + ], + "tables": [], + "ricardian_clauses": [], + "variants": [], + "action_results": [ + { + "name": "actionresret", + "result_type": "int32" + } + ] +} \ No newline at end of file diff --git a/unittests/test-contracts/action_results/action_results.cpp b/unittests/test-contracts/action_results/action_results.cpp new file mode 100644 index 00000000000..30de5176211 --- /dev/null +++ b/unittests/test-contracts/action_results/action_results.cpp @@ -0,0 +1,15 @@ +#include + +using namespace eosio; + +class [[eosio::contract]] action_results : public contract { + public: + using contract::contract; + + [[eosio::action]] + int actionresret() { + return 10; + } + + private: +}; diff --git a/unittests/test-contracts/action_results/action_results.wasm b/unittests/test-contracts/action_results/action_results.wasm new file mode 100755 index 0000000000000000000000000000000000000000..44bdd1ab61b6825176795e6ff0e22139bd5d3266 GIT binary patch literal 1687 zcmZ8hF>f426n<}JcF*?QapOdCh||n26s{BLBGGVTDS`kJ3V-0d*bDOB*>}F%7#l_2 z1EoMHMLI%HheZPg3R2{j8i7Q^4?qHX3gCOYzSv}o-Fe@XestzJKVl?Q(a#KiJ92Y%tsXI42gkosVa` z<3To?<9`EE7=_{)gx6Bf;(XAzUmX(Qk!pxCo;&@G09Oh?aD+w7*I)ed=Z{anyy+E8LEX!dr_H%MXHTE} zOz)X~sO?{W`u2}c|01_!ZFFhBIY->T`TMuuzpCnk5b?=;eksBRa%*8{2P@pcL zKpW~2?BEVlE>hKl)u0disrFQaZV@I2DfQIDJ_1#6rKh(g9BVGb-!m2oTWoWmLiL91 zhR0{**m`Y0=Z2F#jZ%Jrn1xssss0}^L|71;b7C#TrXkh~V#y#;LabgSz9(T z^$-j>g)>w$&+pc7`!ej1IA*nmGMyto3Y?XJbKCLA3U2tF#(2zyEFHK^*a*7SLp0WVsv&JhsA zHJxvKB82FAk6i~+-h_@}Ezy#AFn2rDRN$Ocb8PTxTz2viKP)nD2+q)4pjXYPfI$498fZf4gUbr zGK#TW-xB@SKE8V+)lyCZrbZy`uHart#|uo0@)5=-(HFUBxp?|{4%TCMM4mbeOrshm zMo0s{DY|?1O0v$!yqevQ2Gy$TrE`q literal 0 HcmV?d00001 From 326495ffb872b3780d95809fb3610fc7d113418c Mon Sep 17 00:00:00 2001 From: Emory Barlow Date: Tue, 14 Jul 2020 15:30:48 -0400 Subject: [PATCH 4/4] Fix unpack to match return type --- unittests/api_tests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unittests/api_tests.cpp b/unittests/api_tests.cpp index e61e9671266..4f538ac680a 100644 --- a/unittests/api_tests.cpp +++ b/unittests/api_tests.cpp @@ -3100,7 +3100,7 @@ BOOST_FIXTURE_TEST_CASE(action_results_tests, TESTER) { try { auto &atrace = res->action_traces; BOOST_REQUIRE_EQUAL( atrace[0].receipt.valid(), true ); BOOST_REQUIRE_EQUAL( atrace[0].return_value.size(), 4 ); - BOOST_REQUIRE_EQUAL( fc::raw::unpack(atrace[0].return_value), unsigned_int(10) ); + BOOST_REQUIRE_EQUAL( fc::raw::unpack(atrace[0].return_value), 10 ); } ); } FC_LOG_AND_RETHROW() }