____tz_zs 2021-11-24 15:27:47 草稿
随着2021 年 8 月的伦敦升级,eth链交易费用的计算方式发生了变化。
一、EIP-1559 gas策略参数
EIP-1559
新规范的参数不同于旧的gas策略,它不再需要gasPrice
字段,而是使用maxFeePerGas/maxPriorityFeePerGas
的组合(type 为可选,会根据交易参数隐式设置类型),如下:
{'chainId': 1, 'nonce': 6, 'gas': 159000, 'maxFeePerGas': 231834409218, 'maxPriorityFeePerGas': 2000000000, 'type': 2}
包含的gasPrice
的方式现在被标记为LEGACY
并且仍然有效。但是,您可以预期它们比EIP-1559
方式的消耗gas更多。使用gasPrice
和maxFeePerGas/maxPriorityFeePerGas
组合的事务将引发错误。
以下分别为两种方式在eth浏览器上的情况:
二、maxFeePerGas/maxPriorityFeePerGas 的生成
def generate_gas_price_EIP1559(self):
"""
EIP-1559 标准的Gas Estimator 推荐 Max Fee = (2 * Base Fee) + Max Priority Fee
maxFeePerGas 和 baseFeePerGas+maxPriorityFeePerGas 之间的差额将退还给用户。
"""
baseFeePerGas = self.w3.eth.getBlock("pending").baseFeePerGas # 即时的base,只用于预估的,最后不一定是这个值,所以一般计算max时会乘以一个系数2。
if isinstance(baseFeePerGas, str):
baseFeePerGas = int(baseFeePerGas, 16)
maxPriorityFeePerGas = self.to_wei(self.__maxPriorityFeePerGas, "gwei") # 支付给矿工的那部分费用,一般为2gwei,2000000000
maxFeePerGas = baseFeePerGas * self.__max_base_fee_multiplier + maxPriorityFeePerGas # 最多愿意支付
... ...
三、注意web3py版本
旧版本的web3py并未支持或存在一些bug。
v5.21.0 使用存在问题
EIP1559 Send Transaction require to include the field: gasPrice #2071
v5.21.0 (2021-07-12) 版本增加了EIP 1559的支持
v5.21.0 (2021-07-12) 添加对 EIP 1559 交易密钥的支持。
Merge bulk of London support to master #2060
支持maxFeePerGas和maxPriorityFeePerGas加入,主要是sendTransactionRPC调用以及内部replace_transaction和modify_transaction方法。
v5.22.0 (2021-08-02) 版本
v5.22.0 (2021-08-02)
eth_signTransaction 支持 eip-1559 参数“maxFeePerGas”和“maxPriorityFeePerGas”(#2082)
Update eth-account version & add eip-1559 eth_signTransaction support #2082
更新 eth-account 版本并添加 eip-1559 eth_signTransaction 支持。
将 eth-account 版本更新为最新版本,其中包括 eip-1559 支持。添加了集成测试并进行了小幅调整以支持 eth_signTransaction 的 eip-1559 参数
四、旧的gas策略的影响
如果有使用过以往的gas策略和中间件,例如设置里下面这种gas策略(中间件 Gas Price Strategy、Gas Price API)。则使用 EIP-1559 规范时会受影响。
def set_gas_price_strategy(self, price_strategy_version="自定义"):
"""
设置gas价格策略
:param price_strategy_version:
:return:
"""
"""
https://web3py.readthedocs.io/en/stable/gas_price.html#gas-price-api
即用型版本:
web3.gas_strategies.time_based.fast_gas_price_strategy:交易在 60 秒内开采。
web3.gas_strategies.time_based.medium_gas_price_strategy: 交易在 5 分钟内开采。
web3.gas_strategies.time_based.slow_gas_price_strategy: 交易在 1 小时内开采。
web3.gas_strategies.time_based.glacial_gas_price_strategy: 交易在 24 小时内开采。
"""
# 生成价格策略:即 GasPriceStrategy 对象
if price_strategy_version == "fast":
price_strategy = web3.gas_strategies.time_based.fast_gas_price_strategy
elif price_strategy_version == "medium":
price_strategy = web3.gas_strategies.time_based.medium_gas_price_strategy # 120个区块,线下跑时阻塞了110秒
elif price_strategy_version == "slow":
price_strategy = web3.gas_strategies.time_based.slow_gas_price_strategy
elif price_strategy_version == "glacial":
price_strategy = web3.gas_strategies.time_based.glacial_gas_price_strategy
else:
# 自定义
price_strategy = web3.gas_strategies.time_based.construct_time_based_gas_price_strategy( # 10个区块,线下跑时阻塞了10秒
max_wait_seconds=60, # 交易所需的最大秒数。
sample_size=10, # 要采样的最近的块的数量
probability=98, # 交易将在 max_wait_seconds 内挖掘的所需概率的整数。0 表示 0%,100 表示 100%。
# weighted=True # 时间加权到最近开采的块上。在某些计算机上(pgq)无法时间加权。
)
self.w3.eth.setGasPriceStrategy(price_strategy)
# 使用缓存解决方案来减少每个请求需要重新获取的链数据量。
self.w3.middleware_onion.add(middleware.time_based_cache_middleware)
self.w3.middleware_onion.add(middleware.latest_block_based_cache_middleware)
self.w3.middleware_onion.add(middleware.simple_cache_middleware)
def generate_gas_price(self, tx_params):
"""
计算gas价格
:param tx_params: 交易参数
:return: gas_price (单位:wei)
"""
# 使用预设的gas价格策略,会阻塞。有点久!!!!
gas_price = self.w3.eth.generateGasPrice(tx_params) # 使用预设的gas价格策略,会阻塞(单位:wei)
... ...
因为在调用buildTransaction
函数编码交易函数时,自动添加了gasPrice字段。如下:
{'value': 0, 'gasPrice': 106315430605, 'chainId': 1, 'nonce': 4, 'gas': 159000, 'maxFeePerGas': 189631675486, 'maxPriorityFeePerGas': 2000000000, 'type': 2, 'to': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', 'data': '0x8803dbee0000000000000000000000000000000000000000000003310023da6b781c00000000000000000000000000000000000000000000000000000dd446f061fdd71200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000002597609bb2578c1bb3c241c4ba5095376b4a61a40000000000000000000000000000000000000000000000000000000061994eca0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009a0aba393aac4dfbff4333b06c407458002c6183'}
正常情况:
{'value': 0, 'chainId': 1, 'nonce': 4, 'gas': 159000, 'maxFeePerGas': 185928191006, 'maxPriorityFeePerGas': 2000000000, 'type': 2, 'to': '0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D', 'data': '0x8803dbee0000000000000000000000000000000000000000000003310023da6b781c00000000000000000000000000000000000000000000000000000dd446f061fdd71200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000002597609bb2578c1bb3c241c4ba5095376b4a61a400000000000000000000000000000000000000000000000000000000619953060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000009a0aba393aac4dfbff4333b06c407458002c6183'}
data字段:
data: bytes or text - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI.
在签名(w3.eth.account.signTransaction
)时会报错:TypeError: Unknown kwargs: [‘gasPrice’],因为 EIP-1559 规范使用maxFeePerGas
和maxPriorityFeePerGas
而不是gasPrice
字段,同时使用是会造成歧义的。
五、其他bug
1、max fee per gas less than block base fee
ValueError: {'code': -32000, 'message': 'err: max fee per gas less than block base fee: address 0x0000000000000000000000000000000000000000, maxFeePerGas: 120469458894 baseFee: 147438523185 (supplied gas 14995852)'}
旧的gas策略可能会低于区块最小的base价格参数,旧策略要么给很大的gasPrice
,但这样会付出很多的额外的gas。
2、TypeError: Transaction must not include unrecognized fields: {'maxFeePerGas', 'maxPriorityFeePerGas'}
TypeError: Transaction must not include unrecognized fields: {'maxFeePerGas', 'maxPriorityFeePerGas'}
web3py版本太旧了,不支持。
六、参考
Docs web3.eth API
web3py 版本发布
Sending transactions after London Fork considering EIP 1559
fix: eip1559 validation incorrectly adds gas price field #2099
Web3.py in London
GAS AND FEES