我的系统:CentOS7 64位
环境需要:Go 1.9以上版本
geth工具
WARN [11-04|09:34:47.411] System clock seems off by -10h15m43.047110838s, which can prevent network connectivity
WARN [11-04|09:34:47.411] Please enable network time synchronisation in system settings.
一.环境搭建
1.安装Go
下载源码 https://golang.org/dl/
找到适合自己操作系统的版本,必须1.9版本以上。我安装的是1.9.5
解压到/usr/local下
tar -zxvf go1.9.5.linux-amd64.tar.gz -C /usr/local/
创建软链接
ln -s /usr/local/go/bin/go /usr/bin/go
测试是否成功
go version
#go version go1.9.5 linux/amd64
2.安装geth工具
下载geth源码
git clone https://github.com/ethereum/go-ethereum.git
解压到/usr/local/下
unzip -d /usr/local/ go-ethereum-master.zip
编译源码
cd /usr/local/go-ethereum
make
成功的话会出现如下:
Done building.
Run "/usr/local/go-ethereum-master/build/bin/geth" to launch geth.
创建软链接 这样我们可以直接用geth命令,而不用输入路径
ln -s /usr/local/go-ethereum-master/build/bin/geth /usr/bin/geth
make过程中 如果出现以下错误:
exec: “gcc”: executable file not found in $PATH
则是没有安装gcc的原因,执行
yum install gcc
二.搭建私有链
1.创建用户
mkdir geth
cd geth
进入geth控制台
geth --datadir db --nodiscover console
创建用户
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0x12844bb3206f10a331557bffb7c8d34ee4ca8b65"
> personal.newAccount()
Passphrase:
Repeat passphrase:
"0xa6faa81cad6a3b038d9a51db80cedbe65184c7e2"
查看用户余额
> eth.getBalance(eth.accounts[0])
0
> eth.getBalance(eth.accounts[1])
0
给用户创建别名
> yujuan=eth.accounts[0]
"0x12844bb3206f10a331557bffb7c8d34ee4ca8b65"
> hcb=eth.accounts[1]
"0xa6faa81cad6a3b038d9a51db80cedbe65184c7e2"
可以看到在db目录下,有个keystore目录,里面已经存了我们刚刚创建的两个账户。
[root@localhost mychain]# tree
.
├── geth
│ ├── chaindata
│ │ ├── 000001.log
│ │ ├── CURRENT
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000000
│ ├── LOCK
│ ├── nodekey
│ ├── nodes
│ │ ├── 000001.log
│ │ ├── CURRENT
│ │ ├── LOCK
│ │ ├── LOG
│ │ └── MANIFEST-000000
│ └── transactions.rlp
├── geth.ipc
└── keystore
├── UTC--2018-11-04T16-02-52.181405978Z--12844bb3206f10a331557bffb7c8d34ee4ca8b65
└── UTC--2018-11-04T16-03-15.055116889Z--a6faa81cad6a3b038d9a51db80cedbe65184c7e2
2.传世区块配置文件
cd mychain
vim gensis.json
在gensis.json中输入如下内容
{
"alloc": {
"0x12844bb3206f10a331557bffb7c8d34ee4ca8b65": {
"balance": "999000000000000000000"
}
},
"config":{
"chainId":15,
"homesteadBlock":0,
"eip155Block":0,
"eip158Block":0
},
"nonce":"0x0000000000000001",
"mixhash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"difficulty": "0x01",
"coinbase":"0x0000000000000000000000000000000000000000",
"timestamp": "0x00",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x777573686f756865",
"gasLimit":"0xffffffff"
}
注意这里的alloc后的地址要用之前创建的地址
2.初始化
准备好创世区块配置文件后,需要初始化区块链,将上面的传世区块信息写入到区块链中。
始初始化区块
geth --datadir “./mychain/” init ./mychain/gensis.json
–datadir 指定数据存放目录
可能出现如下错误,原因是前面启动私有链时已经创建了默认的创世区块
Fatal: Failed to write genesis block: database already contains an incompatible genesis block
如下删除数据
geth removedb
成功的话可以看到如下结果
[root@localhost blockchain]# geth --datadir "./mychain/" init ./mychain/gensis.json
WARN [11-04|11:59:11.370] Sanitizing cache to Go's GC limits provided=1024 updated=324
INFO [11-04|11:59:11.380] Maximum peer count ETH=25 LES=0 total=25
INFO [11-04|11:59:11.383] Allocated cache and file handles database=/home/blockchain/mychain/geth/chaindata cache=16 handles=16
INFO [11-04|11:59:11.411] Writing custom genesis block
INFO [11-04|11:59:11.412] Persisted trie from memory database nodes=1 size=149.00B time=230.093µs gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-04|11:59:11.412] Successfully wrote genesis state database=chaindata hash=481cfe…9fd026
INFO [11-04|11:59:11.412] Allocated cache and file handles database=/home/blockchain/mychain/geth/lightchaindata cache=16 handles=16
INFO [11-04|11:59:11.425] Writing custom genesis block
INFO [11-04|11:59:11.426] Persisted trie from memory database nodes=1 size=149.00B time=1.090266ms gcnodes=0 gcsize=0.00B gctime=0s livenodes=1 livesize=0.00B
INFO [11-04|11:59:11.427] Successfully wrote genesis state database=lightchaindata hash=481cfe…9fd026
3.测试基本的操作
1)此时再查看余额,可以看到
> eth.accounts
["0x12844bb3206f10a331557bffb7c8d34ee4ca8b65", "0xa6faa81cad6a3b038d9a51db80cedbe65184c7e2"]
> eth.getBalance(eth.accounts[0])
999000000000000000000
2)转账
> a1=eth.accounts[0]
"0x12844bb3206f10a331557bffb7c8d34ee4ca8b65"
> a2=eth.accounts[1]
"0xa6faa81cad6a3b038d9a51db80cedbe65184c7e2"
我们从账户a1转10个以太币给a2
转账之前需要先对账户a1解锁
> personal.unlockAccount(a1,"123456")
true
转账
> eth.sendTransaction({from:a1, to:a2, value:web3.toWei(10,"ether")})
INFO [11-04|12:28:37.209] Setting new local account address=0x12844bB3206F10A331557bFfB7c8D34eE4ca8b65
INFO [11-04|12:28:37.210] Submitted transaction fullhash=0x21d4e590f240322b2ab16b750f6e7ded187242ecdfb17c49cb5d229649f1bc56 recipient=0xA6fAA81cAD6A3b038D9a51DB80CEDbe65184c7E2
"0x21d4e590f240322b2ab16b750f6e7ded187242ecdfb17c49cb5d229649f1bc56"
交易已经成功执行,最后一排即是交易的hash值
那我们再来看一下两个账户的余额
> eth.getBalance(a1)
999000000000000000000
> eth.getBalance(a2)
0
奇怪,为什么账户的余额根本就没有变呢。那是因为这里没有矿工参与,所以也没有人来将交易打包写入区块。
3)启动节点
geth --datadir "./mychain" --rpc --rpcaddr=0.0.0.0 --rpcport 8545 --rpccorsdomain "*" --rpcapi "eth,net,web3,personal,admin,ssh,txpool,debug,miner" --nodiscover --maxpeers 30 --networkid 1981 --mine --minerthreads 1 --etherbase "0x12844bb3206f10a331557bffb7c8d34ee4ca8b65" console
这样我们就成功运行了一个私有链,再稍过一会儿
就会发现出现了斧头,说明已经开始挖矿了
这个时候我们再来看刚刚转账后的账户余额
> web3.fromWei(eth.getBalance(eth.accounts[0]))
994
> web3.fromWei(eth.getBalance(eth.accounts[1]))
10
web3.fromWei是将Wei转换成ether
因为我们设置的矿工奖励地址是accounts[0],所以这里的账户余额是994,而不是989
4) 交易
通过attach命令,连接一个已经启动的节点,启动JS命令环境
geth --datadir './mychain/' attach ipc:./mychain/geth.ipc
成功进入
[root@localhost blockchain]# geth --datadir './mychain/' attach ipc:./mychain/geth.ipc
WARN [11-04|14:01:44.332] Sanitizing cache to Go's GC limits provided=1024 updated=324
Welcome to the Geth JavaScript console!
instance: Geth/v1.8.18-unstable/linux-amd64/go1.9.5
coinbase: 0x12844bb3206f10a331557bffb7c8d34ee4ca8b65
at block: 1 (Sun, 04 Nov 2018 12:43:43 EST)
datadir: /home/blockchain/mychain
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
现在开始挖矿
可以通过miner.setEtherbase(eth.accounts[0])来设置挖矿奖励地址
> eth.accounts
["0x12844bb3206f10a331557bffb7c8d34ee4ca8b65", "0xa6faa81cad6a3b038d9a51db80cedbe65184c7e2", "0x0cdba6a391a52155042d4709a90fbc9ed3b72f06"]
> a2=eth.accounts[2]
"0x0cdba6a391a52155042d4709a90fbc9ed3b72f06"
> a0=eth.accounts[0]
"0x12844bb3206f10a331557bffb7c8d34ee4ca8b65"
> personal.unlockAccount(a0)
Unlock account 0x12844bb3206f10a331557bffb7c8d34ee4ca8b65
Passphrase:
true
> eth.sendTransaction({from:a0,to:a2,value:web3.toWei(20,"ether")})
"0x0d711995130df3809294b5e8f62652a91cd9154188282b10c250fc99a6d06745"
将账户a2设置为挖矿奖励地址
> miner.setEtherbase(a2)
true
> eth.coinbase
"0x0cdba6a391a52155042d4709a90fbc9ed3b72f06"
>
现在已经有一个未打包进区块的交易在交易池中。txpool.status返回正在等待打包的交易。pending表示已经提交还未被处理的交易
> txpool.status
{
pending: 1,
queued: 0
}
查看pending交易详情
> txpool.inspect.pending
{
0x12844bB3206F10A331557bFfB7c8D34eE4ca8b65: {
1: "0x0CDBA6A391a52155042D4709A90fBC9ed3B72F06: 20000000000000000000 wei + 90000 gas × 1000000000 wei"
}
}
5)挖矿
要使交易被处理,必须要挖矿,
这里启动挖矿,然后等到挖到第一个区块之后就停止挖矿
miner.start(1);admin.sleepBlocks(1);miner.stop();
6)区块
之前交易的hash值0x0d711995130df3809294b5e8f62652a91cd9154188282b10c250fc99a6d06745
得到发起交易时的详情
eth.getTransaction("0x0d711995130df3809294b5e8f62652a91cd9154188282b10c250fc99a6d06745")
下面是交易被打包进区块时详细信息:
eth.getTransactionReceipt("0x0d711995130df3809294b5e8f62652a91cd9154188282b10c250fc99a6d06745")
查看当前区块总数
eth.blockNumber
查询最新区块
eth.getBlock(‘latest’)
返回区块number的信息
eth.getBlock(0)
4远程节点管理
重新开一台机子(当然贫困的我是重开了一个虚拟机)
依照上面配置环境后启动节点。注意gensis.block需要一样。
添加其他节点
可以通过admin.addPeer()方法连接到其他节点,两个节点要想联通,必须保证网络是连接的,并且启动时指定的networkid相同。
通过下面的命令获得另一个节点的ecode信息
> admin.nodeInfo.enode
"enode://c56903836723db6d643a2b9fb13e11ed30e53618606c600f7c0ebab89246d24b381df7ef6f08b19461b423b72d88d62dcbf6aa2989024093b24536633977515a@127.0.0.1:30303?discport=0"
链接节点2:
> admin.addPeer("enode://c56903836723db6d643a2b9fb13e11ed30e53618606c600f7c0ebab89246d24b381df7ef6f08b19461b423b72d88d62dcbf6aa2989024093b24536633977515a@192.168.183.137:30303?discport=0")
true
注意这里需要把ip地址改成节点2的ip地址。
连接成功后,节点二会开始同步节点一的区块,同步完成后,任意一个节点开始挖矿,另一个节点会自动同步区块。
查看已连接到的节点