Alert Source Discuss
🚧 Stagnant Standards Track: Core

EIP-1959: 用于检查 chainID 是否属于 chainID 历史的新操作码

Authors Ronan Sandford (@wighawag)
Created 2019-04-20
Discussion Link https://ethereum-magicians.org/t/eip-1959-valid-chainid-opcode/3170
Requires EIP-155

简述

为了保护链下消息不被跨不同链重用,需要为智能合约提供一种机制,使其仅接受该链的消息。由于链可能会更改其 chainID,因此该机制应考虑旧的 chainID 有效。

摘要

本 EIP 添加了一个操作码,该操作码返回传入的特定数字是否为链历史记录(包括当前 chainID)中有效的 chainID(EIP-155 唯一标识符)。

动机

EIP-155 建议使用 chain ID 来防止不同链之间的重放攻击。如果在智能合约中处理签名时,尤其是对于使用 EIP-712 的 Layer 2 签名方案,拥有相同的可能性将是一个很大的好处。

EIP-1344 试图通过让智能合约访问 chainID 历史记录的顶端来解决这个问题。这还不够,因为这样的值在不断变化。因此,EIP-1344 描述了一种基于合约的解决方案来解决这个问题。最好以一种更简单、更经济、更安全的方式来解决它,从而消除 EIP-1344 中存在的潜在滥用风险。

规范

在 0x46 处添加一个新的操作码 VALID_CHAINID,它使用 1 个堆栈参数:一个代表要测试的 chainID 的 32 字节值。如果 uint256 值属于该链的 chainID 历史记录(自创世以来),它会将 0x1 推送到堆栈上,否则推送 0x0

该操作的执行成本为 G_blockhash

随着链历史记录中 chainID 数量的增长,可能需要稍后调整操作成本。

但请注意,维护旧 chainID 的替代方法是实施基于智能合约的缓存解决方案,如 EIP-1344 提出的那样,这会带来更高的总体 gas 成本。因此,gas 成本只是该功能的必要成本。

理由

目前唯一可用的方法是在编译时指定链 ID。在发生有争议的硬分叉后,使用这种方法会导致问题,因为合约无法接受使用新 chainID 签名的消息。

EIP-1344 提出的方法是允许访问最新的 chainID。这本身是不够的,并且会造成上述问题的相反情况,因为一旦发生更改 chainID 的硬分叉,根据 EIP-712 签名的所有 L2 消息(使用之前的 chainID)将在分叉后无法被合约接受。

这就是为什么在 EIP-1344 的理由中提到用户需要实施/使用一种机制,通过智能合约实现的无需信任的缓存来验证过去 chainID 的有效性。

虽然这有效(除了一个临时缺口,即立即之前的 chainID 不被认为是有效的),但这实际上是所有想要接受 L2 消息的合约的必需程序,因为如果没有它,在更新 chainID 的硬分叉之前签名的消息将被拒绝。 换句话说,EIP-1344 暴露了这种风险,并且合约很容易通过简单地检查 chainID == CHAIN_ID() 而不考虑过去的 chainID 来不考虑它。

事实上,让合约访问最新的 chainID 以进行 L2 消息验证是危险的。最新的 chainID 只是 chainID 历史记录的顶端。 作为一个变化的值,最新的 chainID 因此不适合确保 L2 消息的有效性。

签署链下消息的用户希望他们的消息从签署之时起就有效,并且不希望这些消息受到未来硬分叉的影响。 如果合约使用最新的 chainID 进行验证,则消息将在更新 chainID 的硬分叉发生后立即失效。 对于某些应用程序,这将需要用户重新提交新消息(考虑元交易),从而导致他们潜在的损失(或在硬分叉过渡期间的一些不便),但对于其他一些应用程序(考虑状态通道),整个链下状态变得无法访问,从而导致可能灾难性的情况。

换句话说,我们应该将所有(具有有效 chainID)的链下消息视为链的链下状态的一部分。 这里提出的操作码为智能合约提供了一种简单而安全的方法来确保链下状态在分叉期间保持有效。

至于重放保护,将所有使用有效 chainID 签名的链下消息视为链的链下状态的一部分的想法意味着所有这些链下消息都可以在共享通用 chainID 历史记录(直至它们不同的地方)的不同分叉上重用。这实际上是一个重要的特性,因为正如所提到的,用户希望他们签署的消息从签署之时起就有效。 从那时起,这些消息应被视为链的链下状态的一部分。 因此,硬分叉不应使它们无效。 这类似于先前的链上状态在 2 个硬分叉之间共享的方式。

钱包将确保在任何时候,签名消息请求都使用正在使用的链的最新 chainID。 这可以防止在具有不同 chainID 历史记录的链上进行重放攻击(它们不会具有相同的最新 chainID)。

现在在 EIP1344 讨论 中认为,当发生有争议的硬分叉并且分叉的一方决定不更新其 chainID 时,链的这一方将容易受到重放攻击,因为用户将继续使用在分叉的链中也有效的 chainID 进行签名。 EIP-1344 中也存在这个问题。

这仅仅是使用 chainID 作为 L2 消息的唯一反重放信息的自然结果。 但如果硬分叉是由少数人创建的,这确实可能是一个问题。 在这种情况下,如果大多数人忽略该分叉并且不更新其 chainID,则来自大多数链的所有新消息(直到他们更新其 chainID 为止)都可以在少数人领导的硬分叉上重放,因为大多数人的当前 chainID 也是少数人领导的分叉的 chainID 历史记录的一部分。

为了解决这个问题,每条消息都可以指定表示其签名时间的区块号。 然后,合约可以验证指定为该消息一部分的 chainID 在该特定区块是否有效。

虽然 EIP-1344 无法准确地做到这一点,因为缓存系统可能会留下差距,但如果对其进行修改以返回 chainID 无效时的 blockNumber,则此提案可以解决它。 不幸的是,合约很容易不执行该检查。 并且由于仅需一个重要的应用程序不遵循此程序将少数人领导的分叉置于不利地位,因此这将无法实现保护少数人领导的分叉免受重放的预期目标。

由于被多数人忽略的少数人领导的分叉意味着多数人不会跟踪要提交的消息(状态通道,…),因此如果此类分叉稍后获得关注,这将以不知情的多数人用户的利益为代价。 因此,该提案假设少数人领导的分叉稍后不会获得关注,因此不需要保护。

测试用例

待定

实现

待定

向后兼容性

本 EIP 与所有为交易签名实现 EIP-155 chain ID 域分隔符的链完全向后兼容。 现有合约不受影响。

与 EIP-1344 类似,更新 EIP-712(仍在草案中)以与域分隔符分开处理 chainID 可能是有益的。 事实上,由于 chainID 预计会发生变化,如果域分隔符包含 chainID,则必须动态计算它。 但是,智能合约可以使用缓存机制。

参考

这之前在 EIP-1344 讨论 中被提出。

版权

通过 CC0 放弃版权和相关权利。

Citation

Please cite this document as:

Ronan Sandford (@wighawag), "EIP-1959: 用于检查 chainID 是否属于 chainID 历史的新操作码 [DRAFT]," Ethereum Improvement Proposals, no. 1959, April 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1959.