Removing unnecessary indexing from account history plugin, it can now focus on just tracking operation history
This commit is contained in:
parent
23a633bea1
commit
a0765e2cf2
3 changed files with 4 additions and 351 deletions
|
|
@ -34,69 +34,15 @@ namespace graphene { namespace account_history {
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
class account_create_observer : public graphene::chain::evaluation_observer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
account_create_observer( account_history_plugin& plugin )
|
|
||||||
: _plugin( plugin ) {}
|
|
||||||
virtual ~account_create_observer();
|
|
||||||
|
|
||||||
virtual void post_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result ) override;
|
|
||||||
|
|
||||||
account_history_plugin& _plugin;
|
|
||||||
};
|
|
||||||
|
|
||||||
class account_update_observer : public graphene::chain::evaluation_observer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
account_update_observer( account_history_plugin& plugin )
|
|
||||||
: _plugin( plugin )
|
|
||||||
{
|
|
||||||
_pre_account_keys.reserve( GRAPHENE_DEFAULT_MAX_AUTHORITY_MEMBERSHIP * 2 + 2 );
|
|
||||||
}
|
|
||||||
virtual ~account_update_observer();
|
|
||||||
|
|
||||||
virtual void pre_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge ) override;
|
|
||||||
|
|
||||||
virtual void post_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result ) override;
|
|
||||||
|
|
||||||
virtual void evaluation_failed(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result ) override;
|
|
||||||
|
|
||||||
account_history_plugin& _plugin;
|
|
||||||
flat_set< key_id_type > _pre_account_keys;
|
|
||||||
};
|
|
||||||
|
|
||||||
class account_history_plugin_impl
|
class account_history_plugin_impl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
account_history_plugin_impl(account_history_plugin& _plugin)
|
account_history_plugin_impl(account_history_plugin& _plugin)
|
||||||
: _self( _plugin ),
|
: _self( _plugin )
|
||||||
_create_observer( _plugin ),
|
|
||||||
_update_observer( _plugin )
|
|
||||||
{ }
|
{ }
|
||||||
virtual ~account_history_plugin_impl();
|
virtual ~account_history_plugin_impl();
|
||||||
|
|
||||||
void rebuild_key_account_index();
|
|
||||||
|
|
||||||
flat_set<key_id_type> get_keys_for_account(
|
flat_set<key_id_type> get_keys_for_account(
|
||||||
const account_id_type& account_id );
|
const account_id_type& account_id );
|
||||||
|
|
||||||
|
|
@ -104,7 +50,6 @@ class account_history_plugin_impl
|
||||||
* and will process/index all operations that were applied in the block.
|
* and will process/index all operations that were applied in the block.
|
||||||
*/
|
*/
|
||||||
void update_account_histories( const signed_block& b );
|
void update_account_histories( const signed_block& b );
|
||||||
void index_account_keys( const account_id_type& account_id );
|
|
||||||
|
|
||||||
graphene::chain::database& database()
|
graphene::chain::database& database()
|
||||||
{
|
{
|
||||||
|
|
@ -112,8 +57,6 @@ class account_history_plugin_impl
|
||||||
}
|
}
|
||||||
|
|
||||||
account_history_plugin& _self;
|
account_history_plugin& _self;
|
||||||
account_create_observer _create_observer;
|
|
||||||
account_update_observer _update_observer;
|
|
||||||
flat_set<account_id_type> _tracked_accounts;
|
flat_set<account_id_type> _tracked_accounts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -248,271 +191,13 @@ struct operation_get_impacted_accounts
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
account_create_observer::~account_create_observer()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_create_observer::post_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result
|
|
||||||
)
|
|
||||||
{
|
|
||||||
assert( op.which() == operation::tag<account_create_operation>::value );
|
|
||||||
|
|
||||||
if( !apply )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if we only care about given accounts, then key -> account mapping
|
|
||||||
// is not maintained
|
|
||||||
if( _plugin.my->_tracked_accounts.size() > 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
account_id_type account_id = result.get< object_id_type >();
|
|
||||||
_plugin.my->index_account_keys( account_id );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
account_update_observer::~account_update_observer()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_update_observer::pre_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge
|
|
||||||
)
|
|
||||||
{
|
|
||||||
assert( op.which() == operation::tag<account_update_operation>::value );
|
|
||||||
|
|
||||||
if( !apply )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if we only care about given accounts, then key -> account mapping
|
|
||||||
// is not maintained
|
|
||||||
if( _plugin.my->_tracked_accounts.size() > 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// is this a tx which affects a key?
|
|
||||||
// switch( op.which() )
|
|
||||||
// {
|
|
||||||
// see note in configure() why account_create_operation handling is unnecessary
|
|
||||||
// case operation::tag<account_create_operation>::value:
|
|
||||||
// const account_create_operation& create_op = op.get< account_create_operation >();
|
|
||||||
// break;
|
|
||||||
// case operation::tag<account_update_operation>::value:
|
|
||||||
// const account_update_operation& update_op = op.get< account_update_operation >();
|
|
||||||
// _pre_account_keys.clear();
|
|
||||||
// get_updatable_account_keys( update_op, _pre_account_keys );
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// FC_ASSERT( false, "account_update_observer got unexpected operation type" );
|
|
||||||
//}
|
|
||||||
|
|
||||||
const account_update_operation& update_op = op.get< account_update_operation >();
|
|
||||||
_pre_account_keys = _plugin.my->get_keys_for_account( update_op.account );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_update_observer::post_evaluate(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result
|
|
||||||
)
|
|
||||||
{
|
|
||||||
assert( op.which() == operation::tag<account_update_operation>::value );
|
|
||||||
|
|
||||||
if( !apply )
|
|
||||||
return;
|
|
||||||
|
|
||||||
graphene::chain::database& db = _plugin.my->database();
|
|
||||||
|
|
||||||
// if we only care about given accounts, then key -> account mapping
|
|
||||||
// is not maintained
|
|
||||||
if( _plugin.my->_tracked_accounts.size() > 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// wild back-of-envelope heuristic: most account update ops
|
|
||||||
// don't add more than two keys
|
|
||||||
flat_set<key_id_type> post_account_keys;
|
|
||||||
post_account_keys.reserve( _pre_account_keys.size() + 2 );
|
|
||||||
|
|
||||||
vector<key_id_type> removed_account_keys;
|
|
||||||
removed_account_keys.reserve( _pre_account_keys.size() );
|
|
||||||
|
|
||||||
const account_update_operation& update_op = op.get< account_update_operation >();
|
|
||||||
post_account_keys = _plugin.my->get_keys_for_account( update_op.account );
|
|
||||||
|
|
||||||
std::set_difference(
|
|
||||||
_pre_account_keys.begin(), _pre_account_keys.end(),
|
|
||||||
post_account_keys.begin(), post_account_keys.end(),
|
|
||||||
std::back_inserter( removed_account_keys )
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
|
||||||
// If a key_id is in _pre_account_keys but not in post_account_keys,
|
|
||||||
// then it is placed in removed_account_keys by set_difference().
|
|
||||||
//
|
|
||||||
// Note, the *address* corresponding to this key may still exist
|
|
||||||
// in the account, because it may be aliased to multiple key_id's.
|
|
||||||
//
|
|
||||||
// We delete the key_account_object for all removed_account_keys.
|
|
||||||
// This correctly deletes addresses which were removed
|
|
||||||
// from the account by the update_op.
|
|
||||||
//
|
|
||||||
// Unfortunately, in the case of aliased keys, it deletes
|
|
||||||
// key_account_object if *any* of the aliases was removed from
|
|
||||||
// the account. We want it to delete only if *all* of the aliases
|
|
||||||
// were removed from the account.
|
|
||||||
//
|
|
||||||
// However, we need to run index_account_keys() afterwards anyway.
|
|
||||||
// It will re-add to the index any addresses which had been
|
|
||||||
// deleted -- but only if they still exist in the account under
|
|
||||||
// at least one alias.
|
|
||||||
//
|
|
||||||
// This is precisely the correct behavior.
|
|
||||||
//
|
|
||||||
|
|
||||||
for( const key_id_type& key_id : removed_account_keys )
|
|
||||||
{
|
|
||||||
auto& index = db.get_index_type<key_account_index>().indices().get<by_key>();
|
|
||||||
auto it = index.find( key_id(db).key_address() );
|
|
||||||
assert( it != index.end() );
|
|
||||||
|
|
||||||
db.modify<key_account_object>( *it, [&]( key_account_object& ka )
|
|
||||||
{
|
|
||||||
ka.account_ids.erase( update_op.account );
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_plugin.my->index_account_keys( update_op.account );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_update_observer::evaluation_failed(
|
|
||||||
const transaction_evaluation_state& eval_state,
|
|
||||||
const operation& op,
|
|
||||||
bool apply,
|
|
||||||
generic_evaluator* ge,
|
|
||||||
const operation_result& result
|
|
||||||
)
|
|
||||||
{
|
|
||||||
if( !apply )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if we only care about given accounts, then key -> account mapping
|
|
||||||
// is not maintained
|
|
||||||
if( _plugin.my->_tracked_accounts.size() > 0 )
|
|
||||||
return;
|
|
||||||
|
|
||||||
// cleaning up here is not strictly necessary, but good "hygiene"
|
|
||||||
_pre_account_keys.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
account_history_plugin_impl::~account_history_plugin_impl()
|
account_history_plugin_impl::~account_history_plugin_impl()
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void account_history_plugin_impl::rebuild_key_account_index()
|
|
||||||
{
|
|
||||||
// TODO: We should really delete the index before we re-create it.
|
|
||||||
// TODO: Building and sorting a vector of tuples is probably more efficient
|
|
||||||
const graphene::chain::database& db = database();
|
|
||||||
|
|
||||||
vector< pair< account_id_type, address > > tuples_from_db;
|
|
||||||
const auto& primary_account_idx = db.get_index_type<account_index>().indices().get<by_id>();
|
|
||||||
for( const account_object& acct : primary_account_idx )
|
|
||||||
index_account_keys( acct.id );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
flat_set<key_id_type> account_history_plugin_impl::get_keys_for_account( const account_id_type& account_id )
|
|
||||||
{
|
|
||||||
const graphene::chain::database& db = database();
|
|
||||||
const account_object& acct = account_id(db);
|
|
||||||
|
|
||||||
const flat_map<object_id_type, weight_type>& owner_auths =
|
|
||||||
acct.owner.auths;
|
|
||||||
const flat_map<object_id_type, weight_type>& active_auths =
|
|
||||||
acct.active.auths;
|
|
||||||
|
|
||||||
flat_set<key_id_type> key_id_set;
|
|
||||||
key_id_set.reserve(owner_auths.size() + active_auths.size() + 2);
|
|
||||||
|
|
||||||
key_id_set.insert(acct.options.memo_key);
|
|
||||||
|
|
||||||
// we don't use get_keys() here to avoid an intermediate copy operation
|
|
||||||
for( const pair<object_id_type, weight_type>& item : active_auths )
|
|
||||||
{
|
|
||||||
if( item.first.type() == key_object_type )
|
|
||||||
key_id_set.insert( item.first );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( const pair<object_id_type, weight_type>& item : owner_auths )
|
|
||||||
{
|
|
||||||
if( item.first.type() == key_object_type )
|
|
||||||
key_id_set.insert( item.first );
|
|
||||||
}
|
|
||||||
|
|
||||||
return key_id_set;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_history_plugin_impl::index_account_keys( const account_id_type& account_id )
|
|
||||||
{
|
|
||||||
// for each key in account authority... get address, modify(..)
|
|
||||||
graphene::chain::database& db = database();
|
|
||||||
|
|
||||||
flat_set<key_id_type> key_id_set = get_keys_for_account( account_id );
|
|
||||||
|
|
||||||
flat_set<address> address_set;
|
|
||||||
|
|
||||||
//
|
|
||||||
// we pass the addresses through another flat_set because the
|
|
||||||
// blockchain doesn't force de-duplication of addresses
|
|
||||||
// (multiple key_id's might refer to the same address)
|
|
||||||
//
|
|
||||||
address_set.reserve( key_id_set.size() );
|
|
||||||
|
|
||||||
for( const key_id_type& key_id : key_id_set )
|
|
||||||
address_set.insert( key_id(db).key_address() );
|
|
||||||
|
|
||||||
// add mappings for the given account
|
|
||||||
for( const address& addr : address_set )
|
|
||||||
{
|
|
||||||
auto& idx = db.get_index_type<key_account_index>().indices().get<by_key>();
|
|
||||||
auto it = idx.find( addr );
|
|
||||||
if( it == idx.end() )
|
|
||||||
{
|
|
||||||
// if unknown, we need to create a new object
|
|
||||||
db.create<key_account_object>( [&]( key_account_object& ka )
|
|
||||||
{
|
|
||||||
ka.key = addr;
|
|
||||||
ka.account_ids.insert( account_id );
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// if known, we need to add to existing object
|
|
||||||
db.modify<key_account_object>( *it,
|
|
||||||
[&]( key_account_object& ka )
|
|
||||||
{
|
|
||||||
ka.account_ids.insert( account_id );
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void account_history_plugin_impl::update_account_histories( const signed_block& b )
|
void account_history_plugin_impl::update_account_histories( const signed_block& b )
|
||||||
{
|
{
|
||||||
|
|
@ -555,8 +240,6 @@ void account_history_plugin_impl::update_account_histories( const signed_block&
|
||||||
{
|
{
|
||||||
if( impacted.find( account_id ) != impacted.end() )
|
if( impacted.find( account_id ) != impacted.end() )
|
||||||
{
|
{
|
||||||
index_account_keys( account_id );
|
|
||||||
|
|
||||||
// add history
|
// add history
|
||||||
const auto& stats_obj = account_id(db).statistics(db);
|
const auto& stats_obj = account_id(db).statistics(db);
|
||||||
const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){
|
const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){
|
||||||
|
|
@ -603,17 +286,12 @@ void account_history_plugin::plugin_initialize(const boost::program_options::var
|
||||||
database().applied_block.connect( [&]( const signed_block& b){ my->update_account_histories(b); } );
|
database().applied_block.connect( [&]( const signed_block& b){ my->update_account_histories(b); } );
|
||||||
database().add_index< primary_index< simple_index< operation_history_object > > >();
|
database().add_index< primary_index< simple_index< operation_history_object > > >();
|
||||||
database().add_index< primary_index< simple_index< account_transaction_history_object > > >();
|
database().add_index< primary_index< simple_index< account_transaction_history_object > > >();
|
||||||
database().add_index< primary_index< key_account_index >>();
|
|
||||||
|
|
||||||
database().register_evaluation_observer<account_create_evaluator>( my->_create_observer );
|
|
||||||
database().register_evaluation_observer< graphene::chain::account_update_evaluator >( my->_update_observer );
|
|
||||||
|
|
||||||
LOAD_VALUE_SET(options, "tracked-accounts", my->_tracked_accounts, graphene::chain::account_id_type);
|
LOAD_VALUE_SET(options, "tracked-accounts", my->_tracked_accounts, graphene::chain::account_id_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void account_history_plugin::plugin_startup()
|
void account_history_plugin::plugin_startup()
|
||||||
{
|
{
|
||||||
my->rebuild_key_account_index();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flat_set<account_id_type> account_history_plugin::tracked_accounts() const
|
flat_set<account_id_type> account_history_plugin::tracked_accounts() const
|
||||||
|
|
|
||||||
|
|
@ -45,29 +45,6 @@ enum account_history_object_type
|
||||||
bucket_object_type = 1 ///< used in market_history_plugin
|
bucket_object_type = 1 ///< used in market_history_plugin
|
||||||
};
|
};
|
||||||
|
|
||||||
class key_account_object : public abstract_object<key_account_object>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint8_t space_id = ACCOUNT_HISTORY_SPACE_ID;
|
|
||||||
static const uint8_t type_id = key_account_object_type;
|
|
||||||
|
|
||||||
key_account_object() {}
|
|
||||||
key_account_object( const address& a ) : key(a) {}
|
|
||||||
|
|
||||||
address key;
|
|
||||||
flat_set<account_id_type> account_ids;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct by_key{};
|
|
||||||
typedef multi_index_container<
|
|
||||||
key_account_object,
|
|
||||||
indexed_by<
|
|
||||||
hashed_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
|
|
||||||
ordered_unique< tag<by_key>, member< key_account_object, address, &key_account_object::key > >
|
|
||||||
>
|
|
||||||
> key_account_object_multi_index_type;
|
|
||||||
|
|
||||||
typedef generic_index<key_account_object, key_account_object_multi_index_type> key_account_index;
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
@ -95,8 +72,3 @@ class account_history_plugin : public graphene::app::plugin
|
||||||
|
|
||||||
} } //graphene::account_history
|
} } //graphene::account_history
|
||||||
|
|
||||||
FC_REFLECT_DERIVED( graphene::account_history::key_account_object,
|
|
||||||
(graphene::db::object),
|
|
||||||
(key)
|
|
||||||
(account_ids)
|
|
||||||
)
|
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ void database_fixture::verify_asset_supplies( )const
|
||||||
|
|
||||||
void database_fixture::verify_account_history_plugin_index( )const
|
void database_fixture::verify_account_history_plugin_index( )const
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
if( skip_key_index_test )
|
if( skip_key_index_test )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -219,6 +220,7 @@ void database_fixture::verify_account_history_plugin_index( )const
|
||||||
tuples_from_db.emplace_back( account_id, addr );
|
tuples_from_db.emplace_back( account_id, addr );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
vector< pair< account_id_type, address > > tuples_from_index;
|
vector< pair< account_id_type, address > > tuples_from_index;
|
||||||
tuples_from_index.reserve( tuples_from_db.size() );
|
tuples_from_index.reserve( tuples_from_db.size() );
|
||||||
const auto& key_account_idx =
|
const auto& key_account_idx =
|
||||||
|
|
@ -263,6 +265,7 @@ void database_fixture::verify_account_history_plugin_index( )const
|
||||||
|
|
||||||
bool account_history_plugin_index_ok = is_equal;
|
bool account_history_plugin_index_ok = is_equal;
|
||||||
BOOST_CHECK( account_history_plugin_index_ok );
|
BOOST_CHECK( account_history_plugin_index_ok );
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue