欢迎来到激动人心的以太坊世界!以太坊作为全球领先的智能合约平台,不仅加密货币,更是一个去中心化的应用(DApp)生态系统,本教程将“手把手”带你从零开始,了解以太坊的核心概念,并一步步动手实践,最终构建一个简单的智能合约和与之交互的前端应用。
第一部分:以太坊基础入门——你需要知道什么?
在敲下第一行代码之前,让我们先快速了解几个核心概念:
- 区块链与以太坊:区块链是一种分布式账本技术,以太坊则是基于区块链技术的开源平台,它允许开发者构建和部署智能合约。
- 智能合约:智能合约是运行在以太坊区块链上的自动执行的程序,它们在满足预设条件时会被触发,不可篡改,无需第三方干预,一个简单的代币转账合约。
- 以太坊虚拟机 (EVM):以太坊虚拟机是以太坊的“计算机”,它执行智能合约代码,确保所有节点对计算结果达成一致。
- 账户 (Accounts):以太坊上有两种账户:外部账户(由用户通过私钥控制,如你的MetaMask钱包)和合约账户(由代码控制),账户之间通过交易进行交互。
- Gas (燃料):在以太坊网络上执行任何操作(如转账、调用合约)都需要支付Gas,这是为了防止网络滥用和补偿计算资源,Gas价格由市场供需决定。
- 钱包与MetaMask:钱包是你管理以太坊账户、私钥、进行交易的工具,MetaMask是最流行的浏览器钱包插件,我们将用它来与以太坊网络交互。
第二部分:环境搭建——你的以太坊开发工具箱
要开始开发,我们需要安装和配置一些工具:
- 安装Node.js 和 npm:Node.js是一个JavaScript运行时,npm是Node.js的包管理器,前往 Node.js官网 下载并安装LTS版本。
- 安装MetaMask:在浏览器(如Chrome、Firefox)中访问MetaMask官网,安装插件,并按照提示创建钱包。务必妥善保存你的助记词!
- 安装代码编辑器:Visual Studio Code (VS Code) 是目前最受欢迎的代码编辑器之一,安装它并推荐一些Solidity相关插件(如Solidity by Juan Blanco)。
- 安装Truffle框架:Truffle是以太坊最受欢迎的开发框架之一,它简化了智能合约的编译、测试和部署流程,打开终端(命令行工具),运行:
npm install -g truffle
- 安装Ganache:Ganache是一个个人以太坊区块链,它为你提供一个本地测试环境,可以快速生成测试账户并查看交易详情,你可以下载Ganache桌面版,或者使用其命令行版本(
npm install -g ganache-cli)。
第三部分:创建你的第一个以太坊项目——“Hello, DApp!”
让我们动手创建一个项目结构:
-
创建项目目录:
mkdir my-first-dapp cd my-first-dapp
-
初始化Truffle项目:
truffle init
这会生成一些标准目录结构:
contracts/: 存放Solidity智能合约文件。migrations/: 存放部署脚本文件。test/: 存放测试文件。truffle-config.js: Truffle配置文件。
-
启动Ganache:打开Ganache,点击“QUICKSTART”,它会为你创建一个本地区块链,并提供10个测试账户,每个账户有100个测试用的ETH。
-
配置Truffle连接Ganache: 打开
truffle-config.js,在networks对象中添加Ganache的配置(默认端口是7545):module.exports = { // ... 其他配置 networks: { development: { host: "127.0.0.1", // Localhost (default: none) port: 7545, // Standard Ethereum port (default: none) network_id: "*", // Any network (default: none) }, }, // ... 其他配置 };
第四部分:编写你的第一个智能合约
我们将编写一个简单的“存储合约”,允许用户存储和读取一个字符串。
-
创建合约文件:在
contracts目录下创建一个新的文件Storage.sol。 -
编写合约代码:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract Storage { string private myString; event StringSet(string _newString); function set(string memory _newString) public { myString = _newString; emit StringSet(_newString); } function get() public view returns (string memory) { return myString; } }SPDX-License-Identifier和pragma solidity是合约的标准开头。string private myString: 声明一个私有的字符串变量。event StringSet: 定义一个事件,用于通知外部世界字符串已被设置。set函数:用于设置字符串的值,并触发事件。get函数:用于获取当前存储的字符串值。
-
编译合约:在项目根目录的终端中运行:
truffle compile
如果成功,你会在
build/contracts目录下看到编译后的合约JSON文件。
第五部分:部署智能合约
现在我们将编译好的合约部署到Ganache本地网络上。
-
创建迁移脚本:在
migrations目录下创建一个新的文件,2_deploy_storage.js(数字前缀表示部署顺序)。const Storage = artifacts.require("Storage"); module.exports = function (deployer) { deployer.deploy(Storage); }; -
执行部署:在终端中运行:
truffle migrate --network development
你会看到Truffle正在部署合约,并且在Ganache界面上能看到新的交易产生,部署成功后,
build/contracts/Storage.json中会包含合约的地址,这个地址很重要!
第六部分:创建前端与智能合约交互
合约部署好了,我们需要一个前端界面来调用它。
-
创建前端目录结构:在项目根目录下创建
src文件夹,用于存放前端代码,在src下创建index.html和app.js。 -
编写HTML (
src/index.html):<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My First DApp</title> <script src="https://cdn.ethers.io/lib/ethers-5.2.umd.min.js" type="application/javascript"></script></head> <body> <h1>以太坊存储合约交互</h1> <div> <label for="newValue">输入新值:</label> <input type="text" id="newValue" placeholder="输入要存储的字符串"> <button onclick="setString()">设置</button> </div> <div><button onclick="getString()">获取当前值</button> <p>当前值: <span id="currentValue"></span></p> </div> <script src="app.js"></script> </body> </html>
-
编写JavaScript交互逻辑 (
src/app.js):let contract; let account; // 替换为你在Ganache中看到的第一个测试账户地址 const defaultAccount = "0xYourFirstGanacheAccountAddressHere"; // 替换为你的合约部署地址 const contractAddress = "0xYourDeployedContractAddressHere"; // 合约ABI (Application Binary Interface),可以从 build/contracts/Storage.json 中复制 const contractABI = [ { "inputs": [], "name": "get", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "_newString", "type": "string" } ], "name": "set", "outputs": [], "stateMutability": "nonpayable", "type": "function"