搭建私有链(Private Chain)并进行挖矿和交易

搭建私有链并进行挖矿和交易

创世区块的配置

搭建私有链首先需要指定创世区块的配置,此文件就是一个内容格式为json的文本文件。 我们可以将创世区块 genesis.json 的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"alloc": {},
"config": {
"chainID": 72,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"nonce": "0x0000000000000000",
"difficulty": "0x4000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa",
"gasLimit": "0xffffffff"
}

配置项简介:

  1. alloc: 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以不需要预置有币的账号,需要的时候自己创建即可以。
  2. nonce: 一个64位随机数,用于挖矿,和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4.Block Header Validity (44)章节所描述的条件。
  3. difficulty: 设置计算区块的难度,如果数值过大,挖矿时间较长,在测试环境为节省算力和等带时间可设置较小值。
  4. mixhash: 与nonce配合用于挖矿,由上一个区块的一部分生成的hash。和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
  5. coinbase: 矿工账号,随便填写。
  6. timestamp: 设置创世块的时间戳。
  7. parentHash: 上一个区块的hash值,因为是创世块,所以这个值是0。
  8. extraData: 附加信息,随便填,可以填你的个性信息,必须为十六进制的字符串。
  9. gasLimit: 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为是私有链,所以填最大。

初始化创世块

通过以下命名初始化创世区块:

1
geth --datadir ./private_chain_data_1/ init genesis.json

得到日志如下:

1
2
3
4
5
6
7
8
9
INFO [03-07|21:02:11] Maximum peer count                       ETH=25 LES=0 total=25
INFO [03-07|21:02:11] Allocated cache and file handles database=/home/wangy/ethereum/private_chain/private_chain_data_1/geth/chaindata cache=16 handles=16
INFO [03-07|21:02:11] Writing custom genesis block
INFO [03-07|21:02:11] Persisted trie from memory database nodes=0 size=0.00B time=52.906µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [03-07|21:02:11] Successfully wrote genesis state database=chaindata hash=942f59…a2588a
INFO [03-07|21:02:11] Allocated cache and file handles database=/home/wangy/ethereum/private_chain/private_chain_data_1/geth/lightchaindata cache=16 handles=16
INFO [03-07|21:02:11] Writing custom genesis block
INFO [03-07|21:02:11] Persisted trie from memory database nodes=0 size=0.00B time=1.416µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [03-07|21:02:11] Successfully wrote genesis state database=lightchaindata hash=942f59…a2588a

私有链初始化完成.

启动并进入控制台

通过指定datadir来启动节点:

1
geth --datadir ./private_chain_data_1/ --networkid 88 --nodiscover console

geth参数说明:

  1. networkid 指定网路ID,确保不适用1-4。
  2. nodiscover 此参数确保geth不去寻找peers,主要是为了严格控制联盟链连入的节点。
  3. identity: 区块链的标示,随便填写,用于标示目前网络的名字
  4. init: 指定创世块文件的位置,并创建初始块
  5. datadir: 设置当前区块链网络数据存放的位置
  6. port: 网络监听端口
  7. rpc: 启动rpc通信,可以进行智能合约的部署和调试
  8. rpcapi: 设置允许连接的rpc的客户端,一般为db,eth,net,web3
  9. console: 启动命令行模式,可以在Geth中执行命令

节点启动后, 得到日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
INFO [03-07|21:08:40] Maximum peer count                       ETH=25 LES=0 total=25
INFO [03-07|21:08:40] Starting peer-to-peer node instance=Geth/v1.8.2-stable/linux-amd64/go1.8.3
INFO [03-07|21:08:40] Allocated cache and file handles database=/home/wangy/ethereum/private_chain/private_chain_data_1/geth/chaindata cache=768 handles=512
WARN [03-07|21:08:40] Upgrading database to use lookup entries
INFO [03-07|21:08:40] Initialised chain configuration config="{ChainID: 72 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [03-07|21:08:40] Disk storage enabled for ethash caches dir=/home/wangy/ethereum/private_chain/private_chain_data_1/geth/ethash count=3
INFO [03-07|21:08:40] Disk storage enabled for ethash DAGs dir=/home/wangy/.ethash count=2
INFO [03-07|21:08:40] Initialising Ethereum protocol versions="[63 62]" network=88
INFO [03-07|21:08:40] Loaded most recent local header number=0 hash=942f59…a2588a td=16384
INFO [03-07|21:08:40] Loaded most recent local full block number=0 hash=942f59…a2588a td=16384
INFO [03-07|21:08:40] Loaded most recent local fast block number=0 hash=942f59…a2588a td=16384
INFO [03-07|21:08:40] Regenerated local transaction journal transactions=0 accounts=0
INFO [03-07|21:08:40] Starting P2P networking
INFO [03-07|21:08:40] Database deduplication successful deduped=0
INFO [03-07|21:08:40] RLPx listener up self="enode://b41177a956e39a36f77bb73b857688d3c27989a259a8820559d1efa81e8952b70280bfa91419acd7e93f2ccff5bcdb298f400bc384b6e3ce3fbf2a0952bb060b@[::]:30303?discport=0"
INFO [03-07|21:08:40] IPC endpoint opened url=/home/wangy/ethereum/private_chain/private_chain_data_1/geth.ipc
Welcome to the Geth JavaScript console!

