首页 > 教程攻略 > web3.0 >解读以太坊即将到来的硬分叉 Pectra 升级

解读以太坊即将到来的硬分叉 Pectra 升级

来源:互联网 时间:2026-07-28 11:42:32

以太坊从 PoW 转向 PoS 的历程并不简单。最早是在现有执行层上叠加了信标链——信标链运行权益证明共识,而执行层暂时保留工作量证明(这就是 Phase0 和 Altair 两次硬分叉做的事)。之后 Bellatrix 硬分叉正式激活了 PoS(不过当时还不能提款)。紧接着 Capella 硬分叉打开了提款通道,验证者的生命周期才算完整。再往后是 Deneb,作为 Dencun(Deneb + Cancun)升级的一部分,它对信标链的参数做了小调整,比如见证消息的时间窗口、自愿退出的处理、验证者轮换的限制等。而 Dencun 真正的重头戏在执行层:引入了 blob 交易、blob gas、用于 blob 的 KZG 承诺,并废弃了 SELFDESTRUCT 操作码。

现在轮到 Prague/Electra,也就是大家常说的 Pectra 硬分叉,它给执行层和共识层都带来了不少改动。我们作为 Lido 项目的审计方,自然会特别关注其中与共识和质押相关的部分。不过 Prague 这边的执行层变化也不能忽略——有些特性会影响到以太坊整个网络,包括验证者本身。下面咱们一个一个来看。

Pectra 到底改了些什么?

Electra 为信标层带来了好几个新功能。主要变化包括:

  • 验证者的有效余额不再锁死在 32 ETH,而是可以在 32 到 2048 ETH 之间浮动。

  • 验证者现在能用另一组“提款”凭证来发起退出,不再非得用活跃验证者的密钥。

  • 信标层处理 Eth1 存款的方式变了——不再从存款合约里解析事件。

  • 新增了一个通用框架,用于处理从常规 Eth1 合约发来的请求(类似之前处理存款的方式)。

与此同时,Prague 给执行层带来了这些改动:

  • 新增一个预编译合约,支持 BLS12-381 曲线,用来验证 zkSNARK 证明(之前只能用 BN254)。

  • 新增一个系统合约,可以存储并查询最多 8192 个历史区块哈希(对无状态客户端来说很实用)。

  • 提高了 calldata 的 gas 成本,目的是限制区块大小,鼓励那些大量使用 calldata 的项目(比如 rollup)改用 Dencun 引入的 blob。

  • 每个 Eth1 区块允许包含更多 blob,同时提供了读取这些数量的 API。

  • 外部账户(EOA)终于可以拥有自己的代码了,这意味着 EOA 能做更多事,比如一次调用多个合约、把执行权委托给其他地址等。

下面我们把相关的以太坊改进提案(EIP)列出来,方便对照着讨论:

  • EIP-7251: 提高最大有效余额(MAX_EFFECTIVE_BALANCE)

  • EIP-7002: 执行层可触发的退出

  • EIP-6110: 链上提供验证者存款

  • EIP-7549: 将委员会索引移出证明

  • EIP-7685: 通用执行层请求

  • EIP-2537: BLS12-381 曲线操作的预编译

  • EIP-2935: 在状态中保存历史区块哈希

  • EIP-7623: 增加 calldata 成本

  • EIP-7691: blob 吞吐量增加

  • EIP-7840: 向 EL 配置文件添加 blob 调度

  • EIP-7702: 设置 EOA 账户代码

这些 EIP 有些只涉及共识(信标)层,有些只涉及执行层,还有几个是跨层的——比如存款和提款,需要共识层和执行层同步修改。正因为这种互相依赖的关系,把 Electra 和 Prague 拆开讲其实不太现实。所以我们打算按照每个 EIP 的顺序逐一说明,同时标注它影响的是以太坊的哪一部分。

EIP-7251: 提高最大有效余额

参考: EIP-7251

