Alert Source Discuss
Standards Track: Core

EIP-3607: 拒绝来自部署了代码的发送者的交易

不允许 `tx.sender` 部署了任何代码的交易。

Authors Dankrad Feist (@dankrad), Dmitry Khovratovich (@khovratovich), Marius van der Wijden (@MariusVanDerWijden)
Created 2021-06-10

摘要

以太坊地址目前只有 160 位。这意味着可以使用估计的 2**80 次计算操作在合约账户和外部拥有账户 (EOA) 之间创建冲突,考虑到大量的预算(约 100 亿美元),现在这是可行的。此 EIP 中的修复程序可防止最糟糕的攻击,即将一个看起来安全的合约(例如,token 包装器或 AMM 类型的合约)部署以吸引用户资金,然后可以使用相同地址的 EOA 密钥来花费这些资金。解决方法是永远不允许使用已部署代码的地址作为 EOA 地址。

动机

生成地址冲突

通过为 2**80 个 EOA 创建密钥并模拟从这些 EOA 部署 2**80 个合约(每个合约一个),人们期望找到一个冲突,其中一个 EOA 与一个合约具有相同的地址。

这种非常简单的攻击形式需要存储 2**80 个地址,这是一个实际的障碍:这将需要 2.4*10**25 字节的内存 (24 Yottabyte)。但是,有一些循环查找算法可以执行冲突搜索而无需大量存储。这里 对复杂性进行了估计。我们估计,大约花费 100 亿美元的硬件和电力投资,可以在大约一年内找到合约和 EOA 之间的冲突。

背景

目前正在讨论将以太坊上的地址更改为 256 位,这将使抗冲突性提高到 2**128 的复杂度,目前认为在可预见的将来这是不可行的。但是,使用 160 位地址,如上所示,现在可以有效地解决冲突问题。

大多数可能通过地址冲突发生的攻击实际上是不切实际的:它们涉及用户在部署合约之前将资金发送到某个地址。这在实践中是一种非常罕见的应用,用户可以通过在合约安全部署并获得足够的确认之前决不将资金发送到合约来轻松规避攻击。

但是,黄皮书没有明确指定客户端应如何处理从已经部署了合约代码的帐户发送交易的情况;大概是因为当时认为这是不可行的。假设是,大多数客户端会在当前状态下允许此交易。

此 EIP 旨在指定此行为,以始终禁止此类交易。这修复了由于地址冲突引起的大多数现实或严重的攻击。

规范

任何 tx.sender 具有 CODEHASH != EMPTYCODEHASH 的交易都必须被拒绝为无效,其中 EMPTYCODEHASH = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470。 无效交易必须被客户端拒绝,不得包含在区块中。 包含此类交易的区块必须被视为无效。

理由

我们注意到,人们一直期望合约账户的行为受到该合约中代码的约束——这意味着该账户的资金不应突然可以被某些私钥花费。过去只是隐式地假设 160 位地址长度足以提供抗冲突性,因此这种情况永远不会发生。从这个意义上讲,该 EIP 应该被视为对先前未定义情况下的协议行为的澄清,而不是对共识规则的显式升级。

这并不排除所有可能的攻击媒介,仅排除最严重的攻击媒介。通过合约和 EOA 之间的地址冲突可能产生的其他攻击向量包括:

  1. 攻击者可以说服用户在部署账户之前将资金发送到该账户。某些应用程序需要此行为(例如,状态通道)。
  2. 在部署合约后可能会发生链重组。如果重组删除了合约部署交易,则仍然可以使用私钥访问资金。
  3. 合约可以自毁,并声明合约中的 ERC20(或其他 token)将被销毁。但是,现在可以通过该地址的密钥访问它们。

对于攻击者而言,所有这些情况都更难以利用,并且可能产生的收益要低得多,因此攻击不太可能在经济上可行。

向后兼容性

不太可能在以太坊主网上已经发生了这样的攻击,否则我们很可能已经听说过了。当人们可以通过简单地将一些方法添加到合约而不是花费数十亿美元来构建硬件以寻找哈希冲突时,无法想象有人会使用它作为“功能”来使合约同时成为 EOA。

私有网络可能已经在 genesis 部署了也可以作为 EOA 的合约,并且应检查此升级是否会影响其工作流程。

客户端可能会选择为 eth_calleth_estimateGas 等 RPC 调用禁用此规则,因为某些多重签名合约使用这些调用来创建交易,就像它们源自多重签名合约本身一样。

测试用例

给定一个创世分配

Address: 0x71562b71999873DB5b286dF957af199Ec94617F7
Balance: 1000000000000000000 // 1 ether
Nonce:   0,
Code:    0xB0B0FACE",

由与 0x715656... 对应的私钥 (b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291) 发送的每笔交易都应被拒绝。 这些交易必须被拒绝,不得包含在区块中。

参考实现

在检查发件人的 nonce 是否正确后,必须将以下检查添加到状态转换检查中。 发件人是从交易签名中恢复的地址。

// Make sure the sender is an EOA
// 确保发件人是 EOA
Set ch to the CodeHash of the sender account
// 将 ch 设置为发件人帐户的 CodeHash
if ch is not equal to EmptyCodeHash then
// 如果 ch 不等于 EmptyCodeHash
	return ErrSenderNoEOA
end if

可以在此处找到在 go-ethereum 中实现 EIP-3607 的差异

安全注意事项

此 EIP 是一项严格的安全升级:它只是使以前有效的某些交易现在无效。此类交易没有任何合法的用途,因此不应存在安全方面的缺点。

此 EIP 可以作为软分叉来实现,因为新的有效性规则是先前有效性规则的严格超集。

版权

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

Citation

Please cite this document as:

Dankrad Feist (@dankrad), Dmitry Khovratovich (@khovratovich), Marius van der Wijden (@MariusVanDerWijden), "EIP-3607: 拒绝来自部署了代码的发送者的交易," Ethereum Improvement Proposals, no. 3607, June 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3607.