From 889265406a56af658eaebe034bca41aa88432109 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 09:15:34 +0300 Subject: [PATCH] #260 Add votes function to database_api and wallet_api --- libraries/app/database_api.cpp | 107 +++++++++++++++++- .../app/include/graphene/app/database_api.hpp | 35 ++++++ .../include/graphene/chain/votes_info.hpp | 48 ++++++++ .../wallet/include/graphene/wallet/wallet.hpp | 28 ++++- libraries/wallet/wallet.cpp | 42 +++++++ 5 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 libraries/chain/include/graphene/chain/votes_info.hpp diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 77582222..10a83060 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -175,6 +175,23 @@ public: // Votes vector lookup_vote_ids(const vector &votes) const; + vector get_votes_ids(const string &account_name_or_id) const; + template + vector get_votes_objects(const vector &votes, unsigned int variant_max_depth = 1) const + { + static_assert( std::is_base_of::value, "Type must be an index type" ); + + vector result; + const auto &idx = _db.get_index_type().indices().template get(); + for (auto id : votes) { + auto itr = idx.find(id); + if (itr != idx.end()) + result.emplace_back(variant(*itr,variant_max_depth)); + } + return result; + } + votes_info get_votes(const string &account_name_or_id) const; + vector get_voters_by_id(const vote_id_type &vote_id) const; // Authority / validation std::string get_transaction_hex(const signed_transaction &trx) const; @@ -234,6 +251,9 @@ public: vector get_offer_history_by_item(const offer_history_id_type lower_id, const nft_id_type item, uint32_t limit) const; vector get_offer_history_by_bidder(const offer_history_id_type lower_id, const account_id_type bidder_account_id, uint32_t limit) const; + // Account Role + vector get_account_roles_by_owner(account_id_type owner) const; + uint32_t api_limit_get_lower_bound_symbol = 100; uint32_t api_limit_get_limit_orders = 300; uint32_t api_limit_get_limit_orders_by_account = 101; @@ -245,9 +265,6 @@ public: uint32_t api_limit_get_trade_history = 100; uint32_t api_limit_get_trade_history_by_sequence = 100; - // Account Role - vector get_account_roles_by_owner(account_id_type owner) const; - //private: const account_object *get_account_from_string(const std::string &name_or_id, bool throw_if_not_found = true) const; @@ -1885,6 +1902,18 @@ vector database_api::lookup_vote_ids(const vector &votes) return my->lookup_vote_ids(votes); } +vector database_api::get_votes_ids(const string &account_name_or_id) const { + return my->get_votes_ids(account_name_or_id); +} + +votes_info database_api::get_votes(const string &account_name_or_id) const { + return my->get_votes(account_name_or_id); +} + +vector database_api::get_voters_by_id(const vote_id_type &vote_id) const { + return my->get_voters_by_id(vote_id); +} + vector database_api_impl::lookup_vote_ids(const vector &votes) const { FC_ASSERT(votes.size() < 1000, "Only 1000 votes can be queried at a time"); @@ -1946,6 +1975,78 @@ vector database_api_impl::lookup_vote_ids(const vector &v return result; } +vector database_api_impl::get_votes_ids(const string &account_name_or_id) const { + vector result; + const account_object *account = get_account_from_string(account_name_or_id); + + //! Iterate throug votes and fill vector + for( const auto& vote : account->options.votes ) + { + result.emplace_back(vote); + } + + return result; +} + +votes_info database_api_impl::get_votes(const string &account_name_or_id) const { + votes_info result; + + const auto& votes_ids = get_votes_ids(account_name_or_id); + const auto& committee_ids = get_votes_objects(votes_ids); + const auto& witness_ids = get_votes_objects(votes_ids); + const auto& for_worker_ids = get_votes_objects(votes_ids); + const auto& against_worker_ids = get_votes_objects(votes_ids); + const auto& son_ids = get_votes_objects(votes_ids, 5); + + //! Fill votes info + result.votes_for_committee_members.reserve(committee_ids.size()); + for(const auto& committee : committee_ids) + { + const auto& committee_obj = committee.as(2); + result.votes_for_committee_members.emplace_back( votes_info_object{ committee_obj.vote_id, committee_obj.id.instance() } ); + } + result.votes_for_witnesses.reserve(witness_ids.size()); + for(const auto& witness : witness_ids) + { + const auto& witness_obj = witness.as(2); + result.votes_for_witnesses.emplace_back( votes_info_object{ witness_obj.vote_id, witness_obj.id.instance() } ); + } + result.votes_for_workers.reserve(for_worker_ids.size()); + for(const auto& for_worker : for_worker_ids) + { + const auto& for_worker_obj = for_worker.as(2); + result.votes_for_workers.emplace_back( votes_info_object{ for_worker_obj.vote_for, for_worker_obj.id.instance() } ); + } + result.votes_against_workers.reserve(against_worker_ids.size()); + for(const auto& against_worker : against_worker_ids) + { + const auto& against_worker_obj = against_worker.as(2); + result.votes_against_workers.emplace_back( votes_info_object{ against_worker_obj.vote_against, against_worker_obj.id.instance() } ); + } + result.votes_for_sons.reserve(son_ids.size()); + for(const auto& son : son_ids) + { + const auto& son_obj = son.as(6); + result.votes_for_sons.emplace_back( votes_info_object{ son_obj.vote_id, son_obj.id.instance() } ); + } + + return result; +} + +vector database_api_impl::get_voters_by_id(const vote_id_type &vote_id) const { + vector result; + + //! We search all accounts that have voted for this vote_id + const auto& account_index = _db.get_index_type().indices().get(); + for( const auto& account: account_index ) + { + if(account.options.votes.count(vote_id) != 0) + result.emplace_back(account); + } + + return result; +} + ////////////////////////////////////////////////////////////////////// // // // Authority / validation // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 695eae7a..5b507f8e 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -56,6 +56,7 @@ #include #include #include +#include #include @@ -721,6 +722,36 @@ public: */ vector lookup_vote_ids(const vector &votes) const; + /** + * @brief Get a list that ID votes for + * @param account_name_or_id ID or name of the account to get votes for + * @return The list of vote_id_type ID votes for + * + */ + vector get_votes_ids(const string &account_name_or_id) const; + + /** + * @brief Given a set of votes, return the objects ID votes for + * + * This will be a mixture of committee_member_object, witness_objects, and worker_objects + * + * The results will be in the same order as the votes. Null will be returned for + * any vote ids that are not found. + * + * @param account_name_or_id ID or name of the account to get votes for + * @return The set of votes ID votes for + * + */ + votes_info get_votes(const string &account_name_or_id) const; + + /** + * @brief Get a list of accounts that votes for vote_id + * @param vote_id We search accounts that vote for this ID + * @return The accounts that votes for provided ID + * + */ + vector get_voters_by_id(const vote_id_type &vote_id) const; + //////////////////////////// // Authority / validation // //////////////////////////// @@ -1062,8 +1093,12 @@ FC_API(graphene::app::database_api, // workers (get_workers_by_account) + // Votes (lookup_vote_ids) + (get_votes_ids) + (get_votes) + (get_voters_by_id) // Authority / validation (get_transaction_hex) diff --git a/libraries/chain/include/graphene/chain/votes_info.hpp b/libraries/chain/include/graphene/chain/votes_info.hpp new file mode 100644 index 00000000..bb757f90 --- /dev/null +++ b/libraries/chain/include/graphene/chain/votes_info.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace graphene { namespace chain { + + /** + * @class votes_info_object + * @tparam IdType id type of the object + * @ingroup object + */ + template + struct votes_info_object { + votes_info_object() = default; + votes_info_object(const vote_id_type& vote_id_, uint64_t id_) + : vote_id{vote_id_} + , id{id_} + {} + + vote_id_type vote_id; + IdType id; + }; + + /** + * @class votes_info + * @brief tracks information about a votes info + * @ingroup object + */ + struct votes_info { + vector< votes_info_object > votes_for_committee_members; + vector< votes_info_object > votes_for_witnesses; + vector< votes_info_object > votes_for_workers; + vector< votes_info_object > votes_against_workers; + vector< votes_info_object > votes_for_sons; + }; + +} } // graphene::chain + +FC_REFLECT_TEMPLATE( (typename IdType), graphene::chain::votes_info_object, + (vote_id) + (id) ) + +FC_REFLECT( graphene::chain::votes_info, + (votes_for_committee_members) + (votes_for_witnesses) + (votes_for_workers) + (votes_against_workers) + (votes_for_sons) ) \ No newline at end of file diff --git a/libraries/wallet/include/graphene/wallet/wallet.hpp b/libraries/wallet/include/graphene/wallet/wallet.hpp index ff32ac10..76d92f6b 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2487,9 +2487,32 @@ class wallet_api bool broadcast = false, bool to_temp = false ); - std::map> get_result_formatters() const; + /** + * @brief Get a list of vote_id_type that ID votes for + * @param account_name_or_id ID or name of the account to get votes for + * @return The list of vote_id_type ID votes for + * + */ + vector get_votes_ids(const string &account_name_or_id) const; + + /** + * @brief Return the objects account_name_or_id votes for + * @param account_name_or_id ID or name of the account to get votes for + * @return The votes_info account_name_or_id votes for + * + */ + votes_info get_votes(const string &account_name_or_id) const; + + /** + * @brief Get a list of accounts that votes for vote_id + * @param vote_id We search accounts that vote for this ID + * @return The accounts that votes for provided ID + * + */ + vector get_voters_by_id(const vote_id_type &vote_id) const; + fc::signal lock_changed; std::shared_ptr my; void encrypt_keys(); @@ -2795,4 +2818,7 @@ FC_API( graphene::wallet::wallet_api, (get_custom_account_authorities_by_permission_id) (get_custom_account_authorities_by_permission_name) (get_active_custom_account_authorities_by_operation) + (get_votes_ids) + (get_votes) + (get_voters_by_id) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index ae8b350e..0b7e99f7 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -4082,6 +4082,33 @@ public: return it->second; } + vector get_votes_ids(const string &account_name_or_id) const + { + try + { + return _remote_db->get_votes_ids(account_name_or_id); + } + FC_CAPTURE_AND_RETHROW( (account_name_or_id) ) + } + + votes_info get_votes(const string &account_name_or_id) const + { + try + { + return _remote_db->get_votes(account_name_or_id); + } + FC_CAPTURE_AND_RETHROW( (account_name_or_id) ) + } + + vector get_voters_by_id(const vote_id_type &vote_id) const + { + try + { + return _remote_db->get_voters_by_id(vote_id); + } + FC_CAPTURE_AND_RETHROW( (vote_id) ) + } + string _wallet_filename; wallet_data _wallet; @@ -7583,6 +7610,21 @@ std::vector wallet_api::get_all_matched_bets_for_bettor(acco return( my->_remote_bookie->get_all_matched_bets_for_bettor(bettor_id, start, limit) ); } +vector wallet_api::get_votes_ids(const string &account_name_or_id) const +{ + return my->get_votes_ids(account_name_or_id); +} + +votes_info wallet_api::get_votes(const string &account_name_or_id) const +{ + return my->get_votes(account_name_or_id); +} + +vector wallet_api::get_voters_by_id(const vote_id_type &vote_id) const +{ + return my->get_voters_by_id(vote_id); +} + // default ctor necessary for FC_REFLECT signed_block_with_info::signed_block_with_info( const signed_block& block ) : signed_block( block )