ripple (瑞波)区块链网络手续费fee参数 : load_factor参数算法详解

load_factor参数算法详解

server_info的load_factor

//src\ripple\app\misc\NetworkOPs.cpp : getServerInfo
info[jss::load_factor] = static_cast<double> (loadFactor) / loadBaseServer;

参数说明:

  1. loadBaseServer为load_factor的基础初始值:lftNormalFee = 256;
  2. loadFactor由以下参数决定:
auto const escalationMetrics = app_.getTxQ().getMetrics(*app_.openLedger().current());
auto const loadFactorServer = app_.getFeeTrack().getLoadFactor();
auto const loadBaseServer = app_.getFeeTrack().getLoadBase();
auto const loadFactorFeeEscalation = escalationMetrics ? escalationMetrics->expFeeLevel : 1;
auto const loadBaseFeeEscalation = escalationMetrics ? escalationMetrics->referenceFeeLevel : 1;

auto const loadFactor = std::max(static_cast<std::uint64_t>(loadFactorServer),
        mulDiv(loadFactorFeeEscalation, loadBaseServer, loadBaseFeeEscalation).second);

2.1. mulDiv函数定义如下:
给定三个参数A,B,C,结果result=A*B/C; 当result超过uint64_t的最大值limit64时,返回limit64,否则返回result。
2.2. loadFactorServer实际为{ clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_ }三个值取最大值。
这部分涉及本地及远程负载费用计算,在loadFactorServer部分详细介绍;
2.3. loadFactorFeeEscalation和loadBaseFeeEscalation都是由getMetrics返回,这涉及到ripple的FeeEscalation特性

loadFactorServer

loadFactorServer为{ clusterTxnLoadFee_, localTxnLoadFee_, remoteTxnLoadFee_ }三个值取最大值,cluster模式
目前没有使用,暂时不讨论。主要介绍localTxnLoadFee_和remoteTxnLoadFee_ ;

1. localTxnLoadFee_

主要由LoadManger类来负责管理:

//src\ripple\app\main\LoadManager.cpp : run ()
bool change = false;
if (app_.getJobQueue ().isOverloaded ()) {
    JLOG(journal_.info()) << app_.getJobQueue ().getJson (0);
    change = app_.getFeeTrack ().raiseLocalFee ();
}
else {
    change = app_.getFeeTrack ().lowerLocalFee ();
}

if (change) {
    app_.getOPs ().reportFeeChange ();
}

从上述代码中,确定此处有四部分因素:

  • job是否过载;
  • raiseLocalFee;
  • lowerLocalFee;
  • reportFeeChange;

整体过程概述为:
首先判断当前job是否过载,即isOverloaded函数。该函数遍历当前每一个执行的job,如果有任意一个job被判断为过载,
则返回true,触发raiseLocalFee函数。否则触发lowerLocalFee。只有连续两次触发raiseLocalFee,才会调整fee。无论fee
是增大或者减小,只要有变化就会调用reportFeeChange向peer广播本地fee。其他节点收到广播后将其设置为remoteTxnLoadFee_。

1.1. isOverloaded()
该函数遍历每个当前job。进行过载判断,只要有一个过载,就返回ture,触发raiseLocalFee。
每个job都会有一个过载样本库,每次当jobEvent停止时,运行时间加上等待时间被记为延迟时间,超过2ms,就会被加入过载样本库。
样本库计数mLatencyEvents加一,延迟均值和延迟峰值都会增加当前样本延迟量。
当mLatencyEvents值不等于零,就将延迟均值和延迟峰值和该job设定的预期延迟均值mTargetLatencyAvg和预期延迟峰值mTargetLatencyPk进行比较:(预期延迟值在job的定义中给出)

isOverTarget (mLatencyMSAvg / (mLatencyEvents * 4), mLatencyMSPeak / (mLatencyEvents * 4));
bool LoadMonitor::isOverTarget (std::uint64_t avg, std::uint64_t peak)
{
    return (mTargetLatencyPk && (peak > mTargetLatencyPk)) ||
           (mTargetLatencyAvg && (avg > mTargetLatencyAvg));
}

根据比较结果判断是否过载。

1.2. raiseLocalFee()
该函数通过一个计数器控制,每次调用该函数,计数器加一,只有该计数器大于2时,才会调整,否则直接返回,而每次调用lowerLocalFee都会将该计数器减一,最少为0。所以需要连续两次触发reaiseLocalFee,才会有效。
函数内部首先将localTxnLoadFee_与remoteTxnLoadFee_比较,取最大值,然后增加该值的1/4,并与上限lftFeeMax比较,超过上限返回上限,否则返回计算结果。

1.3. lowerLocalFee()
每次调用首先将计数器减一,然后减少localTxnLoadFee_的1/4,并与基础值lftNormalFee比较,小于基础值,返回基础值,否则返回计算结果。

1.4. reportFeeChange()
无论费用是增加或者减少,只有有变动,就会通过该函数,广播给peer节点。其他节点收到后设置为该节点的remoteTxnLoadFee_

2. remoteTxnLoadFee_

即其他信任节点广播的localTxnLoadFee_的值。

FeeEscalation特性

getMetrics函数

//src\ripple\app\misc\impl\TxQ.cpp : getMetrics

在getMetrics函数中,有三个决定因素,分别是当前交易量,期望交易量和倍乘器。

1. 期望交易量算法:

链启动后,对于每个区块设定一个交易数量最小值,期望值和最大值。除了程序预置的以下值,
还可以在配置文件中的[transaction_queue]下手动配置。

StandAloneNormal
最小值10005
期望值100050
最大值NULLNULL

期望交易量就是
上一区块的实际交易量与预置最小值和预置期望值比较,小于最小取最小,大于期望取期望,否则取原本值。
(这是一种情况的取值,另一种情况算法详见chainsqld\src\ripple\app\misc\impl\TxQ.cpp : TxQ::FeeMetrics::update)。

2. 倍乘器算法:

链启动后,设置一个初始最小倍乘器:minimumEscalationMultiplier = 256 * 500。
倍乘器实际算法:(feeLevels是一个vector,按顺序存储当前区块所有交易的手续费)

if (feeLevels.empty())
    {
        escalationMultiplier_ = minimumMultiplier_;
    }
    else
    {
        escalationMultiplier_ = (feeLevels[size / 2] +
            feeLevels[(size - 1) / 2] + 1) / 2;
        escalationMultiplier_ = std::max(escalationMultiplier_,
            minimumMultiplier_);
    }
3. 计算最后expFeeLevel

FeeEscalation特性就是根据当前openledger的交易量和由上一区块的交易量计算出的期望交易量进行比较:

if (current > target)
{
    return mulDiv(multiplier, current * current, target * target).second;
}

return baseLevel;

最后计算

至此,将server_info中计算load_factor的所有参数准备完毕,并依据文章开头的公式:

auto const loadFactor = std::max(static_cast<std::uint64_t>(loadFactorServer),
        mulDiv(loadFactorFeeEscalation, loadBaseServer, loadBaseFeeEscalation).second);

计算出load_factor。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值