💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
>[info] 原文地址:https://github.com/hyperledger/fabric/blob/master/proposals/r1/Next-Consensus-Architecture-Proposal.md 本文档介绍了一个区块链基础设施的体系结构。这里面一个区块链节点的角色分为peers角色【对等体角色】(维护状态/账本),和orderers角色【订阅者角色】(对于账本中事务处理顺序达成共识者)。在常见的区块链架构中(包括Hyperledger Fabric v0.6及之前版本),这些角色都是统一的(参见:Hyperledger Fabric v0.6中的validating peer【验证对等体】)。该架构还引入了endorsing peers(即endorsers)【签名对等体】,作为负责模拟执行和签名事务(大致对应于在HL Fabric 0.6中处理事务的过程)的特殊类型对等体 该架构相比于那些把peers/orderers/endorsers设计为一个的架构(比如,HL Fabric v0.6),有如下优势: * **链码信任的灵活性。** 该架构将链码(区块链上的应用程序)的信任假设与ordering【用于排序】的信任假设区分开来。换句话说,排序服务可以由一系列节点(orderers)提供,并且可以容忍它们中有一些失败或行为不正确,而且对于每一个链码,endorsers可以不同 * **可扩展性。** 由于负责特定链码的endorser节点,与orderers节点是不相关的【orthogonal,正交的】,所以相对于这些功能都是由同样的节点来完成的系统,该系统可以具有更好的扩展性。尤其是当不同的链码指定了不相关的endorsers的情况下,在endorsers中引发了链码的分割,这样就可以允许链码并行执行(endorsement)。此外,那些可能会非常耗时的链码执行,也从ordering服务的关键路径中移除了。 * **保密性。** 对于那些需要内容保密,和事务状态更新保密的链码,使用该架构可以更方便部署。 * **共识模块化。** 该架构是模块化的,并且允许插件式的共识机制实现(比如,ordering service) 这个架构驱动了Hyperledger Fabric v0.6之后版本的开发。下面详述的部分,有些方面会包含在Hyperledger Fabric v1中,而其它部分会延缓至v1之后的版本中。 #### **目录** **第一部分:和Hyperledger Fabric v1相关的架构细节** 1. 系统架构 2. 事务背书【transaction endorsement】的基本工作流 3. 支持策略【Endorsement policies】 **第二部分:v1后续版本的架构细节** 4. 账本检查点(剪枝) * * * * * **1. 系统架构** 区块链是一个分布式系统,包含了很多节点,他们之间互相通信。区块链上运行的程序被称为链码,它们维护状态,和账本数据,以及处理事务。链码是核心要素,因为事务是在链码上调用的操作。事务必须是“可信的【endorsed】”,并且只有可信的事务才会被提交然后对状态产生影响。可能存在一个或多个特殊的链码,来管理函数和参数,统称为系统链码。 **1.1. 事务** 事务可能有2种类型: * *部署类事务*,产生新的链码,接收一个程序作为参数。当一个部署类事务执行成功,相应的链码就安装在了区块链上。 * *调用类事务*,在之前部署的链码上下文环境中执行一个操作。一个调用类事务引用一个链码和一个它提供的函数。当调用类事务执行成功时,链码执行特定的函数 -- 可能包含修改对应的状态,并且返回一个输出。 后续部分会讲解,部署类事务是调用类事务的一个特殊情况,因为一个部署类事务产生了一个新链码,就相当于在一个系统链码上执行一个调用类事务。 >[warning]注意:这份文档目前假设一个事务要么产生新的链码,要么在一个已经部署的链码上调用一个操作。该文档没有描述:a)查询类事务(只读)的优化(已包含在v1中),b)跨链码事务支持(v1之后版本的特性)。 **1.2. 区块链数据结构** **1.2.1. 状态** 区块链的最新状态(或者简单的说,就是状态)被建模为一个版本控制的key/value存储结构(KVS),keys是名字,values是任意二进制对象(blobs,binary large objects)。这些条目被运行在区块链上的链码(应用程序),通过```put```和```get```进行操作。状态将永久存储,并且会记录状态的更新。注意版本控制的KVS被采用作为状态模型,而实际实现可以使用真正的KVS系统,同时也可以使用RDBMS(关系型数据库管理系统),或者任何其他解决方案。 更加形式化的表达,状态s被建模为一个映射元素`K -> (V X N)`。这里: * `K`是一个keys集合 * `V`是一个values集合 * `N`是一个版本号的无限顺序集合。单射函数`next: N -> N`接收一个元素`N`,并且返回下一个版本号。 `V`和`N`都包含一个特殊元素`bot`,它是确保`N`有效的最低元素。最初时,所有的keys都被映射为`(bot, bot)`。对于`s(k)=(v, ver)`,我们使用`s(k).value`代表`v`,使用`s(k).version`代表`ver`。 KVS操作被如下建模: * `put(k, v)`,对于`k in K `和`v in V`,接收区块链状态`s`,并且将其改为`s'`,使得对于所有的`k' != k`,都有`s'(k)=(v, next(s(k).version))`,并且`s'(k') = s(k')` * `get(k)`返回`s(k)` 状态被peers维护,而不是被orderers和clients维护。 >[warning] **状态分区。** 在KVS中的Keys可以从他们的名字识别出属于哪一个特定的链码,从某种角度上来说,只有一个确定链码上的事务才能更改这个链码上的keys。原则上,任意链码都可以读取其它链码的keys。跨链码事务支持,即可以修改2个或多个链码状态是v1之后的版本特性。 **1.2.2 账本** 账本提供了一个能作证的历史记录,包含了所有成功的状态改变(我们称之为合法事务),和所有不成功的改变状态尝试(我们称之为不合法事务),当对系统进行操作时记录。 账本被ordering服务(见1.3.3节)所构建,是一个关于区块,关于(合法或不合法)事务的完全有序的哈希链。**这个哈希链在一个账本中强制区块的总顺序,并且每一个区块包含了一系列完全有序的事务。这就强制保证了所有事务的总顺序。** 账本被保存在所有的peers中,可选的,还可以保存在部分orderers中。在一个orderer上下文环境里,我们称账本【Ledger】为`OrdererLedger`,而在一个peer上下文环境中,我们称账本为`PeerLedger`。`PeerLedger`和`OrdererLedger`有所不同,表现为peer本地会维护一个位掩码,以区分开合法事务和不合法事务。(详见XX节) 按照XX节的描述,Peers可能会删除`PeerLedger`(v1之后版本的特性)。Orderers还会保持`OrdererLedger`,用来容错和可用性(`PeerLedger`的作用),并且也可能在任何时候删除它,只要ordering服务(见1.3.3.节)的属性已被保存。 账本允许peers回放所有事务的历史,以重构状态。因此,1.2.1节中描述的状态是一个可选的数据结构。 **1.3. 节点【Nodes】** 节点是区块链上的通信实体。一个“节点【node】”仅仅是一个逻辑函数,多个不同类型的节点可以运行在同一个物理服务器上。最重要的是在“信任域”上节点如何分组,以及如何关联控制它们的逻辑实体。 有3种类型的节点: 1. **Client或者submitting-client**:向endorsers提交一个实际事务调用【transaction-invocation】的客户端,并且向ordering服务广播事务提议【transaction-proposals】。 2. **Peer**:提交执行事务,并且维护状态,以及账本(见1.2节)的一份拷贝的节点。此外,peers可以拥有一个特殊的**endorser**角色。 3. **Ordering-service-node或者orderer**:运行通信服务的节点,它实现了一个保证性传输,比如原子性或者全序广播。 下面详述这几个节点类型。 **1.3.1. Client** client表示那些代表终端用户行为的实体。它必须连接到一个peer上才能和区块链通信。client可以连接到它选择的任何peer上。Clients创建并调用事务。 如第2节详述的那样,clients和peers以及ordering服务都会进行通信。 **1.3.2. Peer** 一个peer以区块的形式从ordering服务中接收有序状态更新,并维护状态和账本。 Peers可以额外从事一个特殊的角色:**endorsing peer**,或者称作**endorser**。一个endorsing peer的特殊功能与一个特定的链码有关,并且在事务被提交之前对其进行认证【endorsing】。每一个链码都可能会修改担保策略【endorsement policy】,这可能会涉及到一系列担保节点【endorsing peers】。该策略定义了一个合法的事务认证过程所需要的必要且足够的条件(通常是一组认证者的签名),正如后面第2和3节描述的那样。在部署性事务安装新链码这种特殊情况中,(部署)验证策略就被指定为系统链码的一个验证策略。(endorse到底翻译成啥合适,这段太乱了) **1.3.3. Ordering service nodes(Orderers)** orderers提供ordering服务,比如一个通信结构提供可靠性传输。ordering服务可以通过多种途径实现:从中心化服务(比如曾经开发测试中使用的),到针对不同网络和节点故障模型的分布式协议。 Ordering服务为clients和peers提供了一个共享的通信频道,为包含事务的消息提供了一个广播服务。Clients连接上频道,就可以在频道上广播消息,这样就可以被送达所有的peers。频道支持原子性传输所有消息,即,消息通信全部有序,并且可靠(依赖于具体实现)。换句话说,频道向所有连接上的peers输出同样的消息,并且都按照同样的逻辑顺序输出。**这种原子性的可靠通信,在分布式系统的上下文中,也被称为全序广播,原子广播,或者共识**。通信的消息是用于包含在区块链状态中的候选事务。 **分隔(ordering服务频道)。** 有序服务【Ordering service】可能支持多个频道,类似于出版/订阅(pub/sub)信息系统中的多个主题。客户端【Clients】可以连接到一个给定的频道,然后可以发送消息,并能够取得抵达的消息。频道可以想做是分区 -- 连接到一个频道的客户端,感觉不到其它频道的存在,但是客户端也能够够连接到多个频道上。尽管在Hyperledger Fabric v1版本中,一些有序服务的实现将会支持多频道,但为了讲解简单,在这篇文档的余下部分,我们假设有序服务只包含一个频道/主题。 **有序服务API**。Peers通过有序服务提供的接口,连上频道。有序服务API包含2个基本的操作(更通常的说是异步事件): * `broadcast(blob)`:一个客户端调用这个方法,在频道上广播任一个消息`blob`。这个在BFT上下文中,当向服务发送一个请求时,也被称为`request(blob)`。 * `deliver(seqno, prevhash, blob)`:有序服务在peer上调用这个方法传递消息`blob`,并且携带指定的非负实数序列号(`seqno`),以及最近已传递的blob消息哈希值(`prevhash`)。换句话说,它是有序服务的一个输出事件。`deliver()`在出版/订阅系统上有时被称为`notify()`,在BFT系统上有时被称为`commit()` **账本和区块构成**。账本(见1.2.2节)包含了有序服务的所有数据输出。简而言之,它是一个`deliver(seqno, prevhash, blob)`事件序列,根据`prevhash`计算值构成了一个哈希链。 多数时候,为了效率考虑,并不输出单个的事务(blobs),而是由有序服务在一个deliver事件中,向很多区块批量输出一组blobs。在这种情况下,有序服务就必须在每一个区块中,强制传达blobs的一个确定顺序。一个区块输出blobs的数量,可以由有序服务的实现动态选择。 在余下内容中,为了讲解简单,我们定义有序服务的一些属性(即接下来的内容),并且解释一下交易背书的工作流(第2节),假定每一个`deliver`事件对应一个blob。这很容易扩展到blocks的情况,假定一个deliver事件一个块,相当于一组单独的deliver事件序列,每一个对应一个块中的一个blob,根据前面提到的确定性顺序,对一个块中得blobs进行排序。 #### Ordering服务属性【Ordering service properties】 ordering服务的保证(或原子性广播通道)明确规定了一则广播消息如何处理,以及传输的消息之间存在着怎样的关系。这些保证如下所示: 1. **安全(一致性保证)**:只要peers连接在channel上的时间足够长(它们可以断开连接,或者崩溃掉,但是还会重启并重新连接),它们可以看到一组完全相同的,发送过的消息`(seqno, prevhash, blob)`。这就意味着输出(`deliver()`事件)在所有的peers上都是相同的顺序,并遵从序列编号【sequence number】,以及对于相同的序列编号,都携带完全相同的内容(`blob`和`prevhash`)。注意这只是一个逻辑顺序【logical order】,并且在一个peer上的`deliver(seqno, prevhash, blob)`并不要求和其它peer上的相同消息的deliver输出产生任何实时的关系。换句话说【Put differently】,给定一个`seqno`,任何2个正确的peers,都会传输相同的`prevhash`和`blob`值。而且,除非一些客户端(peer)确实调用了`broadcast(blob)`,否则`blob`值就不会传输,理想情况下,每一个广播的blob都只会传输一次。 再者,`deliver()`事件包含了上一个`deliver()`事件数据的加密哈希(即`prevhash`)。当ordering服务实现原子广播保证时,`prevhash`指的就是`seqno-1`序列号的`deliver()`事件参数的加密哈希。这样就建立了一条哈希链,将所有`deliver()`事件串了起来,可以用来帮助确定ordering服务的输出完整性和诚实性,正如后面第4节和第5节讨论的那样,在第一个`deliver()`事件这种特殊情况下,`prevhash`有一个默认值。 2. **保活(传输性保证)**:ordering服务的保活保证由实际实现具体指定。在架构设计中没有具体要求。实际的保证可能依赖于网络,和节点故障模型。 原则上,如果提交客户端【submitting client】没有宕机,ordering服务应该保证每一个连入ordering服务的正确peer,最终都能传输每一笔提交的交易。