From a49f8bf47ca9ce8ceacf7a560e2b5c5fa1f360fd Mon Sep 17 00:00:00 2001 From: Abit Date: Mon, 19 Mar 2018 23:23:59 +0100 Subject: [PATCH] Merge pull request #714 from pmconrad/json_fix JSON fix --- libraries/app/api.cpp | 2 +- libraries/app/application.cpp | 35 +- libraries/app/database_api.cpp | 45 ++- libraries/app/include/graphene/app/plugin.hpp | 14 +- libraries/chain/db_debug.cpp | 10 +- libraries/chain/get_config.cpp | 10 +- .../chain/include/graphene/chain/config.hpp | 1 + .../graphene/chain/protocol/address.hpp | 4 +- .../include/graphene/chain/protocol/ext.hpp | 22 +- .../include/graphene/chain/protocol/types.hpp | 12 +- .../include/graphene/chain/protocol/vote.hpp | 4 +- .../include/graphene/chain/pts_address.hpp | 4 +- libraries/chain/protocol/address.cpp | 4 +- libraries/chain/protocol/types.cpp | 12 +- libraries/chain/protocol/vote.cpp | 4 +- libraries/chain/pts_address.cpp | 4 +- libraries/db/include/graphene/db/index.hpp | 6 +- libraries/db/include/graphene/db/object.hpp | 4 +- .../db/include/graphene/db/object_id.hpp | 8 +- libraries/egenesis/egenesis_brief.cpp.tmpl | 2 +- libraries/egenesis/egenesis_full.cpp.tmpl | 15 +- libraries/egenesis/embed_genesis.cpp | 3 +- libraries/net/include/graphene/net/config.hpp | 4 + libraries/net/node.cpp | 57 ++-- libraries/net/peer_database.cpp | 10 +- libraries/plugins/debug_witness/debug_api.cpp | 6 +- .../plugins/debug_witness/debug_witness.cpp | 4 +- .../delayed_node/delayed_node_plugin.cpp | 4 +- .../grouped_orders/grouped_orders_plugin.cpp | 303 ++++++++++++++++++ .../market_history/market_history_plugin.cpp | 7 +- .../include/graphene/witness/witness.hpp | 2 +- libraries/plugins/witness/witness.cpp | 17 +- libraries/utilities/key_conversion.cpp | 2 +- .../include/graphene/wallet/reflect_util.hpp | 10 +- .../wallet/include/graphene/wallet/wallet.hpp | 4 +- libraries/wallet/wallet.cpp | 102 +++--- programs/build_helpers/member_enumerator.cpp | 7 +- programs/cli_wallet/main.cpp | 30 +- programs/delayed_node/main.cpp | 8 +- programs/genesis_util/genesis_update.cpp | 6 +- programs/genesis_util/get_dev_key.cpp | 9 +- programs/witness_node/main.cpp | 8 +- tests/generate_empty_blocks/main.cpp | 3 +- tests/tests/serialization_tests.cpp | 4 +- 44 files changed, 576 insertions(+), 256 deletions(-) create mode 100644 libraries/plugins/grouped_orders/grouped_orders_plugin.cpp diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index adba2f9f..2cbc94e9 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -160,7 +160,7 @@ namespace graphene { namespace app { { auto block_num = b.block_num(); auto& callback = _callbacks.find(id)->second; - fc::async( [capture_this,this,id,block_num,trx_num,trx,callback](){ callback( fc::variant(transaction_confirmation{ id, block_num, trx_num, trx}) ); } ); + fc::async( [capture_this,this,id,block_num,trx_num,trx,callback](){ callback( fc::variant(transaction_confirmation{ id, block_num, trx_num, trx}, 5) ); } ); } } } diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 5e4f9c7e..dec78acf 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -142,7 +142,7 @@ namespace detail { if( _options->count("seed-nodes") ) { auto seeds_str = _options->at("seed-nodes").as(); - auto seeds = fc::json::from_string(seeds_str).as>(); + auto seeds = fc::json::from_string(seeds_str).as>(2); for( const string& endpoint_string : seeds ) { try { @@ -226,7 +226,7 @@ namespace detail { void new_connection( const fc::http::websocket_connection_ptr& c ) { - auto wsc = std::make_shared(*c); + auto wsc = std::make_shared(*c, GRAPHENE_NET_MAX_NESTED_OBJECTS); auto login = std::make_shared( std::ref(*_self) ); login->enable_api("database_api"); @@ -292,7 +292,7 @@ namespace detail { _websocket_tls_server->start_accept(); } FC_CAPTURE_AND_RETHROW() } - application_impl(application* self) + explicit application_impl(application* self) : _self(self), _chain_db(std::make_shared()) { @@ -309,7 +309,6 @@ namespace detail { public_key_type init_pubkey( init_key ); for( uint64_t i=0; icount("genesis-json") ) { std::string genesis_str; fc::read_file_contents( _options->at("genesis-json").as(), genesis_str ); - genesis_state_type genesis = fc::json::from_string( genesis_str ).as(); + genesis_state_type genesis = fc::json::from_string( genesis_str ).as( 20 ); bool modified_genesis = false; if( _options->count("genesis-timestamp") ) { @@ -356,7 +355,7 @@ namespace detail { graphene::egenesis::compute_egenesis_json( egenesis_json ); FC_ASSERT( egenesis_json != "" ); FC_ASSERT( graphene::egenesis::get_egenesis_json_hash() == fc::sha256::hash( egenesis_json ) ); - auto genesis = fc::json::from_string( egenesis_json ).as(); + auto genesis = fc::json::from_string( egenesis_json ).as( 20 ); genesis.initial_chain_id = fc::sha256::hash( egenesis_json ); return genesis; } @@ -372,7 +371,7 @@ namespace detail { loaded_checkpoints.reserve( cps.size() ); for( auto cp : cps ) { - auto item = fc::json::from_string(cp).as >(); + auto item = fc::json::from_string(cp).as >( 2 ); loaded_checkpoints[item.first] = item.second; } } @@ -447,9 +446,21 @@ namespace detail { _force_validate = true; } - if( _options->count("api-access") ) - _apiaccess = fc::json::from_file( _options->at("api-access").as() ) - .as(); + if( _options->count("api-access") ) { + + if(fc::exists(_options->at("api-access").as())) + { + _apiaccess = fc::json::from_file( _options->at("api-access").as() ).as( 20 ); + ilog( "Using api access file from ${path}", + ("path", _options->at("api-access").as().string()) ); + } + else + { + elog("Failed to load file from ${path}", + ("path", _options->at("api-access").as().string())); + std::exit(EXIT_FAILURE); + } + } else { // TODO: Remove this generous default access policy @@ -991,7 +1002,7 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti if( fc::exists(genesis_out) ) { try { - genesis_state = fc::json::from_file(genesis_out).as(); + genesis_state = fc::json::from_file(genesis_out).as( 20 ); } catch(const fc::exception& e) { std::cerr << "Unable to parse existing genesis file:\n" << e.to_string() << "\nWould you like to replace it? [y/N] "; diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 8dd52e08..b3cf81e1 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -47,9 +47,6 @@ typedef std::map< std::pair { public: @@ -217,7 +214,7 @@ class database_api_impl : public std::enable_shared_from_this auto sub = _market_subscriptions.find( market ); if( sub != _market_subscriptions.end() ) { - queue[market].emplace_back( full_object ? obj->to_variant() : fc::variant(obj->id) ); + queue[market].emplace_back( full_object ? obj->to_variant() : fc::variant(obj->id, 1) ); } } @@ -273,7 +270,7 @@ database_api_impl::database_api_impl( graphene::chain::database& db ):_db(db) _applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); }); _pending_trx_connection = _db.on_pending_transaction.connect([this](const signed_transaction& trx ){ - if( _pending_trx_callback ) _pending_trx_callback( fc::variant(trx) ); + if( _pending_trx_callback ) _pending_trx_callback( fc::variant(trx, GRAPHENE_MAX_NESTED_OBJECTS) ); }); } @@ -645,7 +642,7 @@ std::map database_api_impl::get_full_accounts( const { const account_object* account = nullptr; if (std::isdigit(account_name_or_id[0])) - account = _db.find(fc::variant(account_name_or_id).as()); + account = _db.find(fc::variant(account_name_or_id, 1).as(1)); else { const auto& idx = _db.get_index_type().indices().get(); @@ -663,7 +660,6 @@ std::map database_api_impl::get_full_accounts( const subscribe_to_item( account->id ); } - // fc::mutable_variant_object full_account; full_account acnt; acnt.account = *account; acnt.statistics = account->statistics(_db); @@ -672,12 +668,6 @@ std::map database_api_impl::get_full_accounts( const acnt.lifetime_referrer_name = account->lifetime_referrer(_db).name; acnt.votes = lookup_vote_ids( vector(account->options.votes.begin(),account->options.votes.end()) ); - // Add the account itself, its statistics object, cashback balance, and referral account names - /* - full_account("account", *account)("statistics", account->statistics(_db)) - ("registrar_name", account->registrar(_db).name)("referrer_name", account->referrer(_db).name) - ("lifetime_referrer_name", account->lifetime_referrer(_db).name); - */ if (account->cashback_vb) { acnt.cashback_balance = account->cashback_balance(_db); @@ -697,7 +687,6 @@ std::map database_api_impl::get_full_accounts( const // Add the account's balances auto balance_range = _db.get_index_type().indices().get().equal_range(boost::make_tuple(account->id)); - //vector balances; std::for_each(balance_range.first, balance_range.second, [&acnt](const account_balance_object& balance) { acnt.balances.emplace_back(balance); @@ -1013,7 +1002,7 @@ vector> database_api_impl::lookup_asset_symbols(const vec [this, &assets_by_symbol](const string& symbol_or_id) -> optional { if( !symbol_or_id.empty() && std::isdigit(symbol_or_id[0]) ) { - auto ptr = _db.find(variant(symbol_or_id).as()); + auto ptr = _db.find(variant(symbol_or_id, 1).as(1)); return ptr == nullptr? optional() : *ptr; } auto itr = assets_by_symbol.find(symbol_or_id); @@ -1712,7 +1701,7 @@ vector database_api_impl::lookup_vote_ids( const vector& { auto itr = committee_idx.find( id ); if( itr != committee_idx.end() ) - result.emplace_back( variant( *itr ) ); + result.emplace_back( variant( *itr, 1 ) ); else result.emplace_back( variant() ); break; @@ -1721,7 +1710,7 @@ vector database_api_impl::lookup_vote_ids( const vector& { auto itr = witness_idx.find( id ); if( itr != witness_idx.end() ) - result.emplace_back( variant( *itr ) ); + result.emplace_back( variant( *itr, 1 ) ); else result.emplace_back( variant() ); break; @@ -1730,12 +1719,12 @@ vector database_api_impl::lookup_vote_ids( const vector& { auto itr = for_worker_idx.find( id ); if( itr != for_worker_idx.end() ) { - result.emplace_back( variant( *itr ) ); + result.emplace_back( variant( *itr, 1 ) ); } else { auto itr = against_worker_idx.find( id ); if( itr != against_worker_idx.end() ) { - result.emplace_back( variant( *itr ) ); + result.emplace_back( variant( *itr, 1 ) ); } else { result.emplace_back( variant() ); @@ -1744,6 +1733,8 @@ vector database_api_impl::lookup_vote_ids( const vector& break; } case vote_id_type::VOTE_TYPE_COUNT: break; // supress unused enum value warnings + default: + FC_CAPTURE_AND_THROW( fc::out_of_range_exception, (id) ); } } return result; @@ -1852,8 +1843,8 @@ bool database_api::verify_authority( const signed_transaction& trx )const bool database_api_impl::verify_authority( const signed_transaction& trx )const { trx.verify_authority( _db.get_chain_id(), - [&]( account_id_type id ){ return &id(_db).active; }, - [&]( account_id_type id ){ return &id(_db).owner; }, + [this]( account_id_type id ){ return &id(_db).active; }, + [this]( account_id_type id ){ return &id(_db).owner; }, _db.get_global_properties().parameters.max_authority_depth ); return true; } @@ -1868,7 +1859,7 @@ bool database_api_impl::verify_account_authority( const string& name_or_id, cons FC_ASSERT( name_or_id.size() > 0); const account_object* account = nullptr; if (std::isdigit(name_or_id[0])) - account = _db.find(fc::variant(name_or_id).as()); + account = _db.find(fc::variant(name_or_id, 1).as(1)); else { const auto& idx = _db.get_index_type().indices().get(); @@ -1929,7 +1920,7 @@ struct get_required_fees_helper { asset fee = current_fee_schedule.set_fee( op, core_exchange_rate ); fc::variant result; - fc::to_variant( fee, result ); + fc::to_variant( fee, result, GRAPHENE_NET_MAX_NESTED_OBJECTS ); return result; } } @@ -1949,7 +1940,7 @@ struct get_required_fees_helper // two mutually recursive functions instead of a visitor result.first = current_fee_schedule.set_fee( proposal_create_op, core_exchange_rate ); fc::variant vresult; - fc::to_variant( result, vresult ); + fc::to_variant( result, vresult, GRAPHENE_NET_MAX_NESTED_OBJECTS ); return vresult; } @@ -2211,7 +2202,7 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec } else { - updates.emplace_back( id ); + updates.emplace_back( fc::variant( id, 1 ) ); } } } @@ -2255,7 +2246,7 @@ void database_api_impl::on_applied_block() auto capture_this = shared_from_this(); block_id_type block_id = _db.head_block_id(); fc::async([this,capture_this,block_id](){ - _block_applied_callback(fc::variant(block_id)); + _block_applied_callback(fc::variant(block_id, 1)); }); } @@ -2296,7 +2287,7 @@ void database_api_impl::on_applied_block() { auto itr = _market_subscriptions.find(item.first); if(itr != _market_subscriptions.end()) - itr->second(fc::variant(item.second)); + itr->second(fc::variant(item.second, GRAPHENE_NET_MAX_NESTED_OBJECTS)); } }); } diff --git a/libraries/app/include/graphene/app/plugin.hpp b/libraries/app/include/graphene/app/plugin.hpp index 87220744..c242130b 100644 --- a/libraries/app/include/graphene/app/plugin.hpp +++ b/libraries/app/include/graphene/app/plugin.hpp @@ -121,16 +121,24 @@ class plugin : public abstract_plugin /// @group Some useful tools for boost::program_options arguments using vectors of JSON strings /// @{ template -T dejsonify(const string& s) +T dejsonify(const string& s, uint32_t max_depth) { - return fc::json::from_string(s).as(); + return fc::json::from_string(s).as(max_depth); +} + +namespace impl { + template + T dejsonify( const string& s ) + { + return graphene::app::dejsonify( s, GRAPHENE_MAX_NESTED_OBJECTS ); + } } #define DEFAULT_VALUE_VECTOR(value) default_value({fc::json::to_string(value)}, fc::json::to_string(value)) #define LOAD_VALUE_SET(options, name, container, type) \ if( options.count(name) ) { \ const std::vector& ops = options[name].as>(); \ - std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::dejsonify); \ + std::transform(ops.begin(), ops.end(), std::inserter(container, container.end()), &graphene::app::impl::dejsonify); \ } /// @} diff --git a/libraries/chain/db_debug.cpp b/libraries/chain/db_debug.cpp index aa91fd44..2373eab6 100644 --- a/libraries/chain/db_debug.cpp +++ b/libraries/chain/db_debug.cpp @@ -143,25 +143,19 @@ void debug_apply_update( database& db, const fc::variant_object& vo ) switch( action ) { case db_action_create: - /* - idx.create( [&]( object& obj ) - { - idx.object_from_variant( vo, obj ); - } ); - */ FC_ASSERT( false ); break; case db_action_write: db.modify( db.get_object( oid ), [&]( object& obj ) { idx.object_default( obj ); - idx.object_from_variant( vo, obj ); + idx.object_from_variant( vo, obj, GRAPHENE_MAX_NESTED_OBJECTS ); } ); break; case db_action_update: db.modify( db.get_object( oid ), [&]( object& obj ) { - idx.object_from_variant( vo, obj ); + idx.object_from_variant( vo, obj, GRAPHENE_MAX_NESTED_OBJECTS ); } ); break; case db_action_delete: diff --git a/libraries/chain/get_config.cpp b/libraries/chain/get_config.cpp index c6b35f7a..c961b950 100644 --- a/libraries/chain/get_config.cpp +++ b/libraries/chain/get_config.cpp @@ -103,11 +103,11 @@ fc::variant_object get_config() result[ "GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS" ] = GRAPHENE_DEFAULT_WITNESS_PAY_VESTING_SECONDS; result[ "GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY" ] = GRAPHENE_DEFAULT_WORKER_BUDGET_PER_DAY; result[ "GRAPHENE_MAX_INTEREST_APR" ] = GRAPHENE_MAX_INTEREST_APR; - result[ "GRAPHENE_COMMITTEE_ACCOUNT" ] = GRAPHENE_COMMITTEE_ACCOUNT; - result[ "GRAPHENE_WITNESS_ACCOUNT" ] = GRAPHENE_WITNESS_ACCOUNT; - result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = GRAPHENE_RELAXED_COMMITTEE_ACCOUNT; - result[ "GRAPHENE_NULL_ACCOUNT" ] = GRAPHENE_NULL_ACCOUNT; - result[ "GRAPHENE_TEMP_ACCOUNT" ] = GRAPHENE_TEMP_ACCOUNT; + result[ "GRAPHENE_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS); + result[ "GRAPHENE_WITNESS_ACCOUNT" ] = fc::variant(GRAPHENE_WITNESS_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS); + result[ "GRAPHENE_RELAXED_COMMITTEE_ACCOUNT" ] = fc::variant(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS); + result[ "GRAPHENE_NULL_ACCOUNT" ] = fc::variant(GRAPHENE_NULL_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS); + result[ "GRAPHENE_TEMP_ACCOUNT" ] = fc::variant(GRAPHENE_TEMP_ACCOUNT, GRAPHENE_MAX_NESTED_OBJECTS); return result; } diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index becf73d6..a5354f85 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -211,6 +211,7 @@ { 10000000, 100000} } /* <= 1000: 10.00 */ #define GRAPHENE_DEFAULT_BETTING_PERCENT_FEE (2 * GRAPHENE_1_PERCENT) #define GRAPHENE_DEFAULT_LIVE_BETTING_DELAY_TIME 5 // seconds +#define GRAPHENE_MAX_NESTED_OBJECTS (200) #define TOURNAMENT_MIN_ROUND_DELAY 0 #define TOURNAMENT_MAX_ROUND_DELAY 600 #define TOURNAMENT_MIN_TIME_PER_COMMIT_MOVE 0 diff --git a/libraries/chain/include/graphene/chain/protocol/address.hpp b/libraries/chain/include/graphene/chain/protocol/address.hpp index 00331c08..b225b42c 100644 --- a/libraries/chain/include/graphene/chain/protocol/address.hpp +++ b/libraries/chain/include/graphene/chain/protocol/address.hpp @@ -78,8 +78,8 @@ namespace graphene { namespace chain { namespace fc { - void to_variant( const graphene::chain::address& var, fc::variant& vo ); - void from_variant( const fc::variant& var, graphene::chain::address& vo ); + void to_variant( const graphene::chain::address& var, fc::variant& vo, uint32_t max_depth = 1 ); + void from_variant( const fc::variant& var, graphene::chain::address& vo, uint32_t max_depth = 1 ); } namespace std diff --git a/libraries/chain/include/graphene/chain/protocol/ext.hpp b/libraries/chain/include/graphene/chain/protocol/ext.hpp index ac775535..31f66506 100644 --- a/libraries/chain/include/graphene/chain/protocol/ext.hpp +++ b/libraries/chain/include/graphene/chain/protocol/ext.hpp @@ -145,9 +145,10 @@ namespace fc { template< typename T > struct graphene_extension_from_variant_visitor { - graphene_extension_from_variant_visitor( const variant_object& v, T& val ) - : vo( v ), value( val ) + graphene_extension_from_variant_visitor( const variant_object& v, T& val, uint32_t max_depth ) + : vo( v ), value( val ), _max_depth(max_depth - 1) { + FC_ASSERT( max_depth > 0, "Recursion depth exceeded!" ); count_left = vo.size(); } @@ -157,7 +158,7 @@ struct graphene_extension_from_variant_visitor auto it = vo.find(name); if( it != vo.end() ) { - from_variant( it->value(), (value.*member) ); + from_variant( it->value(), (value.*member), _max_depth ); assert( count_left > 0 ); // x.find(k) returns true for n distinct values of k only if x.size() >= n --count_left; } @@ -165,11 +166,12 @@ struct graphene_extension_from_variant_visitor const variant_object& vo; T& value; + const uint32_t _max_depth; mutable uint32_t count_left = 0; }; template< typename T > -void from_variant( const fc::variant& var, graphene::chain::extension& value ) +void from_variant( const fc::variant& var, graphene::chain::extension& value, uint32_t max_depth ) { value = graphene::chain::extension(); if( var.is_null() ) @@ -180,7 +182,7 @@ void from_variant( const fc::variant& var, graphene::chain::extension& value return; } - graphene_extension_from_variant_visitor vtor( var.get_object(), value.value ); + graphene_extension_from_variant_visitor vtor( var.get_object(), value.value, max_depth ); fc::reflector::visit( vtor ); FC_ASSERT( vtor.count_left == 0 ); // unrecognized extension throws here } @@ -188,23 +190,23 @@ void from_variant( const fc::variant& var, graphene::chain::extension& value template< typename T > struct graphene_extension_to_variant_visitor { - graphene_extension_to_variant_visitor( const T& v ) : value(v) {} + graphene_extension_to_variant_visitor( const T& v, uint32_t max_depth ) : value(v), mvo(max_depth) {} template void operator()( const char* name )const { if( (value.*member).valid() ) - mvo[ name ] = (value.*member); + mvo( name, value.*member ); } const T& value; - mutable mutable_variant_object mvo; + mutable limited_mutable_variant_object mvo; }; template< typename T > -void to_variant( const graphene::chain::extension& value, fc::variant& var ) +void to_variant( const graphene::chain::extension& value, fc::variant& var, uint32_t max_depth ) { - graphene_extension_to_variant_visitor vtor( value.value ); + graphene_extension_to_variant_visitor vtor( value.value, max_depth ); fc::reflector::visit( vtor ); var = vtor.mvo; } diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 4df38372..c2c92ca3 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -367,12 +367,12 @@ namespace graphene { namespace chain { namespace fc { - void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo ); - void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo ); - void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo ); - void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo ); - void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo ); - void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo ); + void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo, uint32_t max_depth = 2 ); + void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo, uint32_t max_depth = 2 ); + void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo, uint32_t max_depth = 2 ); + void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo, uint32_t max_depth = 2 ); + void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo, uint32_t max_depth = 2 ); + void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo, uint32_t max_depth = 2 ); } FC_REFLECT( graphene::chain::public_key_type, (key_data) ) diff --git a/libraries/chain/include/graphene/chain/protocol/vote.hpp b/libraries/chain/include/graphene/chain/protocol/vote.hpp index 215d4902..67536f7a 100644 --- a/libraries/chain/include/graphene/chain/protocol/vote.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vote.hpp @@ -141,8 +141,8 @@ namespace fc class variant; -void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo ); -void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo ); +void to_variant( const graphene::chain::vote_id_type& var, fc::variant& vo, uint32_t max_depth = 1 ); +void from_variant( const fc::variant& var, graphene::chain::vote_id_type& vo, uint32_t max_depth = 1 ); } // fc diff --git a/libraries/chain/include/graphene/chain/pts_address.hpp b/libraries/chain/include/graphene/chain/pts_address.hpp index 8c53fb2e..636e2f11 100644 --- a/libraries/chain/include/graphene/chain/pts_address.hpp +++ b/libraries/chain/include/graphene/chain/pts_address.hpp @@ -73,6 +73,6 @@ FC_REFLECT( graphene::chain::pts_address, (addr) ) namespace fc { - void to_variant( const graphene::chain::pts_address& var, fc::variant& vo ); - void from_variant( const fc::variant& var, graphene::chain::pts_address& vo ); + void to_variant( const graphene::chain::pts_address& var, fc::variant& vo, uint32_t max_depth = 1 ); + void from_variant( const fc::variant& var, graphene::chain::pts_address& vo, uint32_t max_depth = 1 ); } diff --git a/libraries/chain/protocol/address.cpp b/libraries/chain/protocol/address.cpp index 42e03cc2..19bb4df5 100644 --- a/libraries/chain/protocol/address.cpp +++ b/libraries/chain/protocol/address.cpp @@ -101,11 +101,11 @@ namespace graphene { namespace fc { - void to_variant( const graphene::chain::address& var, variant& vo ) + void to_variant( const graphene::chain::address& var, variant& vo, uint32_t max_depth ) { vo = std::string(var); } - void from_variant( const variant& var, graphene::chain::address& vo ) + void from_variant( const variant& var, graphene::chain::address& vo, uint32_t max_depth ) { vo = graphene::chain::address( var.as_string() ); } diff --git a/libraries/chain/protocol/types.cpp b/libraries/chain/protocol/types.cpp index 6e3bf1fb..b7cac207 100644 --- a/libraries/chain/protocol/types.cpp +++ b/libraries/chain/protocol/types.cpp @@ -248,32 +248,32 @@ namespace graphene { namespace chain { namespace fc { using namespace std; - void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo ) + void to_variant( const graphene::chain::public_key_type& var, fc::variant& vo, uint32_t max_depth ) { vo = std::string( var ); } - void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo ) + void from_variant( const fc::variant& var, graphene::chain::public_key_type& vo, uint32_t max_depth ) { vo = graphene::chain::public_key_type( var.as_string() ); } - void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo ) + void to_variant( const graphene::chain::extended_public_key_type& var, fc::variant& vo, uint32_t max_depth ) { vo = std::string( var ); } - void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo ) + void from_variant( const fc::variant& var, graphene::chain::extended_public_key_type& vo, uint32_t max_depth ) { vo = graphene::chain::extended_public_key_type( var.as_string() ); } - void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo ) + void to_variant( const graphene::chain::extended_private_key_type& var, fc::variant& vo, uint32_t max_depth ) { vo = std::string( var ); } - void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo ) + void from_variant( const fc::variant& var, graphene::chain::extended_private_key_type& vo, uint32_t max_depth ) { vo = graphene::chain::extended_private_key_type( var.as_string() ); } diff --git a/libraries/chain/protocol/vote.cpp b/libraries/chain/protocol/vote.cpp index 44be9bca..f78f2b4f 100644 --- a/libraries/chain/protocol/vote.cpp +++ b/libraries/chain/protocol/vote.cpp @@ -38,12 +38,12 @@ vote_id_type get_next_vote_id( global_property_object& gpo, vote_id_type::vote_t namespace fc { -void to_variant(const graphene::chain::vote_id_type& var, variant& vo) +void to_variant( const graphene::chain::vote_id_type& var, variant& vo, uint32_t max_depth ) { vo = string(var); } -void from_variant(const variant& var, graphene::chain::vote_id_type& vo) +void from_variant( const variant& var, graphene::chain::vote_id_type& vo, uint32_t max_depth ) { vo = graphene::chain::vote_id_type(var.as_string()); } diff --git a/libraries/chain/pts_address.cpp b/libraries/chain/pts_address.cpp index d2b8c33c..27f3d256 100644 --- a/libraries/chain/pts_address.cpp +++ b/libraries/chain/pts_address.cpp @@ -89,11 +89,11 @@ namespace graphene { namespace chain { namespace fc { - void to_variant( const graphene::chain::pts_address& var, variant& vo ) + void to_variant( const graphene::chain::pts_address& var, variant& vo, uint32_t max_depth ) { vo = std::string(var); } - void from_variant( const variant& var, graphene::chain::pts_address& vo ) + void from_variant( const variant& var, graphene::chain::pts_address& vo, uint32_t max_depth ) { vo = graphene::chain::pts_address( var.as_string() ); } diff --git a/libraries/db/include/graphene/db/index.hpp b/libraries/db/include/graphene/db/index.hpp index aebdb8b9..a302ec98 100644 --- a/libraries/db/include/graphene/db/index.hpp +++ b/libraries/db/include/graphene/db/index.hpp @@ -130,7 +130,7 @@ namespace graphene { namespace db { virtual fc::uint128 hash()const = 0; virtual void add_observer( const shared_ptr& ) = 0; - virtual void object_from_variant( const fc::variant& var, object& obj )const = 0; + virtual void object_from_variant( const fc::variant& var, object& obj, uint32_t max_depth )const = 0; virtual void object_default( object& obj )const = 0; }; @@ -301,12 +301,12 @@ namespace graphene { namespace db { _observers.emplace_back( o ); } - virtual void object_from_variant( const fc::variant& var, object& obj )const override + virtual void object_from_variant( const fc::variant& var, object& obj, uint32_t max_depth )const override { object_id_type id = obj.id; object_type* result = dynamic_cast( &obj ); FC_ASSERT( result != nullptr ); - fc::from_variant( var, *result ); + fc::from_variant( var, *result, max_depth ); obj.id = id; } diff --git a/libraries/db/include/graphene/db/object.hpp b/libraries/db/include/graphene/db/object.hpp index d8d16c33..c410e273 100644 --- a/libraries/db/include/graphene/db/object.hpp +++ b/libraries/db/include/graphene/db/object.hpp @@ -27,6 +27,8 @@ #include #include +#define MAX_NESTING (200) + namespace graphene { namespace db { /** @@ -98,7 +100,7 @@ namespace graphene { namespace db { { static_cast(*this) = std::move( static_cast(obj) ); } - virtual variant to_variant()const { return variant( static_cast(*this) ); } + virtual variant to_variant()const { return variant( static_cast(*this), MAX_NESTING ); } virtual vector pack()const { return fc::raw::pack( static_cast(*this) ); } virtual fc::uint128 hash()const { auto tmp = this->pack(); diff --git a/libraries/db/include/graphene/db/object_id.hpp b/libraries/db/include/graphene/db/object_id.hpp index 598ff3de..255ef048 100644 --- a/libraries/db/include/graphene/db/object_id.hpp +++ b/libraries/db/include/graphene/db/object_id.hpp @@ -169,12 +169,12 @@ struct reflector > }; - inline void to_variant( const graphene::db::object_id_type& var, fc::variant& vo ) + inline void to_variant( const graphene::db::object_id_type& var, fc::variant& vo, uint32_t max_depth = 1 ) { vo = std::string( var ); } - inline void from_variant( const fc::variant& var, graphene::db::object_id_type& vo ) + inline void from_variant( const fc::variant& var, graphene::db::object_id_type& vo, uint32_t max_depth = 1 ) { try { vo.number = 0; const auto& s = var.get_string(); @@ -191,12 +191,12 @@ struct reflector > vo.number |= (space_id << 56) | (type_id << 48); } FC_CAPTURE_AND_RETHROW( (var) ) } template - void to_variant( const graphene::db::object_id& var, fc::variant& vo ) + void to_variant( const graphene::db::object_id& var, fc::variant& vo, uint32_t max_depth = 1 ) { vo = fc::to_string(SpaceID) + "." + fc::to_string(TypeID) + "." + fc::to_string(var.instance.value); } template - void from_variant( const fc::variant& var, graphene::db::object_id& vo ) + void from_variant( const fc::variant& var, graphene::db::object_id& vo, uint32_t max_depth = 1 ) { try { const auto& s = var.get_string(); auto first_dot = s.find('.'); diff --git a/libraries/egenesis/egenesis_brief.cpp.tmpl b/libraries/egenesis/egenesis_brief.cpp.tmpl index 8ee2ba3b..bd590eb3 100644 --- a/libraries/egenesis/egenesis_brief.cpp.tmpl +++ b/libraries/egenesis/egenesis_brief.cpp.tmpl @@ -26,7 +26,7 @@ using namespace graphene::chain; chain_id_type get_egenesis_chain_id() { - return chain_id_type( "${chain_id}$" ); + return chain_id_type( "${chain_id}" ); } void compute_egenesis_json( std::string& result ) diff --git a/libraries/egenesis/egenesis_full.cpp.tmpl b/libraries/egenesis/egenesis_full.cpp.tmpl index 7054e20f..83285f11 100644 --- a/libraries/egenesis/egenesis_full.cpp.tmpl +++ b/libraries/egenesis/egenesis_full.cpp.tmpl @@ -24,26 +24,25 @@ namespace graphene { namespace egenesis { using namespace graphene::chain; -static const char genesis_json_array[${genesis_json_array_height}$][${genesis_json_array_width}$+1] = +static const char genesis_json_array[${genesis_json_array_height}][${genesis_json_array_width}+1] = { -${genesis_json_array}$ +${genesis_json_array} }; chain_id_type get_egenesis_chain_id() { - return chain_id_type( "${chain_id}$" ); + return chain_id_type( "${chain_id}" ); } void compute_egenesis_json( std::string& result ) { - result.reserve( ${genesis_json_length}$ ); + result.reserve( ${genesis_json_length} ); result.resize(0); - for( size_t i=0; i<${genesis_json_array_height}$-1; i++ ) + for( size_t i=0; i<${genesis_json_array_height}-1; i++ ) { - result.append( genesis_json_array[i], ${genesis_json_array_width}$ ); + result.append( genesis_json_array[i], ${genesis_json_array_width} ); } - result.append( std::string( genesis_json_array[ ${genesis_json_array_height}$-1 ] ) ); - return; + result.append( std::string( genesis_json_array[ ${genesis_json_array_height}-1 ] ) ); } fc::sha256 get_egenesis_json_hash() diff --git a/libraries/egenesis/embed_genesis.cpp b/libraries/egenesis/embed_genesis.cpp index 6fac5dbb..26283080 100644 --- a/libraries/egenesis/embed_genesis.cpp +++ b/libraries/egenesis/embed_genesis.cpp @@ -168,7 +168,7 @@ struct egenesis_info // If genesis not exist, generate from genesis_json try { - genesis = fc::json::from_string( *genesis_json ).as< genesis_state_type >(); + genesis = fc::json::from_string( *genesis_json ).as< genesis_state_type >( 20 ); } catch (const fc::exception& e) { @@ -223,7 +223,6 @@ void load_genesis( std::cerr << "embed_genesis: Genesis ID from argument is " << chain_id_str << "\n"; info.chain_id = chain_id_str; } - return; } int main( int argc, char** argv ) diff --git a/libraries/net/include/graphene/net/config.hpp b/libraries/net/include/graphene/net/config.hpp index 1d400bcf..9edca51c 100644 --- a/libraries/net/include/graphene/net/config.hpp +++ b/libraries/net/include/graphene/net/config.hpp @@ -106,3 +106,7 @@ #define GRAPHENE_NET_MIN_BLOCK_IDS_TO_PREFETCH 10000 #define GRAPHENE_NET_MAX_TRX_PER_SECOND 1000 + +#define GRAPHENE_NET_MAX_NESTED_OBJECTS (250) + +#define MAXIMUM_PEERDB_SIZE 1000 diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index dfdaf1cc..e9232782 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -1853,10 +1853,10 @@ namespace graphene { namespace net { namespace detail { #endif user_data["bitness"] = sizeof(void*) * 8; - user_data["node_id"] = _node_id; + user_data["node_id"] = fc::variant( _node_id, 1 ); item_hash_t head_block_id = _delegate->get_head_block_id(); - user_data["last_known_block_hash"] = head_block_id; + user_data["last_known_block_hash"] = fc::variant( head_block_id, 1 ); user_data["last_known_block_number"] = _delegate->get_block_number(head_block_id); user_data["last_known_block_time"] = _delegate->get_block_time(head_block_id); @@ -1872,19 +1872,19 @@ namespace graphene { namespace net { namespace detail { if (user_data.contains("graphene_git_revision_sha")) originating_peer->graphene_git_revision_sha = user_data["graphene_git_revision_sha"].as_string(); if (user_data.contains("graphene_git_revision_unix_timestamp")) - originating_peer->graphene_git_revision_unix_timestamp = fc::time_point_sec(user_data["graphene_git_revision_unix_timestamp"].as()); + originating_peer->graphene_git_revision_unix_timestamp = fc::time_point_sec(user_data["graphene_git_revision_unix_timestamp"].as(1)); if (user_data.contains("fc_git_revision_sha")) originating_peer->fc_git_revision_sha = user_data["fc_git_revision_sha"].as_string(); if (user_data.contains("fc_git_revision_unix_timestamp")) - originating_peer->fc_git_revision_unix_timestamp = fc::time_point_sec(user_data["fc_git_revision_unix_timestamp"].as()); + originating_peer->fc_git_revision_unix_timestamp = fc::time_point_sec(user_data["fc_git_revision_unix_timestamp"].as(1)); if (user_data.contains("platform")) originating_peer->platform = user_data["platform"].as_string(); if (user_data.contains("bitness")) - originating_peer->bitness = user_data["bitness"].as(); + originating_peer->bitness = user_data["bitness"].as(1); if (user_data.contains("node_id")) - originating_peer->node_id = user_data["node_id"].as(); + originating_peer->node_id = user_data["node_id"].as(1); if (user_data.contains("last_known_fork_block_number")) - originating_peer->last_known_fork_block_number = user_data["last_known_fork_block_number"].as(); + originating_peer->last_known_fork_block_number = user_data["last_known_fork_block_number"].as(1); } void node_impl::on_hello_message( peer_connection* originating_peer, const hello_message& hello_message_received ) @@ -1894,7 +1894,7 @@ namespace graphene { namespace net { namespace detail { node_id_t peer_node_id = hello_message_received.node_public_key; try { - peer_node_id = hello_message_received.user_data["node_id"].as(); + peer_node_id = hello_message_received.user_data["node_id"].as(1); } catch (const fc::exception&) { @@ -2935,7 +2935,7 @@ namespace graphene { namespace net { namespace detail { ( "msg", closing_connection_message_received.reason_for_closing ) ( "error", closing_connection_message_received.error ) ); std::ostringstream message; - message << "Peer " << fc::variant( originating_peer->get_remote_endpoint() ).as_string() << + message << "Peer " << fc::variant( originating_peer->get_remote_endpoint(), GRAPHENE_NET_MAX_NESTED_OBJECTS ).as_string() << " disconnected us: " << closing_connection_message_received.reason_for_closing; fc::exception detailed_error(FC_LOG_MESSAGE(warn, "Peer ${peer} is disconnecting us because of an error: ${msg}, exception: ${error}", ( "peer", originating_peer->get_remote_endpoint() ) @@ -3841,7 +3841,7 @@ namespace graphene { namespace net { namespace detail { user_data["bitness"] = *peer->bitness; user_data["user_agent"] = peer->user_agent; - user_data["last_known_block_hash"] = peer->last_block_delegate_has_seen; + user_data["last_known_block_hash"] = fc::variant( peer->last_block_delegate_has_seen, 1 ); user_data["last_known_block_number"] = _delegate->get_block_number(peer->last_block_delegate_has_seen); user_data["last_known_block_time"] = peer->last_block_time_delegate_has_seen; @@ -4452,7 +4452,7 @@ namespace graphene { namespace net { namespace detail { { try { - _node_configuration = fc::json::from_file( configuration_file_name ).as(); + _node_configuration = fc::json::from_file( configuration_file_name ).as(GRAPHENE_NET_MAX_NESTED_OBJECTS); ilog( "Loaded configuration from file ${filename}", ("filename", configuration_file_name ) ); if( _node_configuration.private_key == fc::ecc::private_key() ) @@ -4816,20 +4816,19 @@ namespace graphene { namespace net { namespace detail { peer_to_disconnect->send_message( closing_message ); } - // notify the user. This will be useful in testing, but we might want to remove it later; - // it makes good sense to notify the user if other nodes think she is behaving badly, but + // notify the user. This will be useful in testing, but we might want to remove it later. + // It makes good sense to notify the user if other nodes think she is behaving badly, but // if we're just detecting and dissconnecting other badly-behaving nodes, they don't really care. if (caused_by_error) { std::ostringstream error_message; - error_message << "I am disconnecting peer " << fc::variant( peer_to_disconnect->get_remote_endpoint() ).as_string() << + error_message << "I am disconnecting peer " << fc::variant( peer_to_disconnect->get_remote_endpoint(), GRAPHENE_NET_MAX_NESTED_OBJECTS ).as_string() << " for reason: " << reason_for_disconnect; _delegate->error_encountered(error_message.str(), fc::oexception()); dlog(error_message.str()); } else dlog("Disconnecting from ${peer} for ${reason}", ("peer",peer_to_disconnect->get_remote_endpoint()) ("reason",reason_for_disconnect)); - // peer_to_disconnect->close_connection(); } void node_impl::listen_on_endpoint( const fc::ip::endpoint& ep, bool wait_if_not_available ) @@ -4888,7 +4887,7 @@ namespace graphene { namespace net { namespace detail { peer_details["version"] = ""; peer_details["subver"] = peer->user_agent; peer_details["inbound"] = peer->direction == peer_connection_direction::inbound; - peer_details["firewall_status"] = peer->is_firewalled; + peer_details["firewall_status"] = fc::variant( peer->is_firewalled, 1 ); peer_details["startingheight"] = ""; peer_details["banscore"] = ""; peer_details["syncnode"] = ""; @@ -4922,7 +4921,7 @@ namespace graphene { namespace net { namespace detail { // provide these for debugging // warning: these are just approximations, if the peer is "downstream" of us, they may // have received blocks from other peers that we are unaware of - peer_details["current_head_block"] = peer->last_block_delegate_has_seen; + peer_details["current_head_block"] = fc::variant( peer->last_block_delegate_has_seen, 1 ); peer_details["current_head_block_number"] = _delegate->get_block_number(peer->last_block_delegate_has_seen); peer_details["current_head_block_time"] = peer->last_block_time_delegate_has_seen; @@ -4998,17 +4997,17 @@ namespace graphene { namespace net { namespace detail { { VERIFY_CORRECT_THREAD(); if (params.contains("peer_connection_retry_timeout")) - _peer_connection_retry_timeout = params["peer_connection_retry_timeout"].as(); + _peer_connection_retry_timeout = params["peer_connection_retry_timeout"].as(1); if (params.contains("desired_number_of_connections")) - _desired_number_of_connections = params["desired_number_of_connections"].as(); + _desired_number_of_connections = params["desired_number_of_connections"].as(1); if (params.contains("maximum_number_of_connections")) - _maximum_number_of_connections = params["maximum_number_of_connections"].as(); + _maximum_number_of_connections = params["maximum_number_of_connections"].as(1); if (params.contains("maximum_number_of_blocks_to_handle_at_one_time")) - _maximum_number_of_blocks_to_handle_at_one_time = params["maximum_number_of_blocks_to_handle_at_one_time"].as(); + _maximum_number_of_blocks_to_handle_at_one_time = params["maximum_number_of_blocks_to_handle_at_one_time"].as(1); if (params.contains("maximum_number_of_sync_blocks_to_prefetch")) - _maximum_number_of_sync_blocks_to_prefetch = params["maximum_number_of_sync_blocks_to_prefetch"].as(); + _maximum_number_of_sync_blocks_to_prefetch = params["maximum_number_of_sync_blocks_to_prefetch"].as(1); if (params.contains("maximum_blocks_per_peer_during_syncing")) - _maximum_blocks_per_peer_during_syncing = params["maximum_blocks_per_peer_during_syncing"].as(); + _maximum_blocks_per_peer_during_syncing = params["maximum_blocks_per_peer_during_syncing"].as(1); _desired_number_of_connections = std::min(_desired_number_of_connections, _maximum_number_of_connections); @@ -5093,9 +5092,9 @@ namespace graphene { namespace net { namespace detail { VERIFY_CORRECT_THREAD(); fc::mutable_variant_object info; info["listening_on"] = _actual_listening_endpoint; - info["node_public_key"] = _node_public_key; - info["node_id"] = _node_id; - info["firewalled"] = _is_firewalled; + info["node_public_key"] = fc::variant( _node_public_key, 1 ); + info["node_id"] = fc::variant( _node_id, 1 ); + info["firewalled"] = fc::variant( _is_firewalled, 1 ); return info; } fc::variant_object node_impl::network_get_usage_stats() const @@ -5123,9 +5122,9 @@ namespace graphene { namespace net { namespace detail { std::plus()); fc::mutable_variant_object result; - result["usage_by_second"] = network_usage_by_second; - result["usage_by_minute"] = network_usage_by_minute; - result["usage_by_hour"] = network_usage_by_hour; + result["usage_by_second"] = fc::variant( network_usage_by_second, 2 ); + result["usage_by_minute"] = fc::variant( network_usage_by_minute, 2 ); + result["usage_by_hour"] = fc::variant( network_usage_by_hour, 2 ); return result; } diff --git a/libraries/net/peer_database.cpp b/libraries/net/peer_database.cpp index c24568fc..2b20364e 100644 --- a/libraries/net/peer_database.cpp +++ b/libraries/net/peer_database.cpp @@ -34,8 +34,7 @@ #include #include - - +#include namespace graphene { namespace net { namespace detail @@ -81,7 +80,7 @@ namespace graphene { namespace net { public: typedef peer_database_impl::potential_peer_set::index::type::iterator last_seen_time_index_iterator; last_seen_time_index_iterator _iterator; - peer_database_iterator_impl(const last_seen_time_index_iterator& iterator) : + explicit peer_database_iterator_impl(const last_seen_time_index_iterator& iterator) : _iterator(iterator) {} }; @@ -95,9 +94,8 @@ namespace graphene { namespace net { { try { - std::vector peer_records = fc::json::from_file(_peer_database_filename).as >(); + std::vector peer_records = fc::json::from_file(_peer_database_filename).as >( GRAPHENE_NET_MAX_NESTED_OBJECTS ); std::copy(peer_records.begin(), peer_records.end(), std::inserter(_potential_peer_set, _potential_peer_set.end())); -#define MAXIMUM_PEERDB_SIZE 1000 if (_potential_peer_set.size() > MAXIMUM_PEERDB_SIZE) { // prune database to a reasonable size @@ -125,7 +123,7 @@ namespace graphene { namespace net { fc::path peer_database_filename_dir = _peer_database_filename.parent_path(); if (!fc::exists(peer_database_filename_dir)) fc::create_directories(peer_database_filename_dir); - fc::json::save_to_file(peer_records, _peer_database_filename); + fc::json::save_to_file( peer_records, _peer_database_filename, GRAPHENE_NET_MAX_NESTED_OBJECTS ); } catch (const fc::exception& e) { diff --git a/libraries/plugins/debug_witness/debug_api.cpp b/libraries/plugins/debug_witness/debug_api.cpp index 6236482b..823755f5 100644 --- a/libraries/plugins/debug_witness/debug_api.cpp +++ b/libraries/plugins/debug_witness/debug_api.cpp @@ -22,12 +22,11 @@ namespace detail { class debug_api_impl { public: - debug_api_impl( graphene::app::application& _app ); + explicit debug_api_impl( graphene::app::application& _app ); void debug_push_blocks( const std::string& src_filename, uint32_t count ); void debug_generate_blocks( const std::string& debug_key, uint32_t count ); void debug_update_object( const fc::variant_object& update ); - //void debug_save_db( std::string db_path ); void debug_stream_json_objects( const std::string& filename ); void debug_stream_json_objects_flush(); std::shared_ptr< graphene::debug_witness_plugin::debug_witness_plugin > get_plugin(); @@ -71,7 +70,6 @@ void debug_api_impl::debug_push_blocks( const std::string& src_filename, uint32_ } } ilog( "Completed loading block_database successfully" ); - return; } } @@ -93,7 +91,7 @@ void debug_api_impl::debug_generate_blocks( const std::string& debug_key, uint32 if( scheduled_key != debug_public_key ) { ilog( "Modified key for witness ${w}", ("w", scheduled_witness) ); - fc::mutable_variant_object update; + fc::limited_mutable_variant_object update( GRAPHENE_MAX_NESTED_OBJECTS ); update("_action", "update")("id", scheduled_witness)("signing_key", debug_public_key); db->debug_update( update ); } diff --git a/libraries/plugins/debug_witness/debug_witness.cpp b/libraries/plugins/debug_witness/debug_witness.cpp index 17f852c5..aea03e32 100644 --- a/libraries/plugins/debug_witness/debug_witness.cpp +++ b/libraries/plugins/debug_witness/debug_witness.cpp @@ -68,7 +68,7 @@ void debug_witness_plugin::plugin_initialize(const boost::program_options::varia const std::vector key_id_to_wif_pair_strings = options["private-key"].as>(); for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings) { - auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string); + auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string, GRAPHENE_MAX_NESTED_OBJECTS); idump((key_id_to_wif_pair)); fc::optional private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second); if (!private_key) @@ -77,7 +77,7 @@ void debug_witness_plugin::plugin_initialize(const boost::program_options::varia // just here to ease the transition, can be removed soon try { - private_key = fc::variant(key_id_to_wif_pair.second).as(); + private_key = fc::variant( key_id_to_wif_pair.second, GRAPHENE_MAX_NESTED_OBJECTS ).as( GRAPHENE_MAX_NESTED_OBJECTS ); } catch (const fc::exception&) { diff --git a/libraries/plugins/delayed_node/delayed_node_plugin.cpp b/libraries/plugins/delayed_node/delayed_node_plugin.cpp index fb70cb68..85c49c50 100644 --- a/libraries/plugins/delayed_node/delayed_node_plugin.cpp +++ b/libraries/plugins/delayed_node/delayed_node_plugin.cpp @@ -65,7 +65,7 @@ void delayed_node_plugin::plugin_set_program_options(bpo::options_description& c void delayed_node_plugin::connect() { - my->client_connection = std::make_shared(*my->client.connect(my->remote_endpoint)); + my->client_connection = std::make_shared(*my->client.connect(my->remote_endpoint), GRAPHENE_NET_MAX_NESTED_OBJECTS); my->database_api = my->client_connection->get_remote_api(0); my->client_connection_closed = my->client_connection->closed.connect([this] { connection_failed(); @@ -142,7 +142,7 @@ void delayed_node_plugin::plugin_startup() connect(); my->database_api->set_block_applied_callback([this]( const fc::variant& block_id ) { - fc::from_variant( block_id, my->last_received_remote_head ); + fc::from_variant( block_id, my->last_received_remote_head, GRAPHENE_MAX_NESTED_OBJECTS ); } ); return; } diff --git a/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp b/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp new file mode 100644 index 00000000..ef1ae04c --- /dev/null +++ b/libraries/plugins/grouped_orders/grouped_orders_plugin.cpp @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include + +#include + +namespace graphene { namespace grouped_orders { + +namespace detail +{ + +class grouped_orders_plugin_impl +{ + public: + grouped_orders_plugin_impl(grouped_orders_plugin& _plugin) + :_self( _plugin ) {} + virtual ~grouped_orders_plugin_impl(); + + graphene::chain::database& database() + { + return _self.database(); + } + + grouped_orders_plugin& _self; + flat_set _tracked_groups; +}; + +/** + * @brief This secondary index is used to track changes on limit order objects. + */ +class limit_order_group_index : public secondary_index +{ + public: + limit_order_group_index( const flat_set& groups ) : _tracked_groups( groups ) {}; + + virtual void object_inserted( const object& obj ) override; + virtual void object_removed( const object& obj ) override; + virtual void about_to_modify( const object& before ) override; + virtual void object_modified( const object& after ) override; + + const flat_set& get_tracked_groups() const + { return _tracked_groups; } + + const map< limit_order_group_key, limit_order_group_data >& get_order_groups() const + { return _og_data; } + + private: + void remove_order( const limit_order_object& obj, bool remove_empty = true ); + + /** tracked groups */ + flat_set _tracked_groups; + + /** maps the group key to group data */ + map< limit_order_group_key, limit_order_group_data > _og_data; +}; + +void limit_order_group_index::object_inserted( const object& objct ) +{ try { + const limit_order_object& o = static_cast( objct ); + + auto& idx = _og_data; + + for( uint16_t group : get_tracked_groups() ) + { + auto create_ogo = [&]() { + idx[ limit_order_group_key( group, o.sell_price ) ] = limit_order_group_data( o.sell_price, o.for_sale ); + }; + // if idx is empty, insert this order + // Note: not capped + if( idx.empty() ) + { + create_ogo(); + continue; + } + + // cap the price + price capped_price = o.sell_price; + price max = o.sell_price.max(); + price min = o.sell_price.min(); + bool capped_max = false; + bool capped_min = false; + if( o.sell_price > max ) + { + capped_price = max; + capped_max = true; + } + else if( o.sell_price < min ) + { + capped_price = min; + capped_min = true; + } + // if idx is not empty, find the group that is next to this order + auto itr = idx.lower_bound( limit_order_group_key( group, capped_price ) ); + bool check_previous = false; + if( itr == idx.end() || itr->first.group != group + || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id + || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id ) + // not same market or group type + check_previous = true; + else // same market and group type + { + bool update_max = false; + if( capped_price > itr->second.max_price ) // implies itr->min_price <= itr->max_price < max + { + update_max = true; + price max_price = itr->first.min_price * ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT ); + // max_price should have been capped here + if( capped_price > max_price ) // new order is out of range + check_previous = true; + } + if( !check_previous ) // new order is within the range + { + if( capped_min && o.sell_price < itr->first.min_price ) + { // need to update itr->min_price here, if itr is below min, and new order is even lower + // TODO improve performance + limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale ); + idx.erase( itr ); + idx[ limit_order_group_key( group, o.sell_price ) ] = data; + } + else + { + if( update_max || ( capped_max && o.sell_price > itr->second.max_price ) ) + itr->second.max_price = o.sell_price; // store real price here, not capped + itr->second.total_for_sale += o.for_sale; + } + } + } + + if( check_previous ) + { + if( itr == idx.begin() ) // no previous + create_ogo(); + else + { + --itr; // should be valid + if( itr->first.group != group || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id + || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id ) + // not same market or group type + create_ogo(); + else // same market and group type + { + // due to lower_bound, always true: capped_price < itr->first.min_price, so no need to check again, + // if new order is in range of itr group, always need to update itr->first.min_price, unless + // o.sell_price is higher than max + price min_price = itr->second.max_price / ratio_type( GRAPHENE_100_PERCENT + group, GRAPHENE_100_PERCENT ); + // min_price should have been capped here + if( capped_price < min_price ) // new order is out of range + create_ogo(); + else if( capped_max && o.sell_price >= itr->first.min_price ) + { // itr is above max, and price of new order is even higher + if( o.sell_price > itr->second.max_price ) + itr->second.max_price = o.sell_price; + itr->second.total_for_sale += o.for_sale; + } + else + { // new order is within the range + // TODO improve performance + limit_order_group_data data( itr->second.max_price, o.for_sale + itr->second.total_for_sale ); + idx.erase( itr ); + idx[ limit_order_group_key( group, o.sell_price ) ] = data; + } + } + } + } + } +} FC_CAPTURE_AND_RETHROW( (objct) ); } + +void limit_order_group_index::object_removed( const object& objct ) +{ try { + const limit_order_object& o = static_cast( objct ); + remove_order( o ); +} FC_CAPTURE_AND_RETHROW( (objct) ); } + +void limit_order_group_index::about_to_modify( const object& objct ) +{ try { + const limit_order_object& o = static_cast( objct ); + remove_order( o, false ); +} FC_CAPTURE_AND_RETHROW( (objct) ); } + +void limit_order_group_index::object_modified( const object& objct ) +{ try { + object_inserted( objct ); +} FC_CAPTURE_AND_RETHROW( (objct) ); } + +void limit_order_group_index::remove_order( const limit_order_object& o, bool remove_empty ) +{ + auto& idx = _og_data; + + for( uint16_t group : get_tracked_groups() ) + { + // find the group that should contain this order + auto itr = idx.lower_bound( limit_order_group_key( group, o.sell_price ) ); + if( itr == idx.end() || itr->first.group != group + || itr->first.min_price.base.asset_id != o.sell_price.base.asset_id + || itr->first.min_price.quote.asset_id != o.sell_price.quote.asset_id + || itr->second.max_price < o.sell_price ) + { + // can not find corresponding group, should not happen + wlog( "can not find the order group containing order for removing (price dismatch): ${o}", ("o",o) ); + continue; + } + else // found + { + if( itr->second.total_for_sale < o.for_sale ) + // should not happen + wlog( "can not find the order group containing order for removing (amount dismatch): ${o}", ("o",o) ); + else if( !remove_empty || itr->second.total_for_sale > o.for_sale ) + itr->second.total_for_sale -= o.for_sale; + else + // it's the only order in the group and need to be removed + idx.erase( itr ); + } + } +} + +grouped_orders_plugin_impl::~grouped_orders_plugin_impl() +{} + +} // end namespace detail + + +grouped_orders_plugin::grouped_orders_plugin() : + my( new detail::grouped_orders_plugin_impl(*this) ) +{ +} + +grouped_orders_plugin::~grouped_orders_plugin() +{ +} + +std::string grouped_orders_plugin::plugin_name()const +{ + return "grouped_orders"; +} + +void grouped_orders_plugin::plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg + ) +{ + cli.add_options() + ("tracked-groups", boost::program_options::value()->default_value("[10,100]"), // 0.1% and 1% + "Group orders by percentage increase on price. Specify a JSON array of numbers here, each number is a group, number 1 means 0.01%. ") + ; + cfg.add(cli); +} + +void grouped_orders_plugin::plugin_initialize(const boost::program_options::variables_map& options) +{ try { + + if( options.count( "tracked-groups" ) ) + { + const std::string& groups = options["tracked-groups"].as(); + my->_tracked_groups = fc::json::from_string(groups).as>( 2 ); + my->_tracked_groups.erase( 0 ); + } + else + my->_tracked_groups = fc::json::from_string("[10,100]").as>(2); + + database().add_secondary_index< primary_index, detail::limit_order_group_index >( my->_tracked_groups ); + +} FC_CAPTURE_AND_RETHROW() } + +void grouped_orders_plugin::plugin_startup() +{ +} + +const flat_set& grouped_orders_plugin::tracked_groups() const +{ + return my->_tracked_groups; +} + +const map< limit_order_group_key, limit_order_group_data >& grouped_orders_plugin::limit_order_groups() +{ + const auto& idx = database().get_index_type< limit_order_index >(); + const auto& pidx = dynamic_cast&>(idx); + const auto& logidx = pidx.get_secondary_index< detail::limit_order_group_index >(); + return logidx.get_order_groups(); +} + +} } diff --git a/libraries/plugins/market_history/market_history_plugin.cpp b/libraries/plugins/market_history/market_history_plugin.cpp index 6ec38968..80876a48 100644 --- a/libraries/plugins/market_history/market_history_plugin.cpp +++ b/libraries/plugins/market_history/market_history_plugin.cpp @@ -265,14 +265,15 @@ void market_history_plugin::plugin_set_program_options( void market_history_plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { - database().applied_block.connect( [&]( const signed_block& b){ my->update_market_histories(b); } ); + database().applied_block.connect( [this]( const signed_block& b){ my->update_market_histories(b); } ); database().add_index< primary_index< bucket_index > >(); database().add_index< primary_index< history_index > >(); if( options.count( "bucket-size" ) ) { - const std::string& buckets = options["bucket-size"].as(); - my->_tracked_buckets = fc::json::from_string(buckets).as>(); + const std::string& buckets = options["bucket-size"].as(); + my->_tracked_buckets = fc::json::from_string(buckets).as>(2); + my->_tracked_buckets.erase( 0 ); } if( options.count( "history-per-size" ) ) my->_maximum_history_per_bucket_size = options["history-per-size"].as(); diff --git a/libraries/plugins/witness/include/graphene/witness/witness.hpp b/libraries/plugins/witness/include/graphene/witness/witness.hpp index e2f60bf8..f0c3ece7 100644 --- a/libraries/plugins/witness/include/graphene/witness/witness.hpp +++ b/libraries/plugins/witness/include/graphene/witness/witness.hpp @@ -75,7 +75,7 @@ public: private: void schedule_production_loop(); block_production_condition::block_production_condition_enum block_production_loop(); - block_production_condition::block_production_condition_enum maybe_produce_block( fc::mutable_variant_object& capture ); + block_production_condition::block_production_condition_enum maybe_produce_block( fc::limited_mutable_variant_object& capture ); boost::program_options::variables_map _options; bool _production_enabled = false; diff --git a/libraries/plugins/witness/witness.cpp b/libraries/plugins/witness/witness.cpp index dce1234a..88b6ba3e 100644 --- a/libraries/plugins/witness/witness.cpp +++ b/libraries/plugins/witness/witness.cpp @@ -59,7 +59,6 @@ void new_chain_banner( const graphene::chain::database& db ) "\n" ; } - return; } void witness_plugin::plugin_set_program_options( @@ -101,8 +100,7 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m const std::vector key_id_to_wif_pair_strings = options["private-key"].as>(); for (const std::string& key_id_to_wif_pair_string : key_id_to_wif_pair_strings) { - auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string); - //idump((key_id_to_wif_pair)); + auto key_id_to_wif_pair = graphene::app::dejsonify >(key_id_to_wif_pair_string, 5); ilog("Public Key: ${public}", ("public", key_id_to_wif_pair.first)); fc::optional private_key = graphene::utilities::wif_to_key(key_id_to_wif_pair.second); if (!private_key) @@ -111,7 +109,7 @@ void witness_plugin::plugin_initialize(const boost::program_options::variables_m // just here to ease the transition, can be removed soon try { - private_key = fc::variant(key_id_to_wif_pair.second).as(); + private_key = fc::variant(key_id_to_wif_pair.second, 2).as(1); } catch (const fc::exception&) { @@ -147,7 +145,7 @@ void witness_plugin::plugin_startup() void witness_plugin::plugin_shutdown() { - return; + // nothing to do } void witness_plugin::schedule_production_loop() @@ -161,7 +159,6 @@ void witness_plugin::schedule_production_loop() fc::time_point next_wakeup( now + fc::microseconds( time_to_next_second ) ); - //wdump( (now.time_since_epoch().count())(next_wakeup.time_since_epoch().count()) ); _block_production_task = fc::schedule([this]{block_production_loop();}, next_wakeup, "Witness Block Production"); } @@ -169,7 +166,7 @@ void witness_plugin::schedule_production_loop() block_production_condition::block_production_condition_enum witness_plugin::block_production_loop() { block_production_condition::block_production_condition_enum result; - fc::mutable_variant_object capture; + fc::limited_mutable_variant_object capture( GRAPHENE_MAX_NESTED_OBJECTS ); try { result = maybe_produce_block(capture); @@ -197,10 +194,8 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc ilog("Not producing block because production is disabled until we receive a recent block (see: --enable-stale-production)"); break; case block_production_condition::not_my_turn: - //ilog("Not producing block because it isn't my turn"); break; case block_production_condition::not_time_yet: - //dlog("Not producing block because slot has not yet arrived"); break; case block_production_condition::no_private_key: ilog("Not producing block because I don't have the private key for ${scheduled_key}", @@ -217,7 +212,7 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc elog("Not producing block because the last block was generated by the same witness.\nThis node is probably disconnected from the network so block production has been disabled.\nDisable this check with --allow-consecutive option."); break; case block_production_condition::exception_producing_block: - elog( "exception prodcing block" ); + elog( "exception producing block" ); break; } @@ -225,7 +220,7 @@ block_production_condition::block_production_condition_enum witness_plugin::bloc return result; } -block_production_condition::block_production_condition_enum witness_plugin::maybe_produce_block( fc::mutable_variant_object& capture ) +block_production_condition::block_production_condition_enum witness_plugin::maybe_produce_block( fc::limited_mutable_variant_object& capture ) { chain::database& db = database(); fc::time_point now_fine = fc::time_point::now(); diff --git a/libraries/utilities/key_conversion.cpp b/libraries/utilities/key_conversion.cpp index e4130789..268b2b5e 100644 --- a/libraries/utilities/key_conversion.cpp +++ b/libraries/utilities/key_conversion.cpp @@ -58,7 +58,7 @@ fc::optional wif_to_key( const std::string& wif_key ) if (wif_bytes.size() < 5) return fc::optional(); std::vector key_bytes(wif_bytes.begin() + 1, wif_bytes.end() - 4); - fc::ecc::private_key key = fc::variant(key_bytes).as(); + fc::ecc::private_key key = fc::variant( key_bytes, 1 ).as( 1 ); fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); fc::sha256 check2 = fc::sha256::hash(check); diff --git a/libraries/wallet/include/graphene/wallet/reflect_util.hpp b/libraries/wallet/include/graphene/wallet/reflect_util.hpp index b8d38473..44c0f412 100644 --- a/libraries/wallet/include/graphene/wallet/reflect_util.hpp +++ b/libraries/wallet/include/graphene/wallet/reflect_util.hpp @@ -39,7 +39,6 @@ namespace impl { std::string clean_name( const std::string& name ) { - std::string result; const static std::string prefix = "graphene::chain::"; const static std::string suffix = "_operation"; // graphene::chain::.*_operation @@ -81,24 +80,25 @@ struct from_which_visitor result_type operator()( const Member& dummy ) { Member result; - from_variant( v, result ); + from_variant( v, result, _max_depth ); return result; // converted from StaticVariant to Result automatically due to return type } const variant& v; + const uint32_t _max_depth; - from_which_visitor( const variant& _v ) : v(_v) {} + from_which_visitor( const variant& _v, uint32_t max_depth ) : v(_v), _max_depth(max_depth) {} }; } // namespace impl template< typename T > -T from_which_variant( int which, const variant& v ) +T from_which_variant( int which, const variant& v, uint32_t max_depth ) { // Parse a variant for a known which() T dummy; dummy.set_which( which ); - impl::from_which_visitor< T > vtor(v); + impl::from_which_visitor< T > vtor(v, max_depth); return dummy.visit( vtor ); } diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index 5618d26a..9c47ec49 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -34,8 +34,8 @@ using namespace std; namespace fc { - void to_variant(const account_multi_index_type& accts, variant& vo); - void from_variant(const variant &var, account_multi_index_type &vo); + void to_variant( const account_multi_index_type& accts, variant& vo, uint32_t max_depth ); + void from_variant( const variant &var, account_multi_index_type &vo, uint32_t max_depth ); } namespace graphene { namespace wallet { diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 59564852..4d473df2 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -98,7 +98,7 @@ namespace detail { struct operation_result_printer { public: - operation_result_printer( const wallet_api_impl& w ) + explicit operation_result_printer( const wallet_api_impl& w ) : _wallet(w) {} const wallet_api_impl& _wallet; typedef std::string result_type; @@ -151,10 +151,10 @@ optional maybe_id( const string& name_or_id ) { try { - return fc::variant(name_or_id).as(); + return fc::variant(name_or_id, 1).as(1); } catch (const fc::exception&) - { + { // not an ID } } return optional(); @@ -641,7 +641,7 @@ public: T get_object(object_id id)const { auto ob = _remote_db->get_objects({id}).front(); - return ob.template as(); + return ob.template as( GRAPHENE_MAX_NESTED_OBJECTS ); } void set_operation_fees( signed_transaction& tx, const fee_schedule& s ) @@ -657,16 +657,16 @@ public: auto dynamic_props = get_dynamic_global_properties(); fc::mutable_variant_object result; result["head_block_num"] = dynamic_props.head_block_number; - result["head_block_id"] = dynamic_props.head_block_id; + result["head_block_id"] = fc::variant(dynamic_props.head_block_id, 1); result["head_block_age"] = fc::get_approximate_relative_time_string(dynamic_props.time, time_point_sec(time_point::now()), " old"); result["next_maintenance_time"] = fc::get_approximate_relative_time_string(dynamic_props.next_maintenance_time); result["chain_id"] = chain_props.chain_id; result["participation"] = (100*dynamic_props.recent_slots_filled.popcount()) / 128.0; - result["active_witnesses"] = global_props.active_witnesses; - result["active_committee_members"] = global_props.active_committee_members; - result["entropy"] = dynamic_props.random; + result["active_witnesses"] = fc::variant(global_props.active_witnesses, GRAPHENE_MAX_NESTED_OBJECTS); + result["active_committee_members"] = fc::variant(global_props.active_committee_members, GRAPHENE_MAX_NESTED_OBJECTS); + result["entropy"] = fc::variant(dynamic_props.random, GRAPHENE_MAX_NESTED_OBJECTS); return result; } @@ -801,7 +801,7 @@ public: FC_ASSERT( asset_symbol_or_id.size() > 0 ); vector> opt_asset; if( std::isdigit( asset_symbol_or_id.front() ) ) - return fc::variant(asset_symbol_or_id).as(); + return fc::variant(asset_symbol_or_id, 1).as( 1 ); opt_asset = _remote_db->lookup_asset_symbols( {asset_symbol_or_id} ); FC_ASSERT( (opt_asset.size() > 0) && (opt_asset[0].valid()) ); return opt_asset[0]->id; @@ -1013,7 +1013,7 @@ public: if( ! fc::exists( wallet_filename ) ) return false; - _wallet = fc::json::from_file( wallet_filename ).as< wallet_data >(); + _wallet = fc::json::from_file( wallet_filename ).as< wallet_data >( 2 * GRAPHENE_MAX_NESTED_OBJECTS ); if( _wallet.chain_id != _chain_id ) FC_THROW( "Wallet chain ID does not match", ("wallet.chain_id", _wallet.chain_id) @@ -1843,7 +1843,6 @@ public: { try { witness_object witness = get_witness(witness_name); account_object witness_account = get_account( witness.witness_account ); - fc::ecc::private_key active_private_key = get_private_key_for_account(witness_account); witness_update_operation witness_update_op; witness_update_op.witness = witness.id; @@ -1867,7 +1866,7 @@ public: static WorkerInit _create_worker_initializer( const variant& worker_settings ) { WorkerInit result; - from_variant( worker_settings, result ); + from_variant( worker_settings, result, GRAPHENE_MAX_NESTED_OBJECTS ); return result; } @@ -1921,7 +1920,6 @@ public: ) { account_object acct = get_account( account ); - account_update_operation op; // you could probably use a faster algorithm for this, but flat_set is fast enough :) flat_set< worker_id_type > merged; @@ -1955,7 +1953,7 @@ public: for( const variant& obj : objects ) { worker_object wo; - from_variant( obj, wo ); + from_variant( obj, wo, GRAPHENE_MAX_NESTED_OBJECTS ); new_votes.erase( wo.vote_for ); new_votes.erase( wo.vote_against ); if( delta.vote_for.find( wo.id ) != delta.vote_for.end() ) @@ -2485,7 +2483,7 @@ public: m["get_account_history"] = [this](variant result, const fc::variants& a) { - auto r = result.as>(); + auto r = result.as>( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; for( operation_detail& d : r ) @@ -2502,7 +2500,7 @@ public: }; m["get_relative_account_history"] = [this](variant result, const fc::variants& a) { - auto r = result.as>(); + auto r = result.as>( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; for( operation_detail& d : r ) @@ -2518,9 +2516,32 @@ public: return ss.str(); }; + m["get_account_history_by_operations"] = [this](variant result, const fc::variants& a) { + auto r = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); + std::stringstream ss; + ss << "total_count : "; + ss << r.total_count; + ss << " \n"; + ss << "result_count : "; + ss << r.result_count; + ss << " \n"; + for (operation_detail_ex& d : r.details) { + operation_history_object& i = d.op; + auto b = _remote_db->get_block_header(i.block_num); + FC_ASSERT(b); + ss << b->timestamp.to_iso_string() << " "; + i.op.visit(operation_printer(ss, *this, i.result)); + ss << " transaction_id : "; + ss << d.transaction_id.str(); + ss << " \n"; + } + + return ss.str(); + }; + m["list_account_balances"] = [this](variant result, const fc::variants& a) { - auto r = result.as>(); + auto r = result.as>( GRAPHENE_MAX_NESTED_OBJECTS ); vector asset_recs; std::transform(r.begin(), r.end(), std::back_inserter(asset_recs), [this](const asset& a) { return get_asset(a.asset_id); @@ -2550,7 +2571,7 @@ public: m["get_blind_balances"] = [this](variant result, const fc::variants& a) { - auto r = result.as>(); + auto r = result.as>( GRAPHENE_MAX_NESTED_OBJECTS ); vector asset_recs; std::transform(r.begin(), r.end(), std::back_inserter(asset_recs), [this](const asset& a) { return get_asset(a.asset_id); @@ -2564,7 +2585,7 @@ public: }; m["transfer_to_blind"] = [this](variant result, const fc::variants& a) { - auto r = result.as(); + auto r = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; r.trx.operations[0].visit( operation_printer( ss, *this, operation_result() ) ); ss << "\n"; @@ -2577,7 +2598,7 @@ public: }; m["blind_transfer"] = [this](variant result, const fc::variants& a) { - auto r = result.as(); + auto r = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; r.trx.operations[0].visit( operation_printer( ss, *this, operation_result() ) ); ss << "\n"; @@ -2590,7 +2611,7 @@ public: }; m["receive_blind_transfer"] = [this](variant result, const fc::variants& a) { - auto r = result.as(); + auto r = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; asset_object as = get_asset( r.amount.asset_id ); ss << as.amount_to_pretty_string( r.amount ) << " " << r.from_label << " => " << r.to_label << " " << r.memo <<"\n"; @@ -2598,7 +2619,7 @@ public: }; m["blind_history"] = [this](variant result, const fc::variants& a) { - auto records = result.as>(); + auto records = result.as>( GRAPHENE_MAX_NESTED_OBJECTS ); std::stringstream ss; ss << "WHEN " << " " << "AMOUNT" << " " << "FROM" << " => " << "TO" << " " << "MEMO" <<"\n"; @@ -2762,7 +2783,7 @@ public: }; m["get_order_book"] = [this](variant result, const fc::variants& a) { - auto orders = result.as(); + auto orders = result.as( GRAPHENE_MAX_NESTED_OBJECTS ); auto bids = orders.bids; auto asks = orders.asks; std::stringstream ss; @@ -2772,12 +2793,10 @@ public: double ask_sum = 0; const int spacing = 20; - auto prettify_num = [&]( double n ) + auto prettify_num = [&ss]( double n ) { - //ss << n; if (abs( round( n ) - n ) < 0.00000000001 ) { - //ss << setiosflags( !ios::fixed ) << (int) n; // doesn't compile on Linux with gcc ss << (int) n; } else if (n - floor(n) < 0.000001) @@ -2859,7 +2878,7 @@ public: const chain_parameters& current_params = get_global_properties().parameters; chain_parameters new_params = current_params; fc::reflector::visit( - fc::from_variant_visitor( changed_values, new_params ) + fc::from_variant_visitor( changed_values, new_params, GRAPHENE_MAX_NESTED_OBJECTS ) ); committee_member_update_global_parameters_operation update_op; @@ -2909,7 +2928,7 @@ public: continue; } // is key a number? - auto is_numeric = [&]() -> bool + auto is_numeric = [&key]() -> bool { size_t n = key.size(); for( size_t i=0; isecond; } - fee_parameters fp = from_which_variant< fee_parameters >( which, item.value() ); + fee_parameters fp = from_which_variant< fee_parameters >( which, item.value(), GRAPHENE_MAX_NESTED_OBJECTS ); fee_map[ which ] = fp; } @@ -3013,7 +3032,7 @@ public: proposal_update_operation update_op; update_op.fee_paying_account = get_account(fee_paying_account).id; - update_op.proposal = fc::variant(proposal_id).as(); + update_op.proposal = fc::variant(proposal_id, 1).as( 1 ); // make sure the proposal exists get_object( update_op.proposal ); @@ -3140,7 +3159,7 @@ public: for( const auto& peer : peers ) { variant v; - fc::to_variant( peer, v ); + fc::to_variant( peer, v, GRAPHENE_MAX_NESTED_OBJECTS ); result.push_back( v ); } return result; @@ -3153,7 +3172,6 @@ public: const account_object& master = *_wallet.my_accounts.get().lower_bound("import"); int number_of_accounts = number_of_transactions / 3; number_of_transactions -= number_of_accounts; - //auto key = derive_private_key("floodshill", 0); try { dbg_make_uia(master.name, "SHILL"); } catch(...) {/* Ignore; the asset probably already exists.*/} @@ -4621,7 +4639,7 @@ string wallet_api::get_private_key( public_key_type pubkey )const public_key_type wallet_api::get_public_key( string label )const { - try { return fc::variant(label).as(); } catch ( ... ){} + try { return fc::variant(label, 1).as( 1 ); } catch ( ... ){} auto key_itr = my->_wallet.labeled_keys.get().find(label); if( key_itr != my->_wallet.labeled_keys.get().end() ) @@ -5911,13 +5929,15 @@ vesting_balance_object_with_info::vesting_balance_object_with_info( const vestin } } // graphene::wallet -void fc::to_variant(const account_multi_index_type& accts, fc::variant& vo) -{ - vo = vector(accts.begin(), accts.end()); -} +namespace fc { + void to_variant( const account_multi_index_type& accts, variant& vo, uint32_t max_depth ) + { + to_variant( std::vector(accts.begin(), accts.end()), vo, max_depth ); + } -void fc::from_variant(const fc::variant& var, account_multi_index_type& vo) -{ - const vector& v = var.as>(); - vo = account_multi_index_type(v.begin(), v.end()); + void from_variant( const variant& var, account_multi_index_type& vo, uint32_t max_depth ) + { + const std::vector& v = var.as>( max_depth ); + vo = account_multi_index_type(v.begin(), v.end()); + } } diff --git a/programs/build_helpers/member_enumerator.cpp b/programs/build_helpers/member_enumerator.cpp index 8ad26633..915d7edf 100644 --- a/programs/build_helpers/member_enumerator.cpp +++ b/programs/build_helpers/member_enumerator.cpp @@ -37,7 +37,7 @@ namespace graphene { namespace member_enumerator { struct class_processor { - class_processor( std::map< std::string, std::vector< std::string > >& r ) : result(r) {} + explicit class_processor( std::map< std::string, std::vector< std::string > >& r ) : result(r) {} template< typename T > void process_class( const T* dummy ); @@ -84,7 +84,7 @@ struct member_visitor struct static_variant_visitor { - static_variant_visitor( class_processor* p ) : proc(p) {} + explicit static_variant_visitor( class_processor* p ) : proc(p) {} typedef void result_type; @@ -215,13 +215,12 @@ int main( int argc, char** argv ) { std::map< std::string, std::vector< std::string > > result; graphene::member_enumerator::class_processor::process_class(result); - //graphene::member_enumerator::process_class(result); fc::mutable_variant_object mvo; for( const std::pair< std::string, std::vector< std::string > >& e : result ) { variant v; - to_variant( e.second, v ); + to_variant( e.second, v , 1); mvo.set( e.first, v ); } diff --git a/programs/cli_wallet/main.cpp b/programs/cli_wallet/main.cpp index 0155897c..d1d34af7 100644 --- a/programs/cli_wallet/main.cpp +++ b/programs/cli_wallet/main.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -108,8 +109,8 @@ int main( int argc, char** argv ) std::cout << "Logging RPC to file: " << (data_dir / ac.filename).preferred_string() << "\n"; - cfg.appenders.push_back(fc::appender_config( "default", "console", fc::variant(fc::console_appender::config()))); - cfg.appenders.push_back(fc::appender_config( "rpc", "file", fc::variant(ac))); + cfg.appenders.push_back(fc::appender_config( "default", "console", fc::variant(fc::console_appender::config(), 20))); + cfg.appenders.push_back(fc::appender_config( "rpc", "file", fc::variant(ac, 5))); cfg.loggers = { fc::logger_config("default"), fc::logger_config( "rpc") }; cfg.loggers.front().level = fc::log_level::info; @@ -117,8 +118,6 @@ int main( int argc, char** argv ) cfg.loggers.back().level = fc::log_level::debug; cfg.loggers.back().appenders = {"rpc"}; - //fc::configure_logging( cfg ); - fc::ecc::private_key committee_private_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key"))); idump( (key_to_wif( committee_private_key ) ) ); @@ -139,7 +138,7 @@ int main( int argc, char** argv ) fc::path wallet_file( options.count("wallet-file") ? options.at("wallet-file").as() : "wallet.json"); if( fc::exists( wallet_file ) ) { - wdata = fc::json::from_file( wallet_file ).as(); + wdata = fc::json::from_file( wallet_file ).as( GRAPHENE_MAX_NESTED_OBJECTS ); if( options.count("chain-id") ) { // the --chain-id on the CLI must match the chain ID embedded in the wallet file @@ -175,12 +174,11 @@ int main( int argc, char** argv ) fc::http::websocket_client client; idump((wdata.ws_server)); auto con = client.connect( wdata.ws_server ); - auto apic = std::make_shared(*con); + auto apic = std::make_shared(*con, GRAPHENE_MAX_NESTED_OBJECTS); auto remote_api = apic->get_remote_api< login_api >(1); edump((wdata.ws_user)(wdata.ws_password) ); - // TODO: Error message here - FC_ASSERT( remote_api->login( wdata.ws_user, wdata.ws_password ) ); + FC_ASSERT( remote_api->login( wdata.ws_user, wdata.ws_password ), "Failed to log in to API server" ); auto wapiptr = std::make_shared( wdata, remote_api ); wapiptr->set_wallet_filename( wallet_file.generic_string() ); @@ -188,11 +186,11 @@ int main( int argc, char** argv ) fc::api wapi(wapiptr); - auto wallet_cli = std::make_shared(); + auto wallet_cli = std::make_shared( GRAPHENE_MAX_NESTED_OBJECTS ); for( auto& name_formatter : wapiptr->get_result_formatters() ) wallet_cli->format_result( name_formatter.first, name_formatter.second ); - boost::signals2::scoped_connection closed_connection(con->closed.connect([=]{ + boost::signals2::scoped_connection closed_connection(con->closed.connect([wallet_cli]{ cerr << "Server has disconnected us.\n"; wallet_cli->stop(); })); @@ -212,10 +210,10 @@ int main( int argc, char** argv ) auto _websocket_server = std::make_shared(); if( options.count("rpc-endpoint") ) { - _websocket_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){ + _websocket_server->on_connection([&wapi]( const fc::http::websocket_connection_ptr& c ){ std::cout << "here... \n"; wlog("." ); - auto wsc = std::make_shared(*c); + auto wsc = std::make_shared(*c, GRAPHENE_MAX_NESTED_OBJECTS); wsc->register_api(wapi); c->set_session_data( wsc ); }); @@ -231,8 +229,8 @@ int main( int argc, char** argv ) auto _websocket_tls_server = std::make_shared(cert_pem); if( options.count("rpc-tls-endpoint") ) { - _websocket_tls_server->on_connection([&]( const fc::http::websocket_connection_ptr& c ){ - auto wsc = std::make_shared(*c); + _websocket_tls_server->on_connection([&wapi]( const fc::http::websocket_connection_ptr& c ){ + auto wsc = std::make_shared(*c, GRAPHENE_MAX_NESTED_OBJECTS); wsc->register_api(wapi); c->set_session_data( wsc ); }); @@ -250,10 +248,10 @@ int main( int argc, char** argv ) // due to implementation, on_request() must come AFTER listen() // _http_server->on_request( - [&]( const fc::http::request& req, const fc::http::server::response& resp ) + [&wapi]( const fc::http::request& req, const fc::http::server::response& resp ) { std::shared_ptr< fc::rpc::http_api_connection > conn = - std::make_shared< fc::rpc::http_api_connection>(); + std::make_shared< fc::rpc::http_api_connection >( GRAPHENE_MAX_NESTED_OBJECTS ); conn->register_api( wapi ); conn->on_request( req, resp ); } ); diff --git a/programs/delayed_node/main.cpp b/programs/delayed_node/main.cpp index 74cd8fc3..112b7dee 100644 --- a/programs/delayed_node/main.cpp +++ b/programs/delayed_node/main.cpp @@ -246,8 +246,8 @@ fc::optional load_logging_config_from_ini_file(const fc::pat console_appender_config.level_colors.emplace_back( fc::console_appender::level_color(fc::log_level::error, fc::console_appender::color::cyan)); - console_appender_config.stream = fc::variant(stream_name).as(); - logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config))); + console_appender_config.stream = fc::variant(stream_name, 1).as(1); + logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config, GRAPHENE_MAX_NESTED_OBJECTS))); found_logging_config = true; } else if (boost::starts_with(section_name, file_appender_section_prefix)) @@ -266,7 +266,7 @@ fc::optional load_logging_config_from_ini_file(const fc::pat file_appender_config.rotate = true; file_appender_config.rotation_interval = fc::hours(1); file_appender_config.rotation_limit = fc::days(1); - logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config))); + logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config, GRAPHENE_MAX_NESTED_OBJECTS))); found_logging_config = true; } else if (boost::starts_with(section_name, logger_section_prefix)) @@ -275,7 +275,7 @@ fc::optional load_logging_config_from_ini_file(const fc::pat std::string level_string = section_tree.get("level"); std::string appenders_string = section_tree.get("appenders"); fc::logger_config logger_config(logger_name); - logger_config.level = fc::variant(level_string).as(); + logger_config.level = fc::variant(level_string, 1).as(1); boost::split(logger_config.appenders, appenders_string, boost::is_any_of(" ,"), boost::token_compress_on); diff --git a/programs/genesis_util/genesis_update.cpp b/programs/genesis_util/genesis_update.cpp index 52329301..e753b8b7 100644 --- a/programs/genesis_util/genesis_update.cpp +++ b/programs/genesis_util/genesis_update.cpp @@ -110,7 +110,7 @@ int main( int argc, char** argv ) std::cerr << "update_genesis: Reading genesis from file " << genesis_json_filename.preferred_string() << "\n"; std::string genesis_json; read_file_contents( genesis_json_filename, genesis_json ); - genesis = fc::json::from_string( genesis_json ).as< genesis_state_type >(); + genesis = fc::json::from_string( genesis_json ).as< genesis_state_type >(20); } else { @@ -120,8 +120,8 @@ int main( int argc, char** argv ) if (!options.count("nop")) { - std::string dev_key_prefix = options["dev-key-prefix"].as(); - auto get_dev_key = [&]( std::string prefix, uint32_t i ) -> public_key_type + const std::string dev_key_prefix = options["dev-key-prefix"].as(); + auto get_dev_key = [&dev_key_prefix]( std::string prefix, uint32_t i ) -> public_key_type { return fc::ecc::private_key::regenerate( fc::sha256::hash( dev_key_prefix + prefix + std::to_string(i) ) ).get_public_key(); }; diff --git a/programs/genesis_util/get_dev_key.cpp b/programs/genesis_util/get_dev_key.cpp index c82e6a60..ea7cdf9f 100644 --- a/programs/genesis_util/get_dev_key.cpp +++ b/programs/genesis_util/get_dev_key.cpp @@ -70,9 +70,9 @@ int main( int argc, char** argv ) bool comma = false; - auto show_key = [&]( const fc::ecc::private_key& priv_key ) + auto show_key = [&comma]( const fc::ecc::private_key& priv_key ) { - fc::mutable_variant_object mvo; + fc::limited_mutable_variant_object mvo(5); graphene::chain::public_key_type pub_key = priv_key.get_public_key(); mvo( "private_key", graphene::utilities::key_to_wif( priv_key ) ) ( "public_key", std::string( pub_key ) ) @@ -80,7 +80,7 @@ int main( int argc, char** argv ) ; if( comma ) std::cout << ",\n"; - std::cout << fc::json::to_string( mvo ); + std::cout << fc::json::to_string( fc::mutable_variant_object(mvo) ); comma = true; }; @@ -90,7 +90,7 @@ int main( int argc, char** argv ) { std::string arg = argv[i]; std::string prefix; - int lep = -1, rep; + int lep = -1, rep = -1; auto dash_pos = arg.rfind('-'); if( dash_pos != string::npos ) { @@ -104,7 +104,6 @@ int main( int argc, char** argv ) rep = std::stoi( rhs.substr( colon_pos+1 ) ); } } - vector< fc::ecc::private_key > keys; if( lep >= 0 ) { for( int k=lep; k load_logging_config_from_ini_file(const fc::pat console_appender_config.level_colors.emplace_back( fc::console_appender::level_color(fc::log_level::error, fc::console_appender::color::cyan)); - console_appender_config.stream = fc::variant(stream_name).as(); - logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config))); + console_appender_config.stream = fc::variant(stream_name).as(GRAPHENE_MAX_NESTED_OBJECTS); + logging_config.appenders.push_back(fc::appender_config(console_appender_name, "console", fc::variant(console_appender_config, GRAPHENE_MAX_NESTED_OBJECTS))); found_logging_config = true; } else if (boost::starts_with(section_name, file_appender_section_prefix)) @@ -312,7 +312,7 @@ fc::optional load_logging_config_from_ini_file(const fc::pat file_appender_config.rotate = true; file_appender_config.rotation_interval = fc::hours(1); file_appender_config.rotation_limit = fc::days(1); - logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config))); + logging_config.appenders.push_back(fc::appender_config(file_appender_name, "file", fc::variant(file_appender_config, GRAPHENE_MAX_NESTED_OBJECTS))); found_logging_config = true; } else if (boost::starts_with(section_name, logger_section_prefix)) @@ -321,7 +321,7 @@ fc::optional load_logging_config_from_ini_file(const fc::pat std::string level_string = section_tree.get("level"); std::string appenders_string = section_tree.get("appenders"); fc::logger_config logger_config(logger_name); - logger_config.level = fc::variant(level_string).as(); + logger_config.level = fc::variant(level_string).as(5); boost::split(logger_config.appenders, appenders_string, boost::is_any_of(" ,"), boost::token_compress_on); diff --git a/tests/generate_empty_blocks/main.cpp b/tests/generate_empty_blocks/main.cpp index 1b45340d..f01a5495 100644 --- a/tests/generate_empty_blocks/main.cpp +++ b/tests/generate_empty_blocks/main.cpp @@ -102,7 +102,7 @@ int main( int argc, char** argv ) std::cerr << "embed_genesis: Reading genesis from file " << genesis_json_filename.preferred_string() << "\n"; std::string genesis_json; read_file_contents( genesis_json_filename, genesis_json ); - genesis = fc::json::from_string( genesis_json ).as< genesis_state_type >(); + genesis = fc::json::from_string( genesis_json ).as< genesis_state_type >(20); } else genesis = graphene::app::detail::create_example_genesis(); @@ -119,7 +119,6 @@ int main( int argc, char** argv ) uint32_t num_blocks = options["num-blocks"].as(); uint32_t miss_rate = options["miss-rate"].as(); - fc::ecc::private_key init_account_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("null_key")) ); fc::ecc::private_key nathan_priv_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); database db; diff --git a/tests/tests/serialization_tests.cpp b/tests/tests/serialization_tests.cpp index fb87c4c4..59e16f01 100644 --- a/tests/tests/serialization_tests.cpp +++ b/tests/tests/serialization_tests.cpp @@ -64,8 +64,8 @@ BOOST_AUTO_TEST_CASE( serialization_json_test ) op.to = account_id_type(2); op.amount = asset(100); trx.operations.push_back( op ); - fc::variant packed(trx); - signed_transaction unpacked = packed.as(); + fc::variant packed(trx, GRAPHENE_MAX_NESTED_OBJECTS); + signed_transaction unpacked = packed.as( GRAPHENE_MAX_NESTED_OBJECTS ); unpacked.validate(); BOOST_CHECK( digest(trx) == digest(unpacked) ); } catch (fc::exception& e) {