Gerrad Zhang
部署到测试网:合约离开本地的第一步

部署到测试网:合约离开本地的第一步

上一篇 Hardhat 工程结尾预告的 M3.3:把只在进程里活着的 Counter 部署到测试网 Sepolia。内容:本地网络、测试网、主网到底差在哪(成本/数据/重置/参与者四维对比);准备工作三件套——水龙头领测试币、为什么需要 Alchemy/Infura 这类 RPC 节点服务、.env 里两项各填什么;部署操作逐条解释(复制 .env.example → 填值 → npx hardhat run scripts/deploy.js --network sepolia);部署后用 Etherscan 测试网版查合约、以及为什么要做合约验证。

Gerrad Zhang
Wuhan, China
2 min read

为什么本地全绿还不够

上一篇(Hardhat 本地测试环境)的结尾留了个尾巴:Counter 合约目前只活在测试进程里——npm test 跑完,内置本地网络连同上面的合约一起消失。测试全绿说明「逻辑对了」,但有一件事它永远证明不了:这条合约在真实以太坊网络上、在真实世界的基础设施上,能不能部署、能不能活下来。

「真的有外部可见的部署」差三样东西:真实的 RPC 连接、真实账户签名的交易、真实(但无价值)代币支付的 Gas 。这些都是 测试网 的领地。本篇就补上这一步:给 dapp/ 工程加部署脚本和网络配置,把 Counter 送上 Sepolia。

先说清一个口径:本文的部署脚本已在本地/模拟网络验证通过npx hardhat run scripts/deploy.js 打印出合约地址、exit 0)。真实测试网部署需要我自己的 RPC 端点和测试私钥,属于按文中步骤即可完成的操作——不是本文的完成条件。


三张网:本地网络 vs 测试网 vs 主网

写部署配置前,先把三个经常被混着叫的「网络」掰开。它们跑的是同一套 EVM 规则,差别在四个维度:

维度本地网络(Hardhat 内置)测试网(Sepolia)主网(Ethereum)
成本免费(虚拟)免费(测试币,无价值)真金白银的 ETH
数据进程内存,跑完就没公开账本,任何人可查公开账本,永久保存
重置每次运行都是新的不能重置,但搞砸无所谓不能重置,搞砸就是事故
参与者只有我和我的测试用例全球开发者 + 少量真实节点全世界的用户和资金
谁能连只有本进程任何人的 RPC 端点任何人的 RPC 端点

用一张图理解它们的关系:

       本地网络                测试网 Sepolia              主网 Ethereum
   ┌─────────────────┐    ┌─────────────────────┐    ┌─────────────────────┐
   │ 我的进程里模拟    │    │ 真实网络,测试币      │    │ 真实网络,真实价值    │
   │ 写测试 → 跑断言   │ →  │ 部署 → 别人能看到    │ →  │ 部署 → 真用户真资金   │
   │ 跑完即焚         │    │ 出错零损失           │    │ 出错无法撤回         │
   └─────────────────┘    └─────────────────────┘    └─────────────────────┘
        验证逻辑                  演练全流程                  承载真价值

为什么中间必须有测试网这一站?因为「逻辑对」和「能上链」之间还隔着:账户有没有币、RPC 配置对不对、交易能不能被打包、gas 够不够。这些环节在本地网络里全是被框架代劳的,只有测试网会把它们真实地暴露出来——但代价为零。跳过测试网直接上主网,等于用真钱做第一次演练。


准备工作:测试币、RPC 节点、.env

测试币从哪来:水龙头

测试网的 gas 要用测试 ETH 支付。Sepolia 的测试 ETH 通过 水龙头 领取:用钱包地址去 faucet 站点提交,几分钟内到账,通常是 0.1–0.5 ETH 的量级——对部署一个 Counter 来说绰绰有余(实际部署交易的花费在 0.001 ETH 以下)。

两个实用提醒:一,新建一个测试专用账户来领币和部署,不要用存有主网资产的账户——测试账户的私钥会频繁进出各种配置文件,从习惯上就应该隔离;二,faucet 普遍有频率限制(隔几小时才能领一次),别把额度浪费在反复试错上,先把下面的 RPC 和 .env 配好再领不迟。

为什么需要第三方 RPC:Alchemy / Infura 的角色

部署交易不会凭空飞到 Sepolia 上——它得先被某个全节点接收、验证、广播、打包。而我自己并不运行以太坊全节点(同步一个要几百 GB 磁盘和数天时间),所以需要一个「替我连网络」的中介:RPC 节点服务。

我的 dapp/ 工程
      │  JSON-RPC(HTTPS)

RPC 节点服务(Alchemy / Infura)──► 它们运营的 Sepolia 全节点
      │                                  │
      ▼                                  ▼
