交易费用
操作类型不同, 所需费用也不同. 各项操作的费用记录在 global_property_object::chain_parameters::fee_schedule
中.
石墨烯代码将创世信息中的 inital_parameters::current_fees
, global_property_object::chain_parameters::fee_schdule
, 以及各项操作中的 struct fee_parameters_type {}
结构关联了起来.
节点启动之前, 一般我们会使用 —create-genesis-json
选项创建创世文件, 创世文件中的 inital_parameters::current_fees
信息会使用各个操作的 struct fee_parameters_type {}
结构写入, 参见:
// 代码 1.1
// libraries/app/application.cpp
79 namespace detail {
80
81 graphene::chain::genesis_state_type create_example_genesis() {
82 auto nathan_key = fc::ecc::private_key::regenerate(fc::sha256::hash(string("nathan")));
83 dlog("Allocating all stake to ${key}", ("key", utilities::key_to_wif(nathan_key)));
84 graphene::chain::genesis_state_type initial_state;
85 initial_state.initial_parameters.current_fees = fee_schedule::get_default();//->set_all_fees(GRAPHENE_BLOCKCHAIN_PRECISION);
86 initial_state.initial_active_witnesses = GRAPHENE_DEFAULT_MIN_WITNESS_COUNT;
87 initial_state.initial_timestamp = time_point_sec(time_point::now().sec_since_epoch() /
88 initial_state.initial_parameters.block_interval *
89 initial_state.initial_parameters.block_interval);
90 for( uint64_t i = 0; i < initial_state.initial_active_witnesses; ++i )
91 {
92 auto name = "init"+fc::to_string(i);
93 initial_state.initial_accounts.emplace_back(name,
94 nathan_key.get_public_key(),
95 nathan_key.get_public_key(),
96 true);
97 initial_state.initial_committee_candidates.push_back({name});
98 initial_state.initial_witness_candidates.push_back({name, nathan_key.get_public_key()});
99 }
100
101 initial_state.initial_accounts.emplace_back("nathan", nathan_key.get_public_key());
102 initial_state.initial_balances.push_back({nathan_key.get_public_key(),
103 GRAPHENE_SYMBOL,
104 GRAPHENE_MAX_SHARE_SUPPLY});
105 initial_state.initial_chain_id = fc::sha256::hash( "BOGUS" );
106
107 return initial_state;
108 }
然后在启动时, global_property_object::chain_parameters::fee_schdule
会用创世信息中的 inital_parameters::current_fees
初始化自己; 后续创建打包交易使用的费用信息都是从 global_property_object::chain_parameters::fee_schdule
获得, 各个操作自己的 struct fee_parameters_type {}
不再被使用.
交易费用的设置
设置交易费用一般发生在交易签名之前, 如果交易中包含多个操作, 每个操作的费用都会被计算并设置:
// 代码 1.2
// libraries/wallet/wallet.cpp
501 void set_operation_fees( signed_transaction& tx, const fee_schedule& s )
502 {
503 for( auto& op : tx.operations )
504 s.set_fee(op);
505 }
fee_schedule::set_fee(op)
方法以操作为参数, 负责设置每个操作的费用. set_fee()
首先调用 calculate_fee()
设置计算操作的费用, calculate_fee()
这里用到了一个 calc_fee_visitor
, 这个 visitor 以 fee_schedule
和 op
为参数, 就是用 op
的计费方法以及 fee_schedule
的计费参数计算费用. calc_fee_visitor
里有一个 try … catch
(代码 1.4) 可能不好理解, 这里的 try … catch
是因为 fee_schedule
这块代码有点问题, 除了 op
是 account_create_operation
之外, 其它情况下 param.get<OpType>()
都会抛异常, 这点感兴趣可以看一下 fee_schedule
的源码便知原因.
// 代码 1.3
// libraries/chain/protocol/fee_schedule.cpp
133 asset fee_schedule::calculate_fee( const operation& op, const price& core_exchange_rate )const
134 {
135 auto base_value = op.visit( calc_fee_visitor( *this, op ) );
136 auto scaled = fc::uint128(base_value) * scale;
137 scaled /= GRAPHENE_100_PERCENT;
138 FC_ASSERT( scaled <= GRAPHENE_MAX_SHARE_SUPPLY );
139 //idump( (base_value)(scaled)(core_exchange_rate) );
140 auto result = asset( scaled.to_uint64(), asset_id_type(0) ) * core_exchange_rate;
141 //FC_ASSERT( result * core_exchange_rate >= asset( scaled.to_uint64()) );
142
143 while( result * core_exchange_rate < asset( scaled.to_uint64()) )
144 result.amount++;
145
146 FC_ASSERT( result.amount <= GRAPHENE_MAX_SHARE_SUPPLY );
147 return result;
148 }
150 asset fee_schedule::set_fee( operation& op, const price& core_exchange_rate )const
151 {
152 auto f = calculate_fee( op, core_exchange_rate );
153 auto f_max = f;
154 for( int i=0; i<MAX_FEE_STABILIZATION_ITERATION; i++ )
155 {
156 op.visit( set_fee_visitor( f_max ) );
157 auto f2 = calculate_fee( op, core_exchange_rate );
158 if( f == f2 )
159 break;
160 f_max = std::max( f_max, f2 );
161 f = f2;
162 if( i == 0 )
163 {
164 // no need for warnings on later iterations
165 wlog( "set_fee requires multiple iterations to stabilize with core_exchange_rate ${p} on operation ${op}",
166 ("p", core_exchange_rate) ("op", op) );
167 }
168 }
169 return f_max;
170 }
// 代码 1.4
libraries/chain/protocol/fee_schedule.cpp
78 struct calc_fee_visitor
79 {
80 typedef uint64_t result_type;
81
82 const fee_schedule& param;
83 const int current_op;
84 calc_fee_visitor( const fee_schedule& p, const operation& op ):param(p),current_op(op.which()){}
85
86 template<typename OpType>
87 result_type operator()( const OpType& op )const
88 {
89 try {
90 return op.calculate_fee( param.get<OpType>() ).value;
91 } catch (fc::assert_exception e) {
92 fee_parameters params; params.set_which(current_op);
93 auto itr = param.parameters.find(params);
94 if( itr != param.parameters.end() ) params = *itr;
95 return op.calculate_fee( params.get<typename OpType::fee_parameters_type>() ).value;
96 }
97 }
98 };
calculate_fee
算出费用后, 便会调用 op.visit(set_fee_visitor(f_max))
将具体费用设置到操作中, set_fee_visitor()
很简单, 就是将 f_max
赋值给操作的 fee 成员, 是的, 每个操作都有一个 fee 成员.
另外在 fee_schedule::set_fee
代码中还考虑到 core_exchange_rate
的变动而多循环执行了几次费用计算, 以达到费用更精确的目的.
// 代码 1.5
// libraries/chain/protocol/fee_schedule.cpp
100 struct set_fee_visitor
101 {
102 typedef void result_type;
103 asset _fee;
104
105 set_fee_visitor( asset f ):_fee(f){}
106
107 template<typename OpType>
108 void operator()( OpType& op )const
109 {
110 op.fee = _fee;
111 }
112 };
至此, 这笔操作的交易费用就被计算并设置到了操作的成员变量中.
@cifer, 这就是文章该有的气质!
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
谢谢
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
我希望我知道更好的中文。
我讀得很好。
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
I wish I could write better English :)
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit
Congratulations @cifer! You have received a personal award!
1 Year on Steemit
Click on the badge to view your Board of Honor.
Do not miss the last post from @steemitboard:
SteemitBoard World Cup Contest - The results, the winners and the prizes
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit