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

fix bugs in abi_serializer variant to binary #5680

Merged
merged 1 commit into from
Sep 14, 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
25 changes: 12 additions & 13 deletions libraries/chain/abi_serializer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ namespace eosio { namespace chain {
vars.emplace_back(std::move(v));
}
EOS_ASSERT( vars.size() == size.value,
unpack_exception,
unpack_exception,
"packed size does not match unpacked array size, packed size ${p} actual size ${a}",
("p", size)("a", vars.size()) );
return fc::variant( std::move(vars) );
Expand Down Expand Up @@ -386,26 +386,25 @@ namespace eosio { namespace chain {
} else if( ends_with(field.type, "$") && allow_extensions ) {
missing_extension = true;
} else {
_variant_to_binary(field.type, fc::variant(), ds, false, recursion_depth, deadline, max_serialization_time);
/// TODO: default construct field and write it out
EOS_THROW( pack_exception, "Missing '${f}' in variant object", ("f",field.name) );
}
}
} else if( var.is_array() ) {
const auto& va = var.get_array();
EOS_ASSERT( st.base == type_name(), invalid_type_inside_abi, "support for base class as array not yet implemented" );
uint32_t i = 0;
if (va.size() > 0) {
for( const auto& field : st.fields ) {
if( va.size() > i )
_variant_to_binary(_remove_bin_extension(field.type), va[i], ds, allow_extensions && &field == &st.fields.back(), recursion_depth, deadline, max_serialization_time);
else if( ends_with(field.type, "$") && allow_extensions )
break;
else
_variant_to_binary(field.type, fc::variant(), ds, false, recursion_depth, deadline, max_serialization_time);
++i;
}
for( const auto& field : st.fields ) {
if( va.size() > i )
_variant_to_binary(_remove_bin_extension(field.type), va[i], ds, allow_extensions && &field == &st.fields.back(), recursion_depth, deadline, max_serialization_time);
else if( ends_with(field.type, "$") && allow_extensions )
break;
else
EOS_THROW( pack_exception, "Early end to array specifying the fields of struct '${t}'; require input for field '${f}'",
("t", st.name)("f", field.name) );
++i;
}
} else {
EOS_THROW( pack_exception, "Failed to serialize struct '${t}' in variant object", ("t", st.name));
}
}
} FC_CAPTURE_AND_RETHROW( (type)(var) ) }
Expand Down
112 changes: 106 additions & 6 deletions unittests/abi_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <eosio/chain/abi_serializer.hpp>
#include <eosio/chain/eosio_contract.hpp>
#include <eosio/abi_generator/abi_generator.hpp>
#include <eosio/testing/tester.hpp>

#include <boost/test/framework.hpp>

Expand Down Expand Up @@ -558,7 +559,7 @@ struct abi_gen_helper {

std::string contract;
std::vector<std::string> actions;

auto extra_args = std::vector<std::string>{"-fparse-all-comments", "--std=c++14", "--target=wasm32", "-ffreestanding", "-nostdlib",
"-nostdlibinc", "-fno-threadsafe-statics", "-fno-rtti", "-fno-exceptions",
include_param, boost_include_param, stdcpp_include_param,
Expand All @@ -567,7 +568,7 @@ struct abi_gen_helper {
bool res = runToolOnCodeWithArgs(
new find_eosio_abi_macro_action(contract, actions, ""),
source,
extra_args
extra_args
);
FC_ASSERT(res == true);

Expand Down Expand Up @@ -3438,7 +3439,16 @@ BOOST_AUTO_TEST_CASE(abi_recursive_structs)
"type": "a"
}
]
}
},
{
"name": "hi2",
"base": "",
"fields": [{
"name": "user",
"type": "name"
}
]
}
],
"actions": [{
"name": "hi",
Expand All @@ -3449,10 +3459,10 @@ BOOST_AUTO_TEST_CASE(abi_recursive_structs)
"tables": []
}
)=====";

abi_serializer abis(fc::json::from_string(abi_str).as<abi_def>(), max_serialization_time);
string hi_data = "{\"user\":\"eosio\",\"arg2\":{\"user\":\"1\"}}";
auto bin = abis.variant_to_binary("hi", fc::json::from_string(hi_data), max_serialization_time);
string hi_data = "{\"user\":\"eosio\"}";
auto bin = abis.variant_to_binary("hi2", fc::json::from_string(hi_data), max_serialization_time);
BOOST_CHECK_THROW( abis.binary_to_variant("hi", bin, max_serialization_time);, fc::exception );

} FC_LOG_AND_RETHROW()
Expand Down Expand Up @@ -3600,4 +3610,94 @@ BOOST_AUTO_TEST_CASE(version)
} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_CASE(abi_serialize_incomplete_json_array)
{
using eosio::testing::fc_exception_message_starts_with;

auto abi = R"({
"version": "eosio::abi/1.0",
"structs": [
{"name": "s", "base": "", "fields": [
{"name": "i0", "type": "int8"},
{"name": "i1", "type": "int8"},
{"name": "i2", "type": "int8"}
]}
],
})";

try {
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), max_serialization_time );

BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"([])"), max_serialization_time),
pack_exception, fc_exception_message_starts_with("Early end to array specifying the fields of struct") );

BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"([1,2])"), max_serialization_time),
pack_exception, fc_exception_message_starts_with("Early end to array specifying the fields of struct") );

verify_round_trip_conversion(abis, "s", R"([1,2,3])", "010203", R"({"i0":1,"i1":2,"i2":3})");

} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_CASE(abi_serialize_incomplete_json_object)
{
using eosio::testing::fc_exception_message_is;

auto abi = R"({
"version": "eosio::abi/1.0",
"structs": [
{"name": "s1", "base": "", "fields": [
{"name": "i0", "type": "int8"},
{"name": "i1", "type": "int8"}
]},
{"name": "s2", "base": "", "fields": [
{"name": "f0", "type": "s1"}
{"name": "i2", "type": "int8"}
]}
],
})";

try {
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), max_serialization_time );

BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({})"), max_serialization_time),
pack_exception, fc_exception_message_is("Missing 'f0' in variant object") );

BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"f0":{"i0":1}})"), max_serialization_time),
pack_exception, fc_exception_message_is("Missing 'i1' in variant object") );

verify_round_trip_conversion(abis, "s2", R"({"f0":{"i0":1,"i1":2},"i2":3})", "010203");

} FC_LOG_AND_RETHROW()
}

BOOST_AUTO_TEST_CASE(abi_serialize_json_mismatching_type)
{
using eosio::testing::fc_exception_message_is;

auto abi = R"({
"version": "eosio::abi/1.0",
"structs": [
{"name": "s1", "base": "", "fields": [
{"name": "i0", "type": "int8"},
]},
{"name": "s2", "base": "", "fields": [
{"name": "f0", "type": "s1"}
{"name": "i1", "type": "int8"}
]}
],
})";

try {
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), max_serialization_time );

BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"f0":1,"i1":2})"), max_serialization_time),
pack_exception, fc_exception_message_is("Failed to serialize struct 's1' in variant object") );

verify_round_trip_conversion(abis, "s2", R"({"f0":{"i0":1},"i1":2})", "0102");

} FC_LOG_AND_RETHROW()
}


BOOST_AUTO_TEST_SUITE_END()