以太坊与智能合约
以太坊是目前最流行的智能合约平台,它扩展了比特币的功能,允许开发者在区块链上部署任意代码。本章将深入介绍以太坊的技术架构和智能合约的工作原理。
以太坊概述
以太坊由 Vitalik Buterin 在 2013 年提出,2015 年正式上线。与比特币主要作为价值存储不同,以太坊被设计成一个可编程的区块链平台,支持智能合约和去中心化应用。
以太坊的特点
图灵完备:以太坊虚拟机(EVM)支持循环和复杂计算,理论上可以执行任意算法。这通过 Gas 机制防止无限循环。
账户模型:以太坊采用账户模型而非 UTXO 模型,更易于编程和理解。账户存储余额、代码和状态。
智能合约:开发者可以部署代码到区块链,代码自动执行且不可篡改。这为去中心化应用提供了基础。
快速出块:以太坊出块时间约 12-15 秒(PoS 后约 12 秒),比比特币的 10 分钟快得多。
以太坊的发展阶段
以太坊的发展分为四个主要阶段:
| 阶段 | 名称 | 时间 | 主要更新 |
|---|---|---|---|
| 阶段 0 | 信标链 | 2020.12 | PoS 链上线 |
| 阶段 1 | 合并 | 2022.09 | PoW 转 PoS |
| 阶段 2 | 分片 | 进行中 | 提高扩展性 |
| 未来 | 完整分片 | 待定 | 完整的分片链 |
以太坊架构
以太坊的架构可以分为多层,每层负责不同的功能。
网络层
网络层负责节点之间的通信。以太坊使用 DevP2P 协议进行节点发现和消息传输。主要功能包括:
- 节点发现:通过 Kademlia DHT 发现对等节点
- 区块同步:从其他节点下载区块和交易
- 交易广播:将新交易传播到网络
共识层
共识层负责达成区块链状态的一致性。以太坊目前采用 PoS 共识机制。
信标链:信标链是 PoS 的核心,负责管理验证者、组织验证者委员会、处理最终确定性。
验证者:验证者需要质押 32 ETH,负责提议区块和验证区块。作恶会被罚没质押。
最终确定性:以太坊使用 Casper FFG 实现最终确定性。一旦区块被最终确定,就不可回滚。
执行层
执行层负责执行交易和维护状态。主要包括:
- 交易执行:验证交易、执行 EVM 代码、更新状态
- 状态管理:维护世界状态树
- Gas 计算:计算交易消耗的资源
存储层
以太坊使用 Merkle Patricia Trie 存储数据:
- 状态树:存储所有账户的状态
- 存储树:存储合约的存储数据
- 交易树:存储区块内的交易
- 收据树:存储交易执行结果
以太坊虚拟机(EVM)
EVM 是以太坊的核心,它是一个沙盒环境,执行智能合约的字节码。
EVM 特点
沙盒隔离:每个合约在独立的沙盒中执行,无法直接访问其他合约的存储或外部系统。
确定性执行:相同输入必然产生相同输出,保证所有节点执行结果一致。
资源限制:通过 Gas 限制计算资源,防止无限循环。
栈式架构:EVM 是基于栈的虚拟机,操作数从栈中获取,结果压入栈中。
EVM 数据结构
栈:1024 个 256 位字的栈空间,用于存储操作数和中间结果。
内存:临时存储空间,交易执行完毕后清除。按 256 位字寻址,使用时支付 Gas。
存储:持久化存储空间,合约状态存储在这里。256 位到 256 位的键值对映射。
EVM 操作码
EVM 定义了约 150 个操作码,分为以下几类:
| 类别 | 示例操作码 | 说明 |
|---|---|---|
| 算术运算 | ADD, SUB, MUL, DIV | 基本数学运算 |
| 比较运算 | LT, GT, EQ | 比较操作 |
| 位运算 | AND, OR, XOR, NOT | 逻辑运算 |
| 栈操作 | PUSH, POP, DUP, SWAP | 栈管理 |
| 内存操作 | MLOAD, MSTORE | 内存读写 |
| 存储操作 | SLOAD, SSTORE | 持久化存储 |
| 控制流 | JUMP, JUMPI | 跳转指令 |
| 区块信息 | BLOCKHASH, TIMESTAMP | 获取区块信息 |
| 系统操作 | CREATE, CALL, SELFDESTRUCT | 合约交互 |
EVM 执行流程
- 从字节码中读取下一个操作码
- 根据操作码获取操作数(从栈中弹出)
- 执行操作
- 将结果压入栈
- 扣除相应 Gas
- 重复直到遇到 STOP 或 RETURN
智能合约
智能合约是存储在区块链上的程序代码,当满足预设条件时自动执行。
智能合约的特点
不可篡改:合约部署后代码无法修改,保证了协议的可预测性。
自动执行:当被调用时自动执行,无需人工干预。
透明公开:代码和状态对所有人可见,可以被审计。
可信计算:执行结果由共识机制保证,无需信任特定节点。
智能合约的生命周期
编写:使用 Solidity、Vyper 等语言编写合约代码。
编译:将源代码编译为 EVM 字节码和 ABI(应用二进制接口)。
部署:通过交易将字节码部署到区块链,获得合约地址。
调用:通过交易或调用执行合约函数。
销毁:合约可以包含自毁逻辑,销毁后代码和存储被清除。
合约调用方式
交易调用:会修改状态,需要支付 Gas,被矿工打包进区块。由外部账户发起。
// 发送交易调用合约
const tx = await contract.methods.setValue(42).send({
from: '0x...',
gas: 100000,
value: 0
});
静态调用:只读操作,不修改状态,不需要支付 Gas,本地执行。可以由合约或外部账户发起。
// 静态调用读取数据
const value = await contract.methods.getValue().call();
合约间调用
合约可以调用其他合约的函数,主要通过以下操作码:
CALL:调用另一个合约的函数,可以传递 ETH,修改被调用合约的状态。
DELEGATECALL:在调用者的上下文中执行被调用合约的代码,保持 msg.sender 和 msg.value 不变。常用于代理模式。
STATICCALL:保证调用不修改状态,用于视图函数。
以太坊代币标准
以太坊定义了多个代币标准,使得不同项目的代币可以互操作。
ERC-20:同质化代币
ERC-20 是最广泛使用的代币标准,定义了同质化代币的接口。
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
核心功能:
- 查询总供应量和账户余额
- 代币转账
- 授权第三方转账
ERC-721:非同质化代币
ERC-721 定义了非同质化代币(NFT)的标准,每个代币都是独一无二的。
interface IERC721 {
function balanceOf(address owner) external view returns (uint256);
function ownerOf(uint256 tokenId) external view returns (address);
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function safeTransferFrom(address from, address to, uint256 tokenId) external;
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
}
特点:
- 每个 tokenId 唯一
- 可以表示数字艺术品、收藏品等
ERC-1155:多代币标准
ERC-1155 允许一个合约管理多种代币类型,包括同质化和非同质化代币。
interface IERC1155 {
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata amounts, bytes calldata data) external;
}
优势:
- 批量转账,节省 Gas
- 单个合约管理多种代币
- 适合游戏道具等场景
以太坊测试网
在主网部署前,开发者通常在测试网测试合约。主要的测试网:
| 测试网 | 共识机制 | 说明 |
|---|---|---|
| Sepolia | PoS | 最新的测试网,推荐使用 |
| Goerli | PoS | 即将弃用 |
| Holesky | PoS | 新的质押测试网 |
获取测试 ETH 可以通过水龙头(Faucet)网站。
开发环境搭建
安装 Node.js
Web3 开发需要 Node.js 环境,建议使用 LTS 版本。
# 使用 nvm 安装 Node.js
nvm install --lts
nvm use --lts
安装 Hardhat
Hardhat 是最流行的以太坊开发框架。
# 创建项目目录
mkdir my-dapp && cd my-dapp
# 初始化项目
npm init -y
# 安装 Hardhat
npm install --save-dev hardhat
# 初始化 Hardhat 项目
npx hardhat init
项目结构
my-dapp/
├── contracts/ # 智能合约源码
├── scripts/ # 部署脚本
├── test/ # 测试文件
├── hardhat.config.js # Hardhat 配置
└── package.json
小结
本章介绍了以太坊平台的核心概念,包括 EVM、智能合约和代币标准。理解这些基础知识是开发去中心化应用的前提。下一章我们将深入学习 Solidity 编程语言,开始编写智能合约。