From 2a7c8749d342a767d1fec4c671eb3e26f7b3adc2 Mon Sep 17 00:00:00 2001 From: satyakoneru <15652887+satyakoneru@users.noreply.github.com> Date: Tue, 26 May 2020 12:28:25 +0000 Subject: [PATCH] rbac1 - evaluators and op validators added --- libraries/chain/CMakeLists.txt | 4 + .../custom_account_authority_evaluator.cpp | 150 ++++++++++++++++++ .../chain/custom_permission_evaluator.cpp | 115 ++++++++++++++ libraries/chain/db_init.cpp | 12 ++ libraries/chain/db_notify.cpp | 19 +++ libraries/chain/hardfork.d/RBAC.hf | 4 + .../chain/include/graphene/chain/config.hpp | 3 + .../custom_account_authority_evaluator.hpp | 34 ++++ .../chain/custom_account_authority_object.hpp | 55 +++++++ .../chain/custom_permission_evaluator.hpp | 34 ++++ .../chain/custom_permission_object.hpp | 49 ++++++ .../protocol/custom_account_authority.hpp | 59 +++++++ .../chain/protocol/custom_permission.hpp | 56 +++++++ .../graphene/chain/protocol/operations.hpp | 10 +- .../include/graphene/chain/protocol/types.hpp | 10 ++ .../protocol/custom_account_authority.cpp | 39 +++++ .../chain/protocol/custom_permission.cpp | 77 +++++++++ programs/js_operation_serializer/main.cpp | 2 + 18 files changed, 731 insertions(+), 1 deletion(-) create mode 100644 libraries/chain/custom_account_authority_evaluator.cpp create mode 100644 libraries/chain/custom_permission_evaluator.cpp create mode 100644 libraries/chain/hardfork.d/RBAC.hf create mode 100644 libraries/chain/include/graphene/chain/custom_account_authority_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/custom_account_authority_object.hpp create mode 100644 libraries/chain/include/graphene/chain/custom_permission_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/custom_permission_object.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/custom_account_authority.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/custom_permission.hpp create mode 100644 libraries/chain/protocol/custom_account_authority.cpp create mode 100644 libraries/chain/protocol/custom_permission.cpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 07f1ea0a..3ab155fe 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -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 diff --git a/libraries/chain/custom_account_authority_evaluator.cpp b/libraries/chain/custom_account_authority_evaluator.cpp new file mode 100644 index 00000000..0d4cbf14 --- /dev/null +++ b/libraries/chain/custom_account_authority_evaluator.cpp @@ -0,0 +1,150 @@ +#include + +#include +#include +#include +#include + +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) {} + + template + void operator()(const T &v) const {} + + void operator()(const custom_permission_create_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_create_operation not allowed yet!" ); + } + void operator()(const custom_permission_update_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_update_operation not allowed yet!" ); + } + void operator()(const custom_permission_delete_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_permission_delete_operation not allowed yet!" ); + } + void operator()(const custom_account_authority_create_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_create_operation not allowed yet!" ); + } + void operator()(const custom_account_authority_update_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_update_operation not allowed yet!" ); + } + void operator()(const custom_account_authority_delete_operation &op) const { + FC_ASSERT( block_time >= HARDFORK_RBAC_TIME, "custom_account_authority_delete_operation not allowed yet!" ); + } +}; + +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"); + 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([&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) { + FC_ASSERT(*op.new_valid_from != aobj.valid_from, + "New valid_from provided is not different from old valid_from"); + valid_from = *op.new_valid_from; + } + + if (op.new_valid_to) { + FC_ASSERT(*op.new_valid_to != aobj.valid_to, + "New valid_to provided is not different from old 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)) +} + +object_id_type 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); + } + FC_CAPTURE_AND_RETHROW((op)) +} + +} // namespace chain +} // namespace graphene diff --git a/libraries/chain/custom_permission_evaluator.cpp b/libraries/chain/custom_permission_evaluator.cpp new file mode 100644 index 00000000..621f9e8b --- /dev/null +++ b/libraries/chain/custom_permission_evaluator.cpp @@ -0,0 +1,115 @@ +#include + +#include +#include +#include + +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().indices().get(); + 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([&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); + // TODO: Remove all the custom_account_authority_object linked to this permission object. + d.remove(pobj); + return void_result(); + } + FC_CAPTURE_AND_RETHROW((op)) +} + +} // namespace chain +} // namespace graphene \ No newline at end of file diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 4e30029b..49214931 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -49,6 +49,8 @@ #include #include #include +#include +#include #include @@ -77,6 +79,8 @@ #include #include #include +#include +#include #include @@ -243,6 +247,12 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -284,6 +294,8 @@ void database::initialize_indexes() tournament_details_idx->add_secondary_index(); add_index< primary_index >(); add_index< primary_index >(); + add_index< primary_index >(); + add_index< primary_index >(); //Implementation object indexes add_index< primary_index >(); diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index e91eaa6b..b25399e6 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -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& result ) diff --git a/libraries/chain/hardfork.d/RBAC.hf b/libraries/chain/hardfork.d/RBAC.hf new file mode 100644 index 00000000..e91e1b8b --- /dev/null +++ b/libraries/chain/hardfork.d/RBAC.hf @@ -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 diff --git a/libraries/chain/include/graphene/chain/config.hpp b/libraries/chain/include/graphene/chain/config.hpp index 710db6c5..fe552610 100644 --- a/libraries/chain/include/graphene/chain/config.hpp +++ b/libraries/chain/include/graphene/chain/config.hpp @@ -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 \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/custom_account_authority_evaluator.hpp b/libraries/chain/include/graphene/chain/custom_account_authority_evaluator.hpp new file mode 100644 index 00000000..b168a3de --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_account_authority_evaluator.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include + +namespace graphene { namespace chain { + +class create_custom_account_authority_evaluator : public 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 +{ +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 +{ +public: + typedef custom_account_authority_delete_operation operation_type; + + void_result do_evaluate(const custom_account_authority_delete_operation& o); + object_id_type do_apply(const custom_account_authority_delete_operation& o); +}; + +} } // namespace graphene::chain \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/custom_account_authority_object.hpp b/libraries/chain/include/graphene/chain/custom_account_authority_object.hpp new file mode 100644 index 00000000..acca8bcf --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_account_authority_object.hpp @@ -0,0 +1,55 @@ +#pragma once +#include +#include +#include + +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 + { + 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, + member + >, + ordered_unique< tag, + composite_key, + member, + member + > + >, + ordered_unique, + composite_key, + member + > + > + > + >; + using custom_account_authority_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::custom_account_authority_object, (graphene::db::object), + (permission_id)(operation_type)(valid_from)(valid_to) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/custom_permission_evaluator.hpp b/libraries/chain/include/graphene/chain/custom_permission_evaluator.hpp new file mode 100644 index 00000000..f436b6e5 --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_permission_evaluator.hpp @@ -0,0 +1,34 @@ +#pragma once +#include +#include + +namespace graphene { namespace chain { + +class create_custom_permission_evaluator : public 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 +{ +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 +{ +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 graphene::chain \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/custom_permission_object.hpp b/libraries/chain/include/graphene/chain/custom_permission_object.hpp new file mode 100644 index 00000000..72789ef4 --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_permission_object.hpp @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include + +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 + { + 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, + member + >, + ordered_unique< tag, + composite_key, + member + > + > + > + >; + using custom_permission_index = generic_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::custom_permission_object, (graphene::db::object), + (account)(permission_name)(auth) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/protocol/custom_account_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_account_authority.hpp new file mode 100644 index 00000000..be1d7868 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/custom_account_authority.hpp @@ -0,0 +1,59 @@ +#pragma once +#include + +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 new_valid_from; + optional 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 graphene::chain + +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) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/protocol/custom_permission.hpp b/libraries/chain/include/graphene/chain/protocol/custom_permission.hpp new file mode 100644 index 00000000..7226dfe8 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/custom_permission.hpp @@ -0,0 +1,56 @@ +#pragma once +#include + +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 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 graphene::chain + +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) ) \ No newline at end of file diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index cb9a83a1..c64249d9 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include 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 diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 8ea3a8af..c5ff066f 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -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, ) diff --git a/libraries/chain/protocol/custom_account_authority.cpp b/libraries/chain/protocol/custom_account_authority.cpp new file mode 100644 index 00000000..4cbdb0e9 --- /dev/null +++ b/libraries/chain/protocol/custom_account_authority.cpp @@ -0,0 +1,39 @@ +#include +#include + +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"); +} + +} } // graphene::chain diff --git a/libraries/chain/protocol/custom_permission.cpp b/libraries/chain/protocol/custom_permission.cpp new file mode 100644 index 00000000..eb2c88cd --- /dev/null +++ b/libraries/chain/protocol/custom_permission.cpp @@ -0,0 +1,77 @@ +#include +#include + +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"); +} + +} } // graphene::chain diff --git a/programs/js_operation_serializer/main.cpp b/programs/js_operation_serializer/main.cpp index 8994b36b..a2962bb1 100644 --- a/programs/js_operation_serializer/main.cpp +++ b/programs/js_operation_serializer/main.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include