第二节中了解了使用geth搭建以太坊私有网络,这一次则要在私有网络中建立多个node组成的集群,并互相发现,产生交易.
为了在本地网络运行多个以太坊节点的实例,必须确保一下几点:
1. 每个实例都有独立的数据目录(--datadir)
2. 每个实例运行都有独立的端口.(eth和rpc两者都是)(--port 和 --rpcprot)
3. 在集群的情况下, 实例之间都必须要知道彼此.
4. 唯一的ipc通信端点,或者禁用ipc.
启动第一个节点(指定端口,并禁用ipc),运行命令和结果如下:
~/Documents/private-geth geth --datadir ./data/00 --networkid 314590 --ipcdisable --port 61910 --rpcport 8200 console
INFO [05-29|16:18:59] Starting peer-to-peer node instance=Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1
INFO [05-29|16:18:59] Allocated cache and file handles database=/home/zl/Documents/private-geth/data/00/geth/chaindata cache=128 handles=1024
INFO [05-29|16:18:59] Initialised chain configuration config="{ChainID: 15 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Engine: unknown}"
INFO [05-29|16:18:59] Disk storage enabled for ethash caches dir=/home/zl/Documents/private-geth/data/00/geth/ethash count=3
INFO [05-29|16:18:59] Disk storage enabled for ethash DAGs dir=/home/zl/.ethash count=2
INFO [05-29|16:18:59] Initialising Ethereum protocol versions="[63 62]" network=314590
INFO [05-29|16:18:59] Loaded most recent local header number=29 hash=8ff3ff…dac4a2 td=7372364
INFO [05-29|16:18:59] Loaded most recent local full block number=29 hash=8ff3ff…dac4a2 td=7372364
INFO [05-29|16:18:59] Loaded most recent local fast block number=29 hash=8ff3ff…dac4a2 td=7372364
WARN [05-29|16:18:59] Blockchain not empty, fast sync disabled
INFO [05-29|16:18:59] Starting P2P networking
INFO [05-29|16:19:01] Mapped network port proto=udp extport=61910 intport=61910 interface="UPNP IGDv1-IP1"
INFO [05-29|16:19:02] RLPx listener up self=enode://ad307e052d0e04af519b8999fa870800df8a7a0cc2a91e6aea30e879b75c344dfa12c773a63a71677c2a3ea1254cf982815817f7ff58bd79e5837ea44d791a2d@192.168.1.2:61910
INFO [05-29|16:19:02] Mapped network port proto=tcp extport=61910 intport=61910 interface="UPNP IGDv1-IP1"
Welcome to the Geth JavaScript console!
instance: Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1
coinbase: 0x5fba50fce50baf0b8a7314200ba46336958ac97e
at block: 29 (Mon, 29 May 2017 13:13:46 CST)
datadir: /home/zl/Documents/private-geth/data/00
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
上面的命令以命令行的(console)的方式启动了节点, 所以我们可以通过继续输入下面的命令获取节点实例的enode url:
>admin.nodeInfo.enode
"enode://ad307e052d0e04af519b8999fa870800df8a7a0cc2a91e6aea30e879b75c344dfa12c773a63a71677c2a3ea1254cf982815817f7ff58bd79e5837ea44d791a2d@192.168.1.2:61910"
>
###########################获取本机IP地址###########################
$ ifconfig|grep netmask|awk '{print $2}'
127.0.0.1
192.168.1.102
###########################
再打开一个终端,初始化第二个节点:
geth --datadir ./data/01 init ./genesis.json
启动第二个节点:
~/Documents/private-geth geth --datadir ./data/01 --networkid 314590 --ipcdisable --port 61911 --rpcport 8101 --bootnodes "enode://ad307e052d0e04af519b8999fa870800df8a7a0cc2a91e6aea30e879b75c344dfa12c773a63a71677c2a3ea1254cf982815817f7ff58bd79e5837ea44d791a2d@192.168.1.2:61910" console
INFO [05-29|18:42:15] Starting peer-to-peer node instance=Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1
INFO [05-29|18:42:15] Allocated cache and file handles database=/home/zl/Documents/private-geth/data/01/geth/chaindata cache=128 handles=1024
INFO [05-29|18:42:15] Initialised chain configuration config="{ChainID: 15 Homestead: 0 DAO: DAOSupport: false EIP150: EIP155: 0 EIP158: 0 Engine: unknown}"
INFO [05-29|18:42:15] Disk storage enabled for ethash caches dir=/home/zl/Documents/private-geth/data/01/geth/ethash count=3
INFO [05-29|18:42:15] Disk storage enabled for ethash DAGs dir=/home/zl/.ethash count=2
INFO [05-29|18:42:15] Initialising Ethereum protocol versions="[63 62]" network=314590
INFO [05-29|18:42:15] Loaded most recent local header number=36 hash=e1541c…418ce3 td=8938686
INFO [05-29|18:42:15] Loaded most recent local full block number=36 hash=e1541c…418ce3 td=8938686
INFO [05-29|18:42:15] Loaded most recent local fast block number=36 hash=e1541c…418ce3 td=8938686
WARN [05-29|18:42:15] Blockchain not empty, fast sync disabled
INFO [05-29|18:42:15] Starting P2P networking
INFO [05-29|18:42:17] Mapped network port proto=udp extport=61911 intport=61911 interface="UPNP IGDv1-IP1"
INFO [05-29|18:42:17] RLPx listener up self=enode://2261c433ed5d12924f727b61bf4084f22f4199b430115827c8eae3bb210c0dd5b3dd7df8dc13d8ca80c80f4a36e25c7bc7737737001d0b09324ee43ca6b9d7f8@192.168.1.2:61911
INFO [05-29|18:42:17] Mapped network port proto=tcp extport=61911 intport=61911 interface="UPNP IGDv1-IP1"
Welcome to the Geth JavaScript console!
instance: Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1
coinbase: 0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf
at block: 36 (Mon, 29 May 2017 18:30:22 CST)
datadir: /home/zl/Documents/private-geth/data/01
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
上面的命令中,--bootndoes 是设置当前节点启动后,直接通过设置--bootndoes 的值来链接第一个节点, --bootnoedes 的值可以通过在第一个节的命令行中,输入:admin.nodeInfo.enode命令打印出来.
也可以不设置 --bootnodes, 直接启动,启动后进入命令行, 通过命令admin.addPeer(enodeUrlOfFirst Instance)把它作为一个peer添加进来.
为了确认链接成功,第二个节点输入:
> admin.nodeInfo
{
enode: "enode://2261c433ed5d12924f727b61bf4084f22f4199b430115827c8eae3bb210c0dd5b3dd7df8dc13d8ca80c80f4a36e25c7bc7737737001d0b09324ee43ca6b9d7f8@192.168.1.2:61911",
id: "2261c433ed5d12924f727b61bf4084f22f4199b430115827c8eae3bb210c0dd5b3dd7df8dc13d8ca80c80f4a36e25c7bc7737737001d0b09324ee43ca6b9d7f8",
ip: "192.168.1.2",
listenAddr: "[::]:61911",
name: "Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1",
ports: {
discovery: 61911,
listener: 61911
},
protocols: {
eth: {
difficulty: 8938686,
genesis: "0xa0e580c6769ac3dd80894b2a256164a76b796839d2eb7f799ef6b9850ea5e82e",
head: "0xe1541cc54dbcade54fb61053ffa71391c44bb6655cf9619635263960bc418ce3",
network: 314590
}
}
}
>
第一个节点输入:
> net.peerCount
1
> admin.peers
[{
caps: ["eth/62", "eth/63"],
id: "2261c433ed5d12924f727b61bf4084f22f4199b430115827c8eae3bb210c0dd5b3dd7df8dc13d8ca80c80f4a36e25c7bc7737737001d0b09324ee43ca6b9d7f8",
name: "Geth/v1.6.1-stable-021c3c28/linux-amd64/go1.8.1",
network: {
localAddress: "192.168.0.103:61910",
remoteAddress: "192.168.1.2:41912"
},
protocols: {
eth: {
difficulty: 8938686,
head: "0xe1541cc54dbcade54fb61053ffa71391c44bb6655cf9619635263960bc418ce3",
version: 63
}
}
}]
>
从得到的结果可以看出,第一个节点有1个peer链接, 链接的node id为:
"2261c433ed5d12924f727b61bf4084f22f4199b430115827c8eae3bb210c0dd5b3dd7df8dc13d8ca80c80f4a36e25c7bc7737737001d0b09324ee43ca6b9d7f8"
这个id,正好就是第二个节点的id.
按照这样的方式继续扩展,可以非常容易就可以建立本地节点集群.这些工作都可以写成脚本代码来完成, 里面还可以包含创建账户,挖矿等..
请参考:https://github.com/ethersphere/eth-utils下的gethcluster.sh脚本,以及README中的使用方法和示例.
链接成功后,使用我们在上一篇文章中挖矿的账户,向第二个节点发送 "ether"(以太币的货币单位,还有一种叫"Wei",基本上这些货币单位都是用一些牛逼的人的名字来命名的).
首先查看第二个节点的Wei数量和整个网络的区块号,还有接收货币的账号id:
> eth.getBalance(eth.accounts[0])
0000000000000000000
> eth.blockNumber
30
> eth.accounts[0]
"0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf"
>
在第一个节点命令行中,执行下面的操作:
> personal.unlockAccount(eth.accounts[0], "ko2005")
true
> eth.sendTransaction({from: "0x5fba50fce50baf0b8a7314200ba46336958ac97e", to: "0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf", value: web3.toWei(1, "ether")})
INFO [05-29|17:33:42] Submitted transaction fullhash=0x51a75422f79fa96e70a0c1481851bc9f827868c44203b68d74f9815ffb367d5f recipient=0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf
"0x51a75422f79fa96e70a0c1481851bc9f827868c44203b68d74f9815ffb367d5f"
> eth.pendingTransactions
[{
blockHash: null,
blockNumber: null,
from: "0x5fba50fce50baf0b8a7314200ba46336958ac97e",
gas: 90000,
gasPrice: 20000000000,
hash: "0x51a75422f79fa96e70a0c1481851bc9f827868c44203b68d74f9815ffb367d5f",
input: "0x",
nonce: 0,
r: "0x5632a8ade4a767dbd949ba1042cb33f98dd0722ab999ba18e1454d19d8bd1f6d",
s: "0x515dcfa3de297f0c956ad9a061a5561f47cc9ccbb0a547cda59193c77fcbe3f7",
to: "0x0a8c35653d8b229c16f0c9ce6f63cffb877cfdcf",
transactionIndex: 0,
v: "0x42",
value: 1000000000000000000
}]
eth.sendTransaction就是执行发送以太币的操作, 参数from, to分别是发送账户和接收账户, web3.toWei(1, "ether")是将1单位"ether"转换为相应的"Wei"数量.
然后执行挖矿(这里我也不理解,为什么发送货币以后,要通过挖矿才能让交易生效)
> miner.start()
INFO [05-29|18:26:47] Updated mining threads threads=0
INFO [05-29|18:26:47] Starting mining operation
null
> INFO [05-29|18:26:47] Commit new mining work number=31 txs=1 uncles=0 elapsed=1.094ms
> INFO [05-29|18:30:14] Successfully sealed new block number=31 hash=19e3d7…a6ecd5
INFO [05-29|18:30:14] 🔨 mined potential block number=31 hash=19e3d7…a6ecd5
INFO [05-29|18:30:14] Commit new mining work number=32 txs=0 uncles=0 elapsed=2.314ms
INFO [05-29|18:30:17] Successfully sealed new block number=32 hash=94748a…cdbc17
INFO [05-29|18:30:17] 🔨 mined potential block number=32 hash=94748a…cdbc17
INFO [05-29|18:30:17] Commit new mining work number=33 txs=0 uncles=0 elapsed=156.295µs
INFO [05-29|18:30:19] Successfully sealed new block number=33 hash=b8e037…cd50ff
INFO [05-29|18:30:19] 🔨 mined potential block number=33 hash=b8e037…cd50ff
INFO [05-29|18:30:19] Commit new mining work number=34 txs=0 uncles=0 elapsed=131.676µs
> mINFO [05-29|18:30:20] Successfully sealed new block number=34 hash=7ad61a…f63067
INFO [05-29|18:30:20] 🔨 mined potential block number=34 hash=7ad61a…f63067
INFO [05-29|18:30:20] Commit new mining work number=35 txs=0 uncles=0 elapsed=138.957µs
> miner.stINFO [05-29|18:30:22] Successfully sealed new block number=35 hash=eb9652…a1a9e3
INFO [05-29|18:30:22] 🔨 mined potential block number=35 hash=eb9652…a1a9e3
INFO [05-29|18:30:22] Commit new mining work number=36 txs=0 uncles=0 elapsed=334.318µs
> miner.stopINFO [05-29|18:30:22] Successfully sealed new block number=36 hash=e1541c…418ce3
INFO [05-29|18:30:22] 🔗 block reached canonical chain number=31 hash=19e3d7…a6ecd5
INFO [05-29|18:30:22] 🔨 mined potential block number=36 hash=e1541c…418ce3
INFO [05-29|18:30:22] Commit new mining work number=37 txs=0 uncles=0 elapsed=117.185µs
> miner.stop()
true
>
从上面的日志可以看到,执行挖矿之后,一共有6个区块产生.
再在第二个节点的命令行输入:
> eth.blockNumber
36
> eth.getBalance(eth.accounts[0])
1000000000000000000
可以看到第二个节点中的账户,已经得有了1个"ether", 并且可以看出,以太坊中,1"ether"=1000000000000000000"Wei.
之前输入eth.blockNumber,得到的值为30,其实只要挖出第一个区块的时候,就可以停止,发送到第二个node账户中的一个"ether",就已经生效.
总结一下:
这次以我们完成了以下内容:
1)创建区块链私有网络,并在网络中,建立自己的节点集群.
2)在接点集群中,通过一个节点的账户向网络中的另外一个节点的账户转了1个以太坊币,交易成功.
下一次,我们将开始使用truffle,写一个以太坊的"Hello World",正式进入区块链的开发.
另外说一下,
本人也是区块链新手,一边学习,一边把学习的过程记录下来向大家分享,中间走了非常多的弯路,
耗费了大量时间, 文章主要是把自己的学习经验分享出来,一个是自己可以巩固,另外可以帮助大家,避免大家和我一样走很多弯路.
如果文章中有写得不对的,或者有更好的方法,还请各位大神批评指正.