协议中存在一个基础 gas 费用,该费用可以根据公式在每个区块中上下浮动,该公式是父区块中使用的 gas 和父区块的 gas 目标(区块 gas 限制除以弹性乘数)的函数。
该算法导致当区块高于 gas 目标时,每 gas 的基础费用增加,而当区块低于 gas 目标时,每 gas 的基础费用减少。
每 gas 的基础费用会被销毁。
交易指定他们愿意支付给矿工的最大每 gas 费用,以激励他们包括该交易(又名:优先级费用)。
交易还指定他们愿意支付的总的最大每 gas 费用(又名:最大费用),其中包括优先级费用和区块的网络Gas费每gas (又名:基础费用)。
发送者将始终支付其交易被包含的区块的每 gas 基础费用,并且他们将支付交易中设置的每 gas 优先级费用,只要两个费用的总金额不超过交易的最大每 gas 费用。
该 EIP 中的提案是从一个基础费用金额开始,该金额由协议根据网络的拥塞程度进行上下调整。当网络超过每个区块的 gas 使用目标时,基础费用略有增加;当容量低于目标时,基础费用略有减少。由于这些基础费用变更受到限制,因此区块之间基础费用的最大差异是可以预测的。这使得钱包能够以高度可靠的方式为用户自动设置 gas 费用。预计即使在高网络活动期间,大多数用户也不必手动调整 gas 费用。对于大多数用户来说,基础费用将由他们的钱包估算,并自动设置一个小的优先级费用,以补偿矿工承担的孤儿风险(例如 1 nanoeth)。用户还可以手动设置交易最大费用以限制其总成本。
此费用系统的一个重要方面是矿工只能保留优先级费用。基础费用始终被烧毁(即,它被协议销毁)。这确保了只有 ETH 才能用于支付以太坊上的交易费用,从而巩固了 ETH 在以太坊平台中的经济价值,并降低了与矿工可提取价值 (MEV) 相关的风险。此外,这种销毁抵消了以太坊的通货膨胀,同时仍然为矿工提供了区块奖励和优先级费用。最后,确保区块的矿工没有收到基础费用非常重要,因为它消除了矿工操纵费用以从用户那里提取更多费用的动机。
fromtypingimportUnion,Dict,Sequence,List,Tuple,Literalfromdataclassesimportdataclass,fieldfromabcimportABC,abstractmethod@dataclassclassTransactionLegacy:signer_nonce:int=0gas_price:int=0gas_limit:int=0destination:int=0amount:int=0payload:bytes=bytes()v:int=0r:int=0s:int=0@dataclassclassTransaction2930Payload:chain_id:int=0signer_nonce:int=0gas_price:int=0gas_limit:int=0destination:int=0amount:int=0payload:bytes=bytes()access_list:List[Tuple[int,List[int]]]=field(default_factory=list)signature_y_parity:bool=Falsesignature_r:int=0signature_s:int=0@dataclassclassTransaction2930Envelope:type:Literal[1]=1payload:Transaction2930Payload=Transaction2930Payload()@dataclassclassTransaction1559Payload:chain_id:int=0signer_nonce:int=0max_priority_fee_per_gas:int=0max_fee_per_gas:int=0gas_limit:int=0destination:int=0amount:int=0payload:bytes=bytes()access_list:List[Tuple[int,List[int]]]=field(default_factory=list)signature_y_parity:bool=Falsesignature_r:int=0signature_s:int=0@dataclassclassTransaction1559Envelope:type:Literal[2]=2payload:Transaction1559Payload=Transaction1559Payload()Transaction2718=Union[Transaction1559Envelope,Transaction2930Envelope]Transaction=Union[TransactionLegacy,Transaction2718]@dataclassclassNormalizedTransaction:signer_address:int=0signer_nonce:int=0max_priority_fee_per_gas:int=0max_fee_per_gas:int=0gas_limit:int=0destination:int=0amount:int=0payload:bytes=bytes()access_list:List[Tuple[int,List[int]]]=field(default_factory=list)@dataclassclassBlock:parent_hash:int=0uncle_hashes:Sequence[int]=field(default_factory=list)author:int=0state_root:int=0transaction_root:int=0transaction_receipt_root:int=0logs_bloom:int=0difficulty:int=0number:int=0gas_limit:int=0# note the gas_limit is the gas_target * ELASTICITY_MULTIPLIER
gas_used:int=0timestamp:int=0extra_data:bytes=bytes()proof_of_work:int=0nonce:int=0base_fee_per_gas:int=0@dataclassclassAccount:address:int=0nonce:int=0balance:int=0storage_root:int=0code_hash:int=0INITIAL_BASE_FEE=1000000000INITIAL_FORK_BLOCK_NUMBER=10# TBD
BASE_FEE_MAX_CHANGE_DENOMINATOR=8ELASTICITY_MULTIPLIER=2classWorld(ABC):defvalidate_block(self,block:Block)->None:parent_gas_target=self.parent(block).gas_limit//ELASTICITY_MULTIPLIERparent_gas_limit=self.parent(block).gas_limit# on the fork block, don't account for the ELASTICITY_MULTIPLIER to avoid
# unduly halving the gas target.
# 在分叉区块上,不要考虑 ELASTICITY_MULTIPLIER,以避免不适当地将 gas 目标减半。
ifINITIAL_FORK_BLOCK_NUMBER==block.number:parent_gas_target=self.parent(block).gas_limitparent_gas_limit=self.parent(block).gas_limit*ELASTICITY_MULTIPLIERparent_base_fee_per_gas=self.parent(block).base_fee_per_gasparent_gas_used=self.parent(block).gas_usedtransactions=self.transactions(block)# check if the block used too much gas
# 检查区块是否使用了过多的 gas
assertblock.gas_used<=block.gas_limit,'invalid block: too much gas used'# check if the block changed the gas limit too much
# 检查区块是否过度更改了 gas 限制
assertblock.gas_limit<parent_gas_limit+parent_gas_limit//1024,'invalid block: gas limit increased too much'assertblock.gas_limit>parent_gas_limit-parent_gas_limit//1024,'invalid block: gas limit decreased too much'# check if the gas limit is at least the minimum gas limit
# 检查 gas 限制是否至少为最小 gas 限制
assertblock.gas_limit>=5000# check if the base fee is correct
# 检查基础费用是否正确
ifINITIAL_FORK_BLOCK_NUMBER==block.number:expected_base_fee_per_gas=INITIAL_BASE_FEEelifparent_gas_used==parent_gas_target:expected_base_fee_per_gas=parent_base_fee_per_gaselifparent_gas_used>parent_gas_target:gas_used_delta=parent_gas_used-parent_gas_targetbase_fee_per_gas_delta=max(parent_base_fee_per_gas*gas_used_delta//parent_gas_target//BASE_FEE_MAX_CHANGE_DENOMINATOR,1)expected_base_fee_per_gas=parent_base_fee_per_gas+base_fee_per_gas_deltaelse:gas_used_delta=parent_gas_target-parent_gas_usedbase_fee_per_gas_delta=parent_base_fee_per_gas*gas_used_delta//parent_gas_target//BASE_FEE_MAX_CHANGE_DENOMINATORexpected_base_fee_per_gas=parent_base_fee_per_gas-base_fee_per_gas_deltaassertexpected_base_fee_per_gas==block.base_fee_per_gas,'invalid block: base fee not correct'# execute transactions and do gas accounting
# 执行交易并进行 gas 记账
cumulative_transaction_gas_used=0forunnormalized_transactionintransactions:# Note: this validates transaction signature and chain ID which must happen before we normalize below since normalized transactions don't include signature or chain ID
# 注意:这会验证交易签名和链 ID,这必须在我们下面规范化之前发生,因为规范化的交易不包括签名或链 ID
signer_address=self.validate_and_recover_signer_address(unnormalized_transaction)transaction=self.normalize_transaction(unnormalized_transaction,signer_address)signer=self.account(signer_address)signer.balance-=transaction.amountassertsigner.balance>=0,'invalid transaction: signer does not have enough ETH to cover attached value'# the signer must be able to afford the transaction
# 签名者必须能够负担得起交易
assertsigner.balance>=transaction.gas_limit*transaction.max_fee_per_gas# ensure that the user was willing to at least pay the base fee
# 确保用户愿意至少支付基础费用
asserttransaction.max_fee_per_gas>=block.base_fee_per_gas# Prevent impossibly large numbers
# 防止出现不可能的大数字
asserttransaction.max_fee_per_gas<2**256# Prevent impossibly large numbers
# 防止出现不可能的大数字
asserttransaction.max_priority_fee_per_gas<2**256# The total must be the larger of the two
# 总数必须是两者中较大的一个
asserttransaction.max_fee_per_gas>=transaction.max_priority_fee_per_gas# priority fee is capped because the base fee is filled first
# 优先级费用被限制,因为首先填充基础费用
priority_fee_per_gas=min(transaction.max_priority_fee_per_gas,transaction.max_fee_per_gas-block.base_fee_per_gas)# signer pays both the priority fee and the base fee
# 签名者支付优先级费用和基础费用
effective_gas_price=priority_fee_per_gas+block.base_fee_per_gassigner.balance-=transaction.gas_limit*effective_gas_priceassertsigner.balance>=0,'invalid transaction: signer does not have enough ETH to cover gas'gas_used=self.execute_transaction(transaction,effective_gas_price)gas_refund=transaction.gas_limit-gas_usedcumulative_transaction_gas_used+=gas_used# signer gets refunded for unused gas
# 签名者获得未使用的 gas 退款
signer.balance+=gas_refund*effective_gas_price# miner only receives the priority fee; note that the base fee is not given to anyone (it is burned)
# 矿工只收到优先级费用;请注意,基础费用不给任何人(它被烧毁)
self.account(block.author).balance+=gas_used*priority_fee_per_gas# check if the block spent too much gas transactions
# 检查区块是否在 gas 交易上花费过多
assertcumulative_transaction_gas_used==block.gas_used,'invalid block: gas_used does not equal total gas used in all transactions'# TODO: verify account balances match block's account balances (via state root comparison)
# TODO: 验证帐户余额与区块的帐户余额匹配(通过状态根比较)
# TODO: validate the rest of the block
# TODO:验证区块的其余部分
defnormalize_transaction(self,transaction:Transaction,signer_address:int)->NormalizedTransaction:# legacy transactions
# 传统交易
ifisinstance(transaction,TransactionLegacy):returnNormalizedTransaction(signer_address=signer_address,signer_nonce=transaction.signer_nonce,gas_limit=transaction.gas_limit,max_priority_fee_per_gas=transaction.gas_price,max_fee_per_gas=transaction.gas_price,destination=transaction.destination,amount=transaction.amount,payload=transaction.payload,access_list=[],)# 2930 transactions
# 2930 交易
elifisinstance(transaction,Transaction2930Envelope):returnNormalizedTransaction(signer_address=signer_address,signer_nonce=transaction.payload.signer_nonce,gas_limit=transaction.payload.gas_limit,max_priority_fee_per_gas=transaction.payload.gas_price,max_fee_per_gas=transaction.payload.gas_price,destination=transaction.payload.destination,amount=transaction.payload.amount,payload=transaction.payload.payload,access_list=transaction.payload.access_list,)# 1559 transactions
# 1559 交易
elifisinstance(transaction,Transaction1559Envelope):returnNormalizedTransaction(signer_address=signer_address,signer_nonce=transaction.payload.signer_nonce,gas_limit=transaction.payload.gas_limit,max_priority_fee_per_gas=transaction.payload.max_priority_fee_per_gas,max_fee_per_gas=transaction.payload.max_fee_per_gas,destination=transaction.payload.destination,amount=transaction.payload.amount,payload=transaction.payload.payload,access_list=transaction.payload.access_list,)else:raiseException('invalid transaction: unexpected number of items')@abstractmethoddefparent(self,block:Block)->Block:pass@abstractmethoddefblock_hash(self,block:Block)->int:pass@abstractmethoddeftransactions(self,block:Block)->Sequence[Transaction]:pass# effective_gas_price is the value returned by the GASPRICE (0x3a) opcode
# effective_gas_price 是 GASPRICE (0x3a) 操作码返回的值
@abstractmethoddefexecute_transaction(self,transaction:NormalizedTransaction,effective_gas_price:int)->int:pass@abstractmethoddefvalidate_and_recover_signer_address(self,transaction:Transaction)->int:pass@abstractmethoddefaccount(self,address:int)->Account:pass
由于大多数人没有竞争优先级费用,而是使用基线费用来包含,因此交易排序现在取决于各个客户端的内部实现细节,例如它们如何将交易存储在内存中。建议具有相同优先级费用的交易按收到交易的时间排序,以保护网络免受垃圾邮件攻击,攻击者将一堆交易扔到待处理池中,以确保至少有一个交易落在有利的位置。纯粹从自私的挖掘角度来看,矿工仍然应该更喜欢 gas 溢价较高的交易,而不是 gas 溢价较低的交易。
通过燃烧基础费用,我们不再能保证固定的以太币供应。这可能会导致经济不稳定,因为 ETH 的长期供应量将不再随时间推移而保持不变。虽然这是一个有效的担忧,但很难量化这将产生多大的影响。如果燃烧的基础费用多于在挖掘奖励中产生的,那么 ETH 将是通货紧缩的;如果在挖掘奖励中产生的多于燃烧的,那么 ETH 将是通货膨胀的。由于我们无法控制用户对区块空间的需求,因此我们目前无法断言 ETH 最终会是通货膨胀还是通货紧缩,因此这种变化导致核心开发人员失去对以太币长期数量的控制权。
Vitalik Buterin (@vbuterin), Eric Conner (@econoar), Rick Dudley (@AFDudley), Matthew Slipper (@mslipper), Ian Norden (@i-norden), Abdelhamid Bakhta (@abdelhamidbakhta), "EIP-1559: ETH 1.0 链的费用市场变更," Ethereum Improvement Proposals, no. 1559, April 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1559.