在之前的文章中,我们介绍了PoA Clique共识下新增验证者节点的操作步骤。本文将以一个示例来说明如何操作。
本文中的示例仅供参考,实际操作中,请根据实际情况进行调整。 本文中的操作基于以太坊客户端Geth v1.13.15,docekr环境执行
1. 网络搭建说明
在本文中,我们将搭建一个具有三个验证者节点的PoA Clique私链网络,角色如下:
- ndoe,地址:0xe23C2c6e7f785e74EB7AAeF96455B78C53adb2E3,初始验证者节点
- node1,地址:0x346271527e300f3c47450b792a6ee362b5cb0005,新增验证者节点
- node2,地址:0x68c86ac751aedcbd3a966c106b42755fac6327ac,新增验证者节点
2. 网络初始化
现在我们先初始化下各个节点,创世文件内容 genesis.json
如下:
{
"config": {
"chainId": 73258216,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"berlinBlock": 0,
"clique": {
"period": 1,
"epoch": 30000
}
},
"difficulty": "1",
"gasLimit": "0xFFFFFFFF",
"extradata": "0x0000000000000000000000000000000000000000000000000000000000000000e23c2c6e7f785e74eb7aaef96455b78c53adb2e30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"alloc": {
"e23c2c6e7f785e74eb7aaef96455b78c53adb2e3": {
"balance": "10000000000000000000000"
}
}
}
初始化节点命令如下:
$ docker run --rm -v $(pwd)/node:/root/.ethereum -v $(pwd)/genesis.json:/root/genesis.json ethereum/client-go:v1.13.15 init /root/genesis.json
$ docker run --rm -v $(pwd)/node1:/root/.ethereum -v $(pwd)/genesis.json:/root/genesis.json ethereum/client-go:v1.13.15 init /root/genesis.json
$ docker run --rm -v $(pwd)/node2:/root/.ethereum -v $(pwd)/genesis.json:/root/genesis.json ethereum/client-go:v1.13.15 init /root/genesis.json
通过上面的命令,我们将三个节点的创世文件和数据目录都初始化好了。
3. 启动网络
docker-compose.yaml
文件内容如下:
services:
node:
image: ethereum/client-go:v1.13.15
container_name: node
volumes:
- ./node:/root/.ethereum
- ./genesis.json:/root/genesis.json
ports:
- 8545:8545 # HTTP RPC
- 30303:30303 # P2P 网络
command: >
--networkid 73258216
--http
--http.addr "0.0.0.0"
--http.port 8545
--http.api "eth,net,web3,personal,miner,admin,txpool,debug"
--http.corsdomain "*"
--txpool.globalslots 4096
--txpool.globalqueue 8192
--txpool.accountslots 128
--txpool.accountqueue 256
--unlock 0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3
--password /root/.ethereum/password.txt
--allow-insecure-unlock
--mine
--miner.etherbase "0xe23C2c6e7f785e74EB7AAeF96455B78C53adb2E3"
--miner.gasprice 1
networks:
- ethereum-network
networks:
ethereum-network:
driver: bridge
启动网络命令如下:
# 启动初始节点
$ docker-compose up -d node
# 获取节点的enode信息
$ docker exec -it node geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3
at block: 4 (Wed Nov 20 2024 01:42:54 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> admin.nodeInfo.enode
"enode://e6a79a96d1cb112e323d6b10e70199f3215cb0a78f7421da0f49ab6feea963dcad215ff54be182aebc66d0024c9ac6ab1ec293fa8087b288b862599207267cb4@127.0.0.1:30303"
>
4. 新增验证节点 node1
新的验证者节点启动时,需要有初始验证者节点做为引导节点,这一操作与新增同步节点类似。但作为验证节点,需要进行挖矿出块操作,因此在节点启动时需要增加挖矿参数 --mine
和 --miner.etherbase
参数。
docker-compose.yaml
文件内容如下:
services:
node1:
image: ethereum/client-go:v1.13.15
container_name: node1
volumes:
- ./node1:/root/.ethereum
- ./genesis.json:/root/genesis.json
ports:
- 8546:8545 # HTTP RPC
- 30304:30303 # P2P 网络
command: >
--networkid 73258216
--http
--http.addr "0.0.0.0"
--http.port 8545
--http.api "eth,net,web3,personal,miner,admin,txpool,debug"
--http.corsdomain "*"
--txpool.globalslots 4096
--txpool.globalqueue 8192
--txpool.accountslots 128
--txpool.accountqueue 256
--unlock 0x346271527e300f3c47450b792a6ee362b5cb0005
--password /root/.ethereum/password.txt
--allow-insecure-unlock
--bootnodes "enode://e6a79a96d1cb112e323d6b10e70199f3215cb0a78f7421da0f49ab6feea963dcad215ff54be182aebc66d0024c9ac6ab1ec293fa8087b288b862599207267cb4@node:30303"
--syncmode full
--mine
--miner.etherbase "0x346271527e300f3c47450b792a6ee362b5cb0005"
--miner.gasprice 1
networks:
- ethereum-network
通过如下命令启动新增 node1 节点,此时查看 node1 的日志,会看到如下的出错信息:
$ docker-compose up -d node1
# 查看 node1 的日志
$ docker logs -f node1
INFO [11-20|01:50:14.221] Commit new sealing work number=1 sealhash=ac65fe..c86c41 txs=0 gas=0 fees=0 elapsed="76.385µs"
WARN [11-20|01:50:14.221] Block sealing failed err="unauthorized signer"
此时需要我们在 node 节点中将 node1 的地址加入到验证者列表中,命令如下:
$ docker exec -it node geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3
at block: 545 (Wed Nov 20 2024 01:51:55 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.propose("0x346271527e300f3c47450b792a6ee362b5cb0005",true)
null
> clique.status()
{
inturnPercent: 96.875,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 1,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 63
}
}
> exit
# 在 node1 节点中查看验证者列信息
$ docker exec -it node1 geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0x346271527e300f3c47450b792a6ee362b5cb0005
at block: 687 (Wed Nov 20 2024 01:54:17 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.status()
{
inturnPercent: 0,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
>
可以看到,node1 节点已经成功加入到验证者列表中,并开始出块。
5. 新增验证节点 node2
新增 node2 节点的操作与新增 node1 节点类似,需要在 node 节点中将 node2 的地址加入到验证者列表中,并启动 node2 节点。需要注意的是现有验证者可以提议增加新的验证者节点,超过 50% 的验证者投票赞成后,新的节点将成为验证者。在我们的示例中,此时只有两个验证者节点,要满足超过 50% 的投票,需要 node 节点和 node1 节点都同意,node2 节点才能成为验证者。
docker-compose.yaml
文件内容如下:
services:
node2:
image: ethereum/client-go:v1.13.15
container_name: node2
volumes:
- ./node2:/root/.ethereum
- ./genesis.json:/root/genesis.json
ports:
- 8547:8545 # HTTP RPC
- 30305:30303 # P2P 网络
command: >
--networkid 73258216
--http
--http.addr "0.0.0.0"
--http.port 8545
--http.api "eth,net,web3,personal,miner,admin,txpool,debug"
--http.corsdomain "*"
--txpool.globalslots 4096
--txpool.globalqueue 8192
--txpool.accountslots 128
--txpool.accountqueue 256
--unlock 0x68c86ac751aedcbd3a966c106b42755fac6327ac
--password /root/.ethereum/password.txt
--allow-insecure-unlock
--bootnodes "enode://e6a79a96d1cb112e323d6b10e70199f3215cb0a78f7421da0f49ab6feea963dcad215ff54be182aebc66d0024c9ac6ab1ec293fa8087b288b862599207267cb4@node:30303"
--syncmode full
--mine
--miner.etherbase "0x68c86ac751aedcbd3a966c106b42755fac6327ac"
--miner.gasprice 1
networks:
- ethereum-network
操作命令如下:
# 启动 node2 节点
$ docker-compose up -d node2
# 在 node 节点中将 node2 的地址加入到验证者列表中
$ docker exec -it node geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3
at block: 1054 (Wed Nov 20 2024 02:00:24 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.status()
{
inturnPercent: 0,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
> clique.propose("0x68c86ac751aedcbd3a966c106b42755fac6327ac",true)
null
> clique.status()
{
inturnPercent: 0,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
# 可以看到现在 node2 节点还不在验证者列表中,此时我们需要在 node1 节点中同意
$ docker exec -it node1 geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0x346271527e300f3c47450b792a6ee362b5cb0005
at block: 687 (Wed Nov 20 2024 01:54:17 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.status()
{
inturnPercent: 0,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
> > clique.propose("0x68c86ac751aedcbd3a966c106b42755fac6327ac",true)
null
# 现在 node2 已经在验证者列表中,但还未出块
> clique.status()
{
inturnPercent: 9.375,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0x68c86ac751aedcbd3a966c106b42755fac6327ac: 0,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
# 稍等一段时间就会发现 node2 节点已经在验证者列表中,并开始出块
> clique.status()
{
inturnPercent: 100,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 22,
0x68c86ac751aedcbd3a966c106b42755fac6327ac: 21,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 21
}
}
6. 删除验证者节点 node2
删除验证者节点操作与新增操作类似,但现有验证者可以提议移除某个验证者,超过 50% 的验证者投票赞成后,目标节点将被移除。在我们的示例中,此时只有两个验证者节点,要满足超过 50% 的投票,需要 node 节点和 node1 节点都同意,node2 节点才能被移除。
操作如下:
# 在 node 节点中提议移除 node2 节点
$ docker exec -it node geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3
at block: 1412 (Wed Nov 20 2024 02:06:22 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.propose("0x68c86ac751aedcbd3a966c106b42755fac6327ac",false)
null
# 在 node1 节点中查看验证者列表,可以看到 node2 节点还在验证者列表中,此时需要我们在 node1 节点中也提议移除 node2 节点
docker exec -it node1 geth attach
Welcome to the Geth JavaScript console!
instance: Geth/v1.13.15-stable-c5ba367e/linux-amd64/go1.21.9
coinbase: 0x346271527e300f3c47450b792a6ee362b5cb0005
at block: 1554 (Wed Nov 20 2024 02:08:44 GMT+0000 (UTC))
datadir: /root/.ethereum
modules: admin:1.0 clique:1.0 debug:1.0 engine:1.0 eth:1.0 miner:1.0 net:1.0 rpc:1.0 txpool:1.0 web3:1.0
To exit, press ctrl-d or type exit
> clique.status()
{
inturnPercent: 100,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 21,
0x68c86ac751aedcbd3a966c106b42755fac6327ac: 21,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 22
}
}
> clique.propose("0x68c86ac751aedcbd3a966c106b42755fac6327ac",false)
null
# 等待一段时间,node2 节点将被移除
> clique.status()
{
inturnPercent: 0,
numBlocks: 64,
sealerActivity: {
0x346271527e300f3c47450b792a6ee362b5cb0005: 32,
0xe23c2c6e7f785e74eb7aaef96455b78c53adb2e3: 32
}
}
# 此时查看 node2 节点的日志,可以看到出块时会报错:
$ docker logs -f node2
...
INFO [11-20|02:09:42.192] Commit new sealing work number=1613 sealhash=a19d84..4daac8 txs=0 gas=0 fees=0 elapsed="51.961µs"
WARN [11-20|02:09:42.192] Block sealing failed err="unauthorized signer"
...
现在我们已经成功移除了 node2 节点的验证者身份,但它还可以作为同步节点参与网络服务。
至此,我们已经成功搭建了一个以太坊的验证者网络,并完成了验证者节点的新增和删除操作。
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特
—