Filecoin的Gas相关计算逻辑

区块网 阅读 71289 2020-9-4 13:13
分享至
微信扫一扫,打开网页后点击屏幕右上角分享按钮

Filecoin开始Space Race了。矿工的实力都开始展现。官方的代码也有不少问题,几天时间,版本从0.5.1升级到0.5.6。好久不看go语言相关的逻辑,最近看了看Filecoin的Gas计算相关的逻辑,分享一下吧。本文分析的是0.5.6的逻辑,Lotus代码的最后一个提交信息如下:

commit 606a58bc6bc035ec0b90c6b50488e29e90f4238f

Author: Aayush Rajasekaran <arajasek94@gmail.com>

Date:   Sat Aug 29 00:56:24 2020 -0400

  Lotus version 0.5.6

Lotus代码的CHANGELOG清晰记录了Gas费用模型的变化:从原来的limit/price,改成了limit/premium/feecap。新的Gas模型参考了EIP-1559:发送交易,交易费用不超过"feecap*limit"。矿工赚取的交易费是"premium*limit"。简单的说,feecap*limit是Gas费用的上限,矿工能赚取的费用是premium*limit。(feecap-premium)*limit的Gas费用会被燃烧。

feecap是如何设置的?limit是不是设置的越大越好?

Gas费用计算的相关逻辑实现在node/impl/full/gas.go中的GasEstimateMessageGas函数。接下来详细介绍Base/Limit/Premium/FeeCap。

1. Base Fee

每个区块都会设置一个baseFee。在该区块中的交易都需要燃烧相应的baseFee。注意baseFee,虽然名字看上去是fee,其实是price,具体燃烧的费用是baseFee*limit。baseFee相关的设置定义在build/params_shared_vals.go中:

const BlockGasLimit = 10_000_000_000

const BlockGasTarget = BlockGasLimit / 2

const BaseFeeMaxChangeDenom = 8 // 12.5%

const InitialBaseFee = 100e6

const MinimumBaseFee = 100

const PackingEfficiencyNum = 4

const PackingEfficiencyDenom = 5

在初始区块,baseFee设置为InitialBaseFee(10^8)。从当前的区块,生成下一个区块时,需要根据当前的区块的limit的总量确定,具体的逻辑请查看chain/store/basefee.go的ComputeBaseFee和computeNextBaseFee函数。

· 最小的baseFee - MinimumBaseFee (100)

· 区块Gas Limit - 区块中所有交易的Gas Limit的总和,在计算baseFee的时候,打了九折(PackingEfficiencyNum/PackingEfficiencyDenom)

· 区块Gas Limit的“超出”部分 - 每个区块存在Gas Limit的目标大小 - BlockGasTarget。超过BlockGasTarget的部分,视为超出部分。注意超出部分,可正可负。

· 更新的baseFee - 下一个区块的baseFee,在当前区块的baseFee的基础上增加超出部分的12.5%(BaseFeeMaxChangeDenom)。相关计算逻辑如下:

    change := big.Mul(baseFee, big.NewInt(delta))

    change = big.Div(change, big.NewInt(build.BlockGasTarget))

    change = big.Div(change, big.NewInt(build.BaseFeeMaxChangeDenom))

简单的说,当前区块中的Gas Limit消耗超出了BlockGasTarget,则base Fee增加超出部分的12.5%。在这样的逻辑下,你会发现在交易多的情况下,base Fee会增加迅速增加和降低。

