From 723b11533bb352940f5784164ed1bfb7a46b915c Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Thu, 16 Jul 2015 17:02:08 -0400 Subject: [PATCH] Progress #166: Initial implementation of get_full_accounts API call --- libraries/app/api.cpp | 95 +++++++++++++++++-- libraries/app/include/graphene/app/api.hpp | 34 +++++-- libraries/chain/db_init.cpp | 5 +- .../graphene/chain/market_evaluator.hpp | 6 +- .../graphene/chain/vesting_balance_object.hpp | 6 +- 5 files changed, 124 insertions(+), 22 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 864539c0..815710d0 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -149,6 +149,87 @@ namespace graphene { namespace app { return result; } + std::map database_api::get_full_accounts(std::function callback, + const vector& names_or_ids) + { + std::map results; + std::set ids_to_subscribe; + + for (const std::string& account_name_or_id : names_or_ids) + { + const account_object* account = nullptr; + if (std::isdigit(account_name_or_id[0])) + account = _db.find(fc::variant(account_name_or_id).as()); + else + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account_name_or_id); + if (itr != idx.end()) + account = &*itr; + } + if (account == nullptr) + continue; + + ids_to_subscribe.insert({account->id, account->statistics}); + + fc::mutable_variant_object full_account; + + // Add the account itself, its statistics object, cashback balance, and referral account names + full_account("account", *account)("statistics", account->statistics(_db)) + ("registrar_name", account->registrar(_db).name)("referrer_name", account->referrer(_db).name) + ("lifetime_referrer_name", account->lifetime_referrer(_db).name); + if (account->cashback_vb) + { + ids_to_subscribe.insert(*account->cashback_vb); + full_account("cashback_balance", account->cashback_balance(_db)); + } + + // Add the account's balances + auto balance_range = _db.get_index_type().indices().get().equal_range(account->id); + vector balances; + std::for_each(balance_range.first, balance_range.second, + [&balances, &ids_to_subscribe](const account_balance_object& balance) { + balances.emplace_back(balance); + ids_to_subscribe.insert(balance.id); + }); + idump((balances)); + full_account("balances", balances); + + // Add the account's vesting balances + auto vesting_range = _db.get_index_type().indices().get().equal_range(account->id); + vector vesting_balances; + std::for_each(vesting_range.first, vesting_range.second, + [&vesting_balances, &ids_to_subscribe](const vesting_balance_object& balance) { + vesting_balances.emplace_back(balance); + ids_to_subscribe.insert(balance.id); + }); + full_account("vesting_balances", vesting_balances); + + // Add the account's orders + auto order_range = _db.get_index_type().indices().get().equal_range(account->id); + vector orders; + std::for_each(order_range.first, order_range.second, + [&orders, &ids_to_subscribe] (const limit_order_object& order) { + orders.emplace_back(order); + ids_to_subscribe.insert(order.id); + }); + auto call_range = _db.get_index_type().indices().get().equal_range(account->id); + vector calls; + std::for_each(call_range.first, call_range.second, + [&calls, &ids_to_subscribe] (const call_order_object& call) { + calls.emplace_back(call); + ids_to_subscribe.insert(call.id); + }); + full_account("limit_orders", orders)("call_orders", calls); + + results[account_name_or_id] = full_account; + } + + wdump((results)); + subscribe_to_objects(callback, vector(ids_to_subscribe.begin(), ids_to_subscribe.end())); + return results; + } + vector database_api::get_account_balances(account_id_type acnt, const flat_set& assets)const { vector result; @@ -278,12 +359,12 @@ namespace graphene { namespace app { // we want to order witnesses by account name, but that name is in the account object // so the witness_index doesn't have a quick way to access it. // get all the names and look them all up, sort them, then figure out what - // records to return. This could be optimized, but we expect the + // records to return. This could be optimized, but we expect the // number of witnesses to be few and the frequency of calls to be rare std::map witnesses_by_account_name; for (const witness_object& witness : witnesses_by_id) if (auto account_iter = _db.find(witness.witness_account)) - if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name witnesses_by_account_name.insert(std::make_pair(account_iter->name, witness.id)); auto end_iter = witnesses_by_account_name.begin(); @@ -292,7 +373,7 @@ namespace graphene { namespace app { witnesses_by_account_name.erase(end_iter, witnesses_by_account_name.end()); return witnesses_by_account_name; } - + map database_api::lookup_committee_member_accounts(const string& lower_bound_name, uint32_t limit)const { FC_ASSERT( limit <= 1000 ); @@ -301,12 +382,12 @@ namespace graphene { namespace app { // we want to order committee_members by account name, but that name is in the account object // so the committee_member_index doesn't have a quick way to access it. // get all the names and look them all up, sort them, then figure out what - // records to return. This could be optimized, but we expect the + // records to return. This could be optimized, but we expect the // number of committee_members to be few and the frequency of calls to be rare std::map committee_members_by_account_name; for (const committee_member_object& committee_member : committee_members_by_id) if (auto account_iter = _db.find(committee_member.committee_member_account)) - if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name + if (account_iter->name >= lower_bound_name) // we can ignore anything below lower_bound_name committee_members_by_account_name.insert(std::make_pair(account_iter->name, committee_member.id)); auto end_iter = committee_members_by_account_name.begin(); @@ -315,7 +396,7 @@ namespace graphene { namespace app { committee_members_by_account_name.erase(end_iter, committee_members_by_account_name.end()); return committee_members_by_account_name; } - + vector> database_api::get_witnesses(const vector& witness_ids)const { vector> result; result.reserve(witness_ids.size()); @@ -605,7 +686,7 @@ namespace graphene { namespace app { return hist->tracked_buckets(); } - vector history_api::get_market_history( asset_id_type a, asset_id_type b, + vector history_api::get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds, fc::time_point_sec start, fc::time_point_sec end )const { try { FC_ASSERT(_app.chain_database()); diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index f820044b..75d3ac52 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -57,29 +57,29 @@ namespace graphene { namespace app { * * If any of the provided IDs does not map to an object, a null variant is returned in its position. */ - fc::variants get_objects(const vector& ids)const; + fc::variants get_objects(const vector& ids)const; /** * @brief Retrieve a block header * @param block_num Height of the block whose header should be returned * @return header of the referenced block, or null if no matching block was found */ - optional get_block_header(uint32_t block_num)const; + optional get_block_header(uint32_t block_num)const; /** * @brief Retrieve a full, signed block * @param block_num Height of the block to be returned * @return the referenced block, or null if no matching block was found */ - optional get_block(uint32_t block_num)const; + optional get_block(uint32_t block_num)const; /** * @brief used to fetch an individual transaction. */ - processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const; + processed_transaction get_transaction( uint32_t block_num, uint32_t trx_in_block )const; /** * @brief Retrieve the current @ref global_property_object */ - global_property_object get_global_properties()const; + global_property_object get_global_properties()const; /** * @brief Retrieve the current @ref dynamic_global_property_object */ @@ -138,6 +138,21 @@ namespace graphene { namespace app { */ map lookup_accounts(const string& lower_bound_name, uint32_t limit)const; + /** + * @brief Fetch all objects relevant to the specified accounts and subscribe to updates + * @param callback Function to call with updates + * @param names_or_ids Each item must be the name or ID of an account to retrieve + * @return Map of string from @ref names_or_ids to the corresponding account + * + * This function fetches all relevant objects for the given accounts, and subscribes to updates to the given + * accounts. If any of the strings in @ref names_or_ids cannot be tied to an account, that input will be + * ignored. All other accounts will be retrieved and subscribed. + * + * TODO: Describe the return value and argument to callback in detail + */ + std::map get_full_accounts(std::function callback, + const vector& names_or_ids); + /** * @brief Get limit orders in a given market * @param a ID of asset being sold @@ -324,9 +339,9 @@ namespace graphene { namespace app { vector get_market_history( asset_id_type a, asset_id_type b, uint32_t bucket_seconds, fc::time_point_sec start, fc::time_point_sec end )const; - flat_set get_market_history_buckets()const; + flat_set get_market_history_buckets()const; private: - application& _app; + application& _app; }; /** @@ -403,7 +418,7 @@ namespace graphene { namespace app { std::vector get_connected_peers() const; private: - application& _app; + application& _app; }; /** @@ -440,7 +455,7 @@ namespace graphene { namespace app { /// @brief Called to enable an API, not reflected. void enable_api( const string& api_name ); - application& _app; + application& _app; optional< fc::api > _database_api; optional< fc::api > _network_broadcast_api; optional< fc::api > _network_node_api; @@ -464,6 +479,7 @@ FC_API(graphene::app::database_api, (lookup_account_names) (get_account_count) (lookup_accounts) + (get_full_accounts) (get_account_balances) (get_named_account_balances) (lookup_asset_symbols) diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 65e91391..32a724cf 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -174,8 +174,7 @@ void database::initialize_indexes() prop_index->add_secondary_index(); add_index< primary_index >(); - //add_index< primary_index >(); - add_index< primary_index> >(); + add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); @@ -214,7 +213,7 @@ void database::init_genesis(const genesis_state_type& genesis_state) transaction_evaluation_state genesis_eval_state(this); - flat_index& bsi = get_mutable_index_type< flat_index >(); + flat_index& bsi = get_mutable_index_type< flat_index >(); bsi.resize(0xffff+1); // Create blockchain accounts diff --git a/libraries/chain/include/graphene/chain/market_evaluator.hpp b/libraries/chain/include/graphene/chain/market_evaluator.hpp index 7e5b7258..cd316491 100644 --- a/libraries/chain/include/graphene/chain/market_evaluator.hpp +++ b/libraries/chain/include/graphene/chain/market_evaluator.hpp @@ -34,6 +34,7 @@ namespace graphene { namespace chain { struct by_id; struct by_price; struct by_expiration; + struct by_account; typedef multi_index_container< limit_order_object, indexed_by< @@ -46,7 +47,8 @@ namespace graphene { namespace chain { member< object, object_id_type, &object::id> >, composite_key_compare< std::greater, std::less > - > + >, + ordered_non_unique< tag, member> > > limit_order_multi_index_type; @@ -74,7 +76,7 @@ namespace graphene { namespace chain { account_id_type borrower; share_type collateral; ///< call_price.base.asset_id, access via get_collateral share_type debt; ///< call_price.quote.asset_id, access via get_collateral - price call_price; ///< Debt / Collateral + price call_price; ///< Debt / Collateral }; /** diff --git a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp index efac5243..3386d021 100644 --- a/libraries/chain/include/graphene/chain/vesting_balance_object.hpp +++ b/libraries/chain/include/graphene/chain/vesting_balance_object.hpp @@ -159,10 +159,14 @@ namespace graphene { namespace chain { /** * @ingroup object_index */ + struct by_account; typedef multi_index_container< vesting_balance_object, indexed_by< - hashed_unique< tag, member< object, object_id_type, &object::id > > + hashed_unique< tag, member< object, object_id_type, &object::id > >, + ordered_non_unique< tag, + member + > > > vesting_balance_multi_index_type; /**