以太坊如何搭建私有连联盟链
以太坊如何搭建私有连联盟链
如何启动geth节点对大家来说已经不是什么难事,今天博主就带大家学习一下如何搭建两个节点的联盟链。
私有链的创建
在之前的文章中我们已经讲到过私有链的创建,本篇文章我们会有道私有链创建的知识,就重新温故一下。创建私有链首先需要指定创始块的配置,也就是genesis.json的配置。此文件就是一个内容格式为json的文本文件。
配置文件的内容格式基本如下:
{ "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"}
配置项简介
我们对配置项的内容进行一下简单的介绍。
alloc: 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以不需要预置有币的账号,需要的时候自己创建即可以。实例代码如下:
"alloc": { "de1e758511a7c67e7db93d1c23c1060a21db4615": { "balance": "1000" }, "27dc8de9e9a1cb673543bd5fce89e83af09e228f": { "balance": "1100" }, "d64a66c28a6ae5150af5e7c34696502793b91ae7": { "balance": "900" }
nonce:一个64位随机数,用于挖矿,和mixhash的设置需要满足以太坊的Yellow paper, 4.3.4.Block Header Validity (44)章节所描述的条件。
difficulty: 设置计算区块的难度,如果数值过大,挖矿时间较长,在测试环境为节省算力和等带时间可设置较小值。
mixhash:与nonce配合用于挖矿,由上一个区块的一部分生成的hash。和nonce的设置需要满足以太坊的Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。
coinbase: 矿工账号,随便填写。
timestamp: 设置创世块的时间戳。
parentHash: 上一个区块的hash值,因为是创世块,所以这个值是0。
extraData: 附加信息,随便填,可以填你的个性信息,必须为十六进制的字符串。
gasLimit: 该值设置对GAS的消耗总量限制,用来限制区块能包含的交易信息总和,因为是私有链,所以填最大。
创世块初始化
本教程以mac操作系统为例,其他操作系统可对照执行。 执行以下命令来启动初始化创世块的命令,最简单的一组操作就是制定dir文件路径,和初始化文件目录。前面我们已经写好了genesis.json的配置文件,下面就执行一下初始化操作,涉及到操作参数为init。
ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init1/ init genesis.json
本教程将初始化json文件放在geth同级目录下,如果放在其他目录下,指定具体的路径即可。同时创建了一个data-init1目录专门存储节点数据,执行完成会发现在该目录下多出两个目录,一个为geth一个为keystore。其中geth里面放数据相关信息,keystore里面放加密过的私钥文件。
执行时打印日志如下:
WARN [12-28|19:12:03] No etherbase set and no accounts found as defaultINFO [12-28|19:12:03] Allocated cache and file handles database=/Users/zzs/develop/eth/geth/data-init1/geth/chaindata cache=16 handles=16INFO [12-28|19:12:03] Writing custom genesis blockINFO [12-28|19:12:03] Successfully wrote genesis state database=chaindata hash=942f59…a2588aINFO [12-28|19:12:03] Allocated cache and file handles database=/Users/zzs/develop/eth/geth/data-init1/geth/lightchaindata cache=16 handles=16INFO [12-28|19:12:03] Writing custom genesis blockINFO [12-28|19:12:03] Successfully wrote genesis state database=lightchaindata hash=942f59…a2588a
经过以上命令,我们已经完成了私有连的初始化工作。因为我们要建立联盟链,因此需要再创建执行一遍同样的命令,json文件必须相同,datadir目录必须不同。博主使用data-init2目录来存储第二个节点的数据。
ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init2/ init genesis.json
启动并进入控制台
根据具体的操作系统,开两个窗口来启动两个节点。这里有一点需要注意的是,虽然是两个节点,但他们的启动程序都是geth,只不过datadir目录不同而已。 在第一个窗口执行以下命令启动一个节点,注意启动之后不要关闭窗口。
./geth --datadir ./data-init1/ --networkid 88 --nodiscover console
参数简介:
networkid 指定网路ID,确保不适用1-4。
nodiscover 此参数确保geth不去寻找peers,主要是为了严格控制联盟链连入的节点。
这里我们需要注意的是在启动第一个节点时并没有指定port参数,因此此处采用了默认的port,也就是30303。 以下为执行时打印的日志,并进入控制台。通过日志我们也可以发现端口为30303。
WARN [12-28|19:23:16] No etherbase set and no accounts found as defaultINFO [12-28|19:23:16] Starting peer-to-peer node instance=Geth/v1.7.3-stable-4bb3c89d/darwin-amd64/go1.9.2INFO [12-28|19:23:16] Allocated cache and file handles database=/Users/zzs/develop/eth/geth/data-init2/geth/chaindata cache=128 handles=1024WARN [12-28|19:23:16] Upgrading database to use lookup entriesINFO [12-28|19:23:16] Database deduplication successful deduped=0INFO [12-28|19:23:16] Initialised chain configuration config="{ChainID: 72 Homestead: 0 DAO: <nil> DAOSupport: false EIP150: <nil> EIP155: 0 EIP158: 0 Byzantium: <nil> Engine: unknown}"INFO [12-28|19:23:16] Disk storage enabled for ethash caches dir=/Users/zzs/develop/eth/geth/data-init2/geth/ethash count=3INFO [12-28|19:23:16] Disk storage enabled for ethash DAGs dir=/Users/zzs/.ethash count=2INFO [12-28|19:23:16] Initialising Ethereum protocol versions="[63 62]" network=88INFO [12-28|19:23:16] Loaded most recent local header number=0 hash=942f59…a2588a td=16384INFO [12-28|19:23:16] Loaded most recent local full block number=0 hash=942f59…a2588a td=16384INFO [12-28|19:23:16] Loaded most recent local fast block number=0 hash=942f59…a2588a td=16384INFO [12-28|19:23:16] Regenerated local transaction journal transactions=0 accounts=0INFO [12-28|19:23:16] Starting P2P networkingINFO [12-28|19:23:16] RLPx listener up self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30303?discport=0"INFO [12-28|19:23:16] IPC endpoint opened: /Users/zzs/develop/eth/geth/data-init2/geth.ipc Welcome to the Geth JavaScript console!instance: Geth/v1.7.3-stable-4bb3c89d/darwin-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> INFO [12-28|19:23:18] Mapped network port proto=tcp extport=30303 intport=30303 interface="UPNP IGDv1-IP1"
下面在另外一个窗口,换一个端口,比如30306,再换一下datadir,来启动第二个节点。
./geth --datadir ./data-init2/ --port 30306 --networkid 88 --nodiscover console
执行上面命令,完成节点2的启动,并进入控制台。
添加coinbase账户
上面的日志我们也看到警告信息,提示没有账户存在,那么现在我们就在第一个节点上创建一个账户,具体在控制台操作命令如下:
> personal.listAccounts[]> personal.newAccount("123456")"0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e">
上面的命令先是查看了节点下的地址,结果为空,然后创建了一个秘密为123456的账号。
同样的,在另外一个窗口我们执行同样的命令:
> personal.listAccounts[]> personal.newAccount("123456")"0x02b7344004c45465796f779b7b95d7912c2ef572">
这样,两个节点就拥有了两个地址。同时,在它们的keystore目录下对应生成了加密的私钥文件。
我们也可以再次执行list命令查看添加账户之后的情况。同时可以执行以下命令查看coinbase账号:
> eth.coinbase"0x02b7344004c45465796f779b7b95d7912c2ef572">
由于只有一个地址,因此该地址就作为coinbase地址。如果想查看更多的信息可以执行以下命令:
> personal.listWallets[{ accounts: [{ address: "0x02b7344004c45465796f779b7b95d7912c2ef572", url: "keystore:///Users/zzs/develop/eth/geth/data-init2/keystore/UTC--2017-12-28T11-36-18.185974427Z--02b7344004c45465796f779b7b95d7912c2ef572" }], status: "Locked", url: "keystore:///Users/zzs/develop/eth/geth/data-init2/keystore/UTC--2017-12-28T11-36-18.185974427Z--02b7344004c45465796f779b7b95d7912c2ef572"}]
这里不仅打印了账户信息,还打印出了私钥存储的位置和账户状态等信息。
联盟链互通
上面分别是在两个节点上进行的操作,下面我们需要把两个节点之间建立起链接。首先,我们执行以下命令查看以下节点的peers的情况。
> admin.peers[]
发现节点并没有链接上任何其他节点,这也是我们的nodiscover参数发挥了效果。
下面就通过分享enode地址的方式来让两个节点建立链接。
> admin.nodeInfo.enode"enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0">
通过上面命令,我们获得了节点2的encode信息。这是geth用来连接到不同节点的enode信息,在这些不同的节点它们能够分享交易和成功挖掘信息。
其实这个信息如果留心的话,在启动节点的打印日志中已经打印出每个节点的encode信息。比如:
INFO [12-28|19:23:16] RLPx listener up self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30303?discport=0"
现在,我们要告知一个节点,另外一个节点的encode信息。首先复制节点2的日志中self等号后面的信息,在节点1的控制台执行以下命令:
> admin.addPeer("enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0")true
返回true,说明执行成功。