Hyperledger fabric v1.0与IOTA原理分析

Hyperledger fabric v1.0与IOTA原理分析

Hyperledger fabirc是超级账本在区块链上的应用,我将从运行性能角度和安全性能角度来探讨Hyperledger fabric。


运行性能

运行性能我围绕着Hyperledger fabric的核心共识机制来阐述。

在这里插入图片描述

共识机制原理图


共识机制原理

  1. 首先客户端向背书(Endorsing peer)节点提交交易提案(Proposal)

注意:这里的背书节点不是随便选的,而是根据背书策略选择相应的背书节点进行背书。

  1. 背书节点收到后,先调用**链码(Chaincode)1**进行模拟执行交易,这一阶段的模拟执行主要是验证一些交易有效性以及判断执 行该交易是否会出现异常。

注意:模拟交易是不提交到记账节点2的。

  1. 当背书节点进行模拟交易发现结果没有问题,那么就响应客户端,告诉客户端交易没有问题。
  2. 这一步也是共识机制的核心。客户端将经过背书节点验证的交易提交给排序节点(Ordering Service),排序节点接受多个交易之后打包成区块发送到各个记账节点。这一步骤原理在下面还会再展开讲解,深入探讨其对Hyperledger在性能提升  中发挥的作用。
  3. 记账节点接收到排序节点发来的区块之后,记账节点会对交易进行一些验证,比如出现一些语法错误3或者逻辑错误4之类   的。如果经过这一系列的验证没有出错后,记账节点就会将这些交易信息提交到本地账本(将包含这些交易的区块链接到   本地节点的区块链当中)。

以上便是Hyperledger fabric v1.0版本的共识机制原理


排序节点性能分析

从整体来说
首先对比一下Hyperledger fabric v1.0和Hyperleder fabric v0.6可以明确的知道,v1.0版本将将节点分为了3种类型:记账节点(一般节点),背书节点,排序节点。这样做的一个最大的好处就是可以大大的提高交易共识的速度。因为在v0.6版本中,HyperLedger默认是所有节点都进行共识,这样难免会有部分节点因为网络等一些原因,导致整体共识速度缓慢,从而影响整体的性能。经过节点分类后将速度较快的节点作为共识节点则可以大大的提高整体的运行速度。

从共识算法来说
在这里插入图片描述

共识算法图


由图可知共识算法分为两类:

  • Crash faults(CFT): CFT共识算法就是能够应对节点错误的共识算法,通俗来说就是能够应对节点宕机,节点损坏等一些Crash fault的共识算法。比如 kafka就是一种典型的CFT算法。
  • Non-crash faults(BFT): BFT共识算法就是能应对一些节点非宕机情况下的共识算法。比如当节点当中存在一些恶意节点时,可以用BTF共识算法。PBFT(拜占庭容错算法)就是一种典型的BFT算法。

注意:Hyperledger fabric v1.0目前只实现了kafka算法,拜占庭算法暂时还未实现。

下面我先分析一下kafka算法和PBFT算法的原理,并对其运行性能进行分析:

  • kafka算法
    严格的说kafka其实并不是一个算法,而是一个机制。在讲kafka之前,先要普及一个重要的知识通道(Channel)

通道:为了实现数据的隔离,Hyperlegder fabric v1.0引入了通道的概念,通道包含了一个或多个的记账节点,并且一个记账节点可以存在于多个通道之中。Hyperledger在创建了通道之后,通道内的节点不停地使用Gossip机制5与通道内的节点传递心跳信息,以此来维持整个通道的拓扑结构,每当有节点加入通道或者离开通道,通道都能快速的调整拓扑结构。通道与通道之间数据不共享,通道内的节点只与通道内的节点进行数据的传播。
**注意:**排序节点并不存在于任何通道内!

kafka机制:kafka是独立于记账节点而存在的一个集群。当来自各个通道的交易信息携带各自的ChannelID提交给排序节点后,排序节点将其转发给kafka集群里的各自通道对应的主题(topic),接着不同的排序节点就从kafka集群中读取最新的交易信息(这个交易信息中包含了对应的ChannelID),然后排序节点就对交易信息进行排序并把来自不同Channel的交易信息打包成一个区块。

