1.4 智能合约


1.4 智能合约

本节摘要:智能合约是 Web3 把"规则"变成"代码"的核心机制。本节讲清楚它和普通程序的区别、为什么"代码即法律"既是优势也是风险、以及编写和部署一个合约的真实流程。读完你能理解为什么 DeFi 被盗动辄上亿美金——不是黑客多厉害,是合约写错代价太大。

一、智能合约是什么

智能合约是部署在区块链上、由链上交易触发自动执行的程序

它和普通程序的关键区别有三点:

  • 部署即不可改(多数情况):合约部署上链后,代码无法直接修改。发现 bug?要么用升级代理模式预留后门,要么眼睁睁看着漏洞被利用。这和 Web2 随时发版修 bug 完全不同。
  • 执行由交易触发:合约不会自己运行,必须有人发交易调用它。每笔调用都要付 Gas 费,执行多少指令付多少费。
  • 状态上链公开:合约的存储变量都记在链上,任何人能查。你部署的合约里存了什么余额、什么配置,全网可见。

二、"代码即法律"的两面

"代码即法律"(Code is Law)是智能合约的核心哲学——规则写成代码,代码怎么执行结果就是什么,没有"我本意不是这样"的申辩空间。

优势:规则透明、执行确定、无人能干预。DeFi 借贷合约规定抵押率低于 150% 就清算,那不管借款人是散户还是巨鲸,触线就清算,没有"通融一下"。

风险:代码写错了也"即法律"。2016 年 The DAO 被盗 360 万 ETH,因为合约里有个递归调用漏洞,黑客按"代码逻辑"合法地提走了钱。社区最后靠硬分叉把钱追回,但这违背了"代码即法律"原则——说明完全靠代码也不现实。

图 1-4 智能合约执行流程

图 1-4 智能合约执行流程

三、一个最简合约长什么样

用 Solidity(以太坊上最主流的合约语言)写一个最简的代币合约:

// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SimpleToken { string public name = "MyToken"; mapping(address => uint256) public balances; uint256 public totalSupply; // 铸造代币给调用者 function mint(uint256 amount) public { totalSupply += amount; balances[msg.sender] += amount; } // 转账 function transfer(address to, uint256 amount) public { require(balances[msg.sender] >= amount, "余额不足"); balances[msg.sender] -= amount; balances[to] += amount; } }

注意几个要点:

  • msg.sender 是自动可用的,代表调用者地址,合约不需要也不应该让用户传入自己的地址(防伪造)。
  • require 是断言,不满足就回滚整笔交易,状态不变,已消耗的 Gas 不退。
  • mapping 是键值存储,相当于持久化的字典,记在链上。

四、智能合约的硬约束

合约运行在 EVM(以太坊虚拟机)里,有几个硬约束决定了它能做什么不能做什么:

1. 不能主动运行。 合约没有"定时任务",必须有人发交易触发。要做定时任务得靠链外服务(Chainlink Keepers、Gelato)发触发交易。

2. 不能访问外部数据。 EVM 是沙箱,不能直接 HTTP 请求。要拿链外数据(股价、天气、比赛结果)得用预言机(Chainlink)把数据喂进来。

3. 不能产生真随机数。 EVM 执行要确定性(所有节点算出同样结果),真随机会让节点结果不一致。要用链上随机得用 VRF(可验证随机函数)。

4. 计算受 Gas 限制。 每个操作消耗 Gas,单笔交易 Gas 有上限,复杂循环可能跑不完。这逼着合约写得高效。

五、合约安全:为什么被盗动辄上亿

合约一旦部署,漏洞就在那等着被发现。历史上几次大案:

事件 年份 损失 漏洞类型
The DAO 2016 360万ETH 递归调用
Parity 多签钱包 2017 15万ETH 库合约未初始化
Poly Network 2021 6.1亿美金 跨链权限校验缺失
Wormhole 2022 3.2亿美金 签名验证绕过
Euler Finance 2023 2亿美金 抵押计算错误

共同点不是黑客多天才,而是合约逻辑里漏了一个边界检查。一个 require 写错位置,几亿美金就没了。

防御手段:

  • 形式化验证:用数学方法证明合约满足某些性质。
  • 多重审计:上线前多家审计公司审。
  • 漏洞赏金:白帽子找漏洞给奖励,Immunefi 平台。
  • 时间锁升级:升级有延迟期,社区有时间审查。
  • 多签管理:关键操作要多个私钥同时签名。

六、合约升级:如何应对"不可改"

完全不可改的合约发现 bug 只能等死,所以出现了可升级模式。最常见的是代理模式:用户调用代理合约,代理把调用委托给逻辑合约,升级时只换逻辑合约地址,代理地址不变,用户无感。

// 代理合约核心:delegatecall contract Proxy { address public logic; // 逻辑合约地址 function upgrade(address newLogic) public onlyOwner { logic = newLogic; // 换逻辑合约=升级 } fallback() external { address impl = logic; assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }

可升级是双刃剑:方便修 bug,但也意味着团队能改规则,违背"代码即法律"。所以成熟项目给升级加时间锁(如 48 小时延迟),让社区有时间否决恶意升级。

⚠️ 最大风险:合约部署前务必多次审计。一旦上链,漏洞就在那等着。很多项目方图快省了审计,结果上线几天被掏空。审计费几万美金,被盗几亿美金,这笔账要算清。

💡 关键直觉:智能合约把规则变成不可单方篡改的代码,这是 Web3 信任转移的基础。但"不可改"也是双刃剑——写错没法偷偷修,所以部署前审计、上线后赏金、必要时可升级+时间锁,是务实的平衡。

重点提炼

  • 定义:链上部署、交易触发、状态公开、多数不可改的程序。
  • 代码即法律:规则透明执行确定,但写错也"即法律",风险极高。
  • 硬约束:不能主动运行、不能访问外部数据、不能真随机、受 Gas 限制。
  • 安全大案:损失动辄上亿,根因多是漏了一个边界检查,不是黑客天才。
  • 防御:形式化验证、多审计、漏洞赏金、时间锁、多签管理。
  • 升级模式:代理+逻辑分离,方便修 bug 但削弱"不可改",用时间锁平衡。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U