准备阶段

本示例使用的geth-1.13.15, 1.14版本的geth已经移除了Clique,详情可参见https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0

本示例参考https://geth.ethereum.org/docs/fundamentals/private-network#creating-genesis-block

搭建并启动私链

1、构建项目结构

mkdir chaindev
cd chaindev
touch genesis.json
mkdir node1 node2

2、创建genesis.json

{
    "config": {
      "chainId": 8888,
      "homesteadBlock": 0,
      "eip150Block": 0,
      "eip155Block": 0,
      "eip158Block": 0,
      "byzantiumBlock": 0,
      "constantinopleBlock": 0,
      "petersburgBlock": 0,
      "istanbulBlock": 0,
      "berlinBlock": 0,
      "clique": {
        "period": 3, 
        "epoch": 30000
      }
    },
    "extraData": "0x00000000000000000000000000000000000000000000000000000000000000001e7d9b53cda80b801052171622c575f5fd7e9d3d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "difficulty": "0x1",
    "gasLimit": "0x2625A00",
    "alloc": {
        "1e7d9b53cda80b801052171622c575f5fd7e9d3d": { 
            "balance": "1000000000000000000000" 
        },
        "28d2b259f9aee1a34d52a028abd492bfe4f4c0c3": { 
            "balance": "1000000000000000000000" 
        }
     }
  }

3、为每个验证者创建账户,保存好密码和私钥

geth account new --datadir node1  
geth account new --datadir node2  

4、输出密码到相应文件(使用上一步保存的密码)

echo "password1" > node1/password.txt
echo "password2" > node2/password.txt

5、初始化相应验证者节点

geth init --datadir node1 genesis.json
geth init --datadir node2 genesis.json
geth init --datadir node3 genesis.json
geth init --datadir node4 genesis.json

(可选)6、删除geth目录,genesis.json作出修改后需要重新执行步骤5时需要

rm -rf node1/geth
rm -rf node2/geth

7、启动节点1

geth --datadir node1 \
    --networkid 8888 \
    --http --http.addr "0.0.0.0" --http.port 8545 \
    --http.api "eth,net,web3,personal,admin,clique" \
    --port 30303 \
    --allow-insecure-unlock \
    --miner.gaslimit "0x2625A00" \
    --rpc.enabledeprecatedpersonal \
    --cache 4096 \
    --unlock "0x1e7d9b53cda80b801052171622c575f5fd7e9d3d" \
    --password "node1/password.txt" \
    --mine \
    --miner.etherbase "0x1e7d9b53cda80b801052171622c575f5fd7e9d3d"

此时,私链已经完成启动,可以对其进行测试。

接入新本地的节点

本例中的node2将作为本地新节点接入。

8、获取enode

geth attach node1/geth.ipc
> admin.nodeInfo.enode

9、启动node2(注意端口不要冲突)

geth --datadir node2 \
    --networkid 8888 \
    --http --http.addr "0.0.0.0" --http.port 8546 \
    --http.api "eth,net,web3,personal,admin,clique" \
    --port 30304 \
    --allow-insecure-unlock \
    --cache 4096 \
    --bootnodes "<enode>" \
    --unlock "0x28d2b259f9aee1a34d52a028abd492bfe4f4c0c3" \
    --password "node2/password.txt" \
    --ws --ws.addr "0.0.0.0" --ws.port 8552 --ws.api "eth,net,web3,personal,admin,clique" \
    --authrpc.port 8554

10、重启Javascript 控制台检查网络属性

> net.peerCount
 2
> admin.peers
[{
    caps: ["eth/68", "snap/1"],
    enode: "<enode>",
    id: "8eccb6e9091a16a549de83dd9bda13ae24f6d19990e0e9b29b503c223b9993cf",
    name: "Geth/v1.13.15-stable/linux-amd64/go1.22.0",
    network: {
      inbound: false,
      localAddress: "127.0.0.1:39848",
      remoteAddress: "127.0.0.1:30303",
      static: false,
      trusted: false
    },
    protocols: {
      eth: {
        version: 68
      },
      snap: {
        version: 1
      }
    }
}]

注意,因为防火墙端口未开放30303,此示例也是再本地运行的node2,所以修改了enode的ip为127.0.0.1

