1 安装前的准备
1.1 配置Linux系统
本文配置的为windows下的VMware软件下搭建的Linux下的cent0S-7系统,推荐系统有CentOS 7和Ubuntu 16.04有条件的可以用云服务器上的Linux系统,好处是可以搭建广域网联盟链。
本文默认你已经对以太坊和docker技术有一定的掌握和了解,并部署好相应的环境。如果你还未准备好,请参考芯链公众号前期发布的环境搭建和部署文章。
1.2 安装Docker
请使用管理员权限进行安装,
# su root
安装Docker(请参考芯链公众号发布的安装指导文章):
CentOS: yum -y install docker-io
Ubuntu: apt-get install docker-engine
安装完毕如图:
然后启动Docker服务:
#service docker start
校验docker是否安装成功:
#docker run hello-world
这个命令会下载一个测试镜像,并且运行在一个容器中。当容器运行时,他会打印一些信息,并且退出。下图表示Docker已经安装完成。
2 安装bootnode
2.1 下载bootnode镜像
运行命令如下命令:
#docker pull docker.io/hawyasunaga/ethereum-bootnode
查看镜像:docker images
2.2 Docker创建bootnode容器节点
生成引导节点:
1
|
|
运行引导节点:
1
|
|
注意:这两个命令参数中,-v /path/docker/bootnode:/root/bootnode为映射路径,在docker的这个bootnode容器中,出现容器内/root/bootnode路径都映射为外部路径/path/docker/bootnode。下方以太坊容器搭建节点命令同理。
2.3 查看bootnode日志得到节点
1
|
|
得到节点如下:
将[::]替换为本机IP地址
好了,用于连接的根节点运行完毕。
3 安装以太坊节点
可以找台Linux进行节点联盟链的搭建了,这里继续以centos7继续演示了。
3.1 创建以太坊的创世文件
新建创世文件genesis.json,内容如下:
1
2
3
4
5
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
3.2 初始化创世文件
首先新建一个准备放置以太坊目录的文件,将genesis.json文件放入该地址,本文为/home/admin下:
运行如下命令
1
|
|
请记住—networkid 8765639736937780,这是当前搭建联盟链的ID。
查看日志文件:docker logs -f gethDev1
初始化成功。
3.3 Docker创建以太坊容器节点
运行如下命令
1
|
|
1
|
|
//enode为上面运行bootnode得到的节点,并将预备的私钥文件放入keystore中,并且—networkid 8765639736937780为联盟链的标识ID。
查看控制台日志:docker logs -f gethDev1
Ok,节点搭建成功。
3.4 验证联盟链的连接
在上一步搭建好节点后,等待一段时间,让节点自动连接根节点bootnode。
进入以太坊容器中:
1
|
|
输入命令:admin
查看peer是否连接:
OK,连接完成,联盟链搭建完成。
连接完成后,开始同步区块:
注意:这里连接的是之前已经加入bootnode根节点的其他节点,与根节点的连接并不会显示在peers中。如果是第一个连接bootnode的节点,连接了bootnode的时候输入admin,peers是空的,需要继续搭建一个节点来测试他们互相连接。
感谢HPB团队整理。
HPB51:RLPx加密握手协议研究
加密握手协议全局位置
Server服务器作为上层使用的接口,直接调用Start启动。Start完成启动监听端口、连接以及建立通信的任务。在运行中,Star通过创建多个goroutine,并将goroutine的结果通过channel形式汇聚给run进行集中处理。当用户间建立节点以后,通过Msg格式进行通信。其中
newTransport 是和节点建立连接(tcp或者udp)后进行协商密钥、协议握手的地方,通过rlpx协议来进行握手。除了建立rlpx握手,在运行通信的整个过程中,需要进行如下判断:
加密握手协议流程
加密握手细节描述
关键步骤补充:
生成Authpacket(Dialing方执行) | 接收AuthPacket(Listening方执行) | |
---|---|---|
1.创建enchandshake结构体,该结构体包含 Initiator(bool) RemoteID(discover.NodeID) remotePub(ecies.pk) initNonce, respNonce(byte) randomPrivateKey(ecies.sk) remoteRandomPub(ecies.pk) | 1.创建authMsgV4结构体 gotPlain(bool) initiatorPubkey(byte) Signature(byte) Nonce(byte) Version(unit) | | |
2.执行makeAuthMsg方法: 1)将romteID恢复为公钥remotePub 其中ECDSA公钥作为ECIES公钥 2) 生成随机intiator nonce 3)生成随机ECDH密钥randomPrivKey 4)对信息签名得到signature(见附录) 处理后输出AuthMsgV4格式的数据 发送的数据包括: Version(=4) Nonce(随机生成)InitiatorPubKey(本地sk参与) Signature | 2.读取authMsg操作readHandshakeMsg ◑ 若为pre-EIP8: 1) 将ECDSA私钥作为ECIES私钥 2) 通过私钥解密ECIES密文为明文 3) 对明文进行解码 ◑ 若为EIP8格式: 1) 增加前缀并连接 2) 解密为明文 3) 对明文进行解码 解码后的[]byte赋值给s作为authPacket | | |
3.生成经过封装的AuthPacketAuthPacket=sealEIP8(AuthMsg) 封装过程如下: 1) rlp编码 2) 填充随机数据使总长至少到100byte 3) 加前缀 4) 进行ECIES加密(remotePub) | | |
生成authRespPacket(Listening方执行) | 接收authRespPacket(Dialing方执行) | |
---|---|---|
1.创建enchandshake结构体(同前) | 1.创建authRespV4结构体 RandomPubkey(byte) Nonce(byte) Version(unit) | | |
2.处理authMsg操作, 通过handleAuthMsg方法 1)将远端的身份传入,其中包括 ◑ nonce值传入给initNonce ◑ 将initiatorPK恢复为remotePub 其中ECDSA公钥作为ECIES公钥 2)生成随机ECDH私钥randomPrivKey 3)检查签名signature,并 恢复出remoteRandomPub | 2.读取authRespMsg操作, 使用readHandshakeMsg方法 ◑ 若为pre-EIP8: 1) 将ECDSA私钥作为ECIES私钥 2) 通过私钥解密ECIES密文为明文 3) 对明文进行解码 ◑ 若为EIP8格式: 1) 增加前缀并连接 2) 解密为明文 3) 对明文进行解码 解码后byte赋值给s作为authRespPacket | | |
3. 执行makeAuthMsg方法: 1)生成随机respNonce 2)创建authRespV4结构体 该结构体包括: RandomPubKey Nonce Version 3)对结构体进行copy赋值 处理后输出AuthRespV4格式的数据 发送的数据包括:Version(=4) Nonce(随机生成)RespPubKey(本地sk参与) | 3.创建enchandshake结构体(同前) | | |
4.生成经过封装的AuthRespPacket ◑ 若为明文格式: 需通过ECIES进行加密(remotePub)authRespPacket=sealPlain(AuthMsg) ◑ 若为非明文格式: 进行EIP8封装(同前)authRespPacket=sealEIP8(AuthMsg) | 4.处理authResp操作handleAuthResp 1)读取nonce 2)将RandomPubKey恢复为remoteRandomPub 其中将输入的PK去编组化,并 将ECDSA公钥作为ECIES公钥 | |
感谢HPB团队整理。
HPB50:主流共识算法分析
区块链核心框架
区块链是一个不断增长的分布式账本[2],账本用“区块”的形式衔接在一起,区块中包含交易, 时间戳,随机数等元数据,每个区块中含有一个指针指向上一个交易链接,区块链的设计是安 全的,因为其具有良好的拜占庭容错能力。区块链可以概括为一个分布式的高频交易系统,如 下图 1 所示,区块链的核心技术可以总结为四部分:分布式的数据库,密码学相关理论,共识机制和 P2P 网络。
中分布式数据库负责数据的写入与读取,密码学中非对称密钥和 HASH 等算法来标识交易者的身份和保证系统的完整性;对等网络是系统运行的基础;共识算法用来保证交易信息在整个账本不同节点中写入的一致性,常用的共识算法有 POW, POS, DPOS 等。
共识算法与 CAP 理论
共识算法是为了解决在对等网络中(P2P),相互独立的节点如何达成一项决议问题的过程。简而言之,共识算法是在解决分布式系统中如何保持一致性的问题。关于此部分的讨论较为成熟和最为广泛接受的理论是 CAP 理论。CAP 由 Eric Brewer )在 2000 年 PODC 会议上提出[4],并提出分布式系统不能同时完全满足 CAP 三个要求的假设,其中包括如下三个方面:
Consistency: 一致性 从不同节点读取的数据一致。一致性是指数据的原子性,在经典的数据库中通过事务来保障,事务完成时,无论成功或回滚,数据都会处于一致的状态,在分布式环境下,一致性是指多个节点数据是否一致。
Availability: 可用性是指服务及时非错误地响应,服务一直保持可用的状态,当用户发出一个请求,服务能在一定的时间内返回结果,响应可终止、不会一直等待。
Partition tolerance:分区容错性即可靠性。可靠性的量化指标是周期内系统平均无故障运行时间. 即使有些消息延迟或者无法到达,并不影响系统的整体运行。简而言之,在网络分区的情况下,被分隔的节点仍能正常对外服务。
和所有分布式系统一样,区块链共识算法设计也是在权衡上面的三个因素,假如区块链中节点能立即确认交易数据,好处是不依赖其他节点立即可用,满足了 CAP 理论中的 AP,可风险是失去了强一致性,其他节点可能丢弃这个区块,因为区块所在的区块链分叉在竞争性的选举中失败了[5]。 为了获得 CP,客户端应该等待区块链大多数节点接受了这笔交易在真正接受它, 说明这笔交易所在分叉已经选举胜利,获得大部分共识,获得了强一致性,但是风险是可能unavailable ,丧失 CAP 的 A,因为网络分区通信等问题可能阻止这种共识。
研究定位
区块链系统是一个将交易数据正确地固化在分布式节点上的系统。共识算法为了解决如何更安全有效的将交易数据写入到区块链上,本质上讲,共识算法旨在解决以下问题:
- 哪个服务节点有权利生成下一个用新区块?
- 上一个区块与下一个区块之间应如何衔接
- 下一个区块什么时间产生?
- 区块中应该包含了哪些内容?
- 区块的大小是多少,一个区块中包含多少交易数据?
- 确认机制如果解决区块链分叉的问题?
本文档从多个角度分析不同共识算法关于以上问题的解决方案,旨在为将来实际算法设计提供相关理论参考,分析方法为以下两点:
- 纵向分析:我们以一个交易的被确认的完整过程,勾画出整个区块链系统的工作过程,纵向的分析共识算法在整个区块链系统中所扮演的角色。
- 横向对比:我们陈列出当前加密货币中常用的共识算法,如 POW,POS,DPOS,PBFT 等,然后从算法的一致性,容错性,网络组织情况等方面进行对比分析。
纵向定位分析
研究共识机制旨在设计更安全,高效的区块产生方案。为了让读者更加清晰的认识共识算法在整个区块链中所扮演的角色,在本章中我们勾画出区块产生的完整周期,并用以比特币的例子详细的讲解区块产生的过程。
图 2. 交易数据在区块链中被确认的过程
图 2 中展示了交易数据在区块链中一个完整的流转过程,在起始阶段,交易信息被客户端组装, 其中交易信息包含了交易的输入金额,输入账户信息和输出账户信息等,客户端可以被认为是 全节点钱包,轻钱包和各大交易平台。在一个完整的交易被生成后被称为“原始交易(Raw
Transaction)”。 原始交易并不能被矿机接收,因为缺乏相应转账人的签名。在转账人签名完成后允许将其广播到区块链系统中,矿机采集相关交易后,经过共识算法将交易数据打包并确认到对等网络中的其他节点上。下面我们以比特的例子详细阐述以上过程。
交易数据的组装
假设用户 A 给用户 B 进行转账,用户 A 的的公钥为 Pk_a,私钥为 Pr_b, 用户 B 的的公钥为Pk_b,私钥为 Pr_b. 我们按照表 1 给出的协议一步一步的给出最终可广播的内容。备注: 以下数据均为十六进制表示,我们采用比特币中最常用的 Pay-to-PubkeyHash 进行分解。经过客户端的数据组合,我们展示一个完整的交易协议如下,其中输入数据 inputs 数据可以从UTXO(Unspent Transaction Output,未开销的比特币交易输出)中获取。
表 1. 比特币原始区块链交易协议
Version (版本) | 01000000 | ||
---|---|---|---|
Input count (输入长度) | 01 | | ||
inputs | previous output hash (上一个脚本的 hash) | be66e10da854e7aea9338c1f91cd4897 68d1d6d7189f586d7a3613f2a24d5396 | | |
inputs | previous output index (上一个交易的索引) | 00000000 | | |
inputs | scriptSig length (表示脚本的长度) | 19 | | |
inputs | scriptSig(脚本签名,实际此部分为脚本的前半部分) | 76a914010966776006953d5567439e5e 39f86a0d273bee88ac | | |
inputs | Sequence (序列) | ffffffff | | |
outputs count (输出长度) | 01 | | ||
outputs | Value (需要转出的比特币的值,上面的输入的值减去) | 605af40500000000 | | |
outputs | script length (表示脚本的长度) | 19 | | |
outputs | script(脚本签名,实际此部分为脚本的前后半部分) | 76a914097072524438d003d23a2f23ed b65aae1bb3e46988ac | | |
lock time (锁定时间) | 00000000 | |
交易数据的签名
交易数据的完成组装后并不能立即被矿机所接受,因为交易的输出方并没有对其进行有效的签名,我们用 sha256 整体对上面的数据的 hash 进行签名,我们假设发送者的公钥是 Pk_a, 签名后的结果为 Sig_a. 为更好的理解签名后在区块链中执行的过程,我们将上面 inputs 中的scriptSig 进行分解76a914010966776006953d5567439e5e39f86a0d273bee88ac 分解后的内容如下表格,表 2. 未签名的 ScriptSig 数据格式分解,备注数字与操作符的对应关系可以通过https://en.bitcoin.it/wiki/Script 查询到,ScriptSig 格式如下:
OP_DUP | 76 | |
---|---|---|
OP_HASH160 | a9 | | |
length | 14 | | |
pubKeyHash | 010966776006953d5567439e5e39f86a0d273bee | | |
OP_EQUALVERIFY | 88 | | |
OP_CHECKSIG | ac | |
经过签名之后我们将签名后的数据衔接在 ScriptSig 上面,因此最终的 ScriptSig 变成如下格式。表 3. 签名后的 ScriptSig 数据格式分解。
Sig_a | Sig_a. | |
---|---|---|
Pk_a | Pk_a | | |