1 主机设备
IP | HOSTNAME | USERNAME |
172.16.xx.170 | tuijian007 | tuijian |
172.16.xx.153 | tuijian005 | tuijian |
172.16.xx.154 | tuijian006 | tuijian |
目录说明:
/data01/recom/go :go语言安装目录
/data01/recom/go-ethereum-1.8.12 :go-ethereum-1.8.12安装目录(修改源码重新编译过的)
/data01/recom/geth/ykchain/geth :geth私有链数据保存目录
/data01/recom/geth/ykchain/keystore :geth私有链账户保存目录
/data01/recom/geth/scripts:初始化、启动geth脚本
2 golang安装
2.1 下载软件包
下载go语言安装包,版本1.4及以上
https://www.golangtc.com/download
2.2 解压安装
tar -xzf go1.9.2.linux-amd64.tar.gz
2.3 配置环境变量
export GOROOT=/data01/recom/go
export PATH=$PATH:/data01/recom/go/bin
2.4 检查Go
通过命令go version查看GO语言版本,以确定是否安装成功
[tuijian@tuijian005 ~]$ go version
go version go1.9.2 linux/amd64
在所有节点上按照2.2-2.4步骤部署go lang。
3 go-ethereum安装
3.1 下载软件包
下载go-ethereum 1.8.12软件包,下载地址:
https://github.com/ethereum/go-ethereum/tree/v1.8.12
3.2 解压软件
unzip go-ethereum-1.8.12.zip
3.3 make 编译
前提:yum -y install gcc* make
make编译go-ethereum-1.8.12:
[root@tuijian005 go-ethereum-1.8.12]# make
build/env.sh go run build/ci.go install ./cmd/geth
>>> /data01/recom/go/bin/go install -v ./cmd/geth
Done building.
Run "/data01/recom/go-ethereum-1.8.12/build/bin/geth" to launch geth.
3.4 配置环境变量
export PATH=$PATH:/data01/recom/go-ethereum-master/build/bin
3.5 检查go-ethereum
通过命令geth version查看geth版本,以确定是否安装成功
[root@tuijian005 go-ethereum-1.8.12]# geth version
Geth
Version: 1.8.12-stable
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.9.2
Operating System: linux
GOPATH=
GOROOT=/data01/recom/go
将3.3编译后的geth目录下所有文件同步到其他节点,在所有节点上按照3.4步骤配置geth环境变量。
4 创建私链
在数据磁盘上新建/data01/recom/geth目录和/data01/recom/geth/ykchain,用于保存genesis.json和私有链的相关信息,目录结构如下:
4.1 创建私有账户
创建两个预制账户,分别预设1000万ether,过程如下:
geth --datadir /data01/recom/geth/ykchain account new
账户一:ykc~private&acc^01*
Address: {edfaca73af1810b80834404f493e5bea07fe1a0c}
账户二:ykc~private&acc^02*
Address: {d1e4f1f52eb5a1062ea2e726eb499914b398c1b3}
备注:使用账户地址时,在如上Address前增加”0x”
4.2 初始化创世块
4.2.1 新建genesis.json
新建创世区块文件:genesis.json,保存于geth目录下,内容如下:
{
"config": {
"chainId": 314591,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"coinbase" : "0x0000000000000000000000000000000000000000",
"difficulty" : "0x20000",
"extraData" : "",
"gasLimit" : "0xffffffff",
"nonce" : "0x0000000000000042",
"mixhash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"parentHash" : "0x0000000000000000000000000000000000000000000000000000000000000000",
"timestamp" : "0x00",
"alloc" : {
"0xedfaca73af1810b80834404f493e5bea07fe1a0c":{"balance":"10000000000000000000000000"},
"0xd1e4f1f52eb5a1062ea2e726eb499914b398c1b3":{"balance":"10000000000000000000000000"}
}
}
参数说明:
l config:区块链相关的基本配置参数。chainId是链编号,用于指定链 的 id(chainId,也被称为 network id),此处我们指定为 314591;alloc中为以太坊账户信息,可以留空,也可以预先配置好以太坊账户及其余额,这里账户余额以wei为单位,格式举例: "0x<#某账户地址#>":{“balance”:”1000000000000000000”}。
l nonce:一个 64 位随机数,用于挖矿,其设置需要满足以太坊的黄皮书([2])的要求
l mixhash:与 nonce 配合用于挖矿,由上一个区块的一部分生成的 hash,其设置同样需 要满足以太坊的黄皮书的要求
l difficulty:设置当前区块的难度,如果难度过大,CPU 挖矿就很难,这里设置较小难度0x800
l coinbase:矿工的账号,此处可随便填
l timestamp:设置创世块的时间戳
l parentHash:上一个区块的 hash 值,因为是创世块,所以这个值是 0
l extraData:额外信息,这里留空。
l gasLimit:该值设置对 GAS 的消耗总量限制,用来限制区块能包含的交易信息总和,因为我们是私有链,所以填最大。
4.2.2 初始化配置
通过命令 geth init /data01/recom/geth/genesis.json --datadir /data01/recom/geth/ykchain 初始化配置
[tuijian@tuijian005 geth]$ geth init /data01/recom/geth/genesis.json --datadir /data01/recom/geth/ykchain
INFO [08-03|09:45:14.126] Maximum peer count ETH=25 LES=0 total=25
INFO [08-03|09:45:14.127] Allocated cache and file handles database=/data01/recom/geth/ykchain/geth/chaindata cache=16 handles=16
INFO [08-03|09:45:14.168] Writing custom genesis block
INFO [08-03|09:45:14.168] Persisted trie from memory database nodes=0 size=0.00B time=29.298µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [08-03|09:45:14.169] Successfully wrote genesis state database=chaindata hash=56c5b5…1fdf50
INFO [08-03|09:45:14.169] Allocated cache and file handles database=/data01/recom/geth/ykchain/geth/lightchaindata cache=16 handles=16
INFO [08-03|09:45:14.188] Writing custom genesis block
INFO [08-03|09:45:14.188] Persisted trie from memory database nodes=0 size=0.00B time=4.292µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [08-03|09:45:14.188] Successfully wrote genesis state database=lightchaindata hash=56c5b5…1fdf50
在所有节点上执行4.1.1和4.1.2步骤,对创世区块进行初始化
4.3 启动私有链
nohup geth --identity "YKChain" --datadir "/data01/recom/geth/ykchain" --rpc --rpcaddr "0.0.0.0" --rpcport "8545" --rpcapi eth,net,web3,personal,admin,txpool,shh,debug,miner --nodiscover --networkid 314591 --port 8920 > nohup.out &
INFO [08-03|09:46:02.217] Maximum peer count ETH=25 LES=0 total=25
INFO [08-03|09:46:02.219] Starting peer-to-peer node instance=Geth/v1.8.12-stable/linux-amd64/go1.9.2
INFO [08-03|09:46:02.219] Allocated cache and file handles database=/data01/recom/geth/ykchain/geth/chaindata cache=768 handles=1024
INFO [08-03|09:46:02.286] Initialised chain configuration config="{ChainID: 314591 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Constantinople: <nil> Engine: unknown}"
INFO [08-03|09:46:02.286] Disk storage enabled for ethash caches dir=/data01/recom/geth/ykchain/geth/ethash count=3
INFO [08-03|09:46:02.286] Disk storage enabled for ethash DAGs dir=/home/tuijian/.ethash count=2
INFO [08-03|09:46:02.286] Initialising Ethereum protocol versions="[63 62]" network=314591
INFO [08-03|09:46:02.288] Loaded most recent local header number=0 hash=56c5b5…1fdf50 td=2048
INFO [08-03|09:46:02.288] Loaded most recent local full block number=0 hash=56c5b5…1fdf50 td=2048
INFO [08-03|09:46:02.288] Loaded most recent local fast block number=0 hash=56c5b5…1fdf50 td=2048
INFO [08-03|09:46:02.288] Regenerated local transaction journal transactions=0 accounts=0
INFO [08-03|09:46:02.289] Starting P2P networking
INFO [08-03|09:46:02.290] RLPx listener up self="enode://56663fab865ec16be3b91e6162ffca389e285bdce6c2dcd809c84af256b4b29062d0541d09cb8b040c144bacb5765b10ca2739eae567870443c10fce1c8ea494@[::]:8920?discport=0"
INFO [08-03|09:46:02.296] IPC endpoint opened url=/data01/recom/geth/ykchain/geth.ipc
INFO [08-03|09:46:02.296] HTTP endpoint opened url=http://0.0.0.0:8545 cors= vhosts=localhost
在所有节点上执行4.2步骤,启动私有链,但是需保证所有节点的rpcport和port不同,其他信息相同,特别是networkid。
4.4 启动console
因为采用了nohup后台运行的方式启动geth,所以通过attach启动console,命令如下:
geth --datadir '/data01/recom/geth/ykchain' attach ipc:/data01/recom/geth/ykchain/geth.ipc
[tuijian@tuijian005 geth]$ geth --datadir '/data01/recom/geth/ykchain' attach ipc:/data01/recom/geth/ykchain/geth.ipc
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.12-stable/linux-amd64/go1.9.2
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
查看节点信息:admin.nodeInfo
查看节点个数:net.peerCount
查看节点列表:admin.peers
4.5 创建账户
查看帐户:web3.eth.accounts
新建账号:web3.personal.newAccount("密码")
153:"ykcnode1*8920*":"0x69a3f9b55918b1cdac88159f7b4175b255db784a"
154:"ykcnode2*8920*":"0x6c22cd4f5030027226a347dd15a4b457cff1e0a9"
170:"ykcnode3*8920*":"0x51a9ed7b62d99e7b34a78c30624b1e126f15d4af"
开始挖矿:miner.start(),通过miner.start(1)指定线程数,默认4
停止挖矿:miner.stop()
4.6 加入其他节点
4.6.1 静态加入其他节点
本次操作以153为基础节点,加入154和170两个节点。如果这两个节点,我们需要一直和它保持链接,那么你可以把那个节点配置成你的静态节点。
n 配置方法
n 在geth数据目录下创建static-nodes.json ,目录结构:<datadir>/static-nodes.json,把节点信息写入这个文件,格式如下:
["enode://pubkey@ip:port","enode://pubkey@ip:port"]
n 本例中配置为:
["enode://8f6378c1a8a33cb86107cc2fbb9295b7adae1ec171ab54b85f8f025b606a3340d571a730b8ef1039dbff9b1b5a609b5deaaef3f7b165ab4c2e995c674c783417@172.16.38.154:8921, "enode://e336854a8da497f03ee1d8579dc83dd05959cbc03c3c50be7d7a3bcd3691f3c9113707425af1662ae0eddb75e2945b2c4a8a5dd45ebcbf07ebcb05293b5de425@172.16.38.170:8922"]
4.6.2 动态加入其他节点
通过admin.addPeer命令加入其他节点,本次操作以153为基础节点,加入154和170两个节点,过程如下:
4.6.2.1 获取加入节点的enode
分别在154和170节点geth终端执行admin.nodeInfo.enode,获取各自enode信息。
获取154节点enode:
> admin.nodeInfo.enode
"enode://8f6378c1a8a33cb86107cc2fbb9295b7adae1ec171ab54b85f8f025b606a3340d571a730b8ef1039dbff9b1b5a609b5deaaef3f7b165ab4c2e995c674c783417@[::]:8921?discport=0"
>
获取170节点enode:
> admin.nodeInfo.enode
"enode://e336854a8da497f03ee1d8579dc83dd05959cbc03c3c50be7d7a3bcd3691f3c9113707425af1662ae0eddb75e2945b2c4a8a5dd45ebcbf07ebcb05293b5de425@[::]:8922?discport=0"
>
保留红色字体部分,并将[::]替换成节点自身的网络ip,最终结果如下:
154节点enode结果:
"enode://8f6378c1a8a33cb86107cc2fbb9295b7adae1ec171ab54b85f8f025b606a3340d571a730b8ef1039dbff9b1b5a609b5deaaef3f7b165ab4c2e995c674c783417@172.16.38.154:8921"
170节点enode结果:
"enode://e336854a8da497f03ee1d8579dc83dd05959cbc03c3c50be7d7a3bcd3691f3c9113707425af1662ae0eddb75e2945b2c4a8a5dd45ebcbf07ebcb05293b5de425@172.16.38.170:8922"
4.6.2.2 加入节点
在153节点geth终端中执行如下命令,分别加入154和170节点:
加入154节点:
> admin.addPeer("enode://8f6378c1a8a33cb86107cc2fbb9295b7adae1ec171ab54b85f8f025b606a3340d571a730b8ef1039dbff9b1b5a609b5deaaef3f7b165ab4c2e995c674c783417@172.16.38.154:8921")
true
>
>
加入170节点:
> admin.addPeer("enode://e336854a8da497f03ee1d8579dc83dd05959cbc03c3c50be7d7a3bcd3691f3c9113707425af1662ae0eddb75e2945b2c4a8a5dd45ebcbf07ebcb05293b5de425@172.16.38.170:8922")
true
>
>
4.6.2.3 查看验证节点加入是否成功
查看节点个数:net.peerCount
> net.peerCount
2
>
查看节点列表:admin.peers
>
> admin.peers
[{
caps: ["eth/63"],
id: "8f6378c1a8a33cb86107cc2fbb9295b7adae1ec171ab54b85f8f025b606a3340d571a730b8ef1039dbff9b1b5a609b5deaaef3f7b165ab4c2e995c674c783417",
name: "Geth/v1.8.12-stable/linux-amd64/go1.9.2",
network: {
inbound: false,
localAddress: "172.16.38.153:35617",
remoteAddress: "172.16.38.154:8921",
static: true,
trusted: false
},
protocols: {
eth: {
difficulty: 2048,
head: "0x56c5b55dd502c597854eb295e1166372649ec5b989c9d31d928883caf51fdf50",
version: 63
}
}
}, {
caps: ["eth/63"],
id: "e336854a8da497f03ee1d8579dc83dd05959cbc03c3c50be7d7a3bcd3691f3c9113707425af1662ae0eddb75e2945b2c4a8a5dd45ebcbf07ebcb05293b5de425",
name: "Geth/v1.8.12-stable/linux-amd64/go1.9.2",
network: {
inbound: false,
localAddress: "172.16.38.153:53998",
remoteAddress: "172.16.38.170:8922",
static: true,
trusted: false
},
protocols: {
eth: {
difficulty: 2048,
head: "0x56c5b55dd502c597854eb295e1166372649ec5b989c9d31d928883caf51fdf50",
version: 63
}
}
}]
>
5 修改源码
修改go-ethereum-1.8.12/consensus/ethash目录下consensus.go文件中代码,将
return CalcDifficulty(chain.Config(), time, parent)
替换成
return big.NewInt(1)
参考:
https://hackernoon.com/how-to-reduce-block-difficulty-in-ethereum-private-testnet-2ad505609e82?gi=1ca92726aa1f
6 交易才挖矿
编写minebytrans.js,代码如下:
var mining_threads = 1
var txBlock = 0
function checkWork() {
if (eth.getBlock("pending").transactions.length > 0) {
txBlock = eth.getBlock("pending").number
if (eth.mining) return;
console.log(" Transactions pending. Mining...");
miner.start(mining_threads)
while (eth.getBlock("latest").number < txBlock + 12) {
if (eth.getBlock("pending").transactions.length > 0) txBlock = eth.getBlock("pending").number;
}
console.log(" 12 confirmations achieved; mining stopped.");
miner.stop()
}
else {
miner.stop()
}
}
eth.filter("latest", function(err, block) { checkWork(); });
eth.filter("pending", function(err, block) { checkWork(); });
checkWork();
启动以太坊私链时,通过js加载上述js文件,限制区块不间断挖矿
参考:
https://ethereum.stackexchange.com/questions/3151/how-to-make-miner-to-mine-only-when-there-are-pending-transactions