instance: Geth/v1.8.2-stable/linux-amd64/go1.8.3
modules: admin:1.0 debug:1.0 eth:1.0 miner:1.0 net:1.0 personal:1.0 rpc:1.0 txpool:1.0 web3:1.0

通过日志可以发现这个节点启用的是默认端口为 30303.

这是一个交互式的Javascript执行环境,在这里面可以执行Javascript方法. 对象主要包括:

  1. eth: 包含一些跟操作区块链相关的方法
  2. net: 包含以下查看p2p网络状态的方法
  3. admin: 包含一些与管理节点相关的方法
  4. miner: 包含启动&停止挖矿的一些方法
  5. personal: 主要包含一些管理账户的方法
  6. txpool: 包含一些查看交易内存池的方法
  7. web3: 包含了以上对象,还包含一些单位换算的方法

配置帐号

上一步的日志说 No etherbase set and no accounts found as default, 那么我们接着创建一个密码为password的帐号:

1
2
3
4
5
6
7
8
9
> personal.listAccounts
[]
>
> personal.newAccount("password")
"0x1a36a03932e3b73292df56b6493058425e518857"
>
> personal.listAccounts
["0x1a36a03932e3b73292df56b6493058425e518857"]
>

查看账户余额:

1
2
> web3.fromWei(eth.getBalance(eth.coinbase), "ether")
0

查看钱包信息:

1
2
3
4
5
6
7
8
9
> personal.listWallets
[{
accounts: [{
address: "0x1a36a03932e3b73292df56b6493058425e518857",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T05-16-25.359680161Z--1a36a03932e3b73292df56b6493058425e518857"
}],
status: "Locked",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T05-16-25.359680161Z--1a36a03932e3b73292df56b6493058425e518857"
}]

挖矿

帐号创建成功以后, 我们就可以通过 miner.start() 来开始挖矿了. 命令启动后, 得到日志如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> miner.start()
INFO [03-07|21:58:20] Updated mining threads threads=0
INFO [03-07|21:58:20] Transaction pool price threshold updated price=18000000000
null
INFO [03-07|21:58:20] Starting mining operation
INFO [03-07|21:58:20] Commit new mining work number=1 txs=0 uncles=0 elapsed=231.751µs
INFO [03-07|21:58:28] Generating DAG in progress epoch=1 percentage=0 elapsed=4.904s
INFO [03-07|21:58:33] Generating DAG in progress epoch=1 percentage=1 elapsed=10.359s
INFO [03-07|21:58:39] Generating DAG in progress epoch=1 percentage=2 elapsed=15.923s
INFO [03-07|21:58:44] Generating DAG in progress epoch=1 percentage=3 elapsed=21.394s
INFO [03-07|21:58:50] Generating DAG in progress epoch=1 percentage=4 elapsed=26.783s
INFO [03-07|21:58:56] Generating DAG in progress epoch=1 percentage=5 elapsed=33.166s
INFO [03-07|21:59:01] Generating DAG in progress epoch=1 percentage=6 elapsed=38.682s
...

注意看 percentage, 这个时候你还没有开始挖矿哦, 在做挖矿准备工作. 只有在percentage变成了100%之后, 才可以挖到矿的. 如下, 只有到了 Generated ethash verification cache 才算整整开始挖矿. Successfully sealed new block才是挖到矿了哦

