3340 lines
134 KiB
C++
3340 lines
134 KiB
C++
#include <algorithm>
|
|
#include <vector>
|
|
#include <iterator>
|
|
#include <cstdlib>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
#include <fc/variant.hpp>
|
|
#include <fc/io/json.hpp>
|
|
#include <fc/exception/exception.hpp>
|
|
#include <fc/log/logger.hpp>
|
|
#include <fc/scoped_exit.hpp>
|
|
#include <fc/time.hpp>
|
|
|
|
#include <eosio/chain/contract_types.hpp>
|
|
#include <eosio/chain/abi_serializer.hpp>
|
|
#include <eosio/chain/eosio_contract.hpp>
|
|
#include <eosio/testing/tester.hpp>
|
|
|
|
#include <boost/test/framework.hpp>
|
|
|
|
#include <deep_nested.abi.hpp>
|
|
#include <large_nested.abi.hpp>
|
|
|
|
using namespace eosio;
|
|
using namespace chain;
|
|
|
|
struct act_sig {
|
|
eosio::chain::signature_type sig;
|
|
|
|
static account_name get_account() {
|
|
return "hello"_n;
|
|
}
|
|
|
|
static action_name get_name() {
|
|
return "act"_n;
|
|
}
|
|
};
|
|
FC_REFLECT(act_sig, (sig) )
|
|
|
|
|
|
BOOST_AUTO_TEST_SUITE(abi_tests)
|
|
|
|
#ifdef NDEBUG
|
|
fc::microseconds max_serialization_time = fc::seconds(1); // some test machines are very slow
|
|
#else
|
|
fc::microseconds max_serialization_time = fc::microseconds::maximum(); // don't check in debug builds
|
|
#endif
|
|
|
|
static fc::time_point get_deadline() {
|
|
return fc::time_point::now().safe_add(max_serialization_time);
|
|
}
|
|
|
|
// verify that round trip conversion, via bytes, reproduces the exact same data
|
|
fc::variant verify_byte_round_trip_conversion( const abi_serializer& abis, const type_name& type, const fc::variant& var )
|
|
{
|
|
auto bytes = abis.variant_to_binary(type, var, abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto b = abis.variant_to_binary(type, var, max_serialization_time );
|
|
BOOST_TEST( b == bytes );
|
|
|
|
auto var2 = abis.binary_to_variant(type, bytes, abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto var3 = abis.binary_to_variant(type, b, max_serialization_time);
|
|
|
|
std::string r2 = fc::json::to_string(var2, get_deadline());
|
|
std::string r3 = fc::json::to_string(var3, get_deadline());
|
|
BOOST_TEST( r2 == r3 );
|
|
|
|
auto bytes2 = abis.variant_to_binary(type, var2, abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto bytes3 = abis.variant_to_binary(type, var3, max_serialization_time);
|
|
BOOST_TEST( bytes2 == bytes3 );
|
|
|
|
BOOST_TEST( fc::to_hex(bytes) == fc::to_hex(bytes2) );
|
|
|
|
return var2;
|
|
}
|
|
|
|
void verify_round_trip_conversion( const abi_serializer& abis, const type_name& type, const std::string& json, const std::string& hex, const std::string& expected_json )
|
|
{
|
|
auto var = fc::json::from_string(json);
|
|
auto bytes = abis.variant_to_binary(type, var, abi_serializer::create_yield_function( max_serialization_time ));
|
|
BOOST_REQUIRE_EQUAL(fc::to_hex(bytes), hex);
|
|
auto b = abis.variant_to_binary(type, var, max_serialization_time);
|
|
BOOST_REQUIRE_EQUAL(fc::to_hex(b), hex);
|
|
auto var2 = abis.binary_to_variant(type, bytes, abi_serializer::create_yield_function( max_serialization_time ));
|
|
BOOST_REQUIRE_EQUAL(fc::json::to_string(var2, get_deadline()), expected_json);
|
|
auto var3 = abis.binary_to_variant(type, b, max_serialization_time );
|
|
BOOST_REQUIRE_EQUAL(fc::json::to_string(var3, get_deadline()), expected_json);
|
|
auto bytes2 = abis.variant_to_binary(type, var2, abi_serializer::create_yield_function( max_serialization_time ));
|
|
BOOST_REQUIRE_EQUAL(fc::to_hex(bytes2), hex);
|
|
auto b2 = abis.variant_to_binary(type, var3, max_serialization_time);
|
|
BOOST_REQUIRE_EQUAL(fc::to_hex(b2), hex);
|
|
}
|
|
|
|
void verify_round_trip_conversion( const abi_serializer& abis, const type_name& type, const std::string& json, const std::string& hex )
|
|
{
|
|
verify_round_trip_conversion( abis, type, json, hex, json );
|
|
}
|
|
|
|
auto get_resolver(const abi_def& abi = abi_def())
|
|
{
|
|
return [&abi](const account_name &name) -> std::optional<abi_serializer> {
|
|
return abi_serializer(eosio_contract_abi(abi), abi_serializer::create_yield_function( max_serialization_time ));
|
|
};
|
|
}
|
|
|
|
// verify that round trip conversion, via actual class, reproduces the exact same data
|
|
template<typename T>
|
|
fc::variant verify_type_round_trip_conversion( const abi_serializer& abis, const type_name& type, const fc::variant& var )
|
|
{ try {
|
|
|
|
auto bytes = abis.variant_to_binary(type, var, abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto b = abis.variant_to_binary(type, var, max_serialization_time);
|
|
|
|
T obj;
|
|
abi_serializer::from_variant(var, obj, get_resolver(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
T obj2;
|
|
abi_serializer::from_variant(var, obj2, get_resolver(), max_serialization_time);
|
|
|
|
fc::variant var2;
|
|
abi_serializer::to_variant(obj, var2, get_resolver(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
fc::variant var3;
|
|
abi_serializer::to_variant(obj2, var3, get_resolver(), max_serialization_time);
|
|
|
|
std::string r2 = fc::json::to_string(var2, get_deadline());
|
|
std::string r3 = fc::json::to_string(var3, get_deadline());
|
|
BOOST_TEST( r2 == r3 );
|
|
|
|
auto bytes2 = abis.variant_to_binary(type, var2, abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto b3 = abis.variant_to_binary(type, var3, max_serialization_time);
|
|
BOOST_TEST( bytes2 == b3 );
|
|
BOOST_TEST( b == b3 );
|
|
|
|
BOOST_TEST( fc::to_hex(bytes) == fc::to_hex(bytes2) );
|
|
|
|
return var2;
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
|
|
const char* my_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "type_name",
|
|
"type": "string"
|
|
},{
|
|
"new_type_name": "field_name",
|
|
"type": "string"
|
|
},{
|
|
"new_type_name": "fields",
|
|
"type": "field_def[]"
|
|
},{
|
|
"new_type_name": "scope_name",
|
|
"type": "name"
|
|
}],
|
|
"structs": [{
|
|
"name": "abi_extension",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "type",
|
|
"type": "uint16"
|
|
},{
|
|
"name": "data",
|
|
"type": "bytes"
|
|
}]
|
|
},{
|
|
"name": "type_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "new_type_name",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "field_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "field_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "struct_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "base",
|
|
"type": "type_name"
|
|
}{
|
|
"name": "fields",
|
|
"type": "field_def[]"
|
|
}]
|
|
},{
|
|
"name": "action_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "action_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "ricardian_contract",
|
|
"type": "string"
|
|
}]
|
|
},{
|
|
"name": "table_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "table_name"
|
|
},{
|
|
"name": "index_type",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "key_names",
|
|
"type": "field_name[]"
|
|
},{
|
|
"name": "key_types",
|
|
"type": "type_name[]"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "clause_pair",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "id",
|
|
"type": "string"
|
|
},{
|
|
"name": "body",
|
|
"type": "string"
|
|
}]
|
|
},{
|
|
"name": "abi_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "version",
|
|
"type": "string"
|
|
},{
|
|
"name": "types",
|
|
"type": "type_def[]"
|
|
},{
|
|
"name": "structs",
|
|
"type": "struct_def[]"
|
|
},{
|
|
"name": "actions",
|
|
"type": "action_def[]"
|
|
},{
|
|
"name": "tables",
|
|
"type": "table_def[]"
|
|
},{
|
|
"name": "ricardian_clauses",
|
|
"type": "clause_pair[]"
|
|
},{
|
|
"name": "abi_extensions",
|
|
"type": "abi_extension[]"
|
|
}]
|
|
},{
|
|
"name" : "A",
|
|
"base" : "PublicKeyTypes",
|
|
"fields": []
|
|
},{
|
|
"name": "signed_transaction",
|
|
"base": "transaction",
|
|
"fields": [{
|
|
"name": "signatures",
|
|
"type": "signature[]"
|
|
},{
|
|
"name": "context_free_data",
|
|
"type": "bytes[]"
|
|
}]
|
|
},{
|
|
"name": "PublicKeyTypes",
|
|
"base" : "AssetTypes",
|
|
"fields": [{
|
|
"name": "publickey",
|
|
"type": "public_key"
|
|
},{
|
|
"name": "publickey_arr",
|
|
"type": "public_key[]"
|
|
}]
|
|
},{
|
|
"name": "AssetTypes",
|
|
"base" : "NativeTypes",
|
|
"fields": [{
|
|
"name": "asset",
|
|
"type": "asset"
|
|
},{
|
|
"name": "asset_arr",
|
|
"type": "asset[]"
|
|
}]
|
|
},{
|
|
"name": "NativeTypes",
|
|
"fields" : [{
|
|
"name": "string",
|
|
"type": "string"
|
|
},{
|
|
"name": "string_arr",
|
|
"type": "string[]"
|
|
},{
|
|
"name": "block_timestamp_type",
|
|
"type": "block_timestamp_type"
|
|
},{
|
|
"name": "time_point",
|
|
"type": "time_point"
|
|
},{
|
|
"name": "time_point_arr",
|
|
"type": "time_point[]"
|
|
},{
|
|
"name": "time_point_sec",
|
|
"type": "time_point_sec"
|
|
},{
|
|
"name": "time_point_sec_arr",
|
|
"type": "time_point_sec[]"
|
|
},{
|
|
"name": "signature",
|
|
"type": "signature"
|
|
},{
|
|
"name": "signature_arr",
|
|
"type": "signature[]"
|
|
},{
|
|
"name": "checksum256",
|
|
"type": "checksum256"
|
|
},{
|
|
"name": "checksum256_arr",
|
|
"type": "checksum256[]"
|
|
},{
|
|
"name": "fieldname",
|
|
"type": "field_name"
|
|
},{
|
|
"name": "fieldname_arr",
|
|
"type": "field_name[]"
|
|
},{
|
|
"name": "typename",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "typename_arr",
|
|
"type": "type_name[]"
|
|
},{
|
|
"name": "uint8",
|
|
"type": "uint8"
|
|
},{
|
|
"name": "uint8_arr",
|
|
"type": "uint8[]"
|
|
},{
|
|
"name": "uint16",
|
|
"type": "uint16"
|
|
},{
|
|
"name": "uint16_arr",
|
|
"type": "uint16[]"
|
|
},{
|
|
"name": "uint32",
|
|
"type": "uint32"
|
|
},{
|
|
"name": "uint32_arr",
|
|
"type": "uint32[]"
|
|
},{
|
|
"name": "uint64",
|
|
"type": "uint64"
|
|
},{
|
|
"name": "uint64_arr",
|
|
"type": "uint64[]"
|
|
},{
|
|
"name": "uint128",
|
|
"type": "uint128"
|
|
},{
|
|
"name": "uint128_arr",
|
|
"type": "uint128[]"
|
|
},{
|
|
"name": "int8",
|
|
"type": "int8"
|
|
},{
|
|
"name": "int8_arr",
|
|
"type": "int8[]"
|
|
},{
|
|
"name": "int16",
|
|
"type": "int16"
|
|
},{
|
|
"name": "int16_arr",
|
|
"type": "int16[]"
|
|
},{
|
|
"name": "int32",
|
|
"type": "int32"
|
|
},{
|
|
"name": "int32_arr",
|
|
"type": "int32[]"
|
|
},{
|
|
"name": "int64",
|
|
"type": "int64"
|
|
},{
|
|
"name": "int64_arr",
|
|
"type": "int64[]"
|
|
},{
|
|
"name": "int128",
|
|
"type": "int128"
|
|
},{
|
|
"name": "int128_arr",
|
|
"type": "int128[]"
|
|
},{
|
|
"name": "name",
|
|
"type": "name"
|
|
},{
|
|
"name": "name_arr",
|
|
"type": "name[]"
|
|
},{
|
|
"name": "field",
|
|
"type": "field_def"
|
|
},{
|
|
"name": "field_arr",
|
|
"type": "field_def[]"
|
|
},{
|
|
"name": "struct",
|
|
"type": "struct_def"
|
|
},{
|
|
"name": "struct_arr",
|
|
"type": "struct_def[]"
|
|
},{
|
|
"name": "fields",
|
|
"type": "fields"
|
|
},{
|
|
"name": "fields_arr",
|
|
"type": "fields[]"
|
|
},{
|
|
"name": "accountname",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "accountname_arr",
|
|
"type": "account_name[]"
|
|
},{
|
|
"name": "permname",
|
|
"type": "permission_name"
|
|
},{
|
|
"name": "permname_arr",
|
|
"type": "permission_name[]"
|
|
},{
|
|
"name": "actionname",
|
|
"type": "action_name"
|
|
},{
|
|
"name": "actionname_arr",
|
|
"type": "action_name[]"
|
|
},{
|
|
"name": "scopename",
|
|
"type": "scope_name"
|
|
},{
|
|
"name": "scopename_arr",
|
|
"type": "scope_name[]"
|
|
},{
|
|
"name": "permlvl",
|
|
"type": "permission_level"
|
|
},{
|
|
"name": "permlvl_arr",
|
|
"type": "permission_level[]"
|
|
},{
|
|
"name": "action",
|
|
"type": "action"
|
|
},{
|
|
"name": "action_arr",
|
|
"type": "action[]"
|
|
},{
|
|
"name": "permlvlwgt",
|
|
"type": "permission_level_weight"
|
|
},{
|
|
"name": "permlvlwgt_arr",
|
|
"type": "permission_level_weight[]"
|
|
},{
|
|
"name": "transaction",
|
|
"type": "transaction"
|
|
},{
|
|
"name": "transaction_arr",
|
|
"type": "transaction[]"
|
|
},{
|
|
"name": "strx",
|
|
"type": "signed_transaction"
|
|
},{
|
|
"name": "strx_arr",
|
|
"type": "signed_transaction[]"
|
|
},{
|
|
"name": "keyweight",
|
|
"type": "key_weight"
|
|
},{
|
|
"name": "keyweight_arr",
|
|
"type": "key_weight[]"
|
|
},{
|
|
"name": "authority",
|
|
"type": "authority"
|
|
},{
|
|
"name": "authority_arr",
|
|
"type": "authority[]"
|
|
},{
|
|
"name": "typedef",
|
|
"type": "type_def"
|
|
},{
|
|
"name": "typedef_arr",
|
|
"type": "type_def[]"
|
|
},{
|
|
"name": "actiondef",
|
|
"type": "action_def"
|
|
},{
|
|
"name": "actiondef_arr",
|
|
"type": "action_def[]"
|
|
},{
|
|
"name": "tabledef",
|
|
"type": "table_def"
|
|
},{
|
|
"name": "tabledef_arr",
|
|
"type": "table_def[]"
|
|
},{
|
|
"name": "abidef",
|
|
"type": "abi_def"
|
|
},{
|
|
"name": "abidef_arr",
|
|
"type": "abi_def[]"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [],
|
|
"tables": [],
|
|
"ricardian_clauses": [{"id":"clause A","body":"clause body A"},
|
|
{"id":"clause B","body":"clause body B"}],
|
|
"abi_extensions": []
|
|
}
|
|
)=====";
|
|
|
|
BOOST_AUTO_TEST_CASE(uint_types)
|
|
{ try {
|
|
|
|
const char* currency_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "amount64",
|
|
"type": "uint64"
|
|
},{
|
|
"name": "amount32",
|
|
"type": "uint32"
|
|
},{
|
|
"name": "amount16",
|
|
"type": "uint16"
|
|
},{
|
|
"name": "amount8",
|
|
"type": "uint8"
|
|
}]
|
|
}],
|
|
"actions": [],
|
|
"tables": [],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = fc::json::from_string(currency_abi).as<abi_def>();
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
const char* test_data = R"=====(
|
|
{
|
|
"amount64" : 64,
|
|
"amount32" : 32,
|
|
"amount16" : 16,
|
|
"amount8" : 8,
|
|
}
|
|
)=====";
|
|
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abi_serializer{std::move(abi), abi_serializer::create_yield_function( max_serialization_time )}, "transfer", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(general)
|
|
{ try {
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(my_abi).as<abi_def>());
|
|
|
|
abi_serializer abis(abi_def(abi), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
const char *my_other = R"=====(
|
|
{
|
|
"publickey" : "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
|
|
"publickey_arr" : ["EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV","EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"],
|
|
"asset" : "100.0000 SYS",
|
|
"asset_arr" : ["100.0000 SYS","100.0000 SYS"],
|
|
|
|
"string" : "ola ke ase",
|
|
"string_arr" : ["ola ke ase","ola ke desi"],
|
|
"block_timestamp_type" : "2021-12-20T15",
|
|
"time_point" : "2021-12-20T15:30",
|
|
"time_point_arr" : ["2021-12-20T15:30","2021-12-20T15:31"],
|
|
"time_point_sec" : "2021-12-20T15:30:21",
|
|
"time_point_sec_arr": ["2021-12-20T15:30:21","2021-12-20T15:31:21"],
|
|
"signature" : "SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5",
|
|
"signature_arr" : ["SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5","SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5"],
|
|
"checksum256" : "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
|
|
"checksum256_arr" : ["ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad","ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"],
|
|
"fieldname" : "name1",
|
|
"fieldname_arr" : ["name1","name2"],
|
|
"typename" : "name3",
|
|
"typename_arr" : ["name4","name5"],
|
|
"bytes" : "010203",
|
|
"bytes_arr" : ["010203","","040506"],
|
|
"uint8" : 8,
|
|
"uint8_arr" : [8,9],
|
|
"uint16" : 16,
|
|
"uint16_arr" : [16,17],
|
|
"uint32" : 32,
|
|
"uint32_arr" : [32,33],
|
|
"uint64" : 64,
|
|
"uint64_arr" : [64,65],
|
|
"uint128" : 128,
|
|
"uint128_arr" : ["0x00000000000000000000000000000080",129],
|
|
"int8" : 108,
|
|
"int8_arr" : [108,109],
|
|
"int16" : 116,
|
|
"int16_arr" : [116,117],
|
|
"int32" : 132,
|
|
"int32_arr" : [132,133],
|
|
"int64" : 164,
|
|
"int64_arr" : [164,165],
|
|
"int128" : -128,
|
|
"int128_arr" : ["0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80",-129],
|
|
"name" : "xname1",
|
|
"name_arr" : ["xname2","xname3"],
|
|
"field" : {"name":"name1", "type":"type1"},
|
|
"field_arr" : [{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}],
|
|
"struct" : {"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}]},
|
|
"struct_arr" : [{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}]},{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}]}],
|
|
"fields" : [{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}],
|
|
"fields_arr" : [[{"name":"name1", "type":"type1"}, {"name":"name2", "type":"type2"}],[{"name":"name3", "type":"type3"}, {"name":"name4", "type":"type4"}]],
|
|
"accountname" : "acc1",
|
|
"accountname_arr" : ["acc1","acc2"],
|
|
"permname" : "pername",
|
|
"permname_arr" : ["pername1","pername2"],
|
|
"actionname" : "actionname",
|
|
"actionname_arr" : ["actionname1","actionname2"],
|
|
"scopename" : "acc1",
|
|
"scopename_arr" : ["acc1","acc2"],
|
|
"permlvl" : {"actor":"acc1","permission":"permname1"},
|
|
"permlvl_arr" : [{"actor":"acc1","permission":"permname1"},{"actor":"acc2","permission":"permname2"}],
|
|
"action" : {"account":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"},
|
|
"action_arr" : [{"account":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"},{"account":"acc2", "name":"actionname2", "authorization":[{"actor":"acc2","permission":"permname2"}], "data":""}],
|
|
"permlvlwgt" : {"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},
|
|
"permlvlwgt_arr" : [{"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},{"permission":{"actor":"acc2","permission":"permname2"},"weight":"2"}],
|
|
"transaction" : {
|
|
"ref_block_num":"1",
|
|
"ref_block_prefix":"2",
|
|
"expiration":"2021-12-20T15:30",
|
|
"context_free_actions":[{"account":"contextfree1", "name":"cfactionname1", "authorization":[{"actor":"cfacc1","permission":"cfpermname1"}], "data":"778899"}],
|
|
"actions":[{"account":"accountname1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}],
|
|
"max_net_usage_words":15,
|
|
"max_cpu_usage_ms":43,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
},
|
|
"transaction_arr": [{
|
|
"ref_block_num":"1",
|
|
"ref_block_prefix":"2",
|
|
"expiration":"2021-12-20T15:30",
|
|
"context_free_actions":[{"account":"contextfree1", "name":"cfactionname1", "authorization":[{"actor":"cfacc1","permission":"cfpermname1"}], "data":"778899"}],
|
|
"actions":[{"account":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}],
|
|
"max_net_usage_words":15,
|
|
"max_cpu_usage_ms":43,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
},{
|
|
"ref_block_num":"2",
|
|
"ref_block_prefix":"3",
|
|
"expiration":"2021-12-20T15:40",
|
|
"context_free_actions":[{"account":"contextfree1", "name":"cfactionname1", "authorization":[{"actor":"cfacc1","permission":"cfpermname1"}], "data":"778899"}],
|
|
"actions":[{"account":"acc2", "name":"actionname2", "authorization":[{"actor":"acc2","permission":"permname2"}], "data":""}],
|
|
"max_net_usage_words":21,
|
|
"max_cpu_usage_ms":87,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
}],
|
|
"strx": {
|
|
"ref_block_num":"1",
|
|
"ref_block_prefix":"2",
|
|
"expiration":"2021-12-20T15:30",
|
|
"region": "1",
|
|
"signatures" : ["SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5"],
|
|
"context_free_data" : ["abcdef","0123456789","ABCDEF0123456789abcdef"],
|
|
"context_free_actions":[{"account":"contextfree1", "name":"cfactionname1", "authorization":[{"actor":"cfacc1","permission":"cfpermname1"}], "data":"778899"}],
|
|
"actions":[{"account":"accountname1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}],
|
|
"max_net_usage_words":15,
|
|
"max_cpu_usage_ms":43,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
},
|
|
"strx_arr": [{
|
|
"ref_block_num":"1",
|
|
"ref_block_prefix":"2",
|
|
"expiration":"2021-12-20T15:30",
|
|
"region": "1",
|
|
"signatures" : ["SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5"],
|
|
"context_free_data" : ["abcdef","0123456789","ABCDEF0123456789abcdef"],
|
|
"context_free_actions":[{"account":"contextfree1", "name":"cfactionname1", "authorization":[{"actor":"cfacc1","permission":"cfpermname1"}], "data":"778899"}],
|
|
"actions":[{"account":"acc1", "name":"actionname1", "authorization":[{"actor":"acc1","permission":"permname1"}], "data":"445566"}],
|
|
"max_net_usage_words":15,
|
|
"max_cpu_usage_ms":43,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
},{
|
|
"ref_block_num":"2",
|
|
"ref_block_prefix":"3",
|
|
"expiration":"2021-12-20T15:40",
|
|
"region": "1",
|
|
"signatures" : ["SIG_K1_Jzdpi5RCzHLGsQbpGhndXBzcFs8vT5LHAtWLMxPzBdwRHSmJkcCdVu6oqPUQn1hbGUdErHvxtdSTS1YA73BThQFwV1v4G5"],
|
|
"context_free_data" : ["abcdef","0123456789","ABCDEF0123456789abcdef"],
|
|
"context_free_actions":[{"account":"contextfree2", "name":"cfactionname2", "authorization":[{"actor":"cfacc2","permission":"cfpermname2"}], "data":"667788"}],
|
|
"actions":[{"account":"acc2", "name":"actionname2", "authorization":[{"actor":"acc2","permission":"permname2"}], "data":""}],
|
|
"max_net_usage_words":15,
|
|
"max_cpu_usage_ms":43,
|
|
"delay_sec":0,
|
|
"transaction_extensions": []
|
|
}],
|
|
"keyweight": {"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"100"},
|
|
"keyweight_arr": [{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"100"},{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"200"}],
|
|
"authority": {
|
|
"threshold":"10",
|
|
"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":100},{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":200}],
|
|
"accounts":[{"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},{"permission":{"actor":"acc2","permission":"permname2"},"weight":"2"}],
|
|
"waits":[]
|
|
},
|
|
"authority_arr": [{
|
|
"threshold":"10",
|
|
"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"100"},{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"200"}],
|
|
"accounts":[{"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},{"permission":{"actor":"acc2","permission":"permname2"},"weight":"2"}],
|
|
"waits":[]
|
|
},{
|
|
"threshold":"10",
|
|
"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"100"},{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", "weight":"200"}],
|
|
"accounts":[{"permission":{"actor":"acc1","permission":"permname1"},"weight":"1"},{"permission":{"actor":"acc2","permission":"permname2"},"weight":"2"}],
|
|
"waits":[]
|
|
}],
|
|
"typedef" : {"new_type_name":"new", "type":"old"},
|
|
"typedef_arr": [{"new_type_name":"new", "type":"old"},{"new_type_name":"new", "type":"old"}],
|
|
"actiondef" : {"name":"actionname1", "type":"type1", "ricardian_contract":"ricardian1"},
|
|
"actiondef_arr" : [{"name":"actionname1", "type":"type1","ricardian_contract":"ricardian1"},{"name":"actionname2", "type":"type2","ricardian_contract":"ricardian2"}],
|
|
"tabledef": {"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"},
|
|
"tabledef_arr": [
|
|
{"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"},
|
|
{"name":"table2","index_type":"indextype2","key_names":["keyname2"],"key_types":["typename2"],"type":"type2"}
|
|
],
|
|
"abidef":{
|
|
"version": "eosio::abi/1.0",
|
|
"types" : [{"new_type_name":"new", "type":"old"}],
|
|
"structs" : [{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type": "type1"}, {"name":"name2", "type": "type2"}] }],
|
|
"actions" : [{"name":"action1","type":"type1", "ricardian_contract":""}],
|
|
"tables" : [{"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"}],
|
|
"ricardian_clauses": [],
|
|
"abi_extensions": []
|
|
},
|
|
"abidef_arr": [{
|
|
"version": "eosio::abi/1.0",
|
|
"types" : [{"new_type_name":"new", "type":"old"}],
|
|
"structs" : [{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type": "type1"}, {"name":"name2", "type": "type2"}] }],
|
|
"actions" : [{"name":"action1","type":"type1", "ricardian_contract":""}],
|
|
"tables" : [{"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"}],
|
|
"ricardian_clauses": [],
|
|
"abi_extensions": []
|
|
},{
|
|
"version": "eosio::abi/1.0",
|
|
"types" : [{"new_type_name":"new", "type":"old"}],
|
|
"structs" : [{"name":"struct1", "base":"base1", "fields": [{"name":"name1", "type": "type1"}, {"name":"name2", "type": "type2"}] }],
|
|
"actions" : [{"name":"action1","type":"type1", "ricardian_contract": ""}],
|
|
"tables" : [{"name":"table1","index_type":"indextype1","key_names":["keyname1"],"key_types":["typename1"],"type":"type1"}],
|
|
"ricardian_clauses": [],
|
|
"abi_extensions": []
|
|
}]
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(my_other);
|
|
verify_byte_round_trip_conversion(abi_serializer{std::move(abi), abi_serializer::create_yield_function( max_serialization_time )}, "A", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_cycle)
|
|
{ try {
|
|
|
|
const char* typedef_cycle_abi = R"=====(
|
|
{
|
|
"types": [{
|
|
"new_type_name": "A",
|
|
"type": "name"
|
|
},{
|
|
"new_type_name": "name",
|
|
"type": "A"
|
|
}],
|
|
"structs": [],
|
|
"actions": [],
|
|
"tables": [],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
const char* struct_cycle_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [],
|
|
"structs": [{
|
|
"name": "A",
|
|
"base": "B",
|
|
"fields": []
|
|
},{
|
|
"name": "B",
|
|
"base": "C",
|
|
"fields": []
|
|
},{
|
|
"name": "C",
|
|
"base": "A",
|
|
"fields": []
|
|
}],
|
|
"actions": [],
|
|
"tables": [],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(typedef_cycle_abi).as<abi_def>());
|
|
|
|
auto is_assert_exception = [](const auto& e) -> bool {
|
|
wlog(e.to_string()); return true;
|
|
};
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_type_def_exception, is_assert_exception);
|
|
|
|
abi = fc::json::from_string(struct_cycle_abi).as<abi_def>();
|
|
abi_serializer abis;
|
|
BOOST_CHECK_EXCEPTION( abis.set_abi(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), abi_circular_def_exception, is_assert_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(linkauth_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
BOOST_CHECK(true);
|
|
const char* test_data = R"=====(
|
|
{
|
|
"account" : "lnkauth.acct",
|
|
"code" : "lnkauth.code",
|
|
"type" : "lnkauth.type",
|
|
"requirement" : "lnkauth.rqm",
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto lauth = var.as<linkauth>();
|
|
BOOST_TEST(name("lnkauth.acct") == lauth.account);
|
|
BOOST_TEST(name("lnkauth.code") == lauth.code);
|
|
BOOST_TEST(name("lnkauth.type") == lauth.type);
|
|
BOOST_TEST(name("lnkauth.rqm") == lauth.requirement);
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "linkauth", var );
|
|
auto linkauth2 = var2.as<linkauth>();
|
|
BOOST_TEST(lauth.account == linkauth2.account);
|
|
BOOST_TEST(lauth.code == linkauth2.code);
|
|
BOOST_TEST(lauth.type == linkauth2.type);
|
|
BOOST_TEST(lauth.requirement == linkauth2.requirement);
|
|
|
|
verify_type_round_trip_conversion<linkauth>( abis, "linkauth", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(unlinkauth_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
BOOST_CHECK(true);
|
|
const char* test_data = R"=====(
|
|
{
|
|
"account" : "lnkauth.acct",
|
|
"code" : "lnkauth.code",
|
|
"type" : "lnkauth.type",
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto unlauth = var.as<unlinkauth>();
|
|
BOOST_TEST(name("lnkauth.acct") == unlauth.account);
|
|
BOOST_TEST(name("lnkauth.code") == unlauth.code);
|
|
BOOST_TEST(name("lnkauth.type") == unlauth.type);
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "unlinkauth", var );
|
|
auto unlinkauth2 = var2.as<unlinkauth>();
|
|
BOOST_TEST(unlauth.account == unlinkauth2.account);
|
|
BOOST_TEST(unlauth.code == unlinkauth2.code);
|
|
BOOST_TEST(unlauth.type == unlinkauth2.type);
|
|
|
|
verify_type_round_trip_conversion<unlinkauth>( abis, "unlinkauth", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(updateauth_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
BOOST_CHECK(true);
|
|
const char* test_data = R"=====(
|
|
{
|
|
"account" : "updauth.acct",
|
|
"permission" : "updauth.prm",
|
|
"parent" : "updauth.prnt",
|
|
"auth" : {
|
|
"threshold" : "2147483145",
|
|
"keys" : [ {"key" : "EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im", "weight" : 57005},
|
|
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
|
|
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
|
|
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 } ],
|
|
"waits" : []
|
|
}
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto updauth = var.as<updateauth>();
|
|
BOOST_TEST(name("updauth.acct") == updauth.account);
|
|
BOOST_TEST(name("updauth.prm") == updauth.permission);
|
|
BOOST_TEST(name("updauth.prnt") == updauth.parent);
|
|
BOOST_TEST(2147483145u == updauth.auth.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(2u == updauth.auth.keys.size());
|
|
BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == updauth.auth.keys[0].key.to_string({}));
|
|
BOOST_TEST(57005u == updauth.auth.keys[0].weight);
|
|
BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == updauth.auth.keys[1].key.to_string({}));
|
|
BOOST_TEST(57605u == updauth.auth.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(2u == updauth.auth.accounts.size());
|
|
BOOST_TEST(name("prm.acct1") == updauth.auth.accounts[0].permission.actor);
|
|
BOOST_TEST(name("prm.prm1") == updauth.auth.accounts[0].permission.permission);
|
|
BOOST_TEST(53005u == updauth.auth.accounts[0].weight);
|
|
BOOST_TEST(name("prm.acct2") == updauth.auth.accounts[1].permission.actor);
|
|
BOOST_TEST(name("prm.prm2") == updauth.auth.accounts[1].permission.permission);
|
|
BOOST_TEST(53405u == updauth.auth.accounts[1].weight);
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "updateauth", var );
|
|
auto updateauth2 = var2.as<updateauth>();
|
|
BOOST_TEST(updauth.account == updateauth2.account);
|
|
BOOST_TEST(updauth.permission == updateauth2.permission);
|
|
BOOST_TEST(updauth.parent == updateauth2.parent);
|
|
|
|
BOOST_TEST(updauth.auth.threshold == updateauth2.auth.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(updauth.auth.keys.size() == updateauth2.auth.keys.size());
|
|
BOOST_TEST(updauth.auth.keys[0].key == updateauth2.auth.keys[0].key);
|
|
BOOST_TEST(updauth.auth.keys[0].weight == updateauth2.auth.keys[0].weight);
|
|
BOOST_TEST(updauth.auth.keys[1].key == updateauth2.auth.keys[1].key);
|
|
BOOST_TEST(updauth.auth.keys[1].weight == updateauth2.auth.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(updauth.auth.accounts.size() == updateauth2.auth.accounts.size());
|
|
BOOST_TEST(updauth.auth.accounts[0].permission.actor == updateauth2.auth.accounts[0].permission.actor);
|
|
BOOST_TEST(updauth.auth.accounts[0].permission.permission == updateauth2.auth.accounts[0].permission.permission);
|
|
BOOST_TEST(updauth.auth.accounts[0].weight == updateauth2.auth.accounts[0].weight);
|
|
BOOST_TEST(updauth.auth.accounts[1].permission.actor == updateauth2.auth.accounts[1].permission.actor);
|
|
BOOST_TEST(updauth.auth.accounts[1].permission.permission == updateauth2.auth.accounts[1].permission.permission);
|
|
BOOST_TEST(updauth.auth.accounts[1].weight == updateauth2.auth.accounts[1].weight);
|
|
|
|
verify_type_round_trip_conversion<updateauth>( abis, "updateauth", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(deleteauth_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
BOOST_CHECK(true);
|
|
const char* test_data = R"=====(
|
|
{
|
|
"account" : "delauth.acct",
|
|
"permission" : "delauth.prm"
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto delauth = var.as<deleteauth>();
|
|
BOOST_TEST(name("delauth.acct") == delauth.account);
|
|
BOOST_TEST(name("delauth.prm") == delauth.permission);
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "deleteauth", var );
|
|
auto deleteauth2 = var2.as<deleteauth>();
|
|
BOOST_TEST(delauth.account == deleteauth2.account);
|
|
BOOST_TEST(delauth.permission == deleteauth2.permission);
|
|
|
|
verify_type_round_trip_conversion<deleteauth>( abis, "deleteauth", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(newaccount_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
BOOST_CHECK(true);
|
|
const char* test_data = R"=====(
|
|
{
|
|
"creator" : "newacct.crtr",
|
|
"name" : "newacct.name",
|
|
"owner" : {
|
|
"threshold" : 2147483145,
|
|
"keys" : [ {"key" : "EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im", "weight" : 57005},
|
|
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
|
|
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
|
|
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }],
|
|
"waits" : []
|
|
},
|
|
"active" : {
|
|
"threshold" : 2146483145,
|
|
"keys" : [ {"key" : "EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im", "weight" : 57005},
|
|
{"key" : "EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf", "weight" : 57605} ],
|
|
"accounts" : [ {"permission" : {"actor" : "prm.acct1", "permission" : "prm.prm1"}, "weight" : 53005 },
|
|
{"permission" : {"actor" : "prm.acct2", "permission" : "prm.prm2"}, "weight" : 53405 }],
|
|
"waits" : []
|
|
} }
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto newacct = var.as<newaccount>();
|
|
BOOST_TEST(name("newacct.crtr") == newacct.creator);
|
|
BOOST_TEST(name("newacct.name") == newacct.name);
|
|
|
|
BOOST_TEST(2147483145u == newacct.owner.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(2u == newacct.owner.keys.size());
|
|
BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == newacct.owner.keys[0].key.to_string({}));
|
|
BOOST_TEST(57005u == newacct.owner.keys[0].weight);
|
|
BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == newacct.owner.keys[1].key.to_string({}));
|
|
BOOST_TEST(57605u == newacct.owner.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(2u == newacct.owner.accounts.size());
|
|
BOOST_TEST(name("prm.acct1") == newacct.owner.accounts[0].permission.actor);
|
|
BOOST_TEST(name("prm.prm1") == newacct.owner.accounts[0].permission.permission);
|
|
BOOST_TEST(53005u == newacct.owner.accounts[0].weight);
|
|
BOOST_TEST(name("prm.acct2") == newacct.owner.accounts[1].permission.actor);
|
|
BOOST_TEST(name("prm.prm2") == newacct.owner.accounts[1].permission.permission);
|
|
BOOST_TEST(53405u == newacct.owner.accounts[1].weight);
|
|
|
|
BOOST_TEST(2146483145u == newacct.active.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(2u == newacct.active.keys.size());
|
|
BOOST_TEST("EOS65rXebLhtk2aTTzP4e9x1AQZs7c5NNXJp89W8R3HyaA6Zyd4im" == newacct.active.keys[0].key.to_string({}));
|
|
BOOST_TEST(57005u == newacct.active.keys[0].weight);
|
|
BOOST_TEST("EOS5eVr9TVnqwnUBNwf9kwMTbrHvX5aPyyEG97dz2b2TNeqWRzbJf" == newacct.active.keys[1].key.to_string({}));
|
|
BOOST_TEST(57605u == newacct.active.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(2u == newacct.active.accounts.size());
|
|
BOOST_TEST(name("prm.acct1") == newacct.active.accounts[0].permission.actor);
|
|
BOOST_TEST(name("prm.prm1") == newacct.active.accounts[0].permission.permission);
|
|
BOOST_TEST(53005u == newacct.active.accounts[0].weight);
|
|
BOOST_TEST(name("prm.acct2") == newacct.active.accounts[1].permission.actor);
|
|
BOOST_TEST(name("prm.prm2") == newacct.active.accounts[1].permission.permission);
|
|
BOOST_TEST(53405u == newacct.active.accounts[1].weight);
|
|
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "newaccount", var );
|
|
auto newaccount2 = var2.as<newaccount>();
|
|
BOOST_TEST(newacct.creator == newaccount2.creator);
|
|
BOOST_TEST(newacct.name == newaccount2.name);
|
|
|
|
BOOST_TEST(newacct.owner.threshold == newaccount2.owner.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(newacct.owner.keys.size() == newaccount2.owner.keys.size());
|
|
BOOST_TEST(newacct.owner.keys[0].key == newaccount2.owner.keys[0].key);
|
|
BOOST_TEST(newacct.owner.keys[0].weight == newaccount2.owner.keys[0].weight);
|
|
BOOST_TEST(newacct.owner.keys[1].key == newaccount2.owner.keys[1].key);
|
|
BOOST_TEST(newacct.owner.keys[1].weight == newaccount2.owner.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(newacct.owner.accounts.size() == newaccount2.owner.accounts.size());
|
|
BOOST_TEST(newacct.owner.accounts[0].permission.actor == newaccount2.owner.accounts[0].permission.actor);
|
|
BOOST_TEST(newacct.owner.accounts[0].permission.permission == newaccount2.owner.accounts[0].permission.permission);
|
|
BOOST_TEST(newacct.owner.accounts[0].weight == newaccount2.owner.accounts[0].weight);
|
|
BOOST_TEST(newacct.owner.accounts[1].permission.actor == newaccount2.owner.accounts[1].permission.actor);
|
|
BOOST_TEST(newacct.owner.accounts[1].permission.permission == newaccount2.owner.accounts[1].permission.permission);
|
|
BOOST_TEST(newacct.owner.accounts[1].weight == newaccount2.owner.accounts[1].weight);
|
|
|
|
BOOST_TEST(newacct.active.threshold == newaccount2.active.threshold);
|
|
|
|
BOOST_TEST_REQUIRE(newacct.active.keys.size() == newaccount2.active.keys.size());
|
|
BOOST_TEST(newacct.active.keys[0].key == newaccount2.active.keys[0].key);
|
|
BOOST_TEST(newacct.active.keys[0].weight == newaccount2.active.keys[0].weight);
|
|
BOOST_TEST(newacct.active.keys[1].key == newaccount2.active.keys[1].key);
|
|
BOOST_TEST(newacct.active.keys[1].weight == newaccount2.active.keys[1].weight);
|
|
|
|
BOOST_TEST_REQUIRE(newacct.active.accounts.size() == newaccount2.active.accounts.size());
|
|
BOOST_TEST(newacct.active.accounts[0].permission.actor == newaccount2.active.accounts[0].permission.actor);
|
|
BOOST_TEST(newacct.active.accounts[0].permission.permission == newaccount2.active.accounts[0].permission.permission);
|
|
BOOST_TEST(newacct.active.accounts[0].weight == newaccount2.active.accounts[0].weight);
|
|
BOOST_TEST(newacct.active.accounts[1].permission.actor == newaccount2.active.accounts[1].permission.actor);
|
|
BOOST_TEST(newacct.active.accounts[1].permission.permission == newaccount2.active.accounts[1].permission.permission);
|
|
BOOST_TEST(newacct.active.accounts[1].weight == newaccount2.active.accounts[1].weight);
|
|
|
|
|
|
verify_type_round_trip_conversion<newaccount>( abis, "newaccount", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(setcode_test)
|
|
{ try {
|
|
|
|
abi_serializer abis(eosio_contract_abi(abi_def()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
const char* test_data = R"=====(
|
|
{
|
|
"account" : "setcode.acc",
|
|
"vmtype" : "0",
|
|
"vmversion" : "0",
|
|
"code" : "0061736d0100000001390a60037e7e7f017f60047e7e7f7f017f60017e0060057e7e7e7f7f"
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
|
|
auto set_code = var.as<setcode>();
|
|
BOOST_TEST(name("setcode.acc") == set_code.account);
|
|
BOOST_TEST(0 == set_code.vmtype);
|
|
BOOST_TEST(0 == set_code.vmversion);
|
|
BOOST_TEST("0061736d0100000001390a60037e7e7f017f60047e7e7f7f017f60017e0060057e7e7e7f7f" == fc::to_hex(set_code.code.data(), set_code.code.size()));
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "setcode", var );
|
|
auto setcode2 = var2.as<setcode>();
|
|
BOOST_TEST(set_code.account == setcode2.account);
|
|
BOOST_TEST(set_code.vmtype == setcode2.vmtype);
|
|
BOOST_TEST(set_code.vmversion == setcode2.vmversion);
|
|
BOOST_TEST(set_code.code == setcode2.code);
|
|
|
|
verify_type_round_trip_conversion<setcode>( abis, "setcode", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(setabi_test)
|
|
{ try {
|
|
|
|
const char* abi_def_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "type_name",
|
|
"type": "string"
|
|
},{
|
|
"new_type_name": "field_name",
|
|
"type": "string"
|
|
}],
|
|
"structs": [{
|
|
"name": "abi_extension",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "type",
|
|
"type": "uint16"
|
|
},{
|
|
"name": "data",
|
|
"type": "bytes"
|
|
}]
|
|
},{
|
|
"name": "type_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "new_type_name",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "field_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "field_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "struct_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "base",
|
|
"type": "type_name"
|
|
}{
|
|
"name": "fields",
|
|
"type": "field_def[]"
|
|
}]
|
|
},{
|
|
"name": "action_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "action_name"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "ricardian_contract",
|
|
"type": "string"
|
|
}]
|
|
},{
|
|
"name": "table_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "name",
|
|
"type": "table_name"
|
|
},{
|
|
"name": "index_type",
|
|
"type": "type_name"
|
|
},{
|
|
"name": "key_names",
|
|
"type": "field_name[]"
|
|
},{
|
|
"name": "key_types",
|
|
"type": "type_name[]"
|
|
},{
|
|
"name": "type",
|
|
"type": "type_name"
|
|
}]
|
|
},{
|
|
"name": "clause_pair",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "id",
|
|
"type": "string"
|
|
},{
|
|
"name": "body",
|
|
"type": "string"
|
|
}]
|
|
},{
|
|
"name": "abi_def",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "version",
|
|
"type": "string"
|
|
},{
|
|
"name": "types",
|
|
"type": "type_def[]"
|
|
},{
|
|
"name": "structs",
|
|
"type": "struct_def[]"
|
|
},{
|
|
"name": "actions",
|
|
"type": "action_def[]"
|
|
},{
|
|
"name": "tables",
|
|
"type": "table_def[]"
|
|
},{
|
|
"name": "ricardian_clauses",
|
|
"type": "clause_pair[]"
|
|
},{
|
|
"name": "abi_extensions",
|
|
"type": "abi_extension[]"
|
|
}]
|
|
}],
|
|
"actions": [],
|
|
"tables": [],
|
|
"ricardian_clauses": [],
|
|
"abi_extensions": []
|
|
}
|
|
)=====";
|
|
|
|
auto v = fc::json::from_string(abi_def_abi);
|
|
|
|
abi_serializer abis(eosio_contract_abi(v.as<abi_def>()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
|
|
const char* abi_string = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "account_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer_base",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "memo",
|
|
"type": "string"
|
|
}]
|
|
},{
|
|
"name": "transfer",
|
|
"base": "transfer_base",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
},{
|
|
"name": "account",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "account",
|
|
"type": "name"
|
|
},{
|
|
"name": "balance",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": [{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
}
|
|
],
|
|
"ricardian_clauses": [],
|
|
"abi_extensions": []
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(abi_string);
|
|
auto abi = var.as<abi_def>();
|
|
|
|
BOOST_TEST_REQUIRE(1u == abi.types.size());
|
|
|
|
BOOST_TEST("account_name" == abi.types[0].new_type_name);
|
|
BOOST_TEST("name" == abi.types[0].type);
|
|
|
|
BOOST_TEST_REQUIRE(3u == abi.structs.size());
|
|
|
|
BOOST_TEST("transfer_base" == abi.structs[0].name);
|
|
BOOST_TEST("" == abi.structs[0].base);
|
|
BOOST_TEST_REQUIRE(1u == abi.structs[0].fields.size());
|
|
BOOST_TEST("memo" == abi.structs[0].fields[0].name);
|
|
BOOST_TEST("string" == abi.structs[0].fields[0].type);
|
|
|
|
BOOST_TEST("transfer" == abi.structs[1].name);
|
|
BOOST_TEST("transfer_base" == abi.structs[1].base);
|
|
BOOST_TEST_REQUIRE(3u == abi.structs[1].fields.size());
|
|
BOOST_TEST("from" == abi.structs[1].fields[0].name);
|
|
BOOST_TEST("account_name" == abi.structs[1].fields[0].type);
|
|
BOOST_TEST("to" == abi.structs[1].fields[1].name);
|
|
BOOST_TEST("account_name" == abi.structs[1].fields[1].type);
|
|
BOOST_TEST("amount" == abi.structs[1].fields[2].name);
|
|
BOOST_TEST("uint64" == abi.structs[1].fields[2].type);
|
|
|
|
BOOST_TEST("account" == abi.structs[2].name);
|
|
BOOST_TEST("" == abi.structs[2].base);
|
|
BOOST_TEST_REQUIRE(2u == abi.structs[2].fields.size());
|
|
BOOST_TEST("account" == abi.structs[2].fields[0].name);
|
|
BOOST_TEST("name" == abi.structs[2].fields[0].type);
|
|
BOOST_TEST("balance" == abi.structs[2].fields[1].name);
|
|
BOOST_TEST("uint64" == abi.structs[2].fields[1].type);
|
|
|
|
BOOST_TEST_REQUIRE(1u == abi.actions.size());
|
|
BOOST_TEST(name("transfer") == abi.actions[0].name);
|
|
BOOST_TEST("transfer" == abi.actions[0].type);
|
|
|
|
BOOST_TEST_REQUIRE(1u == abi.tables.size());
|
|
BOOST_TEST(name("account") == abi.tables[0].name);
|
|
BOOST_TEST("account" == abi.tables[0].type);
|
|
BOOST_TEST("i64" == abi.tables[0].index_type);
|
|
BOOST_TEST_REQUIRE(1u == abi.tables[0].key_names.size());
|
|
BOOST_TEST("account" == abi.tables[0].key_names[0]);
|
|
BOOST_TEST_REQUIRE(1u == abi.tables[0].key_types.size());
|
|
BOOST_TEST("name" == abi.tables[0].key_types[0]);
|
|
|
|
auto var2 = verify_byte_round_trip_conversion( abis, "abi_def", var );
|
|
auto abi2 = var2.as<abi_def>();
|
|
|
|
BOOST_TEST_REQUIRE(abi.types.size() == abi2.types.size());
|
|
|
|
BOOST_TEST(abi.types[0].new_type_name == abi2.types[0].new_type_name);
|
|
BOOST_TEST(abi.types[0].type == abi2.types[0].type);
|
|
|
|
BOOST_TEST_REQUIRE(abi.structs.size() == abi2.structs.size());
|
|
|
|
BOOST_TEST(abi.structs[0].name == abi2.structs[0].name);
|
|
BOOST_TEST(abi.structs[0].base == abi2.structs[0].base);
|
|
BOOST_TEST_REQUIRE(abi.structs[0].fields.size() == abi2.structs[0].fields.size());
|
|
BOOST_TEST(abi.structs[0].fields[0].name == abi2.structs[0].fields[0].name);
|
|
BOOST_TEST(abi.structs[0].fields[0].type == abi2.structs[0].fields[0].type);
|
|
|
|
BOOST_TEST(abi.structs[1].name == abi2.structs[1].name);
|
|
BOOST_TEST(abi.structs[1].base == abi2.structs[1].base);
|
|
BOOST_TEST_REQUIRE(abi.structs[1].fields.size() == abi2.structs[1].fields.size());
|
|
BOOST_TEST(abi.structs[1].fields[0].name == abi2.structs[1].fields[0].name);
|
|
BOOST_TEST(abi.structs[1].fields[0].type == abi2.structs[1].fields[0].type);
|
|
BOOST_TEST(abi.structs[1].fields[1].name == abi2.structs[1].fields[1].name);
|
|
BOOST_TEST(abi.structs[1].fields[1].type == abi2.structs[1].fields[1].type);
|
|
BOOST_TEST(abi.structs[1].fields[2].name == abi2.structs[1].fields[2].name);
|
|
BOOST_TEST(abi.structs[1].fields[2].type == abi2.structs[1].fields[2].type);
|
|
|
|
BOOST_TEST(abi.structs[2].name == abi2.structs[2].name);
|
|
BOOST_TEST(abi.structs[2].base == abi2.structs[2].base);
|
|
BOOST_TEST_REQUIRE(abi.structs[2].fields.size() == abi2.structs[2].fields.size());
|
|
BOOST_TEST(abi.structs[2].fields[0].name == abi2.structs[2].fields[0].name);
|
|
BOOST_TEST(abi.structs[2].fields[0].type == abi2.structs[2].fields[0].type);
|
|
BOOST_TEST(abi.structs[2].fields[1].name == abi2.structs[2].fields[1].name);
|
|
BOOST_TEST(abi.structs[2].fields[1].type == abi2.structs[2].fields[1].type);
|
|
|
|
BOOST_TEST_REQUIRE(abi.actions.size() == abi2.actions.size());
|
|
BOOST_TEST(abi.actions[0].name == abi2.actions[0].name);
|
|
BOOST_TEST(abi.actions[0].type == abi2.actions[0].type);
|
|
|
|
BOOST_TEST_REQUIRE(abi.tables.size() == abi2.tables.size());
|
|
BOOST_TEST(abi.tables[0].name == abi2.tables[0].name);
|
|
BOOST_TEST(abi.tables[0].type == abi2.tables[0].type);
|
|
BOOST_TEST(abi.tables[0].index_type == abi2.tables[0].index_type);
|
|
BOOST_TEST_REQUIRE(abi.tables[0].key_names.size() == abi2.tables[0].key_names.size());
|
|
BOOST_TEST(abi.tables[0].key_names[0] == abi2.tables[0].key_names[0]);
|
|
BOOST_TEST_REQUIRE(abi.tables[0].key_types.size() == abi2.tables[0].key_types.size());
|
|
BOOST_TEST(abi.tables[0].key_types[0] == abi2.tables[0].key_types[0]);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
|
|
|
|
|
|
struct action1 {
|
|
action1() = default;
|
|
action1(uint64_t b1, uint32_t b2, uint8_t b3) : blah1(b1), blah2(b2), blah3(b3) {}
|
|
uint64_t blah1;
|
|
uint32_t blah2;
|
|
uint8_t blah3;
|
|
static account_name get_account() { return "acount1"_n; }
|
|
static account_name get_name() { return "action1"_n; }
|
|
|
|
template<typename Stream>
|
|
friend Stream& operator<<( Stream& ds, const action1& act ) {
|
|
ds << act.blah1 << act.blah2 << act.blah3;
|
|
return ds;
|
|
}
|
|
|
|
template<typename Stream>
|
|
friend Stream& operator>>( Stream& ds, action1& act ) {
|
|
ds >> act.blah1 >> act.blah2 >> act.blah3;
|
|
return ds;
|
|
}
|
|
};
|
|
|
|
struct action2 {
|
|
action2() = default;
|
|
action2(uint32_t b1, uint64_t b2, uint8_t b3) : blah1(b1), blah2(b2), blah3(b3) {}
|
|
uint32_t blah1;
|
|
uint64_t blah2;
|
|
uint8_t blah3;
|
|
static account_name get_account() { return "acount2"_n; }
|
|
static account_name get_name() { return "action2"_n; }
|
|
|
|
template<typename Stream>
|
|
friend Stream& operator<<( Stream& ds, const action2& act ) {
|
|
ds << act.blah1 << act.blah2 << act.blah3;
|
|
return ds;
|
|
}
|
|
|
|
template<typename Stream>
|
|
friend Stream& operator>>( Stream& ds, action2& act ) {
|
|
ds >> act.blah1 >> act.blah2 >> act.blah3;
|
|
return ds;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
void verify_action_equal(const chain::action& exp, const chain::action& act)
|
|
{
|
|
BOOST_REQUIRE_EQUAL(exp.account.to_string(), act.account.to_string());
|
|
BOOST_REQUIRE_EQUAL(exp.name.to_string(), act.name.to_string());
|
|
BOOST_REQUIRE_EQUAL(exp.authorization.size(), act.authorization.size());
|
|
for(unsigned int i = 0; i < exp.authorization.size(); ++i)
|
|
{
|
|
BOOST_REQUIRE_EQUAL(exp.authorization[i].actor.to_string(), act.authorization[i].actor.to_string());
|
|
BOOST_REQUIRE_EQUAL(exp.authorization[i].permission.to_string(), act.authorization[i].permission.to_string());
|
|
}
|
|
BOOST_REQUIRE_EQUAL(exp.data.size(), act.data.size());
|
|
BOOST_REQUIRE(!memcmp(exp.data.data(), act.data.data(), exp.data.size()));
|
|
}
|
|
|
|
private_key_type get_private_key( name keyname, string role ) {
|
|
return private_key_type::regenerate<fc::ecc::private_key_shim>(fc::sha256::hash(keyname.to_string()+role));
|
|
}
|
|
|
|
public_key_type get_public_key( name keyname, string role ) {
|
|
return get_private_key( keyname, role ).get_public_key();
|
|
}
|
|
|
|
// This test causes the pack logic performed using the FC_REFLECT defined packing (because of
|
|
// packed_transaction::data), to be combined with the unpack logic performed using the abi_serializer,
|
|
// and thus the abi_def for non-built-in-types. This test will expose if any of the transaction and
|
|
// its sub-types have different packing/unpacking orders in FC_REFLECT vs. their abi_def
|
|
BOOST_AUTO_TEST_CASE(packed_transaction)
|
|
{ try {
|
|
|
|
chain::signed_transaction txn;
|
|
txn.ref_block_num = 1;
|
|
txn.ref_block_prefix = 2;
|
|
txn.expiration.from_iso_string("2021-12-20T15:30");
|
|
name a = "alice"_n;
|
|
txn.context_free_actions.emplace_back(
|
|
vector<permission_level>{{"testapi1"_n, config::active_name}},
|
|
newaccount{
|
|
.creator = config::system_account_name,
|
|
.name = a,
|
|
.owner = authority( get_public_key( a, "owner" )),
|
|
.active = authority( get_public_key( a, "active" ) )
|
|
});
|
|
txn.context_free_actions.emplace_back(
|
|
vector<permission_level>{{"testapi2"_n, config::active_name}},
|
|
action1{ 15, 23, (uint8_t)3});
|
|
txn.actions.emplace_back(
|
|
vector<permission_level>{{"testapi3"_n, config::active_name}},
|
|
action2{ 42, 67, (uint8_t)1});
|
|
txn.actions.emplace_back(
|
|
vector<permission_level>{{"testapi4"_n, config::active_name}},
|
|
action2{ 61, 23, (uint8_t)2});
|
|
txn.max_net_usage_words = 15;
|
|
txn.max_cpu_usage_ms = 43;
|
|
|
|
// pack the transaction to verify that the var unpacking logic is correct
|
|
auto packed_txn = chain::packed_transaction(txn);
|
|
|
|
const char* packed_transaction_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "compression_type",
|
|
"type": "int64"
|
|
}],
|
|
"structs": [{
|
|
"name": "packed_transaction",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "signatures",
|
|
"type": "signature[]"
|
|
},{
|
|
"name": "compression",
|
|
"type": "compression_type"
|
|
},{
|
|
"name": "data",
|
|
"type": "bytes"
|
|
}]
|
|
},{
|
|
"name": "action1",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "blah1",
|
|
"type": "uint64"
|
|
},{
|
|
"name": "blah2",
|
|
"type": "uint32"
|
|
},{
|
|
"name": "blah3",
|
|
"type": "uint8"
|
|
}]
|
|
},{
|
|
"name": "action2",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "blah1",
|
|
"type": "uint32"
|
|
},{
|
|
"name": "blah2",
|
|
"type": "uint64"
|
|
},{
|
|
"name": "blah3",
|
|
"type": "uint8"
|
|
}]
|
|
}]
|
|
"actions": [{
|
|
"name": "action1",
|
|
"type": "action1"
|
|
},{
|
|
"name": "action2",
|
|
"type": "action2"
|
|
}
|
|
],
|
|
"tables": [],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
fc::variant var;
|
|
abi_serializer::to_variant(packed_txn, var, get_resolver(fc::json::from_string(packed_transaction_abi).as<abi_def>()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
fc::variant var2;
|
|
abi_serializer::to_variant(packed_txn, var2, get_resolver(fc::json::from_string(packed_transaction_abi).as<abi_def>()), max_serialization_time);
|
|
|
|
chain::packed_transaction packed_txn2;
|
|
abi_serializer::from_variant(var, packed_txn2, get_resolver(fc::json::from_string(packed_transaction_abi).as<abi_def>()), abi_serializer::create_yield_function( max_serialization_time ));
|
|
chain::packed_transaction packed_txn3;
|
|
abi_serializer::from_variant(var2, packed_txn3, get_resolver(fc::json::from_string(packed_transaction_abi).as<abi_def>()), max_serialization_time);
|
|
|
|
const auto txn2 = packed_txn2.get_transaction();
|
|
const auto txn3 = packed_txn3.get_transaction();
|
|
|
|
BOOST_REQUIRE_EQUAL(txn.ref_block_num, txn2.ref_block_num);
|
|
BOOST_REQUIRE_EQUAL(txn.ref_block_prefix, txn2.ref_block_prefix);
|
|
BOOST_REQUIRE(txn.expiration == txn2.expiration);
|
|
BOOST_REQUIRE_EQUAL(txn.context_free_actions.size(), txn2.context_free_actions.size());
|
|
for (unsigned int i = 0; i < txn.context_free_actions.size(); ++i)
|
|
verify_action_equal<action1>(txn.context_free_actions[i], txn2.context_free_actions[i]);
|
|
BOOST_REQUIRE_EQUAL(txn.actions.size(), txn2.actions.size());
|
|
for (unsigned int i = 0; i < txn.actions.size(); ++i)
|
|
verify_action_equal<action2>(txn.actions[i], txn2.actions[i]);
|
|
BOOST_REQUIRE_EQUAL(txn.max_net_usage_words.value, txn2.max_net_usage_words.value);
|
|
BOOST_REQUIRE_EQUAL(txn.max_cpu_usage_ms, txn2.max_cpu_usage_ms);
|
|
|
|
BOOST_REQUIRE_EQUAL(txn.ref_block_num, txn3.ref_block_num);
|
|
BOOST_REQUIRE_EQUAL(txn.ref_block_prefix, txn3.ref_block_prefix);
|
|
BOOST_REQUIRE(txn.expiration == txn3.expiration);
|
|
BOOST_REQUIRE_EQUAL(txn.context_free_actions.size(), txn3.context_free_actions.size());
|
|
for (unsigned int i = 0; i < txn.context_free_actions.size(); ++i)
|
|
verify_action_equal<action1>(txn.context_free_actions[i], txn3.context_free_actions[i]);
|
|
BOOST_REQUIRE_EQUAL(txn.actions.size(), txn3.actions.size());
|
|
for (unsigned int i = 0; i < txn.actions.size(); ++i)
|
|
verify_action_equal<action2>(txn.actions[i], txn3.actions[i]);
|
|
BOOST_REQUIRE_EQUAL(txn.max_net_usage_words.value, txn3.max_net_usage_words.value);
|
|
BOOST_REQUIRE_EQUAL(txn.max_cpu_usage_ms, txn3.max_cpu_usage_ms);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_repeat)
|
|
{ try {
|
|
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "actor_name",
|
|
"type": "name"
|
|
},{
|
|
"new_type_name": "actor_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
},{
|
|
"name": "account",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "account",
|
|
"type": "name"
|
|
},{
|
|
"name": "balance",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer"
|
|
}
|
|
],
|
|
"tables": [{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
}
|
|
],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(repeat_abi).as<abi_def>());
|
|
auto is_table_exception = [](fc::exception const & e) -> bool { return e.to_detail_string().find("type already exists") != std::string::npos; };
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_type_def_exception, is_table_exception );
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_struct_repeat)
|
|
{ try {
|
|
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "actor_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
},{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "account",
|
|
"type": "name"
|
|
},{
|
|
"name": "balance",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer"
|
|
}
|
|
],
|
|
"tables": [{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
}
|
|
],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(repeat_abi).as<abi_def>());
|
|
BOOST_CHECK_THROW( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_struct_def_exception );
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_action_repeat)
|
|
{ try {
|
|
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "actor_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
},{
|
|
"name": "account",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "account",
|
|
"type": "name"
|
|
},{
|
|
"name": "balance",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer"
|
|
},{
|
|
"name": "transfer",
|
|
"type": "transfer"
|
|
}
|
|
],
|
|
"tables": [{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
}
|
|
],
|
|
"ricardian_clauses": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(repeat_abi).as<abi_def>());
|
|
BOOST_CHECK_THROW( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_action_def_exception );
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_table_repeat)
|
|
{ try {
|
|
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "actor_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "actor_name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
},{
|
|
"name": "account",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "account",
|
|
"type": "name"
|
|
},{
|
|
"name": "balance",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": [{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
},{
|
|
"name": "account",
|
|
"type": "account",
|
|
"index_type": "i64",
|
|
"key_names" : ["account"],
|
|
"key_types" : ["name"]
|
|
}
|
|
]
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(repeat_abi).as<abi_def>());
|
|
BOOST_CHECK_THROW( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_table_def_exception );
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_def)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "account_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
BOOST_CHECK(abis.is_type("name", abi_serializer::create_yield_function( max_serialization_time )));
|
|
BOOST_CHECK(abis.is_type("account_name", abi_serializer::create_yield_function( max_serialization_time )));
|
|
|
|
const char* test_data = R"=====(
|
|
{
|
|
"from" : "kevin",
|
|
"to" : "dan",
|
|
"amount" : 16
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "transfer", var);
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_loop)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "account_name",
|
|
"type": "name"
|
|
},{
|
|
"new_type_name": "name",
|
|
"type": "account_name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
auto is_type_exception = [](fc::exception const & e) -> bool { return e.to_detail_string().find("type already exists") != std::string::npos; };
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_type_def_exception, is_type_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_std_optional)
|
|
{ try {
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.2",
|
|
"types": [],
|
|
"structs": [
|
|
{
|
|
"name": "fees",
|
|
"base": "",
|
|
"fields": [
|
|
{
|
|
"name": "gas_price",
|
|
"type": "uint64?"
|
|
},
|
|
{
|
|
"name": "miner_cut",
|
|
"type": "uint32?"
|
|
},
|
|
{
|
|
"name": "bridge_fee",
|
|
"type": "uint32?"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"actions": [
|
|
{
|
|
"name": "fees",
|
|
"type": "fees",
|
|
"ricardian_contract": ""
|
|
}
|
|
],
|
|
"tables": [],
|
|
"ricardian_clauses": [],
|
|
"variants": [],
|
|
"action_results": []
|
|
}
|
|
)=====";
|
|
|
|
abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
{
|
|
// check conversion when all optional members are provided
|
|
std::string test_data = R"=====(
|
|
{
|
|
"gas_price" : "42",
|
|
"miner_cut" : "2",
|
|
"bridge_fee" : "2"
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "fees", var);
|
|
}
|
|
|
|
{
|
|
// check conversion when the first optional member is missing
|
|
std::string test_data = R"=====(
|
|
{
|
|
"miner_cut" : "2",
|
|
"bridge_fee" : "2"
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "fees", var);
|
|
}
|
|
|
|
{
|
|
// check conversion when the second optional member is missing
|
|
std::string test_data = R"=====(
|
|
{
|
|
"gas_price" : "42",
|
|
"bridge_fee" : "2"
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "fees", var);
|
|
}
|
|
|
|
{
|
|
// check conversion when the last optional member is missing
|
|
std::string test_data = R"=====(
|
|
{
|
|
"gas_price" : "42",
|
|
"miner_cut" : "2",
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "fees", var);
|
|
}
|
|
|
|
{
|
|
// check conversion when all optional members are missing
|
|
std::string test_data = R"=====(
|
|
{
|
|
}
|
|
)=====";
|
|
|
|
auto var = fc::json::from_string(test_data);
|
|
verify_byte_round_trip_conversion(abis, "fees", var);
|
|
}
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_redefine)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "account_name",
|
|
"type": "account_name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
auto is_type_exception = [](fc::exception const & e) -> bool { return e.to_detail_string().find("Circular reference in type account_name") != std::string::npos; };
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), abi_circular_def_exception, is_type_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_redefine_to_name)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [],
|
|
"actions": [],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
auto is_type_exception = [](fc::exception const & e) -> bool { return e.to_detail_string().find("type already exists") != std::string::npos; };
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), duplicate_abi_type_def_exception, is_type_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_type_nested_in_vector)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [],
|
|
"structs": [{
|
|
"name": "store_t",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "id",
|
|
"type": "uint64"
|
|
},{
|
|
"name": "childs",
|
|
"type": "store_t[]"
|
|
}],
|
|
"actions": [],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
BOOST_CHECK_THROW( abi_serializer abis(fc::json::from_string(repeat_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), parse_error_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_account_name_in_eosio_abi)
|
|
{ try {
|
|
// inifinite loop in types
|
|
const char* repeat_abi = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [{
|
|
"new_type_name": "account_name",
|
|
"type": "name"
|
|
}
|
|
],
|
|
"structs": [{
|
|
"name": "transfer",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "from",
|
|
"type": "account_name"
|
|
},{
|
|
"name": "to",
|
|
"type": "name"
|
|
},{
|
|
"name": "amount",
|
|
"type": "uint64"
|
|
}]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "transfer",
|
|
"type": "transfer",
|
|
"ricardian_contract": "transfer contract"
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
auto abi = eosio_contract_abi(fc::json::from_string(repeat_abi).as<abi_def>());
|
|
auto is_type_exception = [](fc::assert_exception const & e) -> bool { return e.to_detail_string().find("type already exists") != std::string::npos; };
|
|
BOOST_CHECK_EXCEPTION( abi_serializer abis(std::move(abi), abi_serializer::create_yield_function(max_serialization_time )), duplicate_abi_type_def_exception, is_type_exception );
|
|
|
|
} FC_LOG_AND_RETHROW() }
|
|
|
|
|
|
// Unlimited array size during abi serialization can exhaust memory and crash the process
|
|
BOOST_AUTO_TEST_CASE(abi_large_array)
|
|
{
|
|
try {
|
|
const char* abi_str = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [],
|
|
"structs": [{
|
|
"name": "hi",
|
|
"base": "",
|
|
"fields": [
|
|
]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "hi",
|
|
"type": "hi[]",
|
|
"ricardian_contract": ""
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
abi_serializer abis( fc::json::from_string( abi_str ).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
// indicate a very large array, but don't actually provide a large array
|
|
bytes bin = {static_cast<char>(0xff),
|
|
static_cast<char>(0xff),
|
|
static_cast<char>(0xff),
|
|
static_cast<char>(0xff),
|
|
static_cast<char>(0x08)};
|
|
BOOST_CHECK_THROW( abis.binary_to_variant( "hi[]", bin, abi_serializer::create_yield_function( max_serialization_time ) );, fc::exception );
|
|
BOOST_CHECK_THROW( abis.binary_to_variant( "hi[]", bin, max_serialization_time );, fc::exception );
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// Infinite recursion of abi_serializer is_type
|
|
BOOST_AUTO_TEST_CASE(abi_is_type_recursion)
|
|
{
|
|
try {
|
|
const char* abi_str = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [
|
|
{
|
|
"new_type_name": "a[]",
|
|
"type": "a[][]",
|
|
},
|
|
],
|
|
"structs": [
|
|
{
|
|
"name": "a[]",
|
|
"base": "",
|
|
"fields": []
|
|
},
|
|
{
|
|
"name": "hi",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "user",
|
|
"type": "name"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "hi",
|
|
"type": "hi",
|
|
"ricardian_contract": ""
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
BOOST_CHECK_THROW( abi_serializer abis(fc::json::from_string(abi_str).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), fc::exception );
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// Infinite recursion of abi_serializer in struct definitions
|
|
BOOST_AUTO_TEST_CASE(abi_recursive_structs)
|
|
{
|
|
try {
|
|
const char* abi_str = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.0",
|
|
"types": [],
|
|
"structs": [
|
|
{
|
|
"name": "a"
|
|
"base": "",
|
|
"fields": [
|
|
{
|
|
"name": "user",
|
|
"type": "b"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "b"
|
|
"base": "",
|
|
"fields": [
|
|
{
|
|
"name": "user",
|
|
"type": "a"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "hi",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "user",
|
|
"type": "name"
|
|
},
|
|
{
|
|
"name": "arg2",
|
|
"type": "a"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"name": "hi2",
|
|
"base": "",
|
|
"fields": [{
|
|
"name": "user",
|
|
"type": "name"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"actions": [{
|
|
"name": "hi",
|
|
"type": "hi",
|
|
"ricardian_contract": ""
|
|
}
|
|
],
|
|
"tables": []
|
|
}
|
|
)=====";
|
|
|
|
abi_serializer abis(fc::json::from_string(abi_str).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
string hi_data = "{\"user\":\"eosio\"}";
|
|
auto bin = abis.variant_to_binary("hi2", fc::json::from_string(hi_data), abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto bin2 = abis.variant_to_binary("hi2", fc::json::from_string(hi_data), max_serialization_time);
|
|
BOOST_CHECK_THROW( abis.binary_to_variant("hi", bin, abi_serializer::create_yield_function( max_serialization_time ));, fc::exception );
|
|
BOOST_CHECK_THROW( abis.binary_to_variant("hi", bin2, max_serialization_time);, fc::exception );
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// Infinite recursion of abi_serializer in struct definitions
|
|
BOOST_AUTO_TEST_CASE(abi_very_deep_structs)
|
|
{
|
|
try {
|
|
abi_serializer abis( fc::json::from_string( large_nested_abi ).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
string hi_data = "{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":{\"f1\":0}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}";
|
|
BOOST_CHECK_THROW( abis.variant_to_binary( "s98", fc::json::from_string( hi_data ), abi_serializer::create_yield_function( max_serialization_time ) ), fc::exception );
|
|
BOOST_CHECK_THROW( abis.variant_to_binary( "s98", fc::json::from_string( hi_data ), max_serialization_time ), fc::exception );
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// Infinite recursion of abi_serializer in struct definitions
|
|
BOOST_AUTO_TEST_CASE(abi_very_deep_structs_1us)
|
|
{
|
|
try {
|
|
BOOST_CHECK_THROW(
|
|
abi_serializer abis( fc::json::from_string( large_nested_abi ).as<abi_def>(), abi_serializer::create_yield_function( fc::microseconds( 1 ) ) ),
|
|
fc::exception );
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_deep_structs_validate)
|
|
{
|
|
try {
|
|
BOOST_CHECK_THROW(
|
|
abi_serializer abis( fc::json::from_string( deep_nested_abi ).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) ),
|
|
fc::exception );
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// Large signature
|
|
BOOST_AUTO_TEST_CASE(abi_large_signature)
|
|
{
|
|
try {
|
|
const char* abi_str = R"=====(
|
|
{
|
|
"version": "eosio::abi/1.1",
|
|
"types": [],
|
|
"structs": [
|
|
{
|
|
"name": "act",
|
|
"base": "",
|
|
"fields": [
|
|
{
|
|
"name": "sig",
|
|
"type": "signature"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"actions": [
|
|
{
|
|
"name": "act",
|
|
"type": "act",
|
|
"ricardian_contract": ""
|
|
}
|
|
],
|
|
"tables": [],
|
|
"ricardian_clauses": [],
|
|
"variants": []
|
|
}
|
|
)=====";
|
|
|
|
std::string big_json(1 << 18, 'a');
|
|
signature_type::storage_type webauth_sig = fc::crypto::webauthn::signature(fc::crypto::r1::compact_signature(), {}, big_json);
|
|
signature_type sig;
|
|
|
|
// signature( storage_type&& other_storage ) is private, pack/unpack as a way to convert from webauthn sig
|
|
auto size = big_json.size() + 1024;
|
|
std::vector<char> buff( size );
|
|
datastream<char*> ds(&buff[0], size);
|
|
fc::raw::pack(ds, webauth_sig);
|
|
ds.seekp(0);
|
|
fc::raw::unpack(ds, sig);
|
|
|
|
name a = "hello"_n;
|
|
authority owner_auth = authority( get_public_key( a, "owner" ) );
|
|
chain::action large_act( vector<permission_level>{{config::system_account_name,config::active_name}},
|
|
act_sig{
|
|
.sig = sig
|
|
});
|
|
|
|
{
|
|
fc::variant var;
|
|
auto start = fc::time_point::now();
|
|
bool check_data = true;
|
|
try {
|
|
abi_serializer::to_variant( large_act, var, get_resolver( fc::json::from_string( abi_str ).as<abi_def>() ),
|
|
abi_serializer::create_yield_function( fc::milliseconds( 1 ) ) );
|
|
} catch( abi_serialization_deadline_exception& ) {
|
|
// can be thrown if check_deadline is tripped after deadline in to_base58 is tripped
|
|
check_data = false;
|
|
}
|
|
auto stop = fc::time_point::now();
|
|
// Give it a leaway of 50ms
|
|
BOOST_CHECK_LE( (stop - start).count(), 51 * 1000 );
|
|
if( check_data ) {
|
|
BOOST_CHECK( var.get_object().contains( "data" ) );
|
|
BOOST_CHECK( var.get_object().contains( "hex_data" ) );
|
|
}
|
|
}
|
|
{
|
|
fc::variant var;
|
|
auto start = fc::time_point::now();
|
|
abi_serializer::to_variant( large_act, var, get_resolver( fc::json::from_string( abi_str ).as<abi_def>() ), fc::milliseconds(1) );
|
|
auto stop = fc::time_point::now();
|
|
// Give it a leaway of 50ms
|
|
BOOST_CHECK_LE( (stop - start).count(), 51 * 1000 );
|
|
BOOST_CHECK( var.get_object().contains( "data" ) );
|
|
BOOST_CHECK( var.get_object().contains( "hex_data" ) );
|
|
}
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(variants)
|
|
{
|
|
using eosio::testing::fc_exception_message_starts_with;
|
|
|
|
auto duplicate_variant_abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"variants": [
|
|
{"name": "v1", "types": ["int8", "string", "bool"]},
|
|
{"name": "v1", "types": ["int8", "string", "bool"]},
|
|
],
|
|
})";
|
|
|
|
auto variant_abi_invalid_type = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"variants": [
|
|
{"name": "v1", "types": ["int91", "string", "bool"]},
|
|
],
|
|
})";
|
|
|
|
auto variant_abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{"new_type_name": "foo", "type": "s"},
|
|
{"new_type_name": "bar", "type": "s"},
|
|
],
|
|
"structs": [
|
|
{"name": "s", "base": "", "fields": [
|
|
{"name": "i0", "type": "int8"},
|
|
{"name": "i1", "type": "int8"},
|
|
]}
|
|
],
|
|
"variants": [
|
|
{"name": "v1", "types": ["int8", "string", "int16"]},
|
|
{"name": "v2", "types": ["foo", "bar"]},
|
|
],
|
|
})";
|
|
|
|
try {
|
|
// round-trip abi through multiple formats
|
|
// json -> variant -> abi_def -> bin
|
|
auto bin = fc::raw::pack(fc::json::from_string(variant_abi).as<abi_def>());
|
|
// bin -> abi_def -> variant -> abi_def
|
|
abi_serializer abis(fc::variant(fc::raw::unpack<abi_def>(bin)).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
// duplicate variant definition detected
|
|
BOOST_CHECK_THROW( abi_serializer( fc::json::from_string(duplicate_variant_abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) ), duplicate_abi_variant_def_exception );
|
|
|
|
// invalid_type_inside_abi
|
|
BOOST_CHECK_THROW( abi_serializer( fc::json::from_string(variant_abi_invalid_type).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) ), invalid_type_inside_abi );
|
|
|
|
// expected array containing variant
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(9)"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"([4])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"([4, 5])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Encountered non-string as first item of input array while processing variant 'v1") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["4", 5, 6])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(9)"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"([4])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"([4, 5])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Encountered non-string as first item of input array while processing variant 'v1") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["4", 5, 6])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Expected input to be an array of two items while processing variant 'v1'") );
|
|
|
|
// type is not valid within this variant
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["int9", 21])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Specified type 'int9' in input array is not valid within the variant 'v1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["int9", 21])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Specified type 'int9' in input array is not valid within the variant 'v1'") );
|
|
|
|
verify_round_trip_conversion(abis, "v1", R"(["int8",21])", "0015");
|
|
verify_round_trip_conversion(abis, "v1", R"(["string","abcd"])", "010461626364");
|
|
verify_round_trip_conversion(abis, "v1", R"(["int16",3])", "020300");
|
|
verify_round_trip_conversion(abis, "v1", R"(["int16",4])", "020400");
|
|
verify_round_trip_conversion(abis, "v2", R"(["foo",{"i0":5,"i1":6}])", "000506");
|
|
verify_round_trip_conversion(abis, "v2", R"(["bar",{"i0":5,"i1":6}])", "010506");
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(aliased_variants)
|
|
{
|
|
using eosio::testing::fc_exception_message_starts_with;
|
|
|
|
auto aliased_variant = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{ "new_type_name": "foo", "type": "foo_variant" }
|
|
],
|
|
"variants": [
|
|
{"name": "foo_variant", "types": ["int8", "string"]}
|
|
],
|
|
})";
|
|
|
|
try {
|
|
// round-trip abi through multiple formats
|
|
// json -> variant -> abi_def -> bin
|
|
auto bin = fc::raw::pack(fc::json::from_string(aliased_variant).as<abi_def>());
|
|
// bin -> abi_def -> variant -> abi_def
|
|
abi_serializer abis(fc::variant(fc::raw::unpack<abi_def>(bin)).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
verify_round_trip_conversion(abis, "foo", R"(["int8",21])", "0015");
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(variant_of_aliases)
|
|
{
|
|
using eosio::testing::fc_exception_message_starts_with;
|
|
|
|
auto aliased_variant = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{ "new_type_name": "foo_0", "type": "int8" },
|
|
{ "new_type_name": "foo_1", "type": "string" }
|
|
],
|
|
"variants": [
|
|
{"name": "foo", "types": ["foo_0", "foo_1"]}
|
|
],
|
|
})";
|
|
|
|
try {
|
|
// round-trip abi through multiple formats
|
|
// json -> variant -> abi_def -> bin
|
|
auto bin = fc::raw::pack(fc::json::from_string(aliased_variant).as<abi_def>());
|
|
// bin -> abi_def -> variant -> abi_def
|
|
abi_serializer abis(fc::variant(fc::raw::unpack<abi_def>(bin)).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
verify_round_trip_conversion(abis, "foo", R"(["foo_0",21])", "0015");
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(extend)
|
|
{
|
|
using eosio::testing::fc_exception_message_starts_with;
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"structs": [
|
|
{"name": "s", "base": "", "fields": [
|
|
{"name": "i0", "type": "int8"},
|
|
{"name": "i1", "type": "int8"},
|
|
{"name": "i2", "type": "int8$"},
|
|
{"name": "a", "type": "int8[]$"},
|
|
{"name": "o", "type": "int8?$"},
|
|
]},
|
|
{"name": "s2", "base": "", "fields": [
|
|
{"name": "i0", "type": "int8"},
|
|
{"name": "i1", "type": "int8$"},
|
|
{"name": "i2", "type": "int8"},
|
|
]}
|
|
],
|
|
})";
|
|
// NOTE: Ideally this ABI would be rejected during validation for an improper definition for struct "s2".
|
|
// Such a check is not yet implemented during validation, but it can check during serialization.
|
|
|
|
try {
|
|
abi_serializer abis(fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
// missing i1
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"({"i0":5})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Missing field 'i1' in input object while processing struct") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"({"i0":5})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Missing field 'i1' in input object while processing struct") );
|
|
|
|
// Unexpected 'a'
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"({"i0":5,"i1":6,"a":[8,9,10]})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Unexpected field 'a' found in input object while processing struct") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"({"i0":5,"i1":6,"a":[8,9,10]})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Unexpected field 'a' found in input object while processing struct") );
|
|
|
|
verify_round_trip_conversion(abis, "s", R"({"i0":5,"i1":6})", "0506");
|
|
verify_round_trip_conversion(abis, "s", R"({"i0":5,"i1":6,"i2":7})", "050607");
|
|
verify_round_trip_conversion(abis, "s", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10]})", "0506070308090a");
|
|
verify_round_trip_conversion(abis, "s", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10],"o":null})", "0506070308090a00");
|
|
verify_round_trip_conversion(abis, "s", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10],"o":31})", "0506070308090a011f");
|
|
|
|
verify_round_trip_conversion(abis, "s", R"([5,6])", "0506", R"({"i0":5,"i1":6})");
|
|
verify_round_trip_conversion(abis, "s", R"([5,6,7])", "050607", R"({"i0":5,"i1":6,"i2":7})");
|
|
verify_round_trip_conversion(abis, "s", R"([5,6,7,[8,9,10]])", "0506070308090a", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10]})");
|
|
verify_round_trip_conversion(abis, "s", R"([5,6,7,[8,9,10],null])", "0506070308090a00", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10],"o":null})");
|
|
verify_round_trip_conversion(abis, "s", R"([5,6,7,[8,9,10],31])", "0506070308090a011f", R"({"i0":5,"i1":6,"i2":7,"a":[8,9,10],"o":31})");
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"i0":1})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
abi_exception, fc_exception_message_starts_with("Encountered field 'i2' without binary extension designation while processing struct") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"i0":1})"), max_serialization_time),
|
|
abi_exception, fc_exception_message_starts_with("Encountered field 'i2' without binary extension designation while processing struct") );
|
|
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(version)
|
|
{
|
|
try {
|
|
BOOST_CHECK_THROW( abi_serializer(fc::json::from_string(R"({})").as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), unsupported_abi_version_exception );
|
|
BOOST_CHECK_THROW( abi_serializer(fc::json::from_string(R"({"version": ""})").as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), unsupported_abi_version_exception );
|
|
BOOST_CHECK_THROW( abi_serializer(fc::json::from_string(R"({"version": "eosio::abi/9.0"})").as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time )), unsupported_abi_version_exception );
|
|
abi_serializer(fc::json::from_string(R"({"version": "eosio::abi/1.0"})").as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
abi_serializer(fc::json::from_string(R"({"version": "eosio::abi/1.1"})").as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ));
|
|
} 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>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"([])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Early end to input array specifying the fields of struct") );
|
|
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 input array specifying the fields of struct") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s", fc::json::from_string(R"([1,2])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Early end to input 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 input 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_starts_with;
|
|
|
|
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>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Missing field 'f0' in input object") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_starts_with("Missing field 'f0' in input object") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"f0":{"i0":1}})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_starts_with("Missing field 'i1' in input 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_starts_with("Missing field 'i1' in input 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>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2", fc::json::from_string(R"({"f0":1,"i1":2})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Unexpected input encountered while processing struct 's2.f0'") );
|
|
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("Unexpected input encountered while processing struct 's2.f0'") );
|
|
|
|
verify_round_trip_conversion(abis, "s2", R"({"f0":{"i0":1},"i1":2})", "0102");
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
// it is a bit odd to have an empty name for a field, but json seems to allow it
|
|
BOOST_AUTO_TEST_CASE(abi_serialize_json_empty_name)
|
|
{
|
|
using eosio::testing::fc_exception_message_is;
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.0",
|
|
"structs": [
|
|
{"name": "s1", "base": "", "fields": [
|
|
{"name": "", "type": "int8"},
|
|
]}
|
|
],
|
|
})";
|
|
|
|
try {
|
|
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
auto bin1 = abis.variant_to_binary("s1", fc::json::from_string(R"({"":1})"), abi_serializer::create_yield_function( max_serialization_time ));
|
|
auto bin2 = abis.variant_to_binary("s1", fc::json::from_string(R"({"":1})"), max_serialization_time);
|
|
|
|
verify_round_trip_conversion(abis, "s1", R"({"":1})", "01");
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_serialize_detailed_error_messages)
|
|
{
|
|
using eosio::testing::fc_exception_message_is;
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{"new_type_name": "foo", "type": "s2"},
|
|
{"new_type_name": "bar", "type": "foo"},
|
|
{"new_type_name": "s1array", "type": "s1[]"},
|
|
{"new_type_name": "s1arrayarray", "type": "s1array[]"}
|
|
],
|
|
"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"}
|
|
]},
|
|
{"name": "s3", "base": "s1", "fields": [
|
|
{"name": "i2", "type": "int8"},
|
|
{"name": "f3", "type": "v2"},
|
|
{"name": "f4", "type": "foo$"},
|
|
{"name": "f5", "type": "s1$"}
|
|
]},
|
|
{"name": "s4", "base": "", "fields": [
|
|
{"name": "f0", "type": "int8[]"},
|
|
{"name": "f1", "type": "s1[]"}
|
|
]},
|
|
{"name": "s5", "base": "", "fields": [
|
|
{"name": "f0", "type": "v2[]"},
|
|
]},
|
|
],
|
|
"variants": [
|
|
{"name": "v1", "types": ["s3", "int8", "s4"]},
|
|
{"name": "v2", "types": ["foo", "bar"]},
|
|
],
|
|
})";
|
|
|
|
try {
|
|
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("bar", fc::json::from_string(R"({"f0":{"i0":1},"i2":3})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's2.f0'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("bar", fc::json::from_string(R"({"f0":{"i0":1},"i2":3})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's2.f0'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i2":3})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i2":3})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["s2",{}]})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Specified type 's2' in input array is not valid within the variant 's3.f3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["s2",{}]})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Specified type 's2' in input array is not valid within the variant 's3.f3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11},"i2":13}]})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's3.f3.<variant(1)=bar>.f0'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s3", fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11},"i2":13}]})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's3.f3.<variant(1)=bar>.f0'") );
|
|
|
|
verify_round_trip_conversion(abis, "s3", R"({"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11,"i1":12},"i2":13}]})", "010203010b0c0d");
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s3",{"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11,"i1":12},"i2":13}],"f5":0}])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Unexpected field 'f5' found in input object while processing struct 'v1.<variant(0)=s3>'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s3",{"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11,"i1":12},"i2":13}],"f5":0}])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Unexpected field 'f5' found in input object while processing struct 'v1.<variant(0)=s3>'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s4",{"f0":[0,1],"f1":[{"i0":2,"i1":3},{"i1":5}]}])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 'v1.<variant(2)=s4>.f1[1]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s4",{"f0":[0,1],"f1":[{"i0":2,"i1":3},{"i1":5}]}])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 'v1.<variant(2)=s4>.f1[1]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2[]", fc::json::from_string(R"([{"f0":{"i0":1,"i1":2},"i2":3},{"f0":{"i0":4},"i2":6}])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 'ARRAY[1].f0'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2[]", fc::json::from_string(R"([{"f0":{"i0":1,"i1":2},"i2":3},{"f0":{"i0":4},"i2":6}])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 'ARRAY[1].f0'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s5", fc::json::from_string(R"({"f0":[["bar",{"f0":{"i0":1,"i1":2},"i2":3}],["foo",{"f0":{"i0":4},"i2":6}]]})"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's5.f0[1].<variant(0)=foo>.f0'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s5", fc::json::from_string(R"({"f0":[["bar",{"f0":{"i0":1,"i1":2},"i2":3}],["foo",{"f0":{"i0":4},"i2":6}]]})"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's5.f0[1].<variant(0)=foo>.f0'") );
|
|
|
|
verify_round_trip_conversion( abis, "s1arrayarray", R"([[{"i0":1,"i1":2},{"i0":3,"i1":4}],[{"i0":5,"i1":6},{"i0":7,"i1":8},{"i0":9,"i1":10}]])", "0202010203040305060708090a");
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s1arrayarray", fc::json::from_string(R"([[{"i0":1,"i1":2},{"i0":3,"i1":4}],[{"i0":6,"i1":6},{"i0":7,"i1":8},{"i1":10}]])"), abi_serializer::create_yield_function( max_serialization_time )),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 'ARRAY[1][2]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s1arrayarray", fc::json::from_string(R"([[{"i0":1,"i1":2},{"i0":3,"i1":4}],[{"i0":6,"i1":6},{"i0":7,"i1":8},{"i1":10}]])"), max_serialization_time),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 'ARRAY[1][2]'") );
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_serialize_short_error_messages)
|
|
{
|
|
using eosio::testing::fc_exception_message_is;
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{"new_type_name": "foo", "type": "s2"},
|
|
{"new_type_name": "bar", "type": "foo"},
|
|
{"new_type_name": "s1array", "type": "s1[]"},
|
|
{"new_type_name": "s1arrayarray", "type": "s1array[]"}
|
|
],
|
|
"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"}
|
|
]},
|
|
{"name": "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3", "base": "s1", "fields": [
|
|
{"name": "i2", "type": "int8"},
|
|
{"name": "f3", "type": "v2"},
|
|
{"name": "f4", "type": "foo$"},
|
|
{"name": "very_very_very_very_very_very_very_very_very_very_long_field_name_f5", "type": "s1$"}
|
|
]},
|
|
{"name": "s4", "base": "", "fields": [
|
|
{"name": "f0", "type": "int8[]"},
|
|
{"name": "f1", "type": "s1[]"}
|
|
]},
|
|
{"name": "s5", "base": "", "fields": [
|
|
{"name": "f0", "type": "v2[]"},
|
|
]},
|
|
],
|
|
"variants": [
|
|
{"name": "v1", "types": ["very_very_very_very_very_very_very_very_very_very_long_struct_name_s3", "int8", "s4"]},
|
|
{"name": "v2", "types": ["foo", "bar"]},
|
|
],
|
|
})";
|
|
|
|
try {
|
|
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("bar", fc::json::from_string(R"({"f0":{"i0":1},"i2":3})"), abi_serializer::create_yield_function( max_serialization_time ), true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("bar", fc::json::from_string(R"({"f0":{"i0":1},"i2":3})"), max_serialization_time, true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i2":3})"), abi_serializer::create_yield_function( max_serialization_time ), true ),
|
|
pack_exception,
|
|
fc_exception_message_is("Missing field 'i1' in input object while processing struct 'very_very_very_very_very_very_very_very_very_very_long_...ame_s3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i2":3})"), max_serialization_time, true ),
|
|
pack_exception,
|
|
fc_exception_message_is("Missing field 'i1' in input object while processing struct 'very_very_very_very_very_very_very_very_very_very_long_...ame_s3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["s2",{}]})"), abi_serializer::create_yield_function( max_serialization_time ), true ),
|
|
pack_exception, fc_exception_message_is("Specified type 's2' in input array is not valid within the variant 'v2'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["s2",{}]})"), max_serialization_time, true ),
|
|
pack_exception, fc_exception_message_is("Specified type 's2' in input array is not valid within the variant 'v2'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11},"i2":13}]})"), abi_serializer::create_yield_function( max_serialization_time ), true ),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",
|
|
fc::json::from_string(R"({"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11},"i2":13}]})"), max_serialization_time, true ),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "v1",
|
|
fc::json::from_string(R"(["very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",{"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11,"i1":12},"i2":13}],"very_very_very_very_very_very_very_very_very_very_long_field_name_f5":0}])"),
|
|
abi_serializer::create_yield_function( max_serialization_time ), true ),
|
|
pack_exception,
|
|
fc_exception_message_is("Unexpected field 'very_very_very_very_very_very_very_very_very_very_long_...ame_f5' found in input object while processing struct 'very_very_very_very_very_very_very_very_very_very_long_...ame_s3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary( "v1",
|
|
fc::json::from_string(R"(["very_very_very_very_very_very_very_very_very_very_long_struct_name_s3",{"i0":1,"i1":2,"i2":3,"f3":["bar",{"f0":{"i0":11,"i1":12},"i2":13}],"very_very_very_very_very_very_very_very_very_very_long_field_name_f5":0}])"),
|
|
max_serialization_time, true ),
|
|
pack_exception,
|
|
fc_exception_message_is("Unexpected field 'very_very_very_very_very_very_very_very_very_very_long_...ame_f5' found in input object while processing struct 'very_very_very_very_very_very_very_very_very_very_long_...ame_s3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s4",{"f0":[0,1],"f1":[{"i0":2,"i1":3},{"i1":5}]}])"), abi_serializer::create_yield_function( max_serialization_time ), true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("v1", fc::json::from_string(R"(["s4",{"f0":[0,1],"f1":[{"i0":2,"i1":3},{"i1":5}]}])"), max_serialization_time, true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 's1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2[]", fc::json::from_string(R"([{"f0":{"i0":1,"i1":2},"i2":3},{"f0":{"i0":4},"i2":6}])"), abi_serializer::create_yield_function( max_serialization_time ), true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s2[]", fc::json::from_string(R"([{"f0":{"i0":1,"i1":2},"i2":3},{"f0":{"i0":4},"i2":6}])"), max_serialization_time, true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s5", fc::json::from_string(R"({"f0":[["bar",{"f0":{"i0":1,"i1":2},"i2":3}],["foo",{"f0":{"i0":4},"i2":6}]]})"), abi_serializer::create_yield_function( max_serialization_time ), true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s5", fc::json::from_string(R"({"f0":[["bar",{"f0":{"i0":1,"i1":2},"i2":3}],["foo",{"f0":{"i0":4},"i2":6}]]})"), max_serialization_time, true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i1' in input object while processing struct 's1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s1arrayarray", fc::json::from_string(R"([[{"i0":1,"i1":2},{"i0":3,"i1":4}],[{"i0":6,"i1":6},{"i0":7,"i1":8},{"i1":10}]])"), abi_serializer::create_yield_function( max_serialization_time ), true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 's1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.variant_to_binary("s1arrayarray", fc::json::from_string(R"([[{"i0":1,"i1":2},{"i0":3,"i1":4}],[{"i0":6,"i1":6},{"i0":7,"i1":8},{"i1":10}]])"), max_serialization_time, true),
|
|
pack_exception, fc_exception_message_is("Missing field 'i0' in input object while processing struct 's1'") );
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_deserialize_detailed_error_messages)
|
|
{
|
|
using eosio::testing::fc_exception_message_is;
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.1",
|
|
"types": [
|
|
{"new_type_name": "oint", "type": "int8?"},
|
|
{"new_type_name": "os1", "type": "s1?"}
|
|
],
|
|
"structs": [
|
|
{"name": "s1", "base": "", "fields": [
|
|
{"name": "i0", "type": "int8"},
|
|
{"name": "i1", "type": "int8"}
|
|
]},
|
|
{"name": "s2", "base": "", "fields": [
|
|
{"name": "f0", "type": "int8[]"},
|
|
{"name": "f1", "type": "s1[]"}
|
|
]},
|
|
{"name": "s3", "base": "s1", "fields": [
|
|
{"name": "i3", "type": "int8"},
|
|
{"name": "i4", "type": "int8$"},
|
|
{"name": "i5", "type": "int8"}
|
|
]},
|
|
{"name": "s4", "base": "", "fields": [
|
|
{"name": "f0", "type": "oint[]"}
|
|
]},
|
|
{"name": "s5", "base": "", "fields": [
|
|
{"name": "f0", "type": "os1[]"},
|
|
{"name": "f1", "type": "v1[]"},
|
|
]},
|
|
{"name": "s6", "base": "", "fields": [
|
|
]},
|
|
],
|
|
"variants": [
|
|
{"name": "v1", "types": ["int8", "s1"]},
|
|
],
|
|
})";
|
|
|
|
// Some details here: c::variant("030101000103") represents an array of std::optional {1,null,3}, and
|
|
// fc::variant("0400000000") represents an array of 4 nulls. Also fc::variant("030001af013a") represents {null, 0xAF, 0x3A}.
|
|
// Test to verify that array of optinal doesn't throw exception
|
|
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
BOOST_CHECK_NO_THROW( abis.binary_to_variant("s4", fc::variant("030101000103").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )) );
|
|
BOOST_CHECK_NO_THROW( abis.binary_to_variant("s4", fc::variant("030101000103").as<bytes>(), max_serialization_time) );
|
|
|
|
try {
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("020102").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'f1' of struct 's2'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("020102").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'f1' of struct 's2'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("0201020103").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'i1' of struct 's2.f1[0]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("0201020103").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'i1' of struct 's2.f1[0]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("020102ff").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack size of array 's2.f1'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s2", fc::variant("020102ff").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack size of array 's2.f1'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s3", fc::variant("010203").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
abi_exception, fc_exception_message_is("Encountered field 'i5' without binary extension designation while processing struct 's3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s3", fc::variant("010203").as<bytes>(), max_serialization_time),
|
|
abi_exception, fc_exception_message_is("Encountered field 'i5' without binary extension designation while processing struct 's3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s3", fc::variant("02010304").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
abi_exception, fc_exception_message_is("Encountered field 'i5' without binary extension designation while processing struct 's3'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s3", fc::variant("02010304").as<bytes>(), max_serialization_time),
|
|
abi_exception, fc_exception_message_is("Encountered field 'i5' without binary extension designation while processing struct 's3'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s4", fc::variant("020101").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack optional of built-in type 'int8' while processing 's4.f0[1]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s4", fc::variant("020101").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack optional of built-in type 'int8' while processing 's4.f0[1]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("02010102").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack presence flag of optional 's5.f0[1]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("02010102").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack presence flag of optional 's5.f0[1]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("0001").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack tag of variant 's5.f1[0]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("0001").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Unable to unpack tag of variant 's5.f1[0]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("00010501").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Unpacked invalid tag (5) for variant 's5.f1[0]'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("00010501").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Unpacked invalid tag (5) for variant 's5.f1[0]'") );
|
|
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("00010101").as<bytes>(), abi_serializer::create_yield_function( max_serialization_time )),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'i1' of struct 's5.f1[0].<variant(1)=s1>'") );
|
|
BOOST_CHECK_EXCEPTION( abis.binary_to_variant("s5", fc::variant("00010101").as<bytes>(), max_serialization_time),
|
|
unpack_exception, fc_exception_message_is("Stream unexpectedly ended; unable to unpack field 'i1' of struct 's5.f1[0].<variant(1)=s1>'") );
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(serialize_optional_struct_type)
|
|
{
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.0",
|
|
"structs": [
|
|
{"name": "s", "base": "", "fields": [
|
|
{"name": "i0", "type": "int8"}
|
|
]},
|
|
],
|
|
})";
|
|
|
|
try {
|
|
abi_serializer abis( fc::json::from_string(abi).as<abi_def>(), abi_serializer::create_yield_function( max_serialization_time ) );
|
|
|
|
verify_round_trip_conversion(abis, "s?", R"({"i0":5})", "0105");
|
|
verify_round_trip_conversion(abis, "s?", R"(null)", "00");
|
|
|
|
} FC_LOG_AND_RETHROW()
|
|
}
|
|
|
|
template<class T>
|
|
inline std::pair<action_trace, std::string> generate_action_trace(const std::optional<T> & return_value, const std::string & return_value_hex, bool parsable = true)
|
|
{
|
|
action_trace at;
|
|
at.action_ordinal = 0;
|
|
at.creator_action_ordinal = 1;
|
|
at.closest_unnotified_ancestor_action_ordinal = 2;
|
|
at.receipt = std::optional<action_receipt>{};
|
|
at.receiver = action_name{"test"};
|
|
at.act = eosio::chain::action(
|
|
std::vector<eosio::chain::permission_level>{
|
|
eosio::chain::permission_level{
|
|
account_name{"acctest"},
|
|
permission_name{"active"}}},
|
|
account_name{"acctest"},
|
|
action_name{"acttest"},
|
|
bytes{fc::raw::pack(std::string{"test_data"})});
|
|
at.elapsed = fc::microseconds{3};
|
|
at.console = "console line";
|
|
at.trx_id = transaction_id_type{"5d039021cf3262c5036a6ad40a809ae1440ae6c6792a48e6e95abf083b108d5f"};
|
|
at.block_num = 4;
|
|
at.block_time = block_timestamp_type{5};
|
|
at.producer_block_id = std::optional<block_id_type>{};
|
|
if (return_value) {
|
|
at.return_value = fc::raw::pack(*return_value);
|
|
}
|
|
std::stringstream expected_json;
|
|
expected_json
|
|
<< "{"
|
|
<< "\"action_traces\":{"
|
|
<< "\"action_ordinal\":0,"
|
|
<< "\"creator_action_ordinal\":1,"
|
|
<< "\"closest_unnotified_ancestor_action_ordinal\":2,"
|
|
<< "\"receipt\":null,"
|
|
<< "\"receiver\":\"test\","
|
|
<< "\"act\":{"
|
|
<< "\"account\":\"acctest\","
|
|
<< "\"name\":\"acttest\","
|
|
<< "\"authorization\":[{"
|
|
<< "\"actor\":\"acctest\","
|
|
<< "\"permission\":\"active\""
|
|
<< "}],"
|
|
<< "\"data\":\"09746573745f64617461\","
|
|
<< "\"hex_data\":\"09746573745f64617461\""
|
|
<< "},"
|
|
<< "\"context_free\":false,"
|
|
<< "\"elapsed\":3,"
|
|
<< "\"console\":\"console line\","
|
|
<< "\"trx_id\":\"5d039021cf3262c5036a6ad40a809ae1440ae6c6792a48e6e95abf083b108d5f\","
|
|
<< "\"block_num\":4,"
|
|
<< "\"block_time\":\"2000-01-01T00:00:02.500\","
|
|
<< "\"producer_block_id\":null,"
|
|
<< "\"account_ram_deltas\":[],"
|
|
<< "\"except\":null,"
|
|
<< "\"error_code\":null,"
|
|
<< "\"return_value_hex_data\":\"" << return_value_hex << "\"";
|
|
if (return_value && parsable) {
|
|
if (std::is_same<T, std::string>::value) {
|
|
expected_json
|
|
<< ",\"return_value_data\":\"" << *return_value << "\"";
|
|
}
|
|
else {
|
|
expected_json
|
|
<< ",\"return_value_data\":" << *return_value;
|
|
}
|
|
}
|
|
expected_json
|
|
<< "}"
|
|
<< "}";
|
|
|
|
return std::make_pair(at, expected_json.str());
|
|
}
|
|
|
|
inline std::pair<action_trace, std::string> generate_action_trace() {
|
|
return generate_action_trace(std::optional<char>(), "");
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_to_variant__add_action__good_return_value)
|
|
{
|
|
action_trace at;
|
|
std::string expected_json;
|
|
std::tie(at, expected_json) = generate_action_trace(std::optional<uint16_t>{6}, "0600");
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.0",
|
|
"structs": [
|
|
{"name": "acttest", "base": "", "fields": [
|
|
{"name": "str", "type": "string"}
|
|
]},
|
|
],
|
|
"action_results": [
|
|
{
|
|
"name": "acttest",
|
|
"result_type": "uint16"
|
|
}
|
|
]
|
|
})";
|
|
auto abidef = fc::json::from_string(abi).as<abi_def>();
|
|
abi_serializer abis(abi_def(abidef), abi_serializer::create_yield_function(max_serialization_time));
|
|
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_yield_function(max_serialization_time), fc::microseconds{});
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_depth_yield_function(), max_serialization_time);
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_to_variant__add_action__bad_return_value)
|
|
{
|
|
action_trace at;
|
|
std::string expected_json;
|
|
std::tie(at, expected_json) = generate_action_trace(std::optional<std::string>{"no return"}, "096e6f2072657475726e", false);
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.0",
|
|
"structs": [
|
|
{"name": "acttest", "base": "", "fields": [
|
|
{"name": "str", "type": "string"}
|
|
]},
|
|
]
|
|
})";
|
|
auto abidef = fc::json::from_string(abi).as<abi_def>();
|
|
abi_serializer abis(abi_def(abidef), abi_serializer::create_yield_function(max_serialization_time));
|
|
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_yield_function(max_serialization_time), fc::microseconds{});
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_depth_yield_function(), max_serialization_time);
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(abi_to_variant__add_action__no_return_value)
|
|
{
|
|
action_trace at;
|
|
std::string expected_json;
|
|
std::tie(at, expected_json) = generate_action_trace();
|
|
|
|
auto abi = R"({
|
|
"version": "eosio::abi/1.0",
|
|
"structs": [
|
|
{
|
|
"name": "acttest",
|
|
"base": "",
|
|
"fields": [
|
|
{"name": "str", "type": "string"}
|
|
]
|
|
},
|
|
],
|
|
"action_results": [
|
|
{
|
|
"name": "acttest",
|
|
"result_type": "uint16"
|
|
}
|
|
]
|
|
})";
|
|
auto abidef = fc::json::from_string(abi).as<abi_def>();
|
|
abi_serializer abis(abi_def(abidef), abi_serializer::create_yield_function(max_serialization_time));
|
|
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_yield_function(max_serialization_time), fc::microseconds{});
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
{
|
|
mutable_variant_object mvo;
|
|
eosio::chain::impl::abi_traverse_context ctx(abi_serializer::create_depth_yield_function(), max_serialization_time);
|
|
eosio::chain::impl::abi_to_variant::add(mvo, "action_traces", at, get_resolver(abidef), ctx);
|
|
std::string res = fc::json::to_string(mvo, get_deadline());
|
|
|
|
BOOST_CHECK_EQUAL(res, expected_json);
|
|
}
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|