源码99-找源码搭建系统网络技术支持、就来源码99不跑路工作室(www.ym99.cc)

全部分类
全部分类

以太坊如何搭建私有连联盟链


以太坊如何搭建私有连联盟链


如何启动geth节点对大家来说已经不是什么难事,今天博主就带大家学习一下如何搭建两个节点的联盟链。

私有链的创建

在之前的文章中我们已经讲到过私有链的创建,本篇文章我们会有道私有链创建的知识,就重新温故一下。创建私有链首先需要指定创始块的配置,也就是genesis.json的配置。此文件就是一个内容格式为json的文本文件。

配置文件的内容格式基本如下:

代码语言:javascript
复制
{
 "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: 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以不需要预置有币的账号,需要的时候自己创建即可以。实例代码如下:

代码语言:javascript
复制
"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。

代码语言:javascript
复制
ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init1/ init genesis.json

本教程将初始化json文件放在geth同级目录下,如果放在其他目录下,指定具体的路径即可。同时创建了一个data-init1目录专门存储节点数据,执行完成会发现在该目录下多出两个目录,一个为geth一个为keystore。其中geth里面放数据相关信息,keystore里面放加密过的私钥文件。

执行时打印日志如下:

代码语言:javascript
复制
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目录来存储第二个节点的数据。

代码语言:javascript
复制
ershixiongdeMacBook-Pro:geth zzs$ ./geth --datadir ./data-init2/ init genesis.json

启动并进入控制台

根据具体的操作系统,开两个窗口来启动两个节点。这里有一点需要注意的是,虽然是两个节点,但他们的启动程序都是geth,只不过datadir目录不同而已。 在第一个窗口执行以下命令启动一个节点,注意启动之后不要关闭窗口。

代码语言:javascript
复制
./geth --datadir ./data-init1/ --networkid 88 --nodiscover console

参数简介:

networkid 指定网路ID,确保不适用1-4。

nodiscover 此参数确保geth不去寻找peers,主要是为了严格控制联盟链连入的节点。

这里我们需要注意的是在启动第一个节点时并没有指定port参数,因此此处采用了默认的port,也就是30303。 以下为执行时打印的日志,并进入控制台。通过日志我们也可以发现端口为30303。

代码语言:javascript
复制
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,来启动第二个节点。

代码语言:javascript
复制
./geth --datadir ./data-init2/ --port 30306 --networkid 88 --nodiscover console

执行上面命令,完成节点2的启动,并进入控制台。

添加coinbase账户

上面的日志我们也看到警告信息,提示没有账户存在,那么现在我们就在第一个节点上创建一个账户,具体在控制台操作命令如下:

代码语言:javascript
复制
> personal.listAccounts[]> personal.newAccount("123456")"0x60c8abe58c9dbc52a4ee9f8510f1799c432c0f3e">

上面的命令先是查看了节点下的地址,结果为空,然后创建了一个秘密为123456的账号。

同样的,在另外一个窗口我们执行同样的命令:

代码语言:javascript
复制
> personal.listAccounts[]> personal.newAccount("123456")"0x02b7344004c45465796f779b7b95d7912c2ef572">

这样,两个节点就拥有了两个地址。同时,在它们的keystore目录下对应生成了加密的私钥文件。

我们也可以再次执行list命令查看添加账户之后的情况。同时可以执行以下命令查看coinbase账号:

代码语言:javascript
复制
> eth.coinbase"0x02b7344004c45465796f779b7b95d7912c2ef572">

由于只有一个地址,因此该地址就作为coinbase地址。如果想查看更多的信息可以执行以下命令:

代码语言:javascript
复制
> 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的情况。

代码语言:javascript
复制
> admin.peers[]

发现节点并没有链接上任何其他节点,这也是我们的nodiscover参数发挥了效果。

下面就通过分享enode地址的方式来让两个节点建立链接。

代码语言:javascript
复制
> admin.nodeInfo.enode"enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0">

通过上面命令,我们获得了节点2的encode信息。这是geth用来连接到不同节点的enode信息,在这些不同的节点它们能够分享交易和成功挖掘信息。

其实这个信息如果留心的话,在启动节点的打印日志中已经打印出每个节点的encode信息。比如:

代码语言:javascript
复制
INFO [12-28|19:23:16] RLPx listener up                         self="enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30303?discport=0"

现在,我们要告知一个节点,另外一个节点的encode信息。首先复制节点2的日志中self等号后面的信息,在节点1的控制台执行以下命令:

代码语言:javascript
复制
> admin.addPeer("enode://aa621c010c685665ef217044dac4d57f4d1d682c682a5b3f92ca23b40982383240a05b680060ce8b0ce020a96c49c9c2c3628c4ea3281845211bd4cf4f03b35c@[::]:30306?discport=0")true

返回true,说明执行成功。


侧栏导航
展开 收缩