小坚的技术博客

Ubuntu以太坊私有链搭建

本文作者:陈进坚
博客地址:https://jian1098.github.io
CSDN博客:https://blog.csdn.net/c_jian
简书:https://www.jianshu.com/u/8ba9ac5706b6
联系方式:jian1098@qq.com

安装geth

1
2
3
jian@ubuntu:~$ sudo add-apt-repository -y ppa:ethereum/ethereum
jian@ubuntu:~$ sudo apt-get update
jian@ubuntu:~$ sudo apt-get install ethereum

查看geth版本

1
2
3
4
5
6
7
8
9
10
11
12
jian@ubuntu:~$ geth version
WARN [12-20|00:00:20.173] Sanitizing cache to Go's GC limits provided=1024 updated=661
Geth
Version: 1.8.20-stable
Git Commit: 24d727b6d6e2c0cde222fa12155c4a6db5caaf2e
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.10.4
Operating System: linux
GOPATH=
GOROOT=/usr/lib/go-1.10

创世区块

新建ethereum文件夹,然后在ethereum文件夹中创建data文件夹(存储区块数据)和genesis.json文件,打开genesis.json文件将创世区块代码复制到文件中并保存

1
2
3
4
jian@ubuntu:~$ mkdir ethereum
jian@ubuntu:~$ cd ethereum/
jian@ubuntu:~/ethereum$ mkdir data
jian@ubuntu:~/ethereum$ vi genesis.json

创世区块数据

1
2
3
4
5
6
7
8
9
10
11
12
{
"nonce": "0x0000000000000042",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x400",
"alloc": {},
"coinbase": "0x3333333333333333333333333333333333333333",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x8000000",
"config": {}
}

参数说明

参数名 说明
nonce nonce就是一个64位随机数,用于挖矿,注意他和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
difficulty 设置当前区块的难度,如果难度过大,cpu挖矿就很难,这里设置较小难度
alloc 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要预置有币的账号,需要的时候自己创建即可以。
coinbase 矿工的账号,任意填写一个账号即可。
imestamp 设置创世块的时间戳
parentHash 上一个区块的hash值,因为是创世块,所以这个值是0
extraData 附加信息,随便填,可以填你的个性信息
gasLimit 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大。
mixhash 与nonce配合用于挖矿,由上一个区块的一部分生成的hash。注意他和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。.

创建创世区块

1
2
3
4
5
6
7
8
9
10
11
12
jian@ubuntu:~/ethereum$ geth --datadir data init genesis.json

WARN [12-20|00:01:37.255] Sanitizing cache to Go's GC limits provided=1024 updated=661
INFO [12-20|00:01:37.257] Maximum peer count ETH=25 LES=0 total=25
INFO [12-20|00:01:37.276] Allocated cache and file handles database=/home/jian/ethereum/data/geth/chaindata cache=16 handles=16
INFO [12-20|00:01:37.285] Writing custom genesis block
INFO [12-20|00:01:37.286] Persisted trie from memory database nodes=0 size=0.00B time=2.214µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [12-20|00:01:37.287] Successfully wrote genesis state database=chaindata hash=6231b0…a0300b
INFO [12-20|00:01:37.287] Allocated cache and file handles database=/home/jian/ethereum/data/geth/lightchaindata cache=16 handles=16
INFO [12-20|00:01:37.292] Writing custom genesis block
INFO [12-20|00:01:37.293] Persisted trie from memory database nodes=0 size=0.00B time=2.226µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [12-20|00:01:37.294] Successfully wrote genesis state database=lightchaindata hash=6231b0…a0300b

启动私有链

1
jian@ubuntu:~/ethereum$ geth --port 3000 --networkid 15 --datadir="data" --maxpeers=3 --rpc --rpcport 8545 --rpcaddr 127.0.0.1 --rpccorsdomain "*"  --rpcapi="db,eth,web3,personal,admin,txpool,net" console

启动成功会进入js控制台

1
2
3
4
5
6
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.20-stable-24d727b6/linux-amd64/go1.10.4
modules: admin:1.0 debug:1.0 eth:1.0 ethash:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

>

退出私有链只需要输入exit即可,如果要让另外一台电脑访问私有链,需要将--rpcaddr设置为本机ip;如果是云服务器,要提供rpc服务给其他电脑使用的话,rpcaddr要填写云服务器的内网地址。

创建钱包

在js控制台输入命令

1
2
> personal.newAccount('123456')
"0xee340225c3b9348847c828881a34ae3237e91456"

得到解锁密码为123456,钱包地址为”0xee340225c3b9348847c828881a34ae3237e91456”的以太坊钱包,第一个创建的钱包地址会自动作为默认钱包,挖矿得到的ETH会存入默认钱包中,查看默认钱包:

1
2
> eth.coinbase
"0xee340225c3b9348847c828881a34ae3237e91456"

钱包列表

列出所有钱包

1
2
> eth.accounts
["0xee340225c3b9348847c828881a34ae3237e91456"]

查询余额

1
2
> eth.getBalance('0xee340225c3b9348847c828881a34ae3237e91456')
0

或者根据钱包列表的序号

1
2
> eth.getBalance(eth.accounts[0])
0

如果是默认钱包还可以这样

1
2
> eth.getBalance(eth.coinbase)
0

开启挖矿

挖矿会生成区块和执行交易,挖矿得到的ETH会存入默认钱包中,如果想修改默认钱包可以用以下命令

1
> miner.setEtherbase("0xa91Ae941e92eb6Fa78FE0d8215F01cbE6b7C014c")

开启挖矿,1表示1个线程

1
2
3
4
5
6
7
8
9
> miner.start(1)

INFO [12-20|00:16:58.760] Generating DAG in progress epoch=0 percentage=0 elapsed=4.311s
INFO [12-20|00:17:03.084] Generating DAG in progress epoch=0 percentage=1 elapsed=8.635s
INFO [12-20|00:17:07.498] Generating DAG in progress epoch=0 percentage=2 elapsed=13.049s
INFO [12-20|00:17:11.975] Generating DAG in progress epoch=0 percentage=3 elapsed=17.526s
INFO [12-20|00:17:16.302] Generating DAG in progress epoch=0 percentage=4 elapsed=21.853s
INFO [12-20|00:17:20.855] Generating DAG in progress epoch=0 percentage=5
......

第一次启动挖矿会先生成挖矿所需的DAG文件,这个过程有点慢,大概需要10分钟,等到 percentage = 100后,就会开始挖矿,此时屏幕会被挖矿信息刷屏。看到类似下面的信息表示挖矿成功

1
2
3
4
5
6
7
8
9
INFO [12-20|00:42:41.957] 🔗 block reached canonical chain          number=2 hash=9a053e…3b1a92
INFO [12-20|00:42:41.957] 🔨 mined potential block number=9 hash=3067bd…6eb8e3
INFO [12-20|00:42:41.978] Commit new mining work number=10 sealhash=3958ea…fc97b1 uncles=0 txs=0 gas=0 fees=0 elapsed=103.483µs
INFO [12-20|00:42:47.737] Generating DAG in progress epoch=1 percentage=31 elapsed=17m30.277s
INFO [12-20|00:42:53.206] Successfully sealed new block number=10 sealhash=3958ea…fc97b1 hash=ae06e1…929511 elapsed=11.228s
INFO [12-20|00:42:53.207] 🔗 block reached canonical chain number=3 hash=c5335d…b00c0c
INFO [12-20|00:42:53.207] 🔨 mined potential block number=10 hash=ae06e1…929511
INFO [12-20|00:42:53.223] Commit new mining work number=11 sealhash=512ca2…b5efb9 uncles=0 txs=0 gas=0 fees=0 elapsed=92.66µs
......

此时新打开终端,用 geth attach 命令连接到js控制台再查询默认钱包余额,发现已经有币了

1
2
3
4
jian@ubuntu:~$ cd ~/ethereum/data
jian@ubuntu:~/ethereum/data$ geth attach ipc:geth.ipc
> eth.getBalance(eth.coinbase)
175000000000000000000

余额的单位是GWEI,要转为ETH只要除以10的18次方即可,这里的余额为175ETH

停止挖矿

1
> miner.stop()

区块高度

区块高度也叫区块数量、最新区块

1
2
> eth.blockNumber
186

解锁钱包

以太坊钱包大概每5分钟就会被锁住,交易和创建合约都需要先解锁,输入下面的命令和钱包密码即可解锁

1
2
3
4
> personal.unlockAccount("0xee340225c3b9348847c828881a34ae3237e91456") 
Unlock account 0xee340225c3b9348847c828881a34ae3237e91456
Passphrase:
true

新版本的geth可能会报错

1
Error: account unlock with HTTP access is forbidden

在启动私有链的时候添加参数--allow-insecure-unlock即可解决

发送交易

发送交易前请先解锁转出地钱包并启动挖矿,然后使用eth.sendTransaction命令发送交易,下面的命令将从eth.accounts[0]转5个ETH到eth.accounts[1],也可以替换成具体的钱包地址:

1
2
3
4
5
6
> amount = web3.toWei(5,'ether') 
"5000000000000000000"
> eth.sendTransaction({from:eth.accounts[0],to:eth.accounts[1],value:amount})

I0322 19:39:36.300675 internal/ethapi/api.go:1047] Tx(0x0c59f431068937cbe9e230483bc79f59bd7146edc8ff5ec37fea6710adcab825) to: 0x814d39aa21f3eed069f2b21da7b5f857f7343afa
"0x0c59f431068937cbe9e230483bc79f59bd7146edc8ff5ec37fea6710adcab825"

