diff --git a/libraries/chain/account_object.cpp b/libraries/chain/account_object.cpp index fed6f66e..054fb9bb 100644 --- a/libraries/chain/account_object.cpp +++ b/libraries/chain/account_object.cpp @@ -153,4 +153,87 @@ void account_object::options_type::validate() const "May not specify fewer witnesses or committee members than the number voted for."); } + + + + +set account_member_index::get_members( const account_object& a )const +{ + set result; + for( auto auth : a.owner.auths ) + result.insert(auth.first); + for( auto auth : a.active.auths ) + result.insert(auth.first); + return result; +} + +void account_member_index::object_inserted( const object& obj ) +{ + assert( dynamic_cast(&obj) ); // for debug only + const account_object& a = static_cast(obj); + + set members = get_members(a); + for( auto item : members ) + account_to_memberships[item].insert( obj.id ); +} + +void account_member_index::object_removed( const object& obj ) +{ + assert( dynamic_cast(&obj) ); // for debug only + const account_object& a = static_cast(obj); + + set members = get_members(a); + for( auto item : members ) + account_to_memberships[item].erase( obj.id ); +} + +void account_member_index::about_to_modify( const object& before ) +{ + before_members.clear(); + assert( dynamic_cast(&before) ); // for debug only + const account_object& a = static_cast(before); + before_members = get_members(a); +} + +void account_member_index::object_modified( const object& after ) +{ + assert( dynamic_cast(&after) ); // for debug only + const account_object& a = static_cast(after); + set after_members = get_members(a); + + vector removed; removed.reserve(before_members.size()); + std::set_difference( before_members.begin(), before_members.end(), + after_members.begin(), after_members.end(), + std::inserter( removed, removed.end() ) ); + + for( auto itr = removed.begin(); itr != removed.end(); ++itr ) + account_to_memberships[*itr].erase( after.id ); + + vector added; added.reserve(after_members.size()); + auto add_end = std::set_difference( after_members.begin(), after_members.end(), + before_members.begin(), before_members.end(), + std::inserter( added, added.end()) ); + + for( auto itr = added.begin(); itr != added.end(); ++itr ) + account_to_memberships[*itr].insert( after.id ); +} + + +void account_referrer_index::object_inserted( const object& obj ) +{ +} +void account_referrer_index::object_removed( const object& obj ) +{ +} +void account_referrer_index::about_to_modify( const object& before ) +{ +} +void account_referrer_index::object_modified( const object& after ) +{ +} + + + + + } } // graphene::chain diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 882234ea..0396f1b3 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -103,7 +103,10 @@ void database::initialize_indexes() //Protocol object indexes add_index< primary_index >(); add_index< primary_index >(); - add_index< primary_index >(); + auto acnt_index = add_index< primary_index >(); + acnt_index->add_secondary_index(); + acnt_index->add_secondary_index(); + add_index< primary_index> >(); add_index< primary_index >(); add_index< primary_index >(); diff --git a/libraries/chain/include/graphene/chain/account_object.hpp b/libraries/chain/include/graphene/chain/account_object.hpp index 0ec2376a..8fcadbe8 100644 --- a/libraries/chain/include/graphene/chain/account_object.hpp +++ b/libraries/chain/include/graphene/chain/account_object.hpp @@ -256,6 +256,44 @@ class database; delegate_id_type delegate_id; // optional }; + /** + * @brief This secondary index will allow a reverse lookup of all accounts that a particular key or account + * is an potential signing authority. + */ + class account_member_index : public secondary_index + { + public: + virtual void object_inserted( const object& obj ) override; + virtual void object_removed( const object& obj ) override; + virtual void about_to_modify( const object& before ) override; + virtual void object_modified( const object& after ) override; + + + /** given an account or key, map it to the set of accounts that reference it in an active or owner authority */ + map< object_id_type, set > account_to_memberships; + + + protected: + set get_members( const account_object& a )const; + set before_members; + }; + + /** + * @brief This secondary index will allow a reverse lookup of all accounts that have been referred by + * a particular account. + */ + class account_referrer_index : public secondary_index + { + public: + virtual void object_inserted( const object& obj ) override; + virtual void object_removed( const object& obj ) override; + virtual void about_to_modify( const object& before ) override; + virtual void object_modified( const object& after ) override; + + /** maps the referrer to the set of accounts that they have referred */ + map< account_id_type, set > referred_by; + }; + struct by_asset; struct by_account; struct by_balance; diff --git a/libraries/db/include/graphene/db/index.hpp b/libraries/db/include/graphene/db/index.hpp index 84c4103a..ae0e61b5 100644 --- a/libraries/db/include/graphene/db/index.hpp +++ b/libraries/db/include/graphene/db/index.hpp @@ -123,6 +123,16 @@ namespace graphene { namespace db { }; + class secondary_index + { + public: + virtual ~secondary_index(){}; + virtual void object_inserted( const object& obj ){}; + virtual void object_removed( const object& obj ){}; + virtual void about_to_modify( const object& before ){}; + virtual void object_modified( const object& after ){}; + }; + /** * Defines the common implementation */ @@ -143,13 +153,32 @@ namespace graphene { namespace db { /** called just after obj is modified */ void on_modify( const object& obj ); + template + void add_secondary_index() + { + _sindex.emplace_back( new T() ); + } + + template + const T& get_secondary_index()const + { + for( const auto& item : _sindex ) + { + const T* result = dynamic_cast(item.get()); + if( result != nullptr ) return *result; + } + assert( !"invalid index type" ); + } + protected: - vector< shared_ptr > _observers; + vector< shared_ptr > _observers; + vector< unique_ptr > _sindex; private: object_database& _db; }; + /** * @class primary_index * @brief Wraps a derived index to intercept calls to create, modify, and remove so that @@ -215,12 +244,16 @@ namespace graphene { namespace db { virtual const object& create(const std::function& constructor )override { const auto& result = DerivedIndex::create( constructor ); + for( const auto& item : _sindex ) + item->object_inserted( result ); on_add( result ); return result; } virtual void remove( const object& obj ) override { + for( const auto& item : _sindex ) + item->object_removed( obj ); on_remove(obj); DerivedIndex::remove(obj); } @@ -228,7 +261,11 @@ namespace graphene { namespace db { virtual void modify( const object& obj, const std::function& m )override { save_undo( obj ); + for( const auto& item : _sindex ) + item->about_to_modify( obj ); DerivedIndex::modify( obj, m ); + for( const auto& item : _sindex ) + item->object_modified( obj ); on_modify( obj ); } diff --git a/libraries/db/include/graphene/db/object_database.hpp b/libraries/db/include/graphene/db/object_database.hpp index ff4cc52d..627c8505 100644 --- a/libraries/db/include/graphene/db/object_database.hpp +++ b/libraries/db/include/graphene/db/object_database.hpp @@ -122,7 +122,7 @@ namespace graphene { namespace db { const T& get( object_id id )const { return get(id); } template - const IndexType* add_index() + IndexType* add_index() { typedef typename IndexType::object_type ObjectType; if( _index[ObjectType::space_id].size() <= ObjectType::type_id ) @@ -130,7 +130,7 @@ namespace graphene { namespace db { assert(!_index[ObjectType::space_id][ObjectType::type_id]); unique_ptr indexptr( new IndexType(*this) ); _index[ObjectType::space_id][ObjectType::type_id] = std::move(indexptr); - return static_cast(_index[ObjectType::space_id][ObjectType::type_id].get()); + return static_cast(_index[ObjectType::space_id][ObjectType::type_id].get()); } void pop_undo();