Merge branch '434-api-fillin-proposed-op-fees' into develop

This commit is contained in:
theoreticalbts 2015-11-05 16:04:44 -05:00
commit 979d52c4c9
3 changed files with 97 additions and 10 deletions

View file

@ -31,6 +31,8 @@
#include <cctype>
#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<database_api_impl>
bool verify_authority( const signed_transaction& trx )const;
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )const;
processed_transaction validate_transaction( const signed_transaction& trx )const;
vector<asset> get_required_fees( const vector<operation>& ops, asset_id_type id )const;
vector< fc::variant > get_required_fees( const vector<operation>& ops, asset_id_type id )const;
// Proposed transactions
vector<proposal_object> 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<asset> database_api::get_required_fees( const vector<operation>& ops, asset_id_type id )const
vector< fc::variant > database_api::get_required_fees( const vector<operation>& ops, asset_id_type id )const
{
return my->get_required_fees( ops, id );
}
vector<asset> database_api_impl::get_required_fees( const vector<operation>& 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<asset> 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<proposal_create_operation>::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<proposal_create_operation>();
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<operation>& 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;
}

View file

@ -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<asset> get_required_fees( const vector<operation>& ops, asset_id_type id )const;
vector< fc::variant > get_required_fees( const vector<operation>& ops, asset_id_type id )const;
///////////////////////////
// Proposed transactions //

View file

@ -31,6 +31,8 @@ namespace fc
//template const graphene::chain::fee_schedule& smart_ref<graphene::chain::fee_schedule>::operator*() const;
}
#define MAX_FEE_STABILIZATION_ITERATION 4
namespace graphene { namespace chain {
typedef fc::smart_ref<fee_schedule> 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<MAX_FEE_STABILIZATION_ITERATION; i++ )
{
op.visit( set_fee_visitor( f_max ) );
auto f2 = calculate_fee( op, core_exchange_rate );
if( f == f2 )
break;
f_max = std::max( f_max, f2 );
f = f2;
if( i == 0 )
{
// no need for warnings on later iterations
wlog( "set_fee requires multiple iterations to stabilize with core_exchange_rate ${p} on operation ${op}",
("p", core_exchange_rate) ("op", op) );
}
}
return f_max;
}
void chain_parameters::validate()const