From f087234213fc056aacb8093b2d6450b500894409 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 5 Aug 2018 11:22:54 -0400 Subject: [PATCH 01/22] Add basic files for custom authority feature --- libraries/chain/CMakeLists.txt | 2 + .../chain/custom_authority_evaluator.cpp | 75 ++++++ libraries/chain/db_init.cpp | 6 + libraries/chain/db_notify.cpp | 19 ++ .../chain/custom_authority_evaluator.hpp | 57 ++++ .../chain/custom_authority_object.hpp | 80 ++++++ .../chain/protocol/custom_authority.hpp | 252 ++++++++++++++++++ .../include/graphene/chain/protocol/ext.hpp | 6 + .../graphene/chain/protocol/operations.hpp | 8 +- .../include/graphene/chain/protocol/types.hpp | 7 +- 10 files changed, 509 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/custom_authority_evaluator.cpp create mode 100644 libraries/chain/include/graphene/chain/custom_authority_evaluator.hpp create mode 100644 libraries/chain/include/graphene/chain/custom_authority_object.hpp create mode 100644 libraries/chain/include/graphene/chain/protocol/custom_authority.hpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index 6fe3f47883..f7f80b1662 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -32,6 +32,7 @@ endif( GRAPHENE_DISABLE_UNITY_BUILD ) ## SORT .cpp by most likely to change / break compile add_library( graphene_chain + protocol/custom_authority.cpp # As database takes the longest to compile, start it first ${GRAPHENE_DB_FILES} fork_database.cpp @@ -80,6 +81,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..8de5ef64ea --- /dev/null +++ b/libraries/chain/custom_authority_evaluator.cpp @@ -0,0 +1,75 @@ +/* + * 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_evaluator::operation_type& op) +{ try { + database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +object_id_type custom_authority_create_evaluator::do_apply(const custom_authority_create_evaluator::operation_type& op) +{ try { + database& d = db(); + + return {}; +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_update_evaluator::do_evaluate(const custom_authority_update_evaluator::operation_type& op) +{ try { + database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_update_evaluator::do_apply(const custom_authority_update_evaluator::operation_type& 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_evaluator::operation_type& op) +{ try { + database& d = db(); + + return void_result(); +} FC_CAPTURE_AND_RETHROW( (op) ) } + +void_result custom_authority_delete_evaluator::do_apply(const custom_authority_delete_evaluator::operation_type& 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..a5d9741e2e --- /dev/null +++ b/libraries/chain/include/graphene/chain/custom_authority_object.hpp @@ -0,0 +1,80 @@ +/* + * 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 auth_id; + bool enabled; + time_point_sec valid_from; + time_point_sec valid_to; + unsigned_int operation_type; + authority auth; + vector restrictions; + }; + + /** + * @ingroup object_index + */ + typedef multi_index_container< + custom_authority_object, + indexed_by< + ordered_unique< tag, member< object, object_id_type, &object::id > > + > + > 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) + (auth_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..956019fdc8 --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -0,0 +1,252 @@ +/* + * 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 { + +/* + template struct transform_to_fee_parameters; + template + struct transform_to_fee_parameters> + { + typedef fc::static_variant< typename T::fee_parameters_type... > type; + }; + typedef transform_to_fee_parameters::type fee_parameters; +*/ + + /** + * @ingroup operations + * + * Defines the set of valid operation restritions as a discriminated union type. + */ + /// @{ +/* template struct transform_to_operation_restrictions; + template + struct transform_to_operation_restrictions> + { + typedef fc::static_variant< typename T::operation_restriction_type... > type; + }; + typedef transform_to_fee_parameters::type operation_restrictions; +*/ /// @} + +// vector restrictions; + + /** + * op_wrapper is used to get around the circular definition of operation and proposals that contain them. + */ + struct op_wrapper; + + struct operation_restriction; + typedef vector attr_restriction_type; + + struct operation_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, + func_not_valid, + FUNCTION_TYPE_COUNT ///< Sentry value which contains the number of different types + }; + + typedef static_variant < + void_t, + + bool, + int64_t, + string, + + account_id_type, + asset_id_type, + force_settlement_id_type, + committee_member_id_type, + witness_id_type, + limit_order_id_type, + call_order_id_type, + custom_id_type, + proposal_id_type, + withdraw_permission_id_type, + vesting_balance_id_type, + worker_id_type, + balance_id_type, + + flat_set< bool >, + flat_set< int64_t >, + flat_set< string >, + + flat_set< account_id_type >, + flat_set< asset_id_type >, + flat_set< force_settlement_id_type >, + flat_set< committee_member_id_type >, + flat_set< witness_id_type >, + flat_set< limit_order_id_type >, + flat_set< call_order_id_type >, + flat_set< custom_id_type >, + flat_set< proposal_id_type >, + flat_set< withdraw_permission_id_type >, + flat_set< vesting_balance_id_type >, + flat_set< worker_id_type >, + flat_set< balance_id_type >, + + attr_restriction_type + + > 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; + void validate( const op_wrapper& opw )const; + }; + + /** + * @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 auth_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_ENUM( graphene::chain::operation_restriction::member_modifier_type, + (mmod_none) + (mmod_size) + (mmod_pack_size) + (MEMBER_MODIFIER_TYPE_COUNT) + ) + +FC_REFLECT_ENUM( graphene::chain::operation_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) + (FUNCTION_TYPE_COUNT) + ) + +FC_REFLECT( graphene::chain::operation_restriction, + (member) + (member_modifier) + (function) + (argument) + (extensions) + ) + +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) ) +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..bc77865379 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 @@ -95,7 +96,10 @@ namespace graphene { namespace chain { bid_collateral_operation, execute_bid_operation, // VIRTUAL asset_claim_pool_operation, - asset_update_issuer_operation + asset_update_issuer_operation, + custom_authority_create_operation, + custom_authority_update_operation, + custom_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 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, ) From a479a7e7164bc9e68d3016bbdbdab82bb33405df Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 05:06:56 -0400 Subject: [PATCH 02/22] Add protocol/custom_authority.cpp --- .../chain/protocol/custom_authority.hpp | 8 +- libraries/chain/protocol/custom_authority.cpp | 591 ++++++++++++++++++ 2 files changed, 595 insertions(+), 4 deletions(-) create mode 100644 libraries/chain/protocol/custom_authority.cpp diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 956019fdc8..716060adfe 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -84,8 +84,8 @@ namespace graphene { namespace chain { func_not_in, func_has_all, func_has_none, - func_is_valid, - func_not_valid, + //func_is_valid, // -> size() == 1 + //func_not_valid, // -> size() == 0 FUNCTION_TYPE_COUNT ///< Sentry value which contains the number of different types }; @@ -230,8 +230,8 @@ FC_REFLECT_ENUM( graphene::chain::operation_restriction::function_type, (func_not_in) (func_has_all) (func_has_none) - (func_is_valid) - (func_not_valid) + //(func_is_valid) + //(func_not_valid) (FUNCTION_TYPE_COUNT) ) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp new file mode 100644 index 0000000000..5545ade304 --- /dev/null +++ b/libraries/chain/protocol/custom_authority.cpp @@ -0,0 +1,591 @@ +/* + * 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 { + +struct argument_get_units_visitor +{ + typedef uint64_t result_type; + + template + result_type operator()( const T& t ) + { + return 1; + } + + template + result_type operator()( const flat_set& t ) + { + return t.size(); + } + + result_type operator()( const attr_restriction_type& t ) + { + result_type result = 0; + for( const auto& restriction : t ) + { + result += restriction.argument.visit(*this); + } + return result; + } +}; + +uint64_t operation_restriction::get_units()const +{ + argument_get_units_visitor vtor; + return argument.visit( vtor ); +} + +namespace detail { + template bool is_simple_data_type() { return false; } + + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + + template<> bool is_simple_data_type() { return true; } + + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } + template<> bool is_simple_data_type() { return true; } +} + +template +struct list_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + list_argument_validate_visitor( const char* _name ) : name(_name) {} + + + template + result_type operator()( const ArgType& arg ); + + // argument type flat_set is compatible with member list_like + result_type operator()( const flat_set& arg ) {} +}; + +template template +void list_argument_validate_visitor::operator()( const ArgType& arg ) +{ + FC_THROW( "Argument type '${a}' is incompatible with list-like member '${m}' whose contained type is ${t}", + ("a", fc::get_typename::name()) + ("m", name) + ("t", fc::get_typename::name()) ); +} + +// special compatible types +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} + +/* +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + // TODO kill duplicate code + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; + +template<> +struct list_argument_validate_visitor +{ + typedef void result_type; + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Incompatible list type for ${t} : ${a}", + ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); + } + + result_type operator()( const flat_set& arg ) {} +}; +*/ + +struct number_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + number_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + result_type operator()( const ArgType& arg ) + { + FC_THROW( "Can only use a number type as argument for ${name}", + ("name", name) ); + } + + result_type operator()( const int64_t& arg ) {} +}; + +void require_comparative_function( const operation_restriction& op_restriction, const char* name ) +{ + // function should be a comparative function + FC_ASSERT( op_restriction.function == operation_restriction::func_eq + || op_restriction.function == operation_restriction::func_ne + || op_restriction.function == operation_restriction::func_lt + || op_restriction.function == operation_restriction::func_le + || op_restriction.function == operation_restriction::func_gt + || op_restriction.function == operation_restriction::func_ge, + "Can only use comparative function for ${name}", + ("name", name) ); +} + +template +void require_list_argument( const operation_restriction& op_restriction, const char* name ) +{ + // argument should be flat_set< T-compatible > + list_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +void require_number_argument( const operation_restriction& op_restriction, const char* name ) +{ + // argument should be a number + number_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +struct op_restriction_validation_helper +{ + const operation_restriction& op_restriction; ///< the restriction + + op_restriction_validation_helper( const operation_restriction& opr ) : op_restriction(opr) {} + + // by default don't support undefined types + // FIXME need it for recursion + template + void validate_by_member_type( const char* name, const T& t ) + { + FC_THROW( "Restriction on ${name} is not supported due to its type ${type}", + ("name", name)("type", fc::get_typename::name()) ); + } + + template + void validate_by_member_type( const char* name, const optional& t ) + { + if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + { + // extract the underlying type + validate_by_member_type( name, T() ); + } + } + + template + void validate_by_member_type( const char* name, const safe& t ) + { + if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + { + // extract the underlying type + validate_by_member_type( name, t.value ); + } + } + + template + void validate_by_member_type( const char* name, const smart_ref& t ) + { + if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + { + // extract the underlying type + validate_by_member_type( name, t.value ); + } + } + + template + void validate_list_like_member( const char* name ) + { + if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + { + FC_ASSERT( op_restriction.function == operation_restriction::func_has_all + || op_restriction.function == operation_restriction::func_has_none, + "List-like member '${name}' can only use func_has_all or func_has_none", + ("name", name) ); + FC_ASSERT( detail::is_simple_data_type(), + "Simple data type in list-like member '${name}' is required", + ("name", name) ); + // validate argument, need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); + } + } + + 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 ); + } +}; + +/* + result_type operator()( const attr_restriction_type& t ) + { + for( const auto& restriction : t ) + { + restriction.argument.visit(*this); + } + } +}; +*/ + +template< typename OpType > +struct member_validate_visitor +{ + member_validate_visitor( const OpType& o, const operation_restriction& opr ) : op(o), op_restriction(opr) {} + + template + void operator()( const char* name )const + { + if( which == op_restriction.member ) // `op.*member` is the specified member + { + + // Firstly we check if the member type is supported + + //validate_member( op_restriction ); + + op_restriction_validation_helper helper( op_restriction ); + helper.validate_by_member_type( name, op.*member ); + + // Giving the member type, we know what function is available + // Giving function, we know what argument it should be + + //function_validate_visitor vtor( op_restriction ); + + // validate argument + //argument_validate_visitor vtor; + //argument.visit( vtor ); + } + ++which; + } + + mutable uint32_t which = 0; + const OpType& op; ///< the operation + const operation_restriction& op_restriction; ///< the restriction +}; + +struct op_restriction_validate_visitor +{ + typedef void result_type; + const operation_restriction& op_restriction; + + op_restriction_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} + + template + result_type operator()( const OpType& op ) + { + FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, + "member number ${m} is too large", + ("m",op_restriction.member) ); + + // TODO: this implementation iterates through all reflected members to find specified member, + // possible to improve performance by visiting specified member by index/number directly + member_validate_visitor vtor( op, op_restriction ); + fc::reflector::visit( vtor ); + } + +}; + +void operation_restriction::validate( const op_wrapper& opw )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_comparative_function( *this, "size modifier" ); + require_number_argument( *this, "size modifier" ); + } + else if( member_modifier.value == mmod_pack_size ) + { + require_comparative_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) ); + + // validate details + op_restriction_validate_visitor vtor( *this ); + opw.op.visit( vtor ); +} + +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& restriction : restrictions ) + { + restriction_units += restriction.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 too large" ); + operation op; + op.set_which( operation_type ); + op_wrapper opw( op ); + + // 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& restriction : restrictions ) + { + // recursively validate member index and argument type + restriction.validate( opw ); + } +} + +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& restriction : restrictions ) + { + // TODO recursively validate member index and argument type + restriction.validate( operation_type ); + } +*/ +} + +void custom_authority_delete_operation::validate()const +{ +} + +} } // graphene::chain From 79f2dabf94da4efc0ab13b8c60c000cf4c2b22ab Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 05:15:20 -0400 Subject: [PATCH 03/22] Remove commented out list_arg visitor code --- libraries/chain/protocol/custom_authority.cpp | 146 +----------------- 1 file changed, 4 insertions(+), 142 deletions(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 5545ade304..9604723a1e 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -91,6 +91,7 @@ namespace detail { template<> bool is_simple_data_type() { return true; } } + template struct list_argument_validate_visitor { @@ -99,7 +100,6 @@ struct list_argument_validate_visitor list_argument_validate_visitor( const char* _name ) : name(_name) {} - template result_type operator()( const ArgType& arg ); @@ -107,6 +107,7 @@ struct list_argument_validate_visitor result_type operator()( const flat_set& arg ) {} }; +// by default incompatible template template void list_argument_validate_visitor::operator()( const ArgType& arg ) { @@ -116,7 +117,7 @@ void list_argument_validate_visitor::operator()( const ArgType& arg ) ("t", fc::get_typename::name()) ); } -// special compatible types +// compatible types X : flat_set and X != Y template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} @@ -124,149 +125,10 @@ template<> template<> void list_argument_validate_visitor::operator()( template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +// no int64_t here because it's already covered by generic template template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -/* -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - // TODO kill duplicate code - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; - -template<> -struct list_argument_validate_visitor -{ - typedef void result_type; - - template - result_type operator()( const ArgType& arg ) - { - FC_THROW( "Incompatible list type for ${t} : ${a}", - ("t", fc::get_typename::name())("a", fc::get_typename::name()) ); - } - - result_type operator()( const flat_set& arg ) {} -}; -*/ - struct number_argument_validate_visitor { typedef void result_type; From f6978015c82c7e680e0a355481537ef736857431 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 09:00:50 -0400 Subject: [PATCH 04/22] Refactor operation visiting --- .../chain/protocol/custom_authority.hpp | 82 ++++++------- .../graphene/chain/protocol/operations.hpp | 108 +++++++++--------- libraries/chain/protocol/custom_authority.cpp | 104 ++++++++++------- 3 files changed, 150 insertions(+), 144 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 716060adfe..3008478a10 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -53,11 +53,6 @@ namespace graphene { namespace chain { // vector restrictions; - /** - * op_wrapper is used to get around the circular definition of operation and proposals that contain them. - */ - struct op_wrapper; - struct operation_restriction; typedef vector attr_restriction_type; @@ -89,48 +84,43 @@ namespace graphene { namespace chain { FUNCTION_TYPE_COUNT ///< Sentry value which contains the number of different types }; - typedef static_variant < - void_t, - - bool, - int64_t, - string, - - account_id_type, - asset_id_type, - force_settlement_id_type, - committee_member_id_type, - witness_id_type, - limit_order_id_type, - call_order_id_type, - custom_id_type, - proposal_id_type, - withdraw_permission_id_type, - vesting_balance_id_type, - worker_id_type, - balance_id_type, - - flat_set< bool >, - flat_set< int64_t >, - flat_set< string >, - - flat_set< account_id_type >, - flat_set< asset_id_type >, - flat_set< force_settlement_id_type >, - flat_set< committee_member_id_type >, - flat_set< witness_id_type >, - flat_set< limit_order_id_type >, - flat_set< call_order_id_type >, - flat_set< custom_id_type >, - flat_set< proposal_id_type >, - flat_set< withdraw_permission_id_type >, - flat_set< vesting_balance_id_type >, - flat_set< worker_id_type >, - flat_set< balance_id_type >, - + #define GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC \ + void_t, \ + bool, \ + int64_t, \ + string, \ + account_id_type, \ + asset_id_type, \ + force_settlement_id_type, \ + committee_member_id_type, \ + witness_id_type, \ + limit_order_id_type, \ + call_order_id_type, \ + custom_id_type, \ + proposal_id_type, \ + withdraw_permission_id_type, \ + vesting_balance_id_type, \ + worker_id_type, \ + balance_id_type, \ + flat_set< bool >, \ + flat_set< int64_t >, \ + flat_set< string >, \ + flat_set< account_id_type >, \ + flat_set< asset_id_type >, \ + flat_set< force_settlement_id_type >, \ + flat_set< committee_member_id_type >, \ + flat_set< witness_id_type >, \ + flat_set< limit_order_id_type >, \ + flat_set< call_order_id_type >, \ + flat_set< custom_id_type >, \ + flat_set< proposal_id_type >, \ + flat_set< withdraw_permission_id_type >, \ + flat_set< vesting_balance_id_type >, \ + flat_set< worker_id_type >, \ + flat_set< balance_id_type >, \ attr_restriction_type - > argument_type; + 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 @@ -140,7 +130,7 @@ namespace graphene { namespace chain { empty_extensions_type extensions; uint64_t get_units()const; - void validate( const op_wrapper& opw )const; + void validate( unsigned_int op_type )const; }; /** diff --git a/libraries/chain/include/graphene/chain/protocol/operations.hpp b/libraries/chain/include/graphene/chain/protocol/operations.hpp index bc77865379..be41cb3b15 100644 --- a/libraries/chain/include/graphene/chain/protocol/operations.hpp +++ b/libraries/chain/include/graphene/chain/protocol/operations.hpp @@ -47,60 +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, - custom_authority_create_operation, - custom_authority_update_operation, - custom_authority_delete_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/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 9604723a1e..4e06fba57d 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -24,6 +24,9 @@ #include #include +#include +#include + namespace graphene { namespace chain { struct argument_get_units_visitor @@ -91,7 +94,6 @@ namespace detail { template<> bool is_simple_data_type() { return true; } } - template struct list_argument_validate_visitor { @@ -111,7 +113,7 @@ struct list_argument_validate_visitor template template void list_argument_validate_visitor::operator()( const ArgType& arg ) { - FC_THROW( "Argument type '${a}' is incompatible with list-like member '${m}' whose contained type is ${t}", + FC_THROW( "Argument type '${a}' is incompatible with list-like member '${m}' which contains data with type ${t}", ("a", fc::get_typename::name()) ("m", name) ("t", fc::get_typename::name()) ); @@ -178,62 +180,54 @@ struct op_restriction_validation_helper { const operation_restriction& op_restriction; ///< the restriction - op_restriction_validation_helper( const operation_restriction& opr ) : op_restriction(opr) {} + op_restriction_validation_helper( const operation_restriction& opr ) : op_restriction(opr) + { + FC_ASSERT( op_restriction.member_modifier.value == operation_restriction::mmod_none, + "Internal error: should only use this helper for mmod_none" ); + } // by default don't support undefined types // FIXME need it for recursion template void validate_by_member_type( const char* name, const T& t ) { - FC_THROW( "Restriction on ${name} is not supported due to its type ${type}", + FC_THROW( "Restriction on '${name}' is not supported due to its type '${type}'", ("name", name)("type", fc::get_typename::name()) ); } template void validate_by_member_type( const char* name, const optional& t ) { - if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) - { - // extract the underlying type - validate_by_member_type( name, T() ); - } + // extract the underlying type + validate_by_member_type( name, T() ); } template void validate_by_member_type( const char* name, const safe& t ) { - if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) - { - // extract the underlying type - validate_by_member_type( name, t.value ); - } + // extract the underlying type + validate_by_member_type( name, t.value ); } template void validate_by_member_type( const char* name, const smart_ref& t ) { - if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) - { - // extract the underlying type - validate_by_member_type( name, t.value ); - } + // extract the underlying type + validate_by_member_type( name, t.value ); } template void validate_list_like_member( const char* name ) { - if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) - { - FC_ASSERT( op_restriction.function == operation_restriction::func_has_all - || op_restriction.function == operation_restriction::func_has_none, - "List-like member '${name}' can only use func_has_all or func_has_none", - ("name", name) ); - FC_ASSERT( detail::is_simple_data_type(), - "Simple data type in list-like member '${name}' is required", - ("name", name) ); - // validate argument, need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); - } + FC_ASSERT( op_restriction.function == operation_restriction::func_has_all + || op_restriction.function == operation_restriction::func_has_none, + "List-like member '${name}' can only use func_has_all or func_has_none", + ("name", name) ); + FC_ASSERT( detail::is_simple_data_type(), + "Simple data type in list-like member '${name}' is required", + ("name", name) ); + // validate argument, need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); } template @@ -253,6 +247,7 @@ struct op_restriction_validation_helper { validate_list_like_member( name ); } + }; /* @@ -315,15 +310,40 @@ struct op_restriction_validate_visitor "member number ${m} is too large", ("m",op_restriction.member) ); - // TODO: this implementation iterates through all reflected members to find specified member, - // possible to improve performance by visiting specified member by index/number directly - member_validate_visitor vtor( op, op_restriction ); - fc::reflector::visit( vtor ); + // other member modifiers have been checked outside, so only check mmod_none here + if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + { + // TODO: this implementation iterates through all reflected members to find specified member, + // possible to improve performance by visiting specified member by index/number directly + member_validate_visitor vtor( op, op_restriction ); + fc::reflector::visit( vtor ); + } } }; -void operation_restriction::validate( const op_wrapper& opw )const +#define GRAPHENE_OP_IDX_CASE_VISIT(r, data, I, elem) \ + case I : \ + operation::visit< I >( vtor ); \ + break; + +void validate_op_restriction_by_op_type( const operation_restriction& op_restriction, unsigned_int op_type ) +{ + op_restriction_validate_visitor vtor( op_restriction ); + switch( op_type.value ) + { + // expands to something like following 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 operation_restriction::validate( const op_wrapper& opw )const +void operation_restriction::validate( unsigned_int op_type )const { // validate member modifier FC_ASSERT( member_modifier < MEMBER_MODIFIER_TYPE_COUNT, @@ -346,9 +366,8 @@ void operation_restriction::validate( const op_wrapper& opw )const "function number ${f} is too large", ("f",function) ); - // validate details - op_restriction_validate_visitor vtor( *this ); - opw.op.visit( vtor ); + // validate details by operation_type + validate_op_restriction_by_op_type( *this, op_type ); } share_type custom_authority_create_operation::calculate_fee( const fee_parameters_type& k )const @@ -387,10 +406,7 @@ void custom_authority_create_operation::validate()const // 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" ); - operation op; - op.set_which( operation_type ); - op_wrapper opw( op ); + 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" ); @@ -402,7 +418,7 @@ void custom_authority_create_operation::validate()const for( const auto& restriction : restrictions ) { // recursively validate member index and argument type - restriction.validate( opw ); + restriction.validate( operation_type ); } } From 1e4245dd27709e709b4bc8df95dc0ecd062cd45a Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 09:34:50 -0400 Subject: [PATCH 05/22] Change validate_by_member_type arg type to pointer Changed from reference, to avoid unexpected nullptr dereference --- libraries/chain/protocol/custom_authority.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 4e06fba57d..7a428ab86d 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -189,31 +189,31 @@ struct op_restriction_validation_helper // by default don't support undefined types // FIXME need it for recursion template - void validate_by_member_type( const char* name, const T& t ) + void validate_by_member_type( const char* name, const T* t ) { FC_THROW( "Restriction on '${name}' is not supported due to its type '${type}'", ("name", name)("type", fc::get_typename::name()) ); } template - void validate_by_member_type( const char* name, const optional& t ) + void validate_by_member_type( const char* name, const optional* t ) { // extract the underlying type - validate_by_member_type( name, T() ); + validate_by_member_type( name, (const T*)nullptr ); } template - void validate_by_member_type( const char* name, const safe& t ) + void validate_by_member_type( const char* name, const safe* t ) { // extract the underlying type - validate_by_member_type( name, t.value ); + validate_by_member_type( name, (const T*)nullptr ); } template - void validate_by_member_type( const char* name, const smart_ref& t ) + void validate_by_member_type( const char* name, const smart_ref* t ) { // extract the underlying type - validate_by_member_type( name, t.value ); + validate_by_member_type( name, (const T*)nullptr ); } template @@ -231,19 +231,19 @@ struct op_restriction_validation_helper } template - void validate_by_member_type( const char* name, const vector& t ) + 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 ) + 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 ) + void validate_by_member_type( const char* name, const flat_set* t ) { validate_list_like_member( name ); } @@ -277,7 +277,7 @@ struct member_validate_visitor //validate_member( op_restriction ); op_restriction_validation_helper helper( op_restriction ); - helper.validate_by_member_type( name, op.*member ); + helper.validate_by_member_type( name, (const Member*)nullptr ); // Giving the member type, we know what function is available // Giving function, we know what argument it should be From 7aa5fb8e1e6a90d724deaa0c4f246e280586f390 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 10:05:21 -0400 Subject: [PATCH 06/22] Member_validate_visitor: avoid nullptr dereference --- libraries/chain/protocol/custom_authority.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 7a428ab86d..7978facf4c 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -264,7 +264,12 @@ struct op_restriction_validation_helper template< typename OpType > struct member_validate_visitor { - member_validate_visitor( const OpType& o, const operation_restriction& opr ) : op(o), op_restriction(opr) {} + typedef void result_type; + + mutable uint32_t which = 0; + const operation_restriction& op_restriction; + + member_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} template void operator()( const char* name )const @@ -291,9 +296,6 @@ struct member_validate_visitor ++which; } - mutable uint32_t which = 0; - const OpType& op; ///< the operation - const operation_restriction& op_restriction; ///< the restriction }; struct op_restriction_validate_visitor @@ -304,8 +306,10 @@ struct op_restriction_validate_visitor op_restriction_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} template - result_type operator()( const OpType& op ) + result_type operator()( const OpType& ) { + // Note: the parameter is a reference of *nullptr, we should not use it + FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, "member number ${m} is too large", ("m",op_restriction.member) ); @@ -315,7 +319,7 @@ struct op_restriction_validate_visitor { // TODO: this implementation iterates through all reflected members to find specified member, // possible to improve performance by visiting specified member by index/number directly - member_validate_visitor vtor( op, op_restriction ); + member_validate_visitor vtor( op_restriction ); fc::reflector::visit( vtor ); } } From 2e97fde7cba0fb8aa63800fbc2aa23cbd20b461d Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 11:14:45 -0400 Subject: [PATCH 07/22] Visit operation members by index directly --- libraries/chain/protocol/custom_authority.cpp | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 7978facf4c..b650626a92 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -261,6 +261,7 @@ struct op_restriction_validation_helper }; */ +/* template< typename OpType > struct member_validate_visitor { @@ -297,6 +298,24 @@ struct member_validate_visitor } }; +*/ + +template< typename OpType > +struct by_index_member_validate_visitor +{ + typedef void result_type; + + const operation_restriction& op_restriction; + + by_index_member_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} + + template + void operator()( const char* name )const + { + op_restriction_validation_helper helper( op_restriction ); + helper.validate_by_member_type( name, (const Member*)nullptr ); + } +}; struct op_restriction_validate_visitor { @@ -306,10 +325,8 @@ struct op_restriction_validate_visitor op_restriction_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} template - result_type operator()( const OpType& ) + result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it { - // Note: the parameter is a reference of *nullptr, we should not use it - FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, "member number ${m} is too large", ("m",op_restriction.member) ); @@ -317,10 +334,17 @@ struct op_restriction_validate_visitor // other member modifiers have been checked outside, so only check mmod_none here if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) { - // TODO: this implementation iterates through all reflected members to find specified member, + // member_validate_visitor vtor( op_restriction ); + // fc::reflector::visit( vtor ); + + // NOTE: above implementation iterates through all reflected members to find specified member, // possible to improve performance by visiting specified member by index/number directly - member_validate_visitor vtor( op_restriction ); - fc::reflector::visit( vtor ); + // ------------------------ + // So we have the code below + // TODO cleanup above comments + + by_index_member_validate_visitor vtor( op_restriction ); + fc::reflector::visit_local_member( vtor, op_restriction.member.value ); } } @@ -336,7 +360,7 @@ void validate_op_restriction_by_op_type( const operation_restriction& op_restric op_restriction_validate_visitor vtor( op_restriction ); switch( op_type.value ) { - // expands to something like following for all operations: + // 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 ) ) From 4c818ea387db5221ede0ca6f137958e1005bf296 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 13:06:37 -0400 Subject: [PATCH 08/22] Update validation of simple data type as argument --- .../chain/protocol/custom_authority.hpp | 4 + libraries/chain/protocol/custom_authority.cpp | 295 +++++++++++++----- 2 files changed, 221 insertions(+), 78 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 3008478a10..5c2f307675 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -89,6 +89,8 @@ namespace graphene { namespace chain { bool, \ int64_t, \ string, \ + time_point_sec, \ + public_key_type, \ account_id_type, \ asset_id_type, \ force_settlement_id_type, \ @@ -105,6 +107,8 @@ namespace graphene { namespace chain { flat_set< bool >, \ flat_set< int64_t >, \ flat_set< string >, \ + flat_set< time_point_sec >, \ + flat_set< public_key_type >, \ flat_set< account_id_type >, \ flat_set< asset_id_type >, \ flat_set< force_settlement_id_type >, \ diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index b650626a92..858284a5c3 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -34,13 +34,13 @@ struct argument_get_units_visitor typedef uint64_t result_type; template - result_type operator()( const T& t ) + inline result_type operator()( const T& t ) { return 1; } template - result_type operator()( const flat_set& t ) + inline result_type operator()( const flat_set& t ) { return t.size(); } @@ -63,37 +63,89 @@ uint64_t operation_restriction::get_units()const } namespace detail { - template bool is_simple_data_type() { return false; } - - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - - template<> bool is_simple_data_type() { return true; } - - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } - template<> bool is_simple_data_type() { return true; } + // comparable data types can use < <= > >= == != + template inline bool is_comparable_data_type() { return false; } + + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + template<> inline bool is_comparable_data_type() { return true; } + + // simple data types can use == != + template inline bool is_simple_data_type() { return false; } + + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } + template<> inline bool is_simple_data_type() { return true; } } +template +struct compatible_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + compatible_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ); + + // argument type T is compatible with member type T + inline result_type operator()( const T& arg ) {} +}; + +// by default incompatible +template template +inline void compatible_argument_validate_visitor::operator()( const ArgType& arg ) +{ + FC_THROW( "Argument '${arg}' is incompatible for ${name}", + ("arg", arg)("name", name) ); +} + +// compatible member types X and argument type Y and X != Y +template<> template<> inline void compatible_argument_validate_visitor::operator()( const string& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +// no int64_t here because it's already covered by generic template +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} + template struct list_argument_validate_visitor { @@ -103,33 +155,31 @@ struct list_argument_validate_visitor list_argument_validate_visitor( const char* _name ) : name(_name) {} template - result_type operator()( const ArgType& arg ); + inline result_type operator()( const ArgType& arg ); // argument type flat_set is compatible with member list_like - result_type operator()( const flat_set& arg ) {} + inline result_type operator()( const flat_set& arg ) {} }; // by default incompatible template template -void list_argument_validate_visitor::operator()( const ArgType& arg ) +inline void list_argument_validate_visitor::operator()( const ArgType& arg ) { - FC_THROW( "Argument type '${a}' is incompatible with list-like member '${m}' which contains data with type ${t}", - ("a", fc::get_typename::name()) - ("m", name) - ("t", fc::get_typename::name()) ); + FC_THROW( "Argument '${arg}' is incompatible, requires a compatible flat_set for ${name}", + ("arg", arg)("name", name) ); } -// compatible types X : flat_set and X != Y -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +// compatible member types X and argument type flat_set and X != Y +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} // no int64_t here because it's already covered by generic template -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} struct number_argument_validate_visitor { @@ -139,26 +189,57 @@ struct number_argument_validate_visitor number_argument_validate_visitor( const char* _name ) : name(_name) {} template - result_type operator()( const ArgType& arg ) + inline result_type operator()( const ArgType& arg ) { - FC_THROW( "Can only use a number type as argument for ${name}", - ("name", name) ); + FC_THROW( "Argument '${arg}' is incompatible, requires a number type for ${name}", + ("arg", arg)("name", name) ); } - result_type operator()( const int64_t& arg ) {} + inline result_type operator()( const int64_t& arg ) {} }; -void require_comparative_function( const operation_restriction& op_restriction, const char* name ) +inline bool is_subset_function( const operation_restriction::function_type function ) +{ + return ( function == operation_restriction::func_in + || function == operation_restriction::func_not_in ); +} + +inline bool is_superset_function( const operation_restriction::function_type function ) { - // function should be a comparative function - FC_ASSERT( op_restriction.function == operation_restriction::func_eq - || op_restriction.function == operation_restriction::func_ne - || op_restriction.function == operation_restriction::func_lt - || op_restriction.function == operation_restriction::func_le - || op_restriction.function == operation_restriction::func_gt - || op_restriction.function == operation_restriction::func_ge, - "Can only use comparative function for ${name}", - ("name", name) ); + return ( function == operation_restriction::func_has_all + || function == operation_restriction::func_has_none ); +} + +inline bool is_equal_function( const operation_restriction::function_type function ) +{ + return ( function == operation_restriction::func_eq + || function == operation_restriction::func_ne ); +} + +inline bool is_compare_function( const operation_restriction::function_type function ) +{ + return ( function == operation_restriction::func_eq + || function == operation_restriction::func_ne + || function == operation_restriction::func_lt + || function == operation_restriction::func_le + || function == operation_restriction::func_gt + || function == operation_restriction::func_ge ); +} + +void require_compare_function( const operation_restriction& op_restriction, const char* name ) +{ + // function should be a compare function + FC_ASSERT( is_compare_function( op_restriction.function ), + "Function '${func}' is incompatible, requires a compare function for ${name}", + ("func", op_restriction.function)("name", name) ); +} + +template +void require_compatible_argument( const operation_restriction& op_restriction, const char* name ) +{ + // argument should be T-compatible + compatible_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); } template @@ -186,13 +267,78 @@ struct op_restriction_validation_helper "Internal error: should only use this helper for mmod_none" ); } - // by default don't support undefined types - // FIXME need it for recursion + template + void validate_comparable_member( const char* name ) + { + if( is_subset_function( op_restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); + } + else if( is_compare_function( op_restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( op_restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires a compare function or subset function for ${name}", + ("func", op_restriction.function)("name", name) ); + } + } + + template + void validate_non_comparable_simple_member( const char* name ) + { + if( is_subset_function( op_restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); + } + else if( is_equal_function( op_restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( op_restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires an equal function or subset function for ${name}", + ("func", op_restriction.function)("name", name) ); + } + } + + template + void validate_list_like_member( const char* name ) + { + FC_ASSERT( is_superset_function( op_restriction.function ), + "List-like member '${name}' can only use func_has_all or func_has_none", + ("name", name) ); + FC_ASSERT( detail::is_simple_data_type(), + "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_list_argument( op_restriction, name ); + } + template void validate_by_member_type( const char* name, const T* t ) { - FC_THROW( "Restriction on '${name}' is not supported due to its type '${type}'", - ("name", name)("type", fc::get_typename::name()) ); + // TODO change to compile-time check for better performance + if( detail::is_comparable_data_type() ) // member is a number type or time point + { + validate_comparable_member( name ); + } + else if( detail::is_simple_data_type() ) // member is another simple type + { + validate_non_comparable_simple_member( name ); + } + else + { + // by default don't support undefined types + // FIXME need it for recursion + FC_THROW( "Restriction on '${name}' is not supported due to its type '${type}'", + ("name", name)("type", fc::get_typename::name()) ); + } } template @@ -217,17 +363,10 @@ struct op_restriction_validation_helper } template - void validate_list_like_member( const char* name ) + void validate_by_member_type( const char* name, const extension* t ) { - FC_ASSERT( op_restriction.function == operation_restriction::func_has_all - || op_restriction.function == operation_restriction::func_has_none, - "List-like member '${name}' can only use func_has_all or func_has_none", - ("name", name) ); - FC_ASSERT( detail::is_simple_data_type(), - "Simple data type in list-like member '${name}' is required", - ("name", name) ); - // validate argument, need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); + // extract the underlying type + validate_by_member_type( name, (const T*)nullptr ); } template @@ -380,12 +519,12 @@ void operation_restriction::validate( unsigned_int op_type )const if( member_modifier.value == mmod_size ) { - require_comparative_function( *this, "size modifier" ); + require_compare_function( *this, "size modifier" ); require_number_argument( *this, "size modifier" ); } else if( member_modifier.value == mmod_pack_size ) { - require_comparative_function( *this, "pack_size modifier" ); + require_compare_function( *this, "pack_size modifier" ); require_number_argument( *this, "pack_size modifier" ); } From ea9cf64ae27f86dc0cecaaa16bb6a634db074092 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 18:54:40 -0400 Subject: [PATCH 09/22] Add func_attr validation --- .../chain/protocol/custom_authority.hpp | 4 + libraries/chain/protocol/custom_authority.cpp | 172 ++++++++++++++---- 2 files changed, 143 insertions(+), 33 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 5c2f307675..338f40fc88 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -81,6 +81,7 @@ namespace graphene { namespace chain { 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 }; @@ -91,6 +92,7 @@ namespace graphene { namespace chain { string, \ time_point_sec, \ public_key_type, \ + fc::sha256, \ account_id_type, \ asset_id_type, \ force_settlement_id_type, \ @@ -109,6 +111,7 @@ namespace graphene { namespace chain { flat_set< string >, \ flat_set< time_point_sec >, \ flat_set< public_key_type >, \ + flat_set< fc::sha256 >, \ flat_set< account_id_type >, \ flat_set< asset_id_type >, \ flat_set< force_settlement_id_type >, \ @@ -226,6 +229,7 @@ FC_REFLECT_ENUM( graphene::chain::operation_restriction::function_type, (func_has_none) //(func_is_valid) //(func_not_valid) + (func_attr) (FUNCTION_TYPE_COUNT) ) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 858284a5c3..49b3339685 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -23,12 +23,21 @@ */ #include #include +#include #include #include +#include + namespace graphene { namespace chain { +template +using bool_const = std::integral_constant; + +struct op_restriction_validate_visitor; +void validate_op_restriction_commons( const operation_restriction& op_restriction ); + struct argument_get_units_visitor { typedef uint64_t result_type; @@ -62,6 +71,43 @@ uint64_t operation_restriction::get_units()const 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; }; + +/* namespace detail { // comparable data types can use < <= > >= == != template inline bool is_comparable_data_type() { return false; } @@ -110,6 +156,7 @@ namespace detail { template<> inline bool is_simple_data_type() { return true; } template<> inline bool is_simple_data_type() { return true; } } +*/ template struct compatible_argument_validate_visitor @@ -181,6 +228,36 @@ template<> template<> inline void list_argument_validate_visitor::oper template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template +struct attr_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + attr_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) + { + FC_THROW( "Argument '${arg}' is incompatible, requires an attr_restriction_type for ${name}", + ("arg", arg)("name", name) ); + } + + result_type operator()( const attr_restriction_type& arg ) // vector + { + // Recursively check T.members + for( const operation_restriction& restriction : arg ) + { + // validate common data + validate_op_restriction_commons( restriction ); + // validate member-related + op_restriction_validate_visitor vtor( restriction ); + vtor( *((const T*)nullptr) ); + } + } +}; + + struct number_argument_validate_visitor { typedef void result_type; @@ -250,6 +327,14 @@ void require_list_argument( const operation_restriction& op_restriction, const c op_restriction.argument.visit( vtor ); } +template +void require_attr_argument( const operation_restriction& op_restriction, const char* name ) +{ + // argument should be flat_set< T-compatible > + attr_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + void require_number_argument( const operation_restriction& op_restriction, const char* name ) { // argument should be a number @@ -267,8 +352,8 @@ struct op_restriction_validation_helper "Internal error: should only use this helper for mmod_none" ); } - template - void validate_comparable_member( const char* name ) + template // comparable, simple data type + void validate_member( const char* name, std::true_type, std::true_type ) { if( is_subset_function( op_restriction.function ) ) { @@ -287,8 +372,8 @@ struct op_restriction_validation_helper } } - template - void validate_non_comparable_simple_member( const char* name ) + template // non-comparable, simple data type + void validate_member( const char* name, std::false_type, std::true_type ) { if( is_subset_function( op_restriction.function ) ) { @@ -307,13 +392,23 @@ struct op_restriction_validation_helper } } + template // non-compatible, not-simple, aka object-like type + void validate_member( const char* name, std::false_type, std::false_type ) + { + FC_ASSERT( op_restriction.function == operation_restriction::func_attr, + "Object-like member '${name}' can only use func_attr", + ("name", name) ); + // argument need to be a attribute_restriction + require_attr_argument( op_restriction, name ); + } + template void validate_list_like_member( const char* name ) { FC_ASSERT( is_superset_function( op_restriction.function ), "List-like member '${name}' can only use func_has_all or func_has_none", ("name", name) ); - FC_ASSERT( detail::is_simple_data_type(), + 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 @@ -323,22 +418,9 @@ struct op_restriction_validation_helper template void validate_by_member_type( const char* name, const T* t ) { - // TODO change to compile-time check for better performance - if( detail::is_comparable_data_type() ) // member is a number type or time point - { - validate_comparable_member( name ); - } - else if( detail::is_simple_data_type() ) // member is another simple type - { - validate_non_comparable_simple_member( name ); - } - else - { - // by default don't support undefined types - // FIXME need it for recursion - FC_THROW( "Restriction on '${name}' is not supported due to its type '${type}'", - ("name", name)("type", fc::get_typename::name()) ); - } + 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 @@ -387,6 +469,26 @@ struct op_restriction_validation_helper 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) ); + } + }; /* @@ -509,30 +611,34 @@ void validate_op_restriction_by_op_type( const operation_restriction& op_restric } -//void operation_restriction::validate( const op_wrapper& opw )const -void operation_restriction::validate( unsigned_int op_type )const +void validate_op_restriction_commons( const operation_restriction& op_restriction ) { // validate member modifier - FC_ASSERT( member_modifier < MEMBER_MODIFIER_TYPE_COUNT, + FC_ASSERT( op_restriction.member_modifier < operation_restriction::MEMBER_MODIFIER_TYPE_COUNT, "member modifier number ${mm} is too large", - ("mm",member_modifier) ); + ("mm", op_restriction.member_modifier) ); - if( member_modifier.value == mmod_size ) + if( op_restriction.member_modifier.value == operation_restriction::mmod_size ) { - require_compare_function( *this, "size modifier" ); - require_number_argument( *this, "size modifier" ); + require_compare_function( op_restriction, "size modifier" ); + require_number_argument( op_restriction, "size modifier" ); } - else if( member_modifier.value == mmod_pack_size ) + else if( op_restriction.member_modifier.value == operation_restriction::mmod_pack_size ) { - require_compare_function( *this, "pack_size modifier" ); - require_number_argument( *this, "pack_size modifier" ); + require_compare_function( op_restriction, "pack_size modifier" ); + require_number_argument( op_restriction, "pack_size modifier" ); } // validate function - FC_ASSERT( function < FUNCTION_TYPE_COUNT, + FC_ASSERT( op_restriction.function < operation_restriction::FUNCTION_TYPE_COUNT, "function number ${f} is too large", - ("f",function) ); + ("f", op_restriction.function) ); +} +void operation_restriction::validate( unsigned_int op_type )const +{ + // validate common data + validate_op_restriction_commons( *this ); // validate details by operation_type validate_op_restriction_by_op_type( *this, op_type ); } From 3f2f9d73fa9f6d816a9705f5834b4c085f23a9a8 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 18:56:20 -0400 Subject: [PATCH 10/22] Code cleanup: remove code that is commented out --- libraries/chain/protocol/custom_authority.cpp | 112 +----------------- 1 file changed, 1 insertion(+), 111 deletions(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 49b3339685..cd7d872736 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -107,57 +107,6 @@ template<> struct is_simple_data_type { static const bo template<> struct is_simple_data_type { static const bool value = true; }; template<> struct is_simple_data_type { static const bool value = true; }; -/* -namespace detail { - // comparable data types can use < <= > >= == != - template inline bool is_comparable_data_type() { return false; } - - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - template<> inline bool is_comparable_data_type() { return true; } - - // simple data types can use == != - template inline bool is_simple_data_type() { return false; } - - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } - template<> inline bool is_simple_data_type() { return true; } -} -*/ - template struct compatible_argument_validate_visitor { @@ -491,56 +440,6 @@ struct op_restriction_validation_helper }; -/* - result_type operator()( const attr_restriction_type& t ) - { - for( const auto& restriction : t ) - { - restriction.argument.visit(*this); - } - } -}; -*/ - -/* -template< typename OpType > -struct member_validate_visitor -{ - typedef void result_type; - - mutable uint32_t which = 0; - const operation_restriction& op_restriction; - - member_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} - - template - void operator()( const char* name )const - { - if( which == op_restriction.member ) // `op.*member` is the specified member - { - - // Firstly we check if the member type is supported - - //validate_member( op_restriction ); - - op_restriction_validation_helper helper( op_restriction ); - helper.validate_by_member_type( name, (const Member*)nullptr ); - - // Giving the member type, we know what function is available - // Giving function, we know what argument it should be - - //function_validate_visitor vtor( op_restriction ); - - // validate argument - //argument_validate_visitor vtor; - //argument.visit( vtor ); - } - ++which; - } - -}; -*/ - template< typename OpType > struct by_index_member_validate_visitor { @@ -572,18 +471,9 @@ struct op_restriction_validate_visitor "member number ${m} is too large", ("m",op_restriction.member) ); - // other member modifiers have been checked outside, so only check mmod_none here + // other member modifiers should have been checked outside, so only check mmod_none here if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) { - // member_validate_visitor vtor( op_restriction ); - // fc::reflector::visit( vtor ); - - // NOTE: above implementation iterates through all reflected members to find specified member, - // possible to improve performance by visiting specified member by index/number directly - // ------------------------ - // So we have the code below - // TODO cleanup above comments - by_index_member_validate_visitor vtor( op_restriction ); fc::reflector::visit_local_member( vtor, op_restriction.member.value ); } From c5b1d42fc573341aaa490cf1b5553610ad264d6b Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 19:07:18 -0400 Subject: [PATCH 11/22] Add comments for static_variant<> argument_type --- .../chain/protocol/custom_authority.hpp | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 338f40fc88..2549afb73f 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -86,46 +86,46 @@ namespace graphene { namespace chain { }; #define GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC \ - void_t, \ - bool, \ - int64_t, \ - string, \ - time_point_sec, \ - public_key_type, \ - fc::sha256, \ - account_id_type, \ - asset_id_type, \ - force_settlement_id_type, \ - committee_member_id_type, \ - witness_id_type, \ - limit_order_id_type, \ - call_order_id_type, \ - custom_id_type, \ - proposal_id_type, \ - withdraw_permission_id_type, \ - vesting_balance_id_type, \ - worker_id_type, \ - balance_id_type, \ - flat_set< bool >, \ - flat_set< int64_t >, \ - flat_set< string >, \ - flat_set< time_point_sec >, \ - flat_set< public_key_type >, \ - flat_set< fc::sha256 >, \ - flat_set< account_id_type >, \ - flat_set< asset_id_type >, \ - flat_set< force_settlement_id_type >, \ - flat_set< committee_member_id_type >, \ - flat_set< witness_id_type >, \ - flat_set< limit_order_id_type >, \ - flat_set< call_order_id_type >, \ - flat_set< custom_id_type >, \ - flat_set< proposal_id_type >, \ - flat_set< withdraw_permission_id_type >, \ - flat_set< vesting_balance_id_type >, \ - flat_set< worker_id_type >, \ - flat_set< balance_id_type >, \ - attr_restriction_type + /* 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 */ attr_restriction_type typedef static_variant < GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC > argument_type; From 0cf5edbb97e475873c0fd250b61d681e6a663cc6 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 11 Aug 2018 20:32:35 -0400 Subject: [PATCH 12/22] Update units calculation --- libraries/chain/protocol/custom_authority.cpp | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index cd7d872736..1c82046358 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -48,10 +48,36 @@ struct argument_get_units_visitor 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(); + 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 attr_restriction_type& t ) From 01332917d7ee212e77abf9553e2f84d877668706 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 07:03:16 -0400 Subject: [PATCH 13/22] Refactory: move restriction to new file and rename --- .../chain/custom_authority_object.hpp | 2 +- .../chain/protocol/custom_authority.hpp | 149 +---------------- .../graphene/chain/protocol/restriction.hpp | 153 ++++++++++++++++++ libraries/chain/protocol/custom_authority.cpp | 82 +++++----- 4 files changed, 197 insertions(+), 189 deletions(-) create mode 100644 libraries/chain/include/graphene/chain/protocol/restriction.hpp diff --git a/libraries/chain/include/graphene/chain/custom_authority_object.hpp b/libraries/chain/include/graphene/chain/custom_authority_object.hpp index a5d9741e2e..3c964ba907 100644 --- a/libraries/chain/include/graphene/chain/custom_authority_object.hpp +++ b/libraries/chain/include/graphene/chain/custom_authority_object.hpp @@ -47,7 +47,7 @@ namespace graphene { namespace chain { time_point_sec valid_to; unsigned_int operation_type; authority auth; - vector restrictions; + vector restrictions; }; /** diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index 2549afb73f..b98b2936b3 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -23,123 +23,10 @@ */ #pragma once #include +#include namespace graphene { namespace chain { -/* - template struct transform_to_fee_parameters; - template - struct transform_to_fee_parameters> - { - typedef fc::static_variant< typename T::fee_parameters_type... > type; - }; - typedef transform_to_fee_parameters::type fee_parameters; -*/ - - /** - * @ingroup operations - * - * Defines the set of valid operation restritions as a discriminated union type. - */ - /// @{ -/* template struct transform_to_operation_restrictions; - template - struct transform_to_operation_restrictions> - { - typedef fc::static_variant< typename T::operation_restriction_type... > type; - }; - typedef transform_to_fee_parameters::type operation_restrictions; -*/ /// @} - -// vector restrictions; - - struct operation_restriction; - typedef vector attr_restriction_type; - - struct operation_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 */ attr_restriction_type - - 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; - void validate( unsigned_int op_type )const; - }; - /** * @brief Create a new custom authority * @ingroup operations @@ -160,7 +47,7 @@ namespace graphene { namespace chain { time_point_sec valid_to; unsigned_int operation_type; authority auth; - vector restrictions; + vector restrictions; empty_extensions_type extensions; @@ -209,38 +96,6 @@ namespace graphene { namespace chain { } } // graphene::chain -FC_REFLECT_ENUM( graphene::chain::operation_restriction::member_modifier_type, - (mmod_none) - (mmod_size) - (mmod_pack_size) - (MEMBER_MODIFIER_TYPE_COUNT) - ) - -FC_REFLECT_ENUM( graphene::chain::operation_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::operation_restriction, - (member) - (member_modifier) - (function) - (argument) - (extensions) - ) - 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) ) 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..c81c4df30a --- /dev/null +++ b/libraries/chain/include/graphene/chain/protocol/restriction.hpp @@ -0,0 +1,153 @@ +/* + * 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 { + + + struct restriction_type; + typedef vector attr_restriction_type; + + /** + * Defines the set of valid operation restritions as a discriminated union type. + */ + struct restriction_type + { + + 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 */ attr_restriction_type + + 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; + void validate( unsigned_int op_type )const; + }; + +} } // graphene::chain + +FC_REFLECT_ENUM( graphene::chain::restriction_type::member_modifier_type, + (mmod_none) + (mmod_size) + (mmod_pack_size) + (MEMBER_MODIFIER_TYPE_COUNT) + ) + +FC_REFLECT_ENUM( graphene::chain::restriction_type::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_type, + (member) + (member_modifier) + (function) + (argument) + (extensions) + ) + diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 1c82046358..142d343373 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -36,7 +36,7 @@ template using bool_const = std::integral_constant; struct op_restriction_validate_visitor; -void validate_op_restriction_commons( const operation_restriction& op_restriction ); +void validate_op_restriction_commons( const restriction_type& op_restriction ); struct argument_get_units_visitor { @@ -91,7 +91,7 @@ struct argument_get_units_visitor } }; -uint64_t operation_restriction::get_units()const +uint64_t restriction_type::get_units()const { argument_get_units_visitor vtor; return argument.visit( vtor ); @@ -218,10 +218,10 @@ struct attr_argument_validate_visitor ("arg", arg)("name", name) ); } - result_type operator()( const attr_restriction_type& arg ) // vector + result_type operator()( const attr_restriction_type& arg ) // vector { // Recursively check T.members - for( const operation_restriction& restriction : arg ) + for( const restriction_type& restriction : arg ) { // validate common data validate_op_restriction_commons( restriction ); @@ -250,35 +250,35 @@ struct number_argument_validate_visitor inline result_type operator()( const int64_t& arg ) {} }; -inline bool is_subset_function( const operation_restriction::function_type function ) +inline bool is_subset_function( const restriction_type::function_type function ) { - return ( function == operation_restriction::func_in - || function == operation_restriction::func_not_in ); + return ( function == restriction_type::func_in + || function == restriction_type::func_not_in ); } -inline bool is_superset_function( const operation_restriction::function_type function ) +inline bool is_superset_function( const restriction_type::function_type function ) { - return ( function == operation_restriction::func_has_all - || function == operation_restriction::func_has_none ); + return ( function == restriction_type::func_has_all + || function == restriction_type::func_has_none ); } -inline bool is_equal_function( const operation_restriction::function_type function ) +inline bool is_equal_function( const restriction_type::function_type function ) { - return ( function == operation_restriction::func_eq - || function == operation_restriction::func_ne ); + return ( function == restriction_type::func_eq + || function == restriction_type::func_ne ); } -inline bool is_compare_function( const operation_restriction::function_type function ) +inline bool is_compare_function( const restriction_type::function_type function ) { - return ( function == operation_restriction::func_eq - || function == operation_restriction::func_ne - || function == operation_restriction::func_lt - || function == operation_restriction::func_le - || function == operation_restriction::func_gt - || function == operation_restriction::func_ge ); + return ( function == restriction_type::func_eq + || function == restriction_type::func_ne + || function == restriction_type::func_lt + || function == restriction_type::func_le + || function == restriction_type::func_gt + || function == restriction_type::func_ge ); } -void require_compare_function( const operation_restriction& op_restriction, const char* name ) +void require_compare_function( const restriction_type& op_restriction, const char* name ) { // function should be a compare function FC_ASSERT( is_compare_function( op_restriction.function ), @@ -287,7 +287,7 @@ void require_compare_function( const operation_restriction& op_restriction, cons } template -void require_compatible_argument( const operation_restriction& op_restriction, const char* name ) +void require_compatible_argument( const restriction_type& op_restriction, const char* name ) { // argument should be T-compatible compatible_argument_validate_visitor vtor( name ); @@ -295,7 +295,7 @@ void require_compatible_argument( const operation_restriction& op_restriction, c } template -void require_list_argument( const operation_restriction& op_restriction, const char* name ) +void require_list_argument( const restriction_type& op_restriction, const char* name ) { // argument should be flat_set< T-compatible > list_argument_validate_visitor vtor( name ); @@ -303,14 +303,14 @@ void require_list_argument( const operation_restriction& op_restriction, const c } template -void require_attr_argument( const operation_restriction& op_restriction, const char* name ) +void require_attr_argument( const restriction_type& op_restriction, const char* name ) { // argument should be flat_set< T-compatible > attr_argument_validate_visitor vtor( name ); op_restriction.argument.visit( vtor ); } -void require_number_argument( const operation_restriction& op_restriction, const char* name ) +void require_number_argument( const restriction_type& op_restriction, const char* name ) { // argument should be a number number_argument_validate_visitor vtor( name ); @@ -319,11 +319,11 @@ void require_number_argument( const operation_restriction& op_restriction, const struct op_restriction_validation_helper { - const operation_restriction& op_restriction; ///< the restriction + const restriction_type& op_restriction; ///< the restriction - op_restriction_validation_helper( const operation_restriction& opr ) : op_restriction(opr) + op_restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) { - FC_ASSERT( op_restriction.member_modifier.value == operation_restriction::mmod_none, + FC_ASSERT( op_restriction.member_modifier.value == restriction_type::mmod_none, "Internal error: should only use this helper for mmod_none" ); } @@ -370,7 +370,7 @@ struct op_restriction_validation_helper template // non-compatible, not-simple, aka object-like type void validate_member( const char* name, std::false_type, std::false_type ) { - FC_ASSERT( op_restriction.function == operation_restriction::func_attr, + FC_ASSERT( op_restriction.function == restriction_type::func_attr, "Object-like member '${name}' can only use func_attr", ("name", name) ); // argument need to be a attribute_restriction @@ -471,9 +471,9 @@ struct by_index_member_validate_visitor { typedef void result_type; - const operation_restriction& op_restriction; + const restriction_type& op_restriction; - by_index_member_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} + by_index_member_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} template void operator()( const char* name )const @@ -486,9 +486,9 @@ struct by_index_member_validate_visitor struct op_restriction_validate_visitor { typedef void result_type; - const operation_restriction& op_restriction; + const restriction_type& op_restriction; - op_restriction_validate_visitor( const operation_restriction& opr ) : op_restriction(opr) {} + op_restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} template result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it @@ -498,7 +498,7 @@ struct op_restriction_validate_visitor ("m",op_restriction.member) ); // other member modifiers should have been checked outside, so only check mmod_none here - if( op_restriction.member_modifier.value == operation_restriction::mmod_none ) + if( op_restriction.member_modifier.value == restriction_type::mmod_none ) { by_index_member_validate_visitor vtor( op_restriction ); fc::reflector::visit_local_member( vtor, op_restriction.member.value ); @@ -512,7 +512,7 @@ struct op_restriction_validate_visitor operation::visit< I >( vtor ); \ break; -void validate_op_restriction_by_op_type( const operation_restriction& op_restriction, unsigned_int op_type ) +void validate_op_restriction_by_op_type( const restriction_type& op_restriction, unsigned_int op_type ) { op_restriction_validate_visitor vtor( op_restriction ); switch( op_type.value ) @@ -527,31 +527,31 @@ void validate_op_restriction_by_op_type( const operation_restriction& op_restric } -void validate_op_restriction_commons( const operation_restriction& op_restriction ) +void validate_op_restriction_commons( const restriction_type& op_restriction ) { // validate member modifier - FC_ASSERT( op_restriction.member_modifier < operation_restriction::MEMBER_MODIFIER_TYPE_COUNT, + FC_ASSERT( op_restriction.member_modifier < restriction_type::MEMBER_MODIFIER_TYPE_COUNT, "member modifier number ${mm} is too large", ("mm", op_restriction.member_modifier) ); - if( op_restriction.member_modifier.value == operation_restriction::mmod_size ) + if( op_restriction.member_modifier.value == restriction_type::mmod_size ) { require_compare_function( op_restriction, "size modifier" ); require_number_argument( op_restriction, "size modifier" ); } - else if( op_restriction.member_modifier.value == operation_restriction::mmod_pack_size ) + else if( op_restriction.member_modifier.value == restriction_type::mmod_pack_size ) { require_compare_function( op_restriction, "pack_size modifier" ); require_number_argument( op_restriction, "pack_size modifier" ); } // validate function - FC_ASSERT( op_restriction.function < operation_restriction::FUNCTION_TYPE_COUNT, + FC_ASSERT( op_restriction.function < restriction_type::FUNCTION_TYPE_COUNT, "function number ${f} is too large", ("f", op_restriction.function) ); } -void operation_restriction::validate( unsigned_int op_type )const +void restriction_type::validate( unsigned_int op_type )const { // validate common data validate_op_restriction_commons( *this ); From 664297404475ba2fbd6c911b41949b2adba2a645 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 07:52:02 -0400 Subject: [PATCH 14/22] Refactory: move restriction impl to new file --- libraries/chain/CMakeLists.txt | 1 + libraries/chain/protocol/custom_authority.cpp | 533 ----------------- libraries/chain/protocol/restriction.cpp | 562 ++++++++++++++++++ 3 files changed, 563 insertions(+), 533 deletions(-) create mode 100644 libraries/chain/protocol/restriction.cpp diff --git a/libraries/chain/CMakeLists.txt b/libraries/chain/CMakeLists.txt index f7f80b1662..da47096da6 100644 --- a/libraries/chain/CMakeLists.txt +++ b/libraries/chain/CMakeLists.txt @@ -32,6 +32,7 @@ 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} diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 142d343373..606a552380 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -23,542 +23,9 @@ */ #include #include -#include - -#include -#include - -#include namespace graphene { namespace chain { -template -using bool_const = std::integral_constant; - -struct op_restriction_validate_visitor; -void validate_op_restriction_commons( const restriction_type& op_restriction ); - -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 attr_restriction_type& t ) - { - result_type result = 0; - for( const auto& restriction : t ) - { - result += restriction.argument.visit(*this); - } - return result; - } -}; - -uint64_t restriction_type::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_validate_visitor -{ - typedef void result_type; - const char* name; - - compatible_argument_validate_visitor( const char* _name ) : name(_name) {} - - template - inline result_type operator()( const ArgType& arg ); - - // argument type T is compatible with member type T - inline result_type operator()( const T& arg ) {} -}; - -// by default incompatible -template template -inline void compatible_argument_validate_visitor::operator()( const ArgType& arg ) -{ - FC_THROW( "Argument '${arg}' is incompatible for ${name}", - ("arg", arg)("name", name) ); -} - -// compatible member types X and argument type Y and X != Y -template<> template<> inline void compatible_argument_validate_visitor::operator()( const string& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -// no int64_t here because it's already covered by generic template -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} - -template -struct list_argument_validate_visitor -{ - typedef void result_type; - const char* name; - - list_argument_validate_visitor( const char* _name ) : name(_name) {} - - template - inline result_type operator()( const ArgType& arg ); - - // argument type flat_set is compatible with member list_like - inline result_type operator()( const flat_set& arg ) {} -}; - -// by default incompatible -template template -inline void list_argument_validate_visitor::operator()( const ArgType& arg ) -{ - FC_THROW( "Argument '${arg}' is incompatible, requires a compatible flat_set for ${name}", - ("arg", arg)("name", name) ); -} - -// compatible member types X and argument type flat_set and X != Y -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -// no int64_t here because it's already covered by generic template -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} - -template -struct attr_argument_validate_visitor -{ - typedef void result_type; - const char* name; - - attr_argument_validate_visitor( const char* _name ) : name(_name) {} - - template - inline result_type operator()( const ArgType& arg ) - { - FC_THROW( "Argument '${arg}' is incompatible, requires an attr_restriction_type for ${name}", - ("arg", arg)("name", name) ); - } - - result_type operator()( const attr_restriction_type& arg ) // vector - { - // Recursively check T.members - for( const restriction_type& restriction : arg ) - { - // validate common data - validate_op_restriction_commons( restriction ); - // validate member-related - op_restriction_validate_visitor vtor( restriction ); - vtor( *((const T*)nullptr) ); - } - } -}; - - -struct number_argument_validate_visitor -{ - typedef void result_type; - const char* name; - - number_argument_validate_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_type::function_type function ) -{ - return ( function == restriction_type::func_in - || function == restriction_type::func_not_in ); -} - -inline bool is_superset_function( const restriction_type::function_type function ) -{ - return ( function == restriction_type::func_has_all - || function == restriction_type::func_has_none ); -} - -inline bool is_equal_function( const restriction_type::function_type function ) -{ - return ( function == restriction_type::func_eq - || function == restriction_type::func_ne ); -} - -inline bool is_compare_function( const restriction_type::function_type function ) -{ - return ( function == restriction_type::func_eq - || function == restriction_type::func_ne - || function == restriction_type::func_lt - || function == restriction_type::func_le - || function == restriction_type::func_gt - || function == restriction_type::func_ge ); -} - -void require_compare_function( const restriction_type& op_restriction, const char* name ) -{ - // function should be a compare function - FC_ASSERT( is_compare_function( op_restriction.function ), - "Function '${func}' is incompatible, requires a compare function for ${name}", - ("func", op_restriction.function)("name", name) ); -} - -template -void require_compatible_argument( const restriction_type& op_restriction, const char* name ) -{ - // argument should be T-compatible - compatible_argument_validate_visitor vtor( name ); - op_restriction.argument.visit( vtor ); -} - -template -void require_list_argument( const restriction_type& op_restriction, const char* name ) -{ - // argument should be flat_set< T-compatible > - list_argument_validate_visitor vtor( name ); - op_restriction.argument.visit( vtor ); -} - -template -void require_attr_argument( const restriction_type& op_restriction, const char* name ) -{ - // argument should be flat_set< T-compatible > - attr_argument_validate_visitor vtor( name ); - op_restriction.argument.visit( vtor ); -} - -void require_number_argument( const restriction_type& op_restriction, const char* name ) -{ - // argument should be a number - number_argument_validate_visitor vtor( name ); - op_restriction.argument.visit( vtor ); -} - -struct op_restriction_validation_helper -{ - const restriction_type& op_restriction; ///< the restriction - - op_restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) - { - FC_ASSERT( op_restriction.member_modifier.value == restriction_type::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( op_restriction.function ) ) - { - // argument need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); - } - else if( is_compare_function( op_restriction.function ) ) - { - // argument need to be compatible - require_compatible_argument( op_restriction, name ); - } - else - { - FC_THROW( "Function '${func}' is incompatible, requires a compare function or subset function for ${name}", - ("func", op_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( op_restriction.function ) ) - { - // argument need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); - } - else if( is_equal_function( op_restriction.function ) ) - { - // argument need to be compatible - require_compatible_argument( op_restriction, name ); - } - else - { - FC_THROW( "Function '${func}' is incompatible, requires an equal function or subset function for ${name}", - ("func", op_restriction.function)("name", name) ); - } - } - - template // non-compatible, not-simple, aka object-like type - void validate_member( const char* name, std::false_type, std::false_type ) - { - FC_ASSERT( op_restriction.function == restriction_type::func_attr, - "Object-like member '${name}' can only use func_attr", - ("name", name) ); - // argument need to be a attribute_restriction - require_attr_argument( op_restriction, name ); - } - - template - void validate_list_like_member( const char* name ) - { - FC_ASSERT( is_superset_function( op_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_list_argument( op_restriction, name ); - } - - template - void validate_by_member_type( const char* name, const T* t ) - { - 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) ); - } - -}; - -template< typename OpType > -struct by_index_member_validate_visitor -{ - typedef void result_type; - - const restriction_type& op_restriction; - - by_index_member_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} - - template - void operator()( const char* name )const - { - op_restriction_validation_helper helper( op_restriction ); - helper.validate_by_member_type( name, (const Member*)nullptr ); - } -}; - -struct op_restriction_validate_visitor -{ - typedef void result_type; - const restriction_type& op_restriction; - - op_restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} - - template - result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it - { - FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, - "member number ${m} is too large", - ("m",op_restriction.member) ); - - // other member modifiers should have been checked outside, so only check mmod_none here - if( op_restriction.member_modifier.value == restriction_type::mmod_none ) - { - by_index_member_validate_visitor vtor( op_restriction ); - fc::reflector::visit_local_member( vtor, op_restriction.member.value ); - } - } - -}; - -#define GRAPHENE_OP_IDX_CASE_VISIT(r, data, I, elem) \ - case I : \ - operation::visit< I >( vtor ); \ - break; - -void validate_op_restriction_by_op_type( const restriction_type& op_restriction, unsigned_int op_type ) -{ - op_restriction_validate_visitor vtor( op_restriction ); - 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 validate_op_restriction_commons( const restriction_type& op_restriction ) -{ - // validate member modifier - FC_ASSERT( op_restriction.member_modifier < restriction_type::MEMBER_MODIFIER_TYPE_COUNT, - "member modifier number ${mm} is too large", - ("mm", op_restriction.member_modifier) ); - - if( op_restriction.member_modifier.value == restriction_type::mmod_size ) - { - require_compare_function( op_restriction, "size modifier" ); - require_number_argument( op_restriction, "size modifier" ); - } - else if( op_restriction.member_modifier.value == restriction_type::mmod_pack_size ) - { - require_compare_function( op_restriction, "pack_size modifier" ); - require_number_argument( op_restriction, "pack_size modifier" ); - } - - // validate function - FC_ASSERT( op_restriction.function < restriction_type::FUNCTION_TYPE_COUNT, - "function number ${f} is too large", - ("f", op_restriction.function) ); -} - -void restriction_type::validate( unsigned_int op_type )const -{ - // validate common data - validate_op_restriction_commons( *this ); - // validate details by operation_type - validate_op_restriction_by_op_type( *this, op_type ); -} - share_type custom_authority_create_operation::calculate_fee( const fee_parameters_type& k )const { share_type core_fee_required = k.basic_fee; diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp new file mode 100644 index 0000000000..ba52615537 --- /dev/null +++ b/libraries/chain/protocol/restriction.cpp @@ -0,0 +1,562 @@ +/* + * 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 op_restriction_validate_visitor; +void validate_op_restriction_commons( const restriction_type& op_restriction ); + +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 attr_restriction_type& t ) + { + result_type result = 0; + for( const auto& restriction : t ) + { + result += restriction.argument.visit(*this); + } + return result; + } +}; + +uint64_t restriction_type::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_validate_visitor +{ + typedef void result_type; + const char* name; + + compatible_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ); + + // argument type T is compatible with member type T + inline result_type operator()( const T& arg ) {} +}; + +// by default incompatible +template template +inline void compatible_argument_validate_visitor::operator()( const ArgType& arg ) +{ + FC_THROW( "Argument '${arg}' is incompatible for ${name}", + ("arg", arg)("name", name) ); +} + +// compatible member types X and argument type Y and X != Y +template<> template<> inline void compatible_argument_validate_visitor::operator()( const string& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +// no int64_t here because it's already covered by generic template +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} + +template +struct list_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + list_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ); + + // argument type flat_set is compatible with member list_like + inline result_type operator()( const flat_set& arg ) {} +}; + +// by default incompatible +template template +inline void list_argument_validate_visitor::operator()( const ArgType& arg ) +{ + FC_THROW( "Argument '${arg}' is incompatible, requires a compatible flat_set for ${name}", + ("arg", arg)("name", name) ); +} + +// compatible member types X and argument type flat_set and X != Y +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +// no int64_t here because it's already covered by generic template +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} +template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} + +template +struct attr_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + attr_argument_validate_visitor( const char* _name ) : name(_name) {} + + template + inline result_type operator()( const ArgType& arg ) + { + FC_THROW( "Argument '${arg}' is incompatible, requires an attr_restriction_type for ${name}", + ("arg", arg)("name", name) ); + } + + result_type operator()( const attr_restriction_type& arg ) // vector + { + // Recursively check T.members + for( const restriction_type& restriction : arg ) + { + // validate common data + validate_op_restriction_commons( restriction ); + // validate member-related + op_restriction_validate_visitor vtor( restriction ); + vtor( *((const T*)nullptr) ); + } + } +}; + + +struct number_argument_validate_visitor +{ + typedef void result_type; + const char* name; + + number_argument_validate_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_type::function_type function ) +{ + return ( function == restriction_type::func_in + || function == restriction_type::func_not_in ); +} + +inline bool is_superset_function( const restriction_type::function_type function ) +{ + return ( function == restriction_type::func_has_all + || function == restriction_type::func_has_none ); +} + +inline bool is_equal_function( const restriction_type::function_type function ) +{ + return ( function == restriction_type::func_eq + || function == restriction_type::func_ne ); +} + +inline bool is_compare_function( const restriction_type::function_type function ) +{ + return ( function == restriction_type::func_eq + || function == restriction_type::func_ne + || function == restriction_type::func_lt + || function == restriction_type::func_le + || function == restriction_type::func_gt + || function == restriction_type::func_ge ); +} + +void require_compare_function( const restriction_type& op_restriction, const char* name ) +{ + // function should be a compare function + FC_ASSERT( is_compare_function( op_restriction.function ), + "Function '${func}' is incompatible, requires a compare function for ${name}", + ("func", op_restriction.function)("name", name) ); +} + +template +void require_compatible_argument( const restriction_type& op_restriction, const char* name ) +{ + // argument should be T-compatible + compatible_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +template +void require_list_argument( const restriction_type& op_restriction, const char* name ) +{ + // argument should be flat_set< T-compatible > + list_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +template +void require_attr_argument( const restriction_type& op_restriction, const char* name ) +{ + // argument should be flat_set< T-compatible > + attr_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +void require_number_argument( const restriction_type& op_restriction, const char* name ) +{ + // argument should be a number + number_argument_validate_visitor vtor( name ); + op_restriction.argument.visit( vtor ); +} + +struct op_restriction_validation_helper +{ + const restriction_type& op_restriction; ///< the restriction + + op_restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) + { + FC_ASSERT( op_restriction.member_modifier.value == restriction_type::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( op_restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); + } + else if( is_compare_function( op_restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( op_restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires a compare function or subset function for ${name}", + ("func", op_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( op_restriction.function ) ) + { + // argument need to be a list, and type should be compatible to T + require_list_argument( op_restriction, name ); + } + else if( is_equal_function( op_restriction.function ) ) + { + // argument need to be compatible + require_compatible_argument( op_restriction, name ); + } + else + { + FC_THROW( "Function '${func}' is incompatible, requires an equal function or subset function for ${name}", + ("func", op_restriction.function)("name", name) ); + } + } + + template // non-compatible, not-simple, aka object-like type + void validate_member( const char* name, std::false_type, std::false_type ) + { + FC_ASSERT( op_restriction.function == restriction_type::func_attr, + "Object-like member '${name}' can only use func_attr", + ("name", name) ); + // argument need to be a attribute_restriction + require_attr_argument( op_restriction, name ); + } + + template + void validate_list_like_member( const char* name ) + { + FC_ASSERT( is_superset_function( op_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_list_argument( op_restriction, name ); + } + + template + void validate_by_member_type( const char* name, const T* t ) + { + 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) ); + } + +}; + +template< typename OpType > +struct by_index_member_validate_visitor +{ + typedef void result_type; + + const restriction_type& op_restriction; + + by_index_member_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} + + template + void operator()( const char* name )const + { + op_restriction_validation_helper helper( op_restriction ); + helper.validate_by_member_type( name, (const Member*)nullptr ); + } +}; + +struct op_restriction_validate_visitor +{ + typedef void result_type; + const restriction_type& op_restriction; + + op_restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} + + template + result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it + { + FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, + "member number ${m} is too large", + ("m",op_restriction.member) ); + + // other member modifiers should have been checked outside, so only check mmod_none here + if( op_restriction.member_modifier.value == restriction_type::mmod_none ) + { + by_index_member_validate_visitor vtor( op_restriction ); + fc::reflector::visit_local_member( vtor, op_restriction.member.value ); + } + } + +}; + +#define GRAPHENE_OP_IDX_CASE_VISIT(r, data, I, elem) \ + case I : \ + operation::visit< I >( vtor ); \ + break; + +void validate_op_restriction_by_op_type( const restriction_type& op_restriction, unsigned_int op_type ) +{ + op_restriction_validate_visitor vtor( op_restriction ); + 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 validate_op_restriction_commons( const restriction_type& op_restriction ) +{ + // validate member modifier + FC_ASSERT( op_restriction.member_modifier < restriction_type::MEMBER_MODIFIER_TYPE_COUNT, + "member modifier number ${mm} is too large", + ("mm", op_restriction.member_modifier) ); + + if( op_restriction.member_modifier.value == restriction_type::mmod_size ) + { + require_compare_function( op_restriction, "size modifier" ); + require_number_argument( op_restriction, "size modifier" ); + } + else if( op_restriction.member_modifier.value == restriction_type::mmod_pack_size ) + { + require_compare_function( op_restriction, "pack_size modifier" ); + require_number_argument( op_restriction, "pack_size modifier" ); + } + + // validate function + FC_ASSERT( op_restriction.function < restriction_type::FUNCTION_TYPE_COUNT, + "function number ${f} is too large", + ("f", op_restriction.function) ); +} + +void restriction_type::validate( unsigned_int op_type )const +{ + // validate common data + validate_op_restriction_commons( *this ); + // validate details by operation_type + validate_op_restriction_by_op_type( *this, op_type ); +} + +} } // graphene::chain From 786cdeca4287483474f89187ed94d8d23d12512b Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 08:42:34 -0400 Subject: [PATCH 15/22] Refactory: change function names --- libraries/chain/protocol/restriction.cpp | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp index ba52615537..f63f9fd3bb 100644 --- a/libraries/chain/protocol/restriction.cpp +++ b/libraries/chain/protocol/restriction.cpp @@ -35,8 +35,8 @@ namespace graphene { namespace chain { template using bool_const = std::integral_constant; -struct op_restriction_validate_visitor; -void validate_op_restriction_commons( const restriction_type& op_restriction ); +struct restriction_validate_visitor; +void validate_restriction_commons( const restriction_type& op_restriction ); struct argument_get_units_visitor { @@ -224,9 +224,9 @@ struct attr_argument_validate_visitor for( const restriction_type& restriction : arg ) { // validate common data - validate_op_restriction_commons( restriction ); + validate_restriction_commons( restriction ); // validate member-related - op_restriction_validate_visitor vtor( restriction ); + restriction_validate_visitor vtor( restriction ); vtor( *((const T*)nullptr) ); } } @@ -317,11 +317,11 @@ void require_number_argument( const restriction_type& op_restriction, const char op_restriction.argument.visit( vtor ); } -struct op_restriction_validation_helper +struct restriction_validation_helper { const restriction_type& op_restriction; ///< the restriction - op_restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) + restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) { FC_ASSERT( op_restriction.member_modifier.value == restriction_type::mmod_none, "Internal error: should only use this helper for mmod_none" ); @@ -478,17 +478,17 @@ struct by_index_member_validate_visitor template void operator()( const char* name )const { - op_restriction_validation_helper helper( op_restriction ); + restriction_validation_helper helper( op_restriction ); helper.validate_by_member_type( name, (const Member*)nullptr ); } }; -struct op_restriction_validate_visitor +struct restriction_validate_visitor { typedef void result_type; const restriction_type& op_restriction; - op_restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} + restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} template result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it @@ -512,9 +512,9 @@ struct op_restriction_validate_visitor operation::visit< I >( vtor ); \ break; -void validate_op_restriction_by_op_type( const restriction_type& op_restriction, unsigned_int op_type ) +void validate_restriction_details( const restriction_type& op_restriction, unsigned_int op_type ) { - op_restriction_validate_visitor vtor( op_restriction ); + restriction_validate_visitor vtor( op_restriction ); switch( op_type.value ) { // will have code like below for all operations: @@ -527,7 +527,7 @@ void validate_op_restriction_by_op_type( const restriction_type& op_restriction, } -void validate_op_restriction_commons( const restriction_type& op_restriction ) +void validate_restriction_commons( const restriction_type& op_restriction ) { // validate member modifier FC_ASSERT( op_restriction.member_modifier < restriction_type::MEMBER_MODIFIER_TYPE_COUNT, @@ -554,9 +554,9 @@ void validate_op_restriction_commons( const restriction_type& op_restriction ) void restriction_type::validate( unsigned_int op_type )const { // validate common data - validate_op_restriction_commons( *this ); + validate_restriction_commons( *this ); // validate details by operation_type - validate_op_restriction_by_op_type( *this, op_type ); + validate_restriction_details( *this, op_type ); } } } // graphene::chain From ae59f392e86d5650776b111cfcabbfc1593e1594 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 09:02:11 -0400 Subject: [PATCH 16/22] Refactor templates and fix comments/typo --- libraries/chain/protocol/restriction.cpp | 48 ++++++++++-------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp index f63f9fd3bb..ca3b2dd25a 100644 --- a/libraries/chain/protocol/restriction.cpp +++ b/libraries/chain/protocol/restriction.cpp @@ -142,20 +142,16 @@ struct compatible_argument_validate_visitor compatible_argument_validate_visitor( const char* _name ) : name(_name) {} template - inline result_type operator()( const ArgType& arg ); + 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 ) {} }; -// by default incompatible -template template -inline void compatible_argument_validate_visitor::operator()( const ArgType& arg ) -{ - FC_THROW( "Argument '${arg}' is incompatible for ${name}", - ("arg", arg)("name", name) ); -} - // compatible member types X and argument type Y and X != Y template<> template<> inline void compatible_argument_validate_visitor::operator()( const string& arg ) {} template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} @@ -177,20 +173,16 @@ struct list_argument_validate_visitor list_argument_validate_visitor( const char* _name ) : name(_name) {} template - inline result_type operator()( const ArgType& arg ); + 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 ) {} }; -// by default incompatible -template template -inline void list_argument_validate_visitor::operator()( const ArgType& arg ) -{ - FC_THROW( "Argument '${arg}' is incompatible, requires a compatible flat_set for ${name}", - ("arg", arg)("name", name) ); -} - // compatible member types X and argument type flat_set and X != Y template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} @@ -225,14 +217,13 @@ struct attr_argument_validate_visitor { // validate common data validate_restriction_commons( restriction ); - // validate member-related + // validate member-related data restriction_validate_visitor vtor( restriction ); vtor( *((const T*)nullptr) ); } } }; - struct number_argument_validate_visitor { typedef void result_type; @@ -295,7 +286,7 @@ void require_compatible_argument( const restriction_type& op_restriction, const } template -void require_list_argument( const restriction_type& op_restriction, const char* name ) +void require_compatible_list_argument( const restriction_type& op_restriction, const char* name ) { // argument should be flat_set< T-compatible > list_argument_validate_visitor vtor( name ); @@ -305,7 +296,7 @@ void require_list_argument( const restriction_type& op_restriction, const char* template void require_attr_argument( const restriction_type& op_restriction, const char* name ) { - // argument should be flat_set< T-compatible > + // argument should be attr and compatible to T attr_argument_validate_visitor vtor( name ); op_restriction.argument.visit( vtor ); } @@ -333,7 +324,7 @@ struct restriction_validation_helper if( is_subset_function( op_restriction.function ) ) { // argument need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); + require_compatible_list_argument( op_restriction, name ); } else if( is_compare_function( op_restriction.function ) ) { @@ -353,7 +344,7 @@ struct restriction_validation_helper if( is_subset_function( op_restriction.function ) ) { // argument need to be a list, and type should be compatible to T - require_list_argument( op_restriction, name ); + require_compatible_list_argument( op_restriction, name ); } else if( is_equal_function( op_restriction.function ) ) { @@ -367,7 +358,7 @@ struct restriction_validation_helper } } - template // non-compatible, not-simple, aka object-like type + template // non-comparable, not-simple, aka object-like type void validate_member( const char* name, std::false_type, std::false_type ) { FC_ASSERT( op_restriction.function == restriction_type::func_attr, @@ -387,11 +378,11 @@ struct restriction_validation_helper "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_list_argument( op_restriction, name ); + require_compatible_list_argument( op_restriction, name ); } template - void validate_by_member_type( const char* name, const T* t ) + 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; @@ -466,7 +457,6 @@ struct restriction_validation_helper }; -template< typename OpType > struct by_index_member_validate_visitor { typedef void result_type; @@ -500,7 +490,7 @@ struct restriction_validate_visitor // other member modifiers should have been checked outside, so only check mmod_none here if( op_restriction.member_modifier.value == restriction_type::mmod_none ) { - by_index_member_validate_visitor vtor( op_restriction ); + by_index_member_validate_visitor vtor( op_restriction ); fc::reflector::visit_local_member( vtor, op_restriction.member.value ); } } From 02b0c891d4c3f2e6eb4300d7ee009ca9ecae137b Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 09:05:09 -0400 Subject: [PATCH 17/22] Refactory: rename visitors --- libraries/chain/protocol/restriction.cpp | 76 ++++++++++++------------ 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp index ca3b2dd25a..95bf16fed3 100644 --- a/libraries/chain/protocol/restriction.cpp +++ b/libraries/chain/protocol/restriction.cpp @@ -35,7 +35,7 @@ namespace graphene { namespace chain { template using bool_const = std::integral_constant; -struct restriction_validate_visitor; +struct restriction_validation_visitor; void validate_restriction_commons( const restriction_type& op_restriction ); struct argument_get_units_visitor @@ -134,12 +134,12 @@ template<> struct is_simple_data_type { static const bool value template<> struct is_simple_data_type { static const bool value = true; }; template -struct compatible_argument_validate_visitor +struct compatible_argument_validation_visitor { typedef void result_type; const char* name; - compatible_argument_validate_visitor( const char* _name ) : name(_name) {} + compatible_argument_validation_visitor( const char* _name ) : name(_name) {} template inline result_type operator()( const ArgType& arg ) // by default incompatible @@ -153,24 +153,24 @@ struct compatible_argument_validate_visitor }; // compatible member types X and argument type Y and X != Y -template<> template<> inline void compatible_argument_validate_visitor::operator()( const string& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_visitor::operator()( const int64_t& arg ) {} +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_validate_visitor::operator()( const int64_t& arg ) {} -template<> template<> inline void compatible_argument_validate_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 -struct list_argument_validate_visitor +struct list_argument_validation_visitor { typedef void result_type; const char* name; - list_argument_validate_visitor( const char* _name ) : name(_name) {} + list_argument_validation_visitor( const char* _name ) : name(_name) {} template inline result_type operator()( const ArgType& arg ) // by default incompatible @@ -184,24 +184,24 @@ struct list_argument_validate_visitor }; // compatible member types X and argument type flat_set and X != Y -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_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 ) {} +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_validate_visitor::operator()( const flat_set& arg ) {} -template<> template<> inline void list_argument_validate_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 -struct attr_argument_validate_visitor +struct attr_argument_validation_visitor { typedef void result_type; const char* name; - attr_argument_validate_visitor( const char* _name ) : name(_name) {} + attr_argument_validation_visitor( const char* _name ) : name(_name) {} template inline result_type operator()( const ArgType& arg ) @@ -218,18 +218,18 @@ struct attr_argument_validate_visitor // validate common data validate_restriction_commons( restriction ); // validate member-related data - restriction_validate_visitor vtor( restriction ); + restriction_validation_visitor vtor( restriction ); vtor( *((const T*)nullptr) ); } } }; -struct number_argument_validate_visitor +struct number_argument_validation_visitor { typedef void result_type; const char* name; - number_argument_validate_visitor( const char* _name ) : name(_name) {} + number_argument_validation_visitor( const char* _name ) : name(_name) {} template inline result_type operator()( const ArgType& arg ) @@ -281,7 +281,7 @@ template void require_compatible_argument( const restriction_type& op_restriction, const char* name ) { // argument should be T-compatible - compatible_argument_validate_visitor vtor( name ); + compatible_argument_validation_visitor vtor( name ); op_restriction.argument.visit( vtor ); } @@ -289,7 +289,7 @@ template void require_compatible_list_argument( const restriction_type& op_restriction, const char* name ) { // argument should be flat_set< T-compatible > - list_argument_validate_visitor vtor( name ); + list_argument_validation_visitor vtor( name ); op_restriction.argument.visit( vtor ); } @@ -297,14 +297,14 @@ template void require_attr_argument( const restriction_type& op_restriction, const char* name ) { // argument should be attr and compatible to T - attr_argument_validate_visitor vtor( name ); + attr_argument_validation_visitor vtor( name ); op_restriction.argument.visit( vtor ); } void require_number_argument( const restriction_type& op_restriction, const char* name ) { // argument should be a number - number_argument_validate_visitor vtor( name ); + number_argument_validation_visitor vtor( name ); op_restriction.argument.visit( vtor ); } @@ -457,13 +457,13 @@ struct restriction_validation_helper }; -struct by_index_member_validate_visitor +struct member_validation_visitor { typedef void result_type; const restriction_type& op_restriction; - by_index_member_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} + member_validation_visitor( const restriction_type& opr ) : op_restriction(opr) {} template void operator()( const char* name )const @@ -473,12 +473,12 @@ struct by_index_member_validate_visitor } }; -struct restriction_validate_visitor +struct restriction_validation_visitor { typedef void result_type; const restriction_type& op_restriction; - restriction_validate_visitor( const restriction_type& opr ) : op_restriction(opr) {} + restriction_validation_visitor( const restriction_type& opr ) : op_restriction(opr) {} template result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it @@ -490,7 +490,7 @@ struct restriction_validate_visitor // other member modifiers should have been checked outside, so only check mmod_none here if( op_restriction.member_modifier.value == restriction_type::mmod_none ) { - by_index_member_validate_visitor vtor( op_restriction ); + member_validation_visitor vtor( op_restriction ); fc::reflector::visit_local_member( vtor, op_restriction.member.value ); } } @@ -504,7 +504,7 @@ struct restriction_validate_visitor void validate_restriction_details( const restriction_type& op_restriction, unsigned_int op_type ) { - restriction_validate_visitor vtor( op_restriction ); + restriction_validation_visitor vtor( op_restriction ); switch( op_type.value ) { // will have code like below for all operations: From 7439058b9d4d4ad90de407bbee276d6a798978dd Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 10:04:43 -0400 Subject: [PATCH 18/22] Refactory: rename variables --- .../graphene/chain/protocol/restriction.hpp | 6 + libraries/chain/protocol/restriction.cpp | 115 +++++++++--------- 2 files changed, 63 insertions(+), 58 deletions(-) diff --git a/libraries/chain/include/graphene/chain/protocol/restriction.hpp b/libraries/chain/include/graphene/chain/protocol/restriction.hpp index c81c4df30a..affc1294f4 100644 --- a/libraries/chain/include/graphene/chain/protocol/restriction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/restriction.hpp @@ -114,7 +114,13 @@ namespace graphene { namespace chain { 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 diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp index 95bf16fed3..c2b5b2d997 100644 --- a/libraries/chain/protocol/restriction.cpp +++ b/libraries/chain/protocol/restriction.cpp @@ -36,7 +36,6 @@ template using bool_const = std::integral_constant; struct restriction_validation_visitor; -void validate_restriction_commons( const restriction_type& op_restriction ); struct argument_get_units_visitor { @@ -83,9 +82,9 @@ struct argument_get_units_visitor result_type operator()( const attr_restriction_type& t ) { result_type result = 0; - for( const auto& restriction : t ) + for( const auto& r : t ) { - result += restriction.argument.visit(*this); + result += r.argument.visit(*this); } return result; } @@ -213,12 +212,12 @@ struct attr_argument_validation_visitor result_type operator()( const attr_restriction_type& arg ) // vector { // Recursively check T.members - for( const restriction_type& restriction : arg ) + for( const restriction_type& r : arg ) { // validate common data - validate_restriction_commons( restriction ); + r.validate_common_data(); // validate member-related data - restriction_validation_visitor vtor( restriction ); + restriction_validation_visitor vtor( r ); vtor( *((const T*)nullptr) ); } } @@ -269,116 +268,116 @@ inline bool is_compare_function( const restriction_type::function_type function || function == restriction_type::func_ge ); } -void require_compare_function( const restriction_type& op_restriction, const char* name ) +void require_compare_function( const restriction_type& r, const char* name ) { // function should be a compare function - FC_ASSERT( is_compare_function( op_restriction.function ), + FC_ASSERT( is_compare_function( r.function ), "Function '${func}' is incompatible, requires a compare function for ${name}", - ("func", op_restriction.function)("name", name) ); + ("func", r.function)("name", name) ); } template -void require_compatible_argument( const restriction_type& op_restriction, const char* name ) +void require_compatible_argument( const restriction_type& r, const char* name ) { // argument should be T-compatible compatible_argument_validation_visitor vtor( name ); - op_restriction.argument.visit( vtor ); + r.argument.visit( vtor ); } template -void require_compatible_list_argument( const restriction_type& op_restriction, const char* name ) +void require_compatible_list_argument( const restriction_type& r, const char* name ) { // argument should be flat_set< T-compatible > list_argument_validation_visitor vtor( name ); - op_restriction.argument.visit( vtor ); + r.argument.visit( vtor ); } template -void require_attr_argument( const restriction_type& op_restriction, const char* name ) +void require_attr_argument( const restriction_type& r, const char* name ) { // argument should be attr and compatible to T attr_argument_validation_visitor vtor( name ); - op_restriction.argument.visit( vtor ); + r.argument.visit( vtor ); } -void require_number_argument( const restriction_type& op_restriction, const char* name ) +void require_number_argument( const restriction_type& r, const char* name ) { // argument should be a number number_argument_validation_visitor vtor( name ); - op_restriction.argument.visit( vtor ); + r.argument.visit( vtor ); } struct restriction_validation_helper { - const restriction_type& op_restriction; ///< the restriction + const restriction_type& _restriction; ///< the restriction - restriction_validation_helper( const restriction_type& opr ) : op_restriction(opr) + restriction_validation_helper( const restriction_type& r ) : _restriction(r) { - FC_ASSERT( op_restriction.member_modifier.value == restriction_type::mmod_none, + FC_ASSERT( _restriction.member_modifier.value == restriction_type::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( op_restriction.function ) ) + if( is_subset_function( _restriction.function ) ) { // argument need to be a list, and type should be compatible to T - require_compatible_list_argument( op_restriction, name ); + require_compatible_list_argument( _restriction, name ); } - else if( is_compare_function( op_restriction.function ) ) + else if( is_compare_function( _restriction.function ) ) { // argument need to be compatible - require_compatible_argument( op_restriction, name ); + require_compatible_argument( _restriction, name ); } else { FC_THROW( "Function '${func}' is incompatible, requires a compare function or subset function for ${name}", - ("func", op_restriction.function)("name", 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( op_restriction.function ) ) + if( is_subset_function( _restriction.function ) ) { // argument need to be a list, and type should be compatible to T - require_compatible_list_argument( op_restriction, name ); + require_compatible_list_argument( _restriction, name ); } - else if( is_equal_function( op_restriction.function ) ) + else if( is_equal_function( _restriction.function ) ) { // argument need to be compatible - require_compatible_argument( op_restriction, name ); + require_compatible_argument( _restriction, name ); } else { FC_THROW( "Function '${func}' is incompatible, requires an equal function or subset function for ${name}", - ("func", op_restriction.function)("name", 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( op_restriction.function == restriction_type::func_attr, + FC_ASSERT( _restriction.function == restriction_type::func_attr, "Object-like member '${name}' can only use func_attr", ("name", name) ); // argument need to be a attribute_restriction - require_attr_argument( op_restriction, name ); + require_attr_argument( _restriction, name ); } template void validate_list_like_member( const char* name ) { - FC_ASSERT( is_superset_function( op_restriction.function ), + 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( op_restriction, name ); + require_compatible_list_argument( _restriction, name ); } template @@ -461,14 +460,14 @@ struct member_validation_visitor { typedef void result_type; - const restriction_type& op_restriction; + const restriction_type& _restriction; - member_validation_visitor( const restriction_type& opr ) : op_restriction(opr) {} + member_validation_visitor( const restriction_type& r ) : _restriction(r) {} template void operator()( const char* name )const { - restriction_validation_helper helper( op_restriction ); + restriction_validation_helper helper( _restriction ); helper.validate_by_member_type( name, (const Member*)nullptr ); } }; @@ -476,22 +475,22 @@ struct member_validation_visitor struct restriction_validation_visitor { typedef void result_type; - const restriction_type& op_restriction; + const restriction_type& _restriction; - restriction_validation_visitor( const restriction_type& opr ) : op_restriction(opr) {} + restriction_validation_visitor( const restriction_type& r ) : _restriction(r) {} template result_type operator()( const OpType& ) // Note: the parameter is a reference of *nullptr, we should not use it { - FC_ASSERT( op_restriction.member < fc::reflector::total_member_count, + FC_ASSERT( _restriction.member < fc::reflector::total_member_count, "member number ${m} is too large", - ("m",op_restriction.member) ); + ("m",_restriction.member) ); // other member modifiers should have been checked outside, so only check mmod_none here - if( op_restriction.member_modifier.value == restriction_type::mmod_none ) + if( _restriction.member_modifier.value == restriction_type::mmod_none ) { - member_validation_visitor vtor( op_restriction ); - fc::reflector::visit_local_member( vtor, op_restriction.member.value ); + member_validation_visitor vtor( _restriction ); + fc::reflector::visit_local_member( vtor, _restriction.member.value ); } } @@ -502,9 +501,9 @@ struct restriction_validation_visitor operation::visit< I >( vtor ); \ break; -void validate_restriction_details( const restriction_type& op_restriction, unsigned_int op_type ) +void validate_restriction_details( const restriction_type& r, unsigned_int op_type ) { - restriction_validation_visitor vtor( op_restriction ); + restriction_validation_visitor vtor( r ); switch( op_type.value ) { // will have code like below for all operations: @@ -517,34 +516,34 @@ void validate_restriction_details( const restriction_type& op_restriction, unsig } -void validate_restriction_commons( const restriction_type& op_restriction ) +void restriction_type::validate_common_data() const { // validate member modifier - FC_ASSERT( op_restriction.member_modifier < restriction_type::MEMBER_MODIFIER_TYPE_COUNT, + FC_ASSERT( member_modifier < MEMBER_MODIFIER_TYPE_COUNT, "member modifier number ${mm} is too large", - ("mm", op_restriction.member_modifier) ); + ("mm", member_modifier) ); - if( op_restriction.member_modifier.value == restriction_type::mmod_size ) + if( member_modifier.value == mmod_size ) { - require_compare_function( op_restriction, "size modifier" ); - require_number_argument( op_restriction, "size modifier" ); + require_compare_function( *this, "size modifier" ); + require_number_argument( *this, "size modifier" ); } - else if( op_restriction.member_modifier.value == restriction_type::mmod_pack_size ) + else if( member_modifier.value == mmod_pack_size ) { - require_compare_function( op_restriction, "pack_size modifier" ); - require_number_argument( op_restriction, "pack_size modifier" ); + require_compare_function( *this, "pack_size modifier" ); + require_number_argument( *this, "pack_size modifier" ); } // validate function - FC_ASSERT( op_restriction.function < restriction_type::FUNCTION_TYPE_COUNT, + FC_ASSERT( function < FUNCTION_TYPE_COUNT, "function number ${f} is too large", - ("f", op_restriction.function) ); + ("f", function) ); } void restriction_type::validate( unsigned_int op_type )const { // validate common data - validate_restriction_commons( *this ); + validate_common_data(); // validate details by operation_type validate_restriction_details( *this, op_type ); } From 7793f2d608a7febd274f4759e1cc58658aa6f679 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 10:17:57 -0400 Subject: [PATCH 19/22] Refactory: rename restriction_type to restriction --- .../chain/custom_authority_object.hpp | 2 +- .../chain/protocol/custom_authority.hpp | 2 +- .../graphene/chain/protocol/restriction.hpp | 14 ++-- libraries/chain/protocol/custom_authority.cpp | 12 +-- libraries/chain/protocol/restriction.cpp | 76 +++++++++---------- 5 files changed, 51 insertions(+), 55 deletions(-) diff --git a/libraries/chain/include/graphene/chain/custom_authority_object.hpp b/libraries/chain/include/graphene/chain/custom_authority_object.hpp index 3c964ba907..ea8021fa88 100644 --- a/libraries/chain/include/graphene/chain/custom_authority_object.hpp +++ b/libraries/chain/include/graphene/chain/custom_authority_object.hpp @@ -47,7 +47,7 @@ namespace graphene { namespace chain { time_point_sec valid_to; unsigned_int operation_type; authority auth; - vector restrictions; + vector restrictions; }; /** diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index b98b2936b3..ec045e4329 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -47,7 +47,7 @@ namespace graphene { namespace chain { time_point_sec valid_to; unsigned_int operation_type; authority auth; - vector restrictions; + vector restrictions; empty_extensions_type extensions; diff --git a/libraries/chain/include/graphene/chain/protocol/restriction.hpp b/libraries/chain/include/graphene/chain/protocol/restriction.hpp index affc1294f4..66c65e2e3b 100644 --- a/libraries/chain/include/graphene/chain/protocol/restriction.hpp +++ b/libraries/chain/include/graphene/chain/protocol/restriction.hpp @@ -26,14 +26,10 @@ namespace graphene { namespace chain { - - struct restriction_type; - typedef vector attr_restriction_type; - /** * Defines the set of valid operation restritions as a discriminated union type. */ - struct restriction_type + struct restriction { enum member_modifier_type @@ -102,7 +98,7 @@ namespace graphene { namespace chain { /* 36 */ flat_set< vesting_balance_id_type >, \ /* 37 */ flat_set< worker_id_type >, \ /* 38 */ flat_set< balance_id_type >, \ - /* 39 */ attr_restriction_type + /* 39 */ vector< restriction > typedef static_variant < GRAPHENE_OP_RESTRICTION_ARGUMENTS_VARIADIC > argument_type; @@ -125,14 +121,14 @@ namespace graphene { namespace chain { } } // graphene::chain -FC_REFLECT_ENUM( graphene::chain::restriction_type::member_modifier_type, +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_type::function_type, +FC_REFLECT_ENUM( graphene::chain::restriction::function_type, (func_eq) (func_ne) (func_lt) @@ -149,7 +145,7 @@ FC_REFLECT_ENUM( graphene::chain::restriction_type::function_type, (FUNCTION_TYPE_COUNT) ) -FC_REFLECT( graphene::chain::restriction_type, +FC_REFLECT( graphene::chain::restriction, (member) (member_modifier) (function) diff --git a/libraries/chain/protocol/custom_authority.cpp b/libraries/chain/protocol/custom_authority.cpp index 606a552380..25522c7100 100644 --- a/libraries/chain/protocol/custom_authority.cpp +++ b/libraries/chain/protocol/custom_authority.cpp @@ -36,9 +36,9 @@ share_type custom_authority_create_operation::calculate_fee( const fee_parameter unit_fee *= (valid_to - valid_from).to_seconds(); unit_fee *= auth.num_auths(); uint64_t restriction_units = 0; - for( const auto& restriction : restrictions ) + for( const auto& r : restrictions ) { - restriction_units += restriction.get_units(); + restriction_units += r.get_units(); } unit_fee *= restriction_units; unit_fee /= 1000; @@ -71,10 +71,10 @@ void custom_authority_create_operation::validate()const //FC_ASSERT( !auth.is_impossible(), "cannot use an imposible authority threshold" ); // Note: allow restrictions to be empty - for( const auto& restriction : restrictions ) + for( const auto& r: restrictions ) { // recursively validate member index and argument type - restriction.validate( operation_type ); + r.validate( operation_type ); } } @@ -110,10 +110,10 @@ void custom_authority_update_operation::validate()const //FC_ASSERT( !auth.is_impossible(), "cannot use an imposible authority threshold" ); // Note: allow restrictions to be empty - for( const auto& restriction : restrictions ) + for( const auto& r : restrictions ) { // TODO recursively validate member index and argument type - restriction.validate( operation_type ); + r.validate( operation_type ); } */ } diff --git a/libraries/chain/protocol/restriction.cpp b/libraries/chain/protocol/restriction.cpp index c2b5b2d997..73bc2ca954 100644 --- a/libraries/chain/protocol/restriction.cpp +++ b/libraries/chain/protocol/restriction.cpp @@ -79,7 +79,7 @@ struct argument_get_units_visitor return result; } - result_type operator()( const attr_restriction_type& t ) + result_type operator()( const vector& t ) { result_type result = 0; for( const auto& r : t ) @@ -90,7 +90,7 @@ struct argument_get_units_visitor } }; -uint64_t restriction_type::get_units()const +uint64_t restriction::get_units()const { argument_get_units_visitor vtor; return argument.visit( vtor ); @@ -205,14 +205,14 @@ struct attr_argument_validation_visitor template inline result_type operator()( const ArgType& arg ) { - FC_THROW( "Argument '${arg}' is incompatible, requires an attr_restriction_type for ${name}", + FC_THROW( "Argument '${arg}' is incompatible, requires 'vector' for ${name}", ("arg", arg)("name", name) ); } - result_type operator()( const attr_restriction_type& arg ) // vector + result_type operator()( const vector& arg ) { // Recursively check T.members - for( const restriction_type& r : arg ) + for( const restriction& r : arg ) { // validate common data r.validate_common_data(); @@ -240,35 +240,35 @@ struct number_argument_validation_visitor inline result_type operator()( const int64_t& arg ) {} }; -inline bool is_subset_function( const restriction_type::function_type function ) +inline bool is_subset_function( const restriction::function_type function ) { - return ( function == restriction_type::func_in - || function == restriction_type::func_not_in ); + return ( function == restriction::func_in + || function == restriction::func_not_in ); } -inline bool is_superset_function( const restriction_type::function_type function ) +inline bool is_superset_function( const restriction::function_type function ) { - return ( function == restriction_type::func_has_all - || function == restriction_type::func_has_none ); + return ( function == restriction::func_has_all + || function == restriction::func_has_none ); } -inline bool is_equal_function( const restriction_type::function_type function ) +inline bool is_equal_function( const restriction::function_type function ) { - return ( function == restriction_type::func_eq - || function == restriction_type::func_ne ); + return ( function == restriction::func_eq + || function == restriction::func_ne ); } -inline bool is_compare_function( const restriction_type::function_type function ) +inline bool is_compare_function( const restriction::function_type function ) { - return ( function == restriction_type::func_eq - || function == restriction_type::func_ne - || function == restriction_type::func_lt - || function == restriction_type::func_le - || function == restriction_type::func_gt - || function == restriction_type::func_ge ); + 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_type& r, const char* name ) +void require_compare_function( const restriction& r, const char* name ) { // function should be a compare function FC_ASSERT( is_compare_function( r.function ), @@ -277,7 +277,7 @@ void require_compare_function( const restriction_type& r, const char* name ) } template -void require_compatible_argument( const restriction_type& r, const char* name ) +void require_compatible_argument( const restriction& r, const char* name ) { // argument should be T-compatible compatible_argument_validation_visitor vtor( name ); @@ -285,7 +285,7 @@ void require_compatible_argument( const restriction_type& r, const char* name ) } template -void require_compatible_list_argument( const restriction_type& r, const char* name ) +void require_compatible_list_argument( const restriction& r, const char* name ) { // argument should be flat_set< T-compatible > list_argument_validation_visitor vtor( name ); @@ -293,14 +293,14 @@ void require_compatible_list_argument( const restriction_type& r, const char* na } template -void require_attr_argument( const restriction_type& r, const char* name ) +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_type& r, const char* name ) +void require_number_argument( const restriction& r, const char* name ) { // argument should be a number number_argument_validation_visitor vtor( name ); @@ -309,11 +309,11 @@ void require_number_argument( const restriction_type& r, const char* name ) struct restriction_validation_helper { - const restriction_type& _restriction; ///< the restriction + const restriction& _restriction; ///< the restriction - restriction_validation_helper( const restriction_type& r ) : _restriction(r) + restriction_validation_helper( const restriction& r ) : _restriction(r) { - FC_ASSERT( _restriction.member_modifier.value == restriction_type::mmod_none, + FC_ASSERT( _restriction.member_modifier.value == restriction::mmod_none, "Internal error: should only use this helper for mmod_none" ); } @@ -360,7 +360,7 @@ struct restriction_validation_helper 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_type::func_attr, + 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 @@ -460,9 +460,9 @@ struct member_validation_visitor { typedef void result_type; - const restriction_type& _restriction; + const restriction& _restriction; - member_validation_visitor( const restriction_type& r ) : _restriction(r) {} + member_validation_visitor( const restriction& r ) : _restriction(r) {} template void operator()( const char* name )const @@ -475,9 +475,9 @@ struct member_validation_visitor struct restriction_validation_visitor { typedef void result_type; - const restriction_type& _restriction; + const restriction& _restriction; - restriction_validation_visitor( const restriction_type& r ) : _restriction(r) {} + 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 @@ -487,7 +487,7 @@ struct restriction_validation_visitor ("m",_restriction.member) ); // other member modifiers should have been checked outside, so only check mmod_none here - if( _restriction.member_modifier.value == restriction_type::mmod_none ) + if( _restriction.member_modifier.value == restriction::mmod_none ) { member_validation_visitor vtor( _restriction ); fc::reflector::visit_local_member( vtor, _restriction.member.value ); @@ -501,7 +501,7 @@ struct restriction_validation_visitor operation::visit< I >( vtor ); \ break; -void validate_restriction_details( const restriction_type& r, unsigned_int op_type ) +void validate_restriction_details( const restriction& r, unsigned_int op_type ) { restriction_validation_visitor vtor( r ); switch( op_type.value ) @@ -516,7 +516,7 @@ void validate_restriction_details( const restriction_type& r, unsigned_int op_ty } -void restriction_type::validate_common_data() const +void restriction::validate_common_data() const { // validate member modifier FC_ASSERT( member_modifier < MEMBER_MODIFIER_TYPE_COUNT, @@ -540,7 +540,7 @@ void restriction_type::validate_common_data() const ("f", function) ); } -void restriction_type::validate( unsigned_int op_type )const +void restriction::validate( unsigned_int op_type )const { // validate common data validate_common_data(); From 4095bc5e2ae06656c24e15203ef61d738f343626 Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 11:01:48 -0400 Subject: [PATCH 20/22] Add reflection for custom_authority_create_op --- libraries/chain/custom_authority_evaluator.cpp | 6 +++--- .../graphene/chain/custom_authority_object.hpp | 15 ++++++++++++--- .../graphene/chain/protocol/custom_authority.hpp | 16 ++++++++++++++-- 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/libraries/chain/custom_authority_evaluator.cpp b/libraries/chain/custom_authority_evaluator.cpp index 8de5ef64ea..b5ce001ca5 100644 --- a/libraries/chain/custom_authority_evaluator.cpp +++ b/libraries/chain/custom_authority_evaluator.cpp @@ -32,7 +32,7 @@ namespace graphene { namespace chain { void_result custom_authority_create_evaluator::do_evaluate(const custom_authority_create_evaluator::operation_type& op) { try { - database& d = db(); + const database& d = db(); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -46,7 +46,7 @@ object_id_type custom_authority_create_evaluator::do_apply(const custom_authorit void_result custom_authority_update_evaluator::do_evaluate(const custom_authority_update_evaluator::operation_type& op) { try { - database& d = db(); + const database& d = db(); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } @@ -60,7 +60,7 @@ void_result custom_authority_update_evaluator::do_apply(const custom_authority_u void_result custom_authority_delete_evaluator::do_evaluate(const custom_authority_delete_evaluator::operation_type& op) { try { - database& d = db(); + const database& d = db(); return void_result(); } FC_CAPTURE_AND_RETHROW( (op) ) } diff --git a/libraries/chain/include/graphene/chain/custom_authority_object.hpp b/libraries/chain/include/graphene/chain/custom_authority_object.hpp index ea8021fa88..4d5585f8ea 100644 --- a/libraries/chain/include/graphene/chain/custom_authority_object.hpp +++ b/libraries/chain/include/graphene/chain/custom_authority_object.hpp @@ -41,7 +41,7 @@ namespace graphene { namespace chain { static const uint8_t type_id = impl_custom_authority_object_type; account_id_type account; - uint32_t auth_id; + uint32_t custom_id; bool enabled; time_point_sec valid_from; time_point_sec valid_to; @@ -50,13 +50,22 @@ namespace graphene { namespace chain { 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, member< object, object_id_type, &object::id > >, + ordered_unique< tag, + composite_key< + custom_authority_object, + member, + member + > + > > > custom_authority_multi_index_type; @@ -70,7 +79,7 @@ namespace graphene { namespace chain { FC_REFLECT_DERIVED( graphene::chain::custom_authority_object, (graphene::db::object), (account) - (auth_id) + (custom_id) (enabled) (valid_from) (valid_to) diff --git a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp index ec045e4329..677cbc8188 100644 --- a/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp +++ b/libraries/chain/include/graphene/chain/protocol/custom_authority.hpp @@ -41,7 +41,7 @@ namespace graphene { namespace chain { asset fee; // TODO: defer fee to expiration / update / removal ? account_id_type account; - uint32_t auth_id; + uint32_t custom_id; bool enabled; time_point_sec valid_from; time_point_sec valid_to; @@ -100,6 +100,18 @@ FC_REFLECT( graphene::chain::custom_authority_create_operation::fee_parameters_t 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) ) +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) ) From f35f6eee025b0f9689b0bdba5ec08192aa5df72a Mon Sep 17 00:00:00 2001 From: abitmore Date: Sun, 12 Aug 2018 11:30:56 -0400 Subject: [PATCH 21/22] Basic impl of custom_authority_create_evaluator still need to add checks in do_evaluate() --- .../chain/custom_authority_evaluator.cpp | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/libraries/chain/custom_authority_evaluator.cpp b/libraries/chain/custom_authority_evaluator.cpp index b5ce001ca5..5cb8ca93bc 100644 --- a/libraries/chain/custom_authority_evaluator.cpp +++ b/libraries/chain/custom_authority_evaluator.cpp @@ -30,42 +30,83 @@ namespace graphene { namespace chain { -void_result custom_authority_create_evaluator::do_evaluate(const custom_authority_create_evaluator::operation_type& op) +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_evaluator::operation_type& op) +object_id_type custom_authority_create_evaluator::do_apply(const custom_authority_create_operation& op) { try { database& d = db(); - return {}; + 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_evaluator::operation_type& 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_evaluator::operation_type& 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_evaluator::operation_type& 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_evaluator::operation_type& op) +void_result custom_authority_delete_evaluator::do_apply(const custom_authority_delete_operation& op) { try { database& d = db(); From dbc8a7607990413ee23b53e8967354d3ffa7808c Mon Sep 17 00:00:00 2001 From: abitmore Date: Sat, 6 Oct 2018 13:05:02 -0400 Subject: [PATCH 22/22] Temporarily update FC to for-cust-auth branch Need to update FC to master after changes got merged into master --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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