Graphene 源码阅读 - 交易篇 - 交易费用

https://steemit.com/bitshares/@cifer/6ai6f6-graphene

交易费用

操作类型不同, 所需费用也不同. 各项操作的费用记录在 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() 都会抛异常, 这点感兴趣可以看一下 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

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

87      result_type operator()( const OpType& op )const

88      {

89          try {

90            return op.calculate_fee( param.get() ).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() ).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

108      void operator()( OpType& op )const

109      {

110          op.fee = _fee;

111      }

112    };

至此, 这笔操作的交易费用就被计算并设置到了操作的成员变量中.

你可能感兴趣的:(Graphene 源码阅读 - 交易篇 - 交易费用)