从 Phase0 开始,为了准备权益证明,验证者的最大有效余额一直固定在 32 ETH。激活验证者至少需要 32 ETH(spec.min_activation_balance)。激活后验证者会从这个最大值起步,但有效余额可以逐渐降到 16 ETH(spec.ejection_balance),一旦跌破这个数就会被强制退出。Electra 保留了“最低余额”的逻辑,但把最大有效余额的上限提到了 2048 ETH。也就是说,你现在可以存 32 到 2048 ETH 来激活一个验证者,这些钱都会算进有效余额里。这可以说是从“32 ETH 权益证明”真正走向了“权益证明”。

改动后的有效余额会直接影响三件事:

  • 成为区块提议者的概率——和有效余额成正比。

  • 成为同步委员会成员的概率——也是正比。

  • 计算削削减和不活跃惩罚的基准。

前两项是验证者最赚钱的活。所以在 Electra 之后,大户验证者会按自己的有效余额比例,更频繁地拿到区块提议和同步委员会的机会。

另一个影响跟削减有关。所有罚款都跟有效余额挂钩:

  • “立即”和“延迟”的削减惩罚,对质押多的验证者来说更重。

  • 如果被削减的是个大户,那么“延迟”削减里其他人的损失也会变大——因为总质押中被削减的比例更高了。

  • 举报大户违规的人,能拿到更大比例的罚款。

Electra 还改了削减比例的计算方式,明确了罚款中多少归举报者。

然后是离线惩罚。当验证者没能及时做见证或提议时,会积累不活跃分数,每个周期都会挨罚。这个惩罚同样和有效余额成正比。

由于有效余额上限提高了,验证者的“更换限制”也跟着变了。在 Electra 之前,所有验证者的有效余额一样,退出上限是“每个周期最多不能有总质押的 1/65536(spec.churn_limit_quotient)退出”。这个数字是固定的。但 Electra 之后,如果几个大户同时退出,他们一个人就可能占掉总质押的很大一块。

还有一个问题是多个验证者密钥的轮换。以前大户不得不在一台服务器上跑几千个验证者密钥,把大额质押拆成无数个 32 ETH 的小份。Electra 之后没必要这么干了。从财务角度看,其实收益差不多——因为奖励和概率都是线性增长的。100 个各质押 32 ETH 的验证者,跟一个质押 3200 ETH 的验证者效果一样。而且多个活跃验证者可以共用同一个 Eth1 提款凭证,这样所有奖励都能提到同一个 ETH 地址,省掉合并奖励所需的 gas 费。不过管理大量密钥本身也有成本。

能合并验证者余额这件事,还带来了一种新的执行层请求类型。以前只有存款和提款,现在多了一个:合并请求。这个请求会把两个验证者变成一个。操作时会包含源验证者的公钥和目标公钥,处理方式和存款、提款差不多。合并请求也有待处理队列和更换限制。

总结一下:

  • 对于小型独立验证者:Electra 允许有效余额(以及对应奖励)自动增长。以前超出 32 ETH 的部分只能提出来,现在这些盈余最终会变成有效余额。不过增长是按 1 ETH 为一个台阶(spec.effective_balance_increment)进行的,只有余额跨过下一个“1 ETH 门槛”时才生效。

  • 对于大型独立验证者:Electra 让你可以把多个活跃验证者密钥合并成一个,管理起来轻松很多。虽然不至于碘伏游戏规则,但经营 1 个 2048 ETH 的验证者,肯定比管理 64 个 32 ETH 的验证者省心。

  • 对于流动性质押提供商:它们平时从用户那里收小额质押,再分配到各个验证者上。Electra 增加了分配方案的灵活性,但也要求它们彻底重构基于固定 32 ETH 有效余额的会计系统。

还有一个值得新手关注的点:历史数据和利润估算。在 Electra 之前,32 ETH 的上限让所有验证者的数据非常整齐——有效余额、奖励、削减处罚、提议频率都一样。这种均匀性帮助以太坊在没有统计异常的情况下测试共识机制,积累了宝贵的网络行为数据。

但 Electra 之后,质押分布会变得很不均匀。大户在提议和同步委员会中会更活跃,被削减时损失更大,对延迟削减、激活队列和退出队列的影响也更明显。这虽然给数据聚合带来了难度,但以太坊的共识机制保证了非线性计算部分很小。唯一涉及平方根的地方是计算基础奖励(sqrt(total_effective_balance)),而且它对所有验证者一视同仁。换句话说,验证者的奖励和惩罚仍然可以按“每 1 ETH”来大致估算(更准确地说,是按 spec.effective_balance_increment 这个最小单位,未来可能会变)。

