以太坊作为全球领先的智能合约平台,不仅是加密货币的生态基础,更是区块链应用创新的“操作系统”,对于开发者而言,“以太坊开发演练”不仅是掌握智能合约编程、DApp搭建的必经之路,更是理解去中心化思想、探索Web3未来窗口,本文将以实战为导向,带你从环境搭建到合约部署,完整演练一个简单DApp的开发全流程。
为什么需要以太坊开发演练
在传统互联网中,应用依赖中心化服务器存储数据、执行逻辑;而在以太坊生态中,智能合约取代了服务器——它是一段部署在区块链上的代码,一旦部署便不可篡改,且能被全球用户调用,开发演练的核心目标,正是理解“智能合约如何替代传统逻辑”,并掌握“前端如何与区块链交互”。
通过演练,你将学会:
- 使用Solidity编写智能合约(以太坊的“智能合约语言”);
- 通过Truffle、Hardhat等框架管理项目、编译部署合约;
- 使用Web3.js或Ethers.js让前端与以太坊节点通信;
- 理解 gas、账户、节点等核心概念。
开发前准备:工具与环境搭建
“工欲善其事,必先利其器”,以太坊开发需要一套完整的工具链,以下是基础环境配置:
-
安装Node.js与npm
以太坊开发依赖JavaScript生态,需安装Node.js(建议v16+)及包管理器npm,通过终端运行node -v和npm -v确认安装成功。 -
安装代码编辑器
VS Code是开发者的首选,配合Solidity插件(如Hardhat for VS Code)可实现语法高亮、智能提示,大幅提升编码效率。 -
安装以太坊节点工具
- Truffle:最受欢迎的以太坊开发框架,提供编译、测试、部署合约的一站式解决方案。
npm install -g truffle
- Ganache:个人区块链节点工具,可一键启动本地私有链,自动生成10个测试账户,方便开发调试(支持GUI和CLI版本)。
- MetaMask:浏览器钱包插件,用于管理测试账户、与DApp交互(开发时需切换至“本地网络”)。
- Truffle:最受欢迎的以太坊开发框架,提供编译、测试、部署合约的一站式解决方案。
-
创建项目目录
初始化一个空项目,并安装Truffle和Ganache:mkdir my-first-dapp && cd my-first-dapp npm init -y npx truffle init # 初始化Truffle项目结构
实战演练:构建一个简单的“任务清单”DApp
本次演练的DApp功能类似传统“Todo List”,但数据存储在以太坊区块链上,具备去中心化、不可篡改的特性,开发流程分为“智能合约编写→合约测试→前端交互→部署上线”四步。
步骤1:编写智能合约(Solidity)
Truffle初始化后,项目目录会包含 contracts/ 文件夹(存放合约代码),我们在这里创建 Todo.sol:
// contracts/Todo.sol
pragma solidity ^0.8.0; // 指定Solidity版本
contract Todo {
struct Task {
uint id; // 任务ID
string content; // 任务内容
bool completed; // 是否完成
}
mapping(uint => Task) public tasks; // 存储任务列表
uint public taskCount = 0; // 任务计数器
// 添加任务
function createTask(string memory _content) public {
taskCount++;
tasks[taskCount] = Task(taskCount, _content, false);
}
// 切换任务完成状态
function toggleTask(uint _id) public {
Task storage task = tasks[_id];
require(task.id != 0, "Task does not exist"); // 检查任务是否存在
task.completed = !task.completed;
}
// 获取任务数量(供前端调用)
function getTaskCount() public view returns (uint) {
return taskCount;
}
}
关键点:
struct定义任务数据结构;mapping类似哈希表,存储任务键值对;public关键字自动生成getter函数,可直接通过合约调用;memory关键字标识函数参数存储在内存中(适用于临时数据)。
步骤2:测试智能合约(Truffle)

代码写完后,需通过测试确保逻辑正确,在 test/ 文件夹创建 todo.test.js(使用JavaScript编写测试用例):
// test/todo.test.js
const Todo = artifacts.require("Todo"); // 引入合约
contract("Todo", (accounts) => {
let todoInstance;
const creator = accounts[0]; // 使用Ganache生成的第一个测试账户
beforeEach(async () => {
todoInstance = await Todo.new(); // 部署新合约实例
});
it("should create a new task", async () => {
await todoInstance.createTask("Learn Ethereum", { from: creator });
const task = await todoInstance.tasks(1);
assert.equal(task.content, "Learn Ethereum", "Task content mismatch");
assert.equal(task.completed, false, "Task should not be completed");
});
it("should toggle task status", async () => {
await todoInstance.createTask("Test task", { from: creator });
await todoInstance.toggleTask(1, { from: creator });
const task = await todoInstance.tasks(1);
assert.equal(task.completed, true, "Task should be completed");
});
});
运行测试:
truffle test
测试通过后,说明合约逻辑正确,可进入部署阶段。
步骤3:构建前端交互界面
DApp的前端需实现“显示任务列表”“添加任务”“切换任务状态”功能,并通过MetaMask与区块链交互。
-
安装前端依赖
在项目根目录创建frontend/文件夹,初始化React项目(或使用HTML+JS):npx create-react-app frontend cd frontend npm install ethers # 以太坊交互库(比Web3.js更现代)
-
编写前端代码
修改frontend/src/App.js,实现核心交互逻辑:
// frontend/src/App.js
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import Todo from "./contracts/Todo.json"; // 编译后的合约ABI(需从build/contracts复制)
function App() {
const [account, setAccount] = useState("");
const [contract, setContract] = useState(null);
const [tasks, setTasks] = useState([]);
const [newTask, setNewTask] = useState("");
// 初始化:连接MetaMask、加载合约
useEffect(() => {
const loadBlockchainData = async () => {
// 1. 连接MetaMask获取账户
if (window.ethereum) {
const accounts = await window.ethereum.request({ method: "eth_requestAccounts" });
setAccount(accounts[0]);
// 2. 连接以太坊节点(使用MetaMask的RPC)
const provider = new ethers.providers.Web3Provider(window.ethereum);
const networkId = await provider.getNetwork();
// 3. 加载合约实例
const deployedContract = new ethers.Contract(
Todo.networks[networkId.id].address, // 合约地址(需从Truffle部署获取)
Todo.abi, // 合约ABI
provider.getSigner() // 签名者(用于发起交易)
);
setContract(deployedContract);
// 4. 加载任务列表
const taskCount = await deployedContract.getTaskCount();
const loadedTasks = [];
for (let i = 1; i <= taskCount; i++) {
const task = await deployedContract.tasks(i);
loadedTasks.push({ id: task.id, content: task.content, completed: task.completed });
}
setTasks(loadedTasks);
} else {
alert("Please install MetaMask!");
}
};
loadBlockchainData();
}, []);
// 添加任务
const addTask = async () => {
if (newTask.trim() === "") return;
const tx = await contract.createTask(newTask);
await tx.wait(); // 等待交易确认
setNewTask(""); // 清空输入框
// 重新加载任务列表
const taskCount = await contract.getTaskCount();
const loadedTasks = [];
for (let i = 1; i <= taskCount; i++) {
const task = await contract.tasks(i);
loadedTasks.push({ id: task.id, content: task.content, completed: task.completed });
}
setTasks(loaded