注意:如果交易的信息量大于了一个区块的容量,那么排序节点会进行区块的分割操作。

最后排序节点会把这个区块提交给记账节点。

注意:排序节点上形成的区块中带有了各自Channel的ID,因此如果区块提交到记账节点之后,会检查是否有这个Channel对应的链,如果没有则通过系统链创建一个新的链对应到这个Channel。以后排序节点将对收到不同Channel上的包装成区块后就提交到记账节点对应的区块链上。

kafka机制由于使用了主题进行批量转发,因此大大提高了整个共识吞吐效率。

  • PBFT算法

拜占庭容错机制虽然在v1.0版本的Hyperledger fabric上没有实现,但我对其原理进行详解,并对其共识性能进行简要的分析。

在这里插入图片描述

PBFT算法产生的背景

由之前的分析可知,在v1.0当中排序节点进行排序后将交易封装成区块再提交到记账节点。但是,由于网络拥塞等原因,可能背书节点提交给排序节点的交易可能会出现不一致的情况,既然交易不一致,那么执行交易后的结果也必然不一致。因此PBFT算法解决这一问题的原理如下:
1. 首先在排序节点中随机指定一个主节点,或者也可以根据某种策略指定主节点。
2. 其次主节点将节点上的交易顺序通过Gossip机制传递给其他排序节点。
3. 其余排序节点收到交易顺序后,根据主节点的交易顺序对自己的交易顺序进行调整。

图示如下:
在这里插入图片描述

排序节点调整交易顺序图示

由此我们可以知道,PBFT算法可以有效的应对恶意节点的干扰交易次序的攻击,同时对网络拥塞等一些不可避免的情况进行了处理解决了共识因网络问题造成的共识异常缓慢的问题,大大提升了共识机制的运行性能和可靠性。

从生成区块来说
有上面的分析可知,排序节点在完成区块的封装之后,要将区块提交给记账节点,在生成区块的过程当中那就必须要根据区块的内容计算该区块的Hash值。Hyperledger fabric v1.0使用了Merkle Hash来计算区块Hash值。Merkle Hash原理如下图所示:

在这里插入图片描述

Merkle Hash原理图

我们知道每有一条新的交易生成,排序节点就要将这条交易封装进入区块当中,每当一条新的交易封装如区块时,如果没有使用Merkle Hash我们必须每次都重新计算整个区块的Hash值。假设这个区块里的交易信息有100M,那么每加一条交易信息,我们必须要重新计算这100M的的交易信息的Hash值,这会大大拖慢整个Hyperledger的运行速度。


Merkle Hash的原理就是,将这一整个区块的交易信息在逻辑上分成一个一个小块,比如分成HA,HB,HC,HD....HP这16个块。然后我们采用了类似霍夫曼编码的算法,两两计算Hash值,比如HAHB计算Hash值为HABHCHD计算Hash值为HCD…其余的以此类推。直到最后HABCDEFGHHIJKLMNOP计算Hash值获得整个区块最终的Hash值。假如说新加入了一条交易,这条交易被随机分进了一个还未满的块,比如说HK,那么需要重新计算Hash值得只有HKLroot块的这一分支上的这些节点的Hash值而已。综上所述Merkle Hash成功将时间复杂度降到了O(log2n)


安全性能

我将从Hyperleder fabric v1.0在CA这一块的安全机制以及对用户交易数据的保护这两个核心部分来对Hyperledger的安全性能进行分析。当然Hyperleder fabric v1.0在Chaincode上也使用了docker进行隔离,使得不同的Chaincode可以运行在不同的容器上。

在这里插入图片描述

Hyperledger fabric v1.0的架构示意图
  • Hyperledger fabirc v1.0对CA的支撑: Hyperledger fabirc v1.0对CA的支撑主要体现在会员制(Membership)服务上。如下图所示:
    在这里插入图片描述
Membership上的CA机制示意图

Membership上的CA分为三种:E-CertT-CertTLS-Cert

  • E-Cert:交易方长期持有,用于身份认证以及追溯使用者的信息。
  • T-Cert:每一个交易生成的时候用于交易的签名。
  • TLS-Cert:主用用于通信双方的认证。

