Merge branch '434-api-fillin-proposed-op-fees' into develop
This commit is contained in:
commit
979d52c4c9
3 changed files with 97 additions and 10 deletions
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
|
#define GET_REQUIRED_FEES_MAX_RECURSION 4
|
||||||
|
|
||||||
namespace graphene { namespace app {
|
namespace graphene { namespace app {
|
||||||
|
|
||||||
class database_api_impl;
|
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_authority( const signed_transaction& trx )const;
|
||||||
bool verify_account_authority( const string& name_or_id, const flat_set<public_key_type>& signers )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;
|
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
|
// Proposed transactions
|
||||||
vector<proposal_object> get_proposed_transactions( account_id_type id )const;
|
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);
|
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 );
|
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());
|
result.reserve(ops.size());
|
||||||
const asset_object& a = id(_db);
|
const asset_object& a = id(_db);
|
||||||
for( const auto& op : ops )
|
get_required_fees_helper helper(
|
||||||
result.push_back( _db.current_fee_schedule().calculate_fee( op, a.options.core_exchange_rate ) );
|
_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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -447,7 +447,7 @@ class database_api
|
||||||
* For each operation calculate the required fee in the specified asset type. If the asset type does
|
* For each operation calculate the required fee in the specified asset type. If the asset type does
|
||||||
* not have a valid core_exchange_rate
|
* 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 //
|
// Proposed transactions //
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,8 @@ namespace fc
|
||||||
//template const graphene::chain::fee_schedule& smart_ref<graphene::chain::fee_schedule>::operator*() const;
|
//template const graphene::chain::fee_schedule& smart_ref<graphene::chain::fee_schedule>::operator*() const;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MAX_FEE_STABILIZATION_ITERATION 4
|
||||||
|
|
||||||
namespace graphene { namespace chain {
|
namespace graphene { namespace chain {
|
||||||
|
|
||||||
typedef fc::smart_ref<fee_schedule> smart_fee_schedule;
|
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
|
asset fee_schedule::set_fee( operation& op, const price& core_exchange_rate )const
|
||||||
{
|
{
|
||||||
auto f = calculate_fee( op, core_exchange_rate );
|
auto f = calculate_fee( op, core_exchange_rate );
|
||||||
op.visit( set_fee_visitor( f ) );
|
auto f_max = f;
|
||||||
return 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
|
void chain_parameters::validate()const
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue