在提案1559之前,出块获得基础奖励费和gasprice*gasused的手续费
https://blockchair.com/ethereum/blocks
gas功能:
在以太坊进行任何操作都需要消耗 gas,每个区块的 gas 空间有限。 这包括计算、储存或操作数据,或转移代币,每种消耗不同数量的“gas”单位。简而言之,Gas 费用有助于确保以太坊网络安全。 在网络上执行的每次计算都需要收费,这样可以防止参与者对网络造成垃圾信息。 为了防止代码中无意、恶意的无限循环或其他计算浪费,要求每个事务对代码可以执行的计算步骤设置一个限制。
存在的问题:
随着 dapp 功能变得更加复杂,智能合约执行的操作数量也会增加。即每个交易在有限大小区块内占用更多空间。 如果需求太大,用户必须提供更高的小费来尝试超越其他用户的出价。 小费更高即更有可能让你的交易进入下一区块。
- 为避免全节点趋于集中,追求架构去中心化的区块链会严格限制区块容量。例如比特币的 Size Limit (隔离见证下4MB)以及以太坊的 Gas Limit。当交易需求超过区块容量,需要一种机制公平地分配稀缺资源,常见的方式是让用户以交易费的形式进行竞价。矿工会优先将交易费高的交易纳入区块。
- 然而,限量和竞价模式也引发了一些问题。由于用户对于其他用户的出价一无所知,只能依靠历史交易费进行猜测。当网络发生拥堵,交易费上升,部分用户为了及时发出交易,只能给出更高价格,从而快速推升交易费率,直到某个临界点,费率又掉头向下。
- 交易费剧烈波动造成两个问题:一是用户支付了过高的交易费,历史数据显示,由竞价导致的用户多支付的交易费高达 5 倍;二是很多交易依旧不能按用户预期的时限成交。
basefee=(gasused*basefee_per_gas)
在2021年8月5日12965000的伦敦升级中,迎来以太坊伦敦硬分叉升级,EIP1559大幅降低交易费总额和交易费波动性。
提案1559 针对以上问题对交易费机制进行优化。首先把目前的区块 Gas Limit 提高一倍,并将 Gas 费用分为了两部分,一部分每笔交易必须支付的、根据上一区块的基础费和区块资源利用率计算的「基本费率」(Base fee),另一部分则是由用户选择性支付的「优先费率」(Priority fee)。目的是通过彻底改造以太坊的交易费用机制,使用户更容易预测以太坊的交易费用。 这一升级带来的更高一层的收益包括更好地估算交易费,通常会加快纳入交易,并通过燃烧一定比例的交易费来抵消发行。
交易总费用的计算用如下所示:Gas 单位 (GasLimit) * (基本费用 + 小费)
此外,还可以为交易设定最高费用 (maxFeePergas)。 最高费用与实际收费之间的差额将归还给 发起人。如: 退款 = 最高费用 - (基本费用 + 优先费)。 可以为执行交易费用设定一个最高金额,而不必担心在执行交易时“超额”支付基本费用
- 伦敦升级在以太坊中引入了大小可变区块。 每个区块的目标大小为 1500 万 gas[gasTarget],但区块的大小将根据网络需求增减。最多到 3000 万 gas 的区块限制【gasLimit】(目标区块大小的 2 倍)。 该协议通过 tâtonnement 的过程使区块大小平均达到 1,500 万。 这意味着如果区块大小超出目标区块大小,协议将增加以下区块的基本费用。 同样,如果区块大小低于目标区块大小,协议将减少基本费用。 基本费用的调整金额与当前区块大小和目标区块大小的差距是成比例。每个块的基础费改变不超过 1/8。用户是无法调节基础费率的,同时这些基础费将会被网络永久销毁。基础费在新机制中起交易税作用,每笔交易都需要缴纳。交易税不奖励给矿工,而是被烧掉,受益者是全体 ETH 持有者。
- 基本费用的计算公式是将上一个区块的gas大小(gasUsed)与目标大小(1500万)进行比较。 如果超过目标区块大小,区块的基本费用将最多增加 12.5%。 这种指数级增长使得区块大小无限期保持高位在经济上不可行。basefee=(gasused*basefee_per_gas)
- 随着新的基本费被燃烧,伦敦升级引入了优先费 (小费),以激励矿工将交易纳入区块。 如果没有小费,矿工会发现开采空区块在经济上可行,因为他们会获得相同的区块奖励。 在常规情况下,一笔金额不大的小费给矿工提供了包含该交易的最低激励。 对于需要在同一区块中优先执行的交易,需要更高的小费来试图出价高于竞争交易。优先费的作用是补偿矿工因把交易纳入区块所增加的叔块风险。同时,对于希望交易能够尽快入块被执行的用户来说,他们可以通过设置高额优先费的方式以确保交易马上被收录。
- 最高费用。要在网络上执行交易,用户可以为他们愿意支付的交易执行费指定最高限额。 此可选参数称为 maxFeePergas。 为了执行交易,最高费用必须超过基本费用和小费的总和。 会为交易发送人退还最高费用与基本费用和小费总和之间的差额。
- 在伦敦升级中执行 EIP-1559 使得交易费机制比以前的 gas 竞价招标更加复杂,但优点是提高 gas 费用的可预测性,从而使交易费市场更加有效。 用户可以在提交交易时设定 maxFeePergas,表示他们愿意为执行交易支付多少费用,同时清楚该数额不会超过 gas 的市场价格 (BaseFeePergas),并且获得减去小费后的剩余退款。
用户对于交易的时效性需求可以分为三类。
第一类是希望交易被尽快收录,但并不特别紧急。
第二类是要求交易被立即收录,并且愿意为此付高价。
第三类是没有时效要求,只要交易最终成功即可。
在新的费用机制下:
- 第一类交易只需按预估的基础费和常规的小费付费,通常都能达到目的。
- 第二类需求的用户可以设置很高的小费,以确保交易马上被收录。
- 第三类用户可以将设置自己愿意接受的交易费上限,耐心等待网络空闲、基础费回落后交易成功。
可见,三类需求都能够得到很好地满足。大多数用户(第一类)无需深入了解交易费机制,只需按照钱包的估计付费,就能得到最优费率和预期的结果,这无疑将提升以太坊的用户体验。
新机制下用户可设置两个参数:交易费上限 (fee_cap) 和小费(tips)。当基础费低于用户设置的交易费上限,交易费被收录,用户支付基础费加小费。当基础费高于交易费上限时,交易在 mempool 中等待。可以预期,EIP1559 的实施将大幅降低以太坊交易费总额和交易费波动性。
INITIAL_BASE_FEE = 1000000000
INITIAL_FORK_BLOCK_NUMBER = 10 # TBD
BASE_FEE_MAX_CHANGE_DENOMINATOR = 8
ELASTICITY_MULTIPLIER = 2
class World(ABC):
def validate_block(self, block: Block) -> None:
parent_gas_target = self.parent(block).gas_limit // ELASTICITY_MULTIPLIER
parent_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.
if INITIAL_FORK_BLOCK_NUMBER == block.number:
parent_gas_target = self.parent(block).gas_limit
parent_gas_limit = self.parent(block).gas_limit * ELASTICITY_MULTIPLIER
parent_base_fee_per_gas = self.parent(block).base_fee_per_gas
parent_gas_used = self.parent(block).gas_used
transactions = self.transactions(block)
# check if the block used too much gas
assert block.gas_used <= block.gas_limit, 'invalid block: too much gas used'
# check if the block changed the gas limit too much
assert block.gas_limit < parent_gas_limit + parent_gas_limit // 1024, 'invalid block: gas limit increased too much'
assert block.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
assert block.gas_limit >= 5000
# check if the base fee is correct
if INITIAL_FORK_BLOCK_NUMBER == block.number:
expected_base_fee_per_gas = INITIAL_BASE_FEE
elif parent_gas_used == parent_gas_target:
expected_base_fee_per_gas = parent_base_fee_per_gas
elif parent_gas_used > parent_gas_target:
gas_used_delta = parent_gas_used - parent_gas_target
base_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_delta
else:
gas_used_delta = parent_gas_target - parent_gas_used
base_fee_per_gas_delta = parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR
expected_base_fee_per_gas = parent_base_fee_per_gas - base_fee_per_gas_delta
assert expected_base_fee_per_gas == block.base_fee_per_gas, 'invalid block: base fee not correct'
# execute transactions and do gas accounting
cumulative_transaction_gas_used = 0
for unnormalized_transaction in transactions:
# 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
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.amount
assert signer.balance >= 0, 'invalid transaction: signer does not have enough ETH to cover attached value'
# the signer must be able to afford the transaction
assert signer.balance >= transaction.gas_limit * transaction.max_fee_per_gas
# ensure that the user was willing to at least pay the base fee
assert transaction.max_fee_per_gas >= block.base_fee_per_gas
# Prevent impossibly large numbers
assert transaction.max_fee_per_gas < 2**256
# Prevent impossibly large numbers
assert transaction.max_priority_fee_per_gas < 2**256
# The total must be the larger of the two
assert transaction.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_gas
signer.balance -= transaction.gas_limit * effective_gas_price
assert signer.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_used
cumulative_transaction_gas_used += gas_used
# signer gets refunded for unused 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
assert cumulative_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: validate the rest of the block
新的机制下,当前区块头信息如下:

根据区块中的gaslimit和basefee,结合上述源码,进行计算当前区块中交易消耗的gas费用

以太坊伦敦升级引入EIP1559,改革交易费用机制,旨在降低费用总额和波动性。交易费用现由基础费和优先费组成,基础费根据网络需求动态调整并被烧掉,优先费作为矿工奖励。用户可通过设置最高费用和小费来控制交易成本,提高了费用预测性和交易效率。新机制满足不同用户对交易时效性的需求,优化了用户体验。

被折叠的 条评论
为什么被折叠?



