合约账户的“不速之客”:智能合约的隐形陷阱

  • Marvin
  • 发布于 19小时前
  • 阅读 45

合约账户的“不速之客”:智能合约的隐形陷阱第一部分:起源这事儿就发生在昨天。听Tiny熊老师讲课后练习的Bank合约,当听到"这个Bank合约不应该维护一个'总存款金额'"时,我心里咯噔一下——这说的不就是我吗?CPU开始高速运转:去掉总金额的状态变量确实能省gas,代码复杂

合约账户的“不速之客”:智能合约的隐形陷阱

第一部分:起源

这事儿就发生在昨天。

听 Tiny 熊老师讲课后练习的 Bank 合约,当听到"这个 Bank 合约不应该维护一个'总存款金额'"时,我心里咯噔一下——这说的不就是我吗?

CPU 开始高速运转:去掉总金额的状态变量确实能省 gas,代码复杂度也能降低。

但接下来的一句直接让我 CPU 烧了:"有人会转 eth 到我这个合约账户,又不会触发我的 receive 或者 fallback"。

还有这种操作?事出反常必有妖,这妖我必须揪出来看看。

第二部分:探索

2.1 合并前(POW时代)

技术上的可行性

1. 自毁(selfdestruct)

这是以太坊协议与生俱来的"核按钮"。

从创世区块就存在的操作码,直到合并后才被标记为废弃,但功能依旧能用。

在 PoW 时代,这是制造"账实不符"漏洞的主要因素。


2. 挖矿的目标地址(coinbase address)

这是协议层的"空投"。

矿工挖出新区块的奖励,直接从以太坊供应中"无中生有",可以指定发送到任何地址——包括我的合约。

这波操作完全绕过交易逻辑,receive/fallback 函数直接装死。


3. 合约部署前发送

这是EVM 的"预言"特性。

由于合约地址是可预测的(由部署者地址+nonce决定),在合约正式上链前,任何人都能先打钱过去。

合约诞生时就自带"第一桶金",但这个过程同样不会触发任何回调。


4. Solidity 0.4 版本前发送

这是上古版本的"历史遗留问题"。

在 payable 关键字出现前,合约接收以太币的逻辑相当模糊,很多老合约在不知不觉中就成了"收钱账户"。

但是,动机是?(为什么会有这种操作?这是我最好奇的~~)

技术需求驱动

  • selfdestruct:设计是用来清理废弃合约的,避免资产被永久锁死
  • 部署前发送:确保合约上线就有启动资金,比如做市商提前充值流动性池

经济效率驱动

  • coinbase address:矿工直连钱包,省去交易费,简单粗暴

历史包袱

  • Solidity 0.4 前版本:语言进化过程中的"设计缺陷",并非主动选择

2.2 合并后(POS时代)

技术上的可行性

✅ 依然有效的

  • selfdestruct:虽然被贴了"deprecated"标签,但功能完好。其他合约依然能通过自毁强行给你的合约打钱
  • 合约部署前发送:EVM 核心特性,与共识机制无关。只要地址生成算法不变,这招就永远有效

❌ 已经失效的

  • coinbase address:PoW 退场,矿工下岗了。验证者取代矿工,区块奖励改成常规交易费分配
  • Solidity 0.4前版本发送:主流项目都升级了,基本很难遇到了

动机分析

技术层面

  • selfdestruct:仍然是合约"自毁"并转移资金的唯一合法途径
  • 合约部署前发送:开发者的"神操作",确保合约出生就带粮草

安全考量

  • 恶意攻击者会利用 selfdestruct 制造数据不一致,造成问题
  • 历史遗留问题(如旧版本合约)仍需保持警惕

📌 重点提醒

在 PoS 时代,重点防范对象就俩:selfdestruct合约部署前发送

这是导致合约"账实不符"的主要元凶。

第三部分:尾声

CPU 散热完毕,是时候来个总结了。

谁能想到,一个看似简单的 Bank 合约,背后居然藏着这么多"骚操作"。

就像你家明明装了防盗门,结果发现有人能从房顶烟囱、地下管道甚至某个平行时空把钱扔进你的保险箱。

心里默念:别相信"应该",要相信"可能"。


探索过程中涉及的资料:

  1. Can a contract with no payable function have ether?

  2. 关于 SELFDESTRUCT 部分描述

  3. 以太坊黄皮书-4.3节:beneficiary

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Marvin
Marvin
江湖只有他的大名,没有他的介绍。