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:
parent
db85d35b19
commit
3eaec849eb
11 changed files with 107 additions and 61 deletions
|
|
@ -17,10 +17,8 @@
|
|||
*/
|
||||
#include <graphene/app/api.hpp>
|
||||
#include <graphene/app/application.hpp>
|
||||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/utilities/key_conversion.hpp>
|
||||
#include <graphene/chain/operation_history_object.hpp>
|
||||
|
||||
#include <fc/crypto/hex.hpp>
|
||||
|
||||
|
|
@ -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<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)
|
||||
:_app(a)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<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);
|
||||
if( _options->count("genesis-json") )
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@
|
|||
#include <graphene/chain/limit_order_object.hpp>
|
||||
#include <graphene/chain/call_order_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 <fc/api.hpp>
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @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
|
||||
* 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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ void database::initialize_indexes()
|
|||
add_index< primary_index<force_settlement_index> >();
|
||||
add_index< primary_index<account_index> >();
|
||||
add_index< primary_index<simple_index<key_object>> >();
|
||||
add_index< primary_index<simple_index<delegate_object>> >();
|
||||
add_index< primary_index<simple_index<witness_object>> >();
|
||||
add_index< primary_index<delegate_index> >();
|
||||
add_index< primary_index<witness_index> >();
|
||||
add_index< primary_index<limit_order_index > >();
|
||||
add_index< primary_index<call_order_index > >();
|
||||
add_index< primary_index<proposal_index > >();
|
||||
|
|
@ -118,12 +118,12 @@ void database::initialize_indexes()
|
|||
add_index< primary_index<transaction_index > >();
|
||||
add_index< primary_index<account_balance_index > >();
|
||||
add_index< primary_index<asset_bitasset_data_index > >();
|
||||
add_index< primary_index<simple_index< global_property_object >> >();
|
||||
add_index< primary_index<simple_index< dynamic_global_property_object >> >();
|
||||
add_index< primary_index<simple_index< account_statistics_object >> >();
|
||||
add_index< primary_index<simple_index< asset_dynamic_data_object >> >();
|
||||
add_index< primary_index<flat_index< block_summary_object >> >();
|
||||
add_index< primary_index< simple_index< witness_schedule_object > > >();
|
||||
add_index< primary_index<simple_index<global_property_object >> >();
|
||||
add_index< primary_index<simple_index<dynamic_global_property_object >> >();
|
||||
add_index< primary_index<simple_index<account_statistics_object >> >();
|
||||
add_index< primary_index<simple_index<asset_dynamic_data_object >> >();
|
||||
add_index< primary_index<flat_index< block_summary_object >> >();
|
||||
add_index< primary_index<simple_index<witness_schedule_object >> >();
|
||||
}
|
||||
|
||||
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)) }
|
||||
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -31,18 +31,19 @@
|
|||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
template<class ObjectType>
|
||||
vector<std::reference_wrapper<const ObjectType>> database::sort_votable_objects(size_t count) const
|
||||
template<class Index>
|
||||
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());
|
||||
vector<std::reference_wrapper<const ObjectType>> 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<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();
|
||||
|
||||
// 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<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
|
||||
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<account_id_type, uint64_t> 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()),
|
||||
|
|
|
|||
|
|
@ -399,8 +399,8 @@ namespace graphene { namespace chain {
|
|||
optional<undo_database::session> _pending_block_session;
|
||||
vector< unique_ptr<op_evaluator> > _operation_evaluators;
|
||||
|
||||
template<class ObjectType>
|
||||
vector<std::reference_wrapper<const ObjectType>> sort_votable_objects(size_t count)const;
|
||||
template<class Index>
|
||||
vector<std::reference_wrapper<const typename Index::object_type>> sort_votable_objects(size_t count)const;
|
||||
|
||||
//////////////////// db_block.cpp ////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
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<delegate_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<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
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::delegate_object, (graphene::db::object),
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/asset.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
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<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
|
||||
|
||||
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) )
|
||||
|
||||
|
|
|
|||
|
|
@ -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<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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<genesis_state_type::initial_witness_type>(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() );
|
||||
|
|
|
|||
Loading…
Reference in a new issue