最新24小时的base Fee可以在飞狐浏览器查看(https://filfox.info/zh):

Filecoin的Gas相关计算逻辑

2. GasLimit

Gas Limit是指一个交易,愿意为交易执行支付的“油量”。一个交易消耗的Gas Limit几乎是固定的,计算过程请查看GasEstimateGasLimit函数。简单的说,当一个交易需要获取Gas Limit时,在目前区块高度上,“执行”该交易:

res, err := a.Stmgr.CallWithGas(ctx, &msg, priorMsgs, ts)

CallWithGas,只是为了获取执行过程消耗的Gas,并不真正改变当前的状态。

3. GasPremium

Gas Premium是指一个交易,愿意为交易执行支付的“油价”。GAS费用是油量乘以油价的结果。油量和交易本身有关,也几乎是固定的。显然的是,油价高,GAS费用高,矿工的收入就高,更愿意将交易优先打包。从交易发送者的角度,油价越低越好。Lotus代码给出一个计算Gas Premium的方法,请查看GasEstimateGasPremium函数,分为几步:

· 查看之前区块(4个 = 2*2)中所有交易,并按照Gas Premium从高到低排序

· 计算所有交易的“平均”Gas Premium。平均的意思是,找出一半油量消耗的Gas Premium:

    at := build.BlockGasTarget * int64(blocks) / 2

    prev1, prev2 := big.Zero(), big.Zero()

    for _, price := range prices {

        prev1, prev2 = price.price, prev1

        at -= price.limit

        if at > 0 {

            continue

        }

    }

· 加上千分之五的随机性

    // mean 1, stddev 0.005 => 95% within +-1%

    noise := 1 + rand.NormFloat64()*0.005

    premium = types.BigMul(premium, types.NewInt(uint64(noise*(1<<precision))+1))

    premium = types.BigDiv(premium, types.NewInt(1<<precision))

4. GasFeeCap

除了Gas Premium,交易还需要支付Base Fee。也就是说,一般情况下,交易需要支付的费用是: (Gas Premium + Base Fee) * Gas Limit。问题是,Base Fee是变化的,有可能太大,交易发送者,不愿意支付。Gas Fee Cap(上限),就是设置支付费用的上限。相关的计算逻辑请看GasEstimateFeeCap函数。

· 交易非常可能不是下一个区块立即被打包,那需要考虑在接下来的多个区块(10个)才被打包的情况下,Base Fee的变化:

    parentBaseFee := ts.Blocks()[0].ParentBaseFee

    increaseFactor := math.Pow(1.+1./float64(build.BaseFeeMaxChangeDenom), float64(maxqueueblks))

    feeInFuture := types.BigMul(parentBaseFee, types.NewInt(uint64(increaseFactor*(1<<8))))

    feeInFuture = types.BigDiv(feeInFuture, types.NewInt(1<<8))

每个区块Base Fee按照12.5%的涨幅计算。

· 当前账户余额的百分之一,作为支付费用的上限:

maxAccepted := types.BigDiv(act.Balance, types.NewInt(MaxSpendOnFeeDenom))

· 上述两种情况下的最少值,作为Gas Fee Cap

5. GasLimit设置惩罚

众所周知,以太坊中的Gas Limit可以设置的非常大。一般情况下,多余的Gas费用会全数返还。特别注意的是,Filecoin并不完全是这样。因为Gas Limit参与了Base Fee和Gas Premium的计算,真实的Gas Limit是非常重要的。如果一个交易,设置了不合理的Gas Limit,Filecoin采取了一种惩罚机制。惩罚的Gas费用也被燃烧,计算逻辑看ComputeGasOverestimationBurn函数。

· 允许一定的误差情况下,计算Gas limit的超出部分

const (

    gasOveruseNum   = 11

    gasOveruseDenom = 10

)

over := gasLimit - (gasOveruseNum*gasUsed)/gasOveruseDenom

Gas消耗的1.1倍以内认为是合理设置。

if over > gasUsed {

    over = gasUsed

}

超出部分的上限是Gas的使用量。

· 按照超出(over)的比例,确定惩罚的油量:

gasToBurn := big.NewInt(gasLimit - gasUsed)

gasToBurn = big.Mul(gasToBurn, big.NewInt(over))

gasToBurn = big.Div(gasToBurn, big.NewInt(gasUsed))

简单的说,惩罚的是over/gasUsed的比例。如果over超过了gasUsed,就是所有罚光。

总结:

Filecoin的Gas模型,引入了BaseFee,用来调节交易的拥堵情况。BaseFee,在区块拥堵或者区块交易不够的情况下,都会按照12.5%进行相应的调节。每笔交易的费用计算公式:(Gas Premium + Base Fee) * Gas Limit。其中BaseFee的部分会被燃烧掉,Gas Premium作为矿工的手续费。特别注意的是,GasLimit不要随意设置,多余的Gas Limit会被燃烧。

btcfans公众号

微信扫描关注公众号,及时掌握新动向

免责声明:
2.本文版权归属原作所有,仅代表作者本人观点,不代表比特范的观点或立场
2.本文版权归属原作所有,仅代表作者本人观点,不代表比特范的观点或立场
标签: Filecoin Gas
上一篇:Revolut已经添加美国地区的BCH支付 下一篇:HiSWAP“嗨场”独创裂变返佣,开启DEX3.0新时代

相关资讯