基于以太坊实现局域网多节点挖矿

上一篇文章简要介绍了本地实现私有链挖矿和转账,现在这篇文章主要实现局域网下实现多个节点实现挖矿

前提,已经安装了go-ethereum,如果没有安装请移步基于以太坊创建私有链进行挖矿、交易

机器:Ubuntu(两个节点),Mac(一个节点)

创建创世节点

创建节点json文件

$ mkdir my_eth2
$ cd my_eth2
$ vim genesis.json
{
  "config": {
        "chainId": 10,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
  "coinbase"   : "0x0000000000000000000000000000000000000000",
  "difficulty" : "0x20000",
  "extraData"  : "",
  "gasLimit"   : "0x2fefd8",
  "nonce"      : "0x0000000000000042",
  "mixhash"    : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
  "timestamp"  : "0x00",
  "alloc"      : {}
}

生成节点(以下使用节点1代指)

$ geth --datadir data00 init genesis.json
WARN [01-25|17:04:25] No etherbase set and no accounts found as default
INFO [01-25|17:04:25] Allocated cache and file handles         database=/home/ubuntu/my_eth2/data00/geth/chaindata cache=16 handles=16
INFO [01-25|17:04:25] Writing custom genesis block
INFO [01-25|17:04:25] Successfully wrote genesis state         database=chaindata                                  hash=5e1fc7…d790e0
INFO [01-25|17:04:25] Allocated cache and file handles         database=/home/ubuntu/my_eth2/data00/geth/lightchaindata cache=16 handles=16
INFO [01-25|17:04:25] Writing custom genesis block
INFO [01-25|17:04:25] Successfully wrote genesis state         database=lightchaindata                                  hash=5e1fc7…d790e0

启动节点1

$ geth --datadir ./data00 --networkid 5201314 console

创建账号

> personal.newAccount("123")
"0x0b514e769e4e1990f8fb0f0f9d876d7f2b9fa5ba"

本地创建第二个节点(以下使用节点2代指)

新开窗口,创建节点2

$ geth --datadir data01 init genesis.json
WARN [01-25|17:07:33] No etherbase set and no accounts found as default
INFO [01-25|17:07:33] Allocated cache and file handles         database=/home/ubuntu/my_eth2/data01/geth/chaindata cache=16 handles=16
INFO [01-25|17:07:33] Writing custom genesis block
INFO [01-25|17:07:33] Successfully wrote genesis state         database=chaindata                                  hash=5e1fc7…d790e0
INFO [01-25|17:07:33] Allocated cache and file handles         database=/home/ubuntu/my_eth2/data01/geth/lightchaindata cache=16 handles=16
INFO [01-25|17:07:33] Writing custom genesis block
INFO [01-25|17:07:33] Successfully wrote genesis state         database=lightchaindata                                  hash=5e1fc7…d790e0

运行节点2

$ geth --datadir data01 --networkid 5201314 --ipcdisable --port 61910 --rpcport 8200 console

创建节点2的账号

 > personal.newAccount("123")
"0x3babf1eeb8d5d29acc4d1f6408529b36b4e6f880"

在Mac上创建新节点,以下使用(节点3代指)

创世节点的json文件要和Ubuntu一致

初始化节点3

$ geth --datadir data00 init genesis.json
WARN [01-25|17:14:10] No etherbase set and no accounts found as default
INFO [01-25|17:14:10] Allocated cache and file handles         database=/Users/feilong/my_chain2/data00/geth/chaindata cache=16 handles=16
INFO [01-25|17:14:10] Writing custom genesis block
INFO [01-25|17:14:10] Successfully wrote genesis state         database=chaindata                                      hash=5e1fc7…d790e0
INFO [01-25|17:14:10] Allocated cache and file handles         database=/Users/feilong/my_chain2/data00/geth/lightchaindata cache=16 handles=16
INFO [01-25|17:14:10] Writing custom genesis block
INFO [01-25|17:14:10] Successfully wrote genesis state         database=lightchaindata                                      hash=5e1fc7…d790e0

运行节点3

$ geth --datadir data00 --networkid 5201314 --ipcdisable --port 61911 --rpcport 8200 console #使用61911端口,保证networkid一致

创建账号

> personal.newAccount("123")
"0xf81b1d6c0e0835790c7e4af8a02301a67e5a0dcb"

节点1和节点2建立联系

节点2运行 > admin.nodeInfo.enode 查看node信息

> admin.nodeInfo.enode
"enode://d5bb9fecc8e997905220b5e8c0db8396880bd5326143614b33f81ead534fc4d8282cbdda620fb81eaea66c359c3acd7d590f64981099b3cc063fddae9ac376d9@192.168.164.210:61910"

节点1添加节点2

> admin.addPeer("enode://d5bb9fecc8e997905220b5e8c0db8396880bd5326143614b33f81ead534fc4d8282cbdda620fb81eaea66c359c3acd7d590f64981099b3cc063fddae9ac376d9@192.168.164.210:61910")
true

节点1和节点2运行> net

> net
{
  listening: true,
  peerCount: 1, #说明添加成功
  version: "5201314",
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}

节点1和节点3建立联系

节点3运行 > admin.nodeInfo.enode 查看node信息

>  admin.nodeInfo.enode
"enode://34dcd9b7e64b24a25fe25b6e2aab6fc10525a439b2174ad79bd55bbf867f98060f7eef26c83223ae665372afa819ffd5c9c49a039c4e5e9c4e72be35a3b65aa8@192.168.164.210:61911"

节点1添加节点3

> admin.addPeer("enode://34dcd9b7e64b24a25fe25b6e2aab6fc10525a439b2174ad79bd55bbf867f98060f7eef26c83223ae665372afa819ffd5c9c49a039c4e5e9c4e72be35a3b65aa8@192.168.164.210:61911")
true

分别查看节点1和节点3链接情况

节点1

> net
{
  listening: true,
  peerCount: 2, ##节点1连接两个节点
  version: "5201314",
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}

节点3

> net
{
  listening: true,
  peerCount: 1,
  version: "5201314",
  getListening: function(callback),
  getPeerCount: function(callback),
  getVersion: function(callback)
}

节点挖矿测试

使用任一节点挖矿,然后观察其他两个控制台,发现都会有同步的数据,说明节点2和节点3也是连接的状态(由于电脑性能原因,挖矿的时候需要等percentage到达100之后才会开始)

遇到的坑

  • 要保证创世节点的json文件一致
  • 保证在统一局域网内,使用Telnet命令测试
  • 节点2和节点3的端口注意不要重复

基于以太坊创建私有链进行挖矿、交易

要说2018年什么最火,无疑就是区块链。比特币的疯狂上涨,每个比特币超过了1万美金。随之而来的就是区块链的技术。
以太坊(Ethereum)并不是一个机构,而是一款能够在区块链上实现智能合约、开源的底层系统。本文主要是通过以太坊,创建私有链,实现挖矿和交易。

安装golang

克隆项目
$ git clone https://github.com/golang/go.git
安装go 1.4

golang 是自编译,所以如果安装版本 >=1.5 需要先编译1.4版本,然后再安装其他版本

$ cp -r go/ $HOME/go1.4 #复制一份文件夹,用于编译1.4版本
$ cd $HOME/go1.4
$ git checkout release-branch.go1.4
$ cd src
$ ./make.bash # 进行编译

编译之后,开始安装go 1.9版本

$ cd $HOME/install/go
$ git checkout release-branch.go1.9
$ cd src/
$ ./all.bash #安装1.9版本
##### Building Go bootstrap tool.
cmd/dist

##### Building Go toolchain using /home/test/go1.4.
bootstrap/cmd/internal/dwarf
bootstrap/cmd/internal/objabi
bootstrap/cmd/internal/src
bootstrap/cmd/internal/sys
bootstrap/cmd/internal/obj
bootstrap/cmd/internal/obj/arm
bootstrap/cmd/internal/obj/arm64
bootstrap/cmd/internal/obj/mips
bootstrap/cmd/internal/obj/ppc64
bootstrap/cmd/internal/obj/s390x
... ##各种编译安装信息
##### API check
Go version is "go1.9.2", ignoring -next /home/test/install/go/api/next.txt

ALL TESTS PASSED

---
Installed Go for linux/amd64 in /home/test/install/go
Installed commands in /home/test/install/go/bin
*** You need to add /home/test/install/go/bin to your PATH.

配置环境变量

$ export PATH=$PATH:/home/test/install/go/bin

查看安装版本

$ go version
go version go1.9.2 linux/amd64
克隆go-ethereum
$ git clone https://github.com/ethereum/go-ethereum.git
安装以太坊
$ make geth

build/env.sh go run build/ci.go install ./cmd/geth
>>> /home/test/install/go/bin/go install -ldflags -X main.gitCommit=5d4267911a7791bfa60f275a97347372fbf0ce99 -v ./cmd/geth
github.com/ethereum/go-ethereum/common/hexutil
github.com/ethereum/go-ethereum/crypto/sha3
github.com/ethereum/go-ethereum/common
...
github.com/ethereum/go-ethereum/vendor/github.com/gizak/termui
github.com/ethereum/go-ethereum/vendor/github.com/naoina/go-stringutil
github.com/ethereum/go-ethereum/vendor/github.com/naoina/toml/ast
github.com/ethereum/go-ethereum/vendor/github.com/naoina/toml
github.com/ethereum/go-ethereum/cmd/geth
Done building.
Run "/home/test/install/go-ethereum/build/bin/geth" to launch geth.
创建连接
$ ln -s  /home/test/install/go-ethereum/build/bin/geth /usr/local/bin/geth

创建私有链

创建创世区块
{
    "config": {
        "chainId": 15,
        "homesteadBlock": 0,
        "eip155Block": 0,
        "eip158Block": 0
    },
    "coinbase" : "0x0000000000000000000000000000000000000000",
    "difficulty" : "0x40000",
    "extraData" : "",
    "gasLimit" : "0xffffffff",
    "nonce" : "0x0000000000000042",
    "mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
    "timestamp" : "0x00",
    "alloc": { }
}
$ mkdir my_chain
$ cd my_chain
$ vim genesis.json # json文件的内容是上面的json字符串
创建创世节点,并且初始化数据
$ geth --datadir data00 init genesis.json

data00就是用来保存创世节点的数据

启动节点,指定networkid
$ geth --datadir ./data00 --networkid 5201314 console #使用console 支持命令行模式

创建节点的账号
# 在console命令模式下
> personal.newAccount("123")
"0x9ff8676095e5999bf82eafeab98192e33ad74364"
开始进行挖矿
> miner.start()
INFO [01-23|00:14:37] Updated mining threads                   threads=0
INFO [01-23|00:14:37] Transaction pool price threshold updated price=18000000000
INFO [01-23|00:14:37] Etherbase automatically configured       address=0x9FF8676095e5999bf82EafEaB98192E33ad74364
null
> INFO [01-23|00:14:37] Starting mining operation
INFO [01-23|00:14:37] Commit new mining work                   number=1 txs=0 uncles=0 elapsed=146.511µs
INFO [01-23|00:14:43] Generating DAG in progress               epoch=0 percentage=0 elapsed=4.529s
INFO [01-23|00:14:48] Generating DAG in progress               epoch=0 percentage=1 elapsed=8.913s
INFO [01-23|00:14:52] Generating DAG in progress               epoch=0 percentage=2 elapsed=13.169s
INFO [01-23|00:14:56] Generating DAG in progress               epoch=0 percentage=3 elapsed=17.298s
INFO [01-23|00:15:01] Generating DAG in progress               epoch=0 percentage=4 elapsed=21.964s
...

等到percentage加载到100的时候就开始进行挖矿

结束挖矿
> miner.stop()
查看挖矿的金额
> eth.getBalance(eth.accounts[0])
5000000000000000000
新开一个窗口,创建第二个节点
$ geth --datadir data01 init genesis.json
运行第二个节点

networkid需要和第一个账号相同

$ geth --datadir data01 --networkid 5201314 --ipcdisable --port 61910 --rpcport 8200 console #使用命令行模式
创建账号
> personal.newAccount("456")
"0xfc350d17b0fb92eeb0a3bab80116c27d9f7e40d1"
开始进行挖矿
> miner.start()
结束挖矿
> miner.stop()

用户交易

回到第一个节点

查看节点信息

> admin.nodeInfo.enode
"enode://49e538b3f090a04e97f56a7fd1e6223c29599535d5e93010349147dee334b690744504f057ae11adb2804baada222375a56398ef42be536c595c6197a4a7cb2d@[::]:30303"
切换到第二个节点窗口

建立联系, 添加第一个节点enode

 admin.addPeer("enode://49e538b3f090a04e97f56a7fd1e6223c29599535d5e93010349147dee334b690744504f057ae11adb2804baada222375a56398ef42be536c595c6197a4a7cb2d@[::]:30303")
true
切换到第一个控制台

查看建立的联系数量

> net.peerCount
1

peerCount=1,说明已经建立了联系

开始进行交易

切换到一个控制台,交易之前,需要先解锁账号才行

> personal.unlockAccount(eth.accounts[0], "123")
true

返回true说明已经解锁成功

> eth.sendTransaction({from: "0x9ff8676095e5999bf82eafeab98192e33ad74364", to: "0xfc350d17b0fb92eeb0a3bab80116c27d9f7e40d1", value: web3.toWei(1, "ether")})

to和form分别是接受和发送的账号,也就是personal.listAccounts里面的账号

查看确认下交易信息

> eth.pendingTransactions
[{
    blockHash: null,
    blockNumber: null,
    from: "0x9ff8676095e5999bf82eafeab98192e33ad74364",
    gas: 90000,
    gasPrice: 18000000000,
    hash: "0x6146513432b27b6a27f54b64fcf0a30dc90290452dfd25e282a05aaf423f4afa",
    input: "0x",
    nonce: 0,
    r: "0x77644ff132f800da9b2d8133c796916f956061a491b55e3cbbd0d710f5157199",
    s: "0x9dbe268e152e5fc15421efa5b00e5d4a601ef4cb2655b577901fd96c5d3c959",
    to: "0xfc350d17b0fb92eeb0a3bab80116c27d9f7e40d1",
    transactionIndex: 0,
    v: "0x42",
    value: 1000000000000000000
}]

开始进行挖矿,使交易生效

> miner.start()
确认交易是否成功

在一个和第二个控制台分别运行命令,确认是否交易成功

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

总结

挖矿对电脑要求比较高,我使用阿里云的服务器,1核1G基本的配置,两个节点同时挖矿,经常出现CPU吃满的情况。

还有一个比较奇怪的,当发起交易的时候,一定要进行挖矿操作,才能使交易生效。

参考文献

blockchain随笔