发送成功将返回交易哈希,等待挖矿执行交易,再查看余额可以看到已经到账

1
2
> web3.fromWei(eth.getBalance(eth.accounts[1]),'ether') 
5

查询交易

可以根据交易哈希查询该交易的详细信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> eth.getTransaction("0x0c59f431068937cbe9e230483bc79f59bd7146edc8ff5ec37fea6710adcab825") 
{
blockHash: "0xf5d3da50065ce5793c9571a031ad6fe5f1af326a3c4fb7ce16458f4d909c1613",
blockNumber: 33,
from: "0xc232e2add308136571bb8f9197ba4ae4e5ba9836",
gas: 90000,
gasPrice: 20000000000,
hash: "0x0c59f431068937cbe9e230483bc79f59bd7146edc8ff5ec37fea6710adcab825",
input: "0x",
nonce: 0,
r: "0x433fe5845391b6da3d8aa0d2b53674e09fb6126f0070a600686809b57e4ef77d",
s: "0x6b0086fb76c46024f849141074a5bc79c49d5f9a658fd0fedbbe354889c34d8d",
to: "0x814d39aa21f3eed069f2b21da7b5f857f7343afa",
transactionIndex: 0,
v: "0x1b",
value: 5000000000000000000
}

连接节点

如果局域网内有多个私有链节点,可以将这些节点连接起来组成链,这些节点会同步相同的区块和交易,相当于小型的公链。但是要将这些节点连接起来需要满足3个条件:

  • 节点所在的机器,相互之间可以互联互通网络
  • 有相同的创世区块
  • 在启动私有链的geth命令中设置相同的networkid

假设有两个节点:节点一(ubuntu端)和节点二(windows端),它们的geth启动命令中的networkid都是1108,首先要知道节点二的enode信息,启动节点二的私有链,在js console中执行下面的命令查看enode信息:

1
2
> admin.nodeInfo.enode  
"enode://9e86289ea859ca041f235aed87a091d0cd594b377cbe13e1c5f5a08a8a280e62d4019ac54063ed6a1d0e3c3eaedad0b73c40b99a16a176993f0373ffe92be672@[::]:30304"

复制上面给出的信息添加到admin.Peer的参数中,注意要把enode中的[::]替换成节点二的IP地址。然后在节点一的js console中执行admin.addPeer(),就可以连接到节点二了

1
> admin.addPeer("enode://9e86289ea859ca041f235aed87a091d0cd594b377cbe13e1c5f5a08a8a280e62d4019ac54063ed6a1d0e3c3eaedad0b73c40b99a16a176993f0373ffe92be672@192.168.1.111:30304")

连接成功后,节点一和节点二就会开始同步的区块,保证区块数据一致。使用admin.peers命令可以查看当前网络连接在一起的所有节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
> admin.peers
[{
caps: ["eth/62", "eth/63"],
id: "070b16d058df62a934bb1b9f6e216f6763d63c51011c559d0ad155ae428294c69aed1e35a46c36a6613989941b67b530ab92c7667bd63e7e8a7a5717a266751f",
name: "Geth/v1.8.12-stable/linux-amd64/go1.9.2",
network: {
inbound: true,
localAddress: "172.31.238.175:30303",
remoteAddress: "145.239.0.91:51238",
static: false,
trusted: false
},
protocols: {
eth: {
difficulty: 8.379127609415399e+21,
head: "0x7ce58e50b8bc9af80c6900729801832ec9a5f86e549930e085f1a208dacf5608",
version: 63
}
}
}, {
caps: ["eth/62", "eth/63"],
id: "19211a5d0fbcabf5184e49639839bda772080cba500a4a0e9ced1f89c3a43fea1c00d4d8de5a463d6002bfa594e46e2c03611a6514117f1bd8c7e889bfb4ec7a",
name: "Geth/v1.8.18-unstable-126dfde6/linux-amd64/go1.9.4",
network: {
inbound: true,
localAddress: "172.31.238.175:30303",
remoteAddress: "120.78.87.202:53548",
static: false,
trusted: false
},
protocols: {
eth: {
difficulty: 5.481064970682881e+21,
head: "0xdb982b1ff69083b090549c3809dd6b58f87ca50db97e0b4144aac9269ad198be",
version: 63
}
}
}]

参考文章

[1] https://my.oschina.net/u/2349981/blog/856956

[2] http://blog.csdn.net/u013096666/article/details/72639906

[3] http://qiita.com/oggata/items/eea4d5e37f38785f6079

-------------本文结束感谢您的阅读-------------
🐶 您的支持将鼓励我继续创作 🐶