【web3py】 gas 新规范 EIP-1559,对 LEGACY 版本的影响以及bug总结

____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更多。使用gasPricemaxFeePerGas/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 StrategyGas 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 规范使用maxFeePerGasmaxPriorityFeePerGas而不是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

猜你喜欢

转载自blog.csdn.net/tz_zs/article/details/121449037
gas
今日推荐