之前我们就讲解过HyperLedger Besu的PoA联盟链并且也成功部署到服务器了,那么Geth同为以太坊系列的是不是也安排一下呢...今天它来了。

与之前一样,这次Geth区块链部署也是使用Docker版本部署来避免不同环境带来的不可预料的情况。

1. 下载Docker镜像

首先,先下载geth的docker镜像

yuanzhenhui@MacBook-Pro ~ % docker pull ethereum/client-go:latest 
latest: Pulling from ethereum/client-go 
df20fa9351a1: Downloading 
c91bff5b9242: Pulling fs layer 
5f274eeeb65e: Pulling fs layer 
latest: Pulling from ethereum/client-go 
df20a9351a1: Pull complete 
c91bff5b9242: Pull complete
5274eeeb65e: Pull complete
Digest: sha256:094f1baec8ecc6f73142cf2aa135dc9741b8593219b09d88cac672eb715b66c
Status:Downloadednewerimageforethereum/client-go:latest
docker.io/ethereum/client-go:latest

与Besu不一样,geth的引导节点镜像要另外下载,如下图:

yuanzhenhui@MacBook-Pro ~ % docker pull hawyasunaga/ethereum-bootnode :latest
latest: Pulling from hawyasunaga/ethereum-bootnode 
88286f41530e: Pull complete
c9849f710038: Pull complete
Digest: sha256: c3a855ade 70648864ec263c1cfee3719532677ada69da1d21c4897cdfbfc351e
Status: Downloaded newer image for hawyasunaga/ethereum-bootnode: latest
docker.io/hawvasunaaa/ethereum-bootnode:latest

2. 部署引导节点

镜像下载下来后就可以配置并部署引导节点了,如下脚本:

docker run -itd -m 256M --privileged=true \
--memory-swap -1 \
-p 30301:30301/udp \
-p 30301:30301/tcp \
-v /Users/yuanzhenhui/Documents/docker_data/geth/bootnode:/root/bootnode \
--name geth_boot hawyasunaga/ethereum-bootnode:latest \
bootnode --genkey=/root/bootnode/boot.key

执行上面语句会在bootnode文件夹中生成一个boot.key文件,如下图:

【区块链】搭建Geth联盟链(PoA)_Geth

之后就可以运行bootnode节点了

docker run -itd -m 256M --privileged=true \
--memory-swap -1 \
-p 30301:30301/udp \
-p 30301:30301/tcp \
-v /Users/yuanzhenhui/Documents/docker_data/geth/bootnode:/root/bootnode \
--name gethboot hawyasunaga/ethereum-bootnode:latest bootnode --nodekey=/root/bootnode/boot.key \
-addr 172.17.0.4:30301

由于我这边使用的是docker内网络,所以使用的是172.17.0.4的ip地址,这个可以根据实际情况进行二次配置。

3. 部署区块节点

由于并不清楚这个docker镜像关于区块节点的数据文件部署路径,于是先直接运行镜像进入docker镜像内部查看

docker run -d --name geth1 -p 8545:8545 -p 30303:30303 ethereum/client-go:latest

发现geth的数据文件保存在/root/.ethereum文件夹中,于是分别修改启动节点的挂载地址,如下:

geth1(节点1)

docker run -d --privileged=true \
--name geth1 \
-p 8555:8545 \
-p 30353:30303 \
-v /Users/yuanzhenhui/Documents/docker_data/geth/node1:/root/.ethereum ethereum/client-go:latest

geth2(节点2)

docker run -d --privileged=true \
--name geth2 \
-p 8565:8545 \
-p 30363:30303 \
-v /Users/yuanzhenhui/Documents/docker_data/geth/node2:/root/.ethereum ethereum/client-go:latest

4. 创建账号

节点创建之后就可以通过CLI创建账号了,进入docker容器内部调用命令创建新账户

geth --datadir /root/.ethereum account new

由于挂载文件夹是/root/.ethereum,因此将账号创建指向这个目录,如下图:

【区块链】搭建Geth联盟链(PoA)_区块链_02

既然系统让我好好保存用户名和密码,那么我就生成一个account.txt文件保存在挂载点上吧 (生产环境下建议采用更安全的方式),如下脚本:

geth1(节点1)

echo 'account: 0x22d19690c9F15a894DF4A5Ad0b3a28e7EAD8a8E4 password: 123456' >> /root/.ethereum/account.txt

geth2(节点2)

echo 'account: 0x66d546cCBF139F3aF4b4EdeC1e02E8796544F37f password: 123456' >> /root/.ethereum/account.txt

【区块链】搭建Geth联盟链(PoA)_Geth_03

5. 创建创世块

接下来就可以生成创世块,由于使用的是docker版本所以不存在网上说的puppeth工具这里只能够通手写创世块了,还好之前在第一次做geth的时候已经编写过一次(详情可查阅《【区块链】搭建Geth私有链(PoW)》一文),所以问题不大。

geth1(节点1)

{
  "config": {
    "chainId": 20,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "",
  "gasLimit": "0xffffffff",
  "difficulty": "0x40",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "alloc": {
    "0x22d19690c9F15a894DF4A5Ad0b3a28e7EAD8a8E4":{
      "balance": "1000000000000000"
    },
    "0xdB10376FD880480c8Aa1a87a46Bb0f11eB89Df0b":{
      "balance": "70000000000000"
    }
  }
}

geth2(节点2)

{
  "config": {
    "chainId": 20,
    "homesteadBlock": 0,
    "eip150Block": 0,
    "eip155Block": 0,
    "eip158Block": 0
  },
  "nonce": "0x0000000000000042",
  "timestamp": "0x0",
  "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "extraData": "",
  "gasLimit": "0xffffffff",
  "difficulty": "0x40",
  "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  "coinbase": "0x0000000000000000000000000000000000000000",
  "alloc": {
    "0x66d546cCBF139F3aF4b4EdeC1e02E8796544F37f": {
      "balance": "50000000000000"
    }
  }
}

之后将docker的geth1节点和geth2节点关闭并删除容器。然后去到宿主机数据挂载文件夹将node1和node2文件夹中的geth文件夹删除。之后就可以执行初始化创世块的命令,如下脚本:

geth1(节点1)

docker run -itd --privileged=true \
-v /Users/yuanzhenhui/Documents/docker_data/geth/node1:/root/.ethereum \
--name geth1 ethereum/client-go:latest \
--datadir /root/.ethereum \
--networkid 8765639436932780 init /root/.ethereum/genesis.json

geth2(节点2)

docker run -itd --privileged=true \
-v /Users/yuanzhenhui/Documents/docker_data/geth/node2:/root/.ethereum \
--name geth2 ethereum/client-go:latest \
--datadir /root/.ethereum \
--networkid 8765639736932780 init /root/.ethereum/genesis.json

执行之后node1和node2文件夹下将重新生成geth文件。

6. 遇见问题

在创世块编写完成后启动或许会遇到以下问题,如下图:

Fatal: Failed to write genesis block: unsupported fork ordering: eip150Block not enabled, but eip155Block enabled at 0 genesis block

geth相关文件也生成不成功。这个错误是由于在创世块中没有将eip150Block的配置信息导致的。由于最新镜像是包含“EIP150”提案优化的(EIP150提案:解决拒绝服务攻击,而通过提高IO 操作相关的Gas 来预防攻击)所以这次要加上。

7. 结果

在上述操作都完成后,可以将docker中的geth容器删除之后就将最终配置写上就可以启动节点了。