2、区块链基础回顾:以太坊与EVM、账户与交易、Gas与手续费、钱包与私钥管理
好,咱们正式开始技术内容之前,先花点时间把区块链的基础再过一遍。我知道有些同学可能已经接触过以太坊,但别急,我保证这一章讲的东西,跟你平时看到的那些科普不太一样。我会结合自己踩过的坑,把那些看似简单、实则容易出问题的地方掰开揉碎了讲。
2.1 以太坊与EVM:不只是“世界计算机”
以太坊是什么?很多人张口就来——“世界计算机”。嗯,这个说法没错,但太笼统了。我个人习惯把它理解成一个全球共享的、确定性的状态机。
什么叫状态机?说白了,就是整个网络有一个全局状态,每出一个新区块,状态就更新一次。而这个状态转换的规则,就是由EVM(以太坊虚拟机)来执行的。
EVM其实是个很轻量的东西。它不像你的电脑有Windows或者macOS,它只认识一套特定的字节码指令。你写的Solidity代码,最终会被编译成这些字节码,然后部署到链上。每次有人调用你的合约,EVM就会逐条执行这些字节码,更新状态。
关键点:EVM是确定性的。同样的输入,在任何节点上执行,结果必须完全一样。这也是区块链能达成共识的基础。我在早期做跨链桥项目时,就因为忽略了不同EVM实现之间的微小差异,导致两边状态对不上,排查了整整两天。
这里有个概念容易混淆:以太坊不等于EVM。以太坊是主网,EVM是它的执行引擎。现在很多公链(比如BSC、Polygon、Avalanche)都兼容EVM,这意味着你写的Solidity合约,稍微改改甚至不改,就能部署上去。但要注意,兼容EVM不代表完全一样,底层的共识机制、区块时间、Gas模型都有区别。
2.2 账户与交易:两种账户,一种规则
以太坊上有两种账户:外部账户(EOA)和合约账户。这个区分非常重要,我见过不少新手在这上面翻车。
| 特性 | 外部账户(EOA) | 合约账户 |
|---|---|---|
| 谁控制 | 私钥持有者 | 合约代码逻辑 |
| 能否发起交易 | 能 | 不能(只能被调用) |
| 是否有代码 | 无 | 有(合约字节码) |
| 存储 | 只有余额 | 有存储空间(Storage) |
你想想看,为什么合约不能主动发起交易?因为合约没有私钥。它的一切行为,都是被外部账户或者其他合约“触发”的。这也是为什么很多DeFi协议需要“ keeper ”或者“ 机器人 ”来定时调用某些函数——合约自己没法起床干活。
交易的结构,我直接给你看最核心的字段:
{
"nonce": 5, // 该地址发起的交易序号,防重放
"from": "0xAbc...", // 发送方
"to": "0xDef...", // 接收方(如果是部署合约,这里为空)
"value": 1000000000000000000, // 1 ETH,单位wei
"gasLimit": 21000, // 最大允许消耗的Gas
"maxPriorityFeePerGas": 2000000000, // 小费,单位wei
"maxFeePerGas": 50000000000, // 你愿意支付的最高Gas价格
"data": "0x..." // 调用数据(转账时为空)
}
这里有个坑,我必须要说。nonce 是严格递增的,而且不能跳号。如果你发了一笔 nonce=5 的交易卡住了,那么 nonce=6、7、8 的交易都得排队等着,哪怕你换一个接收方也没用。我曾经在测试网调试时,不小心把 nonce 搞乱了,结果后面几笔交易全部卡死,只能等那笔卡住的交易超时或者被替换。
避坑指南:如果你发现某笔交易一直 pending,不要急着重发相同 nonce 的交易。先检查一下 nonce 是否被占用。用 ethers.js 的 getTransactionCount() 方法可以查到当前地址的 nonce 值。
2.3 Gas与手续费:为什么你的交易会失败?
Gas 是以太坊上最让人头疼,但也最核心的概念。简单说,Gas 是衡量计算工作量的单位。你每执行一条指令,EVM 都会消耗一定量的 Gas。
手续费的计算公式:
交易手续费 = Gas Used × (Base Fee + Priority Fee)
- Gas Used:实际消耗的 Gas 量。比如一笔简单的 ETH 转账固定消耗 21000 Gas。
- Base Fee:基础费用,由网络拥堵程度决定,会被销毁(EIP-1559 引入)。
- Priority Fee:小费,你给矿工/验证者的激励,越高越容易被优先打包。
为什么交易会失败?最常见的原因就是 Gas 不够。你设置的 gasLimit 太低,EVM 执行到一半发现 Gas 用完了,就会回滚所有状态变化,但已经消耗的 Gas 不会退还。嗯,这里要注意:失败的交易也要付手续费,因为计算资源确实被使用了。
我刚开始写合约时,经常在循环里踩坑。比如一个 for 循环,如果数组长度不可控,Gas 消耗就可能爆炸。你想想看,如果有人故意传一个超长的数组进来,你的合约可能直接耗尽 Gas 导致交易失败,甚至把调用者也拖垮。
我的建议:在合约里尽量避免无上限的循环。如果实在需要,可以用 require 限制最大迭代次数,或者改用“拉取模式”(Pull over Push)让用户自己分批处理。
2.4 钱包与私钥管理:你的命根子
私钥是什么?它就是你对以太坊账户的绝对控制权。谁掌握了私钥,谁就能动用该账户下的所有资产。所以私钥管理,是区块链开发者的基本功,也是最重要的安全防线。
常见的钱包类型:
- 软件钱包:如 MetaMask、imToken。方便,但私钥存在本地,容易被木马或钓鱼攻击。
- 硬件钱包:如 Ledger、Trezor。私钥存储在专用芯片里,交易需要物理确认。我个人强烈建议,但凡涉及主网资产,都用硬件钱包。
- 纸钱包:把私钥或助记词写在纸上。离线存储,但容易丢失或损坏。
助记词(Mnemonic)是私钥的另一种表现形式。它由 12 或 24 个英文单词组成,通过 BIP39 协议可以推导出私钥。记住:助记词 = 私钥,泄露助记词等于交出所有资产。
我曾经犯过的错:有一次我把测试网的助记词截图发到了团队群里,想着反正是测试网没关系。结果那个助记词对应的地址,后来被我误用来部署了一个有真实价值的合约。虽然最后及时转移了资产,但这件事让我后怕了很久。从此以后,我养成了一个习惯:主网和测试网用完全不同的助记词,且永远不截图、不拍照、不复制到剪贴板。
关于私钥的存储,我给出几条铁律:
- 永远不要硬编码私钥。不要在代码里写死私钥,不要提交到 GitHub。用环境变量或者专门的密钥管理服务。
- 加密存储。如果必须存文件,用 AES 或类似算法加密,且密码要足够复杂。
- 多签和冷热分离。大额资金建议用多签钱包(如 Gnosis Safe),日常操作用热钱包,大额转账走冷钱包签名。
- 定期检查授权。你授权给 DeFi 协议的额度,如果不撤销,别人理论上可以一直动用你的资产。用 revoke.cash 这类工具定期清理不必要的授权。
好了,这一章的基础内容就这些。别看都是概念,但每一个都跟后面的智能合约开发息息相关。下一章我们就要开始动手写第一个合约了,到时候你会回来感谢这些基础的。