更多细节可以参考我们之前写的关于验证者行为的文章。

EIP-7002:执行层可触发的退出

参考:EIP-7002

每个以太坊验证者都有两套密钥:一套是活跃密钥,一套是提款密钥。活跃的公钥(BLS 类型)是验证者在信标链上的主要身份,用来签名区块、见证消息、削减提议、同步委员会聚合,以及(在这个 EIP 之前)发起自愿退出。提款凭证可以是另一个 BLS 密钥对,也可以是普通的 Eth1 账户。现在如果你想提到 ETH 地址,需要一条由活跃 BLS 私钥签名的提款消息。这个 EIP 改变了现状。

实际上,这两套密钥的主人可能是不同的人。活跃密钥负责跑节点、保持在线;提款凭证通常归质押所有者管,他们收奖励、看资金。问题是,目前控制提款凭证的人没法自己发起验证者退出,只能提取奖励。这意味着活跃密钥的持有者可以拿验证者的余额当“人质”。虽然可以通过“预签名”退出消息来解决,但毕竟不是长久之计。而且现在的提款和退出都要通过专门的 API 跟信标层交互,挺麻烦的。

最好的办法是让质押所有者能直接通过普通智能合约调用同时完成退出和提款。这样只需要标准的 Eth1 签名检查,操作简单很多。

这个 EIP 允许质押所有者从自己的 ETH 地址往一个专用的智能合约发一笔普通交易,就能触发提款和退出(有点类似之前用“存款”合约存钱的过程)。具体流程如下:

  • 质押者向“提款”合约发送提款请求(可以理解为“进去”的请求)。

  • 合约会收一点 ETH 作为手续费(防止有人恶意刷请求),同时如果请求队列太长,手续费会像 EIP-1559 那样自动涨。

  • 合约把“进去”的提款/退出请求存在自己的存储里。

  • 当某个区块被提议到信标层时,合约会把队列里的“进去”请求取出来。

  • 信标层处理这些“进去”请求,跟验证者的余额交互,安排退出,然后生成“出来”的提款请求。

  • “出来”的请求在执行层处理,质押者收到自己的 ETH。

以前存款是在 Eth1 区块里触发,然后通过“待处理”存款队列“移动”到信标层。提款则是反过来:在信标层触发(通过命令行),然后“移动”到 Eth1 区块。现在两种操作都统一走同一个通用框架(下面会讲):在 Eth1 层创建请求,处理“待处理”存款/提款/合并队列,然后在信标层去处理。对于像提款这样的“输出”操作,还会处理输出队列,最终在 Eth1 区块里“结算”。

有了这个 EIP,质押者用普通的 ETH 交易就能提款并退出,再也不需要直接跟验证者的命令行交互,也不用管验证者的基础设施。这大大简化了质押操作,尤其是对大型质押提供商来说。验证者的基础设施可以几乎完全隔离——只要维护好活跃密钥就行了,所有质押操作可以在别处处理。独立质押者也不用再等着活跃验证者配合了,像 Lido 的 Community Staking Module 这样的服务,链外部分也会简化不少。

可以说,这个 EIP 把质押操作彻底“做完”了——全部迁移到了 Eth1 层,大大降低了基础设施安全风险,也让独立质押变得更容易去中心化。

EIP-6110:链上验证者存款

参考:EIP-6110

目前的存款流程是通过系统“存款”合约里的事件来完成的(之前的文章讲过细节)。合约接收 ETH 和验证者凭证,发出 Deposit() 事件,然后这些事件被解析,转换成信标层上的存款请求。这个系统有很多缺点:它要求信标链层对 eth1data 进行投票,导致明显的延迟。而且信标层还得查询执行层,增加了复杂度。这些问题在 EIP 原文里有详细讨论。一个更简单的办法,是不用处理这么多麻烦,直接在 Eth1 区块的指定位置包含存款请求。这个机制跟上面 EIP-7002 里描述的提款处理流程很相似。

