EIP-7956: 通过区块级随机性实现交易排序
通过强制使用区块级随机性进行确定性交易排序来减少 MEV 攻击。
Authors | Aryaethn (@aryaethn) |
---|---|
Created | 2025-05-24 |
Discussion Link | https://ethereum-magicians.org/t/potential-eip-mev-decrease-by-deterministic-transaction-ordering-via-block-level-randomness/24084 |
Table of Contents
摘要
提议者和构建者目前可以任意排列待处理的交易,从而实现由重新排序驱动的 MEV。本 EIP 引入了一个共识规则,通过将每个交易哈希与新的 slot 随机性进行异或运算来对区块内的所有交易进行排序。该随机性在 slot 开始之前是未知的,因此一旦已知顺序就是确定性的,但事先是无法预测的。该机制显著减少了基于重新排序的 MEV;基于延迟的回溯、审查和其他类型的 MEV 仍然存在,应该通过互补技术(加密 mempool、声誉、PBS 市场等)来缓解。
动机
不受限制的排序是三明治攻击和经典抢先交易攻击的关键因素。确定性排序将这些向量简化为延迟竞争和信息不对称。清晰的候选集和捆绑包语义保留了费用市场,同时消除了对可信排序器的需求。学术研究表明,确定性排序会将三明治利润推向零。
参考
-
Julia Ofoegbu,“最大可提取价值 (MEV):一个与时间一样古老的故事”,Medium (2024)。
-
J. Qian et al., “无需可信排序器的确定性交易排序”,arXiv:2411.03327 v1 (2024)。
-
“Shutter Network 推出了在以太坊上第一个加密 Mempool 的计划”,GlobeNewswire,2025 年 2 月 13 日。
规范
本文档中的关键词“必须 (MUST)”,“禁止 (MUST NOT)”,“必需 (REQUIRED)”,“应该 (SHALL)”,“不应该 (SHALL NOT)”,“推荐 (SHOULD)”,“不推荐 (SHOULD NOT)”,“可以 (MAY)”和“可选 (OPTIONAL)”按照 RFC 2119 和 RFC 8174 中的描述进行解释。
Slot 随机性 R
共识层先决条件 — 需要配套 EIP“
EL‑VRF‑exposure
”将 RANDAO 的每个 slot 的 VRF 输出添加到执行层。
<– TODO – 添加配套 EIP “EL‑VRF‑exposure
” –>
R = randao_mix_slot[0:16] : bytes16
执行负载包括 randomness: bytes16
,它必须等于 R
;执行客户端通过 EIP‑4788 进行验证。
构建者流程
- 候选集选择 – 构建者可以根据优先级费用、附带协议或策略选择 mempool 的任何子集。未选择的交易将被忽略。
- 规范排序 – 按主键
H(tx) ⊕ R
升序,然后按辅助键H(tx)
升序对所选集合进行排序,以防主键发生冲突。 - Gas 限制打包 – 按顺序追加项目,直到添加下一个项目将超过区块 gas 限制。
- 捆绑包(可选的跨地址原子性)
- 定义 – 捆绑包是用户签名的完全签名的交易列表。每个
child_tx_rlp
是规范的签名 RLP 编码,包括签名字段(v, r, s)
。捆绑包以一个 费用支付 交易开始,该交易涵盖整个捆绑包的 gas 费用和构建者小费。 -
哈希/排序键 – 将捆绑包视为一个 虚拟交易,其键为
H(concat(child_tx_rlps))
,其中:child_tx_rlps[i]
必须是稍后将出现在该交易的区块 body 中的确切字节,即 EIP‑2718 / EIP‑155 规则规定的 完全签名的交易的规范 RLP(对于类型化交易,包括前导 类型字节 和长度前缀)。- 实现不得剥离或规范化签名字段
(v,r,s)
;这 65 个字节按原样进行哈希处理,因此每个参与者都派生出一个相同的捆绑包键。 - 连接顺序是作者声明的子交易的执行顺序。
- Gas 消耗核算 – 捆绑包 gas 是所有子交易的
gasLimit
字段的总和。构建者在评估步骤 3 时使用该总和。 - Fit‑or‑skip 规则 – 如果捆绑包(费用支付 + 子交易)将超过剩余 gas 限制,则将原子地跳过该捆绑包。
- 费用动态 – 优先级费用会影响候选集中的成员资格(步骤 1),但一旦选择了交易或捆绑包,永远不会覆盖规范顺序。
以下是上述流程的伪代码:
//---------------------------------------------------------------------
// Inputs
//---------------------------------------------------------------------
// mempool : 构建者可见的所有待处理交易和用户签名的捆绑包
// R : 共识层提供的 16 字节 slot 随机性
// BLOCK_GAS_LIMIT : 区块中允许的最大 gas
//---------------------------------------------------------------------
// Helper functions
//---------------------------------------------------------------------
function HASH(obj) → bytes32 // 字节序列的 Keccak-256
function PRIMARY_KEY(h, R) → bytes32 // h XOR R (按位)
function bundleGas(bundle): // 子交易的 gasLimit 之和
total ← 0
for childTx in bundle.children:
total ← total + childTx.gasLimit
return total
//---------------------------------------------------------------------
// 0. 候选集选择 (构建者策略 / 附带协议 / 费用过滤器)
//---------------------------------------------------------------------
candidates ← pickSubsetFrom(mempool) // 允许任何子集
//---------------------------------------------------------------------
// 1. 计算每个候选对象的规范键和 gas 开销
//---------------------------------------------------------------------
for item in candidates:
if item.type == "single_tx":
item.gasCost ← item.gasLimit
baseHash ← HASH(item.RLP) // 规范签名 RLP (EIP-2718)
else if item.type == "bundle":
concatRlps ← CONCAT(item.child_rlps) // 费用交易 + 作者顺序的子交易
item.gasCost ← bundleGas(item)
baseHash ← HASH(concatRlps)
item.primaryKey ← PRIMARY_KEY(baseHash, R)
item.secondaryKey ← baseHash
//---------------------------------------------------------------------
// 2. 规范排序 (primaryKey 升序,然后 secondaryKey 升序)
//---------------------------------------------------------------------
sort(candidates, by = (primaryKey ASC, secondaryKey ASC))
//---------------------------------------------------------------------
// 3. 具有 fit-or-skip 的 Gas 限制打包,用于捆绑包
//---------------------------------------------------------------------
blockList ← 空列表
gasUsed ← 0
for item in candidates:
if gasUsed + item.gasCost > BLOCK_GAS_LIMIT:
continue // 原子地跳过整个交易或捆绑包
append(blockList, item)
gasUsed ← gasUsed + item.gasCost
//---------------------------------------------------------------------
// 4. 输出 — 组装区块 body 和 header 字段
//---------------------------------------------------------------------
block.randomness ← R // payload header 中的 bytes16
block.txOrderingVersion ← 1
block.body ← flatten(blockList) // 捆绑包分解为子交易
return block
共识规则
如果执行的列表偏离从其 randomness
和包含的交易/捆绑包派生的规范顺序,则区块无效。验证是客观的;分叉选择保持不变。
性能
在今天的硬件上,排序 ≤ 1 500 笔交易仍然是 O(n log n)
(< 1 毫秒)。
部署
添加的参数
randomness
: 在规范中指定。txOrderingVersion = 1
标志:为了与现有的共识规则兼容,并为将来需要的规则添加兼容性。
分叉参数
- ‘ORDERING_FORK_EPOCH’: 信标链 epoch,执行客户端在该 epoch 开始识别新字段
randomness
和txOrderingVersion
。 ORDERING_TRANSITION_EPOCHS
窗口激活规则:64 个 epoch(约 13.6 小时)。在转换窗口期间,接受具有任一排序版本的区块的转换窗口的长度。
这两个参数都是分叉配置中的常量,可以在测试网实验期间进行调整。
激活流程
-
共识层升级 —
ORDERING_FORK_EPOCH
处的信标链分叉激活EL‑VRF‑exposure
(配套 EIP)并开始填充vrf_output_proposer
字段。在此 epoch 之后接收ExecutePayload
的执行客户端需要一个非零randomness
字段。 -
执行层握手 — 构建者和提议者在 Engine API
engine_newPayloadV3
调用中包含新的randomness
和txOrderingVersion
字段。未升级的旧节点将拒绝该 payload,从而导致自然链分裂和升级的经济激励。 -
转换窗口 — 对于
ORDERING_FORK_EPOCH
之后的ORDERING_TRANSITION_EPOCHS
,客户端接受:
-
版本 0 区块 —
txOrderingVersion
== 0;没有随机性;旧排序。 -
版本 1 区块 —
txOrderingVersion
== 1;有效的随机性;强制执行规范排序。在此期间,鼓励(但不是强制)提议者采用版本 1,以便费用市场和 MEV 供应链有时间进行调整。
- 最终确定 — 在
ORDERING_FORK_EPOCH
+ORDERING_TRANSITION_EPOCHS
,共识规则发生变化:区块必须设置txOrderingVersion == 1
并通过规范顺序验证。此后的版本 0 区块被视为无效,并且不会被分叉选择考虑。
理由
为什么是随机性驱动的排序?
-
客观且可验证 – 使用链上随机性 (R) 的函数和交易自身的哈希,为每个验证者提供了一个相同的,廉价的顺序有效性检查。
-
在 Slot 开始之前不可预测 – slot 级 RANDAO 和提议者的 VRF 输出的 XOR 确保用户和构建者都无法在 slot 开始之前知道最终的排序键,从而关闭了经典的抢先交易窗口。
-
最小表面积 – 执行 payload 中的单个 16 字节字段加上哈希操作可使共识更改保持较小且可审核。
为什么是 128 位 R 而不是完整的 256 位?
-
对于每个区块 ≤10k 笔交易,128 位已经远远超出了抗碰撞的需求。
-
在暴力攻击在天文数字上不可行的情况下,将 payload 大小减半会略微降低区块传播成本。
为什么选择 XOR 作为混合函数?
-
XOR 是关联的、快速的,并且除了 SHA-2 之外,不需要额外的密码学假设,SHA-2 已经用于 H(tx)。
-
除非攻击者也控制 VRF 输出,否则一个熵分量(例如,RANDAO)中的任何偏差都会被否定。
为什么允许构建者首先管理候选集?
-
保留费用市场激励:高小费交易仍然会上升到纳入竞争的顶端。
-
避免强制包含低价值垃圾邮件,如果盲目对整个 mempool 进行排序,可能会导致区块膨胀。
为什么是辅助键 H(tx) 用于打破平局?
-
以可忽略的额外成本保证总订单。
-
利用每个节点都知道的值;不需要额外的字段。
为什么选择可选的捆绑包而不是隐式 nonce 链折叠?
-
无法仅通过 nonce 顺序来表示跨地址原子性(例如,借款人 + 贷款人交易对)。
-
要求显式的费用支付交易会嵌入捆绑包对排序中立性施加的外部性的定价。
为什么是“fit‑or‑skip”捆绑包规则?
-
确保所有客户端都计算出相同的 gas 影响,从而防止不同的执行。
-
避免部分捆绑包执行,这会破坏用户的意图。
为什么是版本标志 + 转换窗口?
-
通过为节点运营商提供宽限期来防止意外的共识分裂。
-
镜像以前成功的硬分叉(例如,伦敦的 BASE_FEE 激活序列)。
向后兼容性
- 旧节点 — 忽略新字段的执行客户端会将版本 1 区块视为格式错误并分叉出去。短暂的转换窗口使运营商有时间升级。
- 轻客户端 — 无需额外工作;他们跟踪升级后的完整节点选择的 header 。
安全考虑事项
随机性偏差和 RANDAO 操纵
-
单验证器偏差 – 区块提议者只能影响其自己的 VRF 输出;与 slot 级 RANDAO 的 XOR 将单方面偏差限制为 1-in-2¹²⁸。
-
联盟偏差 – 多个连续 slot 提议者可能会尝试通过扣留签名来影响 RANDAO,但该协议已经削减了 equivocation 和错过的证明。成本随着联盟规模呈指数增长,并且添加的 VRF 熵进一步随机化了
R
。 -
可分叉的偏差 – 长度大于深度 1 的重新组织尝试必须克服通常的共识最终确定阈值。由于
R
嵌入在执行 payload 中,因此所有节点都可以客观地检测到任何分叉冲突。
结论:串通攻击在经济上没有吸引力;来自 RANDAO 和 VRF 的混合熵提供了强大的不可预测性保证。
哈希研磨
仅当 calldata
更改时才需要新签名,但攻击必须在 R
已知 (≤ 12 秒) 之后开始。传播延迟和纳入费用会严重限制高价值交易的盈利研磨。
平局冲突
辅助密钥 H(tx)
保证总订单;碰撞概率 (2^{-256}
) 可以忽略不计。
捆绑包 Gas 一致性
显式求和规则确保每个客户端都计算出捆绑包的相同 gas 用量,从而防止不同的验证。
剩余的 MEV 向量
-
回溯和延迟 – 持续存在。
-
构建者自由裁量权 – 构建者可以在形成候选集时审查或选择性地包括交易;与以太坊的当前状态完全一样。
版权
通过 CC0 放弃版权和相关权利。
Citation
Please cite this document as:
Aryaethn (@aryaethn), "EIP-7956: 通过区块级随机性实现交易排序 [DRAFT]," Ethereum Improvement Proposals, no. 7956, May 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7956.