rbac5 - clear expired and deleted permission linked auths

This commit is contained in:
sierra19XX 2020-05-29 10:42:24 +00:00
parent 4c2efdb871
commit 88a8753a60
3 changed files with 110 additions and 60 deletions

View file

@ -2,6 +2,7 @@
#include <graphene/chain/database.hpp> #include <graphene/chain/database.hpp>
#include <graphene/chain/custom_permission_object.hpp> #include <graphene/chain/custom_permission_object.hpp>
#include <graphene/chain/custom_account_authority_object.hpp>
#include <graphene/chain/hardfork.hpp> #include <graphene/chain/hardfork.hpp>
namespace graphene namespace graphene
@ -105,7 +106,21 @@ void_result delete_custom_permission_evaluator::do_apply(const custom_permission
{ {
database &d = db(); database &d = db();
const custom_permission_object &pobj = op.permission_id(d); 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<custom_account_authority_index>().indices().get<by_permission_and_op>();
vector<std::reference_wrapper<const custom_account_authority_object>> 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); d.remove(pobj);
return void_result(); return void_result();
} }

View file

@ -47,6 +47,7 @@
#include <graphene/chain/witness_object.hpp> #include <graphene/chain/witness_object.hpp>
#include <graphene/chain/witness_schedule_object.hpp> #include <graphene/chain/witness_schedule_object.hpp>
#include <graphene/chain/worker_object.hpp> #include <graphene/chain/worker_object.hpp>
#include <graphene/chain/custom_account_authority_object.hpp>
#define USE_VESTING_OBJECT_BY_ASSET_BALANCE_INDEX // vesting_balance_object by_asset_balance index needed #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<custom_account_authority_index>().indices().get<by_expiration>();
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 // 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 // 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 // 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<asset_bitasset_data_index>() ) //for( const asset_bitasset_data_object* d : get_index_type<asset_bitasset_data_index>() )
for( const auto& d : get_index_type<asset_bitasset_data_index>().indices() ) for( const auto& d : get_index_type<asset_bitasset_data_index>().indices() )
modify( d, [](asset_bitasset_data_object& o) { o.force_settled_volume = 0; }); 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 // process_budget needs to run at the bottom because
// it needs to know the next_maintenance_time // it needs to know the next_maintenance_time
process_budget(); process_budget();

View file

@ -93,11 +93,17 @@ BOOST_AUTO_TEST_CASE(permission_create_success_test)
generate_blocks(HARDFORK_RBAC_TIME); generate_blocks(HARDFORK_RBAC_TIME);
generate_block(); generate_block();
set_expiration(db, trx); set_expiration(db, trx);
ACTORS((alice)(bob)); ACTORS((alice)(bob)(charlie)(dave)(erin));
upgrade_to_lifetime_member(alice); upgrade_to_lifetime_member(alice);
upgrade_to_lifetime_member(bob); 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, alice_id, asset(1000 * GRAPHENE_BLOCKCHAIN_PRECISION));
transfer(committee_account, bob_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<custom_permission_index>().indices().get<by_id>(); const auto &pidx = db.get_index_type<custom_permission_index>().indices().get<by_id>();
// Alice creates a permission abc // Alice creates a permission abc
{ {
@ -138,7 +144,7 @@ BOOST_AUTO_TEST_CASE(permission_update_test)
INVOKE(permission_create_success_test); INVOKE(permission_create_success_test);
GET_ACTOR(alice); GET_ACTOR(alice);
GET_ACTOR(bob); GET_ACTOR(bob);
ACTORS((charlie)); GET_ACTOR(charlie);
const auto &pidx = db.get_index_type<custom_permission_index>().indices().get<by_id>(); const auto &pidx = db.get_index_type<custom_permission_index>().indices().get<by_id>();
BOOST_REQUIRE(pidx.size() == 1); BOOST_REQUIRE(pidx.size() == 1);
BOOST_REQUIRE(custom_permission_id_type(0)(db).permission_name == "abc"); 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() 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<custom_permission_index>().indices().get<by_id>();
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) BOOST_AUTO_TEST_CASE(account_authority_create_test)
{ {
try try
@ -279,7 +235,7 @@ BOOST_AUTO_TEST_CASE(account_authority_create_test)
op.permission_id = custom_permission_id_type(0); op.permission_id = custom_permission_id_type(0);
op.valid_from = db.head_block_time(); op.valid_from = db.head_block_time();
op.valid_to = db.head_block_time() + fc::seconds(10 * db.block_interval()); op.valid_to = db.head_block_time() + fc::seconds(10 * db.block_interval());
op.operation_type = 0; op.operation_type = operation::tag<transfer_operation>::value;
op.owner_account = alice_id; op.owner_account = alice_id;
trx.operations.push_back(op); trx.operations.push_back(op);
sign(trx, alice_private_key); 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.permission_id = custom_permission_id_type(0);
op.valid_from = db.head_block_time(); op.valid_from = db.head_block_time();
op.valid_to = db.head_block_time() + fc::seconds(11 * db.block_interval()); op.valid_to = db.head_block_time() + fc::seconds(11 * db.block_interval());
op.operation_type = 0; op.operation_type = operation::tag<transfer_operation>::value;
op.owner_account = alice_id; op.owner_account = alice_id;
trx.operations.push_back(op); trx.operations.push_back(op);
sign(trx, alice_private_key); sign(trx, alice_private_key);
@ -379,6 +335,57 @@ BOOST_AUTO_TEST_CASE(account_authority_delete_test)
FC_LOG_AND_RETHROW() 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<custom_permission_index>().indices().get<by_id>();
const auto &cidx = db.get_index_type<custom_account_authority_index>().indices().get<by_id>();
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) BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
{ {
try try
@ -390,6 +397,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
const auto &cidx = db.get_index_type<custom_account_authority_index>().indices().get<by_id>(); const auto &cidx = db.get_index_type<custom_account_authority_index>().indices().get<by_id>();
BOOST_REQUIRE(pidx.size() == 1); BOOST_REQUIRE(pidx.size() == 1);
BOOST_REQUIRE(cidx.size() == 2); BOOST_REQUIRE(cidx.size() == 2);
// alice->bob transfer_operation op with active auth, success
generate_block(); generate_block();
{ {
transfer_operation op; transfer_operation op;
@ -404,7 +412,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
trx.clear(); trx.clear();
generate_block(); generate_block();
} }
// alice->bob transfer_operation op with the created custom account auth, success
{ {
transfer_operation op; transfer_operation op;
op.amount.asset_id = asset_id_type(0); op.amount.asset_id = asset_id_type(0);
@ -418,7 +426,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
trx.clear(); trx.clear();
generate_block(); generate_block();
} }
// alice->bob transfer_operation op with extra unnecessary sigs (both active and the custom auth), fails
{ {
transfer_operation op; transfer_operation op;
op.amount.asset_id = asset_id_type(0); op.amount.asset_id = asset_id_type(0);
@ -433,7 +441,7 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
trx.clear(); trx.clear();
generate_block(); generate_block();
} }
// bob->alice transfer_operation op with alice active auth sig, fails
{ {
transfer_operation op; transfer_operation op;
op.amount.asset_id = asset_id_type(0); op.amount.asset_id = asset_id_type(0);
@ -447,6 +455,20 @@ BOOST_AUTO_TEST_CASE(transfer_op_custom_permission_test)
trx.clear(); trx.clear();
generate_block(); 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() FC_LOG_AND_RETHROW()
} }