这个 EIP 提出的改动很有前景。eth1data 的处理可以完全去掉,不再需要投票,也不用等很长时间(当前大约要等 12 小时)。同时也去掉了存款合约快照的逻辑。这个 EIP 让存款处理变得简单,并且跟提款处理方案保持一致。

对质押者和验证者来说,这些改动显著缩短了从存款到激活之间的等待时间。如果验证者被削减了,补充资金的过程也会更快。

关于这个 EIP 没有太多好说的,它就是清除过时的逻辑,简化流程,让所有参与者都受益。

EIP-7685:通用执行层请求

参考:EIP-7685

这个 EIP 其实应该放在前面三个跟存款/提款/合并相关的 EIP 之前讲,因为它为它们打下了基础。不过放在这里提出来,是为了强调一个日益增长的需求:在 Eth1(执行层)和信标(共识层)区块之间高效地转移专用数据。这个 EIP 影响两个层,让通过普通 ETH 交易触发的请求处理效率更高。目前我们看到:

  • Eth1 区块里的存款事件被“移动”到信标块处理。

  • 信标块里的提款请求(通过命令行)被“移动”到 Eth1 块处理。

  • 验证者合并也需要处理,这也是 Eth1→信标的请求。

这三件事表明,在执行层和信标层之间来回传递各种类型的请求时,需要一致的处理方式。而且我们希望能只用 Eth1 层就能触发这些操作——这样就能把验证者的基础设施和质押管理基础设施隔离开,提高安全性。所以搞一个通用的解决方案既实际又必要。

这个 EIP 为至少三种主要场景建立了框架:存款、提款和合并。这也是为什么前面的 EIP 引入了像 WITHDRAWAL_REQUEST_TYPE 和 DEPOSIT_REQUEST_TYPE 这样的字段,现在合并会再增加一个字段:CONSOLIDATION_REQUEST_TYPE。另外,这个 EIP 还可能包含处理这类请求的限制机制(参考常量:PENDING_DEPOSITS_LIMIT、PENDING_PARTIAL_WITHDRAWALS_LIMIT、PENDING_CONSOLIDATIONS_LIMIT)。

虽然具体的实现细节还没完全公布,但肯定包括关键请求类型、完整性机制(比如哈希和默克尔化请求),以及待处理队列的处理和速率限制。

这个 EIP 有架构上的意义——它让 Eth1 通过一个统一框架就能触发信标层里的关键操作。对普通用户和项目方来说,这意味着所有在 Eth1 层触发的请求,都能在信标层上更高效地传递和处理。

EIP-2537:BLS12-381 曲线操作的预编译

参考:EIP-2537

如果你不想深究细节,可以简单把 BLS12-381 的预编译理解成一种复杂的加密“哈希”操作,现在可以在智能合约里用了。感兴趣的话,我们再往下聊聊。

对椭圆曲线(比如 BLS12-381 和它的前辈 BN-254)做数学运算,目前主要用于两个地方:

  • BLS 签名——用“配对”这个特殊操作来验证签名。BLS 签名被验证者广泛使用,因为它能把多个签名聚合成一个。验证者依赖的是基于 BLS12-381 曲线的 BLS 签名(当然也可以用其他支持配对的曲线,比如 BN254)。

  • zkSNARK 证明的验证——配对用来验证证明。另外,Dencun 引入的 KZG 承诺也用了配对来验证 blob 承诺。

如果你想在智能合约里验证 BLS 签名或 zkSNARK 证明,就得算这些“配对”,计算量非常巨大。以太坊之前已经有了一个针对 BN254 曲线操作的预编译合约(EIP-196 和 EIP-197)。但 BLS12-381 曲线(现在被认为更安全,也更常用)还没有对应的预编译。没有它,在智能合约里实现配对和其他曲线操作,计算量会大得惊人(可以参考这里的例子),耗 gas 可能高达 10^5 到 10^6。

