From 681f0923feca4f5001fcca79699063f4e774bd05 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Mon, 29 Jun 2015 17:29:04 -0400 Subject: [PATCH] add secondary index to get proposals relevant to a particular account --- docs | 2 +- libraries/chain/db_init.cpp | 5 +- libraries/chain/db_update.cpp | 2 +- .../graphene/chain/proposal_object.hpp | 26 +++++++++- libraries/chain/proposal_evaluator.cpp | 2 +- libraries/chain/proposal_object.cpp | 48 +++++++++++++++++-- libraries/fc | 2 +- tests/tests/authority_tests.cpp | 38 +++++++-------- tests/tests/block_tests.cpp | 2 +- 9 files changed, 97 insertions(+), 30 deletions(-) diff --git a/docs b/docs index b893895d..71ed2984 160000 --- a/docs +++ b/docs @@ -1 +1 @@ -Subproject commit b893895d05b4f0d448aabd4f1d2112a7e35e1354 +Subproject commit 71ed2984b71d57cab13cdf12074cff150edc1d3d diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 7ccb01ec..06ac2f2e 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -122,7 +122,10 @@ void database::initialize_indexes() add_index< primary_index >(); add_index< primary_index >(); add_index< primary_index >(); - add_index< primary_index >(); + + auto prop_index = add_index< primary_index >(); + prop_index->add_secondary_index(); + add_index< primary_index >(); add_index< primary_index > >(); add_index< primary_index >(); diff --git a/libraries/chain/db_update.cpp b/libraries/chain/db_update.cpp index a51c3a99..9e0e7570 100644 --- a/libraries/chain/db_update.cpp +++ b/libraries/chain/db_update.cpp @@ -102,7 +102,7 @@ void database::clear_expired_proposals() const proposal_object& proposal = *proposal_expiration_index.begin(); processed_transaction result; try { - if( proposal.is_authorized_to_execute(this) ) + if( proposal.is_authorized_to_execute(*this) ) { result = push_proposal(proposal); //TODO: Do something with result so plugins can process it. diff --git a/libraries/chain/include/graphene/chain/proposal_object.hpp b/libraries/chain/include/graphene/chain/proposal_object.hpp index 1427c4c4..2debc8da 100644 --- a/libraries/chain/include/graphene/chain/proposal_object.hpp +++ b/libraries/chain/include/graphene/chain/proposal_object.hpp @@ -46,7 +46,31 @@ class proposal_object : public abstract_object flat_set available_owner_approvals; flat_set available_key_approvals; - bool is_authorized_to_execute(database* db)const; + bool is_authorized_to_execute(database& db)const; +}; + +/** + * @brief tracks all of the proposal objects that requrie approval of + * an individual account. + * + * @ingroup object + * @ingroup protocol + * + * This is a secondary index on the proposal_index + * + * @note the set of required approvals is constant + */ +class required_approval_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{}; + + void remove( account_id_type a, proposal_id_type p ); + + map > _account_to_proposals; }; struct by_expiration{}; diff --git a/libraries/chain/proposal_evaluator.cpp b/libraries/chain/proposal_evaluator.cpp index f65155aa..a7501468 100644 --- a/libraries/chain/proposal_evaluator.cpp +++ b/libraries/chain/proposal_evaluator.cpp @@ -133,7 +133,7 @@ void_result proposal_update_evaluator::do_apply(const proposal_update_operation& if( _proposal->review_period_time ) return void_result(); - if( _proposal->is_authorized_to_execute(&d) ) + if( _proposal->is_authorized_to_execute(d) ) { // All required approvals are satisfied. Execute! _executed_proposal = true; diff --git a/libraries/chain/proposal_object.cpp b/libraries/chain/proposal_object.cpp index cc148526..64778e36 100644 --- a/libraries/chain/proposal_object.cpp +++ b/libraries/chain/proposal_object.cpp @@ -21,9 +21,9 @@ namespace graphene { namespace chain { -bool proposal_object::is_authorized_to_execute(database* db) const +bool proposal_object::is_authorized_to_execute(database& db) const { - transaction_evaluation_state dry_run_eval(db); + transaction_evaluation_state dry_run_eval(&db); dry_run_eval._is_proposed_trx = true; std::transform(available_active_approvals.begin(), available_active_approvals.end(), std::inserter(dry_run_eval.approved_by, dry_run_eval.approved_by.end()), [](object_id_type id) { @@ -44,13 +44,53 @@ bool proposal_object::is_authorized_to_execute(database* db) const // Check all required approvals. If any of them are unsatisfied, return false. for( const auto& id : required_active_approvals ) - if( !dry_run_eval.check_authority(id(*db), authority::active) ) + if( !dry_run_eval.check_authority(id(db), authority::active) ) return false; for( const auto& id : required_owner_approvals ) - if( !dry_run_eval.check_authority(id(*db), authority::owner) ) + if( !dry_run_eval.check_authority(id(db), authority::owner) ) return false; return true; } + +void required_approval_index::object_inserted( const object& obj ) +{ + assert( dynamic_cast(&obj) ); + const proposal_object& p = static_cast(obj); + + for( const auto& a : p.required_active_approvals ) + _account_to_proposals[a].insert( p.id ); + for( const auto& a : p.required_owner_approvals ) + _account_to_proposals[a].insert( p.id ); + for( const auto& a : p.available_active_approvals ) + _account_to_proposals[a].insert( p.id ); + for( const auto& a : p.available_owner_approvals ) + _account_to_proposals[a].insert( p.id ); +} + +void required_approval_index::remove( account_id_type a, proposal_id_type p ) +{ + auto itr = _account_to_proposals.find(a); + if( itr != _account_to_proposals.end() ) + itr->second.erase(p); + if( itr->second.size() == 0 ) + _account_to_proposals.erase(itr); +} + +void required_approval_index::object_removed( const object& obj ) +{ + assert( dynamic_cast(&obj) ); + const proposal_object& p = static_cast(obj); + + for( const auto& a : p.required_active_approvals ) + remove( a, p.id ); + for( const auto& a : p.required_owner_approvals ) + remove( a, p.id ); + for( const auto& a : p.available_active_approvals ) + remove( a, p.id ); + for( const auto& a : p.available_owner_approvals ) + remove( a, p.id ); +} + } } // graphene::chain diff --git a/libraries/fc b/libraries/fc index fe7eed6b..a8b85f6d 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit fe7eed6bebac28313e4e7350eb77f8da27f6a427 +Subproject commit a8b85f6dcc4558b7a9913b59ef5dc19f3b5e62ca diff --git a/tests/tests/authority_tests.cpp b/tests/tests/authority_tests.cpp index 86e05493..ea3a0b2c 100644 --- a/tests/tests/authority_tests.cpp +++ b/tests/tests/authority_tests.cpp @@ -383,12 +383,12 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) BOOST_CHECK(prop.review_period_time && *prop.review_period_time == pop.expiration_time - *pop.review_period_seconds); BOOST_CHECK(prop.proposed_transaction.operations.size() == 1); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0); - BOOST_CHECK(!db.get(prop.id).is_authorized_to_execute(&db)); + BOOST_CHECK(!db.get(prop.id).is_authorized_to_execute(db)); generate_block(); BOOST_REQUIRE(db.find_object(prop.id)); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0); - BOOST_CHECK(!db.get(prop.id).is_authorized_to_execute(&db)); + BOOST_CHECK(!db.get(prop.id).is_authorized_to_execute(db)); trx.operations.clear(); trx.signatures.clear(); proposal_update_operation uop; @@ -409,7 +409,7 @@ BOOST_AUTO_TEST_CASE( genesis_authority ) trx.signatures[key_id_type(6)] = trx.signatures[key_id_type(1)]; db.push_transaction(trx); BOOST_CHECK_EQUAL(get_balance(nathan, asset_id_type()(db)), 0); - BOOST_CHECK(db.get(prop.id).is_authorized_to_execute(&db)); + BOOST_CHECK(db.get(prop.id).is_authorized_to_execute(db)); generate_blocks(*prop.review_period_time); uop.key_approvals_to_add = {key_id_type(7)}; @@ -457,7 +457,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) sign(trx, key_id_type(), genesis_key); const proposal_object& prop = db.get(PUSH_TX( db, trx ).operation_results.front().get()); proposal_id_type pid = prop.id; - BOOST_CHECK(!pid(db).is_authorized_to_execute(&db)); + BOOST_CHECK(!pid(db).is_authorized_to_execute(db)); //Genesis key approves of the proposal. proposal_update_operation uop; @@ -484,7 +484,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) trx.signatures[key_id_type(9)] = trx.signatures[key_id_type(1)]; trx.sign(key_id_type(), genesis_key); PUSH_TX( db, trx ); - BOOST_CHECK(pid(db).is_authorized_to_execute(&db)); + BOOST_CHECK(pid(db).is_authorized_to_execute(db)); //Time passes... the proposal is now in its review period. generate_blocks(*pid(db).review_period_time); @@ -492,7 +492,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) fc::time_point_sec maintenance_time = db.get_dynamic_global_properties().next_maintenance_time; BOOST_CHECK_LT(maintenance_time.sec_since_epoch(), pid(db).expiration_time.sec_since_epoch()); //Yay! The proposal to give nathan more money is authorized. - BOOST_CHECK(pid(db).is_authorized_to_execute(&db)); + BOOST_CHECK(pid(db).is_authorized_to_execute(db)); nathan = &get_account("nathan"); // no money yet @@ -515,7 +515,7 @@ BOOST_FIXTURE_TEST_CASE( fired_delegates, database_fixture ) //Time passes... the set of active delegates gets updated. generate_blocks(maintenance_time); //The proposal is no longer authorized, because the active delegates got changed. - BOOST_CHECK(!pid(db).is_authorized_to_execute(&db)); + BOOST_CHECK(!pid(db).is_authorized_to_execute(db)); // still no money BOOST_CHECK_EQUAL(get_balance(*nathan, asset_id_type()(db)), 5000); @@ -563,7 +563,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_two_accounts, database_fixture ) const proposal_object& prop = *db.get_index_type().indices().begin(); BOOST_CHECK(prop.required_active_approvals.size() == 2); BOOST_CHECK(prop.required_owner_approvals.size() == 0); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); { proposal_id_type pid = prop.id; @@ -577,7 +577,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_two_accounts, database_fixture ) trx.clear(); BOOST_CHECK(db.find_object(pid) != nullptr); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); uop.active_approvals_to_add = {dan.get_id()}; trx.operations.push_back(uop); @@ -627,7 +627,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_delete, database_fixture ) const proposal_object& prop = *db.get_index_type().indices().begin(); BOOST_CHECK(prop.required_active_approvals.size() == 2); BOOST_CHECK(prop.required_owner_approvals.size() == 0); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); { proposal_update_operation uop; @@ -638,7 +638,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_delete, database_fixture ) trx.sign(nathan_key_obj.id,nathan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_active_approvals.size(), 1); std::swap(uop.active_approvals_to_add, uop.active_approvals_to_remove); @@ -646,7 +646,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_delete, database_fixture ) trx.sign(nathan_key_obj.id,nathan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_active_approvals.size(), 0); } @@ -705,7 +705,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_delete, database_fixture ) const proposal_object& prop = *db.get_index_type().indices().begin(); BOOST_CHECK_EQUAL(prop.required_active_approvals.size(), 1); BOOST_CHECK_EQUAL(prop.required_owner_approvals.size(), 1); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); { proposal_update_operation uop; @@ -716,7 +716,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_delete, database_fixture ) trx.sign(nathan_key_obj.id,nathan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_owner_approvals.size(), 1); std::swap(uop.owner_approvals_to_add, uop.owner_approvals_to_remove); @@ -724,7 +724,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_delete, database_fixture ) trx.sign(nathan_key_obj.id,nathan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_owner_approvals.size(), 0); } @@ -784,7 +784,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_complete, database_fixture ) const proposal_object& prop = *db.get_index_type().indices().begin(); BOOST_CHECK_EQUAL(prop.required_active_approvals.size(), 1); BOOST_CHECK_EQUAL(prop.required_owner_approvals.size(), 1); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); { proposal_id_type pid = prop.id; @@ -797,7 +797,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_complete, database_fixture ) trx.sign(dan_key_obj.id,dan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_key_approvals.size(), 1); std::swap(uop.key_approvals_to_add, uop.key_approvals_to_remove); @@ -806,7 +806,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_complete, database_fixture ) trx.sign(dan_key_obj.id,dan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_key_approvals.size(), 0); std::swap(uop.key_approvals_to_add, uop.key_approvals_to_remove); @@ -817,7 +817,7 @@ BOOST_FIXTURE_TEST_CASE( proposal_owner_authority_complete, database_fixture ) trx.sign(dan_key_obj.id,dan_key); PUSH_TX( db, trx ); trx.clear(); - BOOST_CHECK(!prop.is_authorized_to_execute(&db)); + BOOST_CHECK(!prop.is_authorized_to_execute(db)); BOOST_CHECK_EQUAL(prop.available_key_approvals.size(), 1); uop.key_approvals_to_add.clear(); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index f838dc34..98516cb8 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -611,7 +611,7 @@ BOOST_FIXTURE_TEST_CASE( change_block_interval, database_fixture ) trx.sign(get_account("init6").active.get_keys().front(),delegate_priv_key); trx.sign(get_account("init7").active.get_keys().front(),delegate_priv_key); db.push_transaction(trx); - BOOST_CHECK(proposal_id_type()(db).is_authorized_to_execute(&db)); + BOOST_CHECK(proposal_id_type()(db).is_authorized_to_execute(db)); } BOOST_CHECK_EQUAL(db.get_global_properties().parameters.block_interval, 5);