1
2
3
4
5
6
7
8
9
10
11
12
13
INFO [03-07|22:07:26] Generating DAG in progress               epoch=1 percentage=97 elapsed=9m2.944s
INFO [03-07|22:07:31] Generating DAG in progress epoch=1 percentage=98 elapsed=9m8.134s
INFO [03-07|22:07:37] Generating DAG in progress epoch=1 percentage=99 elapsed=9m13.969s
INFO [03-07|22:07:37] Generated ethash verification cache epoch=1 elapsed=9m13.972s
INFO [03-07|22:14:22] Successfully sealed new block number=1 hash=d26e3e…f6662f
INFO [03-07|22:14:22] 🔨 mined potential block number=1 hash=d26e3e…f6662f
INFO [03-07|22:14:22] Commit new mining work number=2 txs=0 uncles=0 elapsed=174.575µs
INFO [03-07|22:15:00] Successfully sealed new block number=2 hash=1e4192…1f9e6e
INFO [03-07|22:15:00] 🔨 mined potential block number=2 hash=1e4192…1f9e6e
INFO [03-07|22:15:00] Commit new mining work number=3 txs=0 uncles=0 elapsed=119.383µs
INFO [03-07|22:15:05] Successfully sealed new block number=3 hash=2f8d08…47177a
INFO [03-07|22:15:05] 🔨 mined potential block number=3 hash=2f8d08…47177a
INFO [03-07|22:15:05] Commit new mining work number=4 txs=0 uncles=0 elapsed=103.057µs

中途可以通过 miner.stop() 命令可以停止挖矿. 注意: 输入的字符会被挖矿刷屏信息冲掉,没有关系,只要输入完整的 miner.stop() 之后回车,即可停止挖矿。
检查账户余额:

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

挖矿成功.

交易

新建一个帐号用于交易:

1
2
3
4
5
6
7
> personal.newAccount("password1")
"0x2ed11e9f064572d2f2f651e4d7c3824f0b949022"
> personal.newAccount("password2")
"0x2935155a6980bad50a87a29b31c69adb9065cdba"
>
> personal.listAccounts
["0x1a36a03932e3b73292df56b6493058425e518857", "0x2ed11e9f064572d2f2f651e4d7c3824f0b949022", "0x2935155a6980bad50a87a29b31c69adb9065cdba"]

尝试产生交易

1
eth.sendTransaction({from:'0x1a36a03932e3b73292df56b6493058425e518857',to:'0x2ed11e9f064572d2f2f651e4d7c3824f0b949022',value:5})

Error: authentication needed: password or unlock
at web3.js:3143:20
at web3.js:6347:15
at web3.js:5081:36
at :1:1

通过 personal.listWallets 命令可以发现掌勺是Locked状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[{
accounts: [{
address: "0x1a36a03932e3b73292df56b6493058425e518857",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T05-16-25.359680161Z--1a36a03932e3b73292df56b6493058425e518857"
}],
status: "Locked",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T05-16-25.359680161Z--1a36a03932e3b73292df56b6493058425e518857"
}, {
accounts: [{
address: "0x2ed11e9f064572d2f2f651e4d7c3824f0b949022",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T07-23-58.161695617Z--2ed11e9f064572d2f2f651e4d7c3824f0b949022"
}],
status: "Locked",
url: "keystore:///home/wangy/ethereum/private_chain/private_chain_data_1/keystore/UTC--2018-03-08T07-23-58.161695617Z--2ed11e9f064572d2f2f651e4d7c3824f0b949022"
}]

以太坊的保护机制,每隔一段时间帐户就会自动锁定,这个时候任何以太币在账户之间的转换都会被拒绝,除非把该账户解锁

解锁帐号:

1
2
3
4
> personal.unlockAccount('0x1a36a03932e3b73292df56b6493058425e518857')
Unlock account 0x1a36a03932e3b73292df56b6493058425e518857
Passphrase: [Password]
true

输入密码password, 确认解锁帐号.

重新开始交易

1
2
3
eth.sendTransaction({from:'0x1a36a03932e3b73292df56b6493058425e518857',to:'0x2ed11e9f064572d2f2f651e4d7c3824f0b949022',value:5})
INFO [03-07|23:50:03] Submitted transaction fullhash=0x6d4fb888d21b09f39f71b6e06911b090dcd1160c068605ea5ff399aef1702380 recipient=0x2ed11e9f064572d2f2f651E4d7c3824F0B949022
"0x6d4fb888d21b09f39f71b6e06911b090dcd1160c068605ea5ff399aef1702380"

交易成功. 查看账户余额:

1
2
3
4
> eth.getBalance('0x1a36a03932e3b73292df56b6493058425e518857')
15000000000000000000
> eth.getBalance('0x2ed11e9f064572d2f2f651e4d7c3824f0b949022')
0

交易已完成, 怎么两个账户的余额没有发生变化呢?

查看交易池状态 txpool.status:

1
2
3
4
5
> txpool.status
{
pending: 1,
queued: 0
}

这笔交易还处于pending状态. 原来以太链上的交易是由矿工来完成的, 没有矿工, 以太链上的所有操作都是无法完成的.

矿工完成交易操作

让矿工开工 miner.start().

