关键词:智能合约、Solidity、EVM、区块链、以太坊、Gas、事件、映射、Subcurrency
简介:智能合约到底是什么?
智能合约就是一段运行在区块链上的程序,它可以独立自动执行,不可篡改,并且人人可验证。
与传统服务器不同,合约代码一旦部署就面向全网节点开放;任何用户只需发起一笔交易即可与逻辑交互。无论你是开发者、产品经理还是投资者,理解智能合约的运行方式,都是 2025 年 Web3 世界的必修课。
一个简单的存储合约
我们先从一个最基础的「存钱罐」开始:任何人都能存入一个数字,任何人也都能查询它。
合约代码
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.16 <0.9.0;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}逐行拆解
| 行号 | 说明 |
|---|---|
// SPDX-License-Identifier | 开源许可,一键让使用者知道如何合规使用 |
pragma solidity | 指定编译器版本,防止“新版语法破坏旧合约”尴尬 |
uint storedData | 声明状态变量,永久保存在链上 256 位空间 |
set | 写入函数,调用即花费 Gas |
get | 只读函数,使用 view,几乎免费 |
虽然合约简陋,但它已经展示了区块链「共享数据库」特性:
写入需要交易、读取免费、历史可追溯。
加餐:发行你自己的「子货币」
下一个例子将带你完成一枚极简 Token:发行、转账、余额查询一次到位。
合约代码
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Coin {
address public minter;
mapping(address => uint) public balances;
event Sent(address from, address to, uint amount);
constructor() {
minter = msg.sender;
}
function mint(address receiver, uint amount) public {
require(msg.sender == minter, "Only minter can mint");
balances[receiver] += amount;
}
error InsufficientBalance(uint requested, uint available);
function send(address receiver, uint amount) public {
if (amount > balances[msg.sender])
revert InsufficientBalance({
requested: amount,
available: balances[msg.sender]
});
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}新知识点速览
address
160 位以太坊账户地址,不能参与算术,却能接收、存储 ETH。mapping
链上「哈希表」:address → uint。键理论上无限,但你无法遍历全部。
若需要追踪全体持币地址,通常搭配数组或事件。event Sent
轻客户端/前端可订阅此事件,实时同步余额变化。
数据最终可由布隆过滤器检索,减少链上扫描。error InsufficientBalance
在 revert 时附带结构化信息,方便 UI 友好提示。require/revert
Bloom 过滤器级别错误处理,保障原子性与审计友好性。
FAQ:上手阶段最关心的问题
Q1:部署 SimpleStorage 需要多少 Gas?
A:在以太坊主网约 110,000–130,000 Gas;Layer2 网络可能 < 0.001 USD。
Q2:public 会自动生成 getter 吗?
A:是的。uint public x; 会自动合成函数 x() external view returns (uint)。
Q3:为什么 mapping 不能遍历?
A:出于链上计算 & 存储成本考量,EVM 只提供键→值查询接口,无迭代器。若需列表,可手动维持数组或采用可枚举库。
Q4:合约可以自我销毁吗?
A:可以,调用 selfdestruct(address payable recipient);但慎用,任何发送给已销毁地址的 ETH 将永久丢失。新版 Solidity 已打弃用警告。
Q5:如何限制只有我本人能调用 mint?
A:通过 require(msg.sender == minter, "..."),也可以升级为多签或基于角色的权限合约。
Q6:我怎么在前端监听 Sent 事件?
A:使用 ethers.js 的 contract.on("Sent", handler) 或 web3.js 的 .watch() 即可实时响应转账。
区块链基础快速复习
交易/事务
- 全局共享数据库中的原子操作
- 要么全部生效,要么全部回滚
区块
- 打包时间 ≈ 12 秒(PoS)
- 区块高度越深,回滚概率越低
双花攻击预防
- 由矿工/验证者通过共识机制决定交易顺序,形成唯一链
无需深入挖矿和椭圆曲线,只要知道「安全第一」即可安心写链上逻辑。
以太坊虚拟机(EVM)必知点
- 存储 Storage
持久的 256→256 键值数组,读写成本高。用于存状态变量。 - 内存 Memory
每次外部调用后归零的线性空间,生命周期与函数调用绑定。 - 栈 Stack
最大 1024 个插槽、LIFO 运算。复杂算法以循环替代递归,避免深度超限。 - Gas & 计价
EVM 按指令扣除 Gas,价格由市场调整。动态 Gas 机制,既防 51% 攻击又补贴节点。 - 消息调用
合约间同步调用:A.call B.foo{value: 1 ether}(args)。可指定 Gas,还能返回数据。 - 委托调用 Delegate Call
保持当前合约上下文,换代码执行,让「共享库」成为可能,典型代表是 OpenZeppelin 可升级代理。
进阶提示:预编译合约 & 自毁
- 预编译地址 0x01–0x08
看代码永远调不到的神秘函数,如 ecrecover、blake2f。底层由节点直接提供实现。 - selfdestruct
如果你能接受「可能送错的 ETH 永远丢失」的致命风险后再使用;推荐软停用:设置 paused 布尔开关,需要时再升级合约。
小结
10 行 Solidity 就能打造出「全球共享的数字资产」。
从 uint storedData 到 mapping+event,你掌握了智能合约的四根支柱:状态变量、函数可见性、事件日志与错误处理。
下一步,加入 libraries、access control 与 Optimism 的廉价 Gas 环境,你的去中心化应用即将触达千万用户。祝你链上编码愉快!