Progress #61: Getting witnesses/delegates by owner

Support and API are now present for retrieving witnesses and delegates
by their owners.
This commit is contained in:
Nathan Hourt 2015-06-22 15:03:18 -04:00
parent db85d35b19
commit 3eaec849eb
11 changed files with 107 additions and 61 deletions

View file

@ -17,10 +17,8 @@
*/ */
#include <graphene/app/api.hpp> #include <graphene/app/api.hpp>
#include <graphene/app/application.hpp> #include <graphene/app/application.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/database.hpp> #include <graphene/chain/database.hpp>
#include <graphene/utilities/key_conversion.hpp> #include <graphene/utilities/key_conversion.hpp>
#include <graphene/chain/operation_history_object.hpp>
#include <fc/crypto/hex.hpp> #include <fc/crypto/hex.hpp>
@ -251,6 +249,24 @@ namespace graphene { namespace app {
return result; return result;
} }
fc::optional<delegate_object> database_api::get_delegate_by_account(account_id_type account) const
{
const auto& idx = _db.get_index_type<delegate_index>().indices().get<by_account>();
auto itr = idx.find(account);
if( itr != idx.end() )
return *itr;
return {};
}
fc::optional<witness_object> database_api::get_witness_by_account(account_id_type account) const
{
const auto& idx = _db.get_index_type<witness_index>().indices().get<by_account>();
auto itr = idx.find(account);
if( itr != idx.end() )
return *itr;
return {};
}
login_api::login_api(application& a) login_api::login_api(application& a)
:_app(a) :_app(a)
{ {

View file

@ -153,14 +153,14 @@ namespace detail {
secret_hash_type::encoder enc; secret_hash_type::encoder enc;
fc::raw::pack(enc, nathan_key); fc::raw::pack(enc, nathan_key);
fc::raw::pack(enc, secret_hash_type()); fc::raw::pack(enc, secret_hash_type());
auto secret = secret_hash_type::hash(enc.result());
for( int i = 0; i < 10; ++i ) 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); auto name = "init"+fc::to_string(i);
initial_state.initial_committee.push_back({"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<genesis_state_type::initial_witness_type>(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); initial_state.allocation_targets.emplace_back("nathan", address(public_key_type(nathan_key.get_public_key())), 1);
if( _options->count("genesis-json") ) if( _options->count("genesis-json") )

View file

@ -24,7 +24,10 @@
#include <graphene/chain/limit_order_object.hpp> #include <graphene/chain/limit_order_object.hpp>
#include <graphene/chain/call_order_object.hpp> #include <graphene/chain/call_order_object.hpp>
#include <graphene/chain/key_object.hpp> #include <graphene/chain/key_object.hpp>
#include <graphene/chain/delegate_object.hpp>
#include <graphene/chain/witness_object.hpp>
#include <graphene/net/node.hpp> #include <graphene/net/node.hpp>
#include <fc/api.hpp> #include <fc/api.hpp>
namespace graphene { namespace app { namespace graphene { namespace app {
@ -165,6 +168,19 @@ namespace graphene { namespace app {
*/ */
vector<asset_object> list_assets(const string& lower_bound_symbol, uint32_t limit)const; vector<asset_object> 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<delegate_object> 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<witness_object> get_witness_by_account(account_id_type account)const;
/** /**
* @group Push Notification Methods * @group Push Notification Methods
* These methods may be used to get push notifications whenever an object or market is changed * 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_call_orders)
(get_settle_orders) (get_settle_orders)
(list_assets) (list_assets)
(get_delegate_by_account)
(get_witness_by_account)
(subscribe_to_objects) (subscribe_to_objects)
(unsubscribe_from_objects) (unsubscribe_from_objects)
(subscribe_to_market) (subscribe_to_market)

View file

@ -99,20 +99,11 @@ bool database::_push_block( const signed_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 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() ) 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 //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 //Only switch forks if new_head is actually higher than head
if( new_head->data.block_num() > head_block_num() ) if( new_head->data.block_num() > head_block_num() )
{ {
auto branches = _fork_db.fetch_branch_from(new_head->data.id(), _pending_block.previous); 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) );
}
// pop blocks until we hit the forked block // pop blocks until we hit the forked block
while( head_block_id() != branches.second.back()->data.previous ) 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; } catch ( const fc::exception& e ) { except = e; }
if( except ) 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 // remove the rest of branches.first from the fork_db, those blocks are invalid
while( ritr != branches.first.rend() ) while( ritr != branches.first.rend() )
{ {
@ -204,7 +192,6 @@ processed_transaction database::push_transaction( const signed_transaction& trx,
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; 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. // 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. // 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(); 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); 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()); eval_state.operation_results.reserve(proposal.proposed_transaction.operations.size());
processed_transaction ptrx(proposal.proposed_transaction); processed_transaction ptrx(proposal.proposed_transaction);
eval_state._trx = &ptrx; eval_state._trx = &ptrx;

View file

@ -105,8 +105,8 @@ void database::initialize_indexes()
add_index< primary_index<force_settlement_index> >(); add_index< primary_index<force_settlement_index> >();
add_index< primary_index<account_index> >(); add_index< primary_index<account_index> >();
add_index< primary_index<simple_index<key_object>> >(); add_index< primary_index<simple_index<key_object>> >();
add_index< primary_index<simple_index<delegate_object>> >(); add_index< primary_index<delegate_index> >();
add_index< primary_index<simple_index<witness_object>> >(); add_index< primary_index<witness_index> >();
add_index< primary_index<limit_order_index > >(); add_index< primary_index<limit_order_index > >();
add_index< primary_index<call_order_index > >(); add_index< primary_index<call_order_index > >();
add_index< primary_index<proposal_index > >(); add_index< primary_index<proposal_index > >();
@ -356,6 +356,6 @@ void database::init_genesis(const genesis_state_type& genesis_state)
assert( wso.id == witness_schedule_id_type() ); assert( wso.id == witness_schedule_id_type() );
_undo_db.enable(); _undo_db.enable();
} FC_LOG_AND_RETHROW() } } FC_CAPTURE_AND_RETHROW((genesis_state)) }
} } } }

View file

@ -31,10 +31,11 @@
namespace graphene { namespace chain { namespace graphene { namespace chain {
template<class ObjectType> template<class Index>
vector<std::reference_wrapper<const ObjectType>> database::sort_votable_objects(size_t count) const vector<std::reference_wrapper<const typename Index::object_type>> database::sort_votable_objects(size_t count) const
{ {
const auto& all_objects = dynamic_cast<const simple_index<ObjectType>&>(get_index<ObjectType>()); using ObjectType = typename Index::object_type;
const auto& all_objects = get_index_type<Index>().indices();
count = std::min(count, all_objects.size()); count = std::min(count, all_objects.size());
vector<std::reference_wrapper<const ObjectType>> refs; vector<std::reference_wrapper<const ObjectType>> refs;
refs.reserve(all_objects.size()); refs.reserve(all_objects.size());
@ -105,7 +106,7 @@ void database::update_active_witnesses()
&& (stake_tally <= stake_target) ) && (stake_tally <= stake_target) )
stake_tally += _witness_count_histogram_buffer[++witness_count]; stake_tally += _witness_count_histogram_buffer[++witness_count];
auto wits = sort_votable_objects<witness_object>(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT)); auto wits = sort_votable_objects<witness_index>(std::max(witness_count*2+1, GRAPHENE_MIN_WITNESS_COUNT));
const global_property_object& gpo = get_global_properties(); const global_property_object& gpo = get_global_properties();
// Update witness authority // Update witness authority
@ -171,7 +172,7 @@ void database::update_active_delegates()
&& (stake_tally <= stake_target) ) && (stake_tally <= stake_target) )
stake_tally += _committee_count_histogram_buffer[++delegate_count]; stake_tally += _committee_count_histogram_buffer[++delegate_count];
auto delegates = sort_votable_objects<delegate_object>(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT)); auto delegates = sort_votable_objects<delegate_index>(std::max(delegate_count*2+1, GRAPHENE_MIN_DELEGATE_COUNT));
// Update genesis authorities // Update genesis authorities
if( !delegates.empty() ) if( !delegates.empty() )

View file

@ -399,8 +399,8 @@ namespace graphene { namespace chain {
optional<undo_database::session> _pending_block_session; optional<undo_database::session> _pending_block_session;
vector< unique_ptr<op_evaluator> > _operation_evaluators; vector< unique_ptr<op_evaluator> > _operation_evaluators;
template<class ObjectType> template<class Index>
vector<std::reference_wrapper<const ObjectType>> sort_votable_objects(size_t count)const; vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
//////////////////// db_block.cpp //////////////////// //////////////////// db_block.cpp ////////////////////

View file

@ -18,6 +18,7 @@
#pragma once #pragma once
#include <graphene/chain/asset.hpp> #include <graphene/chain/asset.hpp>
#include <graphene/db/object.hpp> #include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain { namespace graphene { namespace chain {
using namespace graphene::db; using namespace graphene::db;
@ -45,6 +46,19 @@ namespace graphene { namespace chain {
vote_id_type vote_id; vote_id_type vote_id;
}; };
struct by_account;
using delegate_multi_index_type = multi_index_container<
delegate_object,
indexed_by<
ordered_unique< tag<by_id>,
member<object, object_id_type, &object::id>
>,
hashed_unique< tag<by_account>,
member<delegate_object, account_id_type, &delegate_object::delegate_account>
>
>
>;
using delegate_index = generic_index<delegate_object, delegate_multi_index_type>;
} } // graphene::chain } } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object), FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object),

View file

@ -18,6 +18,7 @@
#pragma once #pragma once
#include <graphene/chain/asset.hpp> #include <graphene/chain/asset.hpp>
#include <graphene/db/object.hpp> #include <graphene/db/object.hpp>
#include <graphene/db/generic_index.hpp>
namespace graphene { namespace chain { namespace graphene { namespace chain {
using namespace graphene::db; using namespace graphene::db;
@ -40,6 +41,19 @@ namespace graphene { namespace chain {
witness_object() : vote_id(vote_id_type::witness) {} 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<by_id>,
member<object, object_id_type, &object::id>
>,
hashed_unique< tag<by_account>,
member<witness_object, account_id_type, &witness_object::witness_account>
>
>
>;
using witness_index = generic_index<witness_object, witness_multi_index_type>;
} } // graphene::chain } } // graphene::chain
FC_REFLECT_DERIVED( graphene::chain::witness_object, (graphene::db::object), 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) (last_secret)
(accumulated_income) (accumulated_income)
(vote_id) ) (vote_id) )

View file

@ -155,7 +155,7 @@ void database_fixture::verify_asset_supplies( )const
total_balances[bad.options.short_backing_asset] += bad.settlement_fund; total_balances[bad.options.short_backing_asset] += bad.settlement_fund;
} }
} }
for( const witness_object& witness_obj : db.get_index_type<simple_index<witness_object>>() ) for( const witness_object& witness_obj : db.get_index_type<witness_index>().indices() )
{ {
total_balances[asset_id_type()] += witness_obj.accumulated_income; total_balances[asset_id_type()] += witness_obj.accumulated_income;
} }

View file

@ -41,14 +41,14 @@ genesis_state_type make_genesis() {
secret_hash_type::encoder enc; secret_hash_type::encoder enc;
fc::raw::pack(enc, delegate_priv_key); fc::raw::pack(enc, delegate_priv_key);
fc::raw::pack(enc, secret_hash_type()); fc::raw::pack(enc, secret_hash_type());
auto secret = secret_hash_type::hash(enc.result());
for( int i = 0; i < 10; ++i ) 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); auto name = "init"+fc::to_string(i);
genesis_state.initial_committee.push_back({"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<genesis_state_type::initial_witness_type>(10, {"committee-account",
delegate_priv_key.get_public_key(),
secret_hash_type::hash(enc.result())});
return genesis_state; return genesis_state;
} }