From 73abb804aecb24ee56e6025adcef044be899eab9 Mon Sep 17 00:00:00 2001 From: alfredo Date: Thu, 16 Feb 2017 19:33:16 -0300 Subject: [PATCH 01/10] make less false positives( no false positive given in tests with this setting) --- libraries/app/database_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index d460662b..3d464dfa 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -295,7 +295,7 @@ void database_api_impl::set_subscribe_callback( std::function Date: Wed, 8 Mar 2017 01:37:59 +0000 Subject: [PATCH 02/10] Include information of impacted accounts relative to the objects created/changed/removed. Only extract the impacted accounts information if there are handlers defined in order prevent useless cpu usage on nodes not exposing the rpc api --- libraries/chain/db_block.cpp | 393 +++++++++++++++++- .../chain/include/graphene/chain/database.hpp | 6 +- 2 files changed, 382 insertions(+), 17 deletions(-) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index f55f0396..948c7a34 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -26,18 +26,208 @@ #include #include +#include + +#include +#include +#include +#include +#include +#include +#include + #include #include #include +#include #include #include #include +#include #include #include #include #include +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_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 ); + } + +}; + namespace graphene { namespace chain { bool database::is_known_block( const block_id_type& id )const @@ -544,29 +734,204 @@ void database::_apply_block( const signed_block& next_block ) notify_changed_objects(); } FC_CAPTURE_AND_RETHROW( (next_block.block_num()) ) } + +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 ); +} + +void get_relevant_accounts( const object* obj, flat_set& accounts ) +{ + if( obj->id.space() == protocol_ids ) + { + switch( (object_type)obj->id.type() ) + { + case null_object_type: + case base_object_type: + case OBJECT_TYPE_COUNT: + return; + case account_object_type:{ + accounts.insert( obj->id ); + break; + } case asset_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->issuer ); + break; + } case force_settlement_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case committee_member_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->committee_member_account ); + break; + } case witness_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->witness_account ); + break; + } case limit_order_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->seller ); + break; + } case call_order_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->borrower ); + break; + } case custom_object_type:{ + break; + } case proposal_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + transaction_get_impacted_accounts( aobj->proposed_transaction, accounts ); + break; + } case operation_history_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + operation_get_impacted_accounts( aobj->op, accounts ); + break; + } case withdraw_permission_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->withdraw_from_account ); + accounts.insert( aobj->authorized_account ); + break; + } case vesting_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case worker_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->worker_account ); + break; + } case balance_object_type:{ + /** these are free from any accounts */ + break; + } + } + } + else if( obj->id.space() == implementation_ids ) + { + switch( (impl_object_type)obj->id.type() ) + { + case impl_global_property_object_type: + break; + case impl_dynamic_global_property_object_type: + break; + case impl_reserved0_object_type: + break; + case impl_asset_dynamic_data_type: + break; + case impl_asset_bitasset_data_type: + break; + case impl_account_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case impl_account_statistics_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case impl_transaction_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + transaction_get_impacted_accounts( aobj->trx, accounts ); + break; + } case impl_blinded_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + for( const auto& a : aobj->owner.account_auths ) + accounts.insert( a.first ); + break; + } case impl_block_summary_object_type: + break; + case impl_account_transaction_history_object_type: + break; + case impl_chain_property_object_type: + break; + case impl_witness_schedule_object_type: + break; + case impl_budget_record_object_type: + break; + case impl_special_authority_object_type: + break; + case impl_buyback_object_type: + break; + case impl_fba_accumulator_object_type: + break; + } + } +} // end get_relevant_accounts( const object* obj, flat_set& accounts ) + + void database::notify_changed_objects() { try { if( _undo_db.enabled() ) { const auto& head_undo = _undo_db.head(); - vector new_ids; new_ids.reserve(head_undo.new_ids.size()); - for( const auto& item : head_undo.new_ids ) new_ids.push_back(item); - - vector changed_ids; changed_ids.reserve(head_undo.old_values.size()); - for( const auto& item : head_undo.old_values ) changed_ids.push_back(item.first); - - vector removed_ids; removed_ids.reserve( head_undo.removed.size() ); - vector removed; removed.reserve( head_undo.removed.size() ); - for( const auto& item : head_undo.removed ) + // New + if( !new_objects.empty() ) { - removed_ids.emplace_back( item.first ); - removed.emplace_back( item.second.get() ); + vector new_ids; new_ids.reserve(head_undo.new_ids.size()); + flat_set new_accounts_impacted; + for( const auto& item : head_undo.new_ids ) + { + new_ids.push_back(item); + auto obj = find_object(item); + if(obj != nullptr) + get_relevant_accounts(obj, new_accounts_impacted); + } + + new_objects(new_ids, new_accounts_impacted); } - new_objects(new_ids); - changed_objects(changed_ids); - removed_objects(removed_ids, removed); + // Changed + if( !changed_objects.empty() ) + { + vector changed_ids; changed_ids.reserve(head_undo.old_values.size()); + flat_set changed_accounts_impacted; + for( const auto& item : head_undo.old_values ) + { + changed_ids.push_back(item.first); + get_relevant_accounts(item.second.get(), changed_accounts_impacted); + } + + changed_objects(changed_ids, changed_accounts_impacted); + } + + // Removed + if( !removed_objects.empty() ) + { + vector removed_ids; removed_ids.reserve( head_undo.removed.size() ); + vector removed; removed.reserve( head_undo.removed.size() ); + flat_set removed_accounts_impacted; + for( const auto& item : head_undo.removed ) + { + removed_ids.emplace_back( item.first ); + auto obj = item.second.get(); + removed.emplace_back( obj ); + get_relevant_accounts(obj, removed_accounts_impacted); + } + + removed_objects(removed_ids, removed, removed_accounts_impacted); + } } } FC_CAPTURE_AND_LOG( () ) } diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 9e0f1af1..4184fb1d 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -193,18 +193,18 @@ namespace graphene { namespace chain { * Emitted After a block has been applied and committed. The callback * should not yield and should execute quickly. */ - fc::signal&)> new_objects; + fc::signal&, const flat_set&)> new_objects; /** * Emitted After a block has been applied and committed. The callback * should not yield and should execute quickly. */ - fc::signal&)> changed_objects; + fc::signal&, const flat_set&)> changed_objects; /** this signal is emitted any time an object is removed and contains a * pointer to the last value of every object that was removed. */ - fc::signal&, const vector&)> removed_objects; + fc::signal&, const vector&, const flat_set&)> removed_objects; //////////////////// db_witness_schedule.cpp //////////////////// From aab5fddb2f6521fbc0720eea45392d7c7361e42d Mon Sep 17 00:00:00 2001 From: elmato Date: Wed, 8 Mar 2017 01:50:01 +0000 Subject: [PATCH 03/10] Keep track of subscribed accounts and check for events that reference them --- libraries/app/database_api.cpp | 85 +++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 3d464dfa..a09c5f76 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -166,6 +166,16 @@ class database_api_impl : public std::enable_shared_from_this return _subscribe_filter.contains( i ); } + bool is_impacted_account( const flat_set& accounts) + { + if( !_subscribed_accounts.size() || !accounts.size() ) + return false; + + return std::any_of(accounts.begin(), accounts.end(), [this](const account_id_type& account) { + return _subscribed_accounts.find(account) != _subscribed_accounts.end(); + }); + } + template void enqueue_if_subscribed_to_market(const object* obj, market_queue_type& queue, bool full_object=true) { @@ -182,16 +192,17 @@ class database_api_impl : public std::enable_shared_from_this void broadcast_updates( const vector& updates ); void broadcast_market_updates( const market_queue_type& queue); - void handle_object_changed(bool force_notify, const vector& ids, std::function find_object); + void handle_object_changed(bool force_notify, bool full_object, const vector& ids, const flat_set& impacted_accounts, std::function find_object); /** called every time a block is applied to report the objects that were changed */ - void on_objects_new(const vector& ids); - void on_objects_changed(const vector& ids); - void on_objects_removed(const vector& ids, const vector& objs); + void on_objects_new(const vector& ids, const flat_set& impacted_accounts); + void on_objects_changed(const vector& ids, const flat_set& impacted_accounts); + void on_objects_removed(const vector& ids, const vector& objs, const flat_set& impacted_accounts); void on_applied_block(); bool _notify_remove_create = false; mutable fc::bloom_filter _subscribe_filter; + std::set _subscribed_accounts; std::function _subscribe_callback; std::function _pending_trx_callback; std::function _block_applied_callback; @@ -219,14 +230,14 @@ database_api::~database_api() {} database_api_impl::database_api_impl( graphene::chain::database& db ):_db(db) { wlog("creating database api ${x}", ("x",int64_t(this)) ); - _new_connection = _db.new_objects.connect([this](const vector& ids) { - on_objects_new(ids); + _new_connection = _db.new_objects.connect([this](const vector& ids, const flat_set& impacted_accounts) { + on_objects_new(ids, impacted_accounts); }); - _change_connection = _db.changed_objects.connect([this](const vector& ids) { - on_objects_changed(ids); + _change_connection = _db.changed_objects.connect([this](const vector& ids, const flat_set& impacted_accounts) { + on_objects_changed(ids, impacted_accounts); }); - _removed_connection = _db.removed_objects.connect([this](const vector& ids, const vector& objs) { - on_objects_removed(ids, objs); + _removed_connection = _db.removed_objects.connect([this](const vector& ids, const vector& objs, const flat_set& impacted_accounts) { + on_objects_removed(ids, objs, impacted_accounts); }); _applied_block_connection = _db.applied_block.connect([this](const signed_block&){ on_applied_block(); }); @@ -292,6 +303,7 @@ void database_api_impl::set_subscribe_callback( std::function database_api_impl::get_full_accounts( const if( subscribe ) { + FC_ASSERT( std::distance(_subscribed_accounts.begin(), _subscribed_accounts.end()) < 100 ); + _subscribed_accounts.insert( account->get_id() ); subscribe_to_item( account->id ); } @@ -1849,36 +1863,37 @@ void database_api_impl::broadcast_market_updates( const market_queue_type& queue } } -void database_api_impl::on_objects_removed( const vector& ids, const vector& objs ) +void database_api_impl::on_objects_removed( const vector& ids, const vector& objs, const flat_set& impacted_accounts) { - handle_object_changed(_notify_remove_create, ids, [objs](object_id_type id) -> const object* { + handle_object_changed(_notify_remove_create, false, ids, impacted_accounts, + [objs](object_id_type id) -> const object* { + auto it = std::find_if( + objs.begin(), objs.end(), + [id](const object* o) {return o != nullptr && o->id == id;}); - auto it = std::find_if( - objs.begin(), objs.end(), - [id](const object* o) {return o != nullptr && o->id == id;}); + if (it != objs.end()) + return *it; - if (it != objs.end()) - return *it; - - return nullptr; - }); + return nullptr; + } + ); } -void database_api_impl::on_objects_new(const vector& ids) +void database_api_impl::on_objects_new(const vector& ids, const flat_set& impacted_accounts) { - handle_object_changed(_notify_remove_create, ids, + handle_object_changed(_notify_remove_create, true, ids, impacted_accounts, std::bind(&object_database::find_object, &_db, std::placeholders::_1) ); } -void database_api_impl::on_objects_changed(const vector& ids) +void database_api_impl::on_objects_changed(const vector& ids, const flat_set& impacted_accounts) { - handle_object_changed(false, ids, + handle_object_changed(false, true, ids, impacted_accounts, std::bind(&object_database::find_object, &_db, std::placeholders::_1) ); } -void database_api_impl::handle_object_changed(bool force_notify, const vector& ids, std::function find_object) +void database_api_impl::handle_object_changed(bool force_notify, bool full_object, const vector& ids, const flat_set& impacted_accounts, std::function find_object) { if( _subscribe_callback ) { @@ -1886,13 +1901,19 @@ void database_api_impl::handle_object_changed(bool force_notify, const vectorto_variant() ); + auto obj = find_object(id); + if( obj ) + { + updates.emplace_back( obj->to_variant() ); + } + } + else + { + updates.emplace_back( id ); } } } @@ -1908,11 +1929,11 @@ void database_api_impl::handle_object_changed(bool force_notify, const vector() ) { - enqueue_if_subscribed_to_market( find_object(id), broadcast_queue ); + enqueue_if_subscribed_to_market( find_object(id), broadcast_queue, full_object ); } else if( id.is() ) { - enqueue_if_subscribed_to_market( find_object(id), broadcast_queue ); + enqueue_if_subscribed_to_market( find_object(id), broadcast_queue, full_object ); } } From cff792a740d5694b4e0ad94f6039b0d1693ead3a Mon Sep 17 00:00:00 2001 From: elmato Date: Wed, 8 Mar 2017 01:52:25 +0000 Subject: [PATCH 04/10] debug_witness: Handle new params in changed/remove signals from database --- libraries/plugins/debug_witness/debug_witness.cpp | 8 ++++---- .../include/graphene/debug_witness/debug_witness.hpp | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libraries/plugins/debug_witness/debug_witness.cpp b/libraries/plugins/debug_witness/debug_witness.cpp index 19cf0f49..17f852c5 100644 --- a/libraries/plugins/debug_witness/debug_witness.cpp +++ b/libraries/plugins/debug_witness/debug_witness.cpp @@ -98,13 +98,13 @@ void debug_witness_plugin::plugin_startup() // connect needed signals _applied_block_conn = db.applied_block.connect([this](const graphene::chain::signed_block& b){ on_applied_block(b); }); - _changed_objects_conn = db.changed_objects.connect([this](const std::vector& ids){ on_changed_objects(ids); }); - _removed_objects_conn = db.removed_objects.connect([this](const std::vector& ids, const std::vector& objs){ on_removed_objects(ids, objs); }); + _changed_objects_conn = db.changed_objects.connect([this](const std::vector& ids, const fc::flat_set& impacted_accounts){ on_changed_objects(ids, impacted_accounts); }); + _removed_objects_conn = db.removed_objects.connect([this](const std::vector& ids, const std::vector& objs, const fc::flat_set& impacted_accounts){ on_removed_objects(ids, objs, impacted_accounts); }); return; } -void debug_witness_plugin::on_changed_objects( const std::vector& ids ) +void debug_witness_plugin::on_changed_objects( const std::vector& ids, const fc::flat_set& impacted_accounts ) { if( _json_object_stream && (ids.size() > 0) ) { @@ -120,7 +120,7 @@ void debug_witness_plugin::on_changed_objects( const std::vector& ids, const std::vector objs ) +void debug_witness_plugin::on_removed_objects( const std::vector& ids, const std::vector objs, const fc::flat_set& impacted_accounts ) { if( _json_object_stream ) { diff --git a/libraries/plugins/debug_witness/include/graphene/debug_witness/debug_witness.hpp b/libraries/plugins/debug_witness/include/graphene/debug_witness/debug_witness.hpp index fa387891..907d26ae 100644 --- a/libraries/plugins/debug_witness/include/graphene/debug_witness/debug_witness.hpp +++ b/libraries/plugins/debug_witness/include/graphene/debug_witness/debug_witness.hpp @@ -25,8 +25,10 @@ #include #include +#include #include +#include namespace graphene { namespace debug_witness_plugin { @@ -50,8 +52,8 @@ public: private: - void on_changed_objects( const std::vector& ids ); - void on_removed_objects( const std::vector& ids, const std::vector objs ); + void on_changed_objects( const std::vector& ids, const fc::flat_set& impacted_accounts ); + void on_removed_objects( const std::vector& ids, const std::vector objs, const fc::flat_set& impacted_accounts ); void on_applied_block( const graphene::chain::signed_block& b ); boost::program_options::variables_map _options; From 3eb160bed1299ba7b1ec91eec4642868ece03b4a Mon Sep 17 00:00:00 2001 From: elmato Date: Wed, 22 Mar 2017 22:03:45 +0000 Subject: [PATCH 05/10] Move notification related functions from db_block.cpp to db_notify.cpp --- libraries/chain/database.cpp | 1 + libraries/chain/db_block.cpp | 390 +-------------------------------- libraries/chain/db_notify.cpp | 392 ++++++++++++++++++++++++++++++++++ 3 files changed, 394 insertions(+), 389 deletions(-) create mode 100644 libraries/chain/db_notify.cpp diff --git a/libraries/chain/database.cpp b/libraries/chain/database.cpp index aa9f6127..2d02b184 100644 --- a/libraries/chain/database.cpp +++ b/libraries/chain/database.cpp @@ -32,3 +32,4 @@ #include "db_market.cpp" #include "db_update.cpp" #include "db_witness_schedule.cpp" +#include "db_notify.cpp" \ No newline at end of file diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index 948c7a34..d3d9a1d3 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -26,208 +26,19 @@ #include #include -#include - -#include -#include -#include -#include -#include -#include -#include - #include #include #include -#include + #include #include #include -#include #include #include #include #include -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_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 ); - } - -}; - namespace graphene { namespace chain { bool database::is_known_block( const block_id_type& id )const @@ -735,205 +546,6 @@ void database::_apply_block( const signed_block& next_block ) } FC_CAPTURE_AND_RETHROW( (next_block.block_num()) ) } -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 ); -} - -void get_relevant_accounts( const object* obj, flat_set& accounts ) -{ - if( obj->id.space() == protocol_ids ) - { - switch( (object_type)obj->id.type() ) - { - case null_object_type: - case base_object_type: - case OBJECT_TYPE_COUNT: - return; - case account_object_type:{ - accounts.insert( obj->id ); - break; - } case asset_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->issuer ); - break; - } case force_settlement_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->owner ); - break; - } case committee_member_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->committee_member_account ); - break; - } case witness_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->witness_account ); - break; - } case limit_order_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->seller ); - break; - } case call_order_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->borrower ); - break; - } case custom_object_type:{ - break; - } case proposal_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - transaction_get_impacted_accounts( aobj->proposed_transaction, accounts ); - break; - } case operation_history_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - operation_get_impacted_accounts( aobj->op, accounts ); - break; - } case withdraw_permission_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->withdraw_from_account ); - accounts.insert( aobj->authorized_account ); - break; - } case vesting_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->owner ); - break; - } case worker_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->worker_account ); - break; - } case balance_object_type:{ - /** these are free from any accounts */ - break; - } - } - } - else if( obj->id.space() == implementation_ids ) - { - switch( (impl_object_type)obj->id.type() ) - { - case impl_global_property_object_type: - break; - case impl_dynamic_global_property_object_type: - break; - case impl_reserved0_object_type: - break; - case impl_asset_dynamic_data_type: - break; - case impl_asset_bitasset_data_type: - break; - case impl_account_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->owner ); - break; - } case impl_account_statistics_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - accounts.insert( aobj->owner ); - break; - } case impl_transaction_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - transaction_get_impacted_accounts( aobj->trx, accounts ); - break; - } case impl_blinded_balance_object_type:{ - const auto& aobj = dynamic_cast(obj); - assert( aobj != nullptr ); - for( const auto& a : aobj->owner.account_auths ) - accounts.insert( a.first ); - break; - } case impl_block_summary_object_type: - break; - case impl_account_transaction_history_object_type: - break; - case impl_chain_property_object_type: - break; - case impl_witness_schedule_object_type: - break; - case impl_budget_record_object_type: - break; - case impl_special_authority_object_type: - break; - case impl_buyback_object_type: - break; - case impl_fba_accumulator_object_type: - break; - } - } -} // end get_relevant_accounts( const object* obj, flat_set& accounts ) - - -void database::notify_changed_objects() -{ try { - if( _undo_db.enabled() ) - { - const auto& head_undo = _undo_db.head(); - - // New - if( !new_objects.empty() ) - { - vector new_ids; new_ids.reserve(head_undo.new_ids.size()); - flat_set new_accounts_impacted; - for( const auto& item : head_undo.new_ids ) - { - new_ids.push_back(item); - auto obj = find_object(item); - if(obj != nullptr) - get_relevant_accounts(obj, new_accounts_impacted); - } - - new_objects(new_ids, new_accounts_impacted); - } - - // Changed - if( !changed_objects.empty() ) - { - vector changed_ids; changed_ids.reserve(head_undo.old_values.size()); - flat_set changed_accounts_impacted; - for( const auto& item : head_undo.old_values ) - { - changed_ids.push_back(item.first); - get_relevant_accounts(item.second.get(), changed_accounts_impacted); - } - - changed_objects(changed_ids, changed_accounts_impacted); - } - - // Removed - if( !removed_objects.empty() ) - { - vector removed_ids; removed_ids.reserve( head_undo.removed.size() ); - vector removed; removed.reserve( head_undo.removed.size() ); - flat_set removed_accounts_impacted; - for( const auto& item : head_undo.removed ) - { - removed_ids.emplace_back( item.first ); - auto obj = item.second.get(); - removed.emplace_back( obj ); - get_relevant_accounts(obj, removed_accounts_impacted); - } - - removed_objects(removed_ids, removed, removed_accounts_impacted); - } - } -} FC_CAPTURE_AND_LOG( () ) } processed_transaction database::apply_transaction(const signed_transaction& trx, uint32_t skip) { diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp new file mode 100644 index 00000000..7b5375cc --- /dev/null +++ b/libraries/chain/db_notify.cpp @@ -0,0 +1,392 @@ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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_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 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 ); +} + +void get_relevant_accounts( const object* obj, flat_set& accounts ) +{ + if( obj->id.space() == protocol_ids ) + { + switch( (object_type)obj->id.type() ) + { + case null_object_type: + case base_object_type: + case OBJECT_TYPE_COUNT: + return; + case account_object_type:{ + accounts.insert( obj->id ); + break; + } case asset_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->issuer ); + break; + } case force_settlement_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case committee_member_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->committee_member_account ); + break; + } case witness_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->witness_account ); + break; + } case limit_order_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->seller ); + break; + } case call_order_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->borrower ); + break; + } case custom_object_type:{ + break; + } case proposal_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + transaction_get_impacted_accounts( aobj->proposed_transaction, accounts ); + break; + } case operation_history_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + operation_get_impacted_accounts( aobj->op, accounts ); + break; + } case withdraw_permission_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->withdraw_from_account ); + accounts.insert( aobj->authorized_account ); + break; + } case vesting_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case worker_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->worker_account ); + break; + } case balance_object_type:{ + /** these are free from any accounts */ + break; + } + } + } + else if( obj->id.space() == implementation_ids ) + { + switch( (impl_object_type)obj->id.type() ) + { + case impl_global_property_object_type: + break; + case impl_dynamic_global_property_object_type: + break; + case impl_reserved0_object_type: + break; + case impl_asset_dynamic_data_type: + break; + case impl_asset_bitasset_data_type: + break; + case impl_account_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case impl_account_statistics_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + accounts.insert( aobj->owner ); + break; + } case impl_transaction_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + transaction_get_impacted_accounts( aobj->trx, accounts ); + break; + } case impl_blinded_balance_object_type:{ + const auto& aobj = dynamic_cast(obj); + assert( aobj != nullptr ); + for( const auto& a : aobj->owner.account_auths ) + accounts.insert( a.first ); + break; + } case impl_block_summary_object_type: + break; + case impl_account_transaction_history_object_type: + break; + case impl_chain_property_object_type: + break; + case impl_witness_schedule_object_type: + break; + case impl_budget_record_object_type: + break; + case impl_special_authority_object_type: + break; + case impl_buyback_object_type: + break; + case impl_fba_accumulator_object_type: + break; + } + } +} // end get_relevant_accounts( const object* obj, flat_set& accounts ) + +namespace graphene { namespace chain { + +void database::notify_changed_objects() +{ try { + if( _undo_db.enabled() ) + { + const auto& head_undo = _undo_db.head(); + + // New + if( !new_objects.empty() ) + { + vector new_ids; new_ids.reserve(head_undo.new_ids.size()); + flat_set new_accounts_impacted; + for( const auto& item : head_undo.new_ids ) + { + new_ids.push_back(item); + auto obj = find_object(item); + if(obj != nullptr) + get_relevant_accounts(obj, new_accounts_impacted); + } + + new_objects(new_ids, new_accounts_impacted); + } + + // Changed + if( !changed_objects.empty() ) + { + vector changed_ids; changed_ids.reserve(head_undo.old_values.size()); + flat_set changed_accounts_impacted; + for( const auto& item : head_undo.old_values ) + { + changed_ids.push_back(item.first); + get_relevant_accounts(item.second.get(), changed_accounts_impacted); + } + + changed_objects(changed_ids, changed_accounts_impacted); + } + + // Removed + if( !removed_objects.empty() ) + { + vector removed_ids; removed_ids.reserve( head_undo.removed.size() ); + vector removed; removed.reserve( head_undo.removed.size() ); + flat_set removed_accounts_impacted; + for( const auto& item : head_undo.removed ) + { + removed_ids.emplace_back( item.first ); + auto obj = item.second.get(); + removed.emplace_back( obj ); + get_relevant_accounts(obj, removed_accounts_impacted); + } + + removed_objects(removed_ids, removed, removed_accounts_impacted); + } + } +} FC_CAPTURE_AND_LOG( () ) } + +} } \ No newline at end of file From 63189ab2e843db01594b7e5b2e0dbc2484c8756b Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Fri, 24 Mar 2017 12:31:59 -0500 Subject: [PATCH 06/10] Update README --- LICENSE => LICENSE.txt | 0 README.md | 7 +++++-- docs | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) rename LICENSE => LICENSE.txt (100%) diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/README.md b/README.md index 81b44092..70be3650 100644 --- a/README.md +++ b/README.md @@ -36,8 +36,11 @@ To build after all dependencies are installed: cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo . make -Alternate Boost versions can be specified using the `DBOOST_ROOT` CMake argument. After building, the witness node can -be launched with: +**NOTE:** BitShares requires a [Boost](http://www.boost.org/) version in the range [1.57, 1.60]. Versions earlier than +1.57 or newer than 1.60 are NOT supported. If your system Boost version is newer, then you will need to manually build +an older version of Boost and specify it to CMake using `DBOOST_ROOT`. + +After building, the witness node can be launched with: ./programs/witness_node/witness_node diff --git a/docs b/docs index 474c28bc..981d1ef1 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit 474c28bc7181739f25229b45b76646a693cad998 +Subproject commit 981d1ef1eb35e89bb9a9423c1762427fe8ef07cc From 12be59db79e3bf714757dd0a1eadb2d9b9e9c7b9 Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Fri, 24 Mar 2017 16:18:35 -0500 Subject: [PATCH 07/10] Fix crashes in get_ticker and get_24_volume; #250 --- libraries/app/database_api.cpp | 140 ++++++++++++--------------------- 1 file changed, 49 insertions(+), 91 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index a09c5f76..fe46a00f 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1078,120 +1078,78 @@ void database_api_impl::unsubscribe_from_market(asset_id_type a, asset_id_type b market_ticker database_api::get_ticker( const string& base, const string& quote )const { - return my->get_ticker( base, quote ); + return my->get_ticker( base, quote ); } market_ticker database_api_impl::get_ticker( const string& base, const string& quote )const { - auto assets = lookup_asset_symbols( {base, quote} ); - FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); - FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); + const auto assets = lookup_asset_symbols( {base, quote} ); + FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); + FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); - auto base_id = assets[0]->id; - auto quote_id = assets[1]->id; + market_ticker result; + result.base = base; + result.quote = quote; + result.latest = 0; + result.lowest_ask = 0; + result.highest_bid = 0; + result.percent_change = 0; + result.base_volume = 0; + result.quote_volume = 0; - market_ticker result; + try { + const fc::time_point_sec now = fc::time_point::now(); + const fc::time_point_sec yesterday = fc::time_point_sec( now.sec_since_epoch() - 86400 ); + const auto batch_size = 1000; - result.base = base; - result.quote = quote; - result.base_volume = 0; - result.quote_volume = 0; - result.percent_change = 0; - result.lowest_ask = 0; - result.highest_bid = 0; + vector trades = get_trade_history( base, quote, now, yesterday, batch_size ); + if( !trades.empty() ) + { + result.latest = trades[0].price; - auto price_to_real = [&]( const share_type a, int p ) { return double( a.value ) / pow( 10, p ); }; - - try { - if( base_id > quote_id ) std::swap(base_id, quote_id); - - uint32_t day = 86400; - auto now = fc::time_point_sec( fc::time_point::now() ); - auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - day ), 100 ); - - if ( trades.size() ) - { - result.latest = trades[0].price; - - for ( market_trade t: trades ) - { - result.base_volume += t.value; - result.quote_volume += t.amount; - } - - while (trades.size() == 100) - { - trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - day ), 100 ); - - for ( market_trade t: trades ) + while( !trades.empty() ) { - result.base_volume += t.value; - result.quote_volume += t.amount; + for( const market_trade& t: trades ) + { + result.base_volume += t.value; + result.quote_volume += t.amount; + } + + trades = get_trade_history( base, quote, trades.back().date, yesterday, batch_size ); } - } - trades = get_trade_history( base, quote, trades.back().date, fc::time_point_sec(), 1 ); - result.percent_change = trades.size() > 0 ? ( ( result.latest / trades.back().price ) - 1 ) * 100 : 0; - } + const auto last_trade_yesterday = get_trade_history( base, quote, yesterday, fc::time_point_sec(), 1 ); + if( !last_trade_yesterday.empty()) + { + const auto price_yesterday = last_trade_yesterday[0].price; + result.percent_change = ( (result.latest / price_yesterday) - 1 ) * 100; + } + } - auto orders = get_order_book( base, quote, 1 ); - if( orders.asks.size() ) - result.lowest_ask = orders.asks[0].price; - if( orders.bids.size() ) - result.highest_bid = orders.bids[0].price; + const auto orders = get_order_book( base, quote, 1 ); + if( !orders.asks.empty() ) result.lowest_ask = orders.asks[0].price; + if( !orders.bids.empty() ) result.highest_bid = orders.bids[0].price; + } FC_CAPTURE_AND_RETHROW( (base)(quote) ) - } FC_CAPTURE_AND_RETHROW( (base)(quote) ) - - return result; + return result; } market_volume database_api::get_24_volume( const string& base, const string& quote )const { - return my->get_24_volume( base, quote ); + return my->get_24_volume( base, quote ); } market_volume database_api_impl::get_24_volume( const string& base, const string& quote )const { - auto assets = lookup_asset_symbols( {base, quote} ); - FC_ASSERT( assets[0], "Invalid base asset symbol: ${s}", ("s",base) ); - FC_ASSERT( assets[1], "Invalid quote asset symbol: ${s}", ("s",quote) ); + const auto ticker = get_ticker( base, quote ); - auto base_id = assets[0]->id; - auto quote_id = assets[1]->id; + market_volume result; + result.base = ticker.base; + result.quote = ticker.quote; + result.base_volume = ticker.base_volume; + result.quote_volume = ticker.quote_volume; - market_volume result; - result.base = base; - result.quote = quote; - result.base_volume = 0; - result.quote_volume = 0; - - try { - if( base_id > quote_id ) std::swap(base_id, quote_id); - - uint32_t bucket_size = 86400; - auto now = fc::time_point_sec( fc::time_point::now() ); - - auto trades = get_trade_history( base, quote, now, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 ); - - for ( market_trade t: trades ) - { - result.base_volume += t.value; - result.quote_volume += t.amount; - } - - while (trades.size() == 100) - { - trades = get_trade_history( base, quote, trades[99].date, fc::time_point_sec( now.sec_since_epoch() - bucket_size ), 100 ); - - for ( market_trade t: trades ) - { - result.base_volume += t.value; - result.quote_volume += t.amount; - } - } - - return result; - } FC_CAPTURE_AND_RETHROW( (base)(quote) ) + return result; } order_book database_api::get_order_book( const string& base, const string& quote, unsigned limit )const From b209915a36b03b698cc3993ae657e3a08589e17c Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Fri, 24 Mar 2017 16:50:03 -0500 Subject: [PATCH 08/10] Return latest price in get_ticker even if older than 24 hours --- libraries/app/database_api.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index fe46a00f..cfdcea3c 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -193,7 +193,7 @@ class database_api_impl : public std::enable_shared_from_this void broadcast_updates( const vector& updates ); void broadcast_market_updates( const market_queue_type& queue); void handle_object_changed(bool force_notify, bool full_object, const vector& ids, const flat_set& impacted_accounts, std::function find_object); - + /** called every time a block is applied to report the objects that were changed */ void on_objects_new(const vector& ids, const flat_set& impacted_accounts); void on_objects_changed(const vector& ids, const flat_set& impacted_accounts); @@ -666,22 +666,22 @@ std::map database_api_impl::get_full_accounts( const [&acnt] (const call_order_object& call) { acnt.call_orders.emplace_back(call); }); - + // get assets issued by user auto asset_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(asset_range.first, asset_range.second, [&acnt] (const asset_object& asset) { acnt.assets.emplace_back(asset.id); }); - + // get withdraws permissions auto withdraw_range = _db.get_index_type().indices().get().equal_range(account->id); std::for_each(withdraw_range.first, withdraw_range.second, [&acnt] (const withdraw_permission_object& withdraw) { acnt.withdraws.emplace_back(withdraw); }); - - + + results[account_name_or_id] = acnt; } return results; @@ -1105,7 +1105,7 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q vector trades = get_trade_history( base, quote, now, yesterday, batch_size ); if( !trades.empty() ) { - result.latest = trades[0].price; + result.latest = trades[0].price; while( !trades.empty() ) { @@ -1119,12 +1119,18 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q } const auto last_trade_yesterday = get_trade_history( base, quote, yesterday, fc::time_point_sec(), 1 ); - if( !last_trade_yesterday.empty()) + if( !last_trade_yesterday.empty() ) { const auto price_yesterday = last_trade_yesterday[0].price; result.percent_change = ( (result.latest / price_yesterday) - 1 ) * 100; } } + else + { + const auto last_trade = get_trade_history( base, quote, now, fc::time_point_sec(), 1 ); + if( !last_trade.empty() ) + result.latest = last_trade[0].price; + } const auto orders = get_order_book( base, quote, 1 ); if( !orders.asks.empty() ) result.lowest_ask = orders.asks[0].price; @@ -1856,7 +1862,7 @@ void database_api_impl::handle_object_changed(bool force_notify, bool full_objec if( _subscribe_callback ) { vector updates; - + for(auto id : ids) { if( force_notify || is_subscribed_to_item(id) || is_impacted_account(impacted_accounts) ) From 53b40ba5a628afbc87150ab702c291983c4a453f Mon Sep 17 00:00:00 2001 From: Vikram Rajkumar Date: Fri, 24 Mar 2017 17:08:48 -0500 Subject: [PATCH 09/10] Restore get_ticker batch size to 100 --- libraries/app/database_api.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index cfdcea3c..5c882d07 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -1100,7 +1100,7 @@ market_ticker database_api_impl::get_ticker( const string& base, const string& q try { const fc::time_point_sec now = fc::time_point::now(); const fc::time_point_sec yesterday = fc::time_point_sec( now.sec_since_epoch() - 86400 ); - const auto batch_size = 1000; + const auto batch_size = 100; vector trades = get_trade_history( base, quote, now, yesterday, batch_size ); if( !trades.empty() ) From 9466d2096a370e15aff70842b48feeca4a941e5c Mon Sep 17 00:00:00 2001 From: Sigve Kvalsvik Date: Tue, 28 Mar 2017 11:42:24 +0200 Subject: [PATCH 10/10] Update gui_version --- gui_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui_version b/gui_version index 5f25c56d..462b6bda 100644 --- a/gui_version +++ b/gui_version @@ -1 +1 @@ -2.0.170224 +2.0.170328