1
2
3
4
5
6
7
INFO [03-07|23:58:14] Transaction pool price threshold updated price=18000000000
null
> INFO [03-07|23:58:14] Starting mining operation
INFO [03-07|23:58:14] Commit new mining work number=4 txs=1 uncles=0 elapsed=352.367µs
INFO [03-07|23:58:57] Successfully sealed new block number=4 hash=62e46c…53ce76
INFO [03-07|23:58:57] 🔨 mined potential block number=4 hash=62e46c…53ce76
INFO [03-07|23:58:57] Commit new mining work number=5 txs=0 uncles=0 elapsed=1.954ms

查验交易状态

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
# 1. 检查交易池
> txpool.status
{
pending: 0,
queued: 0
}

# 2. 检查账户余额
> eth.getBalance('0x1a36a03932e3b73292df56b6493058425e518857')
129999999999999999995
> eth.getBalance('0x2ed11e9f064572d2f2f651e4d7c3824f0b949022')
5
>

# 3. 查看交易详情
> eth.getTransaction('0x6d4fb888d21b09f39f71b6e06911b090dcd1160c068605ea5ff399aef1702380')
{
blockHash: "0x62e46cef1eccf7fd5b87e22c0ea6a8d0faf085f6fe36ef450a77ae39ee53ce76",
blockNumber: 4,
from: "0x1a36a03932e3b73292df56b6493058425e518857",
gas: 90000,
gasPrice: 18000000000,
hash: "0x6d4fb888d21b09f39f71b6e06911b090dcd1160c068605ea5ff399aef1702380",
input: "0x",
nonce: 0,
r: "0xaebe9cee904684748822c069c48c3710fd18c5143146aa8cb9f5aacb3de48b14",
s: "0x7621ab90a1981e7a96791ebc457c3f1172a21d53fdfb3fe6c8d8a941eee8c76",
to: "0x2ed11e9f064572d2f2f651e4d7c3824f0b949022",
transactionIndex: 0,
v: "0xb3",
value: 5
}

转账成功.

gas 问题

  1. 给帐号2充值

    1
    2
    3
    > eth.sendTransaction({from:'0x1a36a03932e3b73292df56b6493058425e518857',to:'0x2935155a6980bad50a87a29b31c69adb9065cdba',value: 29999999999999999995})
    INFO [03-08|00:20:51] Submitted transaction fullhash=0x70bbeee1f047ae71d02888b75e64d02a1f5dbba2153ffd13489844b94dca99db recipient=0x2935155a6980BAd50A87a29b31C69adb9065cdbA
    "0x70bbeee1f047ae71d02888b75e64d02a1f5dbba2153ffd13489844b94dca99db"

    矿工完成交易后, 查看余额:

    1
    2
    3
    4
    5
    > eth.getBalance('0x2ed11e9f064572d2f2f651e4d7c3824f0b949022')
    5
    > eth.getBalance('0x2935155a6980bad50a87a29b31c69adb9065cdba')
    40000000000
    >

    帐号2给帐号1转账:

    1
    2
    3
    4
    5
    6
    7
    > personal.unlockAccount('0x2935155a6980bad50a87a29b31c69adb9065cdba')
    > eth.sendTransaction({from:'0x2935155a6980bad50a87a29b31c69adb9065cdba',to:'0x2ed11e9f064572d2f2f651e4d7c3824f0b949022',value: 5})
    Error: insufficient funds for gas * price + value
    at web3.js:3143:20
    at web3.js:6347:15
    at web3.js:5081:36
    at <anonymous>:1:1

    WHAT! 40000000000还不够手续费的啊. 看上面的交易’0x6d4fb888d21b09f39f71b6e06911b090dcd1160c068605ea5ff399aef1702380’ 可以看出gas是90000, 而 gasPrice是18000000000.

补充

以太币的单位

以太币不是无限可分的, 相对于比特币只一个计量单位, 比特币的计量单位较多. 以太币的最小单位是Wei, 一个以太币等于1018 Wei.
以太币有以下计量单位, 每一个单位都对应了以为大牛 ( 了解大牛 ):

单位 Wei 大牛
wei 1 Wei Dai
Kwei 103 Babbage
Mwei 106 Lovelace
Gwei 109 Shannon
Microether 1012 Szabo
Milliether 1015 Finney
Ether 1018 -

参考:

  1. http://blog.csdn.net/wo541075754/article/details/78926177
  2. https://www.cnblogs.com/zl03jsj/p/6858928.html
  3. http://blog.csdn.net/ddffr/article/details/73773255
  4. https://github.com/ethereum/go-ethereum/wiki/Private-network
  5. https://zhuanlan.zhihu.com/p/28994731