跳到主要内容

以太坊与智能合约

以太坊是目前最流行的智能合约平台,它扩展了比特币的功能,允许开发者在区块链上部署任意代码。本章将深入介绍以太坊的技术架构和智能合约的工作原理。

以太坊概述​

以太坊由 Vitalik Buterin 在 2013 年提出,2015 年正式上线。与比特币主要作为价值存储不同,以太坊被设计成一个可编程的区块链平台,支持智能合约和去中心化应用。

以太坊的特点​

图灵完备:以太坊虚拟机(EVM)支持循环和复杂计算,理论上可以执行任意算法。这通过 Gas 机制防止无限循环。

账户模型:以太坊采用账户模型而非 UTXO 模型,更易于编程和理解。账户存储余额、代码和状态。

智能合约:开发者可以部署代码到区块链,代码自动执行且不可篡改。这为去中心化应用提供了基础。

快速出块:以太坊出块时间约 12-15 秒(PoS 后约 12 秒),比比特币的 10 分钟快得多。

以太坊的发展阶段​

以太坊的发展分为四个主要阶段:

阶段名称时间主要更新
阶段 0信标链2020.12PoS 链上线
阶段 1合并2022.09PoW 转 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 执行流程​

  1. 从字节码中读取下一个操作码
  2. 根据操作码获取操作数(从栈中弹出)
  3. 执行操作
  4. 将结果压入栈
  5. 扣除相应 Gas
  6. 重复直到遇到 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
  • 单个合约管理多种代币
  • 适合游戏道具等场景

以太坊测试网​

在主网部署前,开发者通常在测试网测试合约。主要的测试网:

测试网共识机制说明
SepoliaPoS最新的测试网,推荐使用
GoerliPoS即将弃用
HoleskyPoS新的质押测试网

获取测试 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 编程语言,开始编写智能合约。

参考资料​