ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

EIP-2976 深度解读:devp2p 网络层如何 Gossip 类型化交易(Typed Transactions over Gossip)

EIP-2976 深度解读:devp2p 网络层如何 Gossip 类型化交易(Typed Transactions over Gossip) EIP-2976 深度解读devp2p 网络层如何 Gossip 类型化交易Typed Transactions over Gossip【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs本文深入解读以太坊改进提案 EIP-2976Typed Transactions over GossipFinal 状态Networking 类。该规范补齐了 EIP-2718 类型化交易信封在共识层引入后、P2P 网络层缺失的传播通道定义了类型化交易与收据如何在 devp2p 协议上以TransactionType || TransactionPayload的形式进行 Gossip 与检索。读完本文你将掌握 EIP-2976 的全部数据定义、协议行为约束、六个核心协议消息格式及其演进逻辑并理解它如何支撑 EIP-1559、EIP-4844 等后续类型化交易的网络传播。背景共识层有了新交易网络层却没有传输通道EIP-2718 在共识层引入了「类型化交易信封」Typed Transaction EnvelopeTransactionType || TransactionPayload是一种合法交易TransactionType || ReceiptPayload是一种合法收据。它通过一个信封结构把「区分交易类型」这一复杂问题简化为「避免 TransactionType 编号冲突」这一简单问题为未来新交易类型如 EIP-1559 的 type 2、EIP-4844 的 type 3打开了大门。但 EIP-2718 只解决了区块内的表现形式——即区块头transactionsRoot与receiptsRoot的组成。正如 EIP-2976 的 Motivation 所指出的然而如果没有一种 Gossip 这些交易的机制没有人能真正把它们打包进区块。EIP-2976 正是为解决这一缺口而生它更新 devp2p 协议以支持类型化交易的传播且不要求因此递增 devp2p 版本号——客户端可以自行开始支持新交易类型的 Gossip而无需升级整个网络协议。核心定义理解 EIP-2976 的每一处数据术语EIP-2976 规范以精确的定义开篇以下是全部术语沿用原文档的字节/类型记号||字节/字节数组连接运算符|类型联合union运算符DEVP2P_VERSION TBD规范发布时版本号待定实际落地时该版本演进交由 eth/65、eth/66 等后续 EIP 处理见下文Transaction要么是TypedTransaction要么是LegacyTransactionTypedTransaction包含TransactionType || TransactionPayload的字节数组TypedTransactionHashkeccak256(TypedTransaction)TransactionType介于0与0x7f之间的正无符号 8 位整数表示交易类型TransactionPayload不透明字节数组其解释依赖于TransactionType由未来 EIP 定义LegacyTransaction形如[nonce, gasPrice, gasLimit, to, value, data, v, r, s]的数组LegacyTransactionHashkeccak256(rlp(LegacyTransaction))TransactionIdkeccak256(TypedTransactionHash | LegacyTransactionHash)——注意这里是对「类型化交易哈希或传统交易哈希」再取一次 keccak256得到统一的 32 字节交易标识供NewPooledTransactionIds/GetPooledTransactions消息使用Receipt要么是TypedReceipt要么是LegacyReceiptTypedReceipt包含TransactionType || ReceiptPayload的字节数组ReceiptPayload不透明字节数组其解释依赖于TransactionType由未来 EIP 定义LegacyReceipt形如[status, cumulativeGasUsed, logsBloom, logs]的数组LegacyReceiptHashkeccak256(rlp(LegacyReceipt))。关键在于协议层不感知TransactionPayload的内部结构。它是不透明的具体语义完全由各交易类型 EIP 自行定义。这正是「无需递增 devp2p 版本」的根基——新交易类型只是换了一个TransactionType编号与一组新的不透明字节协议层无需任何改动。与传统交易的识别规则来自 EIP-2718类型化交易与传统交易的区分完全依赖首字节见 EIP-2718 的 Backwards Compatibility 一节首字节落在[0, 0x7f]类型化交易首字节落在[0xc0, 0xfe]传统legacyRLP 交易0xff保留作未来扩展哨兵值。这一规则保证了 devp2p 层在拿到任意Transaction字节流时无需解析内部结构即可判定类型。协议行为四条约定的强度与意图EIP-2976 的 Protocol Behavior 一节给出了四条客户端行为约束其中MUST必须与SHOULD应当的强度区分值得仔细辨析收到无法识别的TransactionType→ SHOULD 断开发送方无论通过哪条消息收到未知交易类型都应断开该对等节点。这是防 DoS 的第一道闸门动机详见下文 Rationale。收到对TransactionType无效的TransactionPayload→ SHOULD 断开发送方即使类型已知载荷解析/校验失败同样视为异常行为。MUST NOT 在引入分叉块之前发送新交易类型新交易类型只能在它自己的分叉块introductory fork block到达之后才允许在网络中传播这是硬性禁止。MAY 断开「显著早于」分叉块就发送新交易类型的对等节点这是给客户端的可选防御手段针对抢跑发送者。此外规范明确以下所有变更追溯适用于所有协议/版本retroactively即不需要为类型化交易单独发布新版本的 devp2p。协议消息六类消息的完整格式EIP-2976 定义了以下协议消息消息编号沿用 devp2p eth 协议既有编号Transactions (0x02)[Transaction_0, Transaction_1, ..., Transaction_n]交易广播消息列表中每个Transaction均可是类型化或传统交易。BlockBodies (0x06)[BlockBody_0, BlockBody_1, ..., BlockBody_n]其中BlockBody是[TransactionList, UncleList]TransactionList是[Transaction_0, Transaction_1, ..., Transaction_n]UnclesList由 devp2p 规范既有版本定义。区块体中的交易列表现在可以包含类型化交易。NewBlock (0x07)[[BlockHeader, TransactionList, UncleList], TotalDifficulty]其中BlockHeader、UnclesList、TotalDifficulty均由 devp2p 规范既有版本定义TransactionList同上。NewPooledTransactionIds (0x08)[TransactionId_0, TransactionId_1, ..., TransactionId_n]通告一组交易的存在不含内容TransactionId即上文keccak256(TypedTransactionHash | LegacyTransactionHash)。GetPooledTransactions (0x09)[TransactionId_0, TransactionId_1, ..., TransactionId_n]按TransactionId向对等节点请求交易池中的交易。PooledTransactions (0x0a)[Transaction_0, Transaction_1, ..., Transaction_n]对GetPooledTransactions的响应返回交易池中的交易本体。Receipts (0x10)[ReceiptList_0, ReceiptList_1, ..., ReceiptList_n]其中ReceiptList是[Receipt_0, Receipt_1, ..., Receipt_n]每个Receipt可为类型化收据或传统收据。可以看到EIP-2976 的策略是消息外壳保持既有结构不变仅把其中的元素类型放宽为「类型化或传统」的联合。这也是其向后兼容性的直接来源。设计决策三个关键 Rationale为什么不在协议层指定每种交易类型的结构一种备选方案是让 devp2p 协议「感知」每种交易载荷的形状。作者认为若每种新交易类型都要求更新 devp2p长期维护负担过高因此规范只声明「支持类型化交易」把载荷语义完全留给未来 EIP。这一「协议无知」protocol-agnostic的设计让 devp2p 可以以不变应万变。为什么遇到未知交易类型要断开对等节点另一种思路是保持连接等待未来可能认识的交易类型。但这样做会打开 DoS 漏洞攻击者可以发送未定义TransactionType的交易从而在避免「因刷屏被断开」的同时持续消耗接收方资源。此外作者预判当新交易类型开始在 devp2p 上传播时要求所有连接客户端知晓该类型的硬分叉几乎必然迫在眉睫因此断开未知类型是合理且低成本的默认策略。为什么用不透明字节数组而非 RLP 列表承载载荷这一选择继承自 EIP-2718 的 Rationale不透明字节而非 RLP 列表未来可支持 SSZ、LEB128 或定宽格式等不同编码协议层无需感知编码细节。向后兼容性EIP-2976 的 Backwards Compatibility 表述极为简洁但含义清晰Legacy transactions are still supported传统交易仍然受支持。由于类型化交易首字节[0x00, 0x7f]与传统 RLP 交易首字节[0xc0, 0xfe]天然不相交新旧交易可以在同一条消息中共存旧客户端不认识类型化交易也只会将其视为未知类型并按 SHOULD 规则处理。安全考量无视 SHOULD 的代价EIP-2976 明确指出如果客户端选择忽略「断开未知交易类型发送方」的 SHOULD 建议则可能遭受 DoS 攻击。忽略该建议应仅限于受信任的对等节点或 DoS 风险极低的场景。这是协议把「断开」设计为 SHOULD 而非 MUST 的权衡——给予实现灵活性但把安全责任明确交给客户端。生态落地从 eth/65 到 EIP-4844 的类型化交易传播EIP-2976 是「Final」状态的基础网络规范其后的实际演进与落地可以在本仓库的后续 EIP 中看到清晰脉络eth/65EIP-2464正式引入NewPooledTransactionHashes (0x08)、GetPooledTransactions (0x09)、PooledTransactions (0x0a)三个消息将交易传播的带宽复杂度从「与对等节点数线性相关」降为「平方根」并将初始交易池同步从数十上百 MB 降至len(pool) * 32B ≈ 128KB。这实际上就是 EIP-2976 中NewPooledTransactionIds/GetPooledTransactions/PooledTransactions消息的正式化版本EIP-2976 中的TransactionId对应 eth/65 的 32 字节 hash。eth/66EIP-2481为GetPooledTransactions (0x09)、PooledTransactions (0x0a)、BlockBodies (0x06)、Receipts (0x10)等请求/响应消息统一引入 64 位request_id解决多请求并发时响应匹配歧义的问题。从源码结构看EIP-2481 提供了完整的 RLP 编码测试向量见 EIP-2481 Test Cases覆盖了 EIP-2976 涉及的多个消息类型。EIP-1559type 2 交易EIP-1559 定义TransactionType2其TransactionPayload为rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s])ReceiptPayload为rlp([status, cumulative_transaction_gas_used, logs_bloom, logs])——正是 EIP-2976 定义的TransactionType || TransactionPayload/TransactionType || ReceiptPayload结构在区块与网络中流通的实例。EIP-4844blob 交易type 3EIP-4844 的 Networking 一节给出了类型化交易在网络层「一个类型、两种表示」的典型实践在PooledTransactions的 Gossip 响应中EIP-2718 的TransactionPayload被包装为rlp([tx_payload_body, blobs, commitments, proofs])并要求节点校验blob_versioned_hashes与 commitments/proofs 的一致性在BlockBodies区块体检索响应中则使用标准 EIP-2718 的TransactionPayload节点MUST NOT自动向对等节点广播 blob 交易只能通过NewPooledTransactionHashes通告、再由GetPooledTransactions手动请求——这正是 EIP-2976 消息框架上叠加的传输策略。此外 EIP-5793 进一步扩展NewPooledTransactionHashes通告消息以包含交易类型与大小赋予节点更细粒度的传播控制。这些后续 EIP 共同印证了 EIP-2976「协议层不感知载荷、新类型无需递增版本」这一核心设计的前瞻性。结语一份小而关键的「管道」规范EIP-2976 全文不过百行却是以太坊交易类型演化链条上不可或缺的一环它把 EIP-2718 在共识层引入的类型化交易「接上」了 devp2p 网络管道并凭借「载荷不透明 未知类型断开」两条原则让未来的每一类新交易EIP-1559、EIP-4844乃至更远的 SSZ 化交易都能在不升级网络协议版本的前提下完成 Gossip 与检索。对于以太坊客户端开发者而言理解 EIP-2976 即理解类型化交易在节点间传播的底层契约对于研究者而言它也是一个「用最小规范变更撬动生态演进」的经典范本。关联文档本文全部规范内容直接继承自 EIPS/eip-2976.md基础信封结构见 EIPS/eip-2718.md网络层演进见 EIPS/eip-2464.md、EIPS/eip-2481.md、EIPS/eip-4844.md版权遵循仓库 LICENSE.md 的 CC0 豁免声明。【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进