11、测试交易

接入远程节点

1、geth版本(1.13.15)

https://github.com/ethereum/go-ethereum/releases/tag/v1.13.15

为防止出现错误,建议使用相同版本,注意不要使用该版本之后的版本,那将移除Clique

2、创建项目

mkdir chaindev
cd chaindev
mkdir node1

3、创建genesis.json(保持一致)

{
    "config": {
      "chainId": 8888,
      "homesteadBlock": 0,
      "eip150Block": 0,
      "eip155Block": 0,
      "eip158Block": 0,
      "byzantiumBlock": 0,
      "constantinopleBlock": 0,
      "petersburgBlock": 0,
      "istanbulBlock": 0,
      "berlinBlock": 0,
      "clique": {
        "period": 3, 
        "epoch": 30000
      }
    },
    "extraData": "0x00000000000000000000000000000000000000000000000000000000000000001e7d9b53cda80b801052171622c575f5fd7e9d3d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
    "difficulty": "0x1",
    "gasLimit": "0x2625A00",
    "alloc": {
        "1e7d9b53cda80b801052171622c575f5fd7e9d3d": { 
            "balance": "1000000000000000000000" 
        },
        "28d2b259f9aee1a34d52a028abd492bfe4f4c0c3": { 
            "balance": "1000000000000000000000" 
        }
     }
  }

4、为node1创建账户(示例密码为1234)

geth account new --datadir node1  // password: 1234
echo "1234" > node1/password.txt

5、初始化node1

geth init --datadir node1 genesis.json

6、启动节点

A、启动一个(允许出块和验证)的节点

geth --datadir node1 \
    --networkid 8888 \
    --http --http.addr "0.0.0.0" --http.port 8546 \
    --http.api "eth,net,web3,personal,admin,clique" \
    --port 30303 \
    --allow-insecure-unlock \
    --cache 4096 \
    --bootnodes "enode://02af1096f065550865969cd47e25f062b1db8b5e04b91e63ea77584d87e59e27cd7762547e897cbb4330944ae06ff474a94746db0d09f411b5aa222ab15acab1@40.78.123.6:30303" \
    --unlock "<node1_account_address>" \
    --password "node1/password.txt" \
    --ws --ws.addr "0.0.0.0" --ws.port 8552 --ws.api "eth,net,web3,personal,admin,clique" \
    --authrpc.port 8555 \
    --mine \
    --miner.gaslimit "0x2625A00" \
    --miner.etherbase "<node1_account_address>"

注意,可能会遇见端口冲突,修改端口即可,还可能遇见502网关错误,可以尝试rpc: http://localhost:<port>

还需要参与POA共识,提供节点账户地址,让其它签名者达成共识,将其添加到签名者列表中

B、启动一个正常节点(仅同步和广播交易)

geth --datadir node1 \
    --networkid 8888 \
    --http --http.addr "0.0.0.0" --http.port 8546 \
    --http.api "eth,net,web3,personal,admin,clique" \
    --port 30303 \
    --allow-insecure-unlock \
    --cache 4096 \
    --bootnodes "enode://02af1096f065550865969cd47e25f062b1db8b5e04b91e63ea77584d87e59e27cd7762547e897cbb4330944ae06ff474a94746db0d09f411b5aa222ab15acab1@40.78.123.6:30303" \
    --unlock "<node1_account_address>" \
    --password "node1/password.txt" \
    --ws --ws.addr "0.0.0.0" --ws.port 8552 --ws.api "eth,net,web3,personal,admin,clique" \
    --authrpc.port 8555 

7、启动控制台查看同步区块(同步需要时间,可能需要等会儿)

geth attach node1/geth.ipc

一下是一些控制台测试命令:

发送交易
eth.sendTransaction({from: "address1", to: "address2", value: web3.toWei(1, "ether")})
检查余额(按ether)
web3.fromWei(eth.getBalance("address1"), "ether")
解锁账户
personal.unlockAccount("address1", "1234", 600)
检查节点的同步状态:
eth.syncing
创建一个新账户
personal.newAccount("1111")
查看所有账户
eth.accounts
检查节点是否连接到另一个对等节点
net.peerCount
查看区块
eth.blockNumber