diff --git a/libraries/app/CMakeLists.txt b/libraries/app/CMakeLists.txt index 93e540f9..d66b4052 100644 --- a/libraries/app/CMakeLists.txt +++ b/libraries/app/CMakeLists.txt @@ -5,7 +5,6 @@ add_library( graphene_app api.cpp application.cpp database_api.cpp - impacted.cpp plugin.cpp config_util.cpp ${HEADERS} @@ -14,7 +13,7 @@ add_library( graphene_app # need to link graphene_debug_witness because plugins aren't sufficiently isolated #246 #target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_chain fc graphene_db graphene_net graphene_utilities graphene_debug_witness ) -target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness graphene_bookie ) +target_link_libraries( graphene_app graphene_market_history graphene_account_history graphene_accounts_list graphene_affiliate_stats graphene_chain fc graphene_db graphene_net graphene_time graphene_utilities graphene_debug_witness graphene_bookie graphene_elasticsearch ) target_include_directories( graphene_app PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../egenesis/include" ) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 29a4edf9..c808a27c 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -40,8 +39,19 @@ #include #include +#include #include +template class fc::api; +template class fc::api; +template class fc::api; +template class fc::api; +template class fc::api; +template class fc::api; +template class fc::api; +template class fc::api; + + namespace graphene { namespace app { login_api::login_api(application& a) @@ -570,6 +580,18 @@ namespace graphene { namespace app { start = node.operation_id; } catch(...) { return result; } + if(_app.is_plugin_enabled("elasticsearch")) { + auto es = _app.get_plugin("elasticsearch"); + if(es.get()->get_running_mode() != elasticsearch::mode::only_save) { + if(!_app.elasticsearch_thread) + _app.elasticsearch_thread= std::make_shared("elasticsearch"); + + return _app.elasticsearch_thread->async([&es, &account, &stop, &limit, &start]() { + return es->get_account_history(account, stop, limit, start); + }, "thread invoke for method " BOOST_PP_STRINGIZE(method_name)).wait(); + } + } + const auto& hist_idx = db.get_index_type(); const auto& by_op_idx = hist_idx.indices().get(); auto index_start = by_op_idx.begin(); diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index bcbe6659..adfd8402 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -891,7 +891,8 @@ namespace detail { std::shared_ptr _websocket_server; std::shared_ptr _websocket_tls_server; - std::map> _plugins; + std::map> _active_plugins; + std::map> _available_plugins; bool _is_finished_syncing = false; }; @@ -933,6 +934,7 @@ void application::set_program_options(boost::program_options::options_descriptio ("enable-standby-votes-tracking", bpo::value()->implicit_value(true), "Whether to enable tracking of votes of standby witnesses and committee members. " "Set it to true to provide accurate data to API clients, set to false for slightly better performance.") + ("plugins", bpo::value(), "Space-separated list of plugins to activate") ; command_line_options.add(configuration_file_options); command_line_options.add_options() @@ -978,6 +980,33 @@ void application::initialize(const fc::path& data_dir, const boost::program_opti std::exit(EXIT_SUCCESS); } + + std::vector wanted; + if( options.count("plugins") ) + { + boost::split(wanted, options.at("plugins").as(), [](char c){return c == ' ';}); + } + else + { + wanted.push_back("witness"); + wanted.push_back("account_history"); + wanted.push_back("market_history"); + wanted.push_back("bookie"); + } + int es_ah_conflict_counter = 0; + for (auto& it : wanted) + { + if(it == "account_history") + ++es_ah_conflict_counter; + if(it == "elasticsearch") + ++es_ah_conflict_counter; + + if(es_ah_conflict_counter > 1) { + elog("Can't start program with elasticsearch and account_history plugin at the same time"); + std::exit(EXIT_FAILURE); + } + if (!it.empty()) enable_plugin(it); + } } void application::startup() @@ -995,7 +1024,12 @@ void application::startup() std::shared_ptr application::get_plugin(const string& name) const { - return my->_plugins[name]; + return my->_active_plugins[name]; +} + +bool application::is_plugin_enabled(const string& name) const +{ + return !(my->_active_plugins.find(name) == my->_active_plugins.end()); } net::node_ptr application::p2p_node() @@ -1028,14 +1062,21 @@ bool application::is_finished_syncing() const return my->_is_finished_syncing; } -void graphene::app::application::add_plugin(const string& name, std::shared_ptr p) +void graphene::app::application::enable_plugin(const string& name) { - my->_plugins[name] = p; + FC_ASSERT(my->_available_plugins[name], "Unknown plugin '" + name + "'"); + my->_active_plugins[name] = my->_available_plugins[name]; + my->_active_plugins[name]->plugin_set_app(this); +} + +void graphene::app::application::add_available_plugin(std::shared_ptr p) +{ + my->_available_plugins[p->plugin_name()] = p; } void application::shutdown_plugins() { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_shutdown(); return; } @@ -1049,14 +1090,14 @@ void application::shutdown() void application::initialize_plugins( const boost::program_options::variables_map& options ) { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_initialize( options ); return; } void application::startup_plugins() { - for( auto& entry : my->_plugins ) + for( auto& entry : my->_active_plugins ) entry.second->plugin_startup(); return; } diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index c7d63ad5..df6458f3 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -26,11 +26,15 @@ #include #include #include +#include +#include #include #include #include +#include +#include #include #include @@ -45,6 +49,8 @@ typedef std::map< std::pair, std::vector > market_queue_type; +template class fc::api; + namespace graphene { namespace app { class database_api_impl : public std::enable_shared_from_this @@ -2272,7 +2278,28 @@ graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type } #endif + vector account_vbos; + const time_point_sec now = _db.head_block_time(); + auto vesting_range = _db.get_index_type().indices().get().equal_range(account); + std::for_each(vesting_range.first, vesting_range.second, + [&account_vbos, now](const vesting_balance_object& balance) { + if(balance.balance.amount > 0 && balance.balance_type == vesting_balance_type::gpos + && balance.balance.asset_id == asset_id_type()) + account_vbos.emplace_back(balance); + }); + + share_type allowed_withdraw_amount = 0, account_vested_balance = 0; + + for (const vesting_balance_object& vesting_balance_obj : account_vbos) + { + account_vested_balance += vesting_balance_obj.balance.amount; + if(vesting_balance_obj.is_withdraw_allowed(_db.head_block_time(), vesting_balance_obj.balance.amount)) + allowed_withdraw_amount += vesting_balance_obj.balance.amount; + } + result.total_amount = total_amount; + result.allowed_withdraw_amount = allowed_withdraw_amount; + result.account_vested_balance = account_vested_balance; return result; } diff --git a/libraries/app/impacted.cpp b/libraries/app/impacted.cpp deleted file mode 100644 index 08253417..00000000 --- a/libraries/app/impacted.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (c) 2015 Cryptonomex, Inc., 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 app { - -using namespace fc; -using namespace graphene::chain; - -// TODO: Review all of these, especially no-ops -struct get_impacted_account_visitor -{ - flat_set& _impacted; - get_impacted_account_visitor( flat_set& impact ):_impacted(impact) {} - typedef void result_type; - - void operator()( const transfer_operation& op ) - { - _impacted.insert( op.to ); - } - - void operator()( const asset_claim_fees_operation& op ){} - void operator()( const limit_order_create_operation& op ) {} - void operator()( const limit_order_cancel_operation& op ) - { - _impacted.insert( op.fee_paying_account ); - } - void operator()( const call_order_update_operation& op ) {} - void operator()( const fill_order_operation& op ) - { - _impacted.insert( op.account_id ); - } - - void operator()( const account_create_operation& op ) - { - _impacted.insert( op.registrar ); - _impacted.insert( op.referrer ); - add_authority_accounts( _impacted, op.owner ); - add_authority_accounts( _impacted, op.active ); - } - - void operator()( const account_update_operation& op ) - { - _impacted.insert( op.account ); - if( op.owner ) - add_authority_accounts( _impacted, *(op.owner) ); - if( op.active ) - add_authority_accounts( _impacted, *(op.active) ); - } - - void operator()( const account_whitelist_operation& op ) - { - _impacted.insert( op.account_to_list ); - } - - void operator()( const account_upgrade_operation& op ) {} - void operator()( const account_transfer_operation& op ) - { - _impacted.insert( op.new_owner ); - } - - void operator()( const asset_create_operation& op ) {} - void operator()( const asset_update_operation& op ) - { - if( op.new_issuer ) - _impacted.insert( *(op.new_issuer) ); - } - - void operator()( const asset_update_bitasset_operation& op ) {} - void operator()( const asset_update_dividend_operation& op ) {} - void operator()( const asset_dividend_distribution_operation& op ) - { - _impacted.insert( op.account_id ); - } - - void operator()( const asset_update_feed_producers_operation& op ) {} - - void operator()( const asset_issue_operation& op ) - { - _impacted.insert( op.issue_to_account ); - } - - void operator()( const asset_reserve_operation& op ) {} - void operator()( const asset_fund_fee_pool_operation& op ) {} - void operator()( const asset_settle_operation& op ) {} - void operator()( const asset_global_settle_operation& op ) {} - void operator()( const asset_publish_feed_operation& op ) {} - void operator()( const witness_create_operation& op ) - { - _impacted.insert( op.witness_account ); - } - void operator()( const witness_update_operation& op ) - { - _impacted.insert( op.witness_account ); - } - - void operator()( const proposal_create_operation& op ) - { - vector other; - for( const auto& proposed_op : op.proposed_ops ) - operation_get_required_authorities( proposed_op.op, _impacted, _impacted, other ); - for( auto& o : other ) - add_authority_accounts( _impacted, o ); - } - - void operator()( const proposal_update_operation& op ) {} - void operator()( const proposal_delete_operation& op ) {} - - void operator()( const withdraw_permission_create_operation& op ) - { - _impacted.insert( op.authorized_account ); - } - - void operator()( const withdraw_permission_update_operation& op ) - { - _impacted.insert( op.authorized_account ); - } - - void operator()( const withdraw_permission_claim_operation& op ) - { - _impacted.insert( op.withdraw_from_account ); - } - - void operator()( const withdraw_permission_delete_operation& op ) - { - _impacted.insert( op.authorized_account ); - } - - void operator()( const committee_member_create_operation& op ) - { - _impacted.insert( op.committee_member_account ); - } - void operator()( const committee_member_update_operation& op ) - { - _impacted.insert( op.committee_member_account ); - } - void operator()( const committee_member_update_global_parameters_operation& op ) {} - - void operator()( const vesting_balance_create_operation& op ) - { - _impacted.insert( op.owner ); - } - - void operator()( const vesting_balance_withdraw_operation& op ) {} - void operator()( const worker_create_operation& op ) {} - void operator()( const custom_operation& op ) {} - void operator()( const assert_operation& op ) {} - void operator()( const balance_claim_operation& op ) {} - - void operator()( const override_transfer_operation& op ) - { - _impacted.insert( op.to ); - _impacted.insert( op.from ); - _impacted.insert( op.issuer ); - } - - void operator()( const transfer_to_blind_operation& op ) - { - _impacted.insert( op.from ); - for( const auto& out : op.outputs ) - add_authority_accounts( _impacted, out.owner ); - } - - void operator()( const blind_transfer_operation& op ) - { - for( const auto& in : op.inputs ) - add_authority_accounts( _impacted, in.owner ); - for( const auto& out : op.outputs ) - add_authority_accounts( _impacted, out.owner ); - } - - void operator()( const transfer_from_blind_operation& op ) - { - _impacted.insert( op.to ); - for( const auto& in : op.inputs ) - add_authority_accounts( _impacted, in.owner ); - } - - void operator()( const asset_settle_cancel_operation& op ) - { - _impacted.insert( op.account ); - } - - void operator()( const fba_distribute_operation& op ) - { - _impacted.insert( op.account_id ); - } - - void operator()( const sport_create_operation& op ) {} - void operator()( const sport_update_operation& op ) {} - void operator()( const sport_delete_operation& op ) {} - void operator()( const event_group_create_operation& op ) {} - void operator()( const event_group_update_operation& op ) {} - void operator()( const event_group_delete_operation& op ) {} - void operator()( const event_create_operation& op ) {} - void operator()( const event_update_operation& op ) {} - void operator()( const event_update_status_operation& op ) {} - void operator()( const betting_market_rules_create_operation& op ) {} - void operator()( const betting_market_rules_update_operation& op ) {} - void operator()( const betting_market_group_create_operation& op ) {} - void operator()( const betting_market_group_update_operation& op ) {} - void operator()( const betting_market_create_operation& op ) {} - void operator()( const betting_market_update_operation& op ) {} - void operator()( const betting_market_group_resolve_operation& op ) {} - void operator()( const betting_market_group_cancel_unmatched_bets_operation& op ) {} - - void operator()( const bet_place_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - void operator()( const bet_cancel_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - void operator()( const bet_canceled_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - void operator()( const bet_adjusted_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - void operator()( const bet_matched_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - void operator()( const betting_market_group_resolved_operation& op ) - { - _impacted.insert( op.bettor_id ); - } - - void operator()( const tournament_create_operation& op ) - { - _impacted.insert( op.creator ); - _impacted.insert( op.options.whitelist.begin(), op.options.whitelist.end() ); - } - void operator()( const tournament_join_operation& op ) - { - _impacted.insert( op.payer_account_id ); - _impacted.insert( op.player_account_id ); - } - void operator()( const tournament_leave_operation& op ) - { - //if account canceling registration is not the player, it must be the payer - if (op.canceling_account_id != op.player_account_id) - _impacted.erase( op.canceling_account_id ); - _impacted.erase( op.player_account_id ); - } - void operator()( const game_move_operation& op ) - { - _impacted.insert( op.player_account_id ); - } - void operator()( const tournament_payout_operation& op ) - { - _impacted.insert( op.payout_account_id ); - } - void operator()( const affiliate_payout_operation& op ) - { - _impacted.insert( op.affiliate ); - } - void operator()( const affiliate_referral_payout_operation& op ) { } - void operator()( const lottery_asset_create_operation& op) { } - void operator()( const ticket_purchase_operation& op ) - { - _impacted.insert( op.buyer ); - } - void operator()( const lottery_reward_operation& op ) { - _impacted.insert( op.winner ); - } - void operator()( const lottery_end_operation& op ) { - for( auto participant : op.participants ) { - _impacted.insert(participant.first); - } - } - void operator()( const sweeps_vesting_claim_operation& op ) { - _impacted.insert( op.account ); - } -}; - -void operation_get_impacted_accounts( const operation& op, flat_set& result ) -{ - get_impacted_account_visitor vtor = get_impacted_account_visitor( result ); - op.visit( vtor ); -} - -void transaction_get_impacted_accounts( const transaction& tx, flat_set& result ) -{ - for( const auto& op : tx.operations ) - operation_get_impacted_accounts( op, result ); -} - -} } diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index d40dde6e..4adf73a3 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -357,7 +359,17 @@ namespace graphene { namespace app { graphene::chain::database& _db; graphene::app::database_api database_api; }; +} } // graphene::app +extern template class fc::api; +extern template class fc::api; +extern template class fc::api; +extern template class fc::api; +extern template class fc::api; +extern template class fc::api; +extern template class fc::api; + +namespace graphene { namespace app { /** * @brief The login_api class implements the bottom layer of the RPC API * @@ -419,6 +431,8 @@ namespace graphene { namespace app { }} // graphene::app +extern template class fc::api; + FC_REFLECT( graphene::app::network_broadcast_api::transaction_confirmation, (id)(block_num)(trx_num)(trx) ) FC_REFLECT( graphene::app::verify_range_result, diff --git a/libraries/app/include/graphene/app/application.hpp b/libraries/app/include/graphene/app/application.hpp index 26ae78ef..a313e2f8 100644 --- a/libraries/app/include/graphene/app/application.hpp +++ b/libraries/app/include/graphene/app/application.hpp @@ -56,14 +56,15 @@ namespace graphene { namespace app { auto plug = std::make_shared(); plug->plugin_set_app(this); - boost::program_options::options_description plugin_cli_options("Options for plugin " + plug->plugin_name()), plugin_cfg_options; + boost::program_options::options_description plugin_cli_options(plug->plugin_name() + " plugin. " + plug->plugin_description() + "\nOptions"), plugin_cfg_options; + //boost::program_options::options_description plugin_cli_options("Options for plugin " + plug->plugin_name()), plugin_cfg_options; plug->plugin_set_program_options(plugin_cli_options, plugin_cfg_options); if( !plugin_cli_options.options().empty() ) _cli_options.add(plugin_cli_options); if( !plugin_cfg_options.options().empty() ) _cfg_options.add(plugin_cfg_options); - add_plugin( plug->plugin_name(), plug ); + add_available_plugin( plug ); return plug; } std::shared_ptr get_plugin( const string& name )const; @@ -88,8 +89,14 @@ namespace graphene { namespace app { /// Emitted when syncing finishes (is_finished_syncing will return true) boost::signals2::signal syncing_finished; - private: - void add_plugin( const string& name, std::shared_ptr p ); + void enable_plugin( const string& name ); + + bool is_plugin_enabled(const string& name) const; + + std::shared_ptr elasticsearch_thread; + + private: + void add_available_plugin( std::shared_ptr p ); std::shared_ptr my; boost::program_options::options_description _cli_options; diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 00f51a44..dc8aba52 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -119,7 +119,9 @@ struct gpos_info { asset award; share_type total_amount; uint32_t current_subperiod; - fc::time_point_sec last_voted_time; + fc::time_point_sec last_voted_time; + share_type allowed_withdraw_amount; + share_type account_vested_balance; }; /** @@ -715,12 +717,14 @@ private: } } +extern template class fc::api; + FC_REFLECT( graphene::app::order, (price)(quote)(base) ); FC_REFLECT( graphene::app::order_book, (base)(quote)(bids)(asks) ); FC_REFLECT( graphene::app::market_ticker, (base)(quote)(latest)(lowest_ask)(highest_bid)(percent_change)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_volume, (base)(quote)(base_volume)(quote_volume) ); FC_REFLECT( graphene::app::market_trade, (date)(price)(amount)(value) ); -FC_REFLECT( graphene::app::gpos_info, (vesting_factor)(award)(total_amount)(current_subperiod)(last_voted_time) ); +FC_REFLECT( graphene::app::gpos_info, (vesting_factor)(award)(total_amount)(current_subperiod)(last_voted_time)(allowed_withdraw_amount)(account_vested_balance) ); FC_API(graphene::app::database_api, diff --git a/libraries/app/include/graphene/app/plugin.hpp b/libraries/app/include/graphene/app/plugin.hpp index c242130b..45336f67 100644 --- a/libraries/app/include/graphene/app/plugin.hpp +++ b/libraries/app/include/graphene/app/plugin.hpp @@ -35,6 +35,7 @@ class abstract_plugin public: virtual ~abstract_plugin(){} virtual std::string plugin_name()const = 0; + virtual std::string plugin_description()const = 0; /** * @brief Perform early startup routines and register plugin indexes, callbacks, etc. @@ -100,6 +101,7 @@ class plugin : public abstract_plugin virtual ~plugin() override; virtual std::string plugin_name()const override; + virtual std::string plugin_description()const override; virtual void plugin_initialize( const boost::program_options::variables_map& options ) override; virtual void plugin_startup() override; virtual void plugin_shutdown() override; diff --git a/libraries/app/plugin.cpp b/libraries/app/plugin.cpp index 8568d371..cae488a6 100644 --- a/libraries/app/plugin.cpp +++ b/libraries/app/plugin.cpp @@ -43,6 +43,11 @@ std::string plugin::plugin_name()const return ""; } +std::string plugin::plugin_description()const +{ + return ""; +} + void plugin::plugin_initialize( const boost::program_options::variables_map& options ) { return; diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index a8d9e5db..07f1ea0a 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -60,6 +60,7 @@ add_library( graphene_chain protocol/confidential.cpp protocol/vote.cpp protocol/tournament.cpp + protocol/small_ops.cpp genesis_state.cpp get_config.cpp @@ -93,6 +94,7 @@ add_library( graphene_chain fba_object.cpp proposal_object.cpp vesting_balance_object.cpp + small_objects.cpp block_database.cpp diff --git a/libraries/chain/account_evaluator.cpp b/libraries/chain/account_evaluator.cpp index 0d389d7c..ad6ac5dc 100644 --- a/libraries/chain/account_evaluator.cpp +++ b/libraries/chain/account_evaluator.cpp @@ -261,8 +261,6 @@ void_result account_update_evaluator::do_evaluate( const account_update_operatio FC_ASSERT( !o.extensions.value.owner_special_authority.valid() ); FC_ASSERT( !o.extensions.value.active_special_authority.valid() ); } - if( d.head_block_time() < HARDFORK_GPOS_TIME ) - FC_ASSERT( !o.extensions.value.update_last_voting_time.valid() ); try { diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index 466f7a6f..71ee28de 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -22,9 +22,9 @@ * THE SOFTWARE. */ #include -#include #include -#include + +#include #include namespace graphene { namespace chain { @@ -320,3 +320,8 @@ const account_balance_object* balances_by_account_index::get_account_balance( co } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_statistics_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::pending_dividend_payout_balance_for_holder_object ) diff --git a/libraries/chain/asset_object.cpp b/libraries/chain/asset_object.cpp index ea387932..88e5dfca 100644 --- a/libraries/chain/asset_object.cpp +++ b/libraries/chain/asset_object.cpp @@ -24,10 +24,9 @@ #include #include +#include #include -#include - using namespace graphene::chain; share_type asset_bitasset_data_object::max_force_settlement_volume(share_type current_supply) const @@ -296,3 +295,11 @@ void sweeps_vesting_balance_object::adjust_balance( const asset& delta ) FC_ASSERT( delta.asset_id == asset_id ); balance += delta.amount.value; } + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_dynamic_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_bitasset_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_dividend_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::total_distributed_dividend_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::lottery_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::sweeps_vesting_balance_object ) diff --git a/libraries/chain/balance_evaluator.cpp b/libraries/chain/balance_evaluator.cpp index 8d29c01d..817d736f 100644 --- a/libraries/chain/balance_evaluator.cpp +++ b/libraries/chain/balance_evaluator.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index d2e77a32..2d40f5f7 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -336,8 +336,6 @@ processed_transaction database::validate_transaction( const signed_transaction& processed_transaction database::push_proposal(const proposal_object& proposal) { try { - FC_ASSERT( _undo_db.size() < _undo_db.max_size(), "Undo database is full!" ); - transaction_evaluation_state eval_state(this); eval_state._is_proposed_trx = true; @@ -347,6 +345,8 @@ processed_transaction database::push_proposal(const proposal_object& proposal) size_t old_applied_ops_size = _applied_ops.size(); try { + if( _undo_db.size() >= _undo_db.max_size() ) + _undo_db.set_max_size( _undo_db.size() + 1 ); auto session = _undo_db.start_undo_session(true); for( auto& op : proposal.proposed_transaction.operations ) eval_state.operation_results.emplace_back(apply_operation(eval_state, op)); diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index af609833..11a2b426 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -1560,11 +1560,19 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g if(d.head_block_time() >= HARDFORK_GPOS_TIME) { - if (itr == vesting_amounts.end()) + if (itr == vesting_amounts.end() && d.head_block_time() >= (HARDFORK_GPOS_TIME + props.parameters.gpos_subperiod()/2)) return; auto vesting_factor = d.calculate_vesting_factor(stake_account); voting_stake = (uint64_t)floor(voting_stake * vesting_factor); + + //Include votes(based on stake) for the period of gpos_subperiod()/2 as system has zero votes on GPOS activation + if(d.head_block_time() < (HARDFORK_GPOS_TIME + props.parameters.gpos_subperiod()/2)) + { + voting_stake += stats.total_core_in_orders.value + + (stake_account.cashback_vb.valid() ? (*stake_account.cashback_vb)(d).balance.amount.value : 0) + + d.get_balance(stake_account.get_id(), asset_id_type()).amount.value; + } } else { @@ -1644,6 +1652,8 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g p.pending_parameters->extensions.value.permitted_betting_odds_increments = p.parameters.extensions.value.permitted_betting_odds_increments; if( !p.pending_parameters->extensions.value.live_betting_delay_time.valid() ) p.pending_parameters->extensions.value.live_betting_delay_time = p.parameters.extensions.value.live_betting_delay_time; + if( !p.pending_parameters->extensions.value.gpos_period_start.valid() ) + p.pending_parameters->extensions.value.gpos_period_start = p.parameters.extensions.value.gpos_period_start; if( !p.pending_parameters->extensions.value.gpos_period.valid() ) p.pending_parameters->extensions.value.gpos_period = p.parameters.extensions.value.gpos_period; if( !p.pending_parameters->extensions.value.gpos_subperiod.valid() ) diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index 554abc0d..e91eaa6b 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -34,6 +34,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include + using namespace fc; using namespace graphene::chain; @@ -288,13 +295,13 @@ struct get_impacted_account_visitor } }; -void operation_get_impacted_accounts( const operation& op, flat_set& result ) +void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result ) { get_impacted_account_visitor vtor = get_impacted_account_visitor( result ); op.visit( vtor ); } -void transaction_get_impacted_accounts( const transaction& tx, flat_set& result ) +void graphene::chain::transaction_get_impacted_accounts( const transaction& tx, flat_set& result ) { for( const auto& op : tx.operations ) operation_get_impacted_accounts( op, result ); diff --git a/libraries/chain/genesis_state.cpp b/libraries/chain/genesis_state.cpp index a278b680..53311012 100644 --- a/libraries/chain/genesis_state.cpp +++ b/libraries/chain/genesis_state.cpp @@ -36,3 +36,72 @@ chain_id_type genesis_state_type::compute_chain_id() const } } } // graphene::chain + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_account_type, BOOST_PP_SEQ_NIL, (name)(owner_key)(active_key)(is_lifetime_member)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type, BOOST_PP_SEQ_NIL, + (symbol)(issuer_name)(description)(precision)(max_supply)(accumulated_fees)(is_bitasset)(collateral_records)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position, BOOST_PP_SEQ_NIL, + (owner)(collateral)(debt)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_balance_type, BOOST_PP_SEQ_NIL, + (owner)(asset_symbol)(amount)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_vesting_balance_type, BOOST_PP_SEQ_NIL, + (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds)(begin_balance)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_witness_type, BOOST_PP_SEQ_NIL, (owner_name)(block_signing_key)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_committee_member_type, BOOST_PP_SEQ_NIL, (owner_name)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_worker_type, BOOST_PP_SEQ_NIL, (owner_name)(daily_pay)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority, BOOST_PP_SEQ_NIL, + (weight_threshold) + (account_auths) + (key_auths) + (address_auths)) +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy, BOOST_PP_SEQ_NIL, + (vesting_seconds) + (coin_seconds_earned) + (start_claim) + (coin_seconds_earned_last_update)) +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy, BOOST_PP_SEQ_NIL, + (begin_timestamp) + (vesting_cliff_seconds) + (vesting_duration_seconds) + (begin_balance)) +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance, BOOST_PP_SEQ_NIL, + (asset_symbol) + (amount) + (policy_type) + (policy)) +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type, BOOST_PP_SEQ_NIL, + (name) + (owner_authority) + (active_authority) + (core_balance) + (vesting_balances)) + +FC_REFLECT_DERIVED_NO_TYPENAME(graphene::chain::genesis_state_type, BOOST_PP_SEQ_NIL, + (initial_timestamp)(max_core_supply)(initial_parameters)(initial_bts_accounts)(initial_accounts)(initial_assets)(initial_balances) + (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) + (initial_committee_candidates)(initial_worker_candidates) + (initial_chain_id) + (immutable_parameters)) + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_account_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_asset_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_balance_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_vesting_balance_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_witness_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_committee_member_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_worker_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type::initial_bts_account_type) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::genesis_state_type) diff --git a/libraries/chain/hardfork.d/GPOS.hf b/libraries/chain/hardfork.d/GPOS.hf index 626cf003..52e95a72 100644 --- a/libraries/chain/hardfork.d/GPOS.hf +++ b/libraries/chain/hardfork.d/GPOS.hf @@ -1,4 +1,4 @@ -// GPOS HARDFORK Thursday, October 1, 2020 05:00:00 AM GMT +// GPOS HARDFORK Monday, 6 January 2020 01:00:00 GMT #ifndef HARDFORK_GPOS_TIME -#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1601528400 )) +#define HARDFORK_GPOS_TIME (fc::time_point_sec( 1578272400 )) #endif diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 94a1b98e..5f24adeb 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -22,8 +22,9 @@ * THE SOFTWARE. */ #pragma once -#include +#include #include +#include #include namespace graphene { namespace chain { @@ -574,4 +575,7 @@ FC_REFLECT_DERIVED( graphene::chain::pending_dividend_payout_balance_for_holder_ (graphene::db::object), (owner)(dividend_holder_asset_type)(dividend_payout_asset_type)(pending_balance) ) - +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_statistics_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::pending_dividend_payout_balance_for_holder_object ) diff --git a/libraries/chain/include/graphene/chain/asset_object.hpp b/libraries/chain/include/graphene/chain/asset_object.hpp index cba33bb8..8978a6d1 100644 --- a/libraries/chain/include/graphene/chain/asset_object.hpp +++ b/libraries/chain/include/graphene/chain/asset_object.hpp @@ -22,10 +22,11 @@ * THE SOFTWARE. */ #pragma once +#include +#include +#include #include #include -#include -#include /** * @defgroup prediction_market Prediction Market @@ -38,11 +39,10 @@ */ namespace graphene { namespace chain { - class account_object; class database; class transaction_evaluation_state; using namespace graphene::db; - + /** * @brief tracks the asset information that changes frequently * @ingroup object @@ -118,9 +118,9 @@ namespace graphene { namespace chain { /// Convert an asset to a textual representation with symbol, i.e. "123.45 USD" string amount_to_pretty_string(const asset &amount)const { FC_ASSERT(amount.asset_id == id); return amount_to_pretty_string(amount.amount); } - + uint32_t get_issuer_num()const - { return issuer.instance.value; } + { return issuer.instance.value; } /// Ticker symbol for this asset, i.e. "USD" string symbol; /// Maximum number of digits after the decimal point (must be <= 12) @@ -138,7 +138,7 @@ namespace graphene { namespace chain { map< account_id_type, vector< uint16_t > > distribute_winners_part( database& db ); void distribute_sweeps_holders_part( database& db ); void end_lottery( database& db ); - + /// Current supply, fee pool, and collected fees are stored in a separate object as they change frequently. asset_dynamic_data_id_type dynamic_asset_data_id; /// Extra data associated with BitAssets. This field is non-null if and only if is_market_issued() returns true @@ -150,7 +150,7 @@ namespace graphene { namespace chain { optional dividend_data_id; asset_id_type get_id()const { return id; } - + void validate()const { // UIAs may not be prediction markets, have force settlement, or global settlements @@ -174,7 +174,7 @@ namespace graphene { namespace chain { { return db.get(dynamic_asset_data_id); } /** - * The total amount of an asset that is reserved for future issuance. + * The total amount of an asset that is reserved for future issuance. */ template share_type reserved( const DB& db )const @@ -254,7 +254,7 @@ namespace graphene { namespace chain { else return current_feed_publication_time + options.feed_lifetime_sec; } - + bool feed_is_expired_before_hardfork_615(time_point_sec current_time)const { return feed_expiration_time() >= current_time; } bool feed_is_expired(time_point_sec current_time)const @@ -378,7 +378,7 @@ namespace graphene { namespace chain { /// This field is reset any time the dividend_asset_options are updated fc::optional last_scheduled_payout_time; - /// The time payouts on this asset were last processed + /// The time payouts on this asset were last processed /// (this should be the maintenance interval at or after last_scheduled_payout_time) /// This can be displayed for the user fc::optional last_payout_time; @@ -405,7 +405,7 @@ namespace graphene { namespace chain { typedef generic_index asset_dividend_data_object_index; - // This tracks the balances in a dividend distribution account at the last time + // This tracks the balances in a dividend distribution account at the last time // pending dividend payouts were calculated (last maintenance interval). // At each maintenance interval, we will compare the current balance to the // balance stored here to see how much was deposited during that interval. @@ -434,9 +434,9 @@ namespace graphene { namespace chain { > > total_distributed_dividend_balance_object_multi_index_type; typedef generic_index total_distributed_dividend_balance_object_index; - - - + + + /** * @ingroup object */ @@ -445,17 +445,17 @@ namespace graphene { namespace chain { public: static const uint8_t space_id = implementation_ids; static const uint8_t type_id = impl_lottery_balance_object_type; - + asset_id_type lottery_id; asset balance; - + asset get_balance()const { return balance; } void adjust_balance(const asset& delta); }; - - + + struct by_owner; - + /** * @ingroup object_index */ @@ -468,13 +468,13 @@ namespace graphene { namespace chain { > > > lottery_balance_index_type; - + /** * @ingroup object_index */ typedef generic_index lottery_balance_index; - - + + class sweeps_vesting_balance_object : public abstract_object { public: @@ -486,7 +486,7 @@ namespace graphene { namespace chain { uint64_t balance; asset_id_type asset_id; time_point_sec last_claim_date; - + uint64_t get_balance()const { return balance; } void adjust_balance(const asset& delta); asset available_for_claim() const { return asset( balance / SWEEPS_VESTING_BALANCE_MULTIPLIER , asset_id ); } @@ -528,10 +528,10 @@ FC_REFLECT_DERIVED( graphene::chain::asset_bitasset_data_object, (graphene::db:: (asset_cer_updated) (feed_cer_updated) ) - + FC_REFLECT_DERIVED( graphene::chain::asset_dividend_data_object, (graphene::db::object), (options) - (last_scheduled_payout_time) + (last_scheduled_payout_time) (last_payout_time ) (last_scheduled_distribution_time) (last_distribution_time) @@ -561,3 +561,13 @@ FC_REFLECT_DERIVED( graphene::chain::lottery_balance_object, (graphene::db::obje FC_REFLECT_DERIVED( graphene::chain::sweeps_vesting_balance_object, (graphene::db::object), (owner)(balance)(asset_id)(last_claim_date) ) + + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dynamic_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_bitasset_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dividend_data_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::total_distributed_dividend_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::lottery_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::sweeps_vesting_balance_object ) + diff --git a/libraries/chain/include/graphene/chain/balance_object.hpp b/libraries/chain/include/graphene/chain/balance_object.hpp index 8d531d0c..38a1a649 100644 --- a/libraries/chain/include/graphene/chain/balance_object.hpp +++ b/libraries/chain/include/graphene/chain/balance_object.hpp @@ -73,3 +73,5 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::balance_object, (graphene::db::object), (owner)(balance)(vesting_policy)(last_claim_date) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::balance_object ) diff --git a/libraries/chain/include/graphene/chain/block_database.hpp b/libraries/chain/include/graphene/chain/block_database.hpp index d902cd1b..c5cf5df9 100644 --- a/libraries/chain/include/graphene/chain/block_database.hpp +++ b/libraries/chain/include/graphene/chain/block_database.hpp @@ -25,6 +25,8 @@ #include #include +#include + namespace graphene { namespace chain { class index_entry; diff --git a/libraries/chain/include/graphene/chain/block_summary_object.hpp b/libraries/chain/include/graphene/chain/block_summary_object.hpp index f002c030..9f79d43e 100644 --- a/libraries/chain/include/graphene/chain/block_summary_object.hpp +++ b/libraries/chain/include/graphene/chain/block_summary_object.hpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #pragma once +#include #include namespace graphene { namespace chain { @@ -47,4 +48,7 @@ namespace graphene { namespace chain { } } + FC_REFLECT_DERIVED( graphene::chain::block_summary_object, (graphene::db::object), (block_id) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::block_summary_object ) diff --git a/libraries/chain/include/graphene/chain/budget_record_object.hpp b/libraries/chain/include/graphene/chain/budget_record_object.hpp index 49544793..e3f6d06e 100644 --- a/libraries/chain/include/graphene/chain/budget_record_object.hpp +++ b/libraries/chain/include/graphene/chain/budget_record_object.hpp @@ -23,7 +23,6 @@ */ #pragma once #include -#include #include namespace graphene { namespace chain { @@ -54,8 +53,6 @@ struct budget_record share_type supply_delta = 0; }; -class budget_record_object; - class budget_record_object : public graphene::db::abstract_object { public: @@ -68,8 +65,7 @@ class budget_record_object : public graphene::db::abstract_object buyback_index; } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::buyback_object, (graphene::db::object), (asset_to_buy) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::buyback_object ) diff --git a/libraries/chain/include/graphene/chain/chain_property_object.hpp b/libraries/chain/include/graphene/chain/chain_property_object.hpp index 3d2c82a6..3c7a77ff 100644 --- a/libraries/chain/include/graphene/chain/chain_property_object.hpp +++ b/libraries/chain/include/graphene/chain/chain_property_object.hpp @@ -27,8 +27,6 @@ namespace graphene { namespace chain { -class chain_property_object; - /** * Contains invariants which are set at genesis and never changed. */ @@ -48,3 +46,5 @@ FC_REFLECT_DERIVED( graphene::chain::chain_property_object, (graphene::db::objec (chain_id) (immutable_parameters) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::chain_property_object ) diff --git a/libraries/chain/include/graphene/chain/committee_member_object.hpp b/libraries/chain/include/graphene/chain/committee_member_object.hpp index 7b0d8e75..fe7968d3 100644 --- a/libraries/chain/include/graphene/chain/committee_member_object.hpp +++ b/libraries/chain/include/graphene/chain/committee_member_object.hpp @@ -29,8 +29,6 @@ namespace graphene { namespace chain { using namespace graphene::db; - class account_object; - /** * @brief tracks information about a committee_member account. * @ingroup object @@ -73,5 +71,8 @@ namespace graphene { namespace chain { using committee_member_index = generic_index; } } // graphene::chain + FC_REFLECT_DERIVED( graphene::chain::committee_member_object, (graphene::db::object), (committee_member_account)(vote_id)(total_votes)(url) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_object ) diff --git a/libraries/chain/include/graphene/chain/confidential_object.hpp b/libraries/chain/include/graphene/chain/confidential_object.hpp index f98e20a9..acdb0ba5 100644 --- a/libraries/chain/include/graphene/chain/confidential_object.hpp +++ b/libraries/chain/include/graphene/chain/confidential_object.hpp @@ -26,7 +26,6 @@ #include #include -#include #include #include @@ -50,8 +49,6 @@ class blinded_balance_object : public graphene::db::abstract_object #include #include #include @@ -169,56 +170,32 @@ struct genesis_state_type { } } // namespace graphene::chain -FC_REFLECT(graphene::chain::genesis_state_type::initial_account_type, (name)(owner_key)(active_key)(is_lifetime_member)) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_account_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_balance_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_vesting_balance_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_witness_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_committee_member_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_worker_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type::initial_bts_account_type) +FC_REFLECT_TYPENAME(graphene::chain::genesis_state_type) -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type, - (symbol)(issuer_name)(description)(precision)(max_supply)(accumulated_fees)(is_bitasset)(collateral_records)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position, - (owner)(collateral)(debt)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_balance_type, - (owner)(asset_symbol)(amount)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_vesting_balance_type, - (owner)(asset_symbol)(amount)(begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds)(begin_balance)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_witness_type, (owner_name)(block_signing_key)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_committee_member_type, (owner_name)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_worker_type, (owner_name)(daily_pay)) - -FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority, - (weight_threshold) - (account_auths) - (key_auths) - (address_auths)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy, - (vesting_seconds) - (coin_seconds_earned) - (start_claim) - (coin_seconds_earned_last_update)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy, - (begin_timestamp) - (vesting_cliff_seconds) - (vesting_duration_seconds) - (begin_balance)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance, - (asset_symbol) - (amount) - (policy_type) - (policy)) -FC_REFLECT(graphene::chain::genesis_state_type::initial_bts_account_type, - (name) - (owner_authority) - (active_authority) - (core_balance) - (vesting_balances)) - -FC_REFLECT(graphene::chain::genesis_state_type, - (initial_timestamp)(max_core_supply)(initial_parameters)(initial_bts_accounts)(initial_accounts)(initial_assets)(initial_balances) - (initial_vesting_balances)(initial_active_witnesses)(initial_witness_candidates) - (initial_committee_candidates)(initial_worker_candidates) - (initial_chain_id) - (immutable_parameters)) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_account_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_asset_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_asset_type::initial_collateral_position) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_balance_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_vesting_balance_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_witness_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_committee_member_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_worker_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_authority) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_cdd_vesting_policy) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_linear_vesting_policy) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type::initial_vesting_balance) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type::initial_bts_account_type) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::genesis_state_type) diff --git a/libraries/chain/include/graphene/chain/global_property_object.hpp b/libraries/chain/include/graphene/chain/global_property_object.hpp index 77f85df6..0ed401a1 100644 --- a/libraries/chain/include/graphene/chain/global_property_object.hpp +++ b/libraries/chain/include/graphene/chain/global_property_object.hpp @@ -126,7 +126,6 @@ namespace graphene { namespace chain { }} FC_REFLECT_DERIVED( graphene::chain::dynamic_global_property_object, (graphene::db::object), - (random) (head_block_number) (head_block_id) (time) @@ -149,3 +148,6 @@ FC_REFLECT_DERIVED( graphene::chain::global_property_object, (graphene::db::obje (active_committee_members) (active_witnesses) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::dynamic_global_property_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::global_property_object ) diff --git a/libraries/chain/include/graphene/chain/immutable_chain_parameters.hpp b/libraries/chain/include/graphene/chain/immutable_chain_parameters.hpp index 0082383c..6e18c079 100644 --- a/libraries/chain/include/graphene/chain/immutable_chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/immutable_chain_parameters.hpp @@ -23,11 +23,8 @@ */ #pragma once -#include - -#include - #include +#include namespace graphene { namespace chain { @@ -47,3 +44,5 @@ FC_REFLECT( graphene::chain::immutable_chain_parameters, (num_special_accounts) (num_special_assets) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::immutable_chain_parameters ) diff --git a/libraries/app/include/graphene/app/impacted.hpp b/libraries/chain/include/graphene/chain/impacted.hpp similarity index 96% rename from libraries/app/include/graphene/app/impacted.hpp rename to libraries/chain/include/graphene/chain/impacted.hpp index 2e59b910..2a22cbd1 100644 --- a/libraries/app/include/graphene/app/impacted.hpp +++ b/libraries/chain/include/graphene/chain/impacted.hpp @@ -28,7 +28,7 @@ #include #include -namespace graphene { namespace app { +namespace graphene { namespace chain { void operation_get_impacted_accounts( const graphene::chain::operation& op, @@ -39,4 +39,4 @@ void transaction_get_impacted_accounts( fc::flat_set& result ); -} } // graphene::app +} } // graphene::app \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/market_object.hpp b/libraries/chain/include/graphene/chain/market_object.hpp index b56f4e9c..4bd3e048 100644 --- a/libraries/chain/include/graphene/chain/market_object.hpp +++ b/libraries/chain/include/graphene/chain/market_object.hpp @@ -217,3 +217,7 @@ FC_REFLECT_DERIVED( graphene::chain::force_settlement_object, (graphene::db::object), (owner)(balance)(settlement_date) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::force_settlement_object ) diff --git a/libraries/chain/include/graphene/chain/operation_history_object.hpp b/libraries/chain/include/graphene/chain/operation_history_object.hpp index d8b90b58..89199472 100644 --- a/libraries/chain/include/graphene/chain/operation_history_object.hpp +++ b/libraries/chain/include/graphene/chain/operation_history_object.hpp @@ -22,8 +22,10 @@ * THE SOFTWARE. */ #pragma once + #include #include + #include namespace graphene { namespace chain { @@ -94,15 +96,22 @@ namespace graphene { namespace chain { operation_history_id_type operation_id; uint32_t sequence = 0; /// the operation position within the given account account_transaction_history_id_type next; - - //std::pair account_op()const { return std::tie( account, operation_id ); } - //std::pair account_seq()const { return std::tie( account, sequence ); } }; struct by_id; struct by_seq; struct by_op; struct by_opid; + +typedef multi_index_container< + operation_history_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > > + > +> operation_history_multi_index_type; + +typedef generic_index operation_history_index; + typedef multi_index_container< account_transaction_history_object, indexed_by< @@ -132,6 +141,8 @@ typedef generic_index #include +#include namespace graphene { namespace chain { - + class database; /** * @brief tracks the approval of a partially approved transaction @@ -97,3 +98,5 @@ FC_REFLECT_DERIVED( graphene::chain::proposal_object, (graphene::chain::object), (expiration_time)(review_period_time)(proposed_transaction)(required_active_approvals) (available_active_approvals)(required_owner_approvals)(available_owner_approvals) (available_key_approvals)(proposer)(fail_reason)) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_object ) diff --git a/libraries/chain/include/graphene/chain/protocol/account.hpp b/libraries/chain/include/graphene/chain/protocol/account.hpp index 22b3adcb..36926480 100644 --- a/libraries/chain/include/graphene/chain/protocol/account.hpp +++ b/libraries/chain/include/graphene/chain/protocol/account.hpp @@ -317,5 +317,16 @@ FC_REFLECT( graphene::chain::account_whitelist_operation::fee_parameters_type, ( FC_REFLECT( graphene::chain::account_update_operation::fee_parameters_type, (fee)(price_per_kbyte) ) FC_REFLECT( graphene::chain::account_upgrade_operation::fee_parameters_type, (membership_annual_fee)(membership_lifetime_fee) ) FC_REFLECT( graphene::chain::account_transfer_operation::fee_parameters_type, (fee) ) - FC_REFLECT( graphene::chain::account_transfer_operation, (fee)(account_id)(new_owner)(extensions) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_whitelist_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_upgrade_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_whitelist_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_upgrade_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::account_transfer_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/address.hpp b/libraries/chain/include/graphene/chain/protocol/address.hpp index b225b42c..8bf0fab6 100644 --- a/libraries/chain/include/graphene/chain/protocol/address.hpp +++ b/libraries/chain/include/graphene/chain/protocol/address.hpp @@ -25,14 +25,10 @@ #include #include +#include -#include #include - -namespace fc { namespace ecc { - class public_key; - typedef fc::array public_key_data; -} } // fc::ecc +#include namespace graphene { namespace chain { @@ -51,7 +47,7 @@ namespace graphene { namespace chain { class address { public: - address(); ///< constructs empty / null address + address(){} ///< constructs empty / null address explicit address( const std::string& base58str ); ///< converts to binary, validates checksum address( const fc::ecc::public_key& pub ); ///< converts to binary explicit address( const fc::ecc::public_key_data& pub ); ///< converts to binary @@ -97,3 +93,5 @@ namespace std #include FC_REFLECT( graphene::chain::address, (addr) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::address ) diff --git a/libraries/chain/include/graphene/chain/protocol/assert.hpp b/libraries/chain/include/graphene/chain/protocol/assert.hpp index c9f3b277..ce758862 100644 --- a/libraries/chain/include/graphene/chain/protocol/assert.hpp +++ b/libraries/chain/include/graphene/chain/protocol/assert.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -112,3 +113,5 @@ FC_REFLECT( graphene::chain::block_id_predicate, (id) ) FC_REFLECT_TYPENAME( graphene::chain::predicate ) FC_REFLECT( graphene::chain::assert_operation, (fee)(fee_paying_account)(predicates)(required_auths)(extensions) ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::assert_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::assert_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/asset.hpp b/libraries/chain/include/graphene/chain/protocol/asset.hpp index a938129a..60bd3cd0 100644 --- a/libraries/chain/include/graphene/chain/protocol/asset.hpp +++ b/libraries/chain/include/graphene/chain/protocol/asset.hpp @@ -218,3 +218,7 @@ FC_REFLECT( graphene::chain::price, (base)(quote) ) (core_exchange_rate) FC_REFLECT( graphene::chain::price_feed, GRAPHENE_PRICE_FEED_FIELDS ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::price ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::price_feed ) diff --git a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp index a567c5a1..ae5dc211 100644 --- a/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp +++ b/libraries/chain/include/graphene/chain/protocol/asset_ops.hpp @@ -764,3 +764,30 @@ FC_REFLECT( graphene::chain::asset_reserve_operation, FC_REFLECT( graphene::chain::asset_fund_fee_pool_operation, (fee)(from_account)(asset_id)(amount)(extensions) ); FC_REFLECT( graphene::chain::asset_dividend_distribution_operation, (fee)(dividend_asset_id)(account_id)(amounts)(extensions) ); + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::bitasset_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_global_settle_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_fund_fee_pool_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_dividend_distribution_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_claim_fees_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_bitasset_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_feed_producers_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_publish_feed_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_issue_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_reserve_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_global_settle_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_settle_cancel_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_fund_fee_pool_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_claim_fees_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_bitasset_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_update_feed_producers_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_publish_feed_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_issue_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::asset_reserve_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/authority.hpp b/libraries/chain/include/graphene/chain/protocol/authority.hpp index 70b674b3..d279402d 100644 --- a/libraries/chain/include/graphene/chain/protocol/authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/authority.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -134,3 +135,5 @@ void add_authority_accounts( FC_REFLECT( graphene::chain::authority, (weight_threshold)(account_auths)(key_auths)(address_auths) ) // FC_REFLECT_TYPENAME( graphene::chain::authority::classification ) FC_REFLECT_ENUM( graphene::chain::authority::classification, (owner)(active)(key) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::authority ) diff --git a/libraries/chain/include/graphene/chain/protocol/balance.hpp b/libraries/chain/include/graphene/chain/protocol/balance.hpp index f60087a7..9d0b252f 100644 --- a/libraries/chain/include/graphene/chain/protocol/balance.hpp +++ b/libraries/chain/include/graphene/chain/protocol/balance.hpp @@ -23,6 +23,8 @@ */ #pragma once #include +#include +#include namespace graphene { namespace chain { @@ -57,3 +59,5 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::balance_claim_operation::fee_parameters_type, ) FC_REFLECT( graphene::chain::balance_claim_operation, (fee)(deposit_to_account)(balance_to_claim)(balance_owner_key)(total_claimed) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::balance_claim_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/base.hpp b/libraries/chain/include/graphene/chain/protocol/base.hpp index 52240b93..23c285d3 100644 --- a/libraries/chain/include/graphene/chain/protocol/base.hpp +++ b/libraries/chain/include/graphene/chain/protocol/base.hpp @@ -27,8 +27,13 @@ #include #include +#include + namespace graphene { namespace chain { + struct asset; + struct authority; + /** * @defgroup operations Operations * @ingroup transactions Transactions diff --git a/libraries/chain/include/graphene/chain/protocol/block.hpp b/libraries/chain/include/graphene/chain/protocol/block.hpp index 46ac0f6d..ad5b0327 100644 --- a/libraries/chain/include/graphene/chain/protocol/block.hpp +++ b/libraries/chain/include/graphene/chain/protocol/block.hpp @@ -69,3 +69,8 @@ FC_REFLECT( graphene::chain::block_header, (extensions) ) FC_REFLECT_DERIVED( graphene::chain::signed_block_header, (graphene::chain::block_header), (witness_signature) ) FC_REFLECT_DERIVED( graphene::chain::signed_block, (graphene::chain::signed_block_header), (transactions) ) + + +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::block_header) +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_block_header) +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_block) diff --git a/libraries/chain/include/graphene/chain/protocol/buyback.hpp b/libraries/chain/include/graphene/chain/protocol/buyback.hpp index 6adad52d..4a51e8c7 100644 --- a/libraries/chain/include/graphene/chain/protocol/buyback.hpp +++ b/libraries/chain/include/graphene/chain/protocol/buyback.hpp @@ -50,3 +50,5 @@ struct buyback_account_options } } FC_REFLECT( graphene::chain::buyback_account_options, (asset_to_buy)(asset_to_buy_issuer)(markets) ); + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::buyback_account_options ) diff --git a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp index 93098c21..5ab8ae7c 100644 --- a/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp +++ b/libraries/chain/include/graphene/chain/protocol/chain_parameters.hpp @@ -28,25 +28,25 @@ #include #include <../hardfork.d/GPOS.hf> +#include namespace graphene { namespace chain { struct fee_schedule; } } namespace graphene { namespace chain { struct parameter_extension { - optional< bet_multiplier_type > min_bet_multiplier = GRAPHENE_DEFAULT_MIN_BET_MULTIPLIER; - optional< bet_multiplier_type > max_bet_multiplier = GRAPHENE_DEFAULT_MAX_BET_MULTIPLIER; - optional< uint16_t > betting_rake_fee_percentage = GRAPHENE_DEFAULT_RAKE_FEE_PERCENTAGE; - optional< flat_map > - permitted_betting_odds_increments = flat_map(GRAPHENE_DEFAULT_PERMITTED_BETTING_ODDS_INCREMENTS); - optional< uint16_t > live_betting_delay_time = GRAPHENE_DEFAULT_LIVE_BETTING_DELAY_TIME; + optional< bet_multiplier_type > min_bet_multiplier; + optional< bet_multiplier_type > max_bet_multiplier; + optional< uint16_t > betting_rake_fee_percentage; + optional< flat_map > permitted_betting_odds_increments; + optional< uint16_t > live_betting_delay_time; optional< uint16_t > sweeps_distribution_percentage = SWEEPS_DEFAULT_DISTRIBUTION_PERCENTAGE; optional< asset_id_type > sweeps_distribution_asset = SWEEPS_DEFAULT_DISTRIBUTION_ASSET; optional< account_id_type > sweeps_vesting_accumulator_account= SWEEPS_ACCUMULATOR_ACCOUNT; /* gpos parameters */ optional < uint32_t > gpos_period = GPOS_PERIOD; optional < uint32_t > gpos_subperiod = GPOS_SUBPERIOD; - optional < uint32_t > gpos_period_start; + optional < uint32_t > gpos_period_start = HARDFORK_GPOS_TIME.sec_since_epoch(); optional < uint32_t > gpos_vesting_lockin_period = GPOS_VESTING_LOCKIN_PERIOD; }; @@ -203,3 +203,5 @@ FC_REFLECT( graphene::chain::chain_parameters, (maximum_tournament_number_of_wins) (extensions) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::chain_parameters ) diff --git a/libraries/chain/include/graphene/chain/protocol/committee_member.hpp b/libraries/chain/include/graphene/chain/protocol/committee_member.hpp index 77188367..8aaed748 100644 --- a/libraries/chain/include/graphene/chain/protocol/committee_member.hpp +++ b/libraries/chain/include/graphene/chain/protocol/committee_member.hpp @@ -104,3 +104,10 @@ FC_REFLECT( graphene::chain::committee_member_create_operation, FC_REFLECT( graphene::chain::committee_member_update_operation, (fee)(committee_member)(committee_member_account)(new_url) ) FC_REFLECT( graphene::chain::committee_member_update_global_parameters_operation, (fee)(new_parameters) ); + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_global_parameters_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::committee_member_update_global_parameters_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/confidential.hpp b/libraries/chain/include/graphene/chain/protocol/confidential.hpp index 763006ae..697ef35b 100644 --- a/libraries/chain/include/graphene/chain/protocol/confidential.hpp +++ b/libraries/chain/include/graphene/chain/protocol/confidential.hpp @@ -281,3 +281,10 @@ FC_REFLECT( graphene::chain::blind_transfer_operation, FC_REFLECT( graphene::chain::transfer_to_blind_operation::fee_parameters_type, (fee)(price_per_output) ) FC_REFLECT( graphene::chain::transfer_from_blind_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::blind_transfer_operation::fee_parameters_type, (fee)(price_per_output) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_to_blind_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_from_blind_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::blind_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_to_blind_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_from_blind_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::blind_transfer_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/custom.hpp b/libraries/chain/include/graphene/chain/protocol/custom.hpp index e5701a4b..5596aaad 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom.hpp @@ -56,3 +56,6 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::custom_operation::fee_parameters_type, (fee)(price_per_kbyte) ) FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(data) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::custom_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::custom_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/ext.hpp b/libraries/chain/include/graphene/chain/protocol/ext.hpp index 31f66506..6c974630 100644 --- a/libraries/chain/include/graphene/chain/protocol/ext.hpp +++ b/libraries/chain/include/graphene/chain/protocol/ext.hpp @@ -24,6 +24,7 @@ #pragma once #include +#include #include namespace graphene { namespace chain { diff --git a/libraries/chain/include/graphene/chain/protocol/fba.hpp b/libraries/chain/include/graphene/chain/protocol/fba.hpp index 7460ca8d..dc672436 100644 --- a/libraries/chain/include/graphene/chain/protocol/fba.hpp +++ b/libraries/chain/include/graphene/chain/protocol/fba.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -45,3 +46,5 @@ struct fba_distribute_operation : public base_operation FC_REFLECT( graphene::chain::fba_distribute_operation::fee_parameters_type, ) FC_REFLECT( graphene::chain::fba_distribute_operation, (fee)(account_id)(fba_id)(amount) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fba_distribute_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/fee_schedule.hpp b/libraries/chain/include/graphene/chain/protocol/fee_schedule.hpp index e250ab17..9baaffc7 100644 --- a/libraries/chain/include/graphene/chain/protocol/fee_schedule.hpp +++ b/libraries/chain/include/graphene/chain/protocol/fee_schedule.hpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #pragma once +#include #include namespace graphene { namespace chain { @@ -85,3 +86,5 @@ namespace graphene { namespace chain { FC_REFLECT_TYPENAME( graphene::chain::fee_parameters ) FC_REFLECT( graphene::chain::fee_schedule, (parameters)(scale) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fee_schedule ) diff --git a/libraries/chain/include/graphene/chain/protocol/market.hpp b/libraries/chain/include/graphene/chain/protocol/market.hpp index 56352c60..2bff8c56 100644 --- a/libraries/chain/include/graphene/chain/protocol/market.hpp +++ b/libraries/chain/include/graphene/chain/protocol/market.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -165,9 +166,15 @@ FC_REFLECT( graphene::chain::limit_order_cancel_operation::fee_parameters_type, FC_REFLECT( graphene::chain::call_order_update_operation::fee_parameters_type, (fee) ) /// THIS IS THE ONLY VIRTUAL OPERATION THUS FAR... FC_REFLECT( graphene::chain::fill_order_operation::fee_parameters_type, ) - - FC_REFLECT( graphene::chain::limit_order_create_operation,(fee)(seller)(amount_to_sell)(min_to_receive)(expiration)(fill_or_kill)(extensions)) FC_REFLECT( graphene::chain::limit_order_cancel_operation,(fee)(fee_paying_account)(order)(extensions) ) FC_REFLECT( graphene::chain::call_order_update_operation, (fee)(funding_account)(delta_collateral)(delta_debt)(extensions) ) FC_REFLECT( graphene::chain::fill_order_operation, (fee)(order_id)(account_id)(pays)(receives) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_cancel_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::limit_order_cancel_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::call_order_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::fill_order_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/memo.hpp b/libraries/chain/include/graphene/chain/protocol/memo.hpp index b126d3a7..6c5b69fb 100644 --- a/libraries/chain/include/graphene/chain/protocol/memo.hpp +++ b/libraries/chain/include/graphene/chain/protocol/memo.hpp @@ -89,3 +89,6 @@ namespace graphene { namespace chain { FC_REFLECT( graphene::chain::memo_message, (checksum)(text) ) FC_REFLECT( graphene::chain::memo_data, (from)(to)(nonce)(message) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::memo_message ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::memo_data ) diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index bce0e201..cb9a83a1 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -167,3 +167,5 @@ namespace graphene { namespace chain { FC_REFLECT_TYPENAME( graphene::chain::operation ) FC_REFLECT( graphene::chain::op_wrapper, (op) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::op_wrapper ) diff --git a/libraries/chain/include/graphene/chain/protocol/proposal.hpp b/libraries/chain/include/graphene/chain/protocol/proposal.hpp index 3383b6cf..141ec35f 100644 --- a/libraries/chain/include/graphene/chain/protocol/proposal.hpp +++ b/libraries/chain/include/graphene/chain/protocol/proposal.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { /** @@ -179,3 +180,10 @@ FC_REFLECT( graphene::chain::proposal_update_operation, (fee)(fee_paying_account (active_approvals_to_add)(active_approvals_to_remove)(owner_approvals_to_add)(owner_approvals_to_remove) (key_approvals_to_add)(key_approvals_to_remove)(extensions) ) FC_REFLECT( graphene::chain::proposal_delete_operation, (fee)(fee_paying_account)(using_owner_authority)(proposal)(extensions) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_delete_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::proposal_delete_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/special_authority.hpp b/libraries/chain/include/graphene/chain/protocol/special_authority.hpp index 3ee6f15f..05a80719 100644 --- a/libraries/chain/include/graphene/chain/protocol/special_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/special_authority.hpp @@ -48,3 +48,5 @@ void validate_special_authority( const special_authority& auth ); FC_REFLECT( graphene::chain::no_special_authority, ) FC_REFLECT( graphene::chain::top_holders_special_authority, (asset)(num_top_holders) ) FC_REFLECT_TYPENAME( graphene::chain::special_authority ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::top_holders_special_authority ) diff --git a/libraries/chain/include/graphene/chain/protocol/transaction.hpp b/libraries/chain/include/graphene/chain/protocol/transaction.hpp index 95c39961..2a9909a5 100644 --- a/libraries/chain/include/graphene/chain/protocol/transaction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/transaction.hpp @@ -230,3 +230,8 @@ FC_REFLECT( graphene::chain::transaction, (ref_block_num)(ref_block_prefix)(expi // Note: not reflecting signees field for backward compatibility; in addition, it should not be in p2p messages FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures) ) FC_REFLECT_DERIVED( graphene::chain::processed_transaction, (graphene::chain::signed_transaction), (operation_results) ) + + +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::transaction) +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::signed_transaction) +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::chain::processed_transaction) diff --git a/libraries/chain/include/graphene/chain/protocol/transfer.hpp b/libraries/chain/include/graphene/chain/protocol/transfer.hpp index f4417bb7..5366a7ab 100644 --- a/libraries/chain/include/graphene/chain/protocol/transfer.hpp +++ b/libraries/chain/include/graphene/chain/protocol/transfer.hpp @@ -24,6 +24,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { @@ -105,3 +106,8 @@ FC_REFLECT( graphene::chain::override_transfer_operation::fee_parameters_type, ( FC_REFLECT( graphene::chain::override_transfer_operation, (fee)(issuer)(from)(to)(amount)(memo)(extensions) ) FC_REFLECT( graphene::chain::transfer_operation, (fee)(from)(to)(amount)(memo)(extensions) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::override_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transfer_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::override_transfer_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index c2c92ca3..8ea3a8af 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -27,13 +27,15 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include +#include #include #include #include @@ -42,10 +44,34 @@ #include #include #include -#include #include #include +#define GRAPHENE_EXTERNAL_SERIALIZATION(ext, type) \ +namespace fc { \ + ext template void from_variant( const variant& v, type& vo, uint32_t max_depth ); \ + ext template void to_variant( const type& v, variant& vo, uint32_t max_depth ); \ +namespace raw { \ + ext template void pack< datastream, type >( datastream& s, const type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \ + ext template void pack< datastream, type >( datastream& s, const type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \ + ext template void unpack< datastream, type >( datastream& s, type& tx, uint32_t _max_depth=FC_PACK_MAX_DEPTH ); \ +} } // fc::raw + +#define FC_REFLECT_DERIVED_NO_TYPENAME( TYPE, INHERITS, MEMBERS ) \ +namespace fc { \ +template<> struct reflector {\ + typedef TYPE type; \ + typedef fc::true_type is_defined; \ + typedef fc::false_type is_enum; \ + enum member_count_enum { \ + local_member_count = 0 BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_MEMBER_COUNT, +, MEMBERS ),\ + total_member_count = local_member_count BOOST_PP_SEQ_FOR_EACH( FC_REFLECT_BASE_MEMBER_COUNT, +, INHERITS )\ + }; \ + FC_REFLECT_DERIVED_IMPL_INLINE( TYPE, INHERITS, MEMBERS ) \ +}; \ +} // fc + + namespace graphene { namespace chain { using namespace graphene::db; diff --git a/libraries/chain/include/graphene/chain/protocol/vesting.hpp b/libraries/chain/include/graphene/chain/protocol/vesting.hpp index 2a861b2a..4dffb253 100644 --- a/libraries/chain/include/graphene/chain/protocol/vesting.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vesting.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -126,10 +127,15 @@ FC_REFLECT( graphene::chain::vesting_balance_create_operation::fee_parameters_ty FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::vesting_balance_create_operation, (fee)(creator)(owner)(amount)(policy)(balance_type) ) -FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount) ) +FC_REFLECT( graphene::chain::vesting_balance_withdraw_operation, (fee)(vesting_balance)(owner)(amount)) FC_REFLECT(graphene::chain::linear_vesting_policy_initializer, (begin_timestamp)(vesting_cliff_seconds)(vesting_duration_seconds) ) FC_REFLECT(graphene::chain::cdd_vesting_policy_initializer, (start_claim)(vesting_seconds) ) FC_REFLECT_TYPENAME( graphene::chain::vesting_policy_initializer ) FC_REFLECT_ENUM( graphene::chain::vesting_balance_type, (normal)(gpos) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_withdraw_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/vote.hpp b/libraries/chain/include/graphene/chain/protocol/vote.hpp index 67536f7a..7d733e45 100644 --- a/libraries/chain/include/graphene/chain/protocol/vote.hpp +++ b/libraries/chain/include/graphene/chain/protocol/vote.hpp @@ -24,12 +24,7 @@ #pragma once -#include -#include -#include - -#include -#include +#include namespace graphene { namespace chain { @@ -150,3 +145,5 @@ FC_REFLECT_TYPENAME( fc::flat_set ) FC_REFLECT_ENUM( graphene::chain::vote_id_type::vote_type, (witness)(committee)(worker)(VOTE_TYPE_COUNT) ) FC_REFLECT( graphene::chain::vote_id_type, (content) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vote_id_type ) diff --git a/libraries/chain/include/graphene/chain/protocol/withdraw_permission.hpp b/libraries/chain/include/graphene/chain/protocol/withdraw_permission.hpp index 7bc905ac..7963e99f 100644 --- a/libraries/chain/include/graphene/chain/protocol/withdraw_permission.hpp +++ b/libraries/chain/include/graphene/chain/protocol/withdraw_permission.hpp @@ -24,6 +24,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { @@ -179,3 +180,12 @@ FC_REFLECT( graphene::chain::withdraw_permission_update_operation, (fee)(withdra FC_REFLECT( graphene::chain::withdraw_permission_claim_operation, (fee)(withdraw_permission)(withdraw_from_account)(withdraw_to_account)(amount_to_withdraw)(memo) ); FC_REFLECT( graphene::chain::withdraw_permission_delete_operation, (fee)(withdraw_from_account)(authorized_account) (withdrawal_permission) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_claim_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_delete_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_claim_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_delete_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/witness.hpp b/libraries/chain/include/graphene/chain/protocol/witness.hpp index b096e826..2b5e88b0 100644 --- a/libraries/chain/include/graphene/chain/protocol/witness.hpp +++ b/libraries/chain/include/graphene/chain/protocol/witness.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -84,3 +85,8 @@ FC_REFLECT( graphene::chain::witness_create_operation, (fee)(witness_account)(ur FC_REFLECT( graphene::chain::witness_update_operation::fee_parameters_type, (fee) ) FC_REFLECT( graphene::chain::witness_update_operation, (fee)(witness)(witness_account)(new_url)(new_signing_key)(new_initial_secret) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_update_operation ) diff --git a/libraries/chain/include/graphene/chain/protocol/worker.hpp b/libraries/chain/include/graphene/chain/protocol/worker.hpp index 9e6eef35..11e0aa05 100644 --- a/libraries/chain/include/graphene/chain/protocol/worker.hpp +++ b/libraries/chain/include/graphene/chain/protocol/worker.hpp @@ -23,6 +23,7 @@ */ #pragma once #include +#include namespace graphene { namespace chain { @@ -104,3 +105,5 @@ FC_REFLECT( graphene::chain::worker_create_operation::fee_parameters_type, (fee) FC_REFLECT( graphene::chain::worker_create_operation, (fee)(owner)(work_begin_date)(work_end_date)(daily_pay)(name)(url)(initializer) ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_create_operation ) diff --git a/libraries/chain/include/graphene/chain/pts_address.hpp b/libraries/chain/include/graphene/chain/pts_address.hpp index 636e2f11..c0bc80ff 100644 --- a/libraries/chain/include/graphene/chain/pts_address.hpp +++ b/libraries/chain/include/graphene/chain/pts_address.hpp @@ -24,6 +24,8 @@ #pragma once #include +#include +#include #include namespace fc { namespace ecc { class public_key; } } @@ -75,4 +77,11 @@ namespace fc { 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 ); -} +namespace raw { + extern template void pack( datastream& s, const graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); + extern template void pack( datastream& s, const graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); + extern template void unpack( datastream& s, graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); +} } // fc::raw diff --git a/libraries/chain/include/graphene/chain/special_authority_object.hpp b/libraries/chain/include/graphene/chain/special_authority_object.hpp index da9ecc5e..75093f3a 100644 --- a/libraries/chain/include/graphene/chain/special_authority_object.hpp +++ b/libraries/chain/include/graphene/chain/special_authority_object.hpp @@ -68,3 +68,5 @@ FC_REFLECT_DERIVED( (graphene::db::object), (account) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::special_authority_object ) diff --git a/libraries/chain/include/graphene/chain/transaction_object.hpp b/libraries/chain/include/graphene/chain/transaction_object.hpp index 4f76d6be..aaaa31f1 100644 --- a/libraries/chain/include/graphene/chain/transaction_object.hpp +++ b/libraries/chain/include/graphene/chain/transaction_object.hpp @@ -22,12 +22,10 @@ * THE SOFTWARE. */ #pragma once -#include #include #include #include -#include #include #include @@ -72,3 +70,5 @@ namespace graphene { namespace chain { } } FC_REFLECT_DERIVED( graphene::chain::transaction_object, (graphene::db::object), (trx)(trx_id) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::transaction_object ) diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index 56b0ac1a..b03b8f7b 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -38,8 +38,6 @@ namespace graphene { namespace chain { using namespace graphene::db; - class vesting_balance_object; - struct vesting_policy_context { vesting_policy_context( @@ -234,3 +232,7 @@ FC_REFLECT_DERIVED(graphene::chain::vesting_balance_object, (graphene::db::objec (policy) (balance_type) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::linear_vesting_policy ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::cdd_vesting_policy ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::vesting_balance_object ) diff --git a/libraries/chain/include/graphene/chain/withdraw_permission_object.hpp b/libraries/chain/include/graphene/chain/withdraw_permission_object.hpp index 000573bd..a6fee0c5 100644 --- a/libraries/chain/include/graphene/chain/withdraw_permission_object.hpp +++ b/libraries/chain/include/graphene/chain/withdraw_permission_object.hpp @@ -114,3 +114,5 @@ FC_REFLECT_DERIVED( graphene::chain::withdraw_permission_object, (graphene::db:: (expiration) (claimed_this_period) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::withdraw_permission_object ) diff --git a/libraries/chain/include/graphene/chain/witness_object.hpp b/libraries/chain/include/graphene/chain/witness_object.hpp index 2d1b7666..7928b46e 100644 --- a/libraries/chain/include/graphene/chain/witness_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_object.hpp @@ -29,8 +29,6 @@ namespace graphene { namespace chain { using namespace graphene::db; - class witness_object; - class witness_object : public abstract_object { public: @@ -85,3 +83,5 @@ FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), (total_missed) (last_confirmed_block_num) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_object ) diff --git a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp index e4c4bb51..1702212d 100644 --- a/libraries/chain/include/graphene/chain/witness_schedule_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_schedule_object.hpp @@ -30,8 +30,6 @@ namespace graphene { namespace chain { -class witness_schedule_object; - typedef hash_ctr_rng< /* HashClass = */ fc::sha256, /* SeedLength = */ GRAPHENE_RNG_SEED_LENGTH @@ -96,3 +94,6 @@ FC_REFLECT_DERIVED( (recent_slots_filled) (current_shuffled_witnesses) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_scheduler ) +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::witness_schedule_object ) diff --git a/libraries/chain/include/graphene/chain/worker_object.hpp b/libraries/chain/include/graphene/chain/worker_object.hpp index 1219fc1c..5e23f0b8 100644 --- a/libraries/chain/include/graphene/chain/worker_object.hpp +++ b/libraries/chain/include/graphene/chain/worker_object.hpp @@ -22,8 +22,9 @@ * THE SOFTWARE. */ #pragma once -#include +#include #include +#include namespace graphene { namespace chain { @@ -175,3 +176,5 @@ FC_REFLECT_DERIVED( graphene::chain::worker_object, (graphene::db::object), (name) (url) ) + +GRAPHENE_EXTERNAL_SERIALIZATION( extern, graphene::chain::worker_object ) diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index 343edce2..1d5a8706 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -37,7 +37,7 @@ bool proposal_object::is_authorized_to_execute(database& db) const [&]( account_id_type id ){ return &id(db).active; }, [&]( account_id_type id ){ return &id(db).owner; }, db.get_global_properties().parameters.max_authority_depth, - true, /* allow committeee */ + true, /* allow committee */ available_active_approvals, available_owner_approvals ); } @@ -90,3 +90,5 @@ void required_approval_index::object_removed( const object& obj ) } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::proposal_object ) diff --git a/libraries/chain/protocol/account.cpp b/libraries/chain/protocol/account.cpp index 9f86473e..c79811b9 100644 --- a/libraries/chain/protocol/account.cpp +++ b/libraries/chain/protocol/account.cpp @@ -24,6 +24,9 @@ #include #include #include + +#include + namespace graphene { namespace chain { /** @@ -320,3 +323,15 @@ void account_transfer_operation::validate()const } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_whitelist_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_upgrade_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_whitelist_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_upgrade_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_transfer_operation ) diff --git a/libraries/chain/protocol/address.cpp b/libraries/chain/protocol/address.cpp index 19bb4df5..f0edbd49 100644 --- a/libraries/chain/protocol/address.cpp +++ b/libraries/chain/protocol/address.cpp @@ -27,9 +27,10 @@ #include #include +#include + namespace graphene { namespace chain { - address::address(){} address::address( const std::string& base58str ) { @@ -110,3 +111,5 @@ namespace fc vo = graphene::chain::address( var.as_string() ); } } + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::address ) diff --git a/libraries/chain/protocol/assert.cpp b/libraries/chain/protocol/assert.cpp index 60f26e3f..5ce61e45 100644 --- a/libraries/chain/protocol/assert.cpp +++ b/libraries/chain/protocol/assert.cpp @@ -21,7 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include +#include +#include +#include + +#include namespace graphene { namespace chain { @@ -62,5 +66,7 @@ share_type assert_operation::calculate_fee(const fee_parameters_type& k)const return k.fee * predicates.size(); } - } } // namespace graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::assert_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::assert_operation ) diff --git a/libraries/chain/protocol/asset.cpp b/libraries/chain/protocol/asset.cpp index c47d88e3..525e193b 100644 --- a/libraries/chain/protocol/asset.cpp +++ b/libraries/chain/protocol/asset.cpp @@ -24,6 +24,7 @@ #include #include #include +#include namespace graphene { namespace chain { typedef boost::multiprecision::uint128_t uint128_t; @@ -206,3 +207,7 @@ const int64_t scaled_precision_lut[19] = }; } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::price ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::price_feed ) diff --git a/libraries/chain/protocol/asset_ops.cpp b/libraries/chain/protocol/asset_ops.cpp index e4942aa4..5dfd09ee 100644 --- a/libraries/chain/protocol/asset_ops.cpp +++ b/libraries/chain/protocol/asset_ops.cpp @@ -24,6 +24,8 @@ #include #include +#include + namespace graphene { namespace chain { /** @@ -288,3 +290,30 @@ void lottery_asset_options::validate() const } } } // namespace graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::bitasset_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_global_settle_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_settle_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_fund_fee_pool_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_claim_fees_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_bitasset_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_feed_producers_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_publish_feed_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_issue_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_reserve_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_global_settle_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_settle_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_settle_cancel_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_fund_fee_pool_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_claim_fees_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_dividend_distribution_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_bitasset_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_update_feed_producers_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_publish_feed_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_issue_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::asset_reserve_operation ) diff --git a/libraries/chain/protocol/authority.cpp b/libraries/chain/protocol/authority.cpp index 97470d33..6cfed2ec 100644 --- a/libraries/chain/protocol/authority.cpp +++ b/libraries/chain/protocol/authority.cpp @@ -23,6 +23,7 @@ */ #include +#include namespace graphene { namespace chain { @@ -36,3 +37,5 @@ void add_authority_accounts( } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::authority ) diff --git a/libraries/chain/protocol/block.cpp b/libraries/chain/protocol/block.cpp index d32365dd..725ea3a7 100644 --- a/libraries/chain/protocol/block.cpp +++ b/libraries/chain/protocol/block.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include #include #include #include @@ -90,3 +91,7 @@ namespace graphene { namespace chain { } } } + +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::block_header) +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::signed_block_header) +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::signed_block) diff --git a/libraries/chain/protocol/committee_member.cpp b/libraries/chain/protocol/committee_member.cpp index 4c8c5d25..1824870a 100644 --- a/libraries/chain/protocol/committee_member.cpp +++ b/libraries/chain/protocol/committee_member.cpp @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include +#include #include +#include + namespace graphene { namespace chain { void committee_member_create_operation::validate()const @@ -45,3 +49,10 @@ void committee_member_update_global_parameters_operation::validate() const } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_update_global_parameters_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_update_global_parameters_operation ) diff --git a/libraries/chain/protocol/confidential.cpp b/libraries/chain/protocol/confidential.cpp index 603befa1..2e8fbc68 100644 --- a/libraries/chain/protocol/confidential.cpp +++ b/libraries/chain/protocol/confidential.cpp @@ -27,7 +27,6 @@ #include #include -#include namespace graphene { namespace chain { @@ -141,9 +140,6 @@ share_type blind_transfer_operation::calculate_fee( const fee_parameters_type& k return k.fee + outputs.size() * k.price_per_output; } - - - /** * Packs *this then encodes as base58 encoded string. */ @@ -159,6 +155,11 @@ stealth_confirmation::stealth_confirmation( const std::string& base58 ) *this = fc::raw::unpack( fc::from_base58( base58 ) ); } - - } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_to_blind_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_from_blind_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blind_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_to_blind_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_from_blind_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blind_transfer_operation ) diff --git a/libraries/chain/protocol/custom.cpp b/libraries/chain/protocol/custom.cpp index b69243be..72f8dd44 100644 --- a/libraries/chain/protocol/custom.cpp +++ b/libraries/chain/protocol/custom.cpp @@ -23,6 +23,8 @@ */ #include +#include + namespace graphene { namespace chain { void custom_operation::validate()const @@ -35,3 +37,6 @@ share_type custom_operation::calculate_fee(const fee_parameters_type& k)const } } } + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::custom_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::custom_operation ) diff --git a/libraries/chain/protocol/fee_schedule.cpp b/libraries/chain/protocol/fee_schedule.cpp index 138d801e..6d494e37 100644 --- a/libraries/chain/protocol/fee_schedule.cpp +++ b/libraries/chain/protocol/fee_schedule.cpp @@ -35,6 +35,8 @@ namespace fc //template const graphene::chain::fee_schedule& smart_ref::operator*() const; } +#include + #define MAX_FEE_STABILIZATION_ITERATION 4 namespace graphene { namespace chain { @@ -208,3 +210,5 @@ namespace graphene { namespace chain { } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::fee_schedule ) diff --git a/libraries/chain/protocol/market.cpp b/libraries/chain/protocol/market.cpp index 923f4763..ae0a3a68 100644 --- a/libraries/chain/protocol/market.cpp +++ b/libraries/chain/protocol/market.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include namespace graphene { namespace chain { @@ -46,3 +47,11 @@ void call_order_update_operation::validate()const } FC_CAPTURE_AND_RETHROW((*this)) } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::limit_order_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::limit_order_cancel_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::call_order_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::limit_order_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::limit_order_cancel_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::call_order_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::fill_order_operation ) diff --git a/libraries/chain/protocol/memo.cpp b/libraries/chain/protocol/memo.cpp index e04b5e43..afa0b486 100644 --- a/libraries/chain/protocol/memo.cpp +++ b/libraries/chain/protocol/memo.cpp @@ -23,6 +23,7 @@ */ #include #include +#include namespace graphene { namespace chain { @@ -88,3 +89,6 @@ memo_message memo_message::deserialize(const string& serial) } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::memo_message ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::memo_data ) diff --git a/libraries/chain/protocol/operations.cpp b/libraries/chain/protocol/operations.cpp index 40a37eba..7db51078 100644 --- a/libraries/chain/protocol/operations.cpp +++ b/libraries/chain/protocol/operations.cpp @@ -21,7 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include +#include +#include namespace graphene { namespace chain { @@ -85,3 +88,5 @@ void operation_get_required_authorities( const operation& op, } } } // namespace graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::op_wrapper ) diff --git a/libraries/chain/protocol/proposal.cpp b/libraries/chain/protocol/proposal.cpp index 069824af..c77e71e4 100644 --- a/libraries/chain/protocol/proposal.cpp +++ b/libraries/chain/protocol/proposal.cpp @@ -25,6 +25,8 @@ #include #include +#include + namespace graphene { namespace chain { proposal_create_operation proposal_create_operation::committee_proposal(const chain_parameters& global_params, fc::time_point_sec head_block_time ) @@ -105,3 +107,10 @@ void proposal_update_operation::get_required_owner_authorities( flat_set +#include +#include +#include +#include +#include +#include + +#include + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::balance_claim_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::buyback_account_options ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::fba_distribute_operation ) + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vesting_balance_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vesting_balance_withdraw_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vesting_balance_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vesting_balance_withdraw_operation ) + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::chain_parameters ) diff --git a/libraries/chain/protocol/tournament.cpp b/libraries/chain/protocol/tournament.cpp index 57e80bf3..78ab4c01 100644 --- a/libraries/chain/protocol/tournament.cpp +++ b/libraries/chain/protocol/tournament.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include namespace graphene { namespace chain { diff --git a/libraries/chain/protocol/transaction.cpp b/libraries/chain/protocol/transaction.cpp index a11e3335..093e7833 100644 --- a/libraries/chain/protocol/transaction.cpp +++ b/libraries/chain/protocol/transaction.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace graphene { namespace chain { @@ -390,3 +391,7 @@ void signed_transaction::verify_authority( } FC_CAPTURE_AND_RETHROW( (*this) ) } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::transaction) +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::signed_transaction) +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::chain::processed_transaction) diff --git a/libraries/chain/protocol/transfer.cpp b/libraries/chain/protocol/transfer.cpp index 3dfe4eb7..0fb0aefa 100644 --- a/libraries/chain/protocol/transfer.cpp +++ b/libraries/chain/protocol/transfer.cpp @@ -23,6 +23,8 @@ */ #include +#include + namespace graphene { namespace chain { share_type transfer_operation::calculate_fee( const fee_parameters_type& schedule )const @@ -61,3 +63,8 @@ void override_transfer_operation::validate()const } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::override_transfer_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transfer_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::override_transfer_operation ) diff --git a/libraries/chain/protocol/vote.cpp b/libraries/chain/protocol/vote.cpp index f78f2b4f..68f476f5 100644 --- a/libraries/chain/protocol/vote.cpp +++ b/libraries/chain/protocol/vote.cpp @@ -49,3 +49,5 @@ void from_variant( const variant& var, graphene::chain::vote_id_type& vo, uint32 } } // fc + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vote_id_type ) diff --git a/libraries/chain/protocol/withdraw_permission.cpp b/libraries/chain/protocol/withdraw_permission.cpp index 33b40c85..b36c378d 100644 --- a/libraries/chain/protocol/withdraw_permission.cpp +++ b/libraries/chain/protocol/withdraw_permission.cpp @@ -23,6 +23,8 @@ */ #include +#include + namespace graphene { namespace chain { void withdraw_permission_update_operation::validate()const @@ -65,6 +67,13 @@ void withdraw_permission_delete_operation::validate() const FC_ASSERT( withdraw_from_account != authorized_account ); } - } } // graphene::chain +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_claim_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_delete_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_update_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_claim_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_delete_operation ) diff --git a/libraries/chain/protocol/witness.cpp b/libraries/chain/protocol/witness.cpp index 82fa462a..90583cd8 100644 --- a/libraries/chain/protocol/witness.cpp +++ b/libraries/chain/protocol/witness.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include namespace graphene { namespace chain { @@ -39,3 +40,8 @@ void witness_update_operation::validate() const } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_update_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_create_operation ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_update_operation ) diff --git a/libraries/chain/protocol/worker.cpp b/libraries/chain/protocol/worker.cpp index eb133da0..932148ec 100644 --- a/libraries/chain/protocol/worker.cpp +++ b/libraries/chain/protocol/worker.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. */ #include +#include namespace graphene { namespace chain { @@ -36,3 +37,6 @@ void worker_create_operation::validate() const } } } + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::worker_create_operation::fee_parameters_type ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::worker_create_operation ) diff --git a/libraries/chain/pts_address.cpp b/libraries/chain/pts_address.cpp index 27f3d256..c6d74f58 100644 --- a/libraries/chain/pts_address.cpp +++ b/libraries/chain/pts_address.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace graphene { namespace chain { @@ -97,4 +98,12 @@ namespace fc { vo = graphene::chain::pts_address( var.as_string() ); } -} + +namespace raw { + template void pack( datastream& s, const graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); + template void pack( datastream& s, const graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); + template void unpack( datastream& s, graphene::chain::pts_address& tx, + uint32_t _max_depth=FC_PACK_MAX_DEPTH ); +} } // fc::raw diff --git a/libraries/chain/small_objects.cpp b/libraries/chain/small_objects.cpp new file mode 100644 index 00000000..a74fa116 --- /dev/null +++ b/libraries/chain/small_objects.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 BitShares Blockchain Foundation, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::block_summary_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::budget_record ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::budget_record_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::buyback_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::immutable_chain_parameters ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::limit_order_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::call_order_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::force_settlement_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::chain_property_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::committee_member_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::blinded_balance_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::fba_accumulator_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::dynamic_global_property_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::global_property_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::operation_history_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::account_transaction_history_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::special_authority_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::transaction_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::withdraw_permission_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_scheduler ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::witness_schedule_object ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::worker_object ) diff --git a/libraries/chain/special_authority.cpp b/libraries/chain/special_authority.cpp index ca974f30..74889f80 100644 --- a/libraries/chain/special_authority.cpp +++ b/libraries/chain/special_authority.cpp @@ -25,6 +25,8 @@ #include #include +#include + namespace graphene { namespace chain { struct special_authority_validate_visitor @@ -68,3 +70,6 @@ void evaluate_special_authority( const database& db, const special_authority& a } } } // graphene::chain + + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::top_holders_special_authority ) diff --git a/libraries/chain/vesting_balance_evaluator.cpp b/libraries/chain/vesting_balance_evaluator.cpp index ec974600..e81383b6 100644 --- a/libraries/chain/vesting_balance_evaluator.cpp +++ b/libraries/chain/vesting_balance_evaluator.cpp @@ -118,19 +118,8 @@ object_id_type vesting_balance_create_evaluator::do_apply( const vesting_balance operation_result vesting_balance_withdraw_evaluator::start_evaluate( transaction_evaluation_state& eval_state, const operation& op, bool apply ) { try { trx_state = &eval_state; - database& d = db(); const auto& oper = op.get(); - const time_point_sec now = d.head_block_time(); - - if(now >= HARDFORK_GPOS_TIME ) - { - if(oper.fee.amount == 0) - { - trx_state->skip_fee_schedule_check = true; - trx_state->skip_fee = true; - } - } //check_required_authorities(op); auto result = evaluate( oper ); @@ -144,10 +133,32 @@ void_result vesting_balance_withdraw_evaluator::do_evaluate( const vesting_balan const time_point_sec now = d.head_block_time(); const vesting_balance_object& vbo = op.vesting_balance( d ); - FC_ASSERT( op.owner == vbo.owner, "", ("op.owner", op.owner)("vbo.owner", vbo.owner) ); - FC_ASSERT( vbo.is_withdraw_allowed( now, op.amount ), "Account has either insufficient ${balance_type} Vested Balance or lock-in period is not matured", - ("balance_type", get_vesting_balance_type(vbo.balance_type))("now", now)("op", op)("vbo", vbo) ); - assert( op.amount <= vbo.balance ); // is_withdraw_allowed should fail before this check is reached + if(vbo.balance_type == vesting_balance_type::normal) + { + FC_ASSERT( op.owner == vbo.owner, "", ("op.owner", op.owner)("vbo.owner", vbo.owner) ); + FC_ASSERT( vbo.is_withdraw_allowed( now, op.amount ), "Account has insufficient ${balance_type} Vested Balance to withdraw", + ("balance_type", get_vesting_balance_type(vbo.balance_type))("now", now)("op", op)("vbo", vbo) ); + assert( op.amount <= vbo.balance ); // is_withdraw_allowed should fail before this check is reached + } + else if(now > HARDFORK_GPOS_TIME && vbo.balance_type == vesting_balance_type::gpos) + { + const account_id_type account_id = op.owner; + vector vbos; + auto vesting_range = d.get_index_type().indices().get().equal_range(account_id); + std::for_each(vesting_range.first, vesting_range.second, + [&vbos, now](const vesting_balance_object& balance) { + if(balance.balance.amount > 0 && balance.balance_type == vesting_balance_type::gpos + && balance.is_withdraw_allowed(now, balance.balance.amount) && balance.balance.asset_id == asset_id_type()) + vbos.emplace_back(balance); + }); + + asset total_amount; + for (const vesting_balance_object& vesting_balance_obj : vbos) + { + total_amount += vesting_balance_obj.balance.amount; + } + FC_ASSERT( op.amount <= total_amount, "Account has either insufficient GPOS Vested Balance or lock-in period is not matured"); + } /* const account_object& owner_account = op.owner( d ); */ // TODO: Check asset authorizations and withdrawals @@ -159,21 +170,53 @@ void_result vesting_balance_withdraw_evaluator::do_apply( const vesting_balance_ database& d = db(); const time_point_sec now = d.head_block_time(); - + //Handling all GPOS withdrawls separately from normal and SONs(future extension). + // One request/transaction would be sufficient to withdraw from multiple vesting balance ids const vesting_balance_object& vbo = op.vesting_balance( d ); - - // Allow zero balance objects to stick around, (1) to comply - // with the chain's "objects live forever" design principle, (2) - // if it's cashback or worker, it'll be filled up again. - - d.modify( vbo, [&]( vesting_balance_object& vbo ) + if(vbo.balance_type == vesting_balance_type::normal) { - vbo.withdraw( now, op.amount ); - } ); + // Allow zero balance objects to stick around, (1) to comply + // with the chain's "objects live forever" design principle, (2) + // if it's cashback or worker, it'll be filled up again. - d.adjust_balance( op.owner, op.amount ); + d.modify( vbo, [&]( vesting_balance_object& vbo ) + { + vbo.withdraw( now, op.amount ); + } ); + + d.adjust_balance( op.owner, op.amount ); + } + else if(now > HARDFORK_GPOS_TIME && vbo.balance_type == vesting_balance_type::gpos) + { + const account_id_type account_id = op.owner; + vector ids; + auto vesting_range = d.get_index_type().indices().get().equal_range(account_id); + std::for_each(vesting_range.first, vesting_range.second, + [&ids, now](const vesting_balance_object& balance) { + if(balance.balance.amount > 0 && balance.balance_type == vesting_balance_type::gpos + && balance.is_withdraw_allowed(now, balance.balance.amount) && balance.balance.asset_id == asset_id_type()) + ids.emplace_back(balance.id); + }); + + asset total_withdraw_amount = op.amount; + for (const vesting_balance_id_type& id : ids) + { + const vesting_balance_object& vbo = id( d ); + if(total_withdraw_amount.amount > vbo.balance.amount) + { + total_withdraw_amount.amount -= vbo.balance.amount; + d.adjust_balance( op.owner, vbo.balance ); + d.modify( vbo, [&]( vesting_balance_object& vbo ) {vbo.withdraw( now, vbo.balance );} ); + } + else + { + d.modify( vbo, [&]( vesting_balance_object& vbo ) {vbo.withdraw( now, total_withdraw_amount );} ); + d.adjust_balance( op.owner, total_withdraw_amount); + break; + } + } + } - // TODO: Check asset authorizations and withdrawals return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/vesting_balance_object.cpp b/libraries/chain/vesting_balance_object.cpp index afba2557..4674c974 100644 --- a/libraries/chain/vesting_balance_object.cpp +++ b/libraries/chain/vesting_balance_object.cpp @@ -24,6 +24,8 @@ #include +#include + namespace graphene { namespace chain { inline bool sum_below_max_shares(const asset& a, const asset& b) @@ -248,3 +250,7 @@ asset vesting_balance_object::get_allowed_withdraw(const time_point_sec& now)con } } } // graphene::chain + +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::linear_vesting_policy ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::cdd_vesting_policy ) +GRAPHENE_EXTERNAL_SERIALIZATION( /*not extern*/, graphene::chain::vesting_balance_object ) diff --git a/libraries/egenesis/egenesis_none.cpp b/libraries/egenesis/egenesis_none.cpp index 825f7f83..c7a0dcdd 100644 --- a/libraries/egenesis/egenesis_none.cpp +++ b/libraries/egenesis/egenesis_none.cpp @@ -24,6 +24,8 @@ #include +#include + namespace graphene { namespace egenesis { using namespace graphene::chain; diff --git a/libraries/fc b/libraries/fc index bca39221..31e289c5 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit bca392213c5104773be9ffa0fbde8958835a5da2 +Subproject commit 31e289c53d3625afea87c54edb6d97c3bca4c626 diff --git a/libraries/net/CMakeLists.txt b/libraries/net/CMakeLists.txt index 7aa617d7..955012e4 100644 --- a/libraries/net/CMakeLists.txt +++ b/libraries/net/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES node.cpp core_messages.cpp peer_database.cpp peer_connection.cpp + message.cpp message_oriented_connection.cpp) add_library( graphene_net ${SOURCES} ${HEADERS} ) diff --git a/libraries/net/include/graphene/net/message.hpp b/libraries/net/include/graphene/net/message.hpp index cfef1519..686fea24 100644 --- a/libraries/net/include/graphene/net/message.hpp +++ b/libraries/net/include/graphene/net/message.hpp @@ -22,12 +22,16 @@ * THE SOFTWARE. */ #pragma once +#include + +#include + #include #include #include -#include +#include #include -#include +#include namespace graphene { namespace net { @@ -108,10 +112,10 @@ namespace graphene { namespace net { } }; - - - } } // graphene::net FC_REFLECT( graphene::net::message_header, (size)(msg_type) ) FC_REFLECT_DERIVED( graphene::net::message, (graphene::net::message_header), (data) ) + +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::net::message_header) +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::net::message) diff --git a/libraries/net/include/graphene/net/peer_connection.hpp b/libraries/net/include/graphene/net/peer_connection.hpp index 6f9a4b20..5c5f40d5 100644 --- a/libraries/net/include/graphene/net/peer_connection.hpp +++ b/libraries/net/include/graphene/net/peer_connection.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -35,9 +34,7 @@ #include #include #include -#include #include -#include #include #include diff --git a/libraries/net/include/graphene/net/peer_database.hpp b/libraries/net/include/graphene/net/peer_database.hpp index d0a06dd9..ff7f4036 100644 --- a/libraries/net/include/graphene/net/peer_database.hpp +++ b/libraries/net/include/graphene/net/peer_database.hpp @@ -24,13 +24,14 @@ #pragma once #include +#include + #include #include #include #include #include #include -#include namespace graphene { namespace net { @@ -118,5 +119,6 @@ namespace graphene { namespace net { } } // end namespace graphene::net -FC_REFLECT_ENUM(graphene::net::potential_peer_last_connection_disposition, (never_attempted_to_connect)(last_connection_failed)(last_connection_rejected)(last_connection_handshaking_failed)(last_connection_succeeded)) -FC_REFLECT(graphene::net::potential_peer_record, (endpoint)(last_seen_time)(last_connection_disposition)(last_connection_attempt_time)(number_of_successful_connection_attempts)(number_of_failed_connection_attempts)(last_error) ) +FC_REFLECT_TYPENAME( graphene::net::potential_peer_record ) + +GRAPHENE_EXTERNAL_SERIALIZATION(extern, graphene::net::potential_peer_record) diff --git a/libraries/net/message.cpp b/libraries/net/message.cpp new file mode 100644 index 00000000..6d35bfe5 --- /dev/null +++ b/libraries/net/message.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2019 BitShares Blockchain Foundation, 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 + +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::net::message_header) +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::net::message) diff --git a/libraries/net/node.cpp b/libraries/net/node.cpp index 14d93d50..0fc61dde 100644 --- a/libraries/net/node.cpp +++ b/libraries/net/node.cpp @@ -66,6 +66,7 @@ #include #include #include +#include #include #include #include diff --git a/libraries/net/peer_connection.cpp b/libraries/net/peer_connection.cpp index 4dd151b5..9b753e6c 100644 --- a/libraries/net/peer_connection.cpp +++ b/libraries/net/peer_connection.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include diff --git a/libraries/net/peer_database.cpp b/libraries/net/peer_database.cpp index 2b20364e..76ae9c8c 100644 --- a/libraries/net/peer_database.cpp +++ b/libraries/net/peer_database.cpp @@ -274,3 +274,14 @@ namespace graphene { namespace net { } } } // end namespace graphene::net + +FC_REFLECT_ENUM( graphene::net::potential_peer_last_connection_disposition, + (never_attempted_to_connect) + (last_connection_failed)(last_connection_rejected) + (last_connection_handshaking_failed)(last_connection_succeeded) ) +FC_REFLECT_DERIVED_NO_TYPENAME( graphene::net::potential_peer_record, BOOST_PP_SEQ_NIL, + (endpoint)(last_seen_time)(last_connection_disposition) + (last_connection_attempt_time)(number_of_successful_connection_attempts) + (number_of_failed_connection_attempts)(last_error) ) + +GRAPHENE_EXTERNAL_SERIALIZATION(/*not extern*/, graphene::net::potential_peer_record) diff --git a/libraries/plugins/CMakeLists.txt b/libraries/plugins/CMakeLists.txt index 01079fe2..58728a9e 100644 --- a/libraries/plugins/CMakeLists.txt +++ b/libraries/plugins/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory( witness ) add_subdirectory( account_history ) add_subdirectory( accounts_list ) add_subdirectory( affiliate_stats ) +add_subdirectory( elasticsearch ) add_subdirectory( market_history ) add_subdirectory( delayed_node ) add_subdirectory( bookie ) @@ -9,3 +10,4 @@ add_subdirectory( generate_genesis ) add_subdirectory( generate_uia_sharedrop_genesis ) add_subdirectory( debug_witness ) add_subdirectory( snapshot ) +add_subdirectory( es_objects ) diff --git a/libraries/plugins/account_history/account_history_plugin.cpp b/libraries/plugins/account_history/account_history_plugin.cpp index 81acb01e..67322f80 100644 --- a/libraries/plugins/account_history/account_history_plugin.cpp +++ b/libraries/plugins/account_history/account_history_plugin.cpp @@ -24,7 +24,7 @@ #include -#include +#include #include #include @@ -128,8 +128,8 @@ void account_history_plugin_impl::update_account_histories( const signed_block& if( op.op.which() == operation::tag< account_create_operation >::value ) impacted.insert( op.result.get() ); else - graphene::app::operation_get_impacted_accounts( op.op, impacted ); - if( op.op.which() == operation::tag< lottery_end_operation >::value ) + graphene::chain::operation_get_impacted_accounts( op.op, impacted ); + if( op.op.which() == operation::tag< lottery_end_operation >::value ) { auto lop = op.op.get< lottery_end_operation >(); auto asset_object = lop.lottery( db ); @@ -137,6 +137,7 @@ void account_history_plugin_impl::update_account_histories( const signed_block& for( auto benefactor : asset_object.lottery_options->benefactors ) impacted.insert( benefactor.id ); } + for( auto& a : other ) for( auto& item : a.account_auths ) impacted.insert( item.first ); diff --git a/libraries/plugins/accounts_list/accounts_list_plugin.cpp b/libraries/plugins/accounts_list/accounts_list_plugin.cpp index aabf711d..757891ea 100644 --- a/libraries/plugins/accounts_list/accounts_list_plugin.cpp +++ b/libraries/plugins/accounts_list/accounts_list_plugin.cpp @@ -24,7 +24,7 @@ #include -#include +#include #include #include diff --git a/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp b/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp index 438b1aca..da9c8a04 100644 --- a/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp +++ b/libraries/plugins/affiliate_stats/affiliate_stats_plugin.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/libraries/plugins/bookie/bookie_plugin.cpp b/libraries/plugins/bookie/bookie_plugin.cpp index f15ac2f7..261de241 100644 --- a/libraries/plugins/bookie/bookie_plugin.cpp +++ b/libraries/plugins/bookie/bookie_plugin.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include @@ -370,8 +370,8 @@ void bookie_plugin_impl::on_block_applied( const signed_block& ) assert(bet_iter != persistent_bets_by_bet_id.end()); if (bet_iter != persistent_bets_by_bet_id.end()) { - ilog("Adding bet_canceled_operation ${canceled_id} to bet ${bet_id}'s associated operations", - ("canceled_id", op.id)("bet_id", bet_canceled_op.bet_id)); + // ilog("Adding bet_canceled_operation ${canceled_id} to bet ${bet_id}'s associated operations", + // ("canceled_id", op.id)("bet_id", bet_canceled_op.bet_id)); if (is_operation_history_object_stored(op.id)) db.modify(*bet_iter, [&]( persistent_bet_object& obj ) { obj.associated_operations.emplace_back(op.id); @@ -386,8 +386,8 @@ void bookie_plugin_impl::on_block_applied( const signed_block& ) assert(bet_iter != persistent_bets_by_bet_id.end()); if (bet_iter != persistent_bets_by_bet_id.end()) { - ilog("Adding bet_adjusted_operation ${adjusted_id} to bet ${bet_id}'s associated operations", - ("adjusted_id", op.id)("bet_id", bet_adjusted_op.bet_id)); + // ilog("Adding bet_adjusted_operation ${adjusted_id} to bet ${bet_id}'s associated operations", + // ("adjusted_id", op.id)("bet_id", bet_adjusted_op.bet_id)); if (is_operation_history_object_stored(op.id)) db.modify(*bet_iter, [&]( persistent_bet_object& obj ) { obj.associated_operations.emplace_back(op.id); diff --git a/libraries/plugins/delayed_node/delayed_node_plugin.cpp b/libraries/plugins/delayed_node/delayed_node_plugin.cpp index f9db2ccd..d49129b0 100644 --- a/libraries/plugins/delayed_node/delayed_node_plugin.cpp +++ b/libraries/plugins/delayed_node/delayed_node_plugin.cpp @@ -58,7 +58,7 @@ delayed_node_plugin::~delayed_node_plugin() void delayed_node_plugin::plugin_set_program_options(bpo::options_description& cli, bpo::options_description& cfg) { cli.add_options() - ("trusted-node", boost::program_options::value()->required(), "RPC endpoint of a trusted validating node (required)") + ("trusted-node", boost::program_options::value(), "RPC endpoint of a trusted validating node (required)") ; cfg.add(cli); } @@ -74,6 +74,7 @@ void delayed_node_plugin::connect() void delayed_node_plugin::plugin_initialize(const boost::program_options::variables_map& options) { + FC_ASSERT(options.count("trusted-node") > 0); my->remote_endpoint = "ws://" + options.at("trusted-node").as(); } diff --git a/libraries/plugins/elasticsearch/CMakeLists.txt b/libraries/plugins/elasticsearch/CMakeLists.txt new file mode 100644 index 00000000..f4815576 --- /dev/null +++ b/libraries/plugins/elasticsearch/CMakeLists.txt @@ -0,0 +1,23 @@ +file(GLOB HEADERS "include/graphene/elasticsearch/*.hpp") + +add_library( graphene_elasticsearch + elasticsearch_plugin.cpp + ) + +target_link_libraries( graphene_elasticsearch graphene_chain graphene_app curl ) +target_include_directories( graphene_elasticsearch + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +if(MSVC) + set_source_files_properties(elasticsearch_plugin.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) +endif(MSVC) + +install( TARGETS + graphene_elasticsearch + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/elasticsearch" ) + diff --git a/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp new file mode 100644 index 00000000..96dbab7c --- /dev/null +++ b/libraries/plugins/elasticsearch/elasticsearch_plugin.cpp @@ -0,0 +1,616 @@ +/* + * Copyright (c) 2017 Cryptonomex, Inc., 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 +#include +#include +#include + +namespace graphene { namespace elasticsearch { + +namespace detail +{ + +class elasticsearch_plugin_impl +{ + public: + elasticsearch_plugin_impl(elasticsearch_plugin& _plugin) + : _self( _plugin ) + { curl = curl_easy_init(); } + virtual ~elasticsearch_plugin_impl(); + + bool update_account_histories( const signed_block& b ); + + graphene::chain::database& database() + { + return _self.database(); + } + + elasticsearch_plugin& _self; + primary_index< operation_history_index >* _oho_index; + + std::string _elasticsearch_node_url = "http://localhost:9200/"; + uint32_t _elasticsearch_bulk_replay = 10000; + uint32_t _elasticsearch_bulk_sync = 100; + bool _elasticsearch_visitor = false; + std::string _elasticsearch_basic_auth = ""; + std::string _elasticsearch_index_prefix = "peerplays-"; + bool _elasticsearch_operation_object = false; + uint32_t _elasticsearch_start_es_after_block = 0; + bool _elasticsearch_operation_string = true; + mode _elasticsearch_mode = mode::only_save; + CURL *curl; // curl handler + vector bulk_lines; // vector of op lines + vector prepare; + + graphene::utilities::ES es; + uint32_t limit_documents; + int16_t op_type; + operation_history_struct os; + block_struct bs; + visitor_struct vs; + bulk_struct bulk_line_struct; + std::string bulk_line; + std::string index_name; + bool is_sync = false; + fc::time_point last_sync; + private: + bool add_elasticsearch( const account_id_type account_id, const optional& oho, const uint32_t block_number ); + const account_transaction_history_object& addNewEntry(const account_statistics_object& stats_obj, + const account_id_type account_id, + const optional & oho); + const account_statistics_object& getStatsObject(const account_id_type account_id); + void growStats(const account_statistics_object& stats_obj, const account_transaction_history_object& ath); + void getOperationType(const optional & oho); + void doOperationHistory(const optional & oho); + void doBlock(const optional & oho, const signed_block& b); + void doVisitor(const optional & oho); + void checkState(const fc::time_point_sec& block_time); + void cleanObjects(const account_transaction_history_object& ath, account_id_type account_id); + void createBulkLine(const account_transaction_history_object& ath); + void prepareBulk(const account_transaction_history_id_type& ath_id); + void populateESstruct(); +}; + +elasticsearch_plugin_impl::~elasticsearch_plugin_impl() +{ + if (curl) { + curl_easy_cleanup(curl); + curl = nullptr; + } + return; +} + +bool elasticsearch_plugin_impl::update_account_histories( const signed_block& b ) +{ + checkState(b.timestamp); + index_name = graphene::utilities::generateIndexName(b.timestamp, _elasticsearch_index_prefix); + + graphene::chain::database& db = database(); + const vector >& hist = db.get_applied_operations(); + bool is_first = true; + auto skip_oho_id = [&is_first,&db,this]() { + if( is_first && db._undo_db.enabled() ) // this ensures that the current id is rolled back on undo + { + db.remove( db.create( []( operation_history_object& obj) {} ) ); + is_first = false; + } + else + _oho_index->use_next_id(); + }; + for( const optional< operation_history_object >& o_op : hist ) { + optional oho; + + auto create_oho = [&]() { + is_first = false; + return optional( + db.create([&](operation_history_object &h) { + if (o_op.valid()) + { + h.op = o_op->op; + h.result = o_op->result; + h.block_num = o_op->block_num; + h.trx_in_block = o_op->trx_in_block; + h.op_in_trx = o_op->op_in_trx; + h.virtual_op = o_op->virtual_op; + } + })); + }; + + if( !o_op.valid() ) { + skip_oho_id(); + continue; + } + oho = create_oho(); + + // populate what we can before impacted loop + getOperationType(oho); + doOperationHistory(oho); + doBlock(oho, b); + if(_elasticsearch_visitor) + doVisitor(oho); + + const operation_history_object& op = *o_op; + + // get the set of accounts this operation applies to + flat_set impacted; + vector other; + operation_get_required_authorities( op.op, impacted, impacted, other ); // fee_payer is added here + + if( op.op.which() == operation::tag< account_create_operation >::value ) + impacted.insert( op.result.get() ); + else + graphene::chain::operation_get_impacted_accounts( op.op, impacted ); + + for( auto& a : other ) + for( auto& item : a.account_auths ) + impacted.insert( item.first ); + + for( auto& account_id : impacted ) + { + if(!add_elasticsearch( account_id, oho, b.block_num() )) + return false; + } + } + // we send bulk at end of block when we are in sync for better real time client experience + if(is_sync) + { + populateESstruct(); + if(es.bulk_lines.size() > 0) + { + prepare.clear(); + if(!graphene::utilities::SendBulk(es)) + return false; + else + bulk_lines.clear(); + } + } + + return true; +} + +void elasticsearch_plugin_impl::checkState(const fc::time_point_sec& block_time) +{ + fc::time_point current_time(fc::time_point::now()); + if(((current_time - block_time) < fc::seconds(30)) || (current_time - last_sync > fc::seconds(60))) + { + limit_documents = _elasticsearch_bulk_sync; + is_sync = true; + last_sync = current_time; + } + else + { + limit_documents = _elasticsearch_bulk_replay; + is_sync = false; + } +} + +void elasticsearch_plugin_impl::getOperationType(const optional & oho) +{ + if (!oho->id.is_null()) + op_type = oho->op.which(); +} + +void elasticsearch_plugin_impl::doOperationHistory(const optional & oho) +{ + os.trx_in_block = oho->trx_in_block; + os.op_in_trx = oho->op_in_trx; + os.operation_result = fc::json::to_string(oho->result); + os.virtual_op = oho->virtual_op; + + if(_elasticsearch_operation_object) { + oho->op.visit(fc::from_static_variant(os.op_object, FC_PACK_MAX_DEPTH)); + adaptor_struct adaptor; + os.op_object = adaptor.adapt(os.op_object.get_object()); + } + if(_elasticsearch_operation_string) + os.op = fc::json::to_string(oho->op); +} + +void elasticsearch_plugin_impl::doBlock(const optional & oho, const signed_block& b) +{ + std::string trx_id = ""; + if(oho->trx_in_block < b.transactions.size()) + trx_id = b.transactions[oho->trx_in_block].id().str(); + bs.block_num = b.block_num(); + bs.block_time = b.timestamp; + bs.trx_id = trx_id; +} + +void elasticsearch_plugin_impl::doVisitor(const optional & oho) +{ + operation_visitor o_v; + oho->op.visit(o_v); + + vs.fee_data.asset = o_v.fee_asset; + vs.fee_data.amount = o_v.fee_amount; + + vs.transfer_data.asset = o_v.transfer_asset_id; + vs.transfer_data.amount = o_v.transfer_amount; + vs.transfer_data.from = o_v.transfer_from; + vs.transfer_data.to = o_v.transfer_to; + + vs.fill_data.order_id = o_v.fill_order_id; + vs.fill_data.account_id = o_v.fill_account_id; + vs.fill_data.pays_asset_id = o_v.fill_pays_asset_id; + vs.fill_data.pays_amount = o_v.fill_pays_amount; + vs.fill_data.receives_asset_id = o_v.fill_receives_asset_id; + vs.fill_data.receives_amount = o_v.fill_receives_amount; + //vs.fill_data.fill_price = o_v.fill_fill_price; + //vs.fill_data.is_maker = o_v.fill_is_maker; +} + +bool elasticsearch_plugin_impl::add_elasticsearch( const account_id_type account_id, + const optional & oho, + const uint32_t block_number) +{ + const auto &stats_obj = getStatsObject(account_id); + const auto &ath = addNewEntry(stats_obj, account_id, oho); + growStats(stats_obj, ath); + if(block_number > _elasticsearch_start_es_after_block) { + createBulkLine(ath); + prepareBulk(ath.id); + } + cleanObjects(ath, account_id); + + if (curl && bulk_lines.size() >= limit_documents) { // we are in bulk time, ready to add data to elasticsearech + prepare.clear(); + populateESstruct(); + if(!graphene::utilities::SendBulk(es)) + return false; + else + bulk_lines.clear(); + } + + return true; +} + +const account_statistics_object& elasticsearch_plugin_impl::getStatsObject(const account_id_type account_id) +{ + graphene::chain::database& db = database(); + const auto &acct = db.get(account_id); + return acct.statistics(db); +} + +const account_transaction_history_object& elasticsearch_plugin_impl::addNewEntry(const account_statistics_object& stats_obj, + const account_id_type account_id, + const optional & oho) +{ + graphene::chain::database& db = database(); + const auto &ath = db.create([&](account_transaction_history_object &obj) { + obj.operation_id = oho->id; + obj.account = account_id; + obj.sequence = stats_obj.total_ops + 1; + obj.next = stats_obj.most_recent_op; + }); + + return ath; +} + +void elasticsearch_plugin_impl::growStats(const account_statistics_object& stats_obj, + const account_transaction_history_object& ath) +{ + graphene::chain::database& db = database(); + db.modify(stats_obj, [&](account_statistics_object &obj) { + obj.most_recent_op = ath.id; + obj.total_ops = ath.sequence; + }); +} + +void elasticsearch_plugin_impl::createBulkLine(const account_transaction_history_object& ath) +{ + bulk_line_struct.account_history = ath; + bulk_line_struct.operation_history = os; + bulk_line_struct.operation_type = op_type; + bulk_line_struct.operation_id_num = ath.operation_id.instance.value; + bulk_line_struct.block_data = bs; + if(_elasticsearch_visitor) + bulk_line_struct.additional_data = vs; + bulk_line = fc::json::to_string(bulk_line_struct); +} + +void elasticsearch_plugin_impl::prepareBulk(const account_transaction_history_id_type& ath_id) +{ + const std::string _id = fc::json::to_string(ath_id); + fc::mutable_variant_object bulk_header; + bulk_header["_index"] = index_name; + bulk_header["_type"] = "data"; + bulk_header["_id"] = fc::to_string(ath_id.space_id) + "." + fc::to_string(ath_id.type_id) + "." + ath_id.instance; + prepare = graphene::utilities::createBulk(bulk_header, bulk_line); + bulk_lines.insert(bulk_lines.end(), prepare.begin(), prepare.end()); +} + +void elasticsearch_plugin_impl::cleanObjects(const account_transaction_history_object& ath, account_id_type account_id) +{ + graphene::chain::database& db = database(); + // remove everything except current object from ath + const auto &his_idx = db.get_index_type(); + const auto &by_seq_idx = his_idx.indices().get(); + auto itr = by_seq_idx.lower_bound(boost::make_tuple(account_id, 0)); + if (itr != by_seq_idx.end() && itr->account == account_id && itr->id != ath.id) { + // if found, remove the entry + const auto remove_op_id = itr->operation_id; + const auto itr_remove = itr; + ++itr; + db.remove( *itr_remove ); + // modify previous node's next pointer + // this should be always true, but just have a check here + if( itr != by_seq_idx.end() && itr->account == account_id ) + { + db.modify( *itr, [&]( account_transaction_history_object& obj ){ + obj.next = account_transaction_history_id_type(); + }); + } + // do the same on oho + const auto &by_opid_idx = his_idx.indices().get(); + if (by_opid_idx.find(remove_op_id) == by_opid_idx.end()) { + db.remove(remove_op_id(db)); + } + } +} + +void elasticsearch_plugin_impl::populateESstruct() +{ + es.curl = curl; + es.bulk_lines = bulk_lines; + es.elasticsearch_url = _elasticsearch_node_url; + es.auth = _elasticsearch_basic_auth; +} + +} // end namespace detail + +elasticsearch_plugin::elasticsearch_plugin() : + my( new detail::elasticsearch_plugin_impl(*this) ) +{ +} + +elasticsearch_plugin::~elasticsearch_plugin() +{ +} + +std::string elasticsearch_plugin::plugin_name()const +{ + return "elasticsearch"; +} +std::string elasticsearch_plugin::plugin_description()const +{ + return "Stores account history data in elasticsearch database(EXPERIMENTAL)."; +} + +void elasticsearch_plugin::plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg + ) +{ + cli.add_options() + ("elasticsearch-node-url", boost::program_options::value(), + "Elastic Search database node url(http://localhost:9200/)") + ("elasticsearch-bulk-replay", boost::program_options::value(), + "Number of bulk documents to index on replay(10000)") + ("elasticsearch-bulk-sync", boost::program_options::value(), + "Number of bulk documents to index on a syncronied chain(100)") + ("elasticsearch-visitor", boost::program_options::value(), + "Use visitor to index additional data(slows down the replay(false))") + ("elasticsearch-basic-auth", boost::program_options::value(), + "Pass basic auth to elasticsearch database('')") + ("elasticsearch-index-prefix", boost::program_options::value(), + "Add a prefix to the index(peerplays-)") + ("elasticsearch-operation-object", boost::program_options::value(), + "Save operation as object(false)") + ("elasticsearch-start-es-after-block", boost::program_options::value(), + "Start doing ES job after block(0)") + ("elasticsearch-operation-string", boost::program_options::value(), + "Save operation as string. Needed to serve history api calls(true)") + ("elasticsearch-mode", boost::program_options::value(), + "Mode of operation: only_save(0), only_query(1), all(2) - Default: 0") + ; + cfg.add(cli); +} + +void elasticsearch_plugin::plugin_initialize(const boost::program_options::variables_map& options) +{ + my->_oho_index = database().add_index< primary_index< operation_history_index > >(); + database().add_index< primary_index< account_transaction_history_index > >(); + + if (options.count("elasticsearch-node-url")) { + my->_elasticsearch_node_url = options["elasticsearch-node-url"].as(); + } + if (options.count("elasticsearch-bulk-replay")) { + my->_elasticsearch_bulk_replay = options["elasticsearch-bulk-replay"].as(); + } + if (options.count("elasticsearch-bulk-sync")) { + my->_elasticsearch_bulk_sync = options["elasticsearch-bulk-sync"].as(); + } + if (options.count("elasticsearch-visitor")) { + my->_elasticsearch_visitor = options["elasticsearch-visitor"].as(); + } + if (options.count("elasticsearch-basic-auth")) { + my->_elasticsearch_basic_auth = options["elasticsearch-basic-auth"].as(); + } + if (options.count("elasticsearch-index-prefix")) { + my->_elasticsearch_index_prefix = options["elasticsearch-index-prefix"].as(); + } + if (options.count("elasticsearch-operation-object")) { + my->_elasticsearch_operation_object = options["elasticsearch-operation-object"].as(); + } + if (options.count("elasticsearch-start-es-after-block")) { + my->_elasticsearch_start_es_after_block = options["elasticsearch-start-es-after-block"].as(); + } + if (options.count("elasticsearch-operation-string")) { + my->_elasticsearch_operation_string = options["elasticsearch-operation-string"].as(); + } + if (options.count("elasticsearch-mode")) { + const auto option_number = options["elasticsearch-mode"].as(); + if(option_number > mode::all) + FC_THROW_EXCEPTION(fc::exception, "Elasticsearch mode not valid"); + my->_elasticsearch_mode = static_cast(options["elasticsearch-mode"].as()); + } + + if(my->_elasticsearch_mode != mode::only_query) { + if (my->_elasticsearch_mode == mode::all && !my->_elasticsearch_operation_string) + FC_THROW_EXCEPTION(fc::exception, + "If elasticsearch-mode is set to all then elasticsearch-operation-string need to be true"); + + database().applied_block.connect([this](const signed_block &b) { + if (!my->update_account_histories(b)) + FC_THROW_EXCEPTION(fc::exception, + "Error populating ES database, we are going to keep trying."); + }); + } +} + +void elasticsearch_plugin::plugin_startup() +{ + graphene::utilities::ES es; + es.curl = my->curl; + es.elasticsearch_url = my->_elasticsearch_node_url; + es.auth = my->_elasticsearch_basic_auth; + + if(!graphene::utilities::checkES(es)) + FC_THROW_EXCEPTION(fc::exception, "ES database is not up in url ${url}", ("url", my->_elasticsearch_node_url)); + ilog("elasticsearch ACCOUNT HISTORY: plugin_startup() begin"); +} + +operation_history_object elasticsearch_plugin::get_operation_by_id(operation_history_id_type id) +{ + const string operation_id_string = std::string(object_id_type(id)); + + const string query = R"( + { + "query": { + "match": + { + "account_history.operation_id": )" + operation_id_string + R"(" + } + } + } + )"; + + auto es = prepareHistoryQuery(query); + const auto response = graphene::utilities::simpleQuery(es); + variant variant_response = fc::json::from_string(response); + const auto source = variant_response["hits"]["hits"][size_t(0)]["_source"]; + return fromEStoOperation(source); +} + +vector elasticsearch_plugin::get_account_history( + const account_id_type account_id, + operation_history_id_type stop = operation_history_id_type(), + unsigned limit = 100, + operation_history_id_type start = operation_history_id_type()) +{ + const string account_id_string = std::string(object_id_type(account_id)); + + const auto stop_number = stop.instance.value; + const auto start_number = start.instance.value; + + string range = ""; + if(stop_number == 0) + range = " AND operation_id_num: ["+fc::to_string(stop_number)+" TO "+fc::to_string(start_number)+"]"; + else if(stop_number > 0) + range = " AND operation_id_num: {"+fc::to_string(stop_number)+" TO "+fc::to_string(start_number)+"]"; + + const string query = R"( + { + "size": )" + fc::to_string(limit) + R"(, + "sort" : [{ "operation_id_num" : {"order" : "desc"}}], + "query": { + "bool": { + "must": [ + { + "query_string": { + "query": "account_history.account: )" + account_id_string + range + R"(" + } + } + ] + } + } + } + )"; + + auto es = prepareHistoryQuery(query); + + vector result; + + if(!graphene::utilities::checkES(es)) + return result; + + const auto response = graphene::utilities::simpleQuery(es); + variant variant_response = fc::json::from_string(response); + + const auto hits = variant_response["hits"]["total"]["value"]; + const auto size = std::min(static_cast(hits.as_uint64()), limit); + + for(unsigned i=0; i_elasticsearch_node_url; + es.index_prefix = my->_elasticsearch_index_prefix; + es.endpoint = es.index_prefix + "*/data/_search"; + es.query = query; + + return es; +} + +mode elasticsearch_plugin::get_running_mode() +{ + return my->_elasticsearch_mode; +} + + +} } diff --git a/libraries/plugins/elasticsearch/include/graphene/elasticsearch/elasticsearch_plugin.hpp b/libraries/plugins/elasticsearch/include/graphene/elasticsearch/elasticsearch_plugin.hpp new file mode 100644 index 00000000..01a83244 --- /dev/null +++ b/libraries/plugins/elasticsearch/include/graphene/elasticsearch/elasticsearch_plugin.hpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2017 Cryptonomex, Inc., 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. + */ +#pragma once + +#include +#include +#include +#include + +namespace graphene { namespace elasticsearch { + using namespace chain; + +// +// Plugins should #define their SPACE_ID's so plugins with +// conflicting SPACE_ID assignments can be compiled into the +// same binary (by simply re-assigning some of the conflicting #defined +// SPACE_ID's in a build script). +// +// Assignment of SPACE_ID's cannot be done at run-time because +// various template automagic depends on them being known at compile +// time. +// +#ifndef ELASTICSEARCH_SPACE_ID +#define ELASTICSEARCH_SPACE_ID 6 +#endif + +namespace detail +{ + class elasticsearch_plugin_impl; +} + +enum mode { only_save = 0 , only_query = 1, all = 2 }; + +class elasticsearch_plugin : public graphene::app::plugin +{ + public: + elasticsearch_plugin(); + virtual ~elasticsearch_plugin(); + + std::string plugin_name()const override; + std::string plugin_description()const override; + virtual void plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) override; + virtual void plugin_initialize(const boost::program_options::variables_map& options) override; + virtual void plugin_startup() override; + + operation_history_object get_operation_by_id(operation_history_id_type id); + vector get_account_history(const account_id_type account_id, + operation_history_id_type stop, unsigned limit, operation_history_id_type start); + mode get_running_mode(); + + friend class detail::elasticsearch_plugin_impl; + std::unique_ptr my; + + private: + operation_history_object fromEStoOperation(variant source); + graphene::utilities::ES prepareHistoryQuery(string query); +}; + + +struct operation_visitor +{ + typedef void result_type; + + share_type fee_amount; + asset_id_type fee_asset; + + asset_id_type transfer_asset_id; + share_type transfer_amount; + account_id_type transfer_from; + account_id_type transfer_to; + + void operator()( const graphene::chain::transfer_operation& o ) + { + fee_asset = o.fee.asset_id; + fee_amount = o.fee.amount; + + transfer_asset_id = o.amount.asset_id; + transfer_amount = o.amount.amount; + transfer_from = o.from; + transfer_to = o.to; + } + + object_id_type fill_order_id; + account_id_type fill_account_id; + asset_id_type fill_pays_asset_id; + share_type fill_pays_amount; + asset_id_type fill_receives_asset_id; + share_type fill_receives_amount; + //double fill_fill_price; + //bool fill_is_maker; + + void operator()( const graphene::chain::fill_order_operation& o ) + { + fee_asset = o.fee.asset_id; + fee_amount = o.fee.amount; + + fill_order_id = o.order_id; + fill_account_id = o.account_id; + fill_pays_asset_id = o.pays.asset_id; + fill_pays_amount = o.pays.amount; + fill_receives_asset_id = o.receives.asset_id; + fill_receives_amount = o.receives.amount; + //fill_fill_price = o.fill_price.to_real(); + //fill_is_maker = o.is_maker; + } + + template + void operator()( const T& o ) + { + fee_asset = o.fee.asset_id; + fee_amount = o.fee.amount; + } +}; + +struct operation_history_struct { + int trx_in_block; + int op_in_trx; + std::string operation_result; + int virtual_op; + std::string op; + variant op_object; +}; + +struct block_struct { + int block_num; + fc::time_point_sec block_time; + std::string trx_id; +}; + +struct fee_struct { + asset_id_type asset; + share_type amount; +}; + +struct transfer_struct { + asset_id_type asset; + share_type amount; + account_id_type from; + account_id_type to; +}; + +struct fill_struct { + object_id_type order_id; + account_id_type account_id; + asset_id_type pays_asset_id; + share_type pays_amount; + asset_id_type receives_asset_id; + share_type receives_amount; + double fill_price; + bool is_maker; +}; + +struct visitor_struct { + fee_struct fee_data; + transfer_struct transfer_data; + fill_struct fill_data; +}; + +struct bulk_struct { + account_transaction_history_object account_history; + operation_history_struct operation_history; + int operation_type; + int operation_id_num; + block_struct block_data; + optional additional_data; +}; + +struct adaptor_struct { + variant adapt(const variant_object& op) + { + fc::mutable_variant_object o(op); + vector keys_to_rename; + for (auto i = o.begin(); i != o.end(); ++i) + { + auto& element = (*i).value(); + if (element.is_object()) + { + const string& name = (*i).key(); + auto& vo = element.get_object(); + if (vo.contains(name.c_str())) + keys_to_rename.emplace_back(name); + element = adapt(vo); + } + else if (element.is_array()) + adapt(element.get_array()); + } + for (const auto& i : keys_to_rename) + { + string new_name = i + "_"; + o[new_name] = variant(o[i]); + o.erase(i); + } + + if (o.find("memo") != o.end()) + { + auto& memo = o["memo"]; + if (memo.is_string()) + { + o["memo_"] = o["memo"]; + o.erase("memo"); + } + else if (memo.is_object()) + { + fc::mutable_variant_object tmp(memo.get_object()); + if (tmp.find("nonce") != tmp.end()) + { + tmp["nonce"] = tmp["nonce"].as_string(); + o["memo"] = tmp; + } + } + } + if (o.find("new_parameters") != o.end()) + { + auto& tmp = o["new_parameters"]; + if (tmp.is_object()) + { + fc::mutable_variant_object tmp2(tmp.get_object()); + if (tmp2.find("current_fees") != tmp2.end()) + { + tmp2.erase("current_fees"); + o["new_parameters"] = tmp2; + } + } + } + if (o.find("owner") != o.end() && o["owner"].is_string()) + { + o["owner_"] = o["owner"].as_string(); + o.erase("owner"); + } + if (o.find("proposed_ops") != o.end()) + { + o["proposed_ops"] = fc::json::to_string(o["proposed_ops"]); + } + if (o.find("initializer") != o.end()) + { + o["initializer"] = fc::json::to_string(o["initializer"]); + } + + variant v; + fc::to_variant(o, v, FC_PACK_MAX_DEPTH); + return v; + } + + void adapt(fc::variants& v) + { + for (auto& array_element : v) + { + if (array_element.is_object()) + array_element = adapt(array_element.get_object()); + else if (array_element.is_array()) + adapt(array_element.get_array()); + else + array_element = array_element.as_string(); + } + } +}; +} } //graphene::elasticsearch + +FC_REFLECT_ENUM( graphene::elasticsearch::mode, (only_save)(only_query)(all) ) +FC_REFLECT( graphene::elasticsearch::operation_history_struct, (trx_in_block)(op_in_trx)(operation_result)(virtual_op)(op)(op_object) ) +FC_REFLECT( graphene::elasticsearch::block_struct, (block_num)(block_time)(trx_id) ) +FC_REFLECT( graphene::elasticsearch::fee_struct, (asset)(amount) ) +FC_REFLECT( graphene::elasticsearch::transfer_struct, (asset)(amount)(from)(to) ) +FC_REFLECT( graphene::elasticsearch::fill_struct, (order_id)(account_id)(pays_asset_id)(pays_amount)(receives_asset_id)(receives_amount)(fill_price)(is_maker)) +FC_REFLECT( graphene::elasticsearch::visitor_struct, (fee_data)(transfer_data)(fill_data) ) +FC_REFLECT( graphene::elasticsearch::bulk_struct, (account_history)(operation_history)(operation_type)(operation_id_num)(block_data)(additional_data) ) diff --git a/libraries/plugins/es_objects/CMakeLists.txt b/libraries/plugins/es_objects/CMakeLists.txt new file mode 100644 index 00000000..92e3d150 --- /dev/null +++ b/libraries/plugins/es_objects/CMakeLists.txt @@ -0,0 +1,23 @@ +file(GLOB HEADERS "include/graphene/es_objects/*.hpp") + +add_library( graphene_es_objects + es_objects.cpp + ) + +target_link_libraries( graphene_es_objects graphene_chain graphene_app curl ) +target_include_directories( graphene_es_objects + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" ) + +if(MSVC) + set_source_files_properties(es_objects.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) +endif(MSVC) + +install( TARGETS + graphene_es_objects + + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib +) +INSTALL( FILES ${HEADERS} DESTINATION "include/graphene/es_objects" ) + diff --git a/libraries/plugins/es_objects/es_objects.cpp b/libraries/plugins/es_objects/es_objects.cpp new file mode 100644 index 00000000..b9083cbc --- /dev/null +++ b/libraries/plugins/es_objects/es_objects.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2018 oxarbitrage, 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 + +#include +#include +#include +#include +#include +#include + +#include + +namespace graphene { namespace es_objects { + +namespace detail +{ + +class es_objects_plugin_impl +{ + public: + es_objects_plugin_impl(es_objects_plugin& _plugin) + : _self( _plugin ) + { curl = curl_easy_init(); } + virtual ~es_objects_plugin_impl(); + + bool index_database(const vector& ids, std::string action); + bool genesis(); + void remove_from_database(object_id_type id, std::string index); + + es_objects_plugin& _self; + std::string _es_objects_elasticsearch_url = "http://localhost:9200/"; + std::string _es_objects_auth = ""; + uint32_t _es_objects_bulk_replay = 10000; + uint32_t _es_objects_bulk_sync = 100; + bool _es_objects_proposals = true; + bool _es_objects_accounts = true; + bool _es_objects_assets = true; + bool _es_objects_balances = true; + bool _es_objects_limit_orders = true; + bool _es_objects_asset_bitasset = true; + std::string _es_objects_index_prefix = "ppobjects-"; + uint32_t _es_objects_start_es_after_block = 0; + CURL *curl; // curl handler + vector bulk; + vector prepare; + + bool _es_objects_keep_only_current = true; + + uint32_t block_number; + fc::time_point_sec block_time; + + private: + template + void prepareTemplate(T blockchain_object, string index_name); +}; + +bool es_objects_plugin_impl::genesis() +{ + + ilog("elasticsearch OBJECTS: inserting data from genesis"); + + graphene::chain::database &db = _self.database(); + + block_number = db.head_block_num(); + block_time = db.head_block_time(); + + if (_es_objects_accounts) { + auto &index_accounts = db.get_index(1, 2); + index_accounts.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto a = static_cast(obj); + prepareTemplate(*a, "account"); + }); + } + if (_es_objects_assets) { + auto &index_assets = db.get_index(1, 3); + index_assets.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto a = static_cast(obj); + prepareTemplate(*a, "asset"); + }); + } + if (_es_objects_balances) { + auto &index_balances = db.get_index(2, 5); + index_balances.inspect_all_objects([this, &db](const graphene::db::object &o) { + auto obj = db.find_object(o.id); + auto b = static_cast(obj); + prepareTemplate(*b, "balance"); + }); + } + + graphene::utilities::ES es; + es.curl = curl; + es.bulk_lines = bulk; + es.elasticsearch_url = _es_objects_elasticsearch_url; + es.auth = _es_objects_auth; + if (!graphene::utilities::SendBulk(es)) + FC_THROW_EXCEPTION(fc::exception, "Error inserting genesis data."); + else + bulk.clear(); + + return true; +} + +bool es_objects_plugin_impl::index_database(const vector& ids, std::string action) +{ + graphene::chain::database &db = _self.database(); + + block_time = db.head_block_time(); + block_number = db.head_block_num(); + + if(block_number > _es_objects_start_es_after_block) { + + // check if we are in replay or in sync and change number of bulk documents accordingly + uint32_t limit_documents = 0; + if ((fc::time_point::now() - block_time) < fc::seconds(30)) + limit_documents = _es_objects_bulk_sync; + else + limit_documents = _es_objects_bulk_replay; + + + for (auto const &value: ids) { + if (value.is() && _es_objects_proposals) { + auto obj = db.find_object(value); + auto p = static_cast(obj); + if (p != nullptr) { + if (action == "delete") + remove_from_database(p->id, "proposal"); + else + prepareTemplate(*p, "proposal"); + } + } else if (value.is() && _es_objects_accounts) { + auto obj = db.find_object(value); + auto a = static_cast(obj); + if (a != nullptr) { + if (action == "delete") + remove_from_database(a->id, "account"); + else + prepareTemplate(*a, "account"); + } + } else if (value.is() && _es_objects_assets) { + auto obj = db.find_object(value); + auto a = static_cast(obj); + if (a != nullptr) { + if (action == "delete") + remove_from_database(a->id, "asset"); + else + prepareTemplate(*a, "asset"); + } + } else if (value.is() && _es_objects_balances) { + auto obj = db.find_object(value); + auto b = static_cast(obj); + if (b != nullptr) { + if (action == "delete") + remove_from_database(b->id, "balance"); + else + prepareTemplate(*b, "balance"); + } + } else if (value.is() && _es_objects_limit_orders) { + auto obj = db.find_object(value); + auto l = static_cast(obj); + if (l != nullptr) { + if (action == "delete") + remove_from_database(l->id, "limitorder"); + else + prepareTemplate(*l, "limitorder"); + } + } else if (value.is() && _es_objects_asset_bitasset) { + auto obj = db.find_object(value); + auto ba = static_cast(obj); + if (ba != nullptr) { + if (action == "delete") + remove_from_database(ba->id, "bitasset"); + else + prepareTemplate(*ba, "bitasset"); + } + } + } + + if (curl && bulk.size() >= limit_documents) { // we are in bulk time, ready to add data to elasticsearech + + graphene::utilities::ES es; + es.curl = curl; + es.bulk_lines = bulk; + es.elasticsearch_url = _es_objects_elasticsearch_url; + es.auth = _es_objects_auth; + + if (!graphene::utilities::SendBulk(es)) + return false; + else + bulk.clear(); + } + } + + return true; +} + +void es_objects_plugin_impl::remove_from_database( object_id_type id, std::string index) +{ + if(_es_objects_keep_only_current) + { + fc::mutable_variant_object delete_line; + delete_line["_id"] = string(id); + delete_line["_index"] = _es_objects_index_prefix + index; + delete_line["_type"] = "data"; + fc::mutable_variant_object final_delete_line; + final_delete_line["delete"] = delete_line; + prepare.push_back(fc::json::to_string(final_delete_line)); + std::move(prepare.begin(), prepare.end(), std::back_inserter(bulk)); + prepare.clear(); + } +} + +template +void es_objects_plugin_impl::prepareTemplate(T blockchain_object, string index_name) +{ + fc::mutable_variant_object bulk_header; + bulk_header["_index"] = _es_objects_index_prefix + index_name; + bulk_header["_type"] = "data"; + if(_es_objects_keep_only_current) + { + bulk_header["_id"] = string(blockchain_object.id); + } + + adaptor_struct adaptor; + fc::variant blockchain_object_variant; + fc::to_variant( blockchain_object, blockchain_object_variant, GRAPHENE_NET_MAX_NESTED_OBJECTS ); + fc::mutable_variant_object o = adaptor.adapt(blockchain_object_variant.get_object()); + + o["object_id"] = string(blockchain_object.id); + o["block_time"] = block_time; + o["block_number"] = block_number; + + string data = fc::json::to_string(o); + + prepare = graphene::utilities::createBulk(bulk_header, std::move(data)); + std::move(prepare.begin(), prepare.end(), std::back_inserter(bulk)); + prepare.clear(); +} + +es_objects_plugin_impl::~es_objects_plugin_impl() +{ + if (curl) { + curl_easy_cleanup(curl); + curl = nullptr; + } + return; +} + +} // end namespace detail + +es_objects_plugin::es_objects_plugin() : + my( new detail::es_objects_plugin_impl(*this) ) +{ +} + +es_objects_plugin::~es_objects_plugin() +{ +} + +std::string es_objects_plugin::plugin_name()const +{ + return "es_objects"; +} +std::string es_objects_plugin::plugin_description()const +{ + return "Stores blockchain objects in ES database. Experimental."; +} + +void es_objects_plugin::plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg + ) +{ + cli.add_options() + ("es-objects-elasticsearch-url", boost::program_options::value(), "Elasticsearch node url(http://localhost:9200/)") + ("es-objects-auth", boost::program_options::value(), "Basic auth username:password('')") + ("es-objects-bulk-replay", boost::program_options::value(), "Number of bulk documents to index on replay(10000)") + ("es-objects-bulk-sync", boost::program_options::value(), "Number of bulk documents to index on a synchronized chain(100)") + ("es-objects-proposals", boost::program_options::value(), "Store proposal objects(true)") + ("es-objects-accounts", boost::program_options::value(), "Store account objects(true)") + ("es-objects-assets", boost::program_options::value(), "Store asset objects(true)") + ("es-objects-balances", boost::program_options::value(), "Store balances objects(true)") + ("es-objects-limit-orders", boost::program_options::value(), "Store limit order objects(true)") + ("es-objects-asset-bitasset", boost::program_options::value(), "Store feed data(true)") + ("es-objects-index-prefix", boost::program_options::value(), "Add a prefix to the index(ppobjects-)") + ("es-objects-keep-only-current", boost::program_options::value(), "Keep only current state of the objects(true)") + ("es-objects-start-es-after-block", boost::program_options::value(), "Start doing ES job after block(0)") + ; + cfg.add(cli); +} + +void es_objects_plugin::plugin_initialize(const boost::program_options::variables_map& options) +{ + database().applied_block.connect([this](const signed_block &b) { + if(b.block_num() == 1) { + if (!my->genesis()) + FC_THROW_EXCEPTION(fc::exception, "Error populating genesis data."); + } + }); + + database().new_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "create")) + { + FC_THROW_EXCEPTION(fc::exception, "Error creating object from ES database, we are going to keep trying."); + } + }); + database().changed_objects.connect([this]( const vector& ids, const flat_set& impacted_accounts ) { + if(!my->index_database(ids, "update")) + { + FC_THROW_EXCEPTION(fc::exception, "Error updating object from ES database, we are going to keep trying."); + } + }); + database().removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { + if(!my->index_database(ids, "delete")) + { + FC_THROW_EXCEPTION(fc::exception, "Error deleting object from ES database, we are going to keep trying."); + } + }); + + + if (options.count("es-objects-elasticsearch-url")) { + my->_es_objects_elasticsearch_url = options["es-objects-elasticsearch-url"].as(); + } + if (options.count("es-objects-auth")) { + my->_es_objects_auth = options["es-objects-auth"].as(); + } + if (options.count("es-objects-bulk-replay")) { + my->_es_objects_bulk_replay = options["es-objects-bulk-replay"].as(); + } + if (options.count("es-objects-bulk-sync")) { + my->_es_objects_bulk_sync = options["es-objects-bulk-sync"].as(); + } + if (options.count("es-objects-proposals")) { + my->_es_objects_proposals = options["es-objects-proposals"].as(); + } + if (options.count("es-objects-accounts")) { + my->_es_objects_accounts = options["es-objects-accounts"].as(); + } + if (options.count("es-objects-assets")) { + my->_es_objects_assets = options["es-objects-assets"].as(); + } + if (options.count("es-objects-balances")) { + my->_es_objects_balances = options["es-objects-balances"].as(); + } + if (options.count("es-objects-limit-orders")) { + my->_es_objects_limit_orders = options["es-objects-limit-orders"].as(); + } + if (options.count("es-objects-asset-bitasset")) { + my->_es_objects_asset_bitasset = options["es-objects-asset-bitasset"].as(); + } + if (options.count("es-objects-index-prefix")) { + my->_es_objects_index_prefix = options["es-objects-index-prefix"].as(); + } + if (options.count("es-objects-keep-only-current")) { + my->_es_objects_keep_only_current = options["es-objects-keep-only-current"].as(); + } + if (options.count("es-objects-start-es-after-block")) { + my->_es_objects_start_es_after_block = options["es-objects-start-es-after-block"].as(); + } +} + +void es_objects_plugin::plugin_startup() +{ + graphene::utilities::ES es; + es.curl = my->curl; + es.elasticsearch_url = my->_es_objects_elasticsearch_url; + es.auth = my->_es_objects_auth; + es.auth = my->_es_objects_index_prefix; + + if(!graphene::utilities::checkES(es)) + FC_THROW_EXCEPTION(fc::exception, "ES database is not up in url ${url}", ("url", my->_es_objects_elasticsearch_url)); + ilog("elasticsearch OBJECTS: plugin_startup() begin"); +} + +} } diff --git a/libraries/plugins/es_objects/include/graphene/es_objects/es_objects.hpp b/libraries/plugins/es_objects/include/graphene/es_objects/es_objects.hpp new file mode 100644 index 00000000..fa91e3bd --- /dev/null +++ b/libraries/plugins/es_objects/include/graphene/es_objects/es_objects.hpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018 oxarbitrage, 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. + */ +#pragma once + +#include +#include + +namespace graphene { namespace es_objects { + +using namespace chain; + +namespace detail +{ + class es_objects_plugin_impl; +} + +class es_objects_plugin : public graphene::app::plugin +{ + public: + es_objects_plugin(); + virtual ~es_objects_plugin(); + + std::string plugin_name()const override; + std::string plugin_description()const override; + virtual void plugin_set_program_options( + boost::program_options::options_description& cli, + boost::program_options::options_description& cfg) override; + virtual void plugin_initialize(const boost::program_options::variables_map& options) override; + virtual void plugin_startup() override; + + friend class detail::es_objects_plugin_impl; + std::unique_ptr my; +}; + +struct adaptor_struct { + fc::mutable_variant_object adapt(const variant_object &obj) { + fc::mutable_variant_object o(obj); + vector keys_to_rename; + for (auto i = o.begin(); i != o.end(); ++i) { + auto &element = (*i).value(); + if (element.is_object()) { + const string &name = (*i).key(); + auto &vo = element.get_object(); + if (vo.contains(name.c_str())) + keys_to_rename.emplace_back(name); + element = adapt(vo); + } else if (element.is_array()) + adapt(element.get_array()); + } + for (const auto &i : keys_to_rename) { + string new_name = i + "_"; + o[new_name] = variant(o[i]); + o.erase(i); + } + if (o.find("owner") != o.end() && o["owner"].is_string()) + { + o["owner_"] = o["owner"].as_string(); + o.erase("owner"); + } + if (o.find("active_special_authority") != o.end()) + { + o["active_special_authority"] = fc::json::to_string(o["active_special_authority"]); + } + if (o.find("owner_special_authority") != o.end()) + { + o["owner_special_authority"] = fc::json::to_string(o["owner_special_authority"]); + } + if (o.find("feeds") != o.end()) + { + o["feeds"] = fc::json::to_string(o["feeds"]); + } + if (o.find("operations") != o.end()) + { + o["operations"] = fc::json::to_string(o["operations"]); + } + + return o; + } + + void adapt(fc::variants &v) { + for (auto &array_element : v) { + if (array_element.is_object()) + array_element = adapt(array_element.get_object()); + else if (array_element.is_array()) + adapt(array_element.get_array()); + else + array_element = array_element.as_string(); + } + } +}; + +} } //graphene::es_objects diff --git a/libraries/plugins/snapshot/include/graphene/snapshot/snapshot.hpp b/libraries/plugins/snapshot/include/graphene/snapshot/snapshot.hpp index b3ee30c6..eb8d3a16 100644 --- a/libraries/plugins/snapshot/include/graphene/snapshot/snapshot.hpp +++ b/libraries/plugins/snapshot/include/graphene/snapshot/snapshot.hpp @@ -35,6 +35,7 @@ class snapshot_plugin : public graphene::app::plugin { ~snapshot_plugin() {} std::string plugin_name()const override; + std::string plugin_description()const override; virtual void plugin_set_program_options( boost::program_options::options_description &command_line_options, diff --git a/libraries/plugins/snapshot/snapshot.cpp b/libraries/plugins/snapshot/snapshot.cpp index fe856ecb..f74ad589 100644 --- a/libraries/plugins/snapshot/snapshot.cpp +++ b/libraries/plugins/snapshot/snapshot.cpp @@ -54,6 +54,11 @@ std::string snapshot_plugin::plugin_name()const return "snapshot"; } +std::string snapshot_plugin::plugin_description()const +{ + return "Create snapshots at a specified time or block number."; +} + void snapshot_plugin::plugin_initialize(const boost::program_options::variables_map& options) { try { ilog("snapshot plugin: plugin_initialize() begin"); diff --git a/libraries/utilities/CMakeLists.txt b/libraries/utilities/CMakeLists.txt index f2d646d5..98086b10 100644 --- a/libraries/utilities/CMakeLists.txt +++ b/libraries/utilities/CMakeLists.txt @@ -14,6 +14,7 @@ set(sources string_escape.cpp tempdir.cpp words.cpp + elasticsearch.cpp ${HEADERS}) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/git_revision.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/git_revision.cpp" @ONLY) diff --git a/libraries/utilities/elasticsearch.cpp b/libraries/utilities/elasticsearch.cpp new file mode 100644 index 00000000..11a9561b --- /dev/null +++ b/libraries/utilities/elasticsearch.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2018 oxarbitrage, 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 +#include +#include +#include + +size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + ((std::string*)userp)->append((char*)contents, size * nmemb); + return size * nmemb; +} + +namespace graphene { namespace utilities { + +bool checkES(ES& es) +{ + graphene::utilities::CurlRequest curl_request; + curl_request.handler = es.curl; + curl_request.url = es.elasticsearch_url + "_nodes"; + curl_request.auth = es.auth; + curl_request.type = "GET"; + + if(doCurl(curl_request).empty()) + return false; + return true; + +} +const std::string simpleQuery(ES& es) +{ + graphene::utilities::CurlRequest curl_request; + curl_request.handler = es.curl; + curl_request.url = es.elasticsearch_url + es.endpoint; + curl_request.auth = es.auth; + curl_request.type = "POST"; + curl_request.query = es.query; + + return doCurl(curl_request); +} + +bool SendBulk(ES& es) +{ + std::string bulking = joinBulkLines(es.bulk_lines); + + graphene::utilities::CurlRequest curl_request; + curl_request.handler = es.curl; + curl_request.url = es.elasticsearch_url + "_bulk"; + curl_request.auth = es.auth; + curl_request.type = "POST"; + curl_request.query = bulking; + + auto curlResponse = doCurl(curl_request); + + if(handleBulkResponse(getResponseCode(curl_request.handler), curlResponse)) + return true; + return false; +} + +const std::string joinBulkLines(const std::vector& bulk) +{ + auto bulking = boost::algorithm::join(bulk, "\n"); + bulking = bulking + "\n"; + + return bulking; +} +long getResponseCode(CURL *handler) +{ + long http_code = 0; + curl_easy_getinfo (handler, CURLINFO_RESPONSE_CODE, &http_code); + return http_code; +} + +bool handleBulkResponse(long http_code, const std::string& CurlReadBuffer) +{ + if(http_code == 200) { + // all good, but check errors in response + fc::variant j = fc::json::from_string(CurlReadBuffer); + bool errors = j["errors"].as_bool(); + if(errors == true) { + return false; + } + } + else { + if(http_code == 413) { + elog( "413 error: Can be low disk space" ); + } + else if(http_code == 401) { + elog( "401 error: Unauthorized" ); + } + else { + elog( std::to_string(http_code) + " error: Unknown error" ); + } + return false; + } + return true; +} + +const std::vector createBulk(const fc::mutable_variant_object& bulk_header, const std::string& data) +{ + std::vector bulk; + fc::mutable_variant_object final_bulk_header; + final_bulk_header["index"] = bulk_header; + bulk.push_back(fc::json::to_string(final_bulk_header)); + bulk.push_back(data); + + return bulk; +} + +bool deleteAll(ES& es) +{ + graphene::utilities::CurlRequest curl_request; + curl_request.handler = es.curl; + curl_request.url = es.elasticsearch_url + es.index_prefix + "*"; + curl_request.auth = es.auth; + curl_request.type = "DELETE"; + + auto curl_response = doCurl(curl_request); + if(curl_response.empty()) + return false; + else + return true; +} +const std::string getEndPoint(ES& es) +{ + graphene::utilities::CurlRequest curl_request; + curl_request.handler = es.curl; + curl_request.url = es.elasticsearch_url + es.endpoint; + curl_request.auth = es.auth; + curl_request.type = "GET"; + + return doCurl(curl_request); +} + +const std::string generateIndexName(const fc::time_point_sec& block_date, const std::string& _elasticsearch_index_prefix) +{ + auto block_date_string = block_date.to_iso_string(); + std::vector parts; + boost::split(parts, block_date_string, boost::is_any_of("-")); + std::string index_name = _elasticsearch_index_prefix + parts[0] + "-" + parts[1]; + return index_name; +} + +const std::string doCurl(CurlRequest& curl) +{ + std::string CurlReadBuffer; + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Content-Type: application/json"); + + curl_easy_setopt(curl.handler, CURLOPT_HTTPHEADER, headers); + curl_easy_setopt(curl.handler, CURLOPT_URL, curl.url.c_str()); + curl_easy_setopt(curl.handler, CURLOPT_CUSTOMREQUEST, curl.type.c_str()); + if(curl.type == "POST") + { + curl_easy_setopt(curl.handler, CURLOPT_POST, true); + curl_easy_setopt(curl.handler, CURLOPT_POSTFIELDS, curl.query.c_str()); + } + curl_easy_setopt(curl.handler, CURLOPT_WRITEFUNCTION, WriteCallback); + curl_easy_setopt(curl.handler, CURLOPT_WRITEDATA, (void *)&CurlReadBuffer); + curl_easy_setopt(curl.handler, CURLOPT_USERAGENT, "libcrp/0.1"); + if(!curl.auth.empty()) + curl_easy_setopt(curl.handler, CURLOPT_USERPWD, curl.auth.c_str()); + curl_easy_perform(curl.handler); + + return CurlReadBuffer; +} + +} } // end namespace graphene::utilities diff --git a/libraries/utilities/include/graphene/utilities/elasticsearch.hpp b/libraries/utilities/include/graphene/utilities/elasticsearch.hpp new file mode 100644 index 00000000..898464b1 --- /dev/null +++ b/libraries/utilities/include/graphene/utilities/elasticsearch.hpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2018 oxarbitrage, 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. + */ +#pragma once +#include +#include +#include + +#include +#include +#include + +size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp); + +namespace graphene { namespace utilities { + + class ES { + public: + CURL *curl; + std::vector bulk_lines; + std::string elasticsearch_url; + std::string index_prefix; + std::string auth; + std::string endpoint; + std::string query; + }; + class CurlRequest { + public: + CURL *handler; + std::string url; + std::string type; + std::string auth; + std::string query; + }; + + bool SendBulk(ES& es); + const std::vector createBulk(const fc::mutable_variant_object& bulk_header, const std::string& data); + bool checkES(ES& es); + const std::string simpleQuery(ES& es); + bool deleteAll(ES& es); + bool handleBulkResponse(long http_code, const std::string& CurlReadBuffer); + const std::string getEndPoint(ES& es); + const std::string generateIndexName(const fc::time_point_sec& block_date, const std::string& _elasticsearch_index_prefix); + const std::string doCurl(CurlRequest& curl); + const std::string joinBulkLines(const std::vector& bulk); + long getResponseCode(CURL *handler); + +} } // end namespace graphene::utilities diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index d6082564..7f4c7859 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -1927,6 +1927,8 @@ class wallet_api } } +extern template class fc::api; + FC_REFLECT( graphene::wallet::key_label, (label)(key) ) FC_REFLECT( graphene::wallet::blind_balance, (amount)(from)(to)(one_time_key)(blinding_factor)(commitment)(used) ) FC_REFLECT( graphene::wallet::blind_confirmation::output, (label)(pub_key)(decrypted_memo)(confirmation)(auth)(confirmation_receipt) ) @@ -2154,4 +2156,5 @@ FC_API( graphene::wallet::wallet_api, (get_matched_bets_for_bettor) (get_all_matched_bets_for_bettor) (buy_ticket) + (quit) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 27eac237..fe9f7c30 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -89,6 +90,8 @@ # include #endif +template class fc::api; + #define BRAIN_KEY_WORD_COUNT 16 namespace graphene { namespace wallet { @@ -1082,6 +1085,7 @@ public: return true; } + void save_wallet_file(string wallet_filename = "") { // @@ -1096,8 +1100,6 @@ public: if( wallet_filename == "" ) wallet_filename = _wallet_filename; - wlog( "saving wallet to file ${fn}", ("fn", wallet_filename) ); - string data = fc::json::to_pretty_string( _wallet ); try { @@ -1108,14 +1110,38 @@ public: // // http://en.wikipedia.org/wiki/Most_vexing_parse // - fc::ofstream outfile{ fc::path( wallet_filename ) }; + std::string tmp_wallet_filename = wallet_filename + ".tmp"; + fc::ofstream outfile{ fc::path( tmp_wallet_filename ) }; outfile.write( data.c_str(), data.length() ); outfile.flush(); outfile.close(); + + ilog( "saved successfully wallet to tmp file ${fn}", ("fn", tmp_wallet_filename) ); + + std::string wallet_file_content; + fc::read_file_contents(tmp_wallet_filename, wallet_file_content); + + if (wallet_file_content == data) { + dlog( "validated successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); + fc::rename( tmp_wallet_filename, wallet_filename ); + dlog( "renamed successfully tmp wallet file ${fn}", ("fn", tmp_wallet_filename) ); + } + else + { + FC_THROW("tmp wallet file cannot be validated ${fn}", ("fn", tmp_wallet_filename) ); + } + + ilog( "successfully saved wallet to file ${fn}", ("fn", wallet_filename) ); + disable_umask_protection(); } catch(...) { + string ws_password = _wallet.ws_password; + _wallet.ws_password = ""; + elog("wallet file content is: ${data}", ("data", fc::json::to_pretty_string( _wallet ) ) ); + _wallet.ws_password = ws_password; + disable_umask_protection(); throw; } @@ -2118,6 +2144,7 @@ public: asset_object asset_obj = get_asset( asset_symbol ); vector< vesting_balance_object > vbos; + vesting_balance_object vbo; fc::optional vbid = maybe_id(account_name); if( !vbid ) { @@ -2130,47 +2157,23 @@ public: if(!vbos.size()) vbos.emplace_back( get_object(*vbid) ); - signed_transaction tx; - asset withdraw_amount = asset_obj.amount_from_string(amount); - bool onetime_fee_paid = false; - - for(const vesting_balance_object& vbo: vbos ) - { - if((vbo.balance_type == vesting_balance_type::gpos) && vbo.balance.amount > 0) + for (const vesting_balance_object& vesting_balance_obj: vbos) { + if(vesting_balance_obj.balance_type == vesting_balance_type::gpos) { - fc::optional vest_id = vbo.id; - vesting_balance_withdraw_operation vesting_balance_withdraw_op; - - // Since there are multiple vesting objects, below logic with vesting_balance_evaluator.cpp changes will - // deduct fee from single object and set withdrawl fee to 0 for rest of objects based on requested amount. - if(onetime_fee_paid) - vesting_balance_withdraw_op.fee = asset( 0, asset_id_type() ); - else - vesting_balance_withdraw_op.fee = _remote_db->get_global_properties().parameters.current_fees->calculate_fee(vesting_balance_withdraw_op); - - vesting_balance_withdraw_op.vesting_balance = *vest_id; - vesting_balance_withdraw_op.owner = vbo.owner; - if(withdraw_amount.amount > vbo.balance.amount) - { - vesting_balance_withdraw_op.amount = vbo.balance.amount; - withdraw_amount.amount -= vbo.balance.amount; - } - else - { - vesting_balance_withdraw_op.amount = withdraw_amount.amount; - tx.operations.push_back( vesting_balance_withdraw_op ); - withdraw_amount.amount -= vbo.balance.amount; - break; - } - - tx.operations.push_back( vesting_balance_withdraw_op ); - onetime_fee_paid = true; + vbo = vesting_balance_obj; + break; } } - if( withdraw_amount.amount > 0) - FC_THROW("Account has NO or Insufficient balance to withdraw"); + vesting_balance_withdraw_operation vesting_balance_withdraw_op; + vesting_balance_withdraw_op.vesting_balance = vbo.id; + vesting_balance_withdraw_op.owner = vbo.owner; + vesting_balance_withdraw_op.amount = asset_obj.amount_from_string(amount); + + signed_transaction tx; + tx.operations.push_back( vesting_balance_withdraw_op ); + set_operation_fees( tx, _remote_db->get_global_properties().parameters.current_fees ); tx.validate(); return sign_transaction( tx, broadcast ); diff --git a/programs/build_helpers/cat-parts b/programs/build_helpers/cat-parts deleted file mode 100755 index 2bcd1c8a..00000000 Binary files a/programs/build_helpers/cat-parts and /dev/null differ diff --git a/programs/witness_node/CMakeLists.txt b/programs/witness_node/CMakeLists.txt index 3d03253b..0c4c1db4 100644 --- a/programs/witness_node/CMakeLists.txt +++ b/programs/witness_node/CMakeLists.txt @@ -11,7 +11,7 @@ endif() # We have to link against graphene_debug_witness because deficiency in our API infrastructure doesn't allow plugins to be fully abstracted #246 target_link_libraries( witness_node - PRIVATE graphene_app graphene_account_history graphene_affiliate_stats graphene_market_history graphene_witness graphene_chain graphene_debug_witness graphene_bookie graphene_egenesis_full fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) + PRIVATE graphene_app graphene_account_history graphene_affiliate_stats graphene_elasticsearch graphene_market_history graphene_witness graphene_chain graphene_debug_witness graphene_bookie graphene_egenesis_full graphene_es_objects fc ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} ) # also add dependencies to graphene_generate_genesis graphene_generate_uia_sharedrop_genesis if you want those plugins install( TARGETS diff --git a/programs/witness_node/genesis.json b/programs/witness_node/genesis.json index ab153e7b..e07cec92 100644 --- a/programs/witness_node/genesis.json +++ b/programs/witness_node/genesis.json @@ -1,5 +1,5 @@ { - "initial_timestamp": "2019-05-14T18:47:51", + "initial_timestamp": "2020-01-13T06:03:15", "max_core_supply": "1000000000000000", "initial_parameters": { "current_fees": { @@ -307,6 +307,27 @@ 75,{} ],[ 76,{} + ],[ + 77,{ + "lottery_asset": 2000000, + "price_per_kbyte": 10 + } + ],[ + 78,{ + "fee": 0 + } + ],[ + 79,{ + "fee": 0 + } + ],[ + 80,{ + "fee": 0 + } + ],[ + 81,{ + "fee": 2000000 + } ] ], "scale": 10000 @@ -352,7 +373,19 @@ "maximum_tournament_start_time_in_future": 2419200, "maximum_tournament_start_delay": 604800, "maximum_tournament_number_of_wins": 100, - "extensions": {} + "extensions": { + "min_bet_multiplier": 10100, + "max_bet_multiplier": 10000000, + "betting_rake_fee_percentage": 300, + "live_betting_delay_time": 5, + "sweeps_distribution_percentage": 200, + "sweeps_distribution_asset": "1.3.0", + "sweeps_vesting_accumulator_account": "1.2.0", + "gpos_period": 15552000, + "gpos_subperiod": 2592000, + "gpos_period_start": 1601528400, + "gpos_vesting_lockin_period": 2592000 + } }, "initial_bts_accounts": [], "initial_accounts": [{ diff --git a/programs/witness_node/main.cpp b/programs/witness_node/main.cpp index 8c613067..0d6e65c6 100644 --- a/programs/witness_node/main.cpp +++ b/programs/witness_node/main.cpp @@ -25,8 +25,11 @@ #include #include +#include #include #include +#include +#include #include //#include //#include @@ -71,7 +74,10 @@ int main(int argc, char** argv) { bpo::variables_map options; auto witness_plug = node->register_plugin(); + auto debug_witness_plug = node->register_plugin(); auto history_plug = node->register_plugin(); + auto elasticsearch_plug = node->register_plugin(); + auto es_objects_plug = node->register_plugin(); auto market_history_plug = node->register_plugin(); //auto generate_genesis_plug = node->register_plugin(); //auto generate_uia_sharedrop_genesis_plug = node->register_plugin(); @@ -142,7 +148,7 @@ int main(int argc, char** argv) { exit_promise->set_value(signal); }, SIGTERM); - ilog("Started witness node on a chain with ${h} blocks.", ("h", node->chain_database()->head_block_num())); + ilog("Started BitShares node on a chain with ${h} blocks.", ("h", node->chain_database()->head_block_num())); ilog("Chain ID is ${id}", ("id", node->chain_database()->get_chain_id()) ); int signal = exit_promise->wait(); @@ -163,4 +169,4 @@ int main(int argc, char** argv) { delete node; return 1; } -} \ No newline at end of file +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 44af778b..e57e3374 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,38 +8,38 @@ endif() file(GLOB UNIT_TESTS "tests/*.cpp") add_executable( chain_test ${UNIT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( chain_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) if(MSVC) set_source_files_properties( tests/serialization_tests.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) file(GLOB PERFORMANCE_TESTS "performance/*.cpp") add_executable( performance_test ${PERFORMANCE_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( performance_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB BENCH_MARKS "benchmarks/*.cpp") add_executable( chain_bench ${BENCH_MARKS} ${COMMON_SOURCES} ) -target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( chain_bench graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB APP_SOURCES "app/*.cpp") add_executable( app_test ${APP_SOURCES} ) -target_link_libraries( app_test graphene_app graphene_account_history graphene_bookie graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( app_test graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_witness graphene_bookie graphene_net graphene_chain graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB INTENSE_SOURCES "intense/*.cpp") add_executable( intense_test ${INTENSE_SOURCES} ${COMMON_SOURCES} ) -target_link_libraries( intense_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( intense_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB BETTING_TESTS "betting/*.cpp") add_executable( betting_test ${BETTING_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( betting_test graphene_chain graphene_app graphene_account_history graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( betting_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_bookie graphene_egenesis_none fc graphene_wallet ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB TOURNAMENT_TESTS "tournament/*.cpp") add_executable( tournament_test ${TOURNAMENT_TESTS} ${COMMON_SOURCES} ) -target_link_libraries( tournament_test graphene_chain graphene_app graphene_account_history graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( tournament_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB RANDOM_SOURCES "random/*.cpp") add_executable( random_test ${RANDOM_SOURCES} ${COMMON_SOURCES} ) -target_link_libraries( random_test graphene_chain graphene_app graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) +target_link_libraries( random_test graphene_chain graphene_app graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) file(GLOB CLI_SOURCES "cli/*.cpp") add_executable( cli_test ${CLI_SOURCES} ) @@ -51,4 +51,8 @@ if(MSVC) set_source_files_properties( cli/main.cpp PROPERTIES COMPILE_FLAGS "/bigobj" ) endif(MSVC) +file(GLOB ES_SOURCES "elasticsearch/*.cpp") +add_executable( es_test ${ES_SOURCES} ${COMMON_SOURCES} ) +target_link_libraries( es_test graphene_chain graphene_app graphene_account_history graphene_elasticsearch graphene_es_objects graphene_egenesis_none fc ${PLATFORM_SPECIFIC_LIBS} ) + add_subdirectory( generate_empty_blocks ) diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index 0728ce2d..14b10fa3 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -29,11 +29,9 @@ #include #include #include +#include +#include -#include - -#include -#include #include #include #include @@ -51,9 +49,7 @@ #include #include -#include #include -#include #include "database_fixture.hpp" @@ -134,8 +130,51 @@ database_fixture::database_fixture() } // app.initialize(); - ahplugin->plugin_set_app(&app); - ahplugin->plugin_initialize(options); + + auto test_name = boost::unit_test::framework::current_test_case().p_name.value; + if(test_name == "elasticsearch_account_history" || test_name == "elasticsearch_suite" || + test_name == "elasticsearch_history_api") { + auto esplugin = app.register_plugin(); + esplugin->plugin_set_app(&app); + + options.insert(std::make_pair("elasticsearch-node-url", boost::program_options::variable_value(string("http://localhost:9200/"), false))); + options.insert(std::make_pair("elasticsearch-bulk-replay", boost::program_options::variable_value(uint32_t(2), false))); + options.insert(std::make_pair("elasticsearch-bulk-sync", boost::program_options::variable_value(uint32_t(2), false))); + options.insert(std::make_pair("elasticsearch-start-es-after-block", boost::program_options::variable_value(uint32_t(0), false))); + options.insert(std::make_pair("elasticsearch-visitor", boost::program_options::variable_value(false, false))); + options.insert(std::make_pair("elasticsearch-operation-object", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("elasticsearch-operation-string", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("elasticsearch-mode", boost::program_options::variable_value(uint16_t(2), false))); + + esplugin->plugin_initialize(options); + esplugin->plugin_startup(); + } + else { + auto ahplugin = app.register_plugin(); + app.enable_plugin("affiliate_stats"); + ahplugin->plugin_set_app(&app); + ahplugin->plugin_initialize(options); + ahplugin->plugin_startup(); + } + + if(test_name == "elasticsearch_objects" || test_name == "elasticsearch_suite") { + auto esobjects_plugin = app.register_plugin(); + esobjects_plugin->plugin_set_app(&app); + + options.insert(std::make_pair("es-objects-elasticsearch-url", boost::program_options::variable_value(string("http://localhost:9200/"), false))); + options.insert(std::make_pair("es-objects-bulk-replay", boost::program_options::variable_value(uint32_t(2), false))); + options.insert(std::make_pair("es-objects-bulk-sync", boost::program_options::variable_value(uint32_t(2), false))); + options.insert(std::make_pair("es-objects-proposals", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("es-objects-accounts", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("es-objects-assets", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("es-objects-balances", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("es-objects-limit-orders", boost::program_options::variable_value(true, false))); + options.insert(std::make_pair("es-objects-asset-bitasset", boost::program_options::variable_value(true, false))); + + esobjects_plugin->plugin_initialize(options); + esobjects_plugin->plugin_startup(); + } + mhplugin->plugin_set_app(&app); mhplugin->plugin_initialize(options); bookieplugin->plugin_set_app(&app); @@ -143,7 +182,6 @@ database_fixture::database_fixture() affiliateplugin->plugin_set_app(&app); affiliateplugin->plugin_initialize(options); - ahplugin->plugin_startup(); mhplugin->plugin_startup(); bookieplugin->plugin_startup(); affiliateplugin->plugin_startup(); diff --git a/tests/elasticsearch/main.cpp b/tests/elasticsearch/main.cpp new file mode 100644 index 00000000..28d3522c --- /dev/null +++ b/tests/elasticsearch/main.cpp @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2018 oxarbitrage 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 +#include + +#include +#include + +#include "../common/database_fixture.hpp" + +#define BOOST_TEST_MODULE Elastic Search Database Tests +#include + +using namespace graphene::chain; +using namespace graphene::chain::test; +using namespace graphene::app; + +BOOST_FIXTURE_TEST_SUITE( elasticsearch_tests, database_fixture ) + +BOOST_AUTO_TEST_CASE(elasticsearch_account_history) { + try { + + CURL *curl; // curl handler + curl = curl_easy_init(); + + graphene::utilities::ES es; + es.curl = curl; + es.elasticsearch_url = "http://localhost:9200/"; + es.index_prefix = "peerplays-"; + //es.auth = "elastic:changeme"; + + // delete all first + auto delete_account_history = graphene::utilities::deleteAll(es); + fc::usleep(fc::milliseconds(1000)); // this is because index.refresh_interval, nothing to worry + + if(delete_account_history) { // all records deleted + + //account_id_type() do 3 ops + create_bitasset("USD", account_id_type()); + auto dan = create_account("dan"); + auto bob = create_account("bob"); + + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + // for later use + //int asset_crobjeate_op_id = operation::tag::value; + //int account_create_op_id = operation::tag::value; + + string query = "{ \"query\" : { \"bool\" : { \"must\" : [{\"match_all\": {}}] } } }"; + es.endpoint = es.index_prefix + "*/data/_count"; + es.query = query; + + auto res = graphene::utilities::simpleQuery(es); + variant j = fc::json::from_string(res); + auto total = j["count"].as_string(); + BOOST_CHECK_EQUAL(total, "5"); + + es.endpoint = es.index_prefix + "*/data/_search"; + res = graphene::utilities::simpleQuery(es); + j = fc::json::from_string(res); + auto first_id = j["hits"]["hits"][size_t(0)]["_id"].as_string(); + BOOST_CHECK_EQUAL(first_id, "2.9.0"); + + generate_block(); + auto willie = create_account("willie"); + generate_block(); + + fc::usleep(fc::milliseconds(1000)); // index.refresh_interval + + es.endpoint = es.index_prefix + "*/data/_count"; + res = graphene::utilities::simpleQuery(es); + j = fc::json::from_string(res); + + total = j["count"].as_string(); + BOOST_CHECK_EQUAL(total, "7"); + + // do some transfers in 1 block + transfer(account_id_type()(db), bob, asset(100)); + transfer(account_id_type()(db), bob, asset(200)); + transfer(account_id_type()(db), bob, asset(300)); + + generate_block(); + fc::usleep(fc::milliseconds(1000)); // index.refresh_interval + + res = graphene::utilities::simpleQuery(es); + j = fc::json::from_string(res); + + total = j["count"].as_string(); + BOOST_CHECK_EQUAL(total, "13"); + + // check the visitor data + auto block_date = db.head_block_time(); + std::string index_name = graphene::utilities::generateIndexName(block_date, "peerplays-"); + + es.endpoint = index_name + "/data/2.9.12"; // we know last op is a transfer of amount 300 + res = graphene::utilities::getEndPoint(es); + j = fc::json::from_string(res); + auto last_transfer_amount = j["_source"]["operation_history"]["op_object"]["amount_"]["amount"].as_string(); + BOOST_CHECK_EQUAL(last_transfer_amount, "300"); + } + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(elasticsearch_objects) { + try { + + CURL *curl; // curl handler + curl = curl_easy_init(); + + graphene::utilities::ES es; + es.curl = curl; + es.elasticsearch_url = "http://localhost:9200/"; + es.index_prefix = "ppobjects-"; + //es.auth = "elastic:changeme"; + + // delete all first + auto delete_objects = graphene::utilities::deleteAll(es); + + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + if(delete_objects) { // all records deleted + + // asset and bitasset + create_bitasset("USD", account_id_type()); + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + string query = "{ \"query\" : { \"bool\" : { \"must\" : [{\"match_all\": {}}] } } }"; + es.endpoint = es.index_prefix + "*/data/_count"; + es.query = query; + + auto res = graphene::utilities::simpleQuery(es); + variant j = fc::json::from_string(res); + auto total = j["count"].as_string(); + BOOST_CHECK_EQUAL(total, "2"); + + es.endpoint = es.index_prefix + "asset/data/_search"; + res = graphene::utilities::simpleQuery(es); + j = fc::json::from_string(res); + auto first_id = j["hits"]["hits"][size_t(0)]["_source"]["symbol"].as_string(); + BOOST_CHECK_EQUAL(first_id, "USD"); + + auto bitasset_data_id = j["hits"]["hits"][size_t(0)]["_source"]["bitasset_data_id"].as_string(); + es.endpoint = es.index_prefix + "bitasset/data/_search"; + es.query = "{ \"query\" : { \"bool\": { \"must\" : [{ \"term\": { \"object_id\": \""+bitasset_data_id+"\"}}] } } }"; + res = graphene::utilities::simpleQuery(es); + j = fc::json::from_string(res); + auto bitasset_object_id = j["hits"]["hits"][size_t(0)]["_source"]["object_id"].as_string(); + BOOST_CHECK_EQUAL(bitasset_object_id, bitasset_data_id); + } + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(elasticsearch_suite) { + try { + + CURL *curl; // curl handler + curl = curl_easy_init(); + + graphene::utilities::ES es; + es.curl = curl; + es.elasticsearch_url = "http://localhost:9200/"; + es.index_prefix = "peerplays-"; + auto delete_account_history = graphene::utilities::deleteAll(es); + fc::usleep(fc::milliseconds(1000)); + es.index_prefix = "ppobjects-"; + auto delete_objects = graphene::utilities::deleteAll(es); + fc::usleep(fc::milliseconds(1000)); + + if(delete_account_history && delete_objects) { // all records deleted + + + } + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + +BOOST_AUTO_TEST_CASE(elasticsearch_history_api) { + try { + CURL *curl; // curl handler + curl = curl_easy_init(); + + graphene::utilities::ES es; + es.curl = curl; + es.elasticsearch_url = "http://localhost:9200/"; + es.index_prefix = "peerplays-"; + + auto delete_account_history = graphene::utilities::deleteAll(es); + + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + if(delete_account_history) { + + create_bitasset("USD", account_id_type()); // create op 0 + const account_object& dan = create_account("dan"); // create op 1 + create_bitasset("CNY", dan.id); // create op 2 + create_bitasset("BTC", account_id_type()); // create op 3 + create_bitasset("XMR", dan.id); // create op 4 + create_bitasset("EUR", account_id_type()); // create op 5 + create_bitasset("OIL", dan.id); // create op 6 + + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + graphene::app::history_api hist_api(app); + app.enable_plugin("elasticsearch"); + + // f(A, 0, 4, 9) = { 5, 3, 1, 0 } + auto histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(9)); + + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u); + + // f(A, 0, 4, 6) = { 5, 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(6)); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u); + + // f(A, 0, 4, 5) = { 5, 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(5)); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u); + + // f(A, 0, 4, 4) = { 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(4)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 0u); + + // f(A, 0, 4, 3) = { 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(3)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 0u); + + // f(A, 0, 4, 2) = { 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(2)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u); + + // f(A, 0, 4, 1) = { 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type(1)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u); + + // f(A, 0, 4, 0) = { 5, 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 4, operation_history_id_type()); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 0u); + + // f(A, 1, 5, 9) = { 5, 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(9)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + + // f(A, 1, 5, 6) = { 5, 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(6)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + + // f(A, 1, 5, 5) = { 5, 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(5)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + + // f(A, 1, 5, 4) = { 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(4)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + + // f(A, 1, 5, 3) = { 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(3)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + + // f(A, 1, 5, 2) = { } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(2)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(A, 1, 5, 1) = { } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(1)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(A, 1, 5, 0) = { 5, 3 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(1), 5, operation_history_id_type(0)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + + // f(A, 0, 3, 9) = { 5, 3, 1 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(9)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(A, 0, 3, 6) = { 5, 3, 1 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(6)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(A, 0, 3, 5) = { 5, 3, 1 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(5)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(A, 0, 3, 4) = { 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(4)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 0u); + + // f(A, 0, 3, 3) = { 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(3)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 0u); + + // f(A, 0, 3, 2) = { 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(2)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u); + + // f(A, 0, 3, 1) = { 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type(1)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 0u); + + // f(A, 0, 3, 0) = { 5, 3, 1 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(), 3, operation_history_id_type()); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(B, 0, 4, 9) = { 6, 4, 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(9)); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 1u); + + // f(B, 0, 4, 6) = { 6, 4, 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(6)); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 1u); + + // f(B, 0, 4, 5) = { 4, 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(5)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(B, 0, 4, 4) = { 4, 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(4)); + BOOST_CHECK_EQUAL(histories.size(), 3u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 1u); + + // f(B, 0, 4, 3) = { 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(3)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + + // f(B, 0, 4, 2) = { 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(2)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 1u); + + // f(B, 0, 4, 1) = { 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type(1)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 1u); + + // f(B, 0, 4, 0) = { 6, 4, 2, 1 } + histories = hist_api.get_account_history("dan", operation_history_id_type(), 4, operation_history_id_type()); + BOOST_CHECK_EQUAL(histories.size(), 4u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 2u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 1u); + + // f(B, 2, 4, 9) = { 6, 4 } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(9)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + + // f(B, 2, 4, 6) = { 6, 4 } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(6)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + + // f(B, 2, 4, 5) = { 4 } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(5)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u); + + // f(B, 2, 4, 4) = { 4 } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(4)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 4u); + + // f(B, 2, 4, 3) = { } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(3)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(B, 2, 4, 2) = { } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(2)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(B, 2, 4, 1) = { } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(1)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(B, 2, 4, 0) = { 6, 4 } + histories = hist_api.get_account_history("dan", operation_history_id_type(2), 4, operation_history_id_type(0)); + BOOST_CHECK_EQUAL(histories.size(), 2u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 6u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 4u); + + // 0 limits + histories = hist_api.get_account_history("dan", operation_history_id_type(0), 0, operation_history_id_type(0)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(3), 0, operation_history_id_type(9)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // non existent account + histories = hist_api.get_account_history("1.2.18", operation_history_id_type(0), 4, operation_history_id_type(0)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // create a new account C = alice { 7 } + auto alice = create_account("alice"); + + generate_block(); + fc::usleep(fc::milliseconds(1000)); + + // f(C, 0, 4, 10) = { 7 } + histories = hist_api.get_account_history("alice", operation_history_id_type(0), 4, operation_history_id_type(10)); + BOOST_CHECK_EQUAL(histories.size(), 1u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 7u); + + // f(C, 8, 4, 10) = { } + histories = hist_api.get_account_history("alice", operation_history_id_type(8), 4, operation_history_id_type(10)); + BOOST_CHECK_EQUAL(histories.size(), 0u); + + // f(A, 0, 10, 0) = { 7, 5, 3, 1, 0 } + histories = hist_api.get_account_history("1.2.0", operation_history_id_type(0), 10, operation_history_id_type(0)); + BOOST_CHECK_EQUAL(histories.size(), 5u); + BOOST_CHECK_EQUAL(histories[0].id.instance(), 7u); + BOOST_CHECK_EQUAL(histories[1].id.instance(), 5u); + BOOST_CHECK_EQUAL(histories[2].id.instance(), 3u); + BOOST_CHECK_EQUAL(histories[3].id.instance(), 1u); + BOOST_CHECK_EQUAL(histories[4].id.instance(), 0u); + } + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/tests/gpos_tests.cpp b/tests/tests/gpos_tests.cpp index 196fe7ee..aa9969ee 100644 --- a/tests/tests/gpos_tests.cpp +++ b/tests/tests/gpos_tests.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,23 @@ struct gpos_fixture: database_fixture return db.get(ptx.operation_results[0].get()); } + void withdraw_gpos_vesting(const vesting_balance_id_type v_bid, const account_id_type owner, const asset amount, + /*const vesting_balance_type type, */const fc::ecc::private_key& key) + { + vesting_balance_withdraw_operation op; + op.vesting_balance = v_bid; + op.owner = owner; + op.amount = amount; + //op.balance_type = type; + + trx.operations.push_back(op); + set_expiration(db, trx); + trx.validate(); + sign(trx, key); + PUSH_TX(db, trx); + trx.clear(); + } + void update_payout_interval(std::string asset_name, fc::time_point start, uint32_t interval) { auto dividend_holder_asset_object = get_asset(asset_name); @@ -90,10 +108,12 @@ struct gpos_fixture: database_fixture p.parameters.extensions.value.gpos_period = vesting_period; p.parameters.extensions.value.gpos_subperiod = vesting_subperiod; p.parameters.extensions.value.gpos_period_start = period_start.sec_since_epoch(); + p.parameters.extensions.value.gpos_vesting_lockin_period = vesting_subperiod; }); BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), vesting_period); BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), vesting_subperiod); BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), period_start.sec_since_epoch()); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_vesting_lockin_period(), vesting_subperiod); } void update_maintenance_interval(uint32_t new_interval) @@ -514,6 +534,94 @@ BOOST_AUTO_TEST_CASE( gpos_basic_dividend_distribution_to_core_asset ) } } +BOOST_AUTO_TEST_CASE( votes_on_gpos_activation ) +{ + ACTORS((alice)(bob)); + try { + const auto& core = asset_id_type()(db); + + // send some asset to alice and bob + transfer( committee_account, alice_id, core.amount( 1000 ) ); + transfer( committee_account, bob_id, core.amount( 1000 ) ); + generate_block(); + + // update default gpos + auto now = db.head_block_time(); + // 5184000 = 60x60x24x6 = 6 days + // 864000 = 60x60x24x1 = 1 days + update_gpos_global(518400, 86400, HARDFORK_GPOS_TIME); + + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period(), 518400); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_subperiod(), 86400); + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.gpos_period_start(), HARDFORK_GPOS_TIME.sec_since_epoch()); + // no votes for witness 1 + auto witness1 = witness_id_type(1)(db); + BOOST_CHECK_EQUAL(witness1.total_votes, 0); + + // no votes for witness 2 + auto witness2 = witness_id_type(2)(db); + BOOST_CHECK_EQUAL(witness2.total_votes, 0); + + // vote for witness1 and witness2 - this before GPOS period starts + vote_for(alice_id, witness1.vote_id, alice_private_key); + vote_for(bob_id, witness2.vote_id, bob_private_key); + + // go to maint + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + // vote is the same as amount in the first subperiod since voting + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + BOOST_CHECK_EQUAL(witness1.total_votes, 1000); + BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + + update_maintenance_interval(3600); //update maintenance interval to 1hr to evaluate sub-periods + BOOST_CHECK_EQUAL(db.get_global_properties().parameters.maintenance_interval, 3600); + + // move to hardfork + generate_blocks( HARDFORK_GPOS_TIME ); + generate_block(); + + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + BOOST_CHECK_EQUAL(witness1.total_votes, 1000); + BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + + // add some vesting to alice and don't add anything for Bob + create_vesting(alice_id, core.amount(99), vesting_balance_type::gpos); + generate_block(); + vote_for(alice_id, witness1.vote_id, alice_private_key); + generate_block(); + + advance_x_maint(1); + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + //System needs to consider votes based on both regular balance + GPOS balance for 1/2 sub-period on GPOS activation + BOOST_CHECK_EQUAL(witness1.total_votes, 1000); + BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + + advance_x_maint(6); + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + BOOST_CHECK_EQUAL(witness1.total_votes, 1000); + BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + + advance_x_maint(5); + generate_block(); + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + //Since Alice has votes, votes should be based on GPOS balance i.e 99 + //Since Bob not voted after GPOS activation, witness2 votes should be 0 after crossing 1/2 sub-period(12 maintanence intervals in this case) + BOOST_CHECK_EQUAL(witness1.total_votes, 99); + BOOST_CHECK_EQUAL(witness2.total_votes, 0); + + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + BOOST_AUTO_TEST_CASE( voting ) { ACTORS((alice)(bob)); @@ -570,13 +678,20 @@ BOOST_AUTO_TEST_CASE( voting ) // go to maint generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); - // vote is the same as amount in the first subperiod since voting + // need to consider both gpos and regular balance for first 1/2 sub period + witness1 = witness_id_type(1)(db); + witness2 = witness_id_type(2)(db); + BOOST_CHECK_EQUAL(witness1.total_votes, 1000); + BOOST_CHECK_EQUAL(witness2.total_votes, 1000); + + advance_x_maint(6); + witness1 = witness_id_type(1)(db); witness2 = witness_id_type(2)(db); BOOST_CHECK_EQUAL(witness1.total_votes, 100); BOOST_CHECK_EQUAL(witness2.total_votes, 100); - advance_x_maint(10); + advance_x_maint(4); //Bob votes for witness2 - sub-period 2 vote_for(bob_id, witness2.vote_id, bob_private_key); @@ -919,6 +1034,89 @@ BOOST_AUTO_TEST_CASE( account_multiple_vesting ) throw; } } + +BOOST_AUTO_TEST_CASE( Withdraw_gpos_vesting_balance ) +{ + try { + // advance to HF + generate_blocks(HARDFORK_GPOS_TIME); + generate_block(); + set_expiration(db, trx); + + // update default gpos global parameters to 4 days + auto now = db.head_block_time(); + update_gpos_global(345600, 86400, now); + + ACTORS((alice)(bob)); + + graphene::app::database_api db_api1(db); + const auto& core = asset_id_type()(db); + + + transfer( committee_account, alice_id, core.amount( 500 ) ); + transfer( committee_account, bob_id, core.amount( 99 ) ); + + // add some vesting to Alice, Bob + vesting_balance_object vbo1, vbo2; + vbo1 = create_vesting(alice_id, core.amount(150), vesting_balance_type::gpos); + vbo2 = create_vesting(bob_id, core.amount(99), vesting_balance_type::gpos); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + generate_block(); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_blocks(db.get_global_properties().parameters.gpos_vesting_lockin_period()); + BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 350); + withdraw_gpos_vesting(vbo1.id, alice_id, core.amount(50), /*vesting_balance_type::gpos, */alice_private_key); + withdraw_gpos_vesting(vbo2.id, bob_id, core.amount(99), /*vesting_balance_type::gpos, */bob_private_key); + generate_block(); + // verify charles balance + BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 400); + BOOST_CHECK_EQUAL(get_balance(bob_id(db), core), 99); + + // Add more 50 and 73 vesting objects and withdraw 90 from + // total vesting balance of user + vbo1 = create_vesting(alice_id, core.amount(50), vesting_balance_type::gpos); + vbo2 = create_vesting(alice_id, core.amount(73), vesting_balance_type::gpos); + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + + generate_block(); + + vector vbos = db_api1.get_vesting_balances("alice"); + asset total_vesting; + for (const vesting_balance_object& vbo : vbos) + { + if (vbo.balance_type == vesting_balance_type::gpos && vbo.balance.asset_id == asset_id_type()) + total_vesting += vbo.balance; + } + // total vesting balance of alice + BOOST_CHECK_EQUAL(total_vesting.amount.value, core.amount(223).amount.value); + + generate_blocks(db.get_dynamic_global_properties().next_maintenance_time); + generate_blocks(db.get_global_properties().parameters.gpos_vesting_lockin_period()); + BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 277); + withdraw_gpos_vesting(vbo1.id, alice_id, core.amount(90), /*vesting_balance_type::gpos,*/ alice_private_key); + generate_block(); + // verify alice balance + BOOST_CHECK_EQUAL(get_balance(alice_id(db), core), 367); + + // verify remaining vesting balance + vbos = db_api1.get_vesting_balances("alice"); + asset remaining_vesting; + for (const vesting_balance_object& vbo : vbos) + { + if (vbo.balance_type == vesting_balance_type::gpos && vbo.balance.asset_id == asset_id_type()) + remaining_vesting += vbo.balance; + } + // remaining vesting balance of alice + BOOST_CHECK_EQUAL(remaining_vesting.amount.value, core.amount(133).amount.value); + } + catch (fc::exception &e) { + edump((e.to_detail_string())); + throw; + } +} + /* BOOST_AUTO_TEST_CASE( competing_proposals ) { diff --git a/tests/tests/history_api_tests.cpp b/tests/tests/history_api_tests.cpp index 4edccce5..943b8265 100644 --- a/tests/tests/history_api_tests.cpp +++ b/tests/tests/history_api_tests.cpp @@ -595,4 +595,4 @@ BOOST_AUTO_TEST_CASE(get_account_history_operations) { } } -BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file +BOOST_AUTO_TEST_SUITE_END()