与此同时Hyperledger fabirc v1.0引入了Fabric CA来管理这些数字证书。这些证书在Fabric对用户隐私数据的解决中起了重要作用。
下面我简要分析一下Hyperledger fabric v1.0对用户隐私问题的解决原理:在交易的过程当中,T-Certs不会携带有关交易双方的任何信息,只是对交易进行一个签名,以此来证明这个交易是一个有效的交易,因此如果想要通过交易信息追溯到交易双方的信息是不可能的。有关交易双方的信息都存储在E-Certs当中。

  • Hyoerledger fabirc v1.0对交易数据的保护:
    Hyperledger fabric采用对称加密非对称加密结合的方式,取对称加密之效率及非对称加密之安全来达成相对完备的安全体系。其原理如下:
  1. 首先对于仅在一个group内的交易信息共享,hyperledger fabric先对交易信息进行对称加密。
  2. 将生成的密钥再用group内成员的公钥进行非对称加密,将这个加密后的这个密钥分别分发给group内的各个成员
  3. 各个成员在收到这个密钥后,各自用自己的私钥进行解密,于是就获得了对称加密的密钥,于是group成员就可以使用对称加密进行高性能的信息传输。

Hyperledger fabirc v1.0对对交易数据的加密原理示意图如下:

在这里插入图片描述

交易数据的加密原理示意图

IOTA性能分析

IOTA是一个全新的加密货币系统,它和区块链最大的区别就是,IOTA是基于DAG的加密货币系统,而区块链是基于链式结构的加密货币系统。IOTA当中所有的交易构成一个个的节点,节点和节点之间通过验证关系来形成边,从而构成一张DAG6

IOTA运行性能

由于IOTA中节点的验证对整个tangle的运行速度起着至关重要的作用,以此目前我主要围绕tangle的两种验证策略对IOTA性能进行分析。

我们首先来看一下tangle的示意图:
在这里插入图片描述

IOTA系统中tangle示意图1

在IOTA中有几个概念要明确一下,因为坐在后面讲解验证策略的时候需要用到。

  1. Tips: Tips就是在这个Tangle当中代表的是入度为0的点,在现实当中代表的是最新产生的待验证的交易。
  2. 累计权重: 累计权重为当前交易自身的权重加上直接或间接验证这个交易的权值的和。权值在选择验证节点的时候至关重要。

举个例子:参照上图,节点(交易)F被E,B直接验证,被A,C间接验证,因此节点F的累计权重为3+3+1+1+1=9。

  1. 积分: 积分刚好与累计权重的定义相反,为当前交易自身的权重加上所有被它直接或间接验证的交易的权值。

举个例子:参照上图,由于节点A和C是Tips,因此图上所有的交易均能被这两个Tips直接或者间接验证。那么节点A直接验证了B,D,间接验证了F以及权值为11,10和13的节点,因此节点A的积分为:1+3+1+3+1+1+1=11。同理可得节点C的积分为:1+1+1+3+1+1+1=9。

  1. 高度: 某个交易的高度定义为创世交易到这个交易的所有路径的最大值。

举个例子:在示意图2中,交易F的高度为2,交易D的高度为3。

  1. 深度: 深度的定义刚好和高度的定义相反。某个交易的深度定义为当前这个交易到Tips的路径的最大值。

举个例子:在示意图2中,交易D的深度为2,交易F的深度为3。

在这里插入图片描述

IOTA系统中tangle示意图2

下面我们正式来分析两种不同的验证策略对IOTA系统带来的性能的影响:

  • 随机验证两个Tips策略: 这种策略很容易理解,就是在所有的Tips当中随机选择两个Tips进行验证。但这种策略会带来的坏处也显而易见,因为这种策略不鼓励节点去验证新的交易。比如说有几个“较懒”的用户他总是去验证那些懒惰的Tips,对正常的Tips的验证不做任何的贡献,因此这对于IOTA整个系统在高负载的情况下的运行性能带来了问题。

