From 889265406a56af658eaebe034bca41aa88432109 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 09:15:34 +0300 Subject: [PATCH 1/9] #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 ) -- 2.45.2 From 2d237469a0f7e092d646dfc2126130aea43ebb64 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 14:23:06 +0300 Subject: [PATCH 2/9] #260 Add get_workers function --- libraries/app/database_api.cpp | 53 ++++++++++++++----- .../app/include/graphene/app/database_api.hpp | 20 +++++-- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 10a83060..2d0412b0 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -173,6 +173,10 @@ public: fc::optional get_sidechain_address_by_account_and_sidechain(account_id_type account, sidechain_type sidechain) const; uint64_t get_sidechain_addresses_count() const; + // Workers + vector> get_workers(const vector &witness_ids) const; + fc::optional get_worker_by_account(const std::string account_id_or_name) const; + // Votes vector lookup_vote_ids(const vector &votes) const; vector get_votes_ids(const string &account_name_or_id) const; @@ -1569,20 +1573,6 @@ vector> database_api::get_witnesses(const vectorget_witnesses(witness_ids); } -vector database_api::get_workers_by_account(const std::string account_id_or_name) const { - const auto &idx = my->_db.get_index_type().indices().get(); - const account_id_type account = my->get_account_from_string(account_id_or_name)->id; - auto itr = idx.find(account); - vector result; - - if (itr != idx.end() && itr->worker_account == account) { - result.emplace_back(*itr); - ++itr; - } - - return result; -} - vector> database_api_impl::get_witnesses(const vector &witness_ids) const { vector> result; result.reserve(witness_ids.size()); @@ -1892,6 +1882,41 @@ uint64_t database_api_impl::get_sidechain_addresses_count() const { return _db.get_index_type().indices().size(); } +////////////////////////////////////////////////////////////////////// +// // +// Workers // +// // +////////////////////////////////////////////////////////////////////// + +vector> database_api::get_workers(const vector &worker_ids) const { + return my->get_workers(worker_ids); +} + +fc::optional database_api::get_worker_by_account(const std::string account_id_or_name) const { + return my->get_worker_by_account(account_id_or_name); +} + +vector> database_api_impl::get_workers(const vector &worker_ids) const { + vector> result; + result.reserve(worker_ids.size()); + std::transform(worker_ids.begin(), worker_ids.end(), std::back_inserter(result), + [this](worker_id_type id) -> optional { + if (auto o = _db.find(id)) + return *o; + return {}; + }); + return result; +} + +fc::optional database_api_impl::get_worker_by_account(const std::string account_id_or_name) const { + const auto &idx = _db.get_index_type().indices().get(); + const account_id_type account = get_account_from_string(account_id_or_name)->id; + auto itr = idx.find(account); + if (itr != idx.end()) + return *itr; + return {}; +} + ////////////////////////////////////////////////////////////////////// // // // Votes // diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 5b507f8e..acbe2c8b 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -699,14 +699,25 @@ public: */ uint64_t get_sidechain_addresses_count() const; - /// WORKERS + ///////////// + // Workers // + ///////////// + + /** + * @brief Get a list of workers by ID + * @param worker_ids IDs of the workers to retrieve + * @return The workers corresponding to the provided IDs + * + * This function has semantics identical to @ref get_objects + */ + vector> get_workers(const vector &worker_ids) const; /** * @brief Return the worker objects associated with this account. * @param account_id_or_name The ID or name of the account whose worker should be retrieved * @return The worker object or null if the account does not have a worker */ - vector get_workers_by_account(const std::string account_id_or_name) const; + fc::optional get_worker_by_account(const std::string account_id_or_name) const; /////////// // Votes // @@ -1091,8 +1102,9 @@ FC_API(graphene::app::database_api, (get_sidechain_address_by_account_and_sidechain) (get_sidechain_addresses_count) - // workers - (get_workers_by_account) + // Workers + (get_workers) + (get_worker_by_account) // Votes (lookup_vote_ids) -- 2.45.2 From 0f3ea3d637f0c83805950641897cc776150d54c9 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 14:25:13 +0300 Subject: [PATCH 3/9] #260 get_son_by_account and get_son_by_account_id functions --- libraries/app/database_api.cpp | 18 ++++++++++++++---- .../app/include/graphene/app/database_api.hpp | 10 +++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 2d0412b0..0f30c6ff 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -157,7 +157,8 @@ public: // SON members vector> get_sons(const vector &son_ids) const; - fc::optional get_son_by_account(account_id_type account) const; + fc::optional get_son_by_account_id(account_id_type account) const; + fc::optional get_son_by_account(const std::string account_id_or_name) const; map lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const; uint64_t get_son_count() const; @@ -1719,11 +1720,11 @@ vector> database_api_impl::get_sons(const vector database_api::get_son_by_account(account_id_type account) const { - return my->get_son_by_account(account); +fc::optional database_api::get_son_by_account_id(account_id_type account) const { + return my->get_son_by_account_id(account); } -fc::optional database_api_impl::get_son_by_account(account_id_type account) const { +fc::optional database_api_impl::get_son_by_account_id(account_id_type account) const { const auto &idx = _db.get_index_type().indices().get(); auto itr = idx.find(account); if (itr != idx.end()) @@ -1731,6 +1732,15 @@ fc::optional database_api_impl::get_son_by_account(account_id_type a return {}; } +fc::optional database_api::get_son_by_account(const std::string account_id_or_name) const { + return my->get_son_by_account(account_id_or_name); +} + +fc::optional database_api_impl::get_son_by_account(const std::string account_id_or_name) const { + const account_id_type account = get_account_from_string(account_id_or_name)->id; + return get_son_by_account_id(account); +} + map database_api::lookup_son_accounts(const string &lower_bound_name, uint32_t limit) const { return my->lookup_son_accounts(lower_bound_name, limit); } diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index acbe2c8b..8e727d54 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -620,7 +620,14 @@ public: * @param account The ID of the account whose SON should be retrieved * @return The SON object, or null if the account does not have a SON */ - fc::optional get_son_by_account(account_id_type account) const; + fc::optional get_son_by_account_id(account_id_type account) const; + + /** + * @brief Get the SON owned by a given account + * @param account The ID of the account whose SON should be retrieved + * @return The SON object, or null if the account does not have a SON + */ + fc::optional get_son_by_account(const std::string account_id_or_name) const; /** * @brief Get names and IDs for registered SONs @@ -1086,6 +1093,7 @@ FC_API(graphene::app::database_api, // SON members (get_sons) + (get_son_by_account_id) (get_son_by_account) (lookup_son_accounts) (get_son_count) -- 2.45.2 From eb43bc3635d6332fab9f9c2f152f9dff3b2ba56b Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 14:27:43 +0300 Subject: [PATCH 4/9] #260 get_son_by_account_id instead of get_son_by_account in wallet_api --- libraries/wallet/wallet.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 0b7e99f7..0a9a9f21 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -1946,7 +1946,7 @@ public: try { account_id_type owner_account_id = get_account_id(owner_account); - fc::optional son = _remote_db->get_son_by_account(owner_account_id); + fc::optional son = _remote_db->get_son_by_account_id(owner_account_id); if (son) return *son; else @@ -2075,7 +2075,7 @@ public: son_create_op.pay_vb = pay_vb_id; son_create_op.sidechain_public_keys = sidechain_public_keys; - if (_remote_db->get_son_by_account(son_create_op.owner_account)) + if (_remote_db->get_son_by_account_id(son_create_op.owner_account)) FC_THROW("Account ${owner_account} is already a SON", ("owner_account", owner_account)); signed_transaction tx; @@ -2712,7 +2712,7 @@ public: account_object voting_account_object = get_account(voting_account); account_id_type son_account_id = get_account_id(son); - fc::optional son_obj = _remote_db->get_son_by_account(son_account_id); + fc::optional son_obj = _remote_db->get_son_by_account_id(son_account_id); if (!son_obj) FC_THROW("Account ${son} is not registered as a son", ("son", son)); if (approve) @@ -2756,7 +2756,7 @@ public: for (const std::string& son : sons_to_approve) { account_id_type son_owner_account_id = get_account_id(son); - fc::optional son_obj = _remote_db->get_son_by_account(son_owner_account_id); + fc::optional son_obj = _remote_db->get_son_by_account_id(son_owner_account_id); if (!son_obj) FC_THROW("Account ${son} is not registered as a SON", ("son", son)); auto insert_result = voting_account_object.options.votes.insert(son_obj->vote_id); @@ -2766,7 +2766,7 @@ public: for (const std::string& son : sons_to_reject) { account_id_type son_owner_account_id = get_account_id(son); - fc::optional son_obj = _remote_db->get_son_by_account(son_owner_account_id); + fc::optional son_obj = _remote_db->get_son_by_account_id(son_owner_account_id); if (!son_obj) FC_THROW("Account ${son} is not registered as a SON", ("son", son)); unsigned votes_removed = voting_account_object.options.votes.erase(son_obj->vote_id); -- 2.45.2 From cd737b57fe8efed4affe847e235340b213655bf1 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Fri, 4 Feb 2022 14:28:43 +0300 Subject: [PATCH 5/9] #260 Add get_voters function --- libraries/app/database_api.cpp | 183 ++++++++++++++++++ .../app/include/graphene/app/database_api.hpp | 23 ++- .../include/graphene/chain/voters_info.hpp | 40 ++++ .../wallet/include/graphene/wallet/wallet.hpp | 10 + libraries/wallet/wallet.cpp | 14 ++ 5 files changed, 261 insertions(+), 9 deletions(-) create mode 100644 libraries/chain/include/graphene/chain/voters_info.hpp diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 0f30c6ff..563228b3 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -52,6 +52,30 @@ template class fc::api; namespace graphene { namespace app { +template +optional maybe_id( const string& name_or_id ) +{ + if( std::isdigit( name_or_id.front() ) ) + { + try + { + return fc::variant(name_or_id, 1).as(1); + } + catch (const fc::exception&) + { // not an ID + } + } + return optional(); +} + +std::string object_id_to_string(object_id_type id) +{ + std::string object_id = fc::to_string(id.space()) + + "." + fc::to_string(id.type()) + + "." + fc::to_string(id.instance()); + return object_id; +} + class database_api_impl : public std::enable_shared_from_this { public: database_api_impl(graphene::chain::database &db); @@ -197,6 +221,7 @@ public: } votes_info get_votes(const string &account_name_or_id) const; vector get_voters_by_id(const vote_id_type &vote_id) const; + voters_info get_voters(const string &account_name_or_id) const; // Authority / validation std::string get_transaction_hex(const signed_transaction &trx) const; @@ -1949,6 +1974,10 @@ vector database_api::get_voters_by_id(const vote_id_type &vote_i return my->get_voters_by_id(vote_id); } +voters_info database_api::get_voters(const string &account_name_or_id) const { + return my->get_voters(account_name_or_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"); @@ -2082,6 +2111,160 @@ vector database_api_impl::get_voters_by_id(const vote_id_type &v return result; } +voters_info database_api_impl::get_voters(const string &account_name_or_id) const { + voters_info result; + + //! Find account name + bool owner_account_found = false; + std::string owner_account_id; + + //! Check if we have account by name + const auto& account_object = get_account_by_name(account_name_or_id); + if(account_object) { + //! It is account + owner_account_id = object_id_to_string( account_object->get_id() ); + owner_account_found = true; + } + else { + //! Check if we have account id + const auto& account_id = maybe_id(account_name_or_id); + if(account_id) { + //! It may be account id + const auto& account_objects = get_accounts({account_name_or_id}); + if(!account_objects.empty()){ + const auto& account_object = account_objects.front(); + if(account_object) { + //! It is account object + owner_account_id = object_id_to_string( account_object->get_id() ); + owner_account_found = true; + } + } + } + else { + //! Check if we have committee member id + const auto& committee_member_id = maybe_id(account_name_or_id); + if(committee_member_id) { + //! It may be committee member id + const auto& committee_member_objects = get_committee_members({*committee_member_id}); + if(!committee_member_objects.empty()){ + const auto& committee_member_object = committee_member_objects.front(); + if(committee_member_object) { + //! It is committee member object + owner_account_id = object_id_to_string( committee_member_object->committee_member_account ); + owner_account_found = true; + } + } + } + else { + //! Check if we have witness id + const auto& witness_id = maybe_id(account_name_or_id); + if(witness_id) { + //! It may be witness id + const auto& witness_objects = get_witnesses({*witness_id}); + if(!witness_objects.empty()){ + const auto& witness_object = witness_objects.front(); + if(witness_object) { + //! It is witness object + owner_account_id = object_id_to_string( witness_object->witness_account ); + owner_account_found = true; + } + } + } + else { + //! Check if we have worker id + const auto& worker_id = maybe_id(account_name_or_id); + if(worker_id) { + //! It may be worker id + const auto& worker_objects = get_workers({*worker_id}); + if(!worker_objects.empty()){ + const auto& worker_object = worker_objects.front(); + if(worker_object) { + //! It is worker object + owner_account_id = object_id_to_string( worker_object->worker_account ); + owner_account_found = true; + } + } + } + else { + //! Check if we have son id + const auto& son_id = maybe_id(account_name_or_id); + if(son_id) { + //! It may be son id + const auto& son_objects = get_sons({*son_id}); + if(!son_objects.empty()){ + const auto& son_object = son_objects.front(); + if(son_object) { + //! It is son object + owner_account_id = object_id_to_string( son_object->son_account ); + owner_account_found = true; + } + } + } + } + } + } + } + } + + //! We didn't find who it was + if(!owner_account_found) + FC_THROW_EXCEPTION(database_query_exception, "Wrong account_name_or_id: ${account_name_or_id}", ("account_name_or_id", account_name_or_id)); + + //! Fill voters_info + const auto& committee_member_object = get_committee_member_by_account(owner_account_id); + const auto& witness_object = get_witness_by_account(owner_account_id); + const auto& worker_object = get_worker_by_account(owner_account_id); + const auto& son_object = get_son_by_account(owner_account_id); + + //! Info for committee member voters + if(committee_member_object) { + const auto& committee_member_voters = get_voters_by_id(committee_member_object->vote_id); + result.voters_for_committee_member.vote_id = committee_member_object->vote_id; + result.voters_for_committee_member.voters.reserve(committee_member_voters.size()); + for(const auto& voter: committee_member_voters) { + result.voters_for_committee_member.voters.emplace_back(voter.get_id()); + } + } + + //! Info for witness voters + if(witness_object) { + const auto& witness_voters = get_voters_by_id(witness_object->vote_id); + result.voters_for_witness.vote_id = witness_object->vote_id; + result.voters_for_witness.voters.reserve(witness_voters.size()); + for(const auto& voter: witness_voters) { + result.voters_for_witness.voters.emplace_back(voter.get_id()); + } + } + + //! Info for worker voters + if(worker_object) { + const auto& for_worker_voters = get_voters_by_id(worker_object->vote_for); + result.voters_for_worker.vote_id = worker_object->vote_for; + result.voters_for_worker.voters.reserve(for_worker_voters.size()); + for(const auto& voter: for_worker_voters) { + result.voters_for_worker.voters.emplace_back(voter.get_id()); + } + const auto& against_worker_voters = get_voters_by_id(worker_object->vote_against); + result.voters_against_worker.vote_id = worker_object->vote_against; + result.voters_against_worker.voters.reserve(against_worker_voters.size()); + for(const auto& voter: against_worker_voters) { + result.voters_against_worker.voters.emplace_back(voter.get_id()); + } + } + + //! Info for son voters + if(son_object) { + const auto& son_voters = get_voters_by_id(son_object->vote_id); + result.voters_for_son.vote_id = son_object->vote_id; + result.voters_for_son.voters.reserve(son_voters.size()); + for(const auto& voter: son_voters) { + result.voters_for_son.voters.emplace_back(voter.get_id()); + } + } + + 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 8e727d54..836aa632 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -57,6 +57,7 @@ #include #include #include +#include #include @@ -741,7 +742,7 @@ public: vector lookup_vote_ids(const vector &votes) const; /** - * @brief Get a list that ID votes for + * @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 * @@ -749,20 +750,15 @@ public: 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. - * + * @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 set of votes ID 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 @@ -770,6 +766,14 @@ public: */ vector get_voters_by_id(const vote_id_type &vote_id) const; + /** + * @brief Return the accounts that votes for account_name_or_id + * @param account_name_or_id ID or name of the account to get voters for + * @return The voters_info for account_name_or_id + * + */ + voters_info get_voters(const string &account_name_or_id) const; + //////////////////////////// // Authority / validation // //////////////////////////// @@ -1119,6 +1123,7 @@ FC_API(graphene::app::database_api, (get_votes_ids) (get_votes) (get_voters_by_id) + (get_voters) // Authority / validation (get_transaction_hex) diff --git a/libraries/chain/include/graphene/chain/voters_info.hpp b/libraries/chain/include/graphene/chain/voters_info.hpp new file mode 100644 index 00000000..5bd09a11 --- /dev/null +++ b/libraries/chain/include/graphene/chain/voters_info.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace graphene { namespace chain { + + /** + * @class voters_info_object + * @ingroup object + */ + struct voters_info_object { + vote_id_type vote_id; + vector voters; + }; + + /** + * @class voters_info + * @brief tracks information about a voters info + * @ingroup object + */ + struct voters_info { + voters_info_object voters_for_committee_member; + voters_info_object voters_for_witness; + voters_info_object voters_for_worker; + voters_info_object voters_against_worker; + voters_info_object voters_for_son; + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::voters_info_object, + (vote_id) + (voters) ) + +FC_REFLECT( graphene::chain::voters_info, + (voters_for_committee_member) + (voters_for_witness) + (voters_for_worker) + (voters_against_worker) + (voters_for_son) ) \ 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 76d92f6b..4df3dea6 100644 --- a/libraries/wallet/include/graphene/wallet/wallet.hpp +++ b/libraries/wallet/include/graphene/wallet/wallet.hpp @@ -2513,6 +2513,15 @@ class wallet_api */ vector get_voters_by_id(const vote_id_type &vote_id) const; + /** + * @brief Return the accounts that votes for account_name_or_id + * @param account_name_or_id ID or name of the account to get voters for + * @return The voters_info for account_name_or_id + * + */ + voters_info get_voters(const string &account_name_or_id) const; + + fc::signal lock_changed; std::shared_ptr my; void encrypt_keys(); @@ -2821,4 +2830,5 @@ FC_API( graphene::wallet::wallet_api, (get_votes_ids) (get_votes) (get_voters_by_id) + (get_voters) ) diff --git a/libraries/wallet/wallet.cpp b/libraries/wallet/wallet.cpp index 0a9a9f21..0d865c78 100644 --- a/libraries/wallet/wallet.cpp +++ b/libraries/wallet/wallet.cpp @@ -4109,6 +4109,15 @@ public: FC_CAPTURE_AND_RETHROW( (vote_id) ) } + voters_info get_voters(const string &account_name_or_id) const + { + try + { + return _remote_db->get_voters(account_name_or_id); + } + FC_CAPTURE_AND_RETHROW( (account_name_or_id) ) + } + string _wallet_filename; wallet_data _wallet; @@ -7625,6 +7634,11 @@ vector wallet_api::get_voters_by_id(const vote_id_type &vote_id) return my->get_voters_by_id(vote_id); } +voters_info wallet_api::get_voters(const string &account_name_or_id) const +{ + return my->get_voters(account_name_or_id); +} + // default ctor necessary for FC_REFLECT signed_block_with_info::signed_block_with_info( const signed_block& block ) : signed_block( block ) -- 2.45.2 From 6bcea17f28a660cd9655b7583e1584a85447f73d Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Mon, 7 Feb 2022 09:30:37 +0300 Subject: [PATCH 6/9] #260 Add unit test for functions: get_votes() and get_voters() --- tests/cli/son.cpp | 36 ++++++++++++++++++++++++++++++++++++ tests/tests/voting_tests.cpp | 19 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 1996c267..b6cf2644 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -244,6 +244,25 @@ BOOST_AUTO_TEST_CASE( son_voting ) son2_end_votes = son2_obj.total_votes; BOOST_CHECK(son2_end_votes > son2_start_votes); + //! Get nathan account + const auto nathan_account_object = con.wallet_api_ptr->get_account("nathan"); + + //! Check son1account voters + auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); + BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son.voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account.voters_for_son.voters[0].instance, nathan_account_object.id.instance()); + + //! Check son2account voters + auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); + BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son.voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account.voters_for_son.voters[0].instance, nathan_account_object.id.instance()); + + //! Check votes of nathan + auto nathan_votes = con.wallet_api_ptr->get_votes("nathan"); + BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 2); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[0].id.instance, son1_obj.id.instance()); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[1].id.instance, son2_obj.id.instance()); + // Withdraw vote for a son1account BOOST_TEST_MESSAGE("Withdraw vote for a son1account"); vote_son1_tx = con.wallet_api_ptr->vote_for_son("nathan", "son1account", false, true); @@ -254,6 +273,15 @@ BOOST_AUTO_TEST_CASE( son_voting ) son1_end_votes = son1_obj.total_votes; BOOST_CHECK(son1_end_votes == son1_start_votes); + //! Check son1account voters + voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); + BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son.voters.size(), 0); + + //! Check votes of nathan + nathan_votes = con.wallet_api_ptr->get_votes("nathan"); + BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[0].id.instance, son2_obj.id.instance()); + // Withdraw vote for a son2account BOOST_TEST_MESSAGE("Withdraw vote for a son2account"); vote_son2_tx = con.wallet_api_ptr->vote_for_son("nathan", "son2account", false, true); @@ -264,6 +292,14 @@ BOOST_AUTO_TEST_CASE( son_voting ) son2_end_votes = son2_obj.total_votes; BOOST_CHECK(son2_end_votes == son2_start_votes); + //! Check son2account voters + voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); + BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son.voters.size(), 0); + + //! Check votes of nathan + nathan_votes = con.wallet_api_ptr->get_votes("nathan"); + BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 0); + } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); edump((e.to_detail_string())); diff --git a/tests/tests/voting_tests.cpp b/tests/tests/voting_tests.cpp index a6f41675..7ed8e2a9 100644 --- a/tests/tests/voting_tests.cpp +++ b/tests/tests/voting_tests.cpp @@ -322,6 +322,16 @@ BOOST_AUTO_TEST_CASE(track_votes_witnesses_enabled) auto witness1_object = db_api1.get_witness_by_account(witness1_id(db).name); BOOST_CHECK_EQUAL(witness1_object->total_votes, 111); + //! Check witness1 voters + const auto voters_for_witness1 = db_api1.get_voters("witness1"); + BOOST_CHECK_EQUAL(voters_for_witness1.voters_for_witness.voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_witness1.voters_for_witness.voters[0].instance, 18); + + //! Check votes of account + const auto account_votes = db_api1.get_votes("1.2.18"); + BOOST_CHECK_EQUAL(account_votes.votes_for_witnesses.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_witnesses[0].id.instance, witness1_object->id.instance()); + } FC_LOG_AND_RETHROW() } @@ -501,6 +511,15 @@ BOOST_AUTO_TEST_CASE(track_votes_committee_enabled) auto committee1_object = db_api1.get_committee_member_by_account(committee1_id(db).name); BOOST_CHECK_EQUAL(committee1_object->total_votes, 111); + //! Check committee1 voters + const auto voters_for_committee1 = db_api1.get_voters("committee1"); + BOOST_CHECK_EQUAL(voters_for_committee1.voters_for_committee_member.voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_committee1.voters_for_committee_member.voters[0].instance, 18); + + //! Check votes of account + const auto account_votes = db_api1.get_votes("1.2.18"); + BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_committee_members.back().id.instance, committee1_object->id.instance()); + } FC_LOG_AND_RETHROW() } -- 2.45.2 From 9c7c3d2e14ef183b2c261c9ac52fc2d837394f88 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 8 Feb 2022 09:38:17 +0300 Subject: [PATCH 7/9] #260 fix get_workers_by_account() --- libraries/app/database_api.cpp | 46 ++++++++++++------- .../app/include/graphene/app/database_api.hpp | 4 +- .../include/graphene/chain/voters_info.hpp | 14 +++--- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 563228b3..682c7b97 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -200,7 +200,7 @@ public: // Workers vector> get_workers(const vector &witness_ids) const; - fc::optional get_worker_by_account(const std::string account_id_or_name) const; + vector get_workers_by_account(const std::string account_id_or_name) const; // Votes vector lookup_vote_ids(const vector &votes) const; @@ -1927,8 +1927,8 @@ vector> database_api::get_workers(const vectorget_workers(worker_ids); } -fc::optional database_api::get_worker_by_account(const std::string account_id_or_name) const { - return my->get_worker_by_account(account_id_or_name); +vector database_api::get_workers_by_account(const std::string account_id_or_name) const { + return my->get_workers_by_account(account_id_or_name); } vector> database_api_impl::get_workers(const vector &worker_ids) const { @@ -1943,13 +1943,18 @@ vector> database_api_impl::get_workers(const vector database_api_impl::get_worker_by_account(const std::string account_id_or_name) const { +vector database_api_impl::get_workers_by_account(const std::string account_id_or_name) const { const auto &idx = _db.get_index_type().indices().get(); const account_id_type account = get_account_from_string(account_id_or_name)->id; auto itr = idx.find(account); - if (itr != idx.end()) - return *itr; - return {}; + vector result; + + if (itr != idx.end() && itr->worker_account == account) { + result.emplace_back(*itr); + ++itr; + } + + return result; } ////////////////////////////////////////////////////////////////////// @@ -2213,7 +2218,7 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons //! Fill voters_info const auto& committee_member_object = get_committee_member_by_account(owner_account_id); const auto& witness_object = get_witness_by_account(owner_account_id); - const auto& worker_object = get_worker_by_account(owner_account_id); + const auto& worker_objects = get_workers_by_account(owner_account_id); const auto& son_object = get_son_by_account(owner_account_id); //! Info for committee member voters @@ -2237,19 +2242,26 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons } //! Info for worker voters - if(worker_object) { - const auto& for_worker_voters = get_voters_by_id(worker_object->vote_for); - result.voters_for_worker.vote_id = worker_object->vote_for; - result.voters_for_worker.voters.reserve(for_worker_voters.size()); + result.voters_for_workers.reserve(worker_objects.size()); + result.voters_against_workers.reserve(worker_objects.size()); + for(const auto& worker_object : worker_objects) { + voters_info_object voters_for_worker; + const auto& for_worker_voters = get_voters_by_id(worker_object.vote_for); + voters_for_worker.vote_id = worker_object.vote_for; + voters_for_worker.voters.reserve(for_worker_voters.size()); for(const auto& voter: for_worker_voters) { - result.voters_for_worker.voters.emplace_back(voter.get_id()); + voters_for_worker.voters.emplace_back(voter.get_id()); } - const auto& against_worker_voters = get_voters_by_id(worker_object->vote_against); - result.voters_against_worker.vote_id = worker_object->vote_against; - result.voters_against_worker.voters.reserve(against_worker_voters.size()); + result.voters_for_workers.emplace_back(std::move(voters_for_worker)); + + voters_info_object voters_against_worker; + const auto& against_worker_voters = get_voters_by_id(worker_object.vote_against); + voters_against_worker.vote_id = worker_object.vote_against; + voters_against_worker.voters.reserve(against_worker_voters.size()); for(const auto& voter: against_worker_voters) { - result.voters_against_worker.voters.emplace_back(voter.get_id()); + voters_against_worker.voters.emplace_back(voter.get_id()); } + result.voters_against_workers.emplace_back(std::move(voters_against_worker)); } //! Info for son voters diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 836aa632..0c9d10f2 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -725,7 +725,7 @@ public: * @param account_id_or_name The ID or name of the account whose worker should be retrieved * @return The worker object or null if the account does not have a worker */ - fc::optional get_worker_by_account(const std::string account_id_or_name) const; + vector get_workers_by_account(const std::string account_id_or_name) const; /////////// // Votes // @@ -1116,7 +1116,7 @@ FC_API(graphene::app::database_api, // Workers (get_workers) - (get_worker_by_account) + (get_workers_by_account) // Votes (lookup_vote_ids) diff --git a/libraries/chain/include/graphene/chain/voters_info.hpp b/libraries/chain/include/graphene/chain/voters_info.hpp index 5bd09a11..4225732e 100644 --- a/libraries/chain/include/graphene/chain/voters_info.hpp +++ b/libraries/chain/include/graphene/chain/voters_info.hpp @@ -19,11 +19,11 @@ namespace graphene { namespace chain { * @ingroup object */ struct voters_info { - voters_info_object voters_for_committee_member; - voters_info_object voters_for_witness; - voters_info_object voters_for_worker; - voters_info_object voters_against_worker; - voters_info_object voters_for_son; + voters_info_object voters_for_committee_member; + voters_info_object voters_for_witness; + vector voters_for_workers; + vector voters_against_workers; + voters_info_object voters_for_son; }; } } // graphene::chain @@ -35,6 +35,6 @@ FC_REFLECT( graphene::chain::voters_info_object, FC_REFLECT( graphene::chain::voters_info, (voters_for_committee_member) (voters_for_witness) - (voters_for_worker) - (voters_against_worker) + (voters_for_workers) + (voters_against_workers) (voters_for_son) ) \ No newline at end of file -- 2.45.2 From 558e3c004596ffadc0b58f7dbabd8dde36a7cd4c Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 8 Feb 2022 10:19:49 +0300 Subject: [PATCH 8/9] #260 voters_info all members as optional --- libraries/app/database_api.cpp | 64 +++++++++++-------- .../include/graphene/chain/voters_info.hpp | 10 +-- tests/cli/son.cpp | 16 +++-- tests/tests/voting_tests.cpp | 10 +-- 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 682c7b97..57d9372e 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2224,54 +2224,64 @@ voters_info database_api_impl::get_voters(const string &account_name_or_id) cons //! Info for committee member voters if(committee_member_object) { const auto& committee_member_voters = get_voters_by_id(committee_member_object->vote_id); - result.voters_for_committee_member.vote_id = committee_member_object->vote_id; - result.voters_for_committee_member.voters.reserve(committee_member_voters.size()); + voters_info_object voters_for_committee_member; + voters_for_committee_member.vote_id = committee_member_object->vote_id; + voters_for_committee_member.voters.reserve(committee_member_voters.size()); for(const auto& voter: committee_member_voters) { - result.voters_for_committee_member.voters.emplace_back(voter.get_id()); + voters_for_committee_member.voters.emplace_back(voter.get_id()); } + result.voters_for_committee_member = std::move(voters_for_committee_member); } //! Info for witness voters if(witness_object) { const auto& witness_voters = get_voters_by_id(witness_object->vote_id); - result.voters_for_witness.vote_id = witness_object->vote_id; - result.voters_for_witness.voters.reserve(witness_voters.size()); + voters_info_object voters_for_witness; + voters_for_witness.vote_id = witness_object->vote_id; + voters_for_witness.voters.reserve(witness_voters.size()); for(const auto& voter: witness_voters) { - result.voters_for_witness.voters.emplace_back(voter.get_id()); + voters_for_witness.voters.emplace_back(voter.get_id()); } + result.voters_for_witness = std::move(voters_for_witness); } //! Info for worker voters - result.voters_for_workers.reserve(worker_objects.size()); - result.voters_against_workers.reserve(worker_objects.size()); - for(const auto& worker_object : worker_objects) { - voters_info_object voters_for_worker; - const auto& for_worker_voters = get_voters_by_id(worker_object.vote_for); - voters_for_worker.vote_id = worker_object.vote_for; - voters_for_worker.voters.reserve(for_worker_voters.size()); - for(const auto& voter: for_worker_voters) { - voters_for_worker.voters.emplace_back(voter.get_id()); - } - result.voters_for_workers.emplace_back(std::move(voters_for_worker)); + if(!worker_objects.empty()) { + vector voters_for_workers(worker_objects.size()); + vector voters_against_workers(worker_objects.size()); + for (const auto &worker_object : worker_objects) { + voters_info_object voters_for_worker; + const auto &for_worker_voters = get_voters_by_id(worker_object.vote_for); + voters_for_worker.vote_id = worker_object.vote_for; + voters_for_worker.voters.reserve(for_worker_voters.size()); + for (const auto &voter : for_worker_voters) { + voters_for_worker.voters.emplace_back(voter.get_id()); + } + voters_for_workers.emplace_back(std::move(voters_for_worker)); - voters_info_object voters_against_worker; - const auto& against_worker_voters = get_voters_by_id(worker_object.vote_against); - voters_against_worker.vote_id = worker_object.vote_against; - voters_against_worker.voters.reserve(against_worker_voters.size()); - for(const auto& voter: against_worker_voters) { - voters_against_worker.voters.emplace_back(voter.get_id()); + voters_info_object voters_against_worker; + const auto &against_worker_voters = get_voters_by_id(worker_object.vote_against); + voters_against_worker.vote_id = worker_object.vote_against; + voters_against_worker.voters.reserve(against_worker_voters.size()); + for (const auto &voter : against_worker_voters) { + voters_against_worker.voters.emplace_back(voter.get_id()); + } + voters_against_workers.emplace_back(std::move(voters_against_worker)); } - result.voters_against_workers.emplace_back(std::move(voters_against_worker)); + result.voters_for_workers = std::move(voters_for_workers); + result.voters_against_workers = std::move(voters_against_workers); } //! Info for son voters if(son_object) { const auto& son_voters = get_voters_by_id(son_object->vote_id); - result.voters_for_son.vote_id = son_object->vote_id; - result.voters_for_son.voters.reserve(son_voters.size()); + voters_info_object voters_for_son; + voters_for_son.vote_id = son_object->vote_id; + voters_for_son.voters.reserve(son_voters.size()); for(const auto& voter: son_voters) { - result.voters_for_son.voters.emplace_back(voter.get_id()); + voters_for_son.voters.emplace_back(voter.get_id()); } + result.voters_for_son = std::move(voters_for_son); } return result; diff --git a/libraries/chain/include/graphene/chain/voters_info.hpp b/libraries/chain/include/graphene/chain/voters_info.hpp index 4225732e..53b0e74a 100644 --- a/libraries/chain/include/graphene/chain/voters_info.hpp +++ b/libraries/chain/include/graphene/chain/voters_info.hpp @@ -19,11 +19,11 @@ namespace graphene { namespace chain { * @ingroup object */ struct voters_info { - voters_info_object voters_for_committee_member; - voters_info_object voters_for_witness; - vector voters_for_workers; - vector voters_against_workers; - voters_info_object voters_for_son; + optional voters_for_committee_member; + optional voters_for_witness; + optional > voters_for_workers; + optional > voters_against_workers; + optional voters_for_son; }; } } // graphene::chain diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index b6cf2644..41ef89a5 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -249,13 +249,15 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check son1account voters auto voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); - BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son.voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account.voters_for_son.voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE(voters_for_son1account.voters_for_son); + BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son1account.voters_for_son->voters[0].instance, nathan_account_object.id.instance()); //! Check son2account voters auto voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); - BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son.voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account.voters_for_son.voters[0].instance, nathan_account_object.id.instance()); + BOOST_REQUIRE(voters_for_son2account.voters_for_son); + BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_son2account.voters_for_son->voters[0].instance, nathan_account_object.id.instance()); //! Check votes of nathan auto nathan_votes = con.wallet_api_ptr->get_votes("nathan"); @@ -275,7 +277,8 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check son1account voters voters_for_son1account = con.wallet_api_ptr->get_voters("son1account"); - BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son.voters.size(), 0); + BOOST_REQUIRE(voters_for_son1account.voters_for_son); + BOOST_CHECK_EQUAL(voters_for_son1account.voters_for_son->voters.size(), 0); //! Check votes of nathan nathan_votes = con.wallet_api_ptr->get_votes("nathan"); @@ -294,7 +297,8 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check son2account voters voters_for_son2account = con.wallet_api_ptr->get_voters("son2account"); - BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son.voters.size(), 0); + BOOST_REQUIRE(voters_for_son2account.voters_for_son); + BOOST_CHECK_EQUAL(voters_for_son2account.voters_for_son->voters.size(), 0); //! Check votes of nathan nathan_votes = con.wallet_api_ptr->get_votes("nathan"); diff --git a/tests/tests/voting_tests.cpp b/tests/tests/voting_tests.cpp index 7ed8e2a9..0a33e6ba 100644 --- a/tests/tests/voting_tests.cpp +++ b/tests/tests/voting_tests.cpp @@ -324,8 +324,9 @@ BOOST_AUTO_TEST_CASE(track_votes_witnesses_enabled) //! Check witness1 voters const auto voters_for_witness1 = db_api1.get_voters("witness1"); - BOOST_CHECK_EQUAL(voters_for_witness1.voters_for_witness.voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_witness1.voters_for_witness.voters[0].instance, 18); + BOOST_REQUIRE(voters_for_witness1.voters_for_witness); + BOOST_CHECK_EQUAL(voters_for_witness1.voters_for_witness->voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_witness1.voters_for_witness->voters[0].instance, 18); //! Check votes of account const auto account_votes = db_api1.get_votes("1.2.18"); @@ -513,8 +514,9 @@ BOOST_AUTO_TEST_CASE(track_votes_committee_enabled) //! Check committee1 voters const auto voters_for_committee1 = db_api1.get_voters("committee1"); - BOOST_CHECK_EQUAL(voters_for_committee1.voters_for_committee_member.voters.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)voters_for_committee1.voters_for_committee_member.voters[0].instance, 18); + BOOST_REQUIRE(voters_for_committee1.voters_for_committee_member); + BOOST_CHECK_EQUAL(voters_for_committee1.voters_for_committee_member->voters.size(), 1); + BOOST_CHECK_EQUAL((uint32_t)voters_for_committee1.voters_for_committee_member->voters[0].instance, 18); //! Check votes of account const auto account_votes = db_api1.get_votes("1.2.18"); -- 2.45.2 From 504680f727fc4d7dbfbe91b9589f14419370ca58 Mon Sep 17 00:00:00 2001 From: Vlad Dobromyslov Date: Tue, 8 Feb 2022 11:03:36 +0300 Subject: [PATCH 9/9] #260 votes_info all members as optional --- libraries/app/database_api.cpp | 69 ++++++++++++------- .../include/graphene/chain/votes_info.hpp | 10 +-- tests/cli/son.cpp | 14 ++-- tests/tests/voting_tests.cpp | 8 ++- 4 files changed, 62 insertions(+), 39 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index 57d9372e..632f74b9 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -2068,35 +2068,54 @@ votes_info database_api_impl::get_votes(const string &account_name_or_id) const 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() } ); + if(!committee_ids.empty()) { + vector< votes_info_object > votes_for_committee_members; + votes_for_committee_members.reserve(committee_ids.size()); + for (const auto &committee : committee_ids) { + const auto &committee_obj = committee.as(2); + votes_for_committee_members.emplace_back(votes_info_object{committee_obj.vote_id, committee_obj.id.instance()}); + } + result.votes_for_committee_members = std::move(votes_for_committee_members); } - 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() } ); + + if(!witness_ids.empty()) { + vector< votes_info_object > votes_for_witnesses; + votes_for_witnesses.reserve(witness_ids.size()); + for (const auto &witness : witness_ids) { + const auto &witness_obj = witness.as(2); + votes_for_witnesses.emplace_back(votes_info_object{witness_obj.vote_id, witness_obj.id.instance()}); + } + result.votes_for_witnesses = std::move(votes_for_witnesses); } - 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() } ); + + if(!for_worker_ids.empty()) { + vector< votes_info_object > votes_for_workers; + 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); + votes_for_workers.emplace_back(votes_info_object{for_worker_obj.vote_for, for_worker_obj.id.instance()}); + } + result.votes_for_workers = std::move(votes_for_workers); } - 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() } ); + + if(!against_worker_ids.empty()) { + vector< votes_info_object > votes_against_workers; + 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); + votes_against_workers.emplace_back(votes_info_object{against_worker_obj.vote_against, against_worker_obj.id.instance()}); + } + result.votes_against_workers = std::move(votes_against_workers); } - 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() } ); + + if(!son_ids.empty()) { + vector< votes_info_object > votes_for_sons; + votes_for_sons.reserve(son_ids.size()); + for (const auto &son : son_ids) { + const auto &son_obj = son.as(6); + votes_for_sons.emplace_back(votes_info_object{son_obj.vote_id, son_obj.id.instance()}); + } + result.votes_for_sons = std::move(votes_for_sons); } return result; diff --git a/libraries/chain/include/graphene/chain/votes_info.hpp b/libraries/chain/include/graphene/chain/votes_info.hpp index bb757f90..b802a020 100644 --- a/libraries/chain/include/graphene/chain/votes_info.hpp +++ b/libraries/chain/include/graphene/chain/votes_info.hpp @@ -27,11 +27,11 @@ namespace graphene { namespace chain { * @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; + optional< vector< votes_info_object > > votes_for_committee_members; + optional< vector< votes_info_object > > votes_for_witnesses; + optional< vector< votes_info_object > > votes_for_workers; + optional< vector< votes_info_object > > votes_against_workers; + optional< vector< votes_info_object > > votes_for_sons; }; } } // graphene::chain diff --git a/tests/cli/son.cpp b/tests/cli/son.cpp index 41ef89a5..b2dba7b4 100644 --- a/tests/cli/son.cpp +++ b/tests/cli/son.cpp @@ -261,9 +261,10 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check votes of nathan auto nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 2); - BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[0].id.instance, son1_obj.id.instance()); - BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[1].id.instance, son2_obj.id.instance()); + BOOST_REQUIRE(nathan_votes.votes_for_sons); + BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 2); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons->at(0).id.instance, son1_obj.id.instance()); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons->at(1).id.instance, son2_obj.id.instance()); // Withdraw vote for a son1account BOOST_TEST_MESSAGE("Withdraw vote for a son1account"); @@ -282,8 +283,9 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check votes of nathan nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons[0].id.instance, son2_obj.id.instance()); + BOOST_REQUIRE(nathan_votes.votes_for_sons); + BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons->size(), 1); + BOOST_CHECK_EQUAL((uint32_t)nathan_votes.votes_for_sons->at(0).id.instance, son2_obj.id.instance()); // Withdraw vote for a son2account BOOST_TEST_MESSAGE("Withdraw vote for a son2account"); @@ -302,7 +304,7 @@ BOOST_AUTO_TEST_CASE( son_voting ) //! Check votes of nathan nathan_votes = con.wallet_api_ptr->get_votes("nathan"); - BOOST_CHECK_EQUAL(nathan_votes.votes_for_sons.size(), 0); + BOOST_CHECK(!nathan_votes.votes_for_sons.valid()); } catch( fc::exception& e ) { BOOST_TEST_MESSAGE("SON cli wallet tests exception"); diff --git a/tests/tests/voting_tests.cpp b/tests/tests/voting_tests.cpp index 0a33e6ba..2003534a 100644 --- a/tests/tests/voting_tests.cpp +++ b/tests/tests/voting_tests.cpp @@ -330,8 +330,9 @@ BOOST_AUTO_TEST_CASE(track_votes_witnesses_enabled) //! Check votes of account const auto account_votes = db_api1.get_votes("1.2.18"); - BOOST_CHECK_EQUAL(account_votes.votes_for_witnesses.size(), 1); - BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_witnesses[0].id.instance, witness1_object->id.instance()); + BOOST_REQUIRE(account_votes.votes_for_witnesses); + BOOST_CHECK_EQUAL(account_votes.votes_for_witnesses->size(), 1); + BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_witnesses->at(0).id.instance, witness1_object->id.instance()); } FC_LOG_AND_RETHROW() } @@ -520,7 +521,8 @@ BOOST_AUTO_TEST_CASE(track_votes_committee_enabled) //! Check votes of account const auto account_votes = db_api1.get_votes("1.2.18"); - BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_committee_members.back().id.instance, committee1_object->id.instance()); + BOOST_REQUIRE(account_votes.votes_for_committee_members); + BOOST_CHECK_EQUAL((uint32_t)account_votes.votes_for_committee_members->back().id.instance, committee1_object->id.instance()); } FC_LOG_AND_RETHROW() } -- 2.45.2