EIP-1559 引入了动态的基本费用机制,取代了传统的 gas 竞价模式,大大提高了以太坊交易费用预测的准确性和透明度。用户设置最高费用和小费,协议根据网络拥堵自动调整基本费用,并销毁一部分 ETH,从而优化了用户体验,提高了费用的稳定性。文章还提供了使用 Go 语言在 Polygon Amoy 测试网上构建和广播 EIP-1559 动态费用交易的示例。
在访问列表交易之后,以太坊演进的下一个主要里程碑是 EIP-1559,它在 伦敦硬分叉 期间被引入。
这个提案完全重新设计了以太坊的费用市场,使 gas 定价更具可预测性和透明度,解决了旧的 第一价格拍卖**模型效率低下的问题,在旧模型中,用户必须猜测足够高的
gasPrice才能被包含在区块中。EIP-1559 交易(类型
0x02)用两个字段替换了单个gasPrice:maxFeePerGas和maxPriorityFeePerGas。加上一个由 协议定义的 base fee,它在每个区块动态调整,这个模型平滑了费用波动并改善了用户体验。base fee 被销毁,减少了 ETH 供应,而只有小费(优先级费用)会给到验证者。
在本文中,我们将:
1. 了解动态 base fee 机制是如何工作的。
2. 使用
eth_feeHistoryRPC 来估算实际的 gas 费用。3. 在 Polygon Amoy 测试网上用 Go 构建和广播一个 EIP-1559 动态费用交易。
到最后,你将看到 EIP-1559 是如何引入一个更公平、更稳定和可持续的费用机制的,该机制现在为所有现代的以太坊兼容网络提供动力。
类型为 0x2 的交易在 EIP-1559 中被引入,在以太坊的伦敦硬分叉期间被激活。这次升级重新设计了以太坊的费用市场,使交易成本更具可预测性,并解决了传统“第一价格拍卖”模型的低效率问题,在该模型中,用户通过竞标 gasPrice 进行竞争,而矿工选择支付最高的交易。
EIP-1559 交易不再指定单个 gasPrice,而是使用一个 动态 base fee,它由协议在每个区块进行调整,具体取决于网络拥塞情况。这个 base fee 会被 销毁,从流通中移除 ETH。
交易和 RLP 编码看起来像这样:
0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s])
{
nonce: "0x0", // 在此之前,发送者发起的交易数量。
gasLimit: "0x2710", // 发送者提供的最大 gas 量。
maxPriorityFeePerGas: "0x0", // 发送者愿意为每个 gas 支付的高于 base fee 的最高费用,单位为 wei。
maxFeePerGas: "0x6f4d3132b", // 发送者愿意为每个 gas 支付的最高总费用(base fee + 优先级费用),单位为 wei。
to: "0x...", // 接收者的地址。在合约创建交易中不使用。
value: "0x0", // 转移的价值,单位为 wei。
data: "0x...", // 用于定义合约创建和交互。
yParity: "0x1" // secp256k1 签名中 y 值的奇偶性。
r: "0x...", // ECDSA 签名 r。
s: "0x...", // ECDSA 签名 s。
chainId: "0x...", // 交易的链 ID。
accessList: [], // 交易计划访问的地址和存储键的列表。
}
新的交易结构和新的费用字段
以太坊现在协议中内置了一个 每 gas 的 base fee。此费用会根据前一个区块的满状态自动从一个区块更改为另一个区块:
此费用有助于调节需求,并且会被 销毁(销毁),而不是支付给验证者。
当用户发送交易时,他们设置:
priority fee)来支付给验证者,以将其 tx 包含你的交易总是支付它进入的区块的 base fee,并且它支付小费,只要:
base fee + tip ≤ max fee
否则交易将被拒绝。
有几种可能的方法来计算 base_fee_per_gas,但我们主要对 eth_feeHistory 方法感兴趣,这将使我们清楚地了解最新区块中的费用行为。
curl -X POST https://polygon-amoy.drpc.org \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"eth_feeHistory",
"params": ["0x05", "latest", []],
"id":1
}' | jq
注意 :第一个参数
0x05是我们想要回溯的区块数量,我们可以最多获取 1024 个区块。为了示例起见,我们将只查看最新的 5 个区块
响应将如下所示:
{
"id": 1,
"jsonrpc": "2.0",
"result": {
"oldestBlock": "0x46d5609",
"baseFeePerGas": ["0x1205","0x11f3","0x1214","0x1233","0x121b","0x121d"],
"gasUsedRatio": [0.3687491333333333,0.7324738666666667,0.7207432,0.3332721777777778,0.5188374666666666],
....
}
}
当使用 5 个区块的计数调用 eth_feeHistory 时,你将收到:
baseFeePerGas 中的 6 个值:前 5 个 对应于 最近的 5 个区块,第 6 个 是 下一个区块的预测 base fee。
gasUsedRatio 中的 5 个值:每个值都显示了最近一个区块的满状态(0 = 空,1 = 满)。
从上面的例子中我们了解到:
0x121d)。package main
const (
// Polygon Amoy 测试网的公共 RPC URL
NodeRPCURL = "https://polygon-amoy.drpc.org"
AmoyChainID = 80002 // Polygon Amoy 测试网链 ID
)
func main() {
acc2Addr, acc2Priv := account.GetAccount(2)
to := lo.ToPtr(common.HexToAddress("0x0fd9e8d3af1aaee056eb9e802c3a762a667b1904"))
ctx := context.Background()
client, err := ethclient.Dial(NodeRPCURL)
if err != nil {
log.Fatal("Failed to connect to Ethereum node:", err)
}
nonce, err := client.PendingNonceAt(ctx, lo.FromPtr(acc2Addr))
if err != nil {
log.Fatal("Failed to fetch nonce:", err)
}
feeHistory, err := client.FeeHistory(ctx, 5, nil, nil)
if err != nil {
log.Fatal("Failed to fetch gas price:", err)
}
GasTipCap, err := client.SuggestGasTipCap(ctx)
if err != nil {
log.Fatal("Failed to fetch gas price:", err)
}
// 来自最新区块的 base fee
latestBaseFee := feeHistory.BaseFee[len(feeHistory.BaseFee)-1]
// GasFeeCap = baseFee + tip
// 向最新的 base fee 添加 12% 的缓冲区以避免定价过低
// 但你也可以使用费用历史记录中的平均值或中位数。
bufferedBaseFee := new(big.Int).Mul(latestBaseFee, big.NewInt(112))
bufferedBaseFee.Div(bufferedBaseFee, big.NewInt(100))
// 最终 GasFeeCap = bufferedBaseFee + GasTipCap
GasFeeCap := new(big.Int).Add(bufferedBaseFee, GasTipCap)
chainID := big.NewInt(AmoyChainID) // 使用你链的 ID(80002 = Polygon Mumbai 测试网)
gasLimit, err := client.EstimateGas(ctx, ethereum.CallMsg{
From: *acc2Addr,
To: to,
Data: common.FromHex("0xa9059cbb0000000000000000000000008056361b1c1361436D61D187d761233b42d1c20e000000000000000000000000000000000000000000000000016345785D8A0000"),
})
if err != nil {
log.Fatal("Failed to fetch gas limit:", err)
}
tx := types.DynamicFeeTx{
ChainID: chainID,
Nonce: nonce,
GasTipCap: GasTipCap,
GasFeeCap: GasFeeCap,
Gas: gasLimit,
To: to,
Data: common.FromHex("0xa9059cbb0000000000000000000000008056361b1c1361436D61D187d761233b42d1c20e000000000000000000000000000000000000000000000000016345785D8A0000"),
}
// 将其转换为完整的 types.Transaction 对象
eip1559Tx := types.NewTx(&tx)
signedTx, err := types.SignTx(eip1559Tx, types.LatestSignerForChainID(chainID), acc2Priv)
if err != nil {
log.Fatal("Failed to sign transaction:", err)
}
// 广播交易
err = client.SendTransaction(ctx, signedTx)
if err != nil {
log.Fatal("Broadcast failed:", err)
}
fmt.Println("Transaction sent!")
fmt.Println("Tx hash:", signedTx.Hash().Hex())
// 可选地等待包含
time.Sleep(10 * time.Second)
receipt, err := client.TransactionReceipt(ctx, signedTx.Hash())
if err != nil {
fmt.Println("Tx not mined yet.")
} else {
fmt.Println("Tx mined in block:", receipt.BlockNumber)
}
}
我们会得到:
按 Enter 键或单击以全尺寸查看图像

我们可以看到我们的估计是完美的,并且我们的交易已成功挖掘。
EIP-1559 通过用自动适应网络需求的 动态 base fee 替换手动 gas 竞标,从而改变了以太坊的交易模型。
用户现在指定一个 最大费用 和一个可选的 小费,而协议确保了可预测的定价并销毁 base fee,以随着时间的推移减少 ETH 供应。
此升级不仅改善了用户体验和费用稳定性,而且还引入了一种可持续的销毁机制,该机制将网络活动直接与 ETH 的稀缺性联系起来。
EIP-1559 交易(类型 0x02)现在是大多数现代 EVM 链上的标准,构成了以太坊伦敦后费用市场的支柱。
- 原文链接: medium.com/@andrey_obruc...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!