懒惰的Tips:懒惰的Tips的意思就是那些直接验证很早之前的旧交易的Tips称为懒惰的Tips,如示意图3所示。
正常的Tips:正常的Tips就是那些验证最新产生的交易的Tips。

  • 随机验证前αL(t)个Tips中的两个Tips: 这种策略对之前的策略进行了改进,它选取了一个参数α(0<α<1),然后在前αL(t)个Tips当中随机选取两个Tips进行验证(L(t)的表示的是在t时刻tangle中所有的Tips的个数)。α的值可以根据不同的负载进行调节。因此这样就可以基本避免出现总是去验证懒惰的Tips的问题。当然这个策略同样也存在问题,对于那些没有进入前αL(t)个的交易,他们等待的时间会非常的长,这也会对整个系统的性能带来影响。一个解决方法就是发起一笔空白交易,并让这个空白交易去验证没有进入前αL(t)的交易,同时希望这笔空白交易进入前αL(t)个交易。
    在这里插入图片描述
IOTA系统中Tangle示意图3

IOTA安全性能分析

IOTA中存在几种攻击,我通过简要介绍这几种攻击的原理以及IOTA的应对策略来对IOTA的安全性能进行简要的分析。

  • 双花攻击:双花攻击的意思是在一笔合法的交易之后又发起了一笔不合法的交易,并且攻击者在发起了这笔不合法的交易之后,使用自己全部的算力发起大量的微小的交易,并且让这些大量的微小交易去验证后来发起的那个不合法的交易,从而验证这个交易的sub_DAG 超过了主体DAG使得IOTA认为这个错误的交易是正确的并继续往下发展,而原来的那个正确的交易则被抛弃掉。
  • 大权重攻击:大权重攻击其实是双花攻击的一种,只是攻击的方法不同。在发起不合法交易之后,攻击者使用自己全部的算力发起一个权重很大的交易,IOTA会默认优先选择累计权重比较大的交易进行验证7,因此这种攻击让IOTA不断地验证错误的交易,导致原来正确的交易被舍弃。
    解决方案: 设置每个交易的自身权值上限,或者固定权值。
  • 寄生链攻击:攻击者自己建立一个或者Sub-tangle然后接到主tangle上。由于攻击者自己建的链/Sub-tangle可以自己任意的添加交易因此一般情况下寄生链tips拥有更高的积分以及高度,因此有脚注7可知,IOTA会去不断地验证寄生链上的tips从而导致主tangle被无效化。
    解决方案: 使用MCMC算法8
  • 分裂攻击:还在理解。

  1. 智能合约(Smart Contract)在Hyperledger fabric1.0中的表现就是链码,是一段独立运行的程序,并且只与背书节点进行交互。 ↩︎

  2. 记账节点就是一般节点,因为任何一个节点具备记账功能,将交易记录到本地账本上。 ↩︎

  3. 语法错误一般指的是无效的输入,未验证的签名以及重复的交易。 ↩︎

  4. 逻辑错误:逻辑错误一般是指交易的逻辑存在问题从而导致交易失败。 ↩︎

  5. Gossip机制:在Hyperledger fabric v1.0版本之前使用的是洪泛法进行消息的传递,也就是每个节点都将节点信息传递给所有的相邻的节点,再由相邻的节点传递给与之相邻的节点。洪泛法的优点就是消息传播的范围很广,但这个优点也会产生一些不可忽视的缺点,比如:广播风暴以及消耗时间长。因此Gossip机制就采取了节点向随机k个相邻节点传播节点信息,或者可以根据一定的策略进行不随机的选择k个节点。这样做的好处就是有效的避免了广播风暴同时节约了时间。 ↩︎

  6. DAG即有向无环图,在IOTA中DAG也成为tangle↩︎

  7. IOTA默认优先选择累计权值tips积分以及tips高度比较大的进行验证是因为,IOTA认为累计权值越大,则证明该Tips验证得交易数量就越大,可信度越高。 ↩︎

  8. MCMC算法:还在理解。 ↩︎

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Hyperledger Fabric的PBFT算法Go语言实现代码: ```go package pbft import ( "crypto/sha256" "encoding/hex" "encoding/json" "fmt" "sync" ) const ( // PbftPhaseNotStarted represents the state where PBFT is not started PbftPhaseNotStarted = iota // PbftPhasePrePrepare represents the state where PBFT is in the pre-prepare phase PbftPhasePrePrepare // PbftPhasePrepare represents the state where PBFT is in the prepare phase PbftPhasePrepare // PbftPhaseCommit represents the state where PBFT is in the commit phase PbftPhaseCommit ) // PbftMessage represents a message in the PBFT algorithm type PbftMessage struct { Phase int SequenceNum int View int Digest string Block []byte ReplicaID int } // Pbft represents a PBFT instance type Pbft struct { mux sync.Mutex replicaID int view int sequenceNum int state int digest string block []byte messages map[string]PbftMessage } // NewPbft creates a new PBFT instance with the specified replica ID func NewPbft(replicaID int) *Pbft { return &Pbft{ replicaID: replicaID, view: 0, state: PbftPhaseNotStarted, messages: make(map[string]PbftMessage), } } // Start starts the PBFT algorithm with the specified block func (p *Pbft) Start(block []byte) { p.mux.Lock() defer p.mux.Unlock() // Set the initial state p.view = 0 p.sequenceNum = 1 p.state = PbftPhasePrePrepare p.block = block // Compute the digest of the block digest := sha256.Sum256(block) p.digest = hex.EncodeToString(digest[:]) // Create and broadcast the pre-prepare message prePrepareMsg := PbftMessage{ Phase: PbftPhasePrePrepare, SequenceNum: p.sequenceNum, View: p.view, Digest: p.digest, Block: p.block, ReplicaID: p.replicaID, } p.broadcast(prePrepareMsg) } // HandleMessage handles an incoming PBFT message func (p *Pbft) HandleMessage(msg []byte) { p.mux.Lock() defer p.mux.Unlock() // Parse the message var pbftMsg PbftMessage err := json.Unmarshal(msg, &pbftMsg) if err != nil { fmt.Printf("Failed to parse PBFT message: %s\n", err) return } // Check if we have already seen this message key := p.getMessageKey(pbftMsg) if _, ok := p.messages[key]; ok { return } // Add the message to our list of seen messages p.messages[key] = pbftMsg switch p.state { case PbftPhasePrePrepare: p.handlePrePrepare(pbftMsg) case PbftPhasePrepare: p.handlePrepare(pbftMsg) case PbftPhaseCommit: p.handleCommit(pbftMsg) } } // broadcast broadcasts a PBFT message to all other replicas func (p *Pbft) broadcast(msg PbftMessage) { // TODO: implement broadcast } // handlePrePrepare handles a pre-prepare message func (p *Pbft) handlePrePrepare(msg PbftMessage) { if msg.View != p.view || msg.SequenceNum != p.sequenceNum || msg.Digest != p.digest { return } // Create and broadcast the prepare message prepareMsg := PbftMessage{ Phase: PbftPhasePrepare, SequenceNum: p.sequenceNum, View: p.view, Digest: p.digest, Block: p.block, ReplicaID: p.replicaID, } p.broadcast(prepareMsg) // Update state p.state = PbftPhasePrepare } // handlePrepare handles a prepare message func (p *Pbft) handlePrepare(msg PbftMessage) { if msg.View != p.view || msg.SequenceNum != p.sequenceNum || msg.Digest != p.digest { return } // Update state p.state = PbftPhaseCommit // Create and broadcast the commit message commitMsg := PbftMessage{ Phase: PbftPhaseCommit, SequenceNum: p.sequenceNum, View: p.view, Digest: p.digest, Block: p.block, ReplicaID: p.replicaID, } p.broadcast(commitMsg) } // handleCommit handles a commit message func (p *Pbft) handleCommit(msg PbftMessage) { if msg.View != p.view || msg.SequenceNum != p.sequenceNum || msg.Digest != p.digest { return } // TODO: validate the commit message } // getMessageKey returns a unique key for a PBFT message func (p *Pbft) getMessageKey(msg PbftMessage) string { return fmt.Sprintf("%d:%d:%s:%d", msg.View, msg.SequenceNum, msg.Digest, msg.ReplicaID) } ``` 注意,上述代码只是一个简单的示例,需要根据实际情况进行修改和扩展。另外,这里的广播机制还没有实现,需要根据实际情况选择适当的广播方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值