Compare commits
13 commits
master
...
feature/rb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e9f31f03d5 | ||
|
|
3f9965b213 | ||
|
|
f3cf062a42 | ||
|
|
c43ff2e53d | ||
|
|
4c2ea61c48 | ||
|
|
8ee292053a | ||
|
|
29e3802954 | ||
|
|
88a8753a60 | ||
|
|
4c2efdb871 | ||
|
|
b1124a166f | ||
|
|
f376503ac6 | ||
|
|
c74e83d088 | ||
|
|
2a7c8749d3 |
33 changed files with 2996 additions and 42 deletions
|
|
@ -30,26 +30,4 @@ test:
|
|||
- ./tests/chain_test
|
||||
- ./tests/cli_test
|
||||
tags:
|
||||
- builder
|
||||
|
||||
code_quality:
|
||||
stage: test
|
||||
image: docker:stable
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
allow_failure: true
|
||||
services:
|
||||
- docker:stable-dind
|
||||
script:
|
||||
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
||||
- docker run
|
||||
--env SOURCE_CODE="$PWD"
|
||||
--volume "$PWD":/code
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock
|
||||
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
|
||||
artifacts:
|
||||
paths: [gl-code-quality-report.json]
|
||||
expire_in: 1 week
|
||||
except:
|
||||
variables:
|
||||
- $CODE_QUALITY_DISABLED
|
||||
- builder
|
||||
|
|
@ -184,6 +184,14 @@ class database_api_impl : public std::enable_shared_from_this<database_api_impl>
|
|||
// gpos
|
||||
gpos_info get_gpos_info(const account_id_type account) const;
|
||||
|
||||
// rbac
|
||||
vector<custom_permission_object> get_custom_permissions(const account_id_type account) const;
|
||||
fc::optional<custom_permission_object> get_custom_permission_by_name(const account_id_type account, const string& permission_name) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities(const account_id_type account) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const;
|
||||
vector<authority> get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const;
|
||||
|
||||
//private:
|
||||
const account_object* get_account_from_string( const std::string& name_or_id,
|
||||
bool throw_if_not_found = true ) const;
|
||||
|
|
@ -1857,6 +1865,9 @@ set<public_key_type> database_api_impl::get_required_signatures( const signed_tr
|
|||
available_keys,
|
||||
[&]( account_id_type id ){ return &id(_db).active; },
|
||||
[&]( account_id_type id ){ return &id(_db).owner; },
|
||||
[&]( account_id_type id, const operation& op ) {
|
||||
return _db.get_account_custom_authorities(id, op);
|
||||
},
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
wdump((result));
|
||||
return result;
|
||||
|
|
@ -1892,6 +1903,17 @@ set<public_key_type> database_api_impl::get_potential_signatures( const signed_t
|
|||
result.insert(k);
|
||||
return &auth;
|
||||
},
|
||||
[&]( account_id_type id, const operation& op ) {
|
||||
vector<authority> custom_auths = _db.get_account_custom_authorities(id, op);
|
||||
for (const auto& cauth: custom_auths)
|
||||
{
|
||||
for (const auto& k : cauth.get_keys())
|
||||
{
|
||||
result.insert(k);
|
||||
}
|
||||
}
|
||||
return custom_auths;
|
||||
},
|
||||
_db.get_global_properties().parameters.max_authority_depth
|
||||
);
|
||||
|
||||
|
|
@ -1919,6 +1941,9 @@ set<address> database_api_impl::get_potential_address_signatures( const signed_t
|
|||
result.insert(k);
|
||||
return &auth;
|
||||
},
|
||||
[&]( account_id_type id, const operation& op ) {
|
||||
return _db.get_account_custom_authorities(id, op);
|
||||
},
|
||||
_db.get_global_properties().parameters.max_authority_depth
|
||||
);
|
||||
return result;
|
||||
|
|
@ -1934,6 +1959,8 @@ bool database_api_impl::verify_authority( const signed_transaction& trx )const
|
|||
trx.verify_authority( _db.get_chain_id(),
|
||||
[this]( account_id_type id ){ return &id(_db).active; },
|
||||
[this]( account_id_type id ){ return &id(_db).owner; },
|
||||
[this]( account_id_type id, const operation& op ) {
|
||||
return _db.get_account_custom_authorities(id, op); },
|
||||
_db.get_global_properties().parameters.max_authority_depth );
|
||||
return true;
|
||||
}
|
||||
|
|
@ -2303,6 +2330,118 @@ graphene::app::gpos_info database_api_impl::get_gpos_info(const account_id_type
|
|||
return result;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// RBAC methods //
|
||||
// //
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
vector<custom_permission_object> database_api::get_custom_permissions(const account_id_type account) const
|
||||
{
|
||||
return my->get_custom_permissions(account);
|
||||
}
|
||||
|
||||
vector<custom_permission_object> database_api_impl::get_custom_permissions(const account_id_type account) const
|
||||
{
|
||||
const auto& pindex = _db.get_index_type<custom_permission_index>().indices().get<by_account_and_permission>();
|
||||
auto prange = pindex.equal_range(boost::make_tuple(account));
|
||||
vector<custom_permission_object> custom_permissions;
|
||||
for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second))
|
||||
{
|
||||
custom_permissions.push_back(pobj);
|
||||
}
|
||||
return custom_permissions;
|
||||
}
|
||||
|
||||
fc::optional<custom_permission_object> database_api::get_custom_permission_by_name(const account_id_type account, const string& permission_name) const
|
||||
{
|
||||
return my->get_custom_permission_by_name(account, permission_name);
|
||||
}
|
||||
|
||||
fc::optional<custom_permission_object> database_api_impl::get_custom_permission_by_name(const account_id_type account, const string& permission_name) const
|
||||
{
|
||||
const auto& pindex = _db.get_index_type<custom_permission_index>().indices().get<by_account_and_permission>();
|
||||
auto prange = pindex.equal_range(boost::make_tuple(account, permission_name));
|
||||
for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second))
|
||||
{
|
||||
return pobj;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api::get_custom_account_authorities(const account_id_type account) const
|
||||
{
|
||||
return my->get_custom_account_authorities(account);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api_impl::get_custom_account_authorities(const account_id_type account) const
|
||||
{
|
||||
const auto& pindex = _db.get_index_type<custom_permission_index>().indices().get<by_account_and_permission>();
|
||||
const auto& cindex = _db.get_index_type<custom_account_authority_index>().indices().get<by_permission_and_op>();
|
||||
vector<custom_account_authority_object> custom_account_auths;
|
||||
auto prange = pindex.equal_range(boost::make_tuple(account));
|
||||
for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second))
|
||||
{
|
||||
auto crange = cindex.equal_range(boost::make_tuple(pobj.id));
|
||||
for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second))
|
||||
{
|
||||
custom_account_auths.push_back(cobj);
|
||||
}
|
||||
}
|
||||
return custom_account_auths;
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const
|
||||
{
|
||||
return my->get_custom_account_authorities_by_permission_id(permission_id);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api_impl::get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const
|
||||
{
|
||||
const auto& cindex = _db.get_index_type<custom_account_authority_index>().indices().get<by_permission_and_op>();
|
||||
vector<custom_account_authority_object> custom_account_auths;
|
||||
auto crange = cindex.equal_range(boost::make_tuple(permission_id));
|
||||
for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second))
|
||||
{
|
||||
custom_account_auths.push_back(cobj);
|
||||
}
|
||||
return custom_account_auths;
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api::get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const
|
||||
{
|
||||
return my->get_custom_account_authorities_by_permission_name(account, permission_name);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> database_api_impl::get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const
|
||||
{
|
||||
vector<custom_account_authority_object> custom_account_auths;
|
||||
fc::optional<custom_permission_object> pobj = get_custom_permission_by_name(account, permission_name);
|
||||
if(!pobj)
|
||||
{
|
||||
return custom_account_auths;
|
||||
}
|
||||
const auto& cindex = _db.get_index_type<custom_account_authority_index>().indices().get<by_permission_and_op>();
|
||||
auto crange = cindex.equal_range(boost::make_tuple(pobj->id));
|
||||
for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second))
|
||||
{
|
||||
custom_account_auths.push_back(cobj);
|
||||
}
|
||||
return custom_account_auths;
|
||||
}
|
||||
|
||||
vector<authority> database_api::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const
|
||||
{
|
||||
return my->get_active_custom_account_authorities_by_operation(account, operation_type);
|
||||
}
|
||||
|
||||
vector<authority> database_api_impl::get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const
|
||||
{
|
||||
operation op;
|
||||
op.set_which(operation_type);
|
||||
return _db.get_account_custom_authorities(account, op);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// Private methods //
|
||||
|
|
|
|||
|
|
@ -48,6 +48,9 @@
|
|||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/tournament_object.hpp>
|
||||
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
|
||||
#include <graphene/market_history/market_history_plugin.hpp>
|
||||
|
||||
#include <fc/api.hpp>
|
||||
|
|
@ -709,6 +712,18 @@ class database_api
|
|||
*/
|
||||
gpos_info get_gpos_info(const account_id_type account) const;
|
||||
|
||||
//////////
|
||||
// RBAC //
|
||||
//////////
|
||||
/**
|
||||
* @return account and custom permissions/account-authorities info
|
||||
*/
|
||||
vector<custom_permission_object> get_custom_permissions(const account_id_type account) const;
|
||||
fc::optional<custom_permission_object> get_custom_permission_by_name(const account_id_type account, const string& permission_name) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities(const account_id_type account) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_id(const custom_permission_id_type permission_id) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_name(const account_id_type account, const string& permission_name) const;
|
||||
vector<authority> get_active_custom_account_authorities_by_operation(const account_id_type account, int operation_type) const;
|
||||
|
||||
|
||||
private:
|
||||
|
|
@ -848,4 +863,12 @@ FC_API(graphene::app::database_api,
|
|||
|
||||
// gpos
|
||||
(get_gpos_info)
|
||||
|
||||
//rbac
|
||||
(get_custom_permissions)
|
||||
(get_custom_permission_by_name)
|
||||
(get_custom_account_authorities)
|
||||
(get_custom_account_authorities_by_permission_id)
|
||||
(get_custom_account_authorities_by_permission_name)
|
||||
(get_active_custom_account_authorities_by_operation)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,8 @@ add_library( graphene_chain
|
|||
protocol/vote.cpp
|
||||
protocol/tournament.cpp
|
||||
protocol/small_ops.cpp
|
||||
protocol/custom_permission.cpp
|
||||
protocol/custom_account_authority.cpp
|
||||
|
||||
genesis_state.cpp
|
||||
get_config.cpp
|
||||
|
|
@ -112,6 +114,8 @@ add_library( graphene_chain
|
|||
betting_market_evaluator.cpp
|
||||
betting_market_object.cpp
|
||||
betting_market_group_object.cpp
|
||||
custom_permission_evaluator.cpp
|
||||
custom_account_authority_evaluator.cpp
|
||||
|
||||
affiliate_payout.cpp
|
||||
|
||||
|
|
|
|||
147
libraries/chain/custom_account_authority_evaluator.cpp
Normal file
147
libraries/chain/custom_account_authority_evaluator.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
#include <graphene/chain/custom_account_authority_evaluator.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
struct rbac_operation_hardfork_visitor
|
||||
{
|
||||
typedef void result_type;
|
||||
const fc::time_point_sec block_time;
|
||||
|
||||
rbac_operation_hardfork_visitor(const fc::time_point_sec bt) : block_time(bt) {}
|
||||
void operator()(int op_type) const
|
||||
{
|
||||
int first_allowed_op = operation::tag<custom_permission_create_operation>::value;
|
||||
switch (op_type)
|
||||
{
|
||||
case operation::tag<custom_permission_create_operation>::value:
|
||||
case operation::tag<custom_permission_update_operation>::value:
|
||||
case operation::tag<custom_permission_delete_operation>::value:
|
||||
case operation::tag<custom_account_authority_create_operation>::value:
|
||||
case operation::tag<custom_account_authority_update_operation>::value:
|
||||
case operation::tag<custom_account_authority_delete_operation>::value:
|
||||
FC_ASSERT(block_time >= HARDFORK_RBAC_TIME, "Custom permission not allowed on this operation yet!");
|
||||
break;
|
||||
default:
|
||||
FC_ASSERT(op_type < first_allowed_op, "Custom permission not allowed on this operation!");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void_result create_custom_account_authority_evaluator::do_evaluate(const custom_account_authority_create_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
const custom_permission_object &pobj = op.permission_id(d);
|
||||
FC_ASSERT(pobj.account == op.owner_account, "Only owner account can update account authority object");
|
||||
FC_ASSERT(op.valid_to > now, "valid_to expiry should be in future");
|
||||
rbac_operation_hardfork_visitor rvtor(now);
|
||||
rvtor(op.operation_type);
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
object_id_type create_custom_account_authority_evaluator::do_apply(const custom_account_authority_create_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
return d.create<custom_account_authority_object>([&op](custom_account_authority_object &obj) mutable {
|
||||
obj.permission_id = op.permission_id;
|
||||
obj.operation_type = op.operation_type;
|
||||
obj.valid_from = op.valid_from;
|
||||
obj.valid_to = op.valid_to;
|
||||
})
|
||||
.id;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result update_custom_account_authority_evaluator::do_evaluate(const custom_account_authority_update_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
const custom_account_authority_object &aobj = op.auth_id(d);
|
||||
const custom_permission_object &pobj = aobj.permission_id(d);
|
||||
FC_ASSERT(pobj.account == op.owner_account, "Only owner account can update account authority object");
|
||||
auto valid_from = aobj.valid_from;
|
||||
auto valid_to = aobj.valid_to;
|
||||
if (op.new_valid_from)
|
||||
{
|
||||
valid_from = *op.new_valid_from;
|
||||
}
|
||||
|
||||
if (op.new_valid_to)
|
||||
{
|
||||
FC_ASSERT(*op.new_valid_to > now, "New valid_to expiry should be in the future");
|
||||
valid_to = *op.new_valid_to;
|
||||
}
|
||||
FC_ASSERT(valid_from < valid_to, "valid_from should be before valid_to");
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
object_id_type update_custom_account_authority_evaluator::do_apply(const custom_account_authority_update_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
const custom_account_authority_object &aobj = op.auth_id(d);
|
||||
d.modify(aobj, [&op](custom_account_authority_object &obj) {
|
||||
if (op.new_valid_from)
|
||||
obj.valid_from = *op.new_valid_from;
|
||||
if (op.new_valid_to)
|
||||
obj.valid_to = *op.new_valid_to;
|
||||
});
|
||||
return op.auth_id;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result delete_custom_account_authority_evaluator::do_evaluate(const custom_account_authority_delete_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
const custom_account_authority_object &aobj = op.auth_id(d);
|
||||
const custom_permission_object &pobj = aobj.permission_id(d);
|
||||
FC_ASSERT(pobj.account == op.owner_account, "Only owner account can delete account authority object");
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result delete_custom_account_authority_evaluator::do_apply(const custom_account_authority_delete_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
const custom_account_authority_object &aobj = op.auth_id(d);
|
||||
d.remove(aobj);
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
131
libraries/chain/custom_permission_evaluator.cpp
Normal file
131
libraries/chain/custom_permission_evaluator.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
#include <graphene/chain/custom_permission_evaluator.hpp>
|
||||
|
||||
#include <graphene/chain/database.hpp>
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
#include <graphene/chain/hardfork.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
void_result create_custom_permission_evaluator::do_evaluate(const custom_permission_create_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
for (const auto &account_weight_pair : op.auth.account_auths)
|
||||
{
|
||||
account_weight_pair.first(d);
|
||||
}
|
||||
|
||||
const auto &pindex = d.get_index_type<custom_permission_index>().indices().get<by_account_and_permission>();
|
||||
auto pitr = pindex.find(boost::make_tuple(op.owner_account, op.permission_name));
|
||||
FC_ASSERT(pitr == pindex.end(), "Permission name already exists for the given account");
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
object_id_type create_custom_permission_evaluator::do_apply(const custom_permission_create_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
return d.create<custom_permission_object>([&op](custom_permission_object &obj) mutable {
|
||||
obj.account = op.owner_account;
|
||||
obj.permission_name = op.permission_name;
|
||||
obj.auth = op.auth;
|
||||
})
|
||||
.id;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result update_custom_permission_evaluator::do_evaluate(const custom_permission_update_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
const custom_permission_object &pobj = op.permission_id(d);
|
||||
FC_ASSERT(pobj.account == op.owner_account, "Only owner account can update permission object");
|
||||
if (op.new_auth)
|
||||
{
|
||||
FC_ASSERT(!(*op.new_auth == pobj.auth), "New authority provided is not different from old authority");
|
||||
for (const auto &account_weight_pair : op.new_auth->account_auths)
|
||||
{
|
||||
account_weight_pair.first(d);
|
||||
}
|
||||
}
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
object_id_type update_custom_permission_evaluator::do_apply(const custom_permission_update_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
const custom_permission_object &pobj = op.permission_id(d);
|
||||
d.modify(pobj, [&op](custom_permission_object &obj) {
|
||||
if (op.new_auth)
|
||||
obj.auth = *op.new_auth;
|
||||
});
|
||||
|
||||
return op.permission_id;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result delete_custom_permission_evaluator::do_evaluate(const custom_permission_delete_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
const database &d = db();
|
||||
auto now = d.head_block_time();
|
||||
FC_ASSERT(now >= HARDFORK_RBAC_TIME, "Not allowed until RBAC HF");
|
||||
op.owner_account(d);
|
||||
const custom_permission_object &pobj = op.permission_id(d);
|
||||
FC_ASSERT(pobj.account == op.owner_account, "Only owner account can delete permission object");
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
void_result delete_custom_permission_evaluator::do_apply(const custom_permission_delete_operation &op)
|
||||
{
|
||||
try
|
||||
{
|
||||
database &d = db();
|
||||
const custom_permission_object &pobj = op.permission_id(d);
|
||||
// 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);
|
||||
return void_result();
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((op))
|
||||
}
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
|
@ -790,7 +790,10 @@ processed_transaction database::_apply_transaction(const signed_transaction& trx
|
|||
{
|
||||
auto get_active = [&]( account_id_type id ) { return &id(*this).active; };
|
||||
auto get_owner = [&]( account_id_type id ) { return &id(*this).owner; };
|
||||
trx.verify_authority( chain_id, get_active, get_owner, get_global_properties().parameters.max_authority_depth );
|
||||
auto get_custom = [&]( account_id_type id, const operation& op ) {
|
||||
return get_account_custom_authorities(id, op);
|
||||
};
|
||||
trx.verify_authority( chain_id, get_active, get_owner, get_custom, get_global_properties().parameters.max_authority_depth );
|
||||
}
|
||||
|
||||
//Skip all manner of expiration and TaPoS checking if we're on block 1; It's impossible that the transaction is
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include <graphene/chain/asset_object.hpp>
|
||||
#include <graphene/chain/chain_property_object.hpp>
|
||||
#include <graphene/chain/global_property_object.hpp>
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
|
||||
|
|
@ -159,4 +161,24 @@ const witness_schedule_object& database::get_witness_schedule_object()const
|
|||
return *_p_witness_schedule_obj;
|
||||
}
|
||||
|
||||
vector<authority> database::get_account_custom_authorities(account_id_type account, const operation& op)const
|
||||
{
|
||||
const auto& pindex = get_index_type<custom_permission_index>().indices().get<by_account_and_permission>();
|
||||
const auto& cindex = get_index_type<custom_account_authority_index>().indices().get<by_permission_and_op>();
|
||||
auto prange = pindex.equal_range(boost::make_tuple(account));
|
||||
time_point_sec now = head_block_time();
|
||||
vector<authority> custom_auths;
|
||||
for(const custom_permission_object& pobj : boost::make_iterator_range(prange.first, prange.second))
|
||||
{
|
||||
auto crange = cindex.equal_range(boost::make_tuple(pobj.id, op.which()));
|
||||
for(const custom_account_authority_object& cobj : boost::make_iterator_range(crange.first, crange.second))
|
||||
{
|
||||
if(now >= cobj.valid_from && now < cobj.valid_to)
|
||||
{
|
||||
custom_auths.push_back(pobj.auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
return custom_auths;
|
||||
}
|
||||
} }
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
#include <graphene/chain/tournament_object.hpp>
|
||||
#include <graphene/chain/match_object.hpp>
|
||||
#include <graphene/chain/game_object.hpp>
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
|
||||
|
||||
#include <graphene/chain/sport_object.hpp>
|
||||
|
|
@ -77,6 +79,8 @@
|
|||
#include <graphene/chain/event_evaluator.hpp>
|
||||
#include <graphene/chain/betting_market_evaluator.hpp>
|
||||
#include <graphene/chain/tournament_evaluator.hpp>
|
||||
#include <graphene/chain/custom_permission_evaluator.hpp>
|
||||
#include <graphene/chain/custom_account_authority_evaluator.hpp>
|
||||
|
||||
#include <graphene/chain/protocol/fee_schedule.hpp>
|
||||
|
||||
|
|
@ -243,6 +247,12 @@ void database::initialize_evaluators()
|
|||
register_evaluator<lottery_reward_evaluator>();
|
||||
register_evaluator<lottery_end_evaluator>();
|
||||
register_evaluator<sweeps_vesting_claim_evaluator>();
|
||||
register_evaluator<create_custom_permission_evaluator>();
|
||||
register_evaluator<update_custom_permission_evaluator>();
|
||||
register_evaluator<delete_custom_permission_evaluator>();
|
||||
register_evaluator<create_custom_account_authority_evaluator>();
|
||||
register_evaluator<update_custom_account_authority_evaluator>();
|
||||
register_evaluator<delete_custom_account_authority_evaluator>();
|
||||
}
|
||||
|
||||
void database::initialize_indexes()
|
||||
|
|
@ -284,6 +294,8 @@ void database::initialize_indexes()
|
|||
tournament_details_idx->add_secondary_index<tournament_players_index>();
|
||||
add_index< primary_index<match_index> >();
|
||||
add_index< primary_index<game_index> >();
|
||||
add_index< primary_index<custom_permission_index> >();
|
||||
add_index< primary_index<custom_account_authority_index> >();
|
||||
|
||||
//Implementation object indexes
|
||||
add_index< primary_index<transaction_index > >();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <graphene/chain/witness_object.hpp>
|
||||
#include <graphene/chain/witness_schedule_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
|
||||
|
||||
|
|
@ -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
|
||||
// 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<asset_bitasset_data_index>() )
|
||||
for( const auto& d : get_index_type<asset_bitasset_data_index>().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();
|
||||
|
|
|
|||
|
|
@ -293,6 +293,25 @@ struct get_impacted_account_visitor
|
|||
void operator()( const sweeps_vesting_claim_operation& op ) {
|
||||
_impacted.insert( op.account );
|
||||
}
|
||||
|
||||
void operator()( const custom_permission_create_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
void operator()( const custom_permission_update_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
void operator()( const custom_permission_delete_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
void operator()( const custom_account_authority_create_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
void operator()( const custom_account_authority_update_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
void operator()( const custom_account_authority_delete_operation& op ){
|
||||
_impacted.insert( op.owner_account );
|
||||
}
|
||||
};
|
||||
|
||||
void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set<account_id_type>& result )
|
||||
|
|
|
|||
4
libraries/chain/hardfork.d/RBAC.hf
Normal file
4
libraries/chain/hardfork.d/RBAC.hf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// RBAC HARDFORK Wednesday, 20-May-20 00:00:00 UTC
|
||||
#ifndef HARDFORK_RBAC_TIME
|
||||
#define HARDFORK_RBAC_TIME (fc::time_point_sec( 1589932800 ))
|
||||
#endif
|
||||
|
|
@ -234,3 +234,6 @@
|
|||
#define GPOS_PERIOD (60*60*24*30*6) // 6 months
|
||||
#define GPOS_SUBPERIOD (60*60*24*30) // 1 month
|
||||
#define GPOS_VESTING_LOCKIN_PERIOD (60*60*24*30) // 1 month
|
||||
|
||||
#define RBAC_MIN_PERMISSION_NAME_LENGTH 3
|
||||
#define RBAC_MAX_PERMISSION_NAME_LENGTH 10
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/protocol/custom_account_authority.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
class create_custom_account_authority_evaluator : public evaluator<create_custom_account_authority_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_account_authority_create_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_account_authority_create_operation &o);
|
||||
object_id_type do_apply(const custom_account_authority_create_operation &o);
|
||||
};
|
||||
|
||||
class update_custom_account_authority_evaluator : public evaluator<update_custom_account_authority_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_account_authority_update_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_account_authority_update_operation &o);
|
||||
object_id_type do_apply(const custom_account_authority_update_operation &o);
|
||||
};
|
||||
|
||||
class delete_custom_account_authority_evaluator : public evaluator<delete_custom_account_authority_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_account_authority_delete_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_account_authority_delete_operation &o);
|
||||
void_result do_apply(const custom_account_authority_delete_operation &o);
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @class custom_account_authority_object
|
||||
* @brief Tracks the mappings between permission and operation types.
|
||||
* @ingroup object
|
||||
*/
|
||||
class custom_account_authority_object : public abstract_object<custom_account_authority_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = custom_account_authority_object_type;
|
||||
|
||||
custom_permission_id_type permission_id;
|
||||
int operation_type;
|
||||
time_point_sec valid_from;
|
||||
time_point_sec valid_to;
|
||||
};
|
||||
|
||||
struct by_id;
|
||||
struct by_permission_and_op;
|
||||
struct by_expiration;
|
||||
using custom_account_authority_multi_index_type = multi_index_container<
|
||||
custom_account_authority_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>,
|
||||
member<object, object_id_type, &object::id>
|
||||
>,
|
||||
ordered_unique< tag<by_permission_and_op>,
|
||||
composite_key<custom_account_authority_object,
|
||||
member<custom_account_authority_object, custom_permission_id_type, &custom_account_authority_object::permission_id>,
|
||||
member<custom_account_authority_object, int, &custom_account_authority_object::operation_type>,
|
||||
member<object, object_id_type, &object::id>
|
||||
>
|
||||
>,
|
||||
ordered_unique<tag<by_expiration>,
|
||||
composite_key<custom_account_authority_object,
|
||||
member<custom_account_authority_object, time_point_sec, &custom_account_authority_object::valid_to>,
|
||||
member<object, object_id_type, &object::id>
|
||||
>
|
||||
>
|
||||
>
|
||||
>;
|
||||
using custom_account_authority_index = generic_index<custom_account_authority_object, custom_account_authority_multi_index_type>;
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::custom_account_authority_object, (graphene::db::object),
|
||||
(permission_id)(operation_type)(valid_from)(valid_to) )
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/evaluator.hpp>
|
||||
#include <graphene/chain/protocol/custom_permission.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
class create_custom_permission_evaluator : public evaluator<create_custom_permission_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_permission_create_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_permission_create_operation &o);
|
||||
object_id_type do_apply(const custom_permission_create_operation &o);
|
||||
};
|
||||
|
||||
class update_custom_permission_evaluator : public evaluator<update_custom_permission_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_permission_update_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_permission_update_operation &o);
|
||||
object_id_type do_apply(const custom_permission_update_operation &o);
|
||||
};
|
||||
|
||||
class delete_custom_permission_evaluator : public evaluator<delete_custom_permission_evaluator>
|
||||
{
|
||||
public:
|
||||
typedef custom_permission_delete_operation operation_type;
|
||||
|
||||
void_result do_evaluate(const custom_permission_delete_operation &o);
|
||||
void_result do_apply(const custom_permission_delete_operation &o);
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/types.hpp>
|
||||
#include <graphene/db/object.hpp>
|
||||
#include <graphene/db/generic_index.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
using namespace graphene::db;
|
||||
|
||||
/**
|
||||
* @class custom_permission_object
|
||||
* @brief Tracks all the custom permission of an account.
|
||||
* @ingroup object
|
||||
*/
|
||||
class custom_permission_object : public abstract_object<custom_permission_object>
|
||||
{
|
||||
public:
|
||||
static const uint8_t space_id = protocol_ids;
|
||||
static const uint8_t type_id = custom_permission_object_type;
|
||||
|
||||
// Account for which this permission is being created
|
||||
account_id_type account;
|
||||
// Permission name
|
||||
string permission_name;
|
||||
// Authority required for this permission
|
||||
authority auth;
|
||||
};
|
||||
|
||||
struct by_id;
|
||||
struct by_account_and_permission;
|
||||
using custom_permission_multi_index_type = multi_index_container<
|
||||
custom_permission_object,
|
||||
indexed_by<
|
||||
ordered_unique< tag<by_id>,
|
||||
member<object, object_id_type, &object::id>
|
||||
>,
|
||||
ordered_unique< tag<by_account_and_permission>,
|
||||
composite_key<custom_permission_object,
|
||||
member<custom_permission_object, account_id_type, &custom_permission_object::account>,
|
||||
member<custom_permission_object, string, &custom_permission_object::permission_name>
|
||||
>
|
||||
>
|
||||
>
|
||||
>;
|
||||
using custom_permission_index = generic_index<custom_permission_object, custom_permission_multi_index_type>;
|
||||
|
||||
} } // graphene::chain
|
||||
|
||||
FC_REFLECT_DERIVED( graphene::chain::custom_permission_object, (graphene::db::object),
|
||||
(account)(permission_name)(auth) )
|
||||
|
|
@ -294,6 +294,7 @@ namespace graphene { namespace chain {
|
|||
|
||||
|
||||
uint32_t last_non_undoable_block_num() const;
|
||||
vector<authority> get_account_custom_authorities(account_id_type account, const operation& op)const;
|
||||
//////////////////// db_init.cpp ////////////////////
|
||||
|
||||
void initialize_evaluators();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
struct custom_account_authority_create_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
custom_permission_id_type permission_id;
|
||||
int operation_type;
|
||||
time_point_sec valid_from;
|
||||
time_point_sec valid_to;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
struct custom_account_authority_update_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
custom_account_authority_id_type auth_id;
|
||||
optional<time_point_sec> new_valid_from;
|
||||
optional<time_point_sec> new_valid_to;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
struct custom_account_authority_delete_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
custom_account_authority_id_type auth_id;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_create_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_create_operation, (fee)(permission_id)(operation_type)(valid_from)(valid_to)(owner_account))
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_update_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_update_operation, (fee)(auth_id)(new_valid_from)(new_valid_to)(owner_account))
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_delete_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_account_authority_delete_operation, (fee)(auth_id)(owner_account))
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
#include <graphene/chain/protocol/base.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
struct custom_permission_create_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
account_id_type owner_account;
|
||||
string permission_name;
|
||||
authority auth;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
struct custom_permission_update_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
custom_permission_id_type permission_id;
|
||||
optional<authority> new_auth;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
struct custom_permission_delete_operation : public base_operation
|
||||
{
|
||||
struct fee_parameters_type
|
||||
{
|
||||
uint64_t fee = 0;
|
||||
};
|
||||
|
||||
asset fee;
|
||||
custom_permission_id_type permission_id;
|
||||
account_id_type owner_account;
|
||||
|
||||
account_id_type fee_payer() const { return owner_account; }
|
||||
void validate() const;
|
||||
share_type calculate_fee(const fee_parameters_type &k) const { return 0; }
|
||||
};
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_permission_create_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_permission_create_operation, (fee)(owner_account)(permission_name)(auth))
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_permission_update_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_permission_update_operation, (fee)(permission_id)(new_auth)(owner_account))
|
||||
|
||||
FC_REFLECT(graphene::chain::custom_permission_delete_operation::fee_parameters_type, (fee))
|
||||
FC_REFLECT(graphene::chain::custom_permission_delete_operation, (fee)(permission_id)(owner_account))
|
||||
|
|
@ -45,6 +45,8 @@
|
|||
#include <graphene/chain/protocol/event.hpp>
|
||||
#include <graphene/chain/protocol/betting_market.hpp>
|
||||
#include <graphene/chain/protocol/tournament.hpp>
|
||||
#include <graphene/chain/protocol/custom_permission.hpp>
|
||||
#include <graphene/chain/protocol/custom_account_authority.hpp>
|
||||
|
||||
namespace graphene { namespace chain {
|
||||
|
||||
|
|
@ -135,7 +137,13 @@ namespace graphene { namespace chain {
|
|||
ticket_purchase_operation,
|
||||
lottery_reward_operation,
|
||||
lottery_end_operation,
|
||||
sweeps_vesting_claim_operation
|
||||
sweeps_vesting_claim_operation,
|
||||
custom_permission_create_operation,
|
||||
custom_permission_update_operation,
|
||||
custom_permission_delete_operation,
|
||||
custom_account_authority_create_operation,
|
||||
custom_account_authority_update_operation,
|
||||
custom_account_authority_delete_operation
|
||||
> operation;
|
||||
|
||||
/// @} // operations group
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@ namespace graphene { namespace chain {
|
|||
const flat_set<public_key_type>& available_keys,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
)const;
|
||||
|
||||
|
|
@ -148,6 +149,7 @@ namespace graphene { namespace chain {
|
|||
const chain_id_type& chain_id,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH )const;
|
||||
|
||||
/**
|
||||
|
|
@ -162,6 +164,7 @@ namespace graphene { namespace chain {
|
|||
const flat_set<public_key_type>& available_keys,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH
|
||||
) const;
|
||||
|
||||
|
|
@ -194,6 +197,7 @@ namespace graphene { namespace chain {
|
|||
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion = GRAPHENE_MAX_SIG_CHECK_DEPTH,
|
||||
bool allow_committe = false,
|
||||
const flat_set<account_id_type>& active_aprovals = flat_set<account_id_type>(),
|
||||
|
|
|
|||
|
|
@ -171,6 +171,8 @@ namespace graphene { namespace chain {
|
|||
betting_market_group_object_type,
|
||||
betting_market_object_type,
|
||||
bet_object_type,
|
||||
custom_permission_object_type,
|
||||
custom_account_authority_object_type,
|
||||
OBJECT_TYPE_COUNT ///< Sentry value which contains the number of different object types
|
||||
};
|
||||
|
||||
|
|
@ -230,6 +232,8 @@ namespace graphene { namespace chain {
|
|||
class betting_market_group_object;
|
||||
class betting_market_object;
|
||||
class bet_object;
|
||||
class custom_permission_object;
|
||||
class custom_account_authority_object;
|
||||
|
||||
typedef object_id< protocol_ids, account_object_type, account_object> account_id_type;
|
||||
typedef object_id< protocol_ids, asset_object_type, asset_object> asset_id_type;
|
||||
|
|
@ -256,6 +260,8 @@ namespace graphene { namespace chain {
|
|||
typedef object_id< protocol_ids, betting_market_group_object_type, betting_market_group_object> betting_market_group_id_type;
|
||||
typedef object_id< protocol_ids, betting_market_object_type, betting_market_object> betting_market_id_type;
|
||||
typedef object_id< protocol_ids, bet_object_type, bet_object> bet_id_type;
|
||||
typedef object_id< protocol_ids, custom_permission_object_type, custom_permission_object> custom_permission_id_type;
|
||||
typedef object_id< protocol_ids, custom_account_authority_object_type, custom_account_authority_object> custom_account_authority_id_type;
|
||||
|
||||
// implementation types
|
||||
class global_property_object;
|
||||
|
|
@ -436,6 +442,8 @@ FC_REFLECT_ENUM( graphene::chain::object_type,
|
|||
(betting_market_group_object_type)
|
||||
(betting_market_object_type)
|
||||
(bet_object_type)
|
||||
(custom_permission_object_type)
|
||||
(custom_account_authority_object_type)
|
||||
(OBJECT_TYPE_COUNT)
|
||||
)
|
||||
FC_REFLECT_ENUM( graphene::chain::impl_object_type,
|
||||
|
|
@ -505,6 +513,8 @@ FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type )
|
|||
FC_REFLECT_TYPENAME( graphene::chain::betting_market_position_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::global_betting_statistics_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::tournament_details_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::custom_permission_id_type )
|
||||
FC_REFLECT_TYPENAME( graphene::chain::custom_account_authority_id_type )
|
||||
|
||||
FC_REFLECT( graphene::chain::void_t, )
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,30 @@ struct proposal_operation_hardfork_visitor
|
|||
FC_ASSERT( vbco.balance_type == vesting_balance_type::normal, "balance_type in vesting create not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_permission_create_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_create_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_permission_update_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_update_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_permission_delete_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_delete_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_account_authority_create_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_create_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_account_authority_update_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_update_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
void operator()(const custom_account_authority_delete_operation &v) const {
|
||||
FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_delete_operation not allowed yet!" );
|
||||
}
|
||||
|
||||
// loop and self visit in proposals
|
||||
void operator()(const proposal_create_operation &v) const {
|
||||
for (const op_wrapper &op : v.proposed_ops)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ bool proposal_object::is_authorized_to_execute(database& db) const
|
|||
available_key_approvals,
|
||||
[&]( account_id_type id ){ return &id(db).active; },
|
||||
[&]( account_id_type id ){ return &id(db).owner; },
|
||||
[&]( account_id_type id, const operation& op ){
|
||||
return db.get_account_custom_authorities(id, op); },
|
||||
db.get_global_properties().parameters.max_authority_depth,
|
||||
true, /* allow committee */
|
||||
available_active_approvals,
|
||||
|
|
|
|||
38
libraries/chain/protocol/custom_account_authority.cpp
Normal file
38
libraries/chain/protocol/custom_account_authority.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#include <graphene/chain/protocol/custom_account_authority.hpp>
|
||||
#include <graphene/chain/protocol/operations.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
void custom_account_authority_create_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
FC_ASSERT(valid_from < valid_to, "valid_from should be earlier than valid_to");
|
||||
FC_ASSERT(operation_type >= 0 && operation_type < operation::count(), "operation_type is not valid");
|
||||
}
|
||||
|
||||
void custom_account_authority_update_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
FC_ASSERT(new_valid_from.valid() || new_valid_to.valid(), "Something must be updated");
|
||||
if (new_valid_from && new_valid_to)
|
||||
{
|
||||
FC_ASSERT(*new_valid_from < *new_valid_to, "valid_from should be earlier than valid_to");
|
||||
}
|
||||
}
|
||||
|
||||
void custom_account_authority_delete_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
}
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
80
libraries/chain/protocol/custom_permission.cpp
Normal file
80
libraries/chain/protocol/custom_permission.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#include <graphene/chain/protocol/custom_permission.hpp>
|
||||
#include <graphene/chain/protocol/operations.hpp>
|
||||
|
||||
namespace graphene
|
||||
{
|
||||
namespace chain
|
||||
{
|
||||
|
||||
bool is_valid_permission_name(const string &name)
|
||||
{
|
||||
try
|
||||
{
|
||||
const size_t len = name.size();
|
||||
// RBAC_MIN_PERMISSION_NAME_LENGTH <= len minimum length check
|
||||
if (len < RBAC_MIN_PERMISSION_NAME_LENGTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// len <= RBAC_MAX_PERMISSION_NAME_LENGTH max length check
|
||||
if (len > RBAC_MAX_PERMISSION_NAME_LENGTH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// First character should be a letter between a-z
|
||||
if (!(name[0] >= 'a' && name[0] <= 'z'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Any character of a permission name should either be a small case letter a-z or a digit 0-9
|
||||
for (const auto &ch : name)
|
||||
{
|
||||
if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Don't accept active and owner permissions as we already have them by default
|
||||
// This is for removing ambiguity for users, accepting them doesn't create any problems
|
||||
if (name == "active" || name == "owner")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
FC_CAPTURE_AND_RETHROW((name))
|
||||
}
|
||||
|
||||
void custom_permission_create_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(is_valid_permission_name(permission_name), "Invalid permission name provided");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
FC_ASSERT(!auth.is_impossible(), "Impossible authority threshold auth provided");
|
||||
FC_ASSERT(auth.address_auths.size() == 0, "Only account and key auths supported");
|
||||
}
|
||||
|
||||
void custom_permission_update_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
FC_ASSERT(new_auth.valid(), "Something must be updated");
|
||||
if (new_auth)
|
||||
{
|
||||
FC_ASSERT(!new_auth->is_impossible(), "Impossible authority threshold auth provided");
|
||||
FC_ASSERT(new_auth->address_auths.size() == 0, "Only account and key auths supported");
|
||||
}
|
||||
}
|
||||
|
||||
void custom_permission_delete_operation::validate() const
|
||||
{
|
||||
FC_ASSERT(fee.amount >= 0, "Fee must not be negative");
|
||||
FC_ASSERT(owner_account != GRAPHENE_TEMP_ACCOUNT && owner_account != GRAPHENE_COMMITTEE_ACCOUNT && owner_account != GRAPHENE_WITNESS_ACCOUNT && owner_account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT,
|
||||
"Custom permissions and account auths cannot be created for special accounts");
|
||||
}
|
||||
|
||||
} // namespace chain
|
||||
} // namespace graphene
|
||||
|
|
@ -248,6 +248,7 @@ struct sign_state
|
|||
void verify_authority( const vector<operation>& ops, const flat_set<public_key_type>& sigs,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion_depth,
|
||||
bool allow_committe,
|
||||
const flat_set<account_id_type>& active_aprovals,
|
||||
|
|
@ -257,13 +258,6 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
flat_set<account_id_type> required_owner;
|
||||
vector<authority> other;
|
||||
|
||||
for( const auto& op : ops )
|
||||
operation_get_required_authorities( op, required_active, required_owner, other );
|
||||
|
||||
if( !allow_committe )
|
||||
GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
|
||||
invalid_committee_approval, "Committee account may only propose transactions" );
|
||||
|
||||
sign_state s(sigs,get_active);
|
||||
s.max_recursion = max_recursion_depth;
|
||||
for( auto& id : active_aprovals )
|
||||
|
|
@ -271,6 +265,35 @@ void verify_authority( const vector<operation>& ops, const flat_set<public_key_t
|
|||
for( auto& id : owner_approvals )
|
||||
s.approved_by.insert( id );
|
||||
|
||||
auto approved_by_custom_authority = [&s, &get_custom](
|
||||
account_id_type account,
|
||||
operation op ) mutable {
|
||||
auto custom_auths = get_custom( account, op );
|
||||
for( const auto& auth : custom_auths )
|
||||
if( s.check_authority( &auth ) ) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for( const auto& op : ops ) {
|
||||
flat_set<account_id_type> operation_required_active;
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other );
|
||||
|
||||
auto itr = operation_required_active.begin();
|
||||
while ( itr != operation_required_active.end() ) {
|
||||
if ( approved_by_custom_authority( *itr, op ) )
|
||||
itr = operation_required_active.erase( itr );
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
required_active.insert( operation_required_active.begin(), operation_required_active.end() );
|
||||
}
|
||||
|
||||
if( !allow_committe )
|
||||
GRAPHENE_ASSERT( required_active.find(GRAPHENE_COMMITTEE_ACCOUNT) == required_active.end(),
|
||||
invalid_committee_approval, "Committee account may only propose transactions" );
|
||||
|
||||
|
||||
for( const auto& auth : other )
|
||||
{
|
||||
GRAPHENE_ASSERT( s.check_authority(&auth), tx_missing_other_auth, "Missing Authority", ("auth",auth)("sigs",sigs) );
|
||||
|
|
@ -325,17 +348,41 @@ set<public_key_type> signed_transaction::get_required_signatures(
|
|||
const flat_set<public_key_type>& available_keys,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion_depth )const
|
||||
{
|
||||
flat_set<account_id_type> required_active;
|
||||
flat_set<account_id_type> required_owner;
|
||||
vector<authority> other;
|
||||
get_required_authorities( required_active, required_owner, other );
|
||||
|
||||
const flat_set<public_key_type>& signature_keys = get_signature_keys( chain_id );
|
||||
sign_state s( signature_keys, get_active, available_keys );
|
||||
s.max_recursion = max_recursion_depth;
|
||||
|
||||
auto approved_by_custom_authority = [&s, &get_custom](
|
||||
account_id_type account,
|
||||
operation op ) mutable {
|
||||
auto custom_auths = get_custom( account, op );
|
||||
for( const auto& auth : custom_auths )
|
||||
if( s.check_authority( &auth ) ) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
for( const auto& op : operations ) {
|
||||
flat_set<account_id_type> operation_required_active;
|
||||
operation_get_required_authorities( op, operation_required_active, required_owner, other );
|
||||
|
||||
auto itr = operation_required_active.begin();
|
||||
while ( itr != operation_required_active.end() ) {
|
||||
if ( approved_by_custom_authority( *itr, op ) )
|
||||
itr = operation_required_active.erase( itr );
|
||||
else
|
||||
++itr;
|
||||
}
|
||||
|
||||
required_active.insert( operation_required_active.begin(), operation_required_active.end() );
|
||||
}
|
||||
|
||||
for( const auto& auth : other )
|
||||
s.check_authority(&auth);
|
||||
for( auto& owner : required_owner )
|
||||
|
|
@ -359,10 +406,11 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
|
|||
const flat_set<public_key_type>& available_keys,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion
|
||||
) const
|
||||
{
|
||||
set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, max_recursion );
|
||||
set< public_key_type > s = get_required_signatures( chain_id, available_keys, get_active, get_owner, get_custom, max_recursion );
|
||||
flat_set< public_key_type > result( s.begin(), s.end() );
|
||||
|
||||
for( const public_key_type& k : s )
|
||||
|
|
@ -370,7 +418,7 @@ set<public_key_type> signed_transaction::minimize_required_signatures(
|
|||
result.erase( k );
|
||||
try
|
||||
{
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, max_recursion );
|
||||
graphene::chain::verify_authority( operations, result, get_active, get_owner, get_custom, max_recursion );
|
||||
continue; // element stays erased if verify_authority is ok
|
||||
}
|
||||
catch( const tx_missing_owner_auth& e ) {}
|
||||
|
|
@ -385,9 +433,10 @@ void signed_transaction::verify_authority(
|
|||
const chain_id_type& chain_id,
|
||||
const std::function<const authority*(account_id_type)>& get_active,
|
||||
const std::function<const authority*(account_id_type)>& get_owner,
|
||||
const std::function<vector<authority>(account_id_type, const operation&)>& get_custom,
|
||||
uint32_t max_recursion )const
|
||||
{ try {
|
||||
graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, max_recursion );
|
||||
graphene::chain::verify_authority( operations, get_signature_keys( chain_id ), get_active, get_owner, get_custom, max_recursion );
|
||||
} FC_CAPTURE_AND_RETHROW( (*this) ) }
|
||||
|
||||
} } // graphene::chain
|
||||
|
|
|
|||
|
|
@ -1895,6 +1895,38 @@ class wallet_api
|
|||
bool is_gpos,
|
||||
bool broadcast);
|
||||
|
||||
signed_transaction create_custom_permission(string owner,
|
||||
string permission_name,
|
||||
authority auth,
|
||||
bool broadcast = true);
|
||||
signed_transaction update_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
fc::optional<authority> new_auth,
|
||||
bool broadcast = true);
|
||||
signed_transaction delete_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
bool broadcast = true);
|
||||
signed_transaction create_custom_account_authority(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
int operation_type,
|
||||
fc::time_point_sec valid_from,
|
||||
fc::time_point_sec valid_to,
|
||||
bool broadcast = true);
|
||||
signed_transaction update_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
fc::optional<fc::time_point_sec> new_valid_from,
|
||||
fc::optional<fc::time_point_sec> new_valid_to,
|
||||
bool broadcast = true);
|
||||
signed_transaction delete_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
bool broadcast = true);
|
||||
vector<custom_permission_object> get_custom_permissions(string owner) const;
|
||||
fc::optional<custom_permission_object> get_custom_permission_by_name(string owner, string permission_name) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities(string owner) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_id(custom_permission_id_type permission_id) const;
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_name(string owner, string permission_name) const;
|
||||
vector<authority> get_active_custom_account_authorities_by_operation(string owner, int operation_type) const;
|
||||
|
||||
void dbg_make_uia(string creator, string symbol);
|
||||
void dbg_make_mia(string creator, string symbol);
|
||||
void dbg_push_blocks( std::string src_filename, uint32_t count );
|
||||
|
|
@ -2157,4 +2189,16 @@ FC_API( graphene::wallet::wallet_api,
|
|||
(get_all_matched_bets_for_bettor)
|
||||
(buy_ticket)
|
||||
(quit)
|
||||
(create_custom_permission)
|
||||
(update_custom_permission)
|
||||
(delete_custom_permission)
|
||||
(create_custom_account_authority)
|
||||
(update_custom_account_authority)
|
||||
(delete_custom_account_authority)
|
||||
(get_custom_permissions)
|
||||
(get_custom_permission_by_name)
|
||||
(get_custom_account_authorities)
|
||||
(get_custom_account_authorities_by_permission_id)
|
||||
(get_custom_account_authorities_by_permission_name)
|
||||
(get_active_custom_account_authorities_by_operation)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3242,6 +3242,140 @@ public:
|
|||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction create_custom_permission(string owner,
|
||||
string permission_name,
|
||||
authority auth,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_permission_create_operation create_op;
|
||||
create_op.owner_account = get_account(owner).id;
|
||||
create_op.permission_name = permission_name;
|
||||
create_op.auth = auth;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(create_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction update_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
fc::optional<authority> new_auth,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_permission_update_operation update_op;
|
||||
update_op.owner_account = get_account(owner).id;
|
||||
update_op.permission_id = permission_id;
|
||||
update_op.new_auth = new_auth;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(update_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction delete_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_permission_delete_operation delete_op;
|
||||
delete_op.owner_account = get_account(owner).id;
|
||||
delete_op.permission_id = permission_id;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(delete_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction create_custom_account_authority(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
int operation_type,
|
||||
fc::time_point_sec valid_from,
|
||||
fc::time_point_sec valid_to,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_account_authority_create_operation create_op;
|
||||
create_op.owner_account = get_account(owner).id;
|
||||
create_op.permission_id = permission_id;
|
||||
create_op.operation_type = operation_type;
|
||||
create_op.valid_from = valid_from;
|
||||
create_op.valid_to = valid_to;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(create_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction update_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
fc::optional<fc::time_point_sec> new_valid_from,
|
||||
fc::optional<fc::time_point_sec> new_valid_to,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_account_authority_update_operation update_op;
|
||||
update_op.owner_account = get_account(owner).id;
|
||||
update_op.auth_id = auth_id;
|
||||
update_op.new_valid_from = new_valid_from;
|
||||
update_op.new_valid_to = new_valid_to;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(update_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction delete_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
bool broadcast)
|
||||
{
|
||||
custom_account_authority_delete_operation delete_op;
|
||||
delete_op.owner_account = get_account(owner).id;
|
||||
delete_op.auth_id = auth_id;
|
||||
|
||||
signed_transaction tx;
|
||||
tx.operations.push_back(delete_op);
|
||||
set_operation_fees(tx, get_global_properties().parameters.current_fees);
|
||||
tx.validate();
|
||||
return sign_transaction(tx, broadcast);
|
||||
}
|
||||
|
||||
vector<custom_permission_object> get_custom_permissions(string owner) const
|
||||
{
|
||||
return _remote_db->get_custom_permissions(get_account(owner).id);
|
||||
}
|
||||
|
||||
fc::optional<custom_permission_object> get_custom_permission_by_name(string owner, string permission_name) const
|
||||
{
|
||||
return _remote_db->get_custom_permission_by_name(get_account(owner).id, permission_name);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> get_custom_account_authorities(string owner) const
|
||||
{
|
||||
return _remote_db->get_custom_account_authorities(get_account(owner).id);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_id(custom_permission_id_type permission_id) const
|
||||
{
|
||||
return _remote_db->get_custom_account_authorities_by_permission_id(permission_id);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> get_custom_account_authorities_by_permission_name(string owner, string permission_name) const
|
||||
{
|
||||
return _remote_db->get_custom_account_authorities_by_permission_name(get_account(owner).id, permission_name);
|
||||
}
|
||||
|
||||
vector<authority> get_active_custom_account_authorities_by_operation(string owner, int operation_type) const
|
||||
{
|
||||
return _remote_db->get_active_custom_account_authorities_by_operation(get_account(owner).id, operation_type);
|
||||
}
|
||||
|
||||
void dbg_make_uia(string creator, string symbol)
|
||||
{
|
||||
asset_options opts;
|
||||
|
|
@ -4541,8 +4675,84 @@ signed_transaction wallet_api::approve_proposal(
|
|||
return my->approve_proposal( fee_paying_account, proposal_id, delta, broadcast );
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_custom_permission(string owner,
|
||||
string permission_name,
|
||||
authority auth,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->create_custom_permission(owner, permission_name, auth, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::update_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
fc::optional<authority> new_auth,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->update_custom_permission(owner, permission_id, new_auth, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::delete_custom_permission(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->delete_custom_permission(owner, permission_id, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::create_custom_account_authority(string owner,
|
||||
custom_permission_id_type permission_id,
|
||||
int operation_type,
|
||||
fc::time_point_sec valid_from,
|
||||
fc::time_point_sec valid_to,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->create_custom_account_authority(owner, permission_id, operation_type, valid_from, valid_to, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::update_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
fc::optional<fc::time_point_sec> new_valid_from,
|
||||
fc::optional<fc::time_point_sec> new_valid_to,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->update_custom_account_authority(owner, auth_id, new_valid_from, new_valid_to, broadcast);
|
||||
}
|
||||
|
||||
signed_transaction wallet_api::delete_custom_account_authority(string owner,
|
||||
custom_account_authority_id_type auth_id,
|
||||
bool broadcast)
|
||||
{
|
||||
return my->delete_custom_account_authority(owner, auth_id, broadcast);
|
||||
}
|
||||
|
||||
vector<custom_permission_object> wallet_api::get_custom_permissions(string owner) const
|
||||
{
|
||||
return my->get_custom_permissions(owner);
|
||||
}
|
||||
|
||||
fc::optional<custom_permission_object> wallet_api::get_custom_permission_by_name(string owner, string permission_name) const
|
||||
{
|
||||
return my->get_custom_permission_by_name(owner, permission_name);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> wallet_api::get_custom_account_authorities(string owner) const
|
||||
{
|
||||
return my->get_custom_account_authorities(owner);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> wallet_api::get_custom_account_authorities_by_permission_id(custom_permission_id_type permission_id) const
|
||||
{
|
||||
return my->get_custom_account_authorities_by_permission_id(permission_id);
|
||||
}
|
||||
|
||||
vector<custom_account_authority_object> wallet_api::get_custom_account_authorities_by_permission_name(string owner, string permission_name) const
|
||||
{
|
||||
return my->get_custom_account_authorities_by_permission_name(owner, permission_name);
|
||||
}
|
||||
|
||||
vector<authority> wallet_api::get_active_custom_account_authorities_by_operation(string owner, int operation_type) const
|
||||
{
|
||||
return my->get_active_custom_account_authorities_by_operation(owner, operation_type);
|
||||
}
|
||||
|
||||
global_property_object wallet_api::get_global_properties() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@
|
|||
#include <graphene/chain/tournament_object.hpp>
|
||||
#include <graphene/chain/match_object.hpp>
|
||||
#include <graphene/chain/game_object.hpp>
|
||||
#include <graphene/chain/custom_permission_object.hpp>
|
||||
#include <graphene/chain/custom_account_authority_object.hpp>
|
||||
|
||||
#include <fc/smart_ref_impl.hpp>
|
||||
#include <iostream>
|
||||
|
|
|
|||
|
|
@ -1189,6 +1189,14 @@ BOOST_FIXTURE_TEST_CASE( get_required_signatures_test, database_fixture )
|
|||
return &(aid(db).owner);
|
||||
} ;
|
||||
|
||||
auto get_custom = [&](
|
||||
account_id_type id,
|
||||
const operation& op
|
||||
) -> vector<authority>
|
||||
{
|
||||
return db.get_account_custom_authorities(id, op);
|
||||
} ;
|
||||
|
||||
auto chk = [&](
|
||||
const signed_transaction& tx,
|
||||
flat_set<public_key_type> available_keys,
|
||||
|
|
@ -1196,7 +1204,7 @@ BOOST_FIXTURE_TEST_CASE( get_required_signatures_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
} ;
|
||||
|
|
@ -1303,6 +1311,14 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
return &(aid(db).owner);
|
||||
} ;
|
||||
|
||||
auto get_custom = [&](
|
||||
account_id_type id,
|
||||
const operation& op
|
||||
) -> vector<authority>
|
||||
{
|
||||
return db.get_account_custom_authorities(id, op);
|
||||
} ;
|
||||
|
||||
auto chk = [&](
|
||||
const signed_transaction& tx,
|
||||
flat_set<public_key_type> available_keys,
|
||||
|
|
@ -1310,7 +1326,7 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
set<public_key_type> result_set = tx.get_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
} ;
|
||||
|
|
@ -1322,7 +1338,7 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
) -> bool
|
||||
{
|
||||
//wdump( (tx)(available_keys) );
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner );
|
||||
set<public_key_type> result_set = tx.minimize_required_signatures( db.get_chain_id(), available_keys, get_active, get_owner, get_custom );
|
||||
//wdump( (result_set)(ref_set) );
|
||||
return result_set == ref_set;
|
||||
} ;
|
||||
|
|
@ -1341,9 +1357,9 @@ BOOST_FIXTURE_TEST_CASE( nonminimal_sig_test, database_fixture )
|
|||
BOOST_CHECK( chk( tx, { alice_public_key, bob_public_key }, { alice_public_key, bob_public_key } ) );
|
||||
BOOST_CHECK( chk_min( tx, { alice_public_key, bob_public_key }, { alice_public_key } ) );
|
||||
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner ), fc::exception );
|
||||
GRAPHENE_REQUIRE_THROW( tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom ), fc::exception );
|
||||
sign( tx, alice_private_key );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner );
|
||||
tx.verify_authority( db.get_chain_id(), get_active, get_owner, get_custom );
|
||||
}
|
||||
catch(fc::exception& e)
|
||||
{
|
||||
|
|
|
|||
1647
tests/tests/custom_permission_tests.cpp
Normal file
1647
tests/tests/custom_permission_tests.cpp
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue