From a96fd62d0363af38ae6574eeaf1846b818669d8c Mon Sep 17 00:00:00 2001 From: theoreticalbts Date: Thu, 5 Nov 2015 14:56:59 -0500 Subject: [PATCH 1/2] fee_schedule.cpp: Use relaxation to set fee #435 --- libraries/chain/protocol/fee_schedule.cpp | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libraries/chain/protocol/fee_schedule.cpp b/libraries/chain/protocol/fee_schedule.cpp index 6950aac0..6a8fc11f 100644 --- a/libraries/chain/protocol/fee_schedule.cpp +++ b/libraries/chain/protocol/fee_schedule.cpp @@ -31,6 +31,8 @@ namespace fc //template const graphene::chain::fee_schedule& smart_ref::operator*() const; } +#define MAX_FEE_STABILIZATION_ITERATION 4 + namespace graphene { namespace chain { typedef fc::smart_ref smart_fee_schedule; @@ -138,8 +140,23 @@ namespace graphene { namespace chain { asset fee_schedule::set_fee( operation& op, const price& core_exchange_rate )const { auto f = calculate_fee( op, core_exchange_rate ); - op.visit( set_fee_visitor( f ) ); - return f; + auto f_max = f; + for( int i=0; i Date: Thu, 5 Nov 2015 14:57:29 -0500 Subject: [PATCH 2/2] database_api.cpp: Recursively evaluate proposal fees #434 --- libraries/app/database_api.cpp | 84 +++++++++++++++++-- .../app/include/graphene/app/database_api.hpp | 2 +- 2 files changed, 78 insertions(+), 8 deletions(-) diff --git a/libraries/app/database_api.cpp b/libraries/app/database_api.cpp index bca3ac3c..3d668fa1 100644 --- a/libraries/app/database_api.cpp +++ b/libraries/app/database_api.cpp @@ -31,6 +31,8 @@ #include +#define GET_REQUIRED_FEES_MAX_RECURSION 4 + namespace graphene { namespace app { class database_api_impl; @@ -116,7 +118,7 @@ class database_api_impl : public std::enable_shared_from_this bool verify_authority( const signed_transaction& trx )const; bool verify_account_authority( const string& name_or_id, const flat_set& signers )const; processed_transaction validate_transaction( const signed_transaction& trx )const; - vector get_required_fees( const vector& ops, asset_id_type id )const; + vector< fc::variant > get_required_fees( const vector& ops, asset_id_type id )const; // Proposed transactions vector get_proposed_transactions( account_id_type id )const; @@ -1355,18 +1357,86 @@ processed_transaction database_api_impl::validate_transaction( const signed_tran return _db.validate_transaction(trx); } -vector database_api::get_required_fees( const vector& ops, asset_id_type id )const +vector< fc::variant > database_api::get_required_fees( const vector& ops, asset_id_type id )const { return my->get_required_fees( ops, id ); } -vector database_api_impl::get_required_fees( const vector& ops, asset_id_type id )const +/** + * Container method for mutually recursive functions used to + * implement get_required_fees() with potentially nested proposals. + */ +struct get_required_fees_helper { - vector result; + get_required_fees_helper( + const fee_schedule& _current_fee_schedule, + const price& _core_exchange_rate, + uint32_t _max_recursion + ) + : current_fee_schedule(_current_fee_schedule), + core_exchange_rate(_core_exchange_rate), + max_recursion(_max_recursion) + {} + + fc::variant set_op_fees( operation& op ) + { + if( op.which() == operation::tag::value ) + { + return set_proposal_create_op_fees( op ); + } + else + { + asset fee = current_fee_schedule.set_fee( op, core_exchange_rate ); + fc::variant result; + fc::to_variant( fee, result ); + return result; + } + } + + fc::variant set_proposal_create_op_fees( operation& proposal_create_op ) + { + proposal_create_operation& op = proposal_create_op.get(); + std::pair< asset, fc::variants > result; + for( op_wrapper& prop_op : op.proposed_ops ) + { + FC_ASSERT( current_recursion < max_recursion ); + ++current_recursion; + result.second.push_back( set_op_fees( prop_op.op ) ); + --current_recursion; + } + // we need to do this on the boxed version, which is why we use + // two mutually recursive functions instead of a visitor + result.first = current_fee_schedule.set_fee( proposal_create_op, core_exchange_rate ); + fc::variant vresult; + fc::to_variant( result, vresult ); + return vresult; + } + + const fee_schedule& current_fee_schedule; + const price& core_exchange_rate; + uint32_t max_recursion; + uint32_t current_recursion = 0; +}; + +vector< fc::variant > database_api_impl::get_required_fees( const vector& ops, asset_id_type id )const +{ + vector< operation > _ops = ops; + // + // we copy the ops because we need to mutate an operation to reliably + // determine its fee, see #435 + // + + vector< fc::variant > result; result.reserve(ops.size()); - const asset_object& a = id(_db); - for( const auto& op : ops ) - result.push_back( _db.current_fee_schedule().calculate_fee( op, a.options.core_exchange_rate ) ); + const asset_object& a = id(_db); + get_required_fees_helper helper( + _db.current_fee_schedule(), + a.options.core_exchange_rate, + GET_REQUIRED_FEES_MAX_RECURSION ); + for( operation& op : _ops ) + { + result.push_back( helper.set_op_fees( op ) ); + } return result; } diff --git a/libraries/app/include/graphene/app/database_api.hpp b/libraries/app/include/graphene/app/database_api.hpp index 1b18dd94..e543819a 100644 --- a/libraries/app/include/graphene/app/database_api.hpp +++ b/libraries/app/include/graphene/app/database_api.hpp @@ -447,7 +447,7 @@ class database_api * For each operation calculate the required fee in the specified asset type. If the asset type does * not have a valid core_exchange_rate */ - vector get_required_fees( const vector& ops, asset_id_type id )const; + vector< fc::variant > get_required_fees( const vector& ops, asset_id_type id )const; /////////////////////////// // Proposed transactions //