From 8ccafe0f03ac499b10e532f73c6f82fad2bd48ae Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Mon, 6 Jul 2015 14:56:35 -0400 Subject: [PATCH] Refactor fee schedule for extensibility --- libraries/app/application.cpp | 3 +- libraries/chain/db_init.cpp | 3 +- .../include/graphene/chain/operations.hpp | 3 +- .../chain/include/graphene/chain/types.hpp | 76 ++++++++++++------- libraries/chain/operations.cpp | 6 +- libraries/chain/types.cpp | 29 +++++++ tests/common/database_fixture.cpp | 5 +- tests/tests/block_tests.cpp | 2 +- 8 files changed, 87 insertions(+), 40 deletions(-) diff --git a/libraries/app/application.cpp b/libraries/app/application.cpp index 09126702..a0d00603 100644 --- a/libraries/app/application.cpp +++ b/libraries/app/application.cpp @@ -157,8 +157,7 @@ namespace detail { auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan"))); genesis_state_type initial_state; - fc::reflector::visit( - fee_schedule_type::fee_set_visitor{initial_state.initial_parameters.current_fees, 0}); + initial_state.initial_parameters.current_fees.set_all_fees(0); secret_hash_type::encoder enc; fc::raw::pack(enc, nathan_key); fc::raw::pack(enc, secret_hash_type()); diff --git a/libraries/chain/db_init.cpp b/libraries/chain/db_init.cpp index 603b12d7..277c4d52 100644 --- a/libraries/chain/db_init.cpp +++ b/libraries/chain/db_init.cpp @@ -240,7 +240,8 @@ void database::init_genesis(const genesis_state_type& genesis_state) p.parameters = genesis_state.initial_parameters; // Set fees to zero initially, so that genesis initialization needs not pay them // We'll fix it at the end of the function - fc::reflector::visit(fee_schedule_type::fee_set_visitor{p.parameters.current_fees, 0}); + p.parameters.current_fees.set_all_fees(0); + }); create( [&](dynamic_global_property_object& p) { p.time = fc::time_point_sec(GRAPHENE_GENESIS_TIMESTAMP); diff --git a/libraries/chain/include/graphene/chain/operations.hpp b/libraries/chain/include/graphene/chain/operations.hpp index 4c770536..895186e1 100644 --- a/libraries/chain/include/graphene/chain/operations.hpp +++ b/libraries/chain/include/graphene/chain/operations.hpp @@ -1050,8 +1050,7 @@ namespace graphene { namespace chain { account_id_type fee_payer()const { return fee_paying_account; } void get_required_auth(flat_set& active_auth_set, flat_set& owner_auth_set)const; void validate()const; - share_type calculate_fee(const fee_schedule_type& k)const - { return k.proposal_delete_fee; } + share_type calculate_fee(const fee_schedule_type& k)const; void get_balance_delta(balance_accumulator& acc, const operation_result& result = asset())const { acc.adjust(fee_payer(), -fee); } }; ///@} diff --git a/libraries/chain/include/graphene/chain/types.hpp b/libraries/chain/include/graphene/chain/types.hpp index 170909d3..e51b6c46 100644 --- a/libraries/chain/include/graphene/chain/types.hpp +++ b/libraries/chain/include/graphene/chain/types.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -312,35 +313,24 @@ namespace graphene { namespace chain { struct fee_schedule_type { - /** - * @brief The fee_set_visitor struct sets all fees to a particular value in one fell swoop - * - * Example: - * @code - * fee_schedule_type sch; - * // Set all fees to 50 - * fc::reflector::visit(fee_schedule_type::fee_set_visitor{sch, 50}); - * @endcode - */ - struct fee_set_visitor { - fee_schedule_type& f; - uint32_t fee; - - template - void operator()(const char*)const - { - f.*member = fee; - } - }; - /// The number of bytes to charge a data fee for const static int BYTES_PER_DATA_FEE = 1024; template uint32_t total_data_fee(Ts... ts)const { return data_size(ts...) / BYTES_PER_DATA_FEE * data_fee; + // return ((fc::uint128(data_size(ts...)) * data_fee) / BYTES_PER_DATA_FEE).to_uint64(); } + + + /** + * Standard fees + * + * These fees are listed because they will be updated frequently and it is lower + * overhead than having a key/value map. + */ + ///@{ uint64_t key_create_fee = 270300; ///< the cost to register a public key with the blockchain uint64_t account_create_fee = 666666; ///< the cost to register the cheapest non-free account uint64_t account_update_fee = 150000; ///< the cost to update an existing account @@ -370,7 +360,6 @@ namespace graphene { namespace chain { uint64_t witness_withdraw_pay_fee = 1500000; ///< fee for withdrawing witness pay uint64_t transfer_fee = 2700000; ///< fee for transferring some asset uint64_t limit_order_create_fee = 666666; ///< fee for placing a limit order in the markets - uint64_t limit_order_cancel_fee = 0; ///< fee for canceling a limit order uint64_t call_order_fee = 800000; ///< fee for placing a call order in the markets uint64_t publish_feed_fee = 10000; ///< fee for publishing a price feed uint64_t data_fee = 13500000; ///< a price per BYTES_PER_DATA_FEE bytes of user data @@ -380,22 +369,49 @@ namespace graphene { namespace chain { uint64_t withdraw_permission_create_fee = 2700000; ///< the cost to create a withdraw permission uint64_t withdraw_permission_update_fee = 150000; ///< the cost to update a withdraw permission uint64_t withdraw_permission_claim_fee = 700000; ///< the cost to withdraw from a withdraw permission - uint64_t withdraw_permission_delete_fee = 0; ///< the cost to delete a withdraw permission uint64_t vesting_balance_create_fee = 7000000; uint64_t vesting_balance_withdraw_fee = 2700000; uint64_t worker_create_fee = 680000000; ///< the cost to create a new worker uint64_t assert_op_fee = 150000; ///< fee per assert operation uint64_t proposal_create_fee = 7000000; ///< fee for creating a proposed transaction uint64_t proposal_update_fee = 1500000; ///< fee for adding or removing approval of a proposed transaction - uint64_t proposal_delete_fee = 0; ///< fee for deleting a proposed transaction uint64_t custom_operation_fee = 300000; ///< fee for a custom operation + ///@{ + + void set_all_fees( uint64_t v ); + + /** Advanced Fees + * + * THese fields are reserved for future expansion of the fee schedule without breaking the + * protocol serialization. + */ + ///@{ + enum advanced_fee_id + { + withdraw_permission_delete_fee_id = 1, ///< the cost to delete a withdraw permission + proposal_delete_fee_id = 2, ///< fee for deleting a proposed transaction + limit_order_cancel_fee_id = 3 ///< fee for canceling a limit order + }; + + uint64_t get_advanced_fee( advanced_fee_id id )const + { + auto itr = advanced.find(id); + if( itr == advanced.end() ) return 0; + return itr->second; + } + + uint64_t withdraw_permission_delete_fee()const { return get_advanced_fee( withdraw_permission_delete_fee_id ); } + + + flat_map advanced; + ///@} protected: - size_t data_size()const { + uint64_t data_size()const { return 0; } template - size_t data_size(T t, Ts... ts)const { + uint64_t data_size(T t, Ts... ts)const { return fc::raw::pack_size(t) + data_size(ts...); } }; @@ -562,7 +578,6 @@ FC_REFLECT( graphene::chain::fee_schedule_type, (witness_withdraw_pay_fee) (transfer_fee) (limit_order_create_fee) - (limit_order_cancel_fee) (call_order_fee) (publish_feed_fee) (asset_create_fee) @@ -578,7 +593,6 @@ FC_REFLECT( graphene::chain::fee_schedule_type, (withdraw_permission_create_fee) (withdraw_permission_update_fee) (withdraw_permission_claim_fee) - (withdraw_permission_delete_fee) (vesting_balance_create_fee) (vesting_balance_withdraw_fee) (asset_global_settle_fee) @@ -586,8 +600,12 @@ FC_REFLECT( graphene::chain::fee_schedule_type, (assert_op_fee) (proposal_create_fee) (proposal_update_fee) - (proposal_delete_fee) + (advanced) ) +FC_REFLECT_ENUM( graphene::chain::fee_schedule_type::advanced_fee_id, + (withdraw_permission_delete_fee_id) + (proposal_delete_fee_id) + (limit_order_cancel_fee_id) ) FC_REFLECT( graphene::chain::chain_parameters, (current_fees) diff --git a/libraries/chain/operations.cpp b/libraries/chain/operations.cpp index 1da28524..005c7b19 100644 --- a/libraries/chain/operations.cpp +++ b/libraries/chain/operations.cpp @@ -454,7 +454,7 @@ void limit_order_cancel_operation::validate()const share_type limit_order_cancel_operation::calculate_fee(const fee_schedule_type& k) const { - return k.limit_order_create_fee; + return k.get_advanced_fee(fee_schedule_type::limit_order_cancel_fee_id); } void call_order_update_operation::get_required_auth(flat_set& active_auth_set, flat_set&) const @@ -555,6 +555,8 @@ void proposal_delete_operation::get_required_auth(flat_set& act else active_auth_set.insert(fee_paying_account); } +share_type proposal_delete_operation::calculate_fee(const fee_schedule_type& k)const +{ return k.get_advanced_fee( fee_schedule_type::proposal_delete_fee_id ); } void account_transfer_operation::validate()const { @@ -677,7 +679,7 @@ void withdraw_permission_delete_operation::validate() const share_type withdraw_permission_delete_operation::calculate_fee(const fee_schedule_type& k) const { - return k.withdraw_permission_delete_fee; + return k.get_advanced_fee( fee_schedule_type::withdraw_permission_delete_fee_id ); } void withdraw_permission_create_operation::get_required_auth(flat_set& active_auth_set, flat_set&) const diff --git a/libraries/chain/types.cpp b/libraries/chain/types.cpp index 0dc3978c..a57dbe6d 100644 --- a/libraries/chain/types.cpp +++ b/libraries/chain/types.cpp @@ -80,6 +80,35 @@ namespace graphene { namespace chain { { return p1.key_data != p2.key_data; } + /** + * @brief The fee_set_visitor struct sets all fees to a particular value in one fell swoop + * + * Example: + * @code + * fee_schedule_type sch; + * // Set all fees to 50 + * fc::reflector::visit(fee_schedule_type::fee_set_visitor{sch, 50}); + * @endcode + */ + struct fee_set_visitor { + fee_schedule_type& f; + uint64_t fee; + + template + void operator()(const char*)const + { + f.*member = fee; + } + template (Class::*member)> + void operator()(const char*)const + { + } + }; + + void fee_schedule_type::set_all_fees( uint64_t v ) + { + fc::reflector::visit(fee_set_visitor{*this, v}); + } } } // graphene::chain diff --git a/tests/common/database_fixture.cpp b/tests/common/database_fixture.cpp index a80e7ebf..51ab549d 100644 --- a/tests/common/database_fixture.cpp +++ b/tests/common/database_fixture.cpp @@ -74,7 +74,7 @@ database_fixture::database_fixture() genesis_state.initial_committee_candidates.push_back({name}); genesis_state.initial_witness_candidates.push_back({name, delegate_priv_key.get_public_key(), secret}); } - fc::reflector::visit(fee_schedule_type::fee_set_visitor{genesis_state.initial_parameters.current_fees, 0}); + genesis_state.initial_parameters.current_fees.set_all_fees(0); db.init_genesis(genesis_state); ahplugin->plugin_startup(); mhplugin->plugin_startup(); @@ -782,8 +782,7 @@ void database_fixture::enable_fees( { db.modify(global_property_id_type()(db), [fee](global_property_object& gpo) { - fc::reflector::visit(fee_schedule_type::fee_set_visitor{gpo.parameters.current_fees, - uint32_t(fee.value)}); + gpo.parameters.current_fees.set_all_fees(fee.value); gpo.parameters.current_fees.membership_annual_fee = 3*fee.value; gpo.parameters.current_fees.membership_lifetime_fee = 10*fee.value; } ); diff --git a/tests/tests/block_tests.cpp b/tests/tests/block_tests.cpp index f79ea3f8..17e07b95 100644 --- a/tests/tests/block_tests.cpp +++ b/tests/tests/block_tests.cpp @@ -51,7 +51,7 @@ genesis_state_type make_genesis() { genesis_state.initial_committee_candidates.push_back({name}); genesis_state.initial_witness_candidates.push_back({name, delegate_priv_key.get_public_key(), secret}); } - fc::reflector::visit(fee_schedule_type::fee_set_visitor{genesis_state.initial_parameters.current_fees, 0}); + genesis_state.initial_parameters.current_fees.set_all_fees(0); return genesis_state; }