本文分析了以太坊坎昆升级后(区块20M-25M)SELFDESTRUCT操作码的使用情况。
已发布数据集(472,641 个事件):https://gist.github.com/chfast/7923cc97710e6e788b2fcd840c17ffb0
数据集为 CSV 格式,包含一个标题行,每个 SD-SAMETX 事件占用一行。行按收集顺序追加,大致按 block 的时间顺序排列。所有十六进制字段均为小写,不带 0x 前缀。
block,tx,addr,ben,balance,origin,caller,initcode,codesize,codehash
| 列 | 类型 | 含义 |
|---|---|---|
block |
十进制 uint64 | 包含 SELFDESTRUCT 的区块编号 |
tx |
32 字节十六进制 | 交易哈希 |
addr |
20 字节十六进制 | 被销毁合约的地址 |
ben |
20 字节十六进制 | 受益人(addr 的 ETH 余额接收方) |
balance |
十进制 wei | SD 操作码执行时的 ETH 余额 |
origin |
20 字节十六进制 | 顶层签名者 EOA(evm.TxContext.Origin) |
caller |
20 字节十六进制 | 被销毁合约的直接调用方——通常是部署并立即销毁(deploy-and-die-in-constructor)模式中的工厂;对于直接的合约创建交易,等于 origin |
initcode |
0 或 1 |
1 表示 SD 在构造函数内触发(运行时代码从未持久化);0 表示 SD 在构造完成后触发(运行时代码当前存在于状态中) |
codesize |
十进制字节 | (仅当 initcode=0 时;否则为空) 持久化运行时代码的大小 |
codehash |
32 字节十六进制 | (仅当 initcode=0 时;否则为空) 持久化运行时代码的 keccak256 哈希 |
关于 initcode 的检测说明:它是在 SD 操作码执行时从 IntraBlockState.GetCodeSize(self) 设置而来的。在构造函数帧中,运行时代码尚未存入(SetCode 在 evm.Run() 返回后执行),因此 codesize == 0 能可靠地标记为构造函数内的情况。一个具有空运行时代码的持久化合约无法到达 SD(对空代码地址的调用不会分派任何操作码),因此等价关系 initcode == 1 ⇔ 在构造函数帧中 在实践中成立。
此数据集仅包含 SD-SAMETX 事件(Cancun 后同一交易创建的合约的每个 SELFDESTRUCT,即 EIP-6780 实际销毁账户的路径)。生成此数据的 Erigon 工具还会发出其他三个标签——SD-BURN、SD-BROKEN-BURN、FINAL-BURN——涵盖正交现象(销毁账户、EIP-6780 阻止的销毁、延迟销毁)。这些标签不在本 CSV 中,也不在此分析中,因为它们与本报告调查的问题“移除 EIP-6780 会在状态膨胀方面带来什么代价”无关。
| 指标 | 值 |
|---|---|
| SD-SAMETX 事件总数 | 472,641 |
| 区块范围 | 20,000,000 → 24,999,999(500 万个区块,约 695 天 @12秒) |
| 唯一 CREATE2 地址(= 如果 SD 被禁用,则为浪费的账户) | 413,508 |
| 硬失败事件(事件数 − 唯一地址数;重新部署时的 CREATE2 冲突) | 59,133(12.51%) |
| 浪费的代码字节(对 initcode=0 的唯一地址的 codesize 求和) | 3,268,302 字节(约 3.27 MB) |
| initcode=0 合约中唯一的运行时代码哈希 | 305 |
| 按代码哈希去重后的浪费代码字节(每个唯一哈希仅保留一份副本) | 909,207 字节(约 909 KB) |
模型如下:在没有 SD 的世界中,每个唯一 CREATE2 地址的 首次 部署成功并留下一个持久化账户;之后在同一地址上的每次部署都会硬失败(当目标地址具有 nonce != 0 或非空 codehash 时,CREATE2 冲突检查会拒绝部署)。
浪费的账户数 = N_unique_addrs
(每个唯一 CREATE2 地址恰好留下一个持久化账户——类别和 initcode 对计数不重要,只影响账户中的内容)
硬失败事件数 = N_total_events − N_unique_addrs
(在已存在于状态中的地址上的事件会触发 CREATE2 冲突并回滚)
浪费的代码字节 = Σ codesize 针对 initcode=0 的唯一地址
(initcode=1 意味着运行时代码从未存入——持久化账户会带有空代码,因此不计入代码字节)
去重后的浪费代码字节 = Σ codesize 针对 initcode=0 的唯一 codehash
(Erigon 的状态存储以 codehash 为键存储代码,因此在许多地址上部署的相同模板会在 trie 中共享同一份代码块)
3.27 MB 到 909 KB 的压缩比(约 3.6 倍)反映了相同的 Deposit/Wrapper 模板被部署在许多不同的地址上。状态实际上只会增加约 909 KB 的新代码,但会增加约 41.4 万个新账户记录。
每个事件根据以下决策树分为六大类之一(第一个匹配优先):
A_DirectScript origin == caller
(顶层 CREATE 交易;无工厂合约)
B_SharedFactory caller 有 ≥ 2 个不同的 origin
(一个工厂合约被多个操作者使用)
C_SybilBatch origin 使用 ≥ 3 个不同的工厂,并且 事件数/交易数 ≥ 3
(单个操作者轮换使用多个工厂,每笔交易批量部署多个临时合约)
D_MultiTenantAggregator (origin, caller) 有 ≥ 5 个不同的受益人
并且 事件数/受益人数 < 50
(一个操作者加一个工厂路由到多个客户钱包,每个受益人交易量少)
E_DepositForwarder 该事件的 addr 在日志中出现 ≥ 2 次
(CEX 风格:同一 CREATE2 地址被重新部署)
F_OneShot 其他情况
(单租户存款转发器,不重用地址——每次都使用新的 CREATE2 地址)
阈值(Sybil 类别:f ≥ 3 && ept ≥ 3;MultiTenant 类别:bens ≥ 5 && events/ben < 50)是在较小的样本上调优的,以免多租户检测器误判在少量热钱包之间轮换的单租户操作者。
| 类别 | 事件数 | %ev | 唯一地址数 | 硬失败数 | %hf | 有代码的地址数 | 代码字节数 | 起源数 | 调用者数 |
|---|---|---|---|---|---|---|---|---|---|
| A_DirectScript | 34,384 | 7.3% | 34,339 | 45 | 0.13% | 172 | 180,069 | 2,098 | 2,098 |
| B_SharedFactory | 98,972 | 20.9% | 97,120 | 1,852 | 1.87% | 1,849 | 1,140,264 | 604 | 79 |
| C_SybilBatch | 37,262 | 7.9% | 34,638 | 2,624 | 7.04% | 264 | 45,634 | 28 | 190 |
| D_MultiTenantAggregator | 10,618 | 2.2% | 3,764 | 6,854 | 64.55% | 90 | 1,914 | 7 | 7 |
| E_DepositForwarder | 59,768 | 12.6% | 12,010 | 47,758 | 79.91% | 496 | 107,282 | 112 | 129 |
| F_OneShot | 231,637 | 49.0% | 231,637 | 0 | 0.00% | 1,048 | 1,793,139 | 504 | 3,251 |
| 总计 | 472,641 | 100.0% | 413,508 | 59,133 | 12.51% | 3,919 | 3,268,302 | — | — |
%hf = 该类别内的硬失败率(hard_fail / events);粗体总计是数据集整体比率。
计算方法:bucket = floor(block / 100_000) * 100_000;每个桶的事件数只是 block 落在 [bucket, bucket + 100_000) 范围内的 SD-SAMETX 行的计数。
20,000,000 5,392 #####
20,100,000 4,255 ####
20,200,000 4,272 ####
20,300,000 6,087 ######
20,400,000 5,129 #####
20,500,000 4,803 ####
20,600,000 5,013 #####
20,700,000 5,308 #####
20,800,000 4,613 ####
20,900,000 4,849 ####
21,000,000 6,090 ######
21,100,000 6,539 ######
21,200,000 4,414 ####
21,300,000 3,761 ###
21,400,000 3,412 ###
21,500,000 4,120 ####
21,600,000 4,185 ####
21,700,000 5,195 #####
21,800,000 5,335 #####
21,900,000 4,714 ####
22,000,000 5,651 #####
22,100,000 6,143 ######
22,200,000 6,928 ######
22,300,000 6,735 ######
22,400,000 5,649 #####
22,500,000 6,599 ######
22,600,000 7,057 #######
22,700,000 9,515 #########
22,800,000 9,049 #########
22,900,000 8,573 ########
23,000,000 100,530 ####################################################################################################
23,100,000 7,647 #######
23,200,000 7,522 #######
23,300,000 7,291 #######
23,400,000 8,049 ########
23,500,000 8,847 ########
23,600,000 8,389 ########
23,700,000 8,121 ########
23,800,000 7,787 #######
23,900,000 11,747 ###########
24,000,000 8,907 ########
24,100,000 7,757 #######
24,200,000 9,079 #########
24,300,000 17,025 #################
24,400,000 17,207 #################
24,500,000 15,887 ###############
24,600,000 13,394 #############
24,700,000 13,835 #############
24,800,000 10,026 ##########
24,900,000 14,209 ##############
(1 个字符 ≈ 1,000 个事件。)
总体趋势:从窗口开始到结束,使用量大约增长到原来的三倍(每 10 万区块 5 k → 约 14 k),其中在 23.0 M 处有一次异常峰值。
- 原文链接: ethereum-magicians.org/t...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
作者暂未设置收款二维码