Hyperledger Fabric Read-Write set semantics——读写集

Read-Write set semantics(读写集函数

本文讨论了关于读写集当前实现的细节。区块链

 

Transaction simulation and read-write set(事务模拟和读写集spa

客户端提交事务到peer,peer会执行背书验证并模拟该事务的请求结果,为该事务的请求准备一个读写集。读集包含了该事务在读取本地帐本时的一列事务版本信息及该信息对应的的一列惟一键,写集包含了一个惟一键(可能也容许与读集中的键重复)列表和事务写入的最新值。若是事务的执行是删除操做,那么将为这一列惟一键设置一个delete标记(在新值的位置)。设计

此外,若是事务为键屡次写入一个值,则只保留最后一个写入值。另外,即便在事务读取结果发出以前更新了键值,也会返回事务读取已提交状态的值。换句话说,必须保证读写一致性。版本控制

正如上面提到的,键的版本只在读取集中记录,而写集仅包含由事务设置的一列唯一键和它们的最新值。code

能够有各类各样的执行版本的方案。版本控制方案的最低要求是为给定的键生成不重复的标识符。例如,使用单调递增的版本能够采用一个这样的方案。在当前的实现中,咱们使用一个基于区块链顶点的版本控制方案,在这个方案中,提交事务的顶点被用做事务修改后的全部键的最新版本,事务的顶点由一个元组表示(txNumber是该块内事务的顶点)。该方案与增量编号方案相比有许多优势—主要是它支持其余组件,如statedb、事务模拟和验证,以实现有效的设计选择。blog

下面是模拟假想事务的一个示例读写集的例子。为了简单起见,咱们使用增量数字表示版本。排序

<TxReadWriteSet>
  <NsReadWriteSet name="chaincode1">
    <read-set>
      <read key="K1", version="1">
      <read key="K2", version="1">
    </read-set>
    <write-set>
      <write key="K1", value="V1">
      <write key="K3", value="V2">
      <write key="K4", isDelete="true">
    </write-set>
  </NsReadWriteSet>
<TxReadWriteSet>

 

此外,若是事务在模拟期间执行范围查询,那么范围查询及其结果将被添加到读写集做为查询信息。事务

 

Transaction validation and updating world state using read-write set(使用读-写集进行事务验证和更新世界状态)

提交者使用读-写集的读集部分来检查事务的有效性,并使用读写集的写集部分更新受影响的键的版本和值。it

在验证阶段,若是在事务读集中每个key的版本都可以与world state(假定以前全部的事务都是有效的,包括以前在同一区块中的已经被提交的事务)中的key版本一致,那么该条事务则被认为是有效的。若是读写集还包含一个或多个查询信息,则须要执行额外的验证。

这些额外的验证须要确保在本次事务查询信息返回结果的范围内的key没有被插入/删除/更新过,换句话说,若是咱们在对提交状态的验证过程当中从新执行任何一个范围查询(在模拟期间执行的事务),那么它应该会产生与在模拟时所观察到的结果相同的结果。此检查确保若是事务在提交期间观察到虚项,则该事务应被标记为无效。注意,这个虚项保护仅限于范围查询(例如:在chaincode中的GetStateByRange函数)而且尚未为其余查询(例如:在chaincode中的GetQueryResult函数)实现。其余查询有可能出现虚项,所以只能在没有提交到排序的只读事务中使用,除非应用程序可以保证模拟和验证/提交时间之间的结果集的稳定性。

若是一个事务经过了有效性检查,提交者将使用写集来更新世界状态。在更新阶段,对于写集中的每一个键,相同键的值都设置为在写集中指定的值,进一步地,这个世界状态的键的版本会被改变,以反映最新的版本。

 

Example simulation and validation(模拟和验证案例)

本节经过一个示例场景帮助理解语义。对于本例的目的,在世界状态中,键k的存在是由元组(k、ver、val)表示的,其中,ver是键k的最新版本,它的值由val表示。

如今,考虑一组5个事务,T一、T二、T三、T4和T5,它们都在同一个快照上模拟世界状态。下面的代码片断显示了对事务进行模拟的世界状态的快照,以及由这些事务执行的读取和写入活动的顺序。

World state: (k1,1,v1), (k2,1,v2), (k3,1,v3), (k4,1,v4), (k5,1,v5)
T1 -> Write(k1, v1'), Write(k2, v2')
T2 -> Read(k1), Write(k3, v3')
T3 -> Write(k2, v2'')
T4 -> Write(k2, v2'''), read(k2)
T5 -> Write(k6, v6'), read(k5)

如今,假设这些事务是在T1的序列中排序的。T5(能够包含在一个区块或不一样的区块中)

  1. T1经过验证,由于它不执行任何读取操做。此外,世界状态中的键k1和k2的元组被更新为(k1,2,v1')和(k2,2,v2')
  2. T2失败了,由于它读取了一个键k1,它被以前的事务修改成T1
  3. T3经过验证,由于它不执行读操做。进一步的,在这个世界状态下的键的元组被更新到(k2,3,v2'')
  4. T4失败了,由于它读取了一个键k2,它被以前的事务T1修改过
  5. T5经过验证,由于它读取了一个键k5,它没有被前面的任何事务修改过

 

注意:目前还不支持具备多个读写集的事务。

相关文章
相关标签/搜索