第1章:区块链基础与EVM原理
各位同学,欢迎来到智能合约安全审计的第一课。
说实话,我见过太多人一上来就写合约,结果连区块链的基本概念都没搞清。嗯,这就像没学会走路就想跑马拉松。今天,我们先把地基打牢。
1.1 区块链核心概念回顾
区块链是什么?说白了,就是一个分布式账本。每个人手里都有一份相同的账本,谁也别想偷偷改数据。
我个人习惯把区块链理解成「一串用密码学锁链连接的数据块」。每个块里装着交易记录,块与块之间通过哈希值链接。你改一个块,后面的所有块都得改,这在算力上几乎不可能。
核心三要素:
- 去中心化:没有单点故障,没有中央服务器
- 不可篡改:数据一旦上链,几乎无法修改
- 透明可追溯:所有交易公开,谁都能查
我在项目中遇到过不少新手,以为「区块链就是数据库」。其实差别很大。数据库可以删改,区块链只能追加。你想想看,这特性对智能合约意味着什么?——代码一旦部署,想改?难了。
1.2 以太坊虚拟机(EVM)架构
EVM,全称 Ethereum Virtual Machine。你可以把它想象成一个全球共享的超级计算机。这台计算机不跑在某个机房,而是跑在成千上万个节点上。
EVM 的核心特点:
- 图灵完备:理论上能计算任何可计算的问题
- 沙箱隔离:合约之间互不影响,出问题只影响自己
- 确定性执行:同样的输入,在任何节点上都得到同样的输出
为什么会强调确定性?因为如果不同节点算出的结果不一样,整个网络就分裂了。我刚开始学的时候,总觉得这限制太多,后来才明白——没有确定性,就没有共识。
EVM 的存储结构
EVM 里有三种存储区域,你得记清楚:
| 存储类型 | 特点 | 成本 | 生命周期 |
|---|---|---|---|
| Storage(存储) | 永久存储,写入链上 | 最贵(20,000 Gas+) | 合约生命周期 |
| Memory(内存) | 临时存储,函数执行期间有效 | 较便宜 | 函数调用期间 |
| Stack(栈) | EVM 操作栈,深度 1024 | 免费(但有限制) | 指令执行期间 |
避坑指南:我曾经审计过一个合约,开发者把大量数据存在 Storage 里,结果每次调用都花天价 Gas。记住:能用 Memory 就别用 Storage,能用事件就别存变量。
1.3 交易与消息调用
在以太坊上,一切动作都始于交易。交易分两种:
- 普通转账:从 A 地址转 ETH 到 B 地址
- 合约调用:调用合约里的某个函数
消息调用呢?就是合约之间互相「说话」。比如合约 A 调用合约 B 的函数,这就是一次消息调用。注意,消息调用不产生新的交易,它是在同一笔交易内部发生的。
安全警告:消息调用是重入攻击的温床。我曾经审计过一个 DeFi 项目,攻击者就是利用合约间的消息调用,反复调用提现函数,把池子掏空了。后面讲重入攻击时,我们会详细拆解。
交易的结构
一笔交易包含这些字段:
- nonce:发送方的交易序号,防止重放攻击
- gasPrice:你愿意为每单位 Gas 付多少钱
- gasLimit:你愿意为这笔交易花多少 Gas
- to:目标地址(合约或外部账户)
- value:转账金额(单位:wei)
- data:调用数据(合约调用时携带的函数签名和参数)
- v, r, s:签名信息,证明交易是你发的
嗯,这里有个坑。很多人以为 gasPrice 越低越好,省钱嘛。但 gasPrice 太低,矿工不打包,交易可能卡几个小时甚至几天。我建议你根据网络拥堵情况动态调整,别省那点钱耽误事。
1.4 Gas 机制详解
Gas 是以太坊的「燃料」。每执行一条指令,都要消耗一定量的 Gas。为什么要设计 Gas?防止死循环。如果没有 Gas 限制,一个恶意合约可以让全网节点无限循环,那整个网络就瘫痪了。
Gas 的计算公式很简单:
交易费用 = gasUsed × gasPrice
其中:
- gasUsed:实际消耗的 Gas 量
- gasPrice:你愿意支付的单价(单位:gwei)
1 ETH = 10^9 gwei = 10^18 wei
常见操作的 Gas 消耗
| 操作 | Gas 消耗 | 说明 |
|---|---|---|
| 转账(基础) | 21,000 | 最简单的 ETH 转账 |
| SLOAD(读存储) | 2,100(热) / 2,100(冷) | 读取 Storage 变量 |
| SSTORE(写存储) | 20,000(新写) / 5,000(修改) | 写入 Storage 变量 |
| 合约创建 | 32,000 + 部署代码 Gas | 部署新合约 |
| SHA3(Keccak256) | 30 + 6 × 数据长度 | 计算哈希 |
关键点:写 Storage 比读 Storage 贵 10 倍。读 Storage 比读 Memory 贵 100 倍。所以,能缓存就缓存,能压缩就压缩。我在审计中经常发现,很多 Gas 浪费都是因为开发者没注意这些细节。
Gas 上限与区块 Gas Limit
每个区块都有 Gas Limit,目前以太坊主网大约是 30,000,000 Gas。这意味着一个区块能容纳的交易量是有限的。如果网络拥堵,交易就得排队。
你可能会问:那我设置 gasLimit 越高越好吗?不是。gasLimit 是你愿意为这笔交易支付的最大 Gas 量。如果实际消耗超过 gasLimit,交易会回滚,但 Gas 不会退还。所以,别设得太低,也别设得太高。
我的经验:对于普通转账,gasLimit 设 21,000 就够了。对于合约调用,我一般设 100,000 起步,复杂操作设 500,000。如果拿不准,可以用 ethers.js 的 estimateGas 方法先估算一下。
知识体系总览
下面这张图,是我自己整理的本章知识结构。你可以把它当作学习地图:
这张图把本章的核心知识点串起来了。你看到没?所有内容最终都指向一个目标——写出更安全的合约。区块链基础决定了你的认知边界,EVM 原理决定了你的代码质量,Gas 机制决定了你的合约成本。三者缺一不可。
好了,第一章就到这里。记住我今天说的:基础不牢,地动山摇。下一章我们开始动手写合约,到时候你会感谢今天打下的基础。
公众号:蓝海资料掘金营,微信 deep3321