这个 EIP 为很多潜在应用打开了大门,尤其是基于 BLS12-381 曲线的低成本 BLS 签名验证。这样一来,很多门限方案都能实现。就像前面说的,以太坊验证者已经在用基于 BLS12-381 的签名。有了这个 EIP,普通的智能合约也能高效地验证聚合后的验证者签名。这可以简化共识证明和跨链资产桥接——因为 BLS 签名在区块链里用得非常多。门限 BLS 签名本身也能用来构建各种高效的投票、去中心化随机数生成、多签等方案。

更便宜的 zkSNARK 证明验证,反过来会解锁一大批应用。很多基于 zkSNARK 的方案过去因为证明验证成本太高,几乎没法实际落地。这个 EIP 有潜力改变这一局面。

EIP-2935:在状态中保存历史区块哈希

参考:EIP-2935

这个 EIP 提议把 8192 个历史区块哈希(大约 27.3 小时)保存在区块链状态里,为无状态客户端(比如 rollup)和智能合约提供更长的历史查询能力。它建议保留 BLOCKHASH 操作码现在的行为,也就是只能查最近 256 个区块,同时引入一个专门用来存储和检索历史哈希的新系统合约。这个合约在执行层处理区块时会执行 set() 操作。它的 get() 方法对所有人开放,可以从环形缓冲区里取出需要的区块哈希。

目前,在 EVM 里引用历史区块哈希是可行的,但只能查最近 256 个区块(大约 50 分钟)。然而有些场景需要访问更早的区块数据——比如跨链应用(需要证明之前区块的数据)和无状态客户端(需要定期访问早期区块哈希)。

这个 EIP 扩展了 rollup 和跨链应用能查到的时间范围,让它们可以直接在 EVM 里访问历史数据,不用再到外面去收集。这些方案因此变得更稳健、更可持续。

EIP-7623:增加 calldata 成本

参考:EIP-7623

calldata 的成本决定了交易能带多少有效负载。在某些情况下,负载可能很大(比如传一个大数组或二进制缓冲区)。大量使用 calldata 的主要是 rollup——它们把当前 rollup 状态用的 calldata 塞进交易里。

把大量可验证的二进制数据送上链,对 rollup 来说至关重要。Dencun(Deneb-Cancun)升级为此类用例引入了一项重要创新——blob 交易(EIP-4844)。blob 交易有自己的“blob gas”费用,主体数据是临时存储的,但它们的加密证明(KZG 承诺)和哈希会被整合到共识层。所以跟用 calldata 存数据相比,blob 对 rollup 来说是更好的方案。

要想让 rollup 把数据迁移到 blob 上,可以用“胡萝卜加大棒”的策略。降低的 blob gas 费用是“胡萝卜”,而这个 EIP 通过提高 calldata 成本来当“大棒”,抑制交易里的过度数据存储。它跟下一个 EIP-7691(增加 blob 吞吐量)是互补的——后者提高了每个区块允许的 blob 数量上限。

EIP-7691:blob 吞吐量增加

参考:EIP-7691

Dencun 硬分叉刚引入 blob 时,每个区块的目标数量和最大数量都设得比较保守。因为很难预测 P2P 网络能不能处理好大型二进制对象在验证者节点之间的传播。之前的配置运行良好,现在时机成熟,可以试试新数值了。之前每个区块的目标/最大 blob 数量是 3 和 6。现在分别提高到了 6 和 9。

结合前面的 EIP-7623(提高 calldata 成本),这个调整进一步促使 rollup 把数据从 calldata 挪到 blob 上。寻找最佳 blob 参数的工作还在继续。

EIP-7840:将 blob 调度添加到 EL 配置文件

参考:EIP-7840

这个 EIP 提议把每个区块的目标和最大 blob 数量(上面讨论过的)以及 baseFeeUpdateFraction 值都加入到以太坊执行层(EL)的配置文件中。同时让客户端可以通过节点 API 查到这些值。这个功能对于估算 blob gas 费用之类的任务特别有用。

EIP-7702:设置 EOA 账户代码

参考:EIP-7702

