众所周知的比特币以及其它基于PoW的加密货币,最大的缺陷之一就是会遭遇51%攻击(虽然难度较大),虽然区块链是不可变的,并且记录无法更改,但是攻击者可能会实施其它攻击,如拒绝服务攻击,从而导致应用瘫痪。
另外,PoW的计算消耗了大量的电力资源,以太坊一直致力研究PoW的替代方案,例如PoS,这解决了电力问题,但它更多地针对的是公链。
对于私链,工作证明根本没有意义。
以太坊很快过渡到了PoS算法,此算法解决了公链工作证是且的问题,想要成为矿工的人会将一些以太币存入智能合约中,如果矿工被认为是恶意的,那么这部分以太币将会被锁定。
因为没有竞争来解决难以解决的数学问题,所以不必总是发行新币,矿工将从交易中获得回报。
这种算法确实解决了过度用电的问题,并确实在一定程度上可以防止51%攻击。
对于私链,PoS可能比Pow更 好,但它仍然没有为我们提供所需的控制和安全级别,因为如果他们提交了足够的以太币做为押金,那么公链上的任何人都可以成为矿工。
PoA是区块链世界中的一个新概念,在这个概念中,您拥有许多预先批准的授权节点(称为审查者,即通常意义上的矿工)。
您要添加任何新节点,必须由当前已有的审查者投票,这使您可以完全控制哪一些节点可以做为审查者。
以太坊的PoA协议称为Clique,它适用于私链,但不适用于公链。
因此本次搭建的智子链是基于POA共识机制。
推荐:ubuntu16.04 4核8G 500G硬盘
最低:ubuntu16.04 2核4G 500G硬盘
git clone https://github.com/ethereum/go-ethereum
cd go-ethereum && make geth
执行完成后在build/bin的目录下会生成可执行文件geth,创建四个
文件夹n1,n2,s1,s2,n 用作普通节点,用于后期节点间发起交易,s作为授权节点,s1 设置为创世块指定的授权节点;s2作为后期加入信任名单授权节点。
为每个节点建立一个智子链账户。指令geth --datadir ./data account new是指使用当前目录下的data目录当作geth存放资料的地方,并且创一个新的Account。在刚刚创建的n1, n2, s1, s2 目录下分别运行相同指令来创建一个账户,如下图所示:
n2,s1,s2以同样的方法创建账户,注意:一定要记住自己的密码和各个账号的Public address of the key,后面会用到。
Clique 是将授权节点的相关信息放在Block Header中,必须设置创世块才可以让授权机制生效。
在 1.6 之后的以太坊中提供了初始化创世块的工具:puppeth, 请选择含有 Geth & Tools 的版本下载,下载地址:https://gethstore.blob.core.windows.net/builds/geth-alltools-linux-amd64-1.9.8-d62e9b28.tar.gz。
puppeth 是个互动式的程序,直接启动照着指示输入相关信息。设置 Private chain 名称(名称里不允许有-,空格),假定为 poatest,如下:
设置生产出一个Block的时间,在这里设5 秒,可自行选择,如下图:
给账户设置一些ether。我选了node1和signer1的address,可自行选择,如下图:
Network Id,直接用random随机生成即可,如下图:
ctrl+c退出,可以看到当前目录有一个poatest.json文件,如下图:
创世块poatets.json文件里参数的意义,如下:
参数 | 解释 |
---|---|
mixhash | 与 nonce 配合用于挖矿,由上一个区块的一部分生成的 hash。注意他和 nonce 的设置需要满足以太坊的 Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的 条件。 |
nonce | nonce 就是一个 64 位随机数,用于挖矿,注意他和 mixhash 的设置需要满足以太 坊的 Yellow paper, 4.3.4. Block Header Validity, (44)章节所描述的条件。 |
difficulty | 设置当前区块的难度,如果难度过大,cpu 挖矿就很难,这里设置较小难度。 |
alloc | 用来预置账号以及账号的以太币数量,因为私有链挖矿比较容易,所以我们不需要 预置有币的账号,需要的时候自己创建即可以。 |
coinbase | 矿工的账号,随便填。 |
timestamp | 设置创世块的时间戳。 |
parentHash | 上一个区块的 hash 值,因为是创世块,所以这个值是 0。 |
extraData | 附加信息,在 POA 挖矿中。 |
gasLimit | 该值设置对 GAS 的消耗总量限制,用来限制区块能包含的交易信息总和,因为我 们是私有链,所以填最大。 |
使用 geth init 指令,分别初始化 4 个节点的 datadir
geth --datadir n1/data/ init geth-alltools/poatest.json
geth --datadir n2/data/ init geth-alltools/poatest.json
geth --datadir s1/data/ init geth-alltools/poatest.json
geth --datadir s2/data/ init geth-alltools/poatest.json
geth 用来存储区块链的数据信息,keystore 用来存储账户信息。
启动各个节点:
以控制台形式启动:geth --datadir n1/data --networkid 66300 --port 3000 console
运行在后台:nohup geth --datadir n1/data --networkid 66300 --port 3000 &
连接控制台:geth attach --datadir n1/data
注意:s1为挖矿节点启动时需要解锁,–password指定密码文件 ,–unlock解锁账户
datadir先前的步骤已经在每个节点各自的目录下都建立了data目录,networkid geths之间一定都要用同一个值才可以互相通信,比如实验中的66300. Portgeths 之间通信时,监听的一个port,由于四个节点都在本机,所以这里必须指定不同的值,使用 n1 对应 3000, n2 对应 3002, s1 对应 3003, s2 对应 3004.
geth参数含义如下:
参数 | 解释 |
---|---|
identity | 区块链的标示,随便填写,用于标示目前网络的名字 |
init | 指定创世块文件的位置,并创建初始块 |
datadir | 设置当前区块链网络数据存放的位置 |
port | 网络监听端口 |
rpc | 启动 rpc 通信,可以进行智能合约的部署和调试 |
rpcapi | 设置允许连接的 rpc 的客户端,一般为 db,eth,net,web3 |
networkid | 设置当前区块链的网络 ID,用于区分不同的网络,是一个数字 |
console | 启动命令行模式,可以在 Geth 中执行命令 |
启动节点时,信息中的enode需要记录,后面建立节点间的通信需要用到。
目前各个节点虽然已经启动,但是各个节点之间仍然处于孤立状态。各节点启动后无法相互通信的,所以geth要连上对方的节点就必须先设置好enode://@:,复制刚刚启动node1时出现的enode信息,将[::]替换为127.0.0.1,这样就可以让其他节点加入。如上面提示的的红色提示所见, n1 的 enode 为:enode://498d3960afb904231c54044b0ed5c6c19a3241460ba06a46170dd5a22f00009735b6515008c6a87c164e41d24446801a523d83050d3bc4da16150bbc91ebb0fa@127.0.0.1:3000
在n2,s1,s2的geth console界面下分别运行如下指令建立节点间的通信:admin.addPeer(“enode://498d3960afb904231c54044b0ed5c6c19a3241460ba06a46170dd5a22f00009735b6515008c6a87c164e41d24446801a523d83050d3bc4da16150bbc91ebb0fa@127.0.0.1:3000”)
完成后,在 node1 的 geth console 输入 admin.peers 应该要看到三个节点资讯,如下:(每个id 对应其他节点的 encode 字段信息)
按照实验的设计,在本实验中 s1 为挖矿节点,我们下面开始进行模拟挖矿,在 s1 的console 界面,键入 miner.start(),geth 就会开始挖矿了,在 s1 的 输出日志nohup.out 会出现正在mining 的信息,如下图:
由上图可看出挖矿节点每5秒出一个块。
按照我们的预设,在 n1 和 s1 上是已经初始化了余额的。查询如下图:
默认账户是Locked状态,需要先解锁为unlock状态,才可以进行账户间的转账,解锁过程如下图:
s2 是一开始未设定在创世块中信任列表的节点,如果这时候让它启动miner,会遇到一个未授权的错误,如下:
回到已经在授权名单内的节点的console界面下,将新的节点加入,如下:
重新启动s1,s2两个节点,进入控制台执行miner.start()发现两节点均提示Signed recently, must wait for others(由于两节点没有建立通信),因此在signer1中通过admin.addPeer()添加signer2,使二者可以通信,如下:
最后在s1,s2上执行miner.start(),两节点开始交替挖矿。如下:
加入第三个信任节点:
启动节点后,首先跟其他节点建立连接admin.addPeer(enode://7267113574d0c7f9c2d0859e5f552f172d2add8e4d31c76861494b7815baea170058b01b35c97dcb638dc57f8b0395127e77f25469d75092eb5abcca497cb57c@172.31.33.187:3000)
然后在s1,s2上分别多新加入的s3进行授权:clique.propose(“0x3f9a3A33884FF903c0924EDD384A2AF1657f926B”,true)
重启s3节点,重新连接后将s3与s1,s2建立连接,在s1,s2上分别执行admin.addPeer(“enode://cd1226502cf4805b2bec5766290717db8ae941b7629aac08668014a32bc1996fd31801fb7f6ce4504593a5a505310379156b47689f33a77df9c5ac426db79e47@127.0.0.1:3004”)
最后在s3节点执行miner.start()开始挖矿,此时s1,s2,s3三个节点交替挖矿。
加入普通节点,先生成一个新账户,再初始化私有链,然后启动该节点,在该节点里与其他节点建立连接即可,截图如下:
clique命令及其意义:
list sealers clique.getSigners()
list propositions: clique.proposals
discard a proposition: clique.discard(“0x1234234234234”)
add a new sealer: clique.propose(“0x1234243214312”, true)
remove a sealer: clique.propose(“0x1234243214312”, false)
删除一个信任节点时,先remove a sealer,再discard a proposition
Tips:在终端不关闭的情况下,重新启动geth进入console界面,通过admin.peers查看链接信息,发现之前添加的节点信息都存在;但是,关闭终端后,重新打开一个新的终端,启动geth进入console界面,通过admin.peers查看链接信息,会发现是空的,需要重新运行admin.addPeer()添加,这一点一定要注意!!!
通过clique.discard(signer_address)删除信任节点。通过clique.propose(signer_address,true)添加信任节点,通过实验发现,无法立即生效,需要一半以上的信任节点的投票。一般要在当前所有的信任节点的终端中都执行clique.propose(),并且在各信任节点的终端都同时挖矿,各自挖出几个块后,新添加的信任节点就可已挖矿了。
引用:
https://blog.csdn.net/shangsongwww/article/details/89063564