区块链学习 1 - 基于 Geth 搭建私链
最近申请了一张 U 卡,基于 USDC 进行充值,然后提现到 U 卡进行消费。这让我想起了 19 年挖过人人影视的 CVNT 币,当时也是可以闪兑成 ETH 的。
当时好奇 ETH 的原理,但没有现在学习这么方便(有 AI 加成),一直想搭建私链却没成功,后来在 ETH 的测试链上玩了一段时间(主要想体验一下转账、发币等)。现在各种开源工具非常丰富,技术也趋于成熟,所以决定自己搭建一个私链来研究一下。
其次的目的就是想学习区块链实战,例如如何让业务系统的关键数据上链,如:交易(hash)、文章防伪(hash)、存证(hash)等。
本文基于 Geth 搭建以太坊私链,选择它的理由如下:
- 官方支持:以太坊官方参考实现
- 生态完善:支持 EVM、Solidity、MetaMask、ethers.js
- 场景灵活:公链 / 私链 / 离线私链均可运行
- 资源丰富:文档齐全,社区活跃
准备工作
- 运行环境:Windows 10 + PowerShell。如果是 Linux 环境,只需自行配置环境变量并微调命令格式即可,差异不大。
- 共识机制:Clique PoA。
1. 下载 Geth
下载 Geth 1.13.X 版本,本文使用的是 1.13.15 版本。
[!IMPORTANT] 版本注意:1.13.x 之后的版本不再支持 PoA/PoW 这种“传统执行层单机共识”链。它要求 PoS(合并后)网络,否则你会看到如下报错:
ERROR[01-17|18:18:27.324] Geth only supports PoS networks. Please transition legacy networks using Geth v1.13.x.
2. 安装与配置
- 解压并安装到特定目录,设置好环境变量。
- 准备私链目录结构,例如我的路径是
E:\geth\geth-ledger。
后续所有命令均在此目录下执行。在文件夹内使用 SHIFT + 右键,选择“在此处打开 PowerShell 窗口”。
创建账户
我们需要创建 2 个账户:一个用于出块,一个用于转账测试。
- 出块者:负责签块(PoA)。
- 转账者:负责转账(用于体验,创世时会分配 1000 个 ETH)。
geth --datadir data account new
geth --datadir data account new
返回数据示例:
Public address of the key: 0x2F02cA3b39C3e86566246489787F37C0453888A2
Path of the secret key file: data\keystore\UTC--2026-01-17T09-27-07.047721600Z--2f02ca3b39c3e86566246489787f37c0453888a2
- You can share your public address with anyone. Others need it to interact with you.
- You must NEVER share the secret key with anyone! The key controls access to your funds!
- You must BACKUP your key file! Without the key, it's impossible to access account funds!
- You must REMEMBER your password! Without the password, it's impossible to decrypt the key!
- 执行后会提示输入密码,请务必牢记!
- 目录下会生成一个
keystore文件,里面存储了加密后的私钥。
保存密码到文件
为了方便后续启动,我们将密码保存到文件中(请妥善保管):
PowerShell (Windows):
Set-Content -Path .\miner.pass -Value "miner_password" -NoNewline -Encoding ASCII
Set-Content -Path .\biz.pass -Value "biz_password" -NoNewline -Encoding ASCII
Bash (Linux):
echo "miner_password" > miner.pass
echo "biz_password" > biz.pass
在本教程中,我的地址分配如下:
- 出块者地址 (miner):
0x2F02cA3b39C3e86566246489787F37C0453888A2 - 转账者地址 (biz):
0xe8aCb15b1d4dB40292B10C8169d369dff180C2f9
创建 genesis.json 文件
这是 Clique (PoA) 私链的创世块配置文件。
{
"config": {
"chainId": 202601,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"clique": {
"period": 2,
"epoch": 30000
}
},
"nonce": "0x0",
"timestamp": "0x0",
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000002f02ca3b39c3e86566246489787f37c0453888a2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x2FAF080",
"difficulty": "0x1",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {
"0xe8aCb15b1d4dB40292B10C8169d369dff180C2f9": { "balance": "0x3635C9ADC5DEA00000" }
带注释版本:
{
"config": {
// 链ID:用于交易签名防重放;与你的 networkid 不强制相等,但通常保持一致更清晰
"chainId": 202601, // 链ID,必须唯一,不能和主网、测试网冲突
// 下面这些 *Block=0 表示:从创世块开始就启用对应的硬分叉规则
// 好处:规则一致、少踩坑;坏处:没什么坏处(私链推荐这样写)
"homesteadBlock": 0, // 升级到 Homestead 协议的区块高度
"eip150Block": 0, // 升级到 EIP150 协议的区块高度
"eip155Block": 0, // 升级到 EIP155 协议的区块高度
"eip158Block": 0, // 升级到 EIP158 协议的区块高度
"byzantiumBlock": 0, // 升级到 Byzantium 协议的区块高度
"constantinopleBlock": 0, // 升级到 Constantinople 协议的区块高度
"petersburgBlock": 0, // 升级到 Petersburg 协议的区块高度
"istanbulBlock": 0, // 升级到 Istanbul 协议的区块高度
"clique": { "period": 2, "epoch": 30000 } // Clique 共识机制配置
},
"nonce": "0x0", // 随机数,用于挖矿
"timestamp": "0x0", // 时间戳,创世区块时间
"extraData": "0x00000000000000000000000000000000000000000000000000000000000000002f02ca3b39c3e86566246489787f37c0453888a2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", // 额外数据,包含出块者地址
"gasLimit": "0x2FAF080", // 创世区块的 Gas 上限
"difficulty": "0x1", // 创世区块的难度
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", // 混合哈希
"coinbase": "0x0000000000000000000000000000000000000000", // 创世区块的矿工地址
"alloc": { // 创世区块的预分配账户
"0xe8aCb15b1d4dB40292B10C8169d369dff180C2f9": { "balance": "0x3635C9ADC5DEA00000" } // 预分配1000个ETH
}
}
更详细查看genesis.json 详解
初始化链
只用执行一次,除非你想重置。
geth --datadir data init genesis.json
执行后,会在运行目录下生成 data 生成相关文件。
启动 signer 节点(PowerShell)
geth `
--datadir data `
--networkid 202601 `
--http --http.addr 0.0.0.0 --http.port 8545 `
--http.api eth,net,web3,txpool,admin `
--http.corsdomain "*" --http.vhosts "*" `
--allow-insecure-unlock `
--unlock 0x2F02cA3b39C3e86566246489787F37C0453888A2 --password miner.pass `
--mine --miner.etherbase 0x2F02cA3b39C3e86566246489787F37C0453888A2 `
--txpool.pricelimit 0
带注释版本:
# 使用 PowerShell 的反引号 ` 作为换行续写符
geth `
# 指定区块数据、状态数据、keystore 的存放目录
# 不写的话默认是 ~/.ethereum
# 私链/多链并行时一定要显式指定
--datadir data `
# 网络 ID(P2P 层用)
# 必须与 genesis.json 中的 chainId 区分理解
# networkid 用来防止节点连错网络
--networkid 202601 `
# 开启 HTTP RPC 服务(旧称 JSON-RPC)
# 业务系统、脚本、控制台通常都通过它与 geth 交互
--http `
# HTTP RPC 监听地址
# 0.0.0.0 表示对外暴露(局域网/容器/宿主机可访问)
--http.addr 0.0.0.0 `
# HTTP RPC 监听端口(以太坊传统默认 8545)
--http.port 8545 `
# 允许通过 HTTP RPC 调用的 API 模块
# eth : 区块、交易、合约相关核心接口
# net : 网络信息(networkId、peer 数等)
# web3 : 工具类接口(编码、hash 等)
# txpool : 交易池状态(pending / queued)
# admin : 节点管理(peers、enode、addPeer 等,生产环境要谨慎)
--http.api eth,net,web3,txpool,admin `
# 允许任意来源的跨域请求(CORS)
# 方便浏览器、前端、内部系统直接访问
--http.corsdomain "*" `
# 允许任意 Host 头访问 HTTP RPC
# 在 Docker / 反向代理 / 内网环境中很常见
--http.vhosts "*" `
# 允许通过 RPC 解锁账户(非常危险的能力)
# 在私链、内网、测试环境中常用
# 生产环境一般禁用
--allow-insecure-unlock `
# 启动时解锁指定账户
# 该账户通常是:
# - Clique 的 signer(出块账户)
# - 或业务服务用于发送交易的账户
--unlock 0x2F02cA3b39C3e86566246489787F37C0453888A2 `
# 解锁账户所使用的密码文件
# 文件内容是纯文本密码
--password miner.pass `
# 开启挖矿(在 Clique 中含义是:参与出块/签名)
# 如果不加这个参数,节点只同步,不会出块
--mine `
# 指定出块收益地址 / 签名者地址
# 在 Clique 中通常与 --unlock 的账户相同
--miner.etherbase 0x2F02cA3b39C3e86566246489787F37C0453888A2 `
# 设置交易池最低 gas price
# 0 表示:接受所有交易(即使 gasPrice = 0)
# 私链里非常常见,避免“没钱发不了交易”
--txpool.pricelimit 0
此时要是没有错误,输出类似:
INFO [01-19|22:37:23.582] Maximum peer count ETH=50 total=50
WARN [01-19|22:37:23.600] Lowering memory allowance on 32bit arch available=65460 addressable=2048
WARN [01-19|22:37:23.600] Sanitizing cache to Go's GC limits provided=1024 updated=682
INFO [01-19|22:37:23.600] Set global gas cap cap=50,000,000
INFO [01-19|22:37:23.602] Initializing the KZG library backend=gokzg
INFO [01-19|22:37:23.687] Allocated trie memory caches clean=102.00MiB dirty=170.00MiB
INFO [01-19|22:37:23.688] Using pebble as the backing database
INFO [01-19|22:37:23.688] Allocated cache and file handles database=E:\geth\geth-ledger\data\geth\chaindata cache=341.00MiB handles=8192
INFO [01-19|22:37:23.944] Opened ancient database database=E:\geth\geth-ledger\data\geth\chaindata\ancient/chain readonly=false
INFO [01-19|22:37:23.945] State scheme set to already existing scheme=hash
INFO [01-19|22:37:23.949] Initialising Ethereum protocol network=202,601 dbversion=8
INFO [01-19|22:37:54.864] Looking for peers peercount=0 tried=22 static=0
INFO [01-19|22:37:56.005] Successfully sealed new block number=29638 sealhash=8f8d95..7a6364 hash=867994..fb1bd1 elapsed=2.000s
INFO [01-19|22:37:56.005] Commit new sealing work number=29639 sealhash=7be5a2..646ead txs=0 gas=0 fees=0 elapsed=0s
INFO [01-19|22:37:58.005] Successfully sealed new block number=29639 sealhash=7be5a2..646ead hash=76321e..2e22ae elapsed=1.999s
INFO [01-19|22:37:58.005] Commit new sealing work number=29640 sealhash=1c9f2d..35c595 txs=0 gas=0 fees=0 elapsed="27.2µs"
INFO [01-19|22:38:00.004] Successfully sealed new block number=29640 sealhash=1c9f2d..35c595 hash=53ecc6..63b509 elapsed=1.999s
INFO [01-19|22:38:00.004] Commit new sealing work number=29641 sealhash=2b4a8a..d9688c txs=0 gas=0 fees=0 elapsed=0s
那就代表出快了。
验证测试
浏览器安装MetaMask扩展
到各自浏览器的扩展商店搜索MetaMask并安装。
导入钱包
在MetaMask中点击“添加钱包”,类型选择“JSON文件”(选择biz账户,里面有我们分配的1000ETH)

选择刚才生成的keystore文件,输入密码,等待1-5分钟即可导入成功。

配置MetaMask连接到私链
此时导入的钱包并没有ETH,我们需要在 MetaMask 切换到本地网络。
网络名称:本地测试网络
新 RPC URL:http://localhost:8545
链 ID:202601
货币符号:ETH(随意)

选择本地测试网络

这时,就能看见1000ETH了。(我已经用了一些)

发送交易

可以临时转到第一步生成的出块者地址,当然,你也可以再创建一个钱包测试。
这里,我的数量输入 10。

点击发送,MetaMask 会弹出确认窗口。这里可以更改燃料价格,因为我们在启动时设置了参数pricelimit,所以可以为 0。
燃料限制为ETH内置常量(这是怎么计算的,查看详情)


验证交易
此时,可以用MetaMask导入收币的钱包,变能看见余额增加了。
下一节,部署合约,让业务系统的业务数据上链。
编写中……
此篇内容仅为搭建记录,其中关于很多名词,我放在WIKI中了,避免污染格式。如有兴趣,可以去WIKI查看。