hardhat 用它发交易                     交易进入网络,被验证者打包

Alchemy、Infura 这类服务商的商业模式就是「替你跑节点、卖 API 端点」,免费档对个人开发完全够用。注册 → 创建 App → 选 Sepolia 网络 → 复制 HTTPS 端点,得到一个形如下面的 URL:

https://eth-sepolia.g.alchemy.com/v2/<你的API_KEY>

这个端点就是工程与测试网之间的唯一通道。

.env:两项各填什么

工程里已经放好模板 dapp/.env.example,复制一份再填:

$ cp .env.example .env

# .env 只有两项:
SEPOLIA_RPC_URL=https://eth-sepolia.g.alchemy.com/v2/<你的API_KEY>   # 上一步复制的端点
PRIVATE_KEY=0x<测试专用账户的私钥>                                      # 领了测试币的那个账户

hardhat.config.js 里对应的 sepolia 配置从环境变量读值,文件本身不含任何秘密:

networks: {
  sepolia: {
    url: process.env.SEPOLIA_RPC_URL || "",
    accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
  },
},

部署操作:一条命令上 Sepolia

部署脚本 scripts/deploy.js 很短,逻辑四步:取签名账户 → 取 Counter 合约工厂 → 部署并等确认 → 打印地址:

const { ethers } = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();
  console.log("Deployer address:", deployer.address);

  const Counter = await ethers.getContractFactory("Counter");
  const counter = await Counter.deploy();
  await counter.waitForDeployment();

  console.log("Counter deployed to:", await counter.getAddress());
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

注意脚本里没有任何网络和密钥的硬编码——连向哪里、用谁的身份,全由运行时的参数和配置决定。

第一步,先在本地验证(不传 --network,用默认 hardhat 网络):

$ npx hardhat run scripts/deploy.js
Deployer address: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Counter deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3

两行输出:部署者(Hardhat 预置的 0xf39F… 测试账户)和合约地址(0x5FbD…,本地网络第一个部署的固定地址)。这一步是我在本仓库实际跑通的——它证明脚本、编译、部署流程三者没问题。

第二步,指向 Sepolia 重跑(前提:.env 已配好、测试币已到账):

$ npx hardhat run scripts/deploy.js --network sepolia
Deployer address: 0x<我的测试账户地址>
Counter deployed to: 0x<这次部署拿到的合约地址>

同一个脚本,只多了 --network sepolia。这次背后发生的事完全不同:Hardhat 用 .env 里的 RPC 连上 Alchemy 的节点,用私钥给部署交易签名,交易进入 内存池 等待打包——几十秒后合约地址打印出来,它已经写在 Sepolia 的公开账本上了,任何人可查、无法删除。


部署之后:Etherscan 查合约与验证

拿到合约地址后,去 Etherscan 的测试网版(sepolia.etherscan.io,注意不是主网站)把地址贴进搜索框,能看到:部署交易、区块号、创建者(就是 Deployer address)、合约余额(0)。到这一步,「外部可见的部署」成立——别人用同一个地址也能看到它。

但此时 Etherscan 上只能看到一堆交易记录,看不到合约的源码——链上存的只是 字节码 。这就是「合约验证(verify)」要做的事:把源码和编译配置提交给 Etherscan,它重新编译一遍,若字节码与链上一致,就给合约盖上蓝色的 Verified 募章,之后任何人都能在网页上直接读源码、调用函数。

为什么要做验证?第一,对使用者:未验证的合约是黑盒,没人敢和它交互——这直接关系下一篇的 DApp 有没有人用;第二,对自己:验证页面就是免费的合约调试台,getCount 这类读函数可以直接在 Etherscan 上点。工具上 hardhat-toolbox 已带 verify 插件,npx hardhat verify <地址> --network sepolia 一条命令的事,前提同样是需要 Etherscan 的 API key(放进 .env,套路与 RPC 相同)。


总结:合约就位,等一个前端

本篇给 dapp/ 补齐了最后一块部署能力:.env.example 模板、sepolia 网络配置、scripts/deploy.js 部署脚本。三张网的分工现在很清楚:本地网络管「逻辑对」,测试网管「流程通」,主网管「真价值」。脚本已在本地验证通过,配好 .env 后一条 --network sepolia 就能上测试网,Etherscan 上查地址、做验证,合约从此对外可见。

下一步(M3.4):合约已经就位,但用户不可能用命令行跟它打交道——接下来写第一个完整 DApp:一个网页前端,连钱包、读 count、点按钮调 increment。合约是后端,这一篇补上前端,阶段 3 就闭环了。

相关文章:

Comments

Link copied to clipboard!