Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

fix abi serialization exception in get block #5548

Merged
merged 4 commits into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions libraries/chain/include/eosio/chain/abi_serializer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,21 +286,25 @@ namespace impl {
mvo("name", act.name);
mvo("authorization", act.authorization);

auto abi = resolver(act.account);
if (abi.valid()) {
auto type = abi->get_action_type(act.name);
if (!type.empty()) {
try {
mvo( "data", abi->_binary_to_variant( type, act.data, recursion_depth, deadline, max_serialization_time ));
mvo("hex_data", act.data);
} catch(...) {
// any failure to serialize data, then leave as not serailzed
try {
auto abi = resolver(act.account);
if (abi.valid()) {
auto type = abi->get_action_type(act.name);
if (!type.empty()) {
try {
mvo( "data", abi->_binary_to_variant( type, act.data, recursion_depth, deadline, max_serialization_time ));
mvo("hex_data", act.data);
} catch(...) {
// any failure to serialize data, then leave as not serailzed
mvo("data", act.data);
}
} else {
mvo("data", act.data);
}
} else {
mvo("data", act.data);
}
} else {
} catch(...) {
mvo("data", act.data);
}
out(name, std::move(mvo));
Expand Down
8 changes: 5 additions & 3 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ set( CMAKE_CXX_STANDARD 14 )

include_directories("${CMAKE_SOURCE_DIR}/plugins/wallet_plugin/include")

file(GLOB UNIT_TESTS "wallet_tests.cpp")
file(GLOB UNIT_TESTS "*.cpp")

add_executable( plugin_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} main.cpp)
add_executable( plugin_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} )
target_link_libraries( plugin_test eosio_testing eosio_chain chainbase eos_utilities chain_plugin wallet_plugin abi_generator fc ${PLATFORM_SPECIFIC_LIBS} )

target_include_directories( plugin_test PUBLIC ${CMAKE_SOURCE_DIR}/plugins/net_plugin/include )
target_include_directories( plugin_test PUBLIC
${CMAKE_SOURCE_DIR}/plugins/net_plugin/include
${CMAKE_SOURCE_DIR}/plugins/chain_plugin/include )
add_dependencies(plugin_test asserter test_api test_api_mem test_api_db test_api_multi_index exchange proxy identity identity_test stltest infinite eosio.system eosio.token eosio.bios test.inline multi_index_test noop dice eosio.msig)

#
Expand Down
132 changes: 132 additions & 0 deletions tests/chain_plugin_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include <boost/test/unit_test.hpp>
#include <boost/algorithm/string/predicate.hpp>

#include <eosio/testing/tester.hpp>
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/wasm_eosio_constraints.hpp>
#include <eosio/chain/resource_limits.hpp>
#include <eosio/chain/exceptions.hpp>
#include <eosio/chain/wast_to_wasm.hpp>
#include <eosio/chain_plugin/chain_plugin.hpp>

#include <asserter/asserter.wast.hpp>
#include <asserter/asserter.abi.hpp>

#include <stltest/stltest.wast.hpp>
#include <stltest/stltest.abi.hpp>

#include <noop/noop.wast.hpp>
#include <noop/noop.abi.hpp>

#include <eosio.system/eosio.system.wast.hpp>
#include <eosio.system/eosio.system.abi.hpp>

#include <fc/io/fstream.hpp>

#include <Runtime/Runtime.h>

#include <fc/variant_object.hpp>
#include <fc/io/json.hpp>

#include <array>
#include <utility>

#ifdef NON_VALIDATING_TEST
#define TESTER tester
#else
#define TESTER validating_tester
#endif

using namespace eosio;
using namespace eosio::chain;
using namespace eosio::testing;
using namespace fc;

BOOST_AUTO_TEST_SUITE(chain_plugin_tests)

BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, TESTER ) try {
produce_blocks(2);

create_accounts( {N(asserter)} );
produce_block();

// setup contract and abi
set_code(N(asserter), asserter_wast);
set_abi(N(asserter), asserter_abi);
produce_blocks(1);

auto resolver = [&,this]( const account_name& name ) -> optional<abi_serializer> {
try {
const auto& accnt = this->control->db().get<account_object,by_name>( name );
abi_def abi;
if (abi_serializer::to_abi(accnt.abi, abi)) {
return abi_serializer(abi, abi_serializer_max_time);
}
return optional<abi_serializer>();
} FC_RETHROW_EXCEPTIONS(error, "resolver failed at chain_plugin_tests::abi_invalid_type");
};

// abi should be resolved
BOOST_REQUIRE_EQUAL(true, resolver(N(asserter)).valid());

// make an action using the valid contract & abi
variant pretty_trx = mutable_variant_object()
("actions", variants({
mutable_variant_object()
("account", "asserter")
("name", "procassert")
("authorization", variants({
mutable_variant_object()
("actor", "asserter")
("permission", name(config::active_name).to_string())
}))
("data", mutable_variant_object()
("condition", 1)
("message", "Should Not Assert!")
)
})
);
signed_transaction trx;
abi_serializer::from_variant(pretty_trx, trx, resolver, abi_serializer_max_time);
set_transaction_headers(trx);
trx.sign( get_private_key( N(asserter), "active" ), control->get_chain_id() );
push_transaction( trx );
produce_blocks(1);

// retrieve block num
uint32_t headnum = this->control->head_block_num();

char headnumstr[20];
sprintf(headnumstr, "%d", headnum);
chain_apis::read_only::get_block_params param{headnumstr};
chain_apis::read_only plugin(*(this->control), fc::microseconds(INT_MAX));

// block should be decoded successfully
std::string block_str = json::to_pretty_string(plugin.get_block(param));
BOOST_TEST(block_str.find("procassert") != std::string::npos);
BOOST_TEST(block_str.find("condition") != std::string::npos);
BOOST_TEST(block_str.find("Should Not Assert!") != std::string::npos);
BOOST_TEST(block_str.find("011253686f756c64204e6f742041737365727421") != std::string::npos); //action data

// set an invalid abi (int8->xxxx)
std::string abi2 = asserter_abi;
auto pos = abi2.find("int8");
BOOST_TEST(pos != std::string::npos);
abi2.replace(pos, 4, "xxxx");
set_abi(N(asserter), abi2.c_str());
produce_blocks(1);

// resolving the invalid abi result in exception
BOOST_CHECK_THROW(resolver(N(asserter)), invalid_type_inside_abi);

// get the same block as string, results in decode failed(invalid abi) but not exception
std::string block_str2 = json::to_pretty_string(plugin.get_block(param));
BOOST_TEST(block_str2.find("procassert") != std::string::npos);
BOOST_TEST(block_str2.find("condition") == std::string::npos); // decode failed
BOOST_TEST(block_str2.find("Should Not Assert!") == std::string::npos); // decode failed
BOOST_TEST(block_str2.find("011253686f756c64204e6f742041737365727421") != std::string::npos); //action data

} FC_LOG_AND_RETHROW() /// get_block_with_invalid_abi

BOOST_AUTO_TEST_SUITE_END()