void account_history_plugin_impl::update_account_histories( const signed_block& b ) { graphene::chain::database& db = database(); const vector<operation_history_object>& hist = db.get_applied_operations(); for( auto op : hist ) { // add to the operation history index const auto& oho = db.create<operation_history_object>( [&]( operation_history_object& h ){ h = op; }); // get the set of accounts this operation applies to flat_set<account_id_type> impacted; vector<authority> other; operation_get_required_authorities( op.op, impacted, impacted, other ); op.op.visit( operation_get_impacted_accounts( oho, _self, impacted ) ); for( auto& a : other ) for( auto& item : a.account_auths ) impacted.insert( item.first ); // for each operation this account applies to that is in the config link it into the history if( _tracked_accounts.size() == 0 ) { for( auto& account_id : impacted ) { // we don't do index_account_keys here anymore, because // that indexing now happens in observers' post_evaluate() // add history const auto& stats_obj = account_id(db).statistics(db); const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){ obj.operation_id = oho.id; obj.next = stats_obj.most_recent_op; }); db.modify( stats_obj, [&]( account_statistics_object& obj ){ obj.most_recent_op = ath.id; }); } } else { for( auto account_id : _tracked_accounts ) { if( impacted.find( account_id ) != impacted.end() ) { // add history const auto& stats_obj = account_id(db).statistics(db); const auto& ath = db.create<account_transaction_history_object>( [&]( account_transaction_history_object& obj ){ obj.operation_id = oho.id; obj.next = stats_obj.most_recent_op; }); db.modify( stats_obj, [&]( account_statistics_object& obj ){ obj.most_recent_op = ath.id; }); } } } } }
vector<account_id_type> get_relevant_accounts( const object* obj ) { vector<account_id_type> result; if( obj->id.space() == protocol_ids ) { switch( (object_type)obj->id.type() ) { case null_object_type: case base_object_type: case OBJECT_TYPE_COUNT: return result; case account_object_type:{ result.push_back( obj->id ); break; } case asset_object_type:{ const auto& aobj = dynamic_cast<const asset_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->issuer ); break; } case force_settlement_object_type:{ const auto& aobj = dynamic_cast<const force_settlement_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->owner ); break; } case committee_member_object_type:{ const auto& aobj = dynamic_cast<const committee_member_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->committee_member_account ); break; } case witness_object_type:{ const auto& aobj = dynamic_cast<const witness_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->witness_account ); break; } case limit_order_object_type:{ const auto& aobj = dynamic_cast<const limit_order_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->seller ); break; } case call_order_object_type:{ const auto& aobj = dynamic_cast<const call_order_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->borrower ); break; } case custom_object_type:{ } case proposal_object_type:{ const auto& aobj = dynamic_cast<const proposal_object*>(obj); assert( aobj != nullptr ); flat_set<account_id_type> impacted; transaction_get_impacted_accounts( aobj->proposed_transaction, impacted ); result.reserve( impacted.size() ); for( auto& item : impacted ) result.emplace_back(item); break; } case operation_history_object_type:{ const auto& aobj = dynamic_cast<const operation_history_object*>(obj); assert( aobj != nullptr ); flat_set<account_id_type> impacted; operation_get_impacted_accounts( aobj->op, impacted ); result.reserve( impacted.size() ); for( auto& item : impacted ) result.emplace_back(item); break; } case withdraw_permission_object_type:{ const auto& aobj = dynamic_cast<const withdraw_permission_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->withdraw_from_account ); result.push_back( aobj->authorized_account ); break; } case vesting_balance_object_type:{ const auto& aobj = dynamic_cast<const vesting_balance_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->owner ); break; } case worker_object_type:{ const auto& aobj = dynamic_cast<const worker_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->worker_account ); break; } case balance_object_type:{ /** these are free from any accounts */ } } } else if( obj->id.space() == implementation_ids ) { switch( (impl_object_type)obj->id.type() ) { case impl_global_property_object_type:{ } case impl_dynamic_global_property_object_type:{ } case impl_reserved0_object_type:{ } case impl_asset_dynamic_data_type:{ } case impl_asset_bitasset_data_type:{ break; } case impl_account_balance_object_type:{ const auto& aobj = dynamic_cast<const account_balance_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->owner ); break; } case impl_account_statistics_object_type:{ const auto& aobj = dynamic_cast<const account_statistics_object*>(obj); assert( aobj != nullptr ); result.push_back( aobj->owner ); break; } case impl_transaction_object_type:{ const auto& aobj = dynamic_cast<const transaction_object*>(obj); assert( aobj != nullptr ); flat_set<account_id_type> impacted; transaction_get_impacted_accounts( aobj->trx, impacted ); result.reserve( impacted.size() ); for( auto& item : impacted ) result.emplace_back(item); break; } case impl_blinded_balance_object_type:{ const auto& aobj = dynamic_cast<const blinded_balance_object*>(obj); assert( aobj != nullptr ); result.reserve( aobj->owner.account_auths.size() ); for( const auto& a : aobj->owner.account_auths ) result.push_back( a.first ); break; } case impl_block_summary_object_type:{ } case impl_account_transaction_history_object_type:{ } case impl_chain_property_object_type: { } case impl_witness_schedule_object_type: { } case impl_budget_record_object_type: { } } } return result; } // end get_relevant_accounts( obj )