diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 6fe3f47883..da47096da6 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -32,6 +32,8 @@ endif( GRAPHENE_DISABLE_UNITY_BUILD ) ## SORT .cpp by most likely to change / break compile add_library( graphene_chain + protocol/restriction.cpp + protocol/custom_authority.cpp # As database takes the longest to compile, start it first ${GRAPHENE_DB_FILES} fork_database.cpp @@ -80,6 +82,7 @@ add_library( graphene_chain confidential_evaluator.cpp special_authority.cpp buyback.cpp + custom_authority_evaluator.cpp account_object.cpp asset_object.cpp diff --git a/libraries/chain/custom_authority_evaluator.cpp b/libraries/chain/custom_authority_evaluator.cpp new file mode 100644 index 0000000000..5cb8ca93bc --- /dev/null +++ b/libraries/chain/custom_authority_evaluator.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include +#include +#include +#include + +namespace graphene { namespace chain { + +void_result custom_authority_create_evaluator::do_evaluate(const custom_authority_create_operation& op) +{ try { + const database& d = db(); + + // account is fee payer so should be valid + + // custom_id should be unique per account + + // valid_from ? + // valid_to should not be too far in the future + + // operation_type HF check + + // if there is an account in auth, need to be valid + + // restrictions size check? global limitation? + + // how many custom authorities per account? + +/* + asset fee; + account_id_type account; + uint32_t custom_id; + bool enabled; + time_point_sec valid_from; + time_point_sec valid_to; + unsigned_int operation_type; + authority auth; + vector restrictions; + + empty_extensions_type extensions; +*/ + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type custom_authority_create_evaluator::do_apply(const custom_authority_create_operation& op) +{ try { + database& d = db(); + + const auto& new_object = d.create( [&op]( custom_authority_object& obj ){ + obj.account = op.account; + obj.custom_id = op.custom_id; + obj.enabled = op.enabled; + obj.valid_from = op.valid_from; + obj.valid_to = op.valid_to; + obj.operation_type = op.operation_type; + obj.auth = op.auth; + obj.restrictions = op.restrictions; + }); + + return new_object.id; + +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_update_evaluator::do_evaluate(const custom_authority_update_operation& op) +{ try { + const database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_update_evaluator::do_apply(const custom_authority_update_operation& op) +{ try { + database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_delete_evaluator::do_evaluate(const custom_authority_delete_operation& op) +{ try { + const database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_delete_evaluator::do_apply(const custom_authority_delete_operation& op) +{ try { + database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +} } // graphene::chain diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 263c5df3e5..6375aa8194 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -53,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -173,6 +175,9 @@ void database::initialize_evaluators() register_evaluator(); register_evaluator(); register_evaluator(); + register_evaluator(); + register_evaluator(); + register_evaluator(); } void database::initialize_indexes() @@ -216,6 +221,7 @@ void database::initialize_indexes() add_index< primary_index< special_authority_index > >(); add_index< primary_index< buyback_index > >(); add_index< primary_index >(); + add_index< primary_index >(); add_index< primary_index< simple_index< fba_accumulator_object > > >(); } diff --git a/libraries/chain/db_notify.cpp b/libraries/chain/db_notify.cpp index ff44a177df..7f6130bc4f 100644 --- a/libraries/chain/db_notify.cpp +++ b/libraries/chain/db_notify.cpp @@ -256,6 +256,19 @@ struct get_impacted_account_visitor { _impacted.insert( op.fee_payer() ); // account_id } + void operator()( const custom_authority_create_operation& op ) + { + _impacted.insert( op.fee_payer() ); // account + add_authority_accounts( _impacted, op.auth ); + } + void operator()( const custom_authority_update_operation& op ) + { + _impacted.insert( op.fee_payer() ); // account + } + void operator()( const custom_authority_delete_operation& op ) + { + _impacted.insert( op.fee_payer() ); // account + } }; void graphene::chain::operation_get_impacted_accounts( const operation& op, flat_set& result ) @@ -406,6 +419,12 @@ void get_relevant_accounts( const object* obj, flat_set& accoun FC_ASSERT( aobj != nullptr ); accounts.insert( aobj->bidder ); break; + } case impl_custom_authority_object_type:{ + const auto& aobj = dynamic_cast(obj); + FC_ASSERT( aobj != nullptr ); + accounts.insert( aobj->account ); + add_authority_accounts( accounts, aobj->auth ); + break; } } } diff --git a/libraries/chain/include/graphene/chain/custom_authority_evaluator.hpp b/libraries/chain/include/graphene/chain/custom_authority_evaluator.hpp new file mode 100644 index 0000000000..d076ed3db8 --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_authority_evaluator.hpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once + +#include + +namespace graphene { namespace chain { + +class custom_authority_create_evaluator : public evaluator +{ +public: + typedef custom_authority_create_operation operation_type; + + void_result do_evaluate( const operation_type& op ); + object_id_type do_apply( const operation_type& op ); +}; + +class custom_authority_update_evaluator : public evaluator +{ +public: + typedef custom_authority_update_operation operation_type; + + void_result do_evaluate( const operation_type& op ); + void_result do_apply( const operation_type& op ); +}; + +class custom_authority_delete_evaluator : public evaluator +{ +public: + typedef custom_authority_delete_operation operation_type; + + void_result do_evaluate( const operation_type& op ); + void_result do_apply( const operation_type& op ); +}; + +} } // graphene::chain diff --git a/libraries/chain/include/graphene/chain/custom_authority_object.hpp b/libraries/chain/include/graphene/chain/custom_authority_object.hpp new file mode 100644 index 0000000000..4d5585f8ea --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_authority_object.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include +#include +#include +#include + +namespace graphene { namespace chain { + + /** + * @brief Tracks account custom authorities + * @ingroup object + * + */ + class custom_authority_object : public abstract_object + { + public: + static const uint8_t space_id = implementation_ids; + static const uint8_t type_id = impl_custom_authority_object_type; + + account_id_type account; + uint32_t custom_id; + bool enabled; + time_point_sec valid_from; + time_point_sec valid_to; + unsigned_int operation_type; + authority auth; + vector restrictions; + }; + + struct by_account_custom; + + /** + * @ingroup object_index + */ + typedef multi_index_container< + custom_authority_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + composite_key< + custom_authority_object, + member, + member + > + > + > + > custom_authority_multi_index_type; + + /** + * @ingroup object_index + */ + typedef generic_index custom_authority_index; + +} } // graphene::chain + +FC_REFLECT_DERIVED( graphene::chain::custom_authority_object, + (graphene::db::object), + (account) + (custom_id) + (enabled) + (valid_from) + (valid_to) + (operation_type) + (auth) + (restrictions) + ) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp new file mode 100644 index 0000000000..677cbc8188 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include +#include + +namespace graphene { namespace chain { + + /** + * @brief Create a new custom authority + * @ingroup operations + */ + struct custom_authority_create_operation : public base_operation + { + struct fee_parameters_type + { + uint64_t basic_fee = GRAPHENE_BLOCKCHAIN_PRECISION; + uint32_t price_per_k_unit = 100; ///< units = valid seconds * items in auth * items in restrictions + }; + + asset fee; // TODO: defer fee to expiration / update / removal ? + account_id_type account; + uint32_t custom_id; + bool enabled; + time_point_sec valid_from; + time_point_sec valid_to; + unsigned_int operation_type; + authority auth; + vector restrictions; + + empty_extensions_type extensions; + + account_id_type fee_payer()const { return account; } + void validate()const; + share_type calculate_fee(const fee_parameters_type& k)const; + }; + + /** + * @brief Update a custom authority + * @ingroup operations + */ + struct custom_authority_update_operation : public base_operation + { + struct fee_parameters_type + { + uint64_t basic_fee = GRAPHENE_BLOCKCHAIN_PRECISION; + uint32_t price_per_k_unit = 100; ///< units = valid seconds * items in auth * items in restrictions + }; + + asset fee; + account_id_type account; + uint64_t delta_units; // to calculate fee, it will be validated in evaluator + // Note: if start was in the past, when updating, used fee should be deducted + + account_id_type fee_payer()const { return account; } + void validate()const; + share_type calculate_fee(const fee_parameters_type& k)const; + }; + + + /** + * @brief Delete a custom authority + * @ingroup operations + */ + struct custom_authority_delete_operation : public base_operation + { + struct fee_parameters_type { uint64_t fee = GRAPHENE_BLOCKCHAIN_PRECISION; }; + + asset fee; + account_id_type account; + + account_id_type fee_payer()const { return account; } + void validate()const; + }; + +} } // graphene::chain + +FC_REFLECT( graphene::chain::custom_authority_create_operation::fee_parameters_type, (basic_fee)(price_per_k_unit) ) +FC_REFLECT( graphene::chain::custom_authority_update_operation::fee_parameters_type, (basic_fee)(price_per_k_unit) ) +FC_REFLECT( graphene::chain::custom_authority_delete_operation::fee_parameters_type, (fee) ) + +FC_REFLECT( graphene::chain::custom_authority_create_operation, + (fee) + (account) + (custom_id) + (enabled) + (valid_from) + (valid_to) + (operation_type) + (auth) + (restrictions) + (extensions) + ) + +FC_REFLECT( graphene::chain::custom_authority_update_operation, (fee)(account) ) +FC_REFLECT( graphene::chain::custom_authority_delete_operation, (fee)(account) ) diff --git a/libraries/chain/include/graphene/chain/protocol/ext.hpp b/libraries/chain/include/graphene/chain/protocol/ext.hpp index f868fa0b23..ef85d83d4f 100644 --- a/libraries/chain/include/graphene/chain/protocol/ext.hpp +++ b/libraries/chain/include/graphene/chain/protocol/ext.hpp @@ -128,8 +128,14 @@ struct graphene_extension_unpack_visitor const uint32_t max_depth; }; +struct empty_struct {}; + +typedef extension< empty_struct > empty_extensions_type; + } } // graphene::chain +FC_REFLECT( graphene::chain::empty_struct, ) + namespace fc { template< typename T > diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index de2cfa7fd9..be41cb3b15 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -27,9 +27,10 @@ #include #include #include -#include #include #include +#include +#include #include #include #include @@ -46,57 +47,60 @@ namespace graphene { namespace chain { * * Defines the set of valid operations as a discriminated union type. */ - typedef fc::static_variant< - transfer_operation, - limit_order_create_operation, - limit_order_cancel_operation, - call_order_update_operation, - fill_order_operation, // VIRTUAL - account_create_operation, - account_update_operation, - account_whitelist_operation, - account_upgrade_operation, - account_transfer_operation, - asset_create_operation, - asset_update_operation, - asset_update_bitasset_operation, - asset_update_feed_producers_operation, - asset_issue_operation, - asset_reserve_operation, - asset_fund_fee_pool_operation, - asset_settle_operation, - asset_global_settle_operation, - asset_publish_feed_operation, - witness_create_operation, - witness_update_operation, - proposal_create_operation, - proposal_update_operation, - proposal_delete_operation, - withdraw_permission_create_operation, - withdraw_permission_update_operation, - withdraw_permission_claim_operation, - withdraw_permission_delete_operation, - committee_member_create_operation, - committee_member_update_operation, - committee_member_update_global_parameters_operation, - vesting_balance_create_operation, - vesting_balance_withdraw_operation, - worker_create_operation, - custom_operation, - assert_operation, - balance_claim_operation, - override_transfer_operation, - transfer_to_blind_operation, - blind_transfer_operation, - transfer_from_blind_operation, - asset_settle_cancel_operation, // VIRTUAL - asset_claim_fees_operation, - fba_distribute_operation, // VIRTUAL - bid_collateral_operation, - execute_bid_operation, // VIRTUAL - asset_claim_pool_operation, - asset_update_issuer_operation - > operation; + #define GRAPHENE_OPERATIONS_VARIADIC \ + /* 0 */ transfer_operation, \ + /* 1 */ limit_order_create_operation, \ + /* 2 */ limit_order_cancel_operation, \ + /* 3 */ call_order_update_operation, \ + /* 4 */ fill_order_operation, /* VIRTUAL */ \ + /* 5 */ account_create_operation, \ + /* 6 */ account_update_operation, \ + /* 7 */ account_whitelist_operation, \ + /* 8 */ account_upgrade_operation, \ + /* 9 */ account_transfer_operation, \ + /* 10 */ asset_create_operation, \ + /* 11 */ asset_update_operation, \ + /* 12 */ asset_update_bitasset_operation, \ + /* 13 */ asset_update_feed_producers_operation, \ + /* 14 */ asset_issue_operation, \ + /* 15 */ asset_reserve_operation, \ + /* 16 */ asset_fund_fee_pool_operation, \ + /* 17 */ asset_settle_operation, \ + /* 18 */ asset_global_settle_operation, \ + /* 19 */ asset_publish_feed_operation, \ + /* 20 */ witness_create_operation, \ + /* 21 */ witness_update_operation, \ + /* 22 */ proposal_create_operation, \ + /* 23 */ proposal_update_operation, \ + /* 24 */ proposal_delete_operation, \ + /* 25 */ withdraw_permission_create_operation, \ + /* 26 */ withdraw_permission_update_operation, \ + /* 27 */ withdraw_permission_claim_operation, \ + /* 28 */ withdraw_permission_delete_operation, \ + /* 29 */ committee_member_create_operation, \ + /* 30 */ committee_member_update_operation, \ + /* 31 */ committee_member_update_global_parameters_operation, \ + /* 32 */ vesting_balance_create_operation, \ + /* 33 */ vesting_balance_withdraw_operation, \ + /* 34 */ worker_create_operation, \ + /* 35 */ custom_operation, \ + /* 36 */ assert_operation, \ + /* 37 */ balance_claim_operation, \ + /* 38 */ override_transfer_operation, \ + /* 39 */ transfer_to_blind_operation, \ + /* 40 */ blind_transfer_operation, \ + /* 41 */ transfer_from_blind_operation, \ + /* 42 */ asset_settle_cancel_operation, /* VIRTUAL */ \ + /* 43 */ asset_claim_fees_operation, \ + /* 44 */ fba_distribute_operation, /* VIRTUAL */ \ + /* 45 */ bid_collateral_operation, \ + /* 46 */ execute_bid_operation, /* VIRTUAL */ \ + /* 47 */ asset_claim_pool_operation, \ + /* 48 */ asset_update_issuer_operation, \ + /* 49 */ custom_authority_create_operation, \ + /* 50 */ custom_authority_update_operation, \ + /* 51 */ custom_authority_delete_operation + typedef fc::static_variant< GRAPHENE_OPERATIONS_VARIADIC > operation; /// @} // operations group diff --git a/libraries/chain/include/graphene/chain/protocol/restriction.hpp b/libraries/chain/include/graphene/chain/protocol/restriction.hpp new file mode 100644 index 0000000000..66c65e2e3b --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/restriction.hpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#pragma once +#include + +namespace graphene { namespace chain { + + /** + * Defines the set of valid operation restritions as a discriminated union type. + */ + struct restriction + { + + enum member_modifier_type + { + mmod_none, + mmod_size, + mmod_pack_size, + MEMBER_MODIFIER_TYPE_COUNT ///< Sentry value which contains the number of different types + }; + + enum function_type + { + func_eq, + func_ne, + func_lt, + func_le, + func_gt, + func_ge, + func_in, + func_not_in, + func_has_all, + func_has_none, + //func_is_valid, // -> size() == 1 + //func_not_valid, // -> size() == 0 + func_attr, + FUNCTION_TYPE_COUNT ///< Sentry value which contains the number of different types + }; + + #define GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC \ + /* 0 */ void_t, \ + /* 1 */ bool, \ + /* 2 */ int64_t, \ + /* 3 */ string, \ + /* 4 */ time_point_sec, \ + /* 5 */ public_key_type, \ + /* 6 */ fc::sha256, \ + /* 7 */ account_id_type, \ + /* 8 */ asset_id_type, \ + /* 9 */ force_settlement_id_type, \ + /* 10 */ committee_member_id_type, \ + /* 11 */ witness_id_type, \ + /* 12 */ limit_order_id_type, \ + /* 13 */ call_order_id_type, \ + /* 14 */ custom_id_type, \ + /* 15 */ proposal_id_type, \ + /* 16 */ withdraw_permission_id_type, \ + /* 17 */ vesting_balance_id_type, \ + /* 18 */ worker_id_type, \ + /* 19 */ balance_id_type, \ + /* 20 */ flat_set< bool >, \ + /* 21 */ flat_set< int64_t >, \ + /* 22 */ flat_set< string >, \ + /* 23 */ flat_set< time_point_sec >, \ + /* 24 */ flat_set< public_key_type >, \ + /* 25 */ flat_set< fc::sha256 >, \ + /* 26 */ flat_set< account_id_type >, \ + /* 27 */ flat_set< asset_id_type >, \ + /* 28 */ flat_set< force_settlement_id_type >, \ + /* 29 */ flat_set< committee_member_id_type >, \ + /* 30 */ flat_set< witness_id_type >, \ + /* 31 */ flat_set< limit_order_id_type >, \ + /* 32 */ flat_set< call_order_id_type >, \ + /* 33 */ flat_set< custom_id_type >, \ + /* 34 */ flat_set< proposal_id_type >, \ + /* 35 */ flat_set< withdraw_permission_id_type >, \ + /* 36 */ flat_set< vesting_balance_id_type >, \ + /* 37 */ flat_set< worker_id_type >, \ + /* 38 */ flat_set< balance_id_type >, \ + /* 39 */ vector< restriction > + + typedef static_variant < GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC > argument_type; + + unsigned_int member; // index, use unsigned_int to save space TODO jsonify to actual name + unsigned_int member_modifier; // index, use unsigned_int to save space TODO jsonify to actual name + unsigned_int function; // index, use unsigned_int to save space TODO jsonify to actual name + argument_type argument; + + empty_extensions_type extensions; + + uint64_t get_units()const; + + /// Validates the restriction with given operation type, to be called by an operation validator + void validate( unsigned_int op_type )const; + + /// Validates common data in the restriction, to be used internally + void validate_common_data() const; + + }; + +} } // graphene::chain + +FC_REFLECT_ENUM( graphene::chain::restriction::member_modifier_type, + (mmod_none) + (mmod_size) + (mmod_pack_size) + (MEMBER_MODIFIER_TYPE_COUNT) + ) + +FC_REFLECT_ENUM( graphene::chain::restriction::function_type, + (func_eq) + (func_ne) + (func_lt) + (func_le) + (func_gt) + (func_ge) + (func_in) + (func_not_in) + (func_has_all) + (func_has_none) + //(func_is_valid) + //(func_not_valid) + (func_attr) + (FUNCTION_TYPE_COUNT) + ) + +FC_REFLECT( graphene::chain::restriction, + (member) + (member_modifier) + (function) + (argument) + (extensions) + ) + diff --git a/libraries/chain/include/graphene/chain/protocol/types.hpp b/libraries/chain/include/graphene/chain/protocol/types.hpp index 06ab7ff291..9a3db70308 100644 --- a/libraries/chain/include/graphene/chain/protocol/types.hpp +++ b/libraries/chain/include/graphene/chain/protocol/types.hpp @@ -162,7 +162,8 @@ namespace graphene { namespace chain { impl_special_authority_object_type, impl_buyback_object_type, impl_fba_accumulator_object_type, - impl_collateral_bid_object_type + impl_collateral_bid_object_type, + impl_custom_authority_object_type }; //typedef fc::unsigned_int object_id_type; @@ -214,6 +215,7 @@ namespace graphene { namespace chain { class buyback_object; class fba_accumulator_object; class collateral_bid_object; + class custom_authority_object; typedef object_id< implementation_ids, impl_global_property_object_type, global_property_object> global_property_id_type; typedef object_id< implementation_ids, impl_dynamic_global_property_object_type, dynamic_global_property_object> dynamic_global_property_id_type; @@ -234,6 +236,7 @@ namespace graphene { namespace chain { typedef object_id< implementation_ids, impl_buyback_object_type, buyback_object > buyback_id_type; typedef object_id< implementation_ids, impl_fba_accumulator_object_type, fba_accumulator_object > fba_accumulator_id_type; typedef object_id< implementation_ids, impl_collateral_bid_object_type, collateral_bid_object > collateral_bid_id_type; + typedef object_id< implementation_ids, impl_custom_authority_object_type, custom_authority_object > custom_authority_id_type; typedef fc::ripemd160 block_id_type; typedef fc::ripemd160 checksum_type; @@ -364,6 +367,7 @@ FC_REFLECT_ENUM( graphene::chain::impl_object_type, (impl_buyback_object_type) (impl_fba_accumulator_object_type) (impl_collateral_bid_object_type) + (impl_custom_authority_object_type) ) FC_REFLECT_TYPENAME( graphene::chain::share_type ) @@ -395,6 +399,7 @@ FC_REFLECT_TYPENAME( graphene::chain::special_authority_id_type ) FC_REFLECT_TYPENAME( graphene::chain::buyback_id_type ) FC_REFLECT_TYPENAME( graphene::chain::fba_accumulator_id_type ) FC_REFLECT_TYPENAME( graphene::chain::collateral_bid_id_type ) +FC_REFLECT_TYPENAME( graphene::chain::custom_authority_id_type ) FC_REFLECT( graphene::chain::void_t, ) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp new file mode 100644 index 0000000000..25522c7100 --- /dev/null +++ b/libraries/chain/protocol/custom_authority.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include + +namespace graphene { namespace chain { + +share_type custom_authority_create_operation::calculate_fee( const fee_parameters_type& k )const +{ + share_type core_fee_required = k.basic_fee; + + if( enabled ) + { + share_type unit_fee = k.price_per_k_unit; + unit_fee *= (valid_to - valid_from).to_seconds(); + unit_fee *= auth.num_auths(); + uint64_t restriction_units = 0; + for( const auto& r : restrictions ) + { + restriction_units += r.get_units(); + } + unit_fee *= restriction_units; + unit_fee /= 1000; + core_fee_required += unit_fee; + } + + return core_fee_required; +} + +void custom_authority_create_operation::validate()const +{ + FC_ASSERT( fee.amount >= 0, "Fee amount can not be negative" ); + + FC_ASSERT( account != GRAPHENE_TEMP_ACCOUNT + && account != GRAPHENE_COMMITTEE_ACCOUNT + && account != GRAPHENE_WITNESS_ACCOUNT + && account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, + "Can not create custom authority for special accounts" ); + + FC_ASSERT( valid_from < valid_to, "valid_from must be earlier than valid_to" ); + + // Note: when adding new operation with hard fork, need to check more strictly in evaluator + // TODO add code in evaluator + FC_ASSERT( operation_type < operation::count(), "operation_type is too large" ); + + // Note: allow auths to be empty + //FC_ASSERT( auth.num_auths() > 0, "Can not set empty auth" ); + FC_ASSERT( auth.address_auths.size() == 0, "Address auth is not supported" ); + // Note: allow auths to be impossible + //FC_ASSERT( !auth.is_impossible(), "cannot use an imposible authority threshold" ); + + // Note: allow restrictions to be empty + for( const auto& r: restrictions ) + { + // recursively validate member index and argument type + r.validate( operation_type ); + } +} + +share_type custom_authority_update_operation::calculate_fee( const fee_parameters_type& k )const +{ + share_type core_fee_required = k.basic_fee; + + share_type unit_fee = k.price_per_k_unit; + unit_fee *= delta_units; + unit_fee /= 1000; + + return core_fee_required + unit_fee; +} + +void custom_authority_update_operation::validate()const +{ + FC_ASSERT( fee.amount >= 0, "Fee amount can not be negative" ); + + FC_ASSERT( account != GRAPHENE_TEMP_ACCOUNT + && account != GRAPHENE_COMMITTEE_ACCOUNT + && account != GRAPHENE_WITNESS_ACCOUNT + && account != GRAPHENE_RELAXED_COMMITTEE_ACCOUNT, + "Can not create custom authority for special accounts" ); +/* + FC_ASSERT( valid_from < valid_to, "valid_from must be earlier than valid_to" ); + + // Note: when adding new operation with hard fork, need to check more strictly in evaluator + // TODO add code in evaluator + FC_ASSERT( operation_type < operation::count(), "operation type too large" ); + + FC_ASSERT( auth.num_auths() > 0, "Can not set empty auth" ); + FC_ASSERT( auth.address_auths.size() == 0, "Address auth is not supported" ); + //FC_ASSERT( !auth.is_impossible(), "cannot use an imposible authority threshold" ); + + // Note: allow restrictions to be empty + for( const auto& r : restrictions ) + { + // TODO recursively validate member index and argument type + r.validate( operation_type ); + } +*/ +} + +void custom_authority_delete_operation::validate()const +{ +} + +} } // graphene::chain diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp new file mode 100644 index 0000000000..73bc2ca954 --- /dev/null +++ b/libraries/chain/protocol/restriction.cpp @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2018 Abit More, and contributors. + * + * The MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include +#include +#include + +#include +#include + +#include + +namespace graphene { namespace chain { + +template +using bool_const = std::integral_constant; + +struct restriction_validation_visitor; + +struct argument_get_units_visitor +{ + typedef uint64_t result_type; + + template + inline result_type operator()( const T& t ) + { + return 1; + } + + inline result_type operator()( const fc::sha256& t ) + { + return 4; + } + + inline result_type operator()( const public_key_type& t ) + { + return 4; + } + + inline result_type operator()( const string& t ) + { + return ( t.size() + 7 ) / 8; + } + + template + inline result_type operator()( const flat_set& t ) + { + return t.size() * (*this)( *((const T*)nullptr) ); + } + + template + inline result_type operator()( const flat_set& t ) + { + result_type result = 0; + for( const auto& s : t ) + { + result += ( s.size() + 7 ) / 8; + } + return result; + } + + result_type operator()( const vector& t ) + { + result_type result = 0; + for( const auto& r : t ) + { + result += r.argument.visit(*this); + } + return result; + } +}; + +uint64_t restriction::get_units()const +{ + argument_get_units_visitor vtor; + return argument.visit( vtor ); +} + +// comparable data types can use < <= > >= == != +template struct is_comparable_data_type { static const bool value = false; }; + +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; +template<> struct is_comparable_data_type { static const bool value = true; }; + +// simple data types can use == != +template struct is_simple_data_type { static const bool value = is_comparable_data_type::value; }; + +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; + +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; +template<> struct is_simple_data_type { static const bool value = true; }; + +template +struct compatible_argument_validation_visitor +{ + typedef void result_type; + const char* name; + + compatible_argument_validation_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) // by default incompatible + { + FC_THROW( "Argument '${arg}' is incompatible for ${name}", + ("arg", arg)("name", name) ); + } + + // argument type T is compatible with member type T + inline result_type operator()( const T& arg ) {} +}; + +// compatible member types X and argument type Y and X != Y +template<> template<> inline void compatible_argument_validation_visitor::operator()( const string& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +// no int64_t here because it's already covered by generic template +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validation_visitor::operator()( const int64_t& arg ) {} + +template +struct list_argument_validation_visitor +{ + typedef void result_type; + const char* name; + + list_argument_validation_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) // by default incompatible + { + FC_THROW( "Argument '${arg}' is incompatible, requires a compatible flat_set for ${name}", + ("arg", arg)("name", name) ); + } + + // argument type flat_set is compatible with member list_like + inline result_type operator()( const flat_set& arg ) {} +}; + +// compatible member types X and argument type flat_set and X != Y +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +// no int64_t here because it's already covered by generic template +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validation_visitor::operator()( const flat_set& arg ) {} + +template +struct attr_argument_validation_visitor +{ + typedef void result_type; + const char* name; + + attr_argument_validation_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) + { + FC_THROW( "Argument '${arg}' is incompatible, requires 'vector' for ${name}", + ("arg", arg)("name", name) ); + } + + result_type operator()( const vector& arg ) + { + // Recursively check T.members + for( const restriction& r : arg ) + { + // validate common data + r.validate_common_data(); + // validate member-related data + restriction_validation_visitor vtor( r ); + vtor( *((const T*)nullptr) ); + } + } +}; + +struct number_argument_validation_visitor +{ + typedef void result_type; + const char* name; + + number_argument_validation_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) + { + FC_THROW( "Argument '${arg}' is incompatible, requires a number type for ${name}", + ("arg", arg)("name", name) ); + } + + inline result_type operator()( const int64_t& arg ) {} +}; + +inline bool is_subset_function( const restriction::function_type function ) +{ + return ( function == restriction::func_in + || function == restriction::func_not_in ); +} + +inline bool is_superset_function( const restriction::function_type function ) +{ + return ( function == restriction::func_has_all + || function == restriction::func_has_none ); +} + +inline bool is_equal_function( const restriction::function_type function ) +{ + return ( function == restriction::func_eq + || function == restriction::func_ne ); +} + +inline bool is_compare_function( const restriction::function_type function ) +{ + return ( function == restriction::func_eq + || function == restriction::func_ne + || function == restriction::func_lt + || function == restriction::func_le + || function == restriction::func_gt + || function == restriction::func_ge ); +} + +void require_compare_function( const restriction& r, const char* name ) +{ + // function should be a compare function + FC_ASSERT( is_compare_function( r.function ), + "Function '${func}' is incompatible, requires a compare function for ${name}", + ("func", r.function)("name", name) ); +} + +template +void require_compatible_argument( const restriction& r, const char* name ) +{ + // argument should be T-compatible + compatible_argument_validation_visitor vtor( name ); + r.argument.visit( vtor ); +} + +template +void require_compatible_list_argument( const restriction& r, const char* name ) +{ + // argument should be flat_set< T-compatible > + list_argument_validation_visitor vtor( name ); + r.argument.visit( vtor ); +} + +template +void require_attr_argument( const restriction& r, const char* name ) +{ + // argument should be attr and compatible to T + attr_argument_validation_visitor vtor( name ); + r.argument.visit( vtor ); +} + +void require_number_argument( const restriction& r, const char* name ) +{ + // argument should be a number + number_argument_validation_visitor vtor( name ); + r.argument.visit( vtor ); +} + +struct restriction_validation_helper +{ + const restriction& _restriction; ///< the restriction + + restriction_validation_helper( const restriction& r ) : _restriction(r) + { + FC_ASSERT( _restriction.member_modifier.value == restriction::mmod_none, + "Internal error: should only use this helper for mmod_none" ); + } + + template // comparable, simple data type + void validate_member( const char* name, std::true_type, std::true_type ) + { + if( is_subset_function( _restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_compatible_list_argument( _restriction, name ); + } + else if( is_compare_function( _restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( _restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires a compare function or subset function for ${name}", + ("func", _restriction.function)("name", name) ); + } + } + + template // non-comparable, simple data type + void validate_member( const char* name, std::false_type, std::true_type ) + { + if( is_subset_function( _restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_compatible_list_argument( _restriction, name ); + } + else if( is_equal_function( _restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( _restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires an equal function or subset function for ${name}", + ("func", _restriction.function)("name", name) ); + } + } + + template // non-comparable, not-simple, aka object-like type + void validate_member( const char* name, std::false_type, std::false_type ) + { + FC_ASSERT( _restriction.function == restriction::func_attr, + "Object-like member '${name}' can only use func_attr", + ("name", name) ); + // argument need to be a attribute_restriction + require_attr_argument( _restriction, name ); + } + + template + void validate_list_like_member( const char* name ) + { + FC_ASSERT( is_superset_function( _restriction.function ), + "List-like member '${name}' can only use func_has_all or func_has_none", + ("name", name) ); + FC_ASSERT( is_simple_data_type::value, + "Simple data type in list-like member '${name}' is required", + ("name", name) ); + // argument need to be a list, and type should be compatible to T + require_compatible_list_argument( _restriction, name ); + } + + template + void validate_by_member_type( const char* name, const T* t ) // generic template + { + const bool is_comparable = is_comparable_data_type::value; + const bool is_simple = is_simple_data_type::value; + validate_member( name, bool_const(), bool_const() ); + } + + template + void validate_by_member_type( const char* name, const optional* t ) + { + // extract the underlying type + validate_by_member_type( name, (const T*)nullptr ); + } + + template + void validate_by_member_type( const char* name, const safe* t ) + { + // extract the underlying type + validate_by_member_type( name, (const T*)nullptr ); + } + + template + void validate_by_member_type( const char* name, const smart_ref* t ) + { + // extract the underlying type + validate_by_member_type( name, (const T*)nullptr ); + } + + template + void validate_by_member_type( const char* name, const extension* t ) + { + // extract the underlying type + validate_by_member_type( name, (const T*)nullptr ); + } + + template + void validate_by_member_type( const char* name, const vector* t ) + { + validate_list_like_member( name ); + } + + template + void validate_by_member_type( const char* name, const set* t ) + { + validate_list_like_member( name ); + } + + template + void validate_by_member_type( const char* name, const flat_set* t ) + { + validate_list_like_member( name ); + } + + template + void validate_by_member_type( const char* name, const flat_map* t ) + { + FC_THROW( "Restriction on '${name}' is not supported due to its type", + ("name", name) ); + } + + template + void validate_by_member_type( const char* name, const static_variant* t ) + { + FC_THROW( "Restriction on '${name}' is not supported due to its type", + ("name", name) ); + } + + void validate_by_member_type( const char* name, const fba_accumulator_id_type* t ) + { + FC_THROW( "Restriction on '${name}' is not supported due to its type", + ("name", name) ); + } + +}; + +struct member_validation_visitor +{ + typedef void result_type; + + const restriction& _restriction; + + member_validation_visitor( const restriction& r ) : _restriction(r) {} + + template + void operator()( const char* name )const + { + restriction_validation_helper helper( _restriction ); + helper.validate_by_member_type( name, (const Member*)nullptr ); + } +}; + +struct restriction_validation_visitor +{ + typedef void result_type; + const restriction& _restriction; + + restriction_validation_visitor( const restriction& r ) : _restriction(r) {} + + template + result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it + { + FC_ASSERT( _restriction.member < fc::reflector::total_member_count, + "member number ${m} is too large", + ("m",_restriction.member) ); + + // other member modifiers should have been checked outside, so only check mmod_none here + if( _restriction.member_modifier.value == restriction::mmod_none ) + { + member_validation_visitor vtor( _restriction ); + fc::reflector::visit_local_member( vtor, _restriction.member.value ); + } + } + +}; + +#define GRAPHENE_OP_IDX_CASE_VISIT(r, data, I, elem) \ + case I : \ + operation::visit< I >( vtor ); \ + break; + +void validate_restriction_details( const restriction& r, unsigned_int op_type ) +{ + restriction_validation_visitor vtor( r ); + switch( op_type.value ) + { + // will have code like below for all operations: + // case op_type : operation::visit( visitor ) + BOOST_PP_SEQ_FOR_EACH_I( GRAPHENE_OP_IDX_CASE_VISIT, , BOOST_PP_VARIADIC_TO_SEQ( GRAPHENE_OPERATIONS_VARIADIC ) ) + + default: + break; + } + +} + +void restriction::validate_common_data() const +{ + // validate member modifier + FC_ASSERT( member_modifier < MEMBER_MODIFIER_TYPE_COUNT, + "member modifier number ${mm} is too large", + ("mm", member_modifier) ); + + if( member_modifier.value == mmod_size ) + { + require_compare_function( *this, "size modifier" ); + require_number_argument( *this, "size modifier" ); + } + else if( member_modifier.value == mmod_pack_size ) + { + require_compare_function( *this, "pack_size modifier" ); + require_number_argument( *this, "pack_size modifier" ); + } + + // validate function + FC_ASSERT( function < FUNCTION_TYPE_COUNT, + "function number ${f} is too large", + ("f", function) ); +} + +void restriction::validate( unsigned_int op_type )const +{ + // validate common data + validate_common_data(); + // validate details by operation_type + validate_restriction_details( *this, op_type ); +} + +} } // graphene::chain diff --git a/libraries/fc b/libraries/fc index 8e1b47a460..70dbcc11e3 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 8e1b47a460d051eb335ee9fa134258af3870cfd8 +Subproject commit 70dbcc11e39d12b74a71ef43169de37e030b88c0