这是一个非常重要的 EIP,会给以太坊用户带来重大变化。大家都知道,外部账户(EOA)不能有代码,只能提供交易签名(tx.origin)。而智能合约有字节码,但不能主动发起“它自己”的直接签名。任何需要额外自动化、可验证逻辑的用户交互,目前都只能通过调一个外部合约来完成。但这样一来,那个外部合约就成了后续合约的 msg.sender,导致调用变成了“来自合约的调用,而不是用户”。

这个 EIP 引入了一种新的交易类型 SET_CODE_TX_TYPE=0x04(之前我们有旧的 0x1 交易、柏林和 EIP-1559 升级带来的 0x02 交易、以及 Dencun 引入的 0x03 blob 交易)。这种新交易类型允许给 EOA 账户设置代码。换句话说,它让 EOA 可以在“自己账户的上下文”里执行外部代码。从外部看,交易期间 EOA 好像“借用”了外部合约的代码并执行。技术上,这是通过在 EOA 地址的“代码”存储里添加特殊的授权数据元组来实现的(在此之前,EOA 的“代码”存储一直是空的)。

目前这个 EIP 提议的 0x04 交易类型包含一个数组:

authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...]

每个元素允许账户使用来自指定地址的代码(取自最后一个有效的授权项)。处理这类交易时,会把给定 EOA 的代码设置成特殊的 0xef0100 || 地址值(23 字节),其中地址指向存有目标代码的合约,|| 表示连接,0xef0100 是一个常规智能合约不能包含的特殊魔法值(根据 EIP-3541)。这个魔法值确保这个 EOA 不会被当成普通合约,也不能像普通合约一样被调用。

当这个 EOA 发起交易时,指定的地址会被用来在该 EOA 的上下文中调用相应的代码。具体的实现细节还不完全清楚,但可以确定这会带来重大变化。

一个主要影响是:现在可以直接从 EOA 发起多重调用(multicall)。多重调用是 DeFi 的一个趋势,很多协议都把它作为强大的工具(比如 Uniswap V4、Balancer V3、Euler V2)。有了这个 EIP,直接从 EOA 发起多重调用不再是问题。

举个例子,这个新特性解决了 DeFi 里一个很常见的问题:approve() + anything() 需要两笔独立的交易,效率很低。有了这个 EIP,就能实现通用的“预授权”逻辑,比如 approve(X) + deposit(X) 可以在单笔交易里完成。

能“代表” EOA 委托交易执行的另一个优势是赞助交易。赞助这个概念经常被讨论,且被很多人期待——它可以帮助新用户轻松进入以太坊。

跟 EOA 关联的可编程逻辑解锁了很多可能性,比如实施安全限制、设置支出上限、强制 KYC 要求等等。

当然,这个转变也带来了很多设计问题。一个是 chain_id 的使用——它决定了同一个签名能不能在多个网络之间通用,取决于签名中包含不包含 chain_id。另一个复杂点是使用目标代码的地址和直接嵌入实际字节码之间的选择。这两种方法各有特点,也有局限性。nonce 的使用在定义权限是“多用途”还是“单次用途”上也起了关键作用。这些元素会影响功能和安全,包括批量失效签名、易用性等方面。Vitalik 在一次讨论中(这里)提到了这些问题,值得进一步研究。

值得注意的是,这个变化会影响以太坊的一个安全机制:tx.origin。目前 require(tx.origin == msg.sender) 是判断 msg.sender 是否为 EOA 而非合约的最可靠方法。其他方法(比如检查 EXTCODESIZE)通常不太靠谱,可以被绕过(比如通过构造函数调用或在交易后往预定义地址部署代码)。这些检查被用来防止重入攻击和闪电贷攻击,但并不理想,因为它们也阻碍了跟外部协议的集成。在这个 EIP 之后,即使是可靠的 require(tx.origin == msg.sender) 检查似乎也要过时了。协议必须通过移除这些检查来适应——因为“EOA”和“合约”之间的界限将不再那么分明:现在每个地址都可能有关联的代码。

传统的 EOA 和智能合约的分离越来越模糊。这个 EIP 让以太坊更接近像 TON 那样的设计——每个账户本质上都是一段可执行代码。随着跟协议的交互变得越来越复杂,用可编程逻辑来改善最终用户体验,是这条演进之路上的自然一步。

相关下载