Featured image of post EVM上的GAS分析

EVM上的GAS分析

在区块链领域,Gas(燃料费) 是用来衡量和支付在网络上执行操作(如交易或智能合约)所需计算资源的一种机制。 它是防止网络滥用和资源浪费的关键组成部分,尤其在以太坊(Ethereum)中最为常见。

# 一、Gas的核心概念

术语 含义
Gas 执行某个操作所需的“单位计算资源”。
Gas Price(Gas价格) 用户愿意为每单位Gas支付多少“币”(如Gwei)。
Gas Limit 用户愿意为某笔交易最多支付多少Gas(防止无限消耗)。
Gas Used 实际执行中消耗的Gas数量。

# 二、对某笔交易进行分析

交易截图

观察上面该笔交易, 可以发现程序能够决定的值有:

  • GasLimit: gas使用量限制
  • GasFeeMax: 每gas的价格限制
  • MaxPriority: 支付给矿工的费用

这三个数据对应到DynamicFeeTx类型字段分别为:

  • GasLimit -> Gas
  • GasFeeMax -> GasFeeCap
  • MaxPriority -> GasTipCap

# 程序如何决定这三个值的合理值呢?

# GasLimit

一般转账固定21000,如果是合约调用,则使用EstimateGas估算limit, 下面是使用EstimateGas的示例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 这是以太坊主网的RPC地址
client, _ := ethclient.DialContext(ctx, "https://mainnet.infura.io/v3/b6bf7d3508c941499b10025c0776eaf8")
gasLimit, _ := client.EstimateGas(ctx, ethereum.CallMsg{
    From:      publicKey,
    To:        &toAddr,
    GasFeeCap: feeCap,
    GasTipCap: tipCap,
    Value:     value,
    Data:      data,
})
# MaxPriority

矿工费用可以使用SuggestGasTipCap进行动态估算:

1
2
3
// 这是以太坊主网的RPC地址
client, _ := ethclient.DialContext(ctx, "https://mainnet.infura.io/v3/b6bf7d3508c941499b10025c0776eaf8")
maxPriority, _ := client.SuggestGasTipCap(ctx)
# GasFeeMax

每gas的单价限制可以使用和MetaMusk(小狐狸)钱包的计算公式:

基础费用 * 1.25 + 矿工费用(gasFeeBase * 1.25) + gasFeeMaxPriority,

示例代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func main() {
    // 这是以太坊主网的RPC地址
    client, _ := ethclient.DialContext(ctx, "https://mainnet.infura.io/v3/b6bf7d3508c941499b10025c0776eaf8")
    // 获取基础费用()
    header, _ := client.HeaderByNumber(ctx, nil)
    baseFee := header.BaseFee
    // 获取tipCap
    tipCap, _ := client.SuggestGasTipCap(ctx)
    feeCap := FeeCapCalc(baseFee, tipCap)
}

// FeeCapCalc 计算FeeCap
func FeeCapCalc(baseFee, tipCap *big.Int) *big.Int {
    multiplier := big.NewFloat(1.25)
    feeCapF := new(big.Float).Add(new(big.Float).SetInt(baseFee), multiplier)
    feeCapF.Add(feeCapF, new(big.Float).SetInt(tipCap))
    feeCap, _ := feeCapF.Int(nil)
    return feeCap
}

实际交易的时候,gasPrice的值是根据链上实时的基础费用 + 设定的矿工费用来决定, 如果超过了feeCap(基础费用是动态的),交易可能会处于pending状态直到链上base+tip降低到feeCap或以下, 交易才会被成功打包。

# 三、如何理解三方工具的实时GAS价格呢?

gasnow

使用三方工具查看GAS的实时价格推荐使用gasnow, 不推荐CoinTool的GAS实现查看面板, 最大优先费用不准确.

可以看到上面比较醒目的数字即为基础费用(gasFeeBase), 在通过代码进行转账, 如果要让代码在基础费用过高的情况下停止工作, 则可以使用baseFee来控制, 下面是示例代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
func main() {
    client, _ := ethclient.DialContext(ctx, "https://mainnet.infura.io/v3/b6bf7d3508c941499b10025c0776eaf8")
    // 获取baseFee
    header, _ := client.HeaderByNumber(ctx, nil)
    baseFee := header.BaseFee
    if baseFee.Cmp(evmutils.EtherInt64(1)) >= 0 { // 当网络基础费用超过1Gwei时不进行工作
        return kerr.WrapTraceStack(
            fmt.Errorf("当前网络基础费用过大, 可以换个时间再重试. 基础费用: %s",
                baseFee.String(),
            ),
        )
    }
	// do something...
}