Filecoin - Gas計算

買賣虛擬貨幣
Filecoin開始Space Race了。礦工的實力都開始展現。官方的程式碼也有不少問題,幾天時間,版本從0.5.1升級到0.5.6。好久不看go語言相關的邏輯,最近看了看Filecoin的Gas計算相關的邏輯,分享一下吧。本文分析的是0.5.6的邏輯,Lotus程式碼的最後一個提交資訊如下:commit 606a58bc6bc035ec0b90c6b50488e29e90f4238fAuthor: Aayush Rajasekaran <admin@chaindaily>Date:   Sat Aug 29 00:56:24 2020 -0400  Lotus version 0.5.6Lotus程式碼的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_000const BlockGasTarget = BlockGasLimit / 2
const BaseFeeMaxChangeDenom = 8 // 12.5%const InitialBaseFee = 100e6const MinimumBaseFee = 100const PackingEfficiencyNum = 4const 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):

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會被燃燒。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;