From 3eaec849eb6fce46c80cbae087a719cadff6efe2 Mon Sep 17 00:00:00 2001 From: Nathan Hourt Date: Mon, 22 Jun 2015 15:03:18 -0400 Subject: [PATCH] Progress #61: Getting witnesses/delegates by owner Support and API are now present for retrieving witnesses and delegates by their owners. --- libraries/app/api.cpp | 24 +++++++++++++--- libraries/app/application.cpp | 10 +++---- libraries/app/include/graphene/app/api.hpp | 18 ++++++++++++ libraries/chain/db_block.cpp | 28 ++++--------------- libraries/chain/db_init.cpp | 18 ++++++------ libraries/chain/db_maint.cpp | 21 +++++++------- .../chain/include/graphene/chain/database.hpp | 4 +-- .../graphene/chain/delegate_object.hpp | 16 ++++++++++- .../include/graphene/chain/witness_object.hpp | 15 +++++++++- tests/common/database_fixture.cpp | 2 +- tests/tests/block_tests.cpp | 12 ++++---- 11 files changed, 107 insertions(+), 61 deletions(-) diff --git a/libraries/app/api.cpp b/libraries/app/api.cpp index 241678b3..bb1e725f 100644 --- a/libraries/app/api.cpp +++ b/libraries/app/api.cpp @@ -17,10 +17,8 @@ */ #include #include -#include #include #include -#include #include @@ -167,7 +165,7 @@ namespace graphene { namespace app { else { result.reserve(assets.size()); - + std::transform(assets.begin(), assets.end(), std::back_inserter(result), [this, acnt](asset_id_type id) { return _db.get_balance(acnt, id); }); } @@ -242,7 +240,7 @@ namespace graphene { namespace app { auto itr = assets_by_symbol.lower_bound(lower_bound_symbol); - if( lower_bound_symbol == "" ) + if( lower_bound_symbol == "" ) itr = assets_by_symbol.begin(); while(limit-- && itr != assets_by_symbol.end()) @@ -251,6 +249,24 @@ namespace graphene { namespace app { return result; } + fc::optional database_api::get_delegate_by_account(account_id_type account) const + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; + } + + fc::optional database_api::get_witness_by_account(account_id_type account) const + { + const auto& idx = _db.get_index_type().indices().get(); + auto itr = idx.find(account); + if( itr != idx.end() ) + return *itr; + return {}; + } + login_api::login_api(application& a) :_app(a) { diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 6deec129..f9711780 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -153,14 +153,14 @@ namespace detail { secret_hash_type::encoder enc; fc::raw::pack(enc, nathan_key); fc::raw::pack(enc, secret_hash_type()); + auto secret = secret_hash_type::hash(enc.result()); for( int i = 0; i < 10; ++i ) { - initial_state.allocation_targets.emplace_back("init"+fc::to_string(i), nathan_key.get_public_key(), 0, true); - initial_state.initial_committee.push_back({"init"+fc::to_string(i)}); + auto name = "init"+fc::to_string(i); + initial_state.allocation_targets.emplace_back(name, nathan_key.get_public_key(), 0, true); + initial_state.initial_committee.push_back({name}); + initial_state.initial_witnesses.push_back({name, nathan_key.get_public_key(), secret}); } - initial_state.initial_witnesses = vector(10, {"committee-account", - nathan_key.get_public_key(), - secret_hash_type::hash(enc.result())}); initial_state.allocation_targets.emplace_back("nathan", address(public_key_type(nathan_key.get_public_key())), 1); if( _options->count("genesis-json") ) diff --git a/libraries/app/include/graphene/app/api.hpp b/libraries/app/include/graphene/app/api.hpp index e4729c3d..e1b2e3c9 100644 --- a/libraries/app/include/graphene/app/api.hpp +++ b/libraries/app/include/graphene/app/api.hpp @@ -24,7 +24,10 @@ #include #include #include +#include +#include #include + #include namespace graphene { namespace app { @@ -165,6 +168,19 @@ namespace graphene { namespace app { */ vector list_assets(const string& lower_bound_symbol, uint32_t limit)const; + /** + * @brief Get the delegate owned by a given account + * @param account The ID of the account whose delegate should be retrieved + * @return The delegate object, or null if the account does not have a delegate + */ + fc::optional get_delegate_by_account(account_id_type account)const; + /** + * @brief Get the witness owned by a given account + * @param account The ID of the account whose witness should be retrieved + * @return The witness object, or null if the account does not have a witness + */ + fc::optional get_witness_by_account(account_id_type account)const; + /** * @group Push Notification Methods * These methods may be used to get push notifications whenever an object or market is changed @@ -338,6 +354,8 @@ FC_API(graphene::app::database_api, (get_call_orders) (get_settle_orders) (list_assets) + (get_delegate_by_account) + (get_witness_by_account) (subscribe_to_objects) (unsubscribe_from_objects) (subscribe_to_market) diff --git a/libraries/chain/db_block.cpp b/libraries/chain/db_block.cpp index bd5a6bb6..f1a483ba 100644 --- a/libraries/chain/db_block.cpp +++ b/libraries/chain/db_block.cpp @@ -80,7 +80,7 @@ const signed_transaction& database::get_recent_transaction(const transaction_id_ * * @return true if we switched forks as a result of this push. */ -bool database::push_block( const signed_block& new_block, uint32_t skip ) +bool database::push_block(const signed_block& new_block, uint32_t skip) { bool result; with_skip_flags( skip, [&]() @@ -90,29 +90,20 @@ bool database::push_block( const signed_block& new_block, uint32_t skip ) return result; } -bool database::_push_block( const signed_block& new_block ) +bool database::_push_block(const signed_block& new_block) { try { uint32_t skip = get_node_properties().skip_flags; if( !(skip&skip_fork_db) ) { - auto new_head = _fork_db.push_block( new_block ); + auto new_head = _fork_db.push_block(new_block); //If the head block from the longest chain does not build off of the current head, we need to switch forks. if( new_head->data.previous != head_block_id() ) { - //edump((new_head->data.previous)); //If the newly pushed block is the same height as head, we get head back in new_head //Only switch forks if new_head is actually higher than head if( new_head->data.block_num() > head_block_num() ) { - auto branches = _fork_db.fetch_branch_from( new_head->data.id(), _pending_block.previous ); - for( auto item : branches.first ) - { - // wdump( ("new")(item->id)(item->data.previous) ); - } - for( auto item : branches.second ) - { - // wdump( ("old")(item->id)(item->data.previous) ); - } + auto branches = _fork_db.fetch_branch_from(new_head->data.id(), _pending_block.previous); // pop blocks until we hit the forked block while( head_block_id() != branches.second.back()->data.previous ) @@ -131,9 +122,6 @@ bool database::_push_block( const signed_block& new_block ) catch ( const fc::exception& e ) { except = e; } if( except ) { - //wdump((except->to_detail_string())); - // elog( "Encountered error when switching to a longer fork at id ${id}. Going back.", - // ("id", (*ritr)->id) ); // remove the rest of branches.first from the fork_db, those blocks are invalid while( ritr != branches.first.rend() ) { @@ -170,8 +158,8 @@ bool database::_push_block( const signed_block& new_block ) try { auto session = _undo_db.start_undo_session(); - apply_block( new_block, skip ); - _block_id_to_block.store( new_block.id(), new_block ); + apply_block(new_block, skip); + _block_id_to_block.store(new_block.id(), new_block); session.commit(); } catch ( const fc::exception& e ) { elog("Failed to push new block:\n${e}", ("e", e.to_detail_string())); @@ -204,7 +192,6 @@ processed_transaction database::push_transaction( const signed_transaction& trx, processed_transaction database::_push_transaction( const signed_transaction& trx ) { uint32_t skip = get_node_properties().skip_flags; - //wdump((trx.digest())(trx.id())); // If this is the first transaction pushed after applying a block, start a new undo session. // This allows us to quickly rewind to the clean state of the head block, in case a new block arrives. if( !_pending_block_session ) _pending_block_session = _undo_db.start_undo_session(); @@ -239,9 +226,6 @@ processed_transaction database::push_proposal(const proposal_object& proposal) return std::make_pair(id, authority::owner); }); - //ilog("Attempting to push proposal ${prop}", ("prop", proposal)); - //idump((eval_state.approved_by)); - eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size()); processed_transaction ptrx(proposal.proposed_transaction); eval_state._trx = &ptrx; diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 86e58690..882234ea 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -105,8 +105,8 @@ void database::initialize_indexes() add_index< primary_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 >(); add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); @@ -118,12 +118,12 @@ void database::initialize_indexes() add_index< primary_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> >(); - add_index< primary_index> >(); - add_index< primary_index< simple_index< witness_schedule_object > > >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); + add_index< primary_index> >(); } void database::init_genesis(const genesis_state_type& genesis_state) @@ -356,6 +356,6 @@ void database::init_genesis(const genesis_state_type& genesis_state) assert( wso.id == witness_schedule_id_type() ); _undo_db.enable(); -} FC_LOG_AND_RETHROW() } +} FC_CAPTURE_AND_RETHROW((genesis_state)) } } } diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 92a2e6a1..11bc6770 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -31,18 +31,19 @@ namespace graphene { namespace chain { -template -vector> database::sort_votable_objects(size_t count) const +template +vector> database::sort_votable_objects(size_t count) const { - const auto& all_objects = dynamic_cast&>(get_index()); + using ObjectType = typename Index::object_type; + const auto& all_objects = get_index_type().indices(); count = std::min(count, all_objects.size()); vector> refs; refs.reserve(all_objects.size()); std::transform(all_objects.begin(), all_objects.end(), std::back_inserter(refs), [](const ObjectType& o) { return std::cref(o); }); - std::partial_sort( refs.begin(), refs.begin() + count, refs.end(), - [this]( const ObjectType& a, const ObjectType& b )->bool { + std::partial_sort(refs.begin(), refs.begin() + count, refs.end(), + [this](const ObjectType& a, const ObjectType& b)->bool { return _vote_tally_buffer[a.vote_id] > _vote_tally_buffer[b.vote_id]; }); @@ -105,7 +106,7 @@ void database::update_active_witnesses() && (stake_tally <= stake_target) ) stake_tally += _witness_count_histogram_buffer[++witness_count]; - auto wits = sort_votable_objects(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); + auto wits = sort_votable_objects(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); const global_property_object& gpo = get_global_properties(); // Update witness authority @@ -171,12 +172,12 @@ void database::update_active_delegates() && (stake_tally <= stake_target) ) stake_tally += _committee_count_histogram_buffer[++delegate_count]; - auto delegates = sort_votable_objects(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); + auto delegates = sort_votable_objects(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); // Update genesis authorities if( !delegates.empty() ) { - modify( get(GRAPHENE_COMMITTEE_ACCOUNT), [&]( account_object& a ) { + modify(get(GRAPHENE_COMMITTEE_ACCOUNT), [&](account_object& a) { uint64_t total_votes = 0; map weights; a.active.weight_threshold = 0; @@ -202,11 +203,11 @@ void database::update_active_delegates() a.active.weight_threshold /= 2; a.active.weight_threshold += 1; }); - modify( get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&](account_object& a) { + modify(get(GRAPHENE_RELAXED_COMMITTEE_ACCOUNT), [&](account_object& a) { a.active = get(GRAPHENE_COMMITTEE_ACCOUNT).active; }); } - modify( get_global_properties(), [&]( global_property_object& gp ) { + modify(get_global_properties(), [&](global_property_object& gp) { gp.active_delegates.clear(); std::transform(delegates.begin(), delegates.end(), std::inserter(gp.active_delegates, gp.active_delegates.begin()), diff --git a/libraries/chain/include/graphene/chain/database.hpp b/libraries/chain/include/graphene/chain/database.hpp index 0c036c95..c26b44a6 100644 --- a/libraries/chain/include/graphene/chain/database.hpp +++ b/libraries/chain/include/graphene/chain/database.hpp @@ -399,8 +399,8 @@ namespace graphene { namespace chain { optional _pending_block_session; vector< unique_ptr > _operation_evaluators; - template - vector> sort_votable_objects(size_t count)const; + template + vector> sort_votable_objects(size_t count)const; //////////////////// db_block.cpp //////////////////// diff --git a/libraries/chain/include/graphene/chain/delegate_object.hpp b/libraries/chain/include/graphene/chain/delegate_object.hpp index 29dcbfd5..9807beef 100644 --- a/libraries/chain/include/graphene/chain/delegate_object.hpp +++ b/libraries/chain/include/graphene/chain/delegate_object.hpp @@ -18,6 +18,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -33,7 +34,7 @@ namespace graphene { namespace chain { * active delegates has control. * * Delegates were separated into a separate object to make iterating over - * the set of delegate easy. + * the set of delegate easy. */ class delegate_object : public abstract_object { @@ -45,6 +46,19 @@ namespace graphene { namespace chain { vote_id_type vote_id; }; + struct by_account; + using delegate_multi_index_type = multi_index_container< + delegate_object, + indexed_by< + ordered_unique< tag, + member + >, + hashed_unique< tag, + member + > + > + >; + using delegate_index = generic_index; } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object), diff --git a/libraries/chain/include/graphene/chain/witness_object.hpp b/libraries/chain/include/graphene/chain/witness_object.hpp index 5d5ba882..82677d66 100644 --- a/libraries/chain/include/graphene/chain/witness_object.hpp +++ b/libraries/chain/include/graphene/chain/witness_object.hpp @@ -18,6 +18,7 @@ #pragma once #include #include +#include namespace graphene { namespace chain { using namespace graphene::db; @@ -40,6 +41,19 @@ namespace graphene { namespace chain { witness_object() : vote_id(vote_id_type::witness) {} }; + struct by_account; + using witness_multi_index_type = multi_index_container< + witness_object, + indexed_by< + hashed_unique< tag, + member + >, + hashed_unique< tag, + member + > + > + >; + using witness_index = generic_index; } } // graphene::chain FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), @@ -49,4 +63,3 @@ FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), (last_secret) (accumulated_income) (vote_id) ) - diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index e74a34b3..02685c58 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -155,7 +155,7 @@ void database_fixture::verify_asset_supplies( )const total_balances[bad.options.short_backing_asset] += bad.settlement_fund; } } - for( const witness_object& witness_obj : db.get_index_type>() ) + for( const witness_object& witness_obj : db.get_index_type().indices() ) { total_balances[asset_id_type()] += witness_obj.accumulated_income; } diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index 2bb9a464..cab95933 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -41,14 +41,14 @@ genesis_state_type make_genesis() { secret_hash_type::encoder enc; fc::raw::pack(enc, delegate_priv_key); fc::raw::pack(enc, secret_hash_type()); + auto secret = secret_hash_type::hash(enc.result()); for( int i = 0; i < 10; ++i ) { - genesis_state.allocation_targets.emplace_back("init"+fc::to_string(i), delegate_priv_key.get_public_key(), 0, true); - genesis_state.initial_committee.push_back({"init"+fc::to_string(i)}); + auto name = "init"+fc::to_string(i); + genesis_state.allocation_targets.emplace_back(name, delegate_priv_key.get_public_key(), 0, true); + genesis_state.initial_committee.push_back({name}); + genesis_state.initial_witnesses.push_back({name, delegate_priv_key.get_public_key(), secret}); } - genesis_state.initial_witnesses = vector(10, {"committee-account", - delegate_priv_key.get_public_key(), - secret_hash_type::hash(enc.result())}); return genesis_state; } @@ -70,7 +70,7 @@ BOOST_AUTO_TEST_CASE( block_database_test ) for( uint32_t i = 0; i < 5; ++i ) { if( i > 0 ) b.previous = b.id(); - b.witness = witness_id_type(i+1); + b.witness = witness_id_type(i+1); bdb.store( b.id(), b ); auto fetch = bdb.fetch_by_number( b.block_num() );