[翻译]HyperLedger下一代共识架构提案
Posted 李赫的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[翻译]HyperLedger下一代共识架构提案相关的知识,希望对你有一定的参考价值。
[翻译]Next Consensus Architecture Proposal
作者: Elli Androulaki, Christian Cachin, Angelo De Caro, Konstantinos Christidis, Chet Murthy, Binh Nguyen, Alessandro Sorniotti, and Marko Vukolić
翻译:梧桐树
- 目录
- 1. 系统架构(System architecture)
- 2. 交易背书的基本流程 (Basic workflow of transaction endorsement)
- 3. 背书策略
- 4. 区块链数据结构
- 5. 状态传输和检查点
- 6. 机密性(Confidentiality)
本文阐述的是一个区块链基础架构,它的区块链节点角色划分为Peer节点(peers)(维护状态/总账的节点)和投票节点(consenters)(投票赞成区块链状态中交易顺序的节点)。在通常的区块链架构中(包括2016年7月的Hyperledger fabric),这些角色都是统一的(参看Hyperledger fabic的validating peer)。这个架构还引入了背书节点(endorsers)的概念,它其实是一种特殊类型的节点,用来模拟执行和背书交易(大概和Hyperldger fabric 0.5-developer-preview的执行/验证交易是类似的)。
这种架构和peers/consenters/endorsers统一的设计相比有如下的优势:
- 链码信任的灵活性(chaincode trust flexibility)。从架构上,区分开链码(区块链应用程序)的信任假设与共识服务的信任假设。就是说,参与到共识服务中的节点可能是背书节点(consenters),也能容忍一些节点失效或者破坏。还有,每个链码的背书节点可能会是不一样的。
- 可扩展性(Scalability)。因为负责特定链码的背书节点和投票节点是正交的,这比所有功能都集中在同一个节点能更好的扩展。尤其是,当最终不同的链码都指定完全不同的背书节点时,链码会在不同的背书节点上分散开,链码执行(背书:endorsement)就可以并行了。而且,链码执行是非常耗时的,不再是共识服务的关键路径了。
- 机密性(Confidentiality)。这个架构使对内容和执行状态更新有机密性要求的链码部署更容易了。
- 共识模块性(Consensus modularity)。这个架构是模块化的,运行插件化的共识实现。
目录
- 系统架构
- 基本的交易背书工作流
- 背书策略
- 区块链数据结构
- 状态转换和检查点
- 机密性
1. 系统架构(System architecture)
区块链是由很多相互通信的节点组成的分布式系统。区块链运行程序(称为链码),保存状态和总账数据,执行交易。链码是处于中心位置,交易是在链码上执行的操作,并且只有链码才能更改状态。交易必须要有背书,只有有背书的交易才能被提交,才能使状态生效。有一个或者多个具有管理功能和参数的特殊链码,统称系统链码(system chaincodes)。
1.1. 交易(Transactions)
交易有两种类型:
- 部署交易(Deploy transactions) 用程序作为它的一个参数创建新的链码。当部署交易成功执行以后,我们就说链码被安装到“链上”了。
- 调用交易(Invoke transactions) 在前面部署的链码环境上执行一个操作。一个调用交易指的是链码及其提供的功能。如果成功的话,链码会执行指定的功能,可能会修改相关的状态,然后返回输出。
后面还会介绍,部署交易是调用交易的特殊情况,调用交易创建新的链码就是在系统链码上的调用交易。
备注:本文假定一个交易要么创建新的链码,要么调用一个已经部署链码提供的交易。本文不会涉及如下内容:a) 跨链交易的支持; b) 查询交易(只读的)的优化。
1.2. 状态(State)
区块链状态(Blockchain state)。区块链的状态(世界状态:world state)有一个简单的结构,模型化就是一个版本化的键值存储(KVS),其中键是名称,值是任意的二进制大对象。这些条目由运行在区块链上的链码(应用)通过put
和get
的KVS进行操作。这些状态是被永久存储的,状态的更新也会有记录。注意版本化的KVS只是状态模型,实现方式可以使用真正的KVS系统,也可以采用关系型数据库系统或者其他的解决方案。
正式点表示,区块链状态s
是K -> (V X N)
映射的一个元素,其中:
K
是键的集合V
是值的集合N
是无数个有序的版本号集合。单射函数next: N -> N
输入N
的一个元素,返回下一个版本号。
V
和N
都有一个特殊的元素\\bot
,代表N
最小的元素。初始化的时候,所有的键都被映射到(\\bot,\\bot)
。s(k)=(v,ver)
这个表达式中,v
用s(k).value
来表示,ver
用s(k).version
来表示。
KVS操作是这样定义的:
put(k,v)
操作。对k\\in K
和v\\in V
键值对,区块链状态s
的新状态s'
计算方法是:s'(k)=(v,next(s(k).version))
。并且对所有的k'!=k
,表达式s'(k')=s(k')
都成立。get(k)
操作。返回s(k)
。
状态分区(State partitioning)。KVS中的键可以通过名称就能识别出它们属于哪个链码,所以只有特定链码的交易才能修改属于这个链码的键。原则上,任意的链码都能读取属于其他链码的键(机密链码的状态是不能明文读取的,参考第6部分)。修改2个或者多个链码状态的跨链交易,以后会支持。
总账(Ledger)。区块链状态的变化过程(历史)是保存在总账中的。总账是交易区块的哈希链(hashchain),总账中的交易是全序的。
区块链状态和总账会在第4部分详细描述。
1.3. 节点(Nodes)
节点是区块链的通信实体。节点是一个逻辑的概念,不同类型的节点是可以运行在同一个物理服务器上的。重要的是节点是怎么被分组成“信任域(trust domains)”,怎么和控制它们的逻辑实体关联的。
有3种类型的节点:
-
客户端(Client)或者提交客户端(submitting-client):提交实际交易请求的客户端。
-
Peer节点(Peer):一个提交交易,维护状态和总账副本的节点。Peer节点有两种特殊的角色:
a. 请求节点(submitting peer或者submitter)
b. 背书节点(endorsing peer或者endorser)
-
共识服务节点(Consensus-service-node)或者投票节点(consenter):一个运行了有送达保证(delivery guarantee,比如原子广播)通信服务的节点,送达保证典型的实现方法是运行共识服务。
注意,投票节点和客户端是不维护总账和区块链状态的,只有Peer节点才会。
下面详细解释节点的类型。
1.3.1. 客户端(Client)
客户端表示的是代表终端用户的实体,它必须连接到Peer节点才能和区块链通信。客户端可以根据自己的选择连接到任意一个Peer节点上,创建交易再调用交易。
1.3.2. Peer节点(Peer)
Peer节点通过共识服务通信维护区块链状态和总账。它们从共识服务接收有序的更新状态,然后更新本地维护的状态。
Peer节点还可以有下面描述的两种角色:
-
请求节点(Submitting peer)。请求节点是一种特殊的角色,它给客户端提供接口,这样客户端就可以连接到请求节点调用交易和获取结果。这个Peer节点代表一个或者多个客户端和其他节点通信来执行交易。
-
背书节点(Endorsing peer)。背书节点的特殊功能是对特定的链码,在其提交交易前对它进行背书。每个链码都可以指定一个背书策略,可能会包含一个背书节点的集合。策略定义了一个有效交易背书(典型情况是背书节点的签名集合)的充要条件,这会在第2部分和第3部分阐述。一个特殊情况是,安装新链码的部署交易中,(部署)背书策略是系统链码的背书策略指定的。
我们强调一个Peer节点同时有请求节点和背书节点角色的时候,就叫它提交节点(committing peer)。
1.3.3. 共识服务节点(Consensus service node (Consenters))
投票节点构成了共识服务,也即,一个提供交付保证的通信组织。共识服务可以有多种实现方式:从中心化的服务(比如:部署和测试)到其目标是不同网络和节点失效模型的分布式协议。
Peer节点是共识服务的客户端,共识服务给它提供了一个有交易信息广播服务的共享通信通道。Peer节点连接到通道上,可以发送或者接收消息。通道支持所有消息的原子交付,就是,消息通信是全序交付的和(跟实现相关)可靠的。换句话说,通道输出给所有连接的节点相同的消息,而且输出的逻辑顺序是相同的。原子通信保证又叫全序广播(total-order broadcast),原子广播(atomic broadcast),或者分布式系统环境下的共识(consensus)。通信过的消息就是作为包含在区块链状态中的候选交易。
共识通道分区(Partitioning (consensus channels))。共识服务可能支持多通道,类似发布/订阅(pub/sub)消息系统的主题(toptics)。客户端连接到一个指定的通道,就可以发送或者获取到达的消息。通道可能会有分区,客户端连接到一个通道是不知道其他通道的存在的,但是客户端可以连接到多个通道。为简单起见,本文后面的部分,除非明确的提到了的其他情况,我们都假设共识服务是由单个通道/主题组成的。
共识服务API(Consensus service API)。Peer节点是通过共识服务的API连接到共识服务提供的通道的。共识服务API有两种基本的操作(更通用的说法:异步事件):
-
broadcast(blob)
:请求节点调用它在通道上广播任意的消息blob
。这在BFT中,当给服务发送一个请求时,又称为request(blob)
。 -
deliver(seqno, prevhash, blob)
:共识服务调用它给Peer节点发送包含非负序列号seqno
和最近一次发送消息哈希prevhash
的消息blob
。换句话说,它是共识服务的输出事件。deliver()
在发布/订阅系统中称为notify()
,BFT系统中称为commit()
。注意共识服务客户端(即Peer节点)只通过
broadcast()
和deliver()
事件和服务进行交互。
共识内容(Consensus properties)。共识服务(或者原子广播通道)有如下的保证,回答了这些问题:广播消息发生了什么
,交付消息间有什么关系
?
-
安全性:一致性保证(Safety (consistency guarantees)):只要Peer节点连接到通道有足够长的时间(它们可以断开或者宕掉,重启或者重新连接就可以),它们就能看到
相同
顺序的交付消息(seqno, prevhash, blob)
。这意味着,给所有Peer节点的输出(deliver()
事件)都是相同顺序
的,相同的序号都是相同的内容
(blob
和prevhash
)。需要注意的是,这只是一个逻辑顺序
,并且,一个Peer节点的deliver(seqno, prevhash, blob)
并不需要和另外一个Peer节点上输出了相同消息的deliver(seqno, prevhash, blob)
有时间上的关联。换句话说,给定一个特定的seqno
,不会
有两个正常的Peer节点发送不同
的prevhash
和blob
。而且是,除非有共识客户端(Peer节点)真正的调用了broadcast(blob)
,是不会有blob
消息发送的,最好是,每个广播的blob
只发送一次
。还有,
deliver()
事件包含了上一个deliver()
事件的加密哈希prevhash
。当共识服务执行一个原子广播保证时,prevhash
是序号为seqno-1
的deliver()
事件的加密哈希。这就在不同的deliver()
事件之间建立了一个哈希链,能够用来帮助验证共识输出的完整性,后面的第4部分和第5部分会讨论这个。第一个deliver()
事件是一个特殊情况,prevhash
会有一个默认值。 -
活跃度:交付保证(Liveness (delivery guarantee)):共识服务的活跃度保证是共识服务的实现指定的。精确的保证要依赖网络和节点失效模型。
原则上,如果提交没有失败,共识服务应该保证每个连接到共识服务的Peer节点最终都能提交每个发出的交易。
总结一下,共识服务保证了下面的内容:
-
协议(Agreement)。正常Peer节点的任意两个事件,
deliver(seqno, prevhash0, blob0)
和deliver(seqno, prevhash1, blob1)
,如果有相同的seqno
,则有prevhash0==prevhash1
,blob0==blob1
成立; -
哈希链完整性(Hashchain integrity)。正常Peer节点的任意两个事件,
deliver(seqno-1, prevhash0, blob0)
和deliver(seqno, prevhash, blob)
,有prevhash = HASH(seqno-1||prevhash0||blob0)
; -
不跳跃(No skipping)。如果一个共识服务给一个正常节点
p
输出deliver(seqno, prevhash, blob)
,如果seqno>0
,则p
一定已经交付了deliver(seqno-1, prevhash0, blob0)
事件; -
不创建(No creation)。一个正常节点的任意
deliver(seqno, prevhash, blob)
事件,前面一定有一个Peer节点发送了broadcast(blob)
事件; -
不重复(No duplication,可选的)。对任意的两个事件
broadcast(blob)
和broadcast(blob')
,当正常Peer节点交付了两个事件,deliver(seqno0, prevhash0, blob)
和deliver(seqno1, prevhash1, blob')
,如果blob
==blob'
,则有seqno0==seqno1
和prevhash0==prevhash1
成立; -
活跃度(Liveness)。如果一个正常Peer节点产生了
broadcast(blob)
事件,则每个正常Peer节点“最终”都会发出一个deliver(*, *, blob)
事件,其中*
代表任意值。
2. 交易背书的基本流程 (Basic workflow of transaction endorsement)
下面我们概要性的介绍一个交易的高层请求流程。
备注:注意后面的协议并不假定所有的交易都是确定性的,允许不确定性的交易。
2.1. 客户端创建一个交易并发送给自己选择的一个请求节点
要调用一个交易,客户端发送如下的消息给请求节点spID
。
<SUBMIT,tx,retryFlag>
,其中:
tx=<clientID,chaincodeID,txPayload,clientSig>
,其中:clientID
是提交客户端的ID,chaincodeID
指的是交易所属的链码,txPayload
是发出的交易本身的有效载荷,clientSig
是客户端tx
消息中其他项的签名。
retryFlag
是一个布尔值,告诉请求节点万一交易失败了要不要重传,
调用交易和部署交易的txPayload
是不一样的(即,调用交易会引用一个部署相关的系统链码)。如果是调用交易,txPayload
只有一个项:
invocation = <operation, metadata>
,其中:operation
代表链码的操作(函数)和参数,metadata
代表调用相关的属性。
如果是部署交易,会有两个项:
chainCode = <source, metadata>
,其中:source
代表链码的源码路径,metadata
代表链码和应用相关的属性。
policies
包含了所有Peer节点都能访问的链码策略,比如背书策略。
待办:确定是否要在客户端显示的包含本地/逻辑时间(时间戳)。
2.2. 请求节点准备一个交易并发送给背书者获取背书
请求节点收到客户端发来的<SUBMIT,tx,retryFlag>
消息后,首先要验证客户端的签名clientSig
,然后就准备交易。请求节点会临时的执行交易(HyperLedger的共识之系统架构