以太坊不仅是数字货币平台,更是全球可编程的分布式计算机。其核心是被称为 EVM(Ethereum Virtual Machine)的图灵完备虚拟机。本文将深入剖析 EVM 的架构、Gas 经济模型、账户体系以及支撑整个网络的状态存储结构。
一、以太坊账户体系
以太坊有两种账户类型:
外部拥有账户(EOA)
由私钥控制的人类用户钱包地址。
type EOAAccount struct {
Nonce uint64 // 交易计数器,防重放
Balance *big.Int // ETH 余额(单位:Wei,1 ETH = 10⁸ Wei)
// 无 CodeHash、StorageRoot
}
特点:
- 只能发起交易(转账或调用合约)
- 无法存储代码(无智能合约逻辑)
- 每笔交易必须由 EOA 触发(支付 Gas 费)
合约账户(Contract)
包含部署代码和状态的自动执行账户。
type ContractAccount struct {
Nonce uint64
Balance *big.Int
StorageRoot []byte // 指向该合约的状态存储(MPT 根)
CodeHash []byte // 部署的 EVM 字节码哈希
}
特点:
- 无私钥,由代码逻辑控制
- 收到交易 / 被其他合约调用时自动执行代码
- 发起交易的能力受限(合约不能主动发起交易,只能在外部触发下响应)
- 可持有 ETH,进行代币转账或调用其他合约
账户核心差异
| 特性 | EOA | 合约账户 |
|---|---|---|
| 控制方式 | 私钥签名 | 代码逻辑 |
| 能否部署代码 | 否 | 是(部署时写入) |
| 能否主动发起交易 | 是 | 否(仅被动响应) |
| 是否有存储状态 | 否 | 是 |
二、Gas:以太坊的经济安全阀
为什么需要 Gas?
EVM 是图灵完备的——如果不限制计算资源,恶意用户可通过无限循环攻击导致全网瘫痪。Gas 作为计价单位,将计算、存储、IO 操作量化为经济成本。
Gas 计费公式(London 升级后)
每笔交易的总手续费计算方式:
$$ \text{总费用} = \text{GasLimit} \times (\text{BaseFee} + \text{MaxPriorityFee}) $$
| 参数 | 含义 | 来源 |
|---|---|---|
GasLimit | 交易消耗的最大 Gas 上限 | 用户设置 |
BaseFee | 基础费用,按区块利用率动态调整,销毁 | 协议自动计算 |
MaxPriorityFee | 给验证人的小费(优先打包激励) | 用户设置 |
| 实际支付给验证人的费用 | GasUsed × Min(MaxPriorityFee, MaxFee - BaseFee) | 实际结算 |
BaseFee 调整机制:
- 区块利用率 > 50% → BaseFee 上升(最高 +12.5%/区块)
- 区块利用率 < 50% → BaseFee 下降
- 目标:让每个区块刚好消耗 1500 万 Gas(Gas 目标是区块上限的 50%)
常见操作的 Gas 成本
| 操作 | Gas 消耗 | 说明 |
|---|---|---|
| EOA 转账 | 21,000 | 固定开销 |
| SSTORE(写入新存储槽) | 20,000 | 冷存储写入 |
| SSTORE(更新已有槽) | 5,000 | 热存储更新 |
| SLOAD(首次读取) | 2,100 | 冷存储读取 |
| SLOAD(重复读取) | 100 | 热存储读取 |
| CREATE(部署合约) | 32,000 + 200 × 字节数 | 包含代码初始化成本 |
| LOG0-LOG4 | 375 + 75 × topic数 + 8 × data字节 | 事件日志记录 |
💡 省钱技巧:
SSTORE第一次写入和将非零值改回零的退款机制(删除数据最高退 19,000 Gas)意味着清理无用状态可以获得 Gas 退款。
三、EVM 架构详解
执行上下文
┌─────────────────────────────────────┐
│ EVM Execution │
│ │
│ Stack (1024 slots, 256-bit word) │
│ ┌───┬───┬───┬───┬───┬───┐ │
│ │ │ │ │ │ │ │ │
│ └───┴───┴───┴───┴───┴───┘ │
│ ▲ │
│ │ │
│ ┌────┴────┐ ┌─────────────┐ │
│ │ PC │ │ Memory │ │
│ │Program │ │ (byte array)│ │
│ │ Counter │ │ 按需扩容 │ │
│ └─────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌───────────────┐ │
│ │ Storage │ │ Calldata │ │
│ │ (256→256bit│ │ (只读,外部传入)│ │
│ │ merkle trie)│ └───────────────┘ │
│ └─────────────┘ │
│ │
│ GasMeter: 追踪剩余 Gas,OutOfGas │
│ ReturnDataBuffer: 子调用返回结果 │
└─────────────────────────────────────┘
EVM 的核心设计约束
- 基于栈(Stack-based):所有操作都通过栈进行,没有寄存器概念
- 256-bit 字长:适配 Keccak256 哈希和椭圆曲线数字的大小
- 确定性执行:相同输入 + 相同状态 → 必定产生相同输出和状态变更
- 顺序执行:不支持真正的并行(这是性能瓶颈,也是 Layer2 的价值所在)
四、世界状态存储:Merkle Patricia Trie
以太坊需要高效地存储和验证整个网络的状态(所有账户的余额、Nonce、合约代码和存储)。解决方案是 MPT(Merkle Patricia Trie)。
Trie 的层次结构
World State Trie (State Trie)
├── 根节点 = 全局状态默克尔根(存储在区块头中)
│ ├── 地址分支 0x0... → 账户 A (Balance, Nonce, CodeHash, StorageRoot)
│ ├── 地址分支 0x1... → 账户 B
│ └── ...
│
且每个合约账户有一个子 Tree:
│
Account Storage Trie
├── slot 0 → value
├── slot 1 → value
└── ...
四个 Trie 的协同工作
| Trie | 存储内容 | 作用 |
|---|---|---|
| State Trie | 所有账户信息 | 验证任意地址的余额 / Nonce |
| Storage Trie | 每个合约的存储槽 | 验证合约内部状态 |
| Transaction Trie | 区块内所有交易 | 验证交易是否包含在区块中 |
| Receipt Trie | 交易收据(Gas 消耗、日志等) | 验证事件日志 |
状态爆炸与状态管理方案
以太坊的历史状态数据已超过 1TB+,导致全节点门槛极高。正在推进的解决方案:
- Verkle Trees:替代 MPT,通过向量承诺将证明大小从 O(log n) 降到更小
- 状态过期 / 历史过期:旧状态自动归档,仅维持最近几个区块的状态
- 无状态验证(Statelessness):区块见证(witness)替代完整状态存储
五、EIP-1559 手续费机制的经济影响
传统机制的问题(London 升级前)
采用简单竞价模式(first-price auction):
- 用户盲猜 GasPrice → 支付过高或交易滞留
- 矿工可直接提取 MEV(Maximal Extractable Value)
- 费用波动剧烈,用户体验差
EIP-1559 的改进
旧机制:Fee = GasUsed × GasPrice(全部给矿工)
新机制:Fee = GasUsed × (BaseFee + PriorityFee)
BaseFee 销毁(通缩压力)
PriorityFee 给验证人
效果:
- 费用可预测:BaseFee 协议自动调整,用户只需设小费
- ETH 通缩:网络活跃时 BaseFee 销毁量 > 增发量(合并后多个时期呈通缩)
- 减少 MEV:协议费用透明化,降低矿工操纵空间
六、本章小结
以太坊通过 EVM + 账户模型 + Gas 经济 + MPT 状态树 四大支柱,构建了一个去中心化的可编程计算平台。EVM 的确定性执行保证了全网一致性,Gas 机制防止了资源滥用,而 EIP-1559 则在经济模型上实现了费用可预测性和 ETH 的通缩设计。理解这些底层原理,是进行 Solidity 智能合约开发与性能优化的必要基础。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。