diff --git a/libraries/chain/custom_permission_evaluator.cpp b/libraries/chain/custom_permission_evaluator.cpp index ae319420..dff6d110 100644 --- a/libraries/chain/custom_permission_evaluator.cpp +++ b/libraries/chain/custom_permission_evaluator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace graphene @@ -105,7 +106,21 @@ void_result delete_custom_permission_evaluator::do_apply(const custom_permission { database &d = db(); const custom_permission_object &pobj = op.permission_id(d); - // TODO: Remove all the custom_account_authority_object linked to this permission object. + // Remove the account authority objects linked to this permission + const auto& cindex = d.get_index_type().indices().get(); + vector> custom_auths; + auto crange = cindex.equal_range(boost::make_tuple(pobj.id)); + // Store the references to the account authorities + for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second)) + { + custom_auths.push_back(cobj); + } + // Now remove the account authorities + for(const auto& cauth : custom_auths) + { + d.remove(cauth); + } + // Now finally remove the permission d.remove(pobj); return void_result(); } @@ -113,4 +128,4 @@ void_result delete_custom_permission_evaluator::do_apply(const custom_permission } } // namespace chain -} // namespace graphene \ No newline at end of file +} // namespace graphene diff --git a/libraries/chain/db_maint.cpp b/libraries/chain/db_maint.cpp index 11a2b426..d300a34b 100644 --- a/libraries/chain/db_maint.cpp +++ b/libraries/chain/db_maint.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #define USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX // vesting_balance_object by_asset_balance index needed @@ -933,6 +934,15 @@ void rolling_period_start(database& db) } } +void clear_expired_custom_account_authorities(database& db) +{ + const auto& cindex = db.get_index_type().indices().get(); + while(!cindex.empty() && cindex.begin()->valid_to < db.head_block_time()) + { + db.remove(*cindex.begin()); + } +} + // Schedules payouts from a dividend distribution account to the current holders of the // dividend-paying asset. This takes any deposits made to the dividend distribution account // since the last time it was called, and distributes them to the current owners of the @@ -1707,7 +1717,10 @@ void database::perform_chain_maintenance(const signed_block& next_block, const g //for( const asset_bitasset_data_object* d : get_index_type() ) for( const auto& d : get_index_type().indices() ) modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); - + // Ideally we have to do this after every block but that leads to longer block applicaiton/replay times. + // So keep it here as it is not critical. valid_to check ensures + // these custom account auths are not usable. + clear_expired_custom_account_authorities(*this); // process_budget needs to run at the bottom because // it needs to know the next_maintenance_time process_budget(); diff --git a/tests/tests/custom_permission_tests.cpp b/tests/tests/custom_permission_tests.cpp index ff037995..e2015b58 100644 --- a/tests/tests/custom_permission_tests.cpp +++ b/tests/tests/custom_permission_tests.cpp @@ -93,11 +93,17 @@ BOOST_AUTO_TEST_CASE(permission_create_success_test) generate_blocks(HARDFORK_RBAC_TIME); generate_block(); set_expiration(db, trx); - ACTORS((alice)(bob)); + ACTORS((alice)(bob)(charlie)(dave)(erin)); upgrade_to_lifetime_member(alice); upgrade_to_lifetime_member(bob); + upgrade_to_lifetime_member(charlie); + upgrade_to_lifetime_member(dave); + upgrade_to_lifetime_member(erin); transfer(committee_account, alice_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION)); transfer(committee_account, bob_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + transfer(committee_account, charlie_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + transfer(committee_account, dave_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION)); + transfer(committee_account, erin_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION)); const auto &pidx = db.get_index_type().indices().get(); // Alice creates a permission abc { @@ -138,7 +144,7 @@ BOOST_AUTO_TEST_CASE(permission_update_test) INVOKE(permission_create_success_test); GET_ACTOR(alice); GET_ACTOR(bob); - ACTORS((charlie)); + GET_ACTOR(charlie); const auto &pidx = db.get_index_type().indices().get(); BOOST_REQUIRE(pidx.size() == 1); BOOST_REQUIRE(custom_permission_id_type(0)(db).permission_name == "abc"); @@ -210,56 +216,6 @@ BOOST_AUTO_TEST_CASE(permission_update_test) FC_LOG_AND_RETHROW() } -BOOST_AUTO_TEST_CASE(permission_delete_test) -{ - try - { - INVOKE(permission_create_success_test); - GET_ACTOR(alice); - GET_ACTOR(bob); - const auto &pidx = db.get_index_type().indices().get(); - BOOST_REQUIRE(pidx.size() == 1); - BOOST_REQUIRE(custom_permission_id_type(0)(db).permission_name == "abc"); - BOOST_REQUIRE(custom_permission_id_type(0)(db).auth == authority(1, bob_id, 1)); - // Alice tries to delete permission abc with wrong owner_account - { - custom_permission_delete_operation op; - op.permission_id = custom_permission_id_type(0); - op.owner_account = bob_id; - trx.operations.push_back(op); - sign(trx, bob_private_key); - BOOST_CHECK_THROW(PUSH_TX(db, trx), fc::exception); - trx.clear(); - BOOST_REQUIRE(pidx.size() == 1); - } - // Alice tries to delete permission abc with wrong permission_id - { - custom_permission_delete_operation op; - op.permission_id = custom_permission_id_type(1); - op.owner_account = alice_id; - trx.operations.push_back(op); - sign(trx, alice_private_key); - BOOST_CHECK_THROW(PUSH_TX(db, trx), fc::exception); - trx.clear(); - BOOST_REQUIRE(pidx.size() == 1); - } - // Alice deletes permission abc - { - BOOST_REQUIRE(custom_permission_id_type(0)(db).permission_name == "abc"); - BOOST_REQUIRE(custom_permission_id_type(0)(db).auth == authority(1, bob_id, 1)); - custom_permission_delete_operation op; - op.permission_id = custom_permission_id_type(0); - op.owner_account = alice_id; - trx.operations.push_back(op); - sign(trx, alice_private_key); - PUSH_TX(db, trx); - trx.clear(); - BOOST_REQUIRE(pidx.size() == 0); - } - } - FC_LOG_AND_RETHROW() -} - BOOST_AUTO_TEST_CASE(account_authority_create_test) { try @@ -279,7 +235,7 @@ BOOST_AUTO_TEST_CASE(account_authority_create_test) op.permission_id = custom_permission_id_type(0); op.valid_from = db.head_block_time(); op.valid_to = db.head_block_time() + fc::seconds(10 * db.block_interval()); - op.operation_type = 0; + op.operation_type = operation::tag::value; op.owner_account = alice_id; trx.operations.push_back(op); sign(trx, alice_private_key); @@ -294,7 +250,7 @@ BOOST_AUTO_TEST_CASE(account_authority_create_test) op.permission_id = custom_permission_id_type(0); op.valid_from = db.head_block_time(); op.valid_to = db.head_block_time() + fc::seconds(11 * db.block_interval()); - op.operation_type = 0; + op.operation_type = operation::tag::value; op.owner_account = alice_id; trx.operations.push_back(op); sign(trx, alice_private_key); @@ -379,6 +335,57 @@ BOOST_AUTO_TEST_CASE(account_authority_delete_test) FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE(permission_delete_test) +{ + try + { + INVOKE(account_authority_create_test); + GET_ACTOR(alice); + GET_ACTOR(bob); + const auto &pidx = db.get_index_type().indices().get(); + const auto &cidx = db.get_index_type().indices().get(); + BOOST_REQUIRE(pidx.size() == 1); + BOOST_REQUIRE(custom_permission_id_type(0)(db).permission_name == "abc"); + BOOST_REQUIRE(custom_permission_id_type(0)(db).auth == authority(1, bob_id, 1)); + BOOST_REQUIRE(cidx.size() == 2); + // Alice tries to delete permission abc with wrong owner_account + { + custom_permission_delete_operation op; + op.permission_id = custom_permission_id_type(0); + op.owner_account = bob_id; + trx.operations.push_back(op); + sign(trx, bob_private_key); + BOOST_CHECK_THROW(PUSH_TX(db, trx), fc::exception); + trx.clear(); + BOOST_REQUIRE(pidx.size() == 1); + } + // Alice tries to delete permission abc with wrong permission_id + { + custom_permission_delete_operation op; + op.permission_id = custom_permission_id_type(1); + op.owner_account = alice_id; + trx.operations.push_back(op); + sign(trx, alice_private_key); + BOOST_CHECK_THROW(PUSH_TX(db, trx), fc::exception); + trx.clear(); + BOOST_REQUIRE(pidx.size() == 1); + } + // Alice deletes permission abc + { + custom_permission_delete_operation op; + op.permission_id = custom_permission_id_type(0); + op.owner_account = alice_id; + trx.operations.push_back(op); + sign(trx, alice_private_key); + PUSH_TX(db, trx); + trx.clear(); + BOOST_REQUIRE(pidx.size() == 0); + BOOST_REQUIRE(cidx.size() == 0); + } + } + FC_LOG_AND_RETHROW() +} + BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) { try @@ -390,6 +397,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) const auto &cidx = db.get_index_type().indices().get(); BOOST_REQUIRE(pidx.size() == 1); BOOST_REQUIRE(cidx.size() == 2); + // alice->bob transfer_operation op with active auth, success generate_block(); { transfer_operation op; @@ -404,7 +412,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) trx.clear(); generate_block(); } - + // alice->bob transfer_operation op with the created custom account auth, success { transfer_operation op; op.amount.asset_id = asset_id_type(0); @@ -418,7 +426,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) trx.clear(); generate_block(); } - + // alice->bob transfer_operation op with extra unnecessary sigs (both active and the custom auth), fails { transfer_operation op; op.amount.asset_id = asset_id_type(0); @@ -433,7 +441,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) trx.clear(); generate_block(); } - + // bob->alice transfer_operation op with alice active auth sig, fails { transfer_operation op; op.amount.asset_id = asset_id_type(0); @@ -447,6 +455,20 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test) trx.clear(); generate_block(); } + // bob->alice transfer_operation op with bob active auth sig, success + { + transfer_operation op; + op.amount.asset_id = asset_id_type(0); + op.amount.amount = 100 * GRAPHENE_BLOCKCHAIN_PRECISION; + op.from = bob_id; + op.to = alice_id; + op.fee.asset_id = asset_id_type(0); + trx.operations.push_back(op); + sign(trx, bob_private_key); + PUSH_TX(db, trx); + trx.clear(); + generate_block(); + } } FC_LOG_AND_RETHROW() }