Hyperledger Fabric 读写集语义

读写集语义

本文讨论了有关读写集语义的当前实现的细节。

Transaction模拟和读写集

在一个背书节点模拟transaction期间,为交易准备了一个读写集合。read set包含在模拟期间transaction读取的唯一键及其提交的版本的列表。write set包含唯一键的列表(尽管可能与读集中存在的键重叠)以及transaction写入的新值。如果transaction执行的更新是删除key,那么设置key的删除标记(代替新值)。

此外,如果transaction为key多次写入值,则只保留最后写入的值。另外,如果一个transaction为一个key读取一个值,即使transaction在发出读取之前更新了key的值,也会返回提交状态中的值。换句话说,不支持Read-your-writing语义。

如前所述,键的版本仅在读集中记录; 写入集只包含唯一键的列表及其由transaction设置的最新值。

可能有各种实现版本的方案。版本控制方案的最低要求是为给定的key生成不重复的标识符。例如,对于版本使用单调增加的数字可以是一种这样的方案。在当前的实现中,我们使用基于区块链高度的版本控制方案,其中提交transaction的高度被用作所有由transaction修改的key的最新版本。在该方案中,transaction的高度由tuple表示(txNumber是块内事务的高度)。该方案比增量数量方案具有许多优点 - 主要是它可以实现其他组件,如说明,交易模拟和验证,以进行有效的设计选择。

以下是通过模拟假设交易准备的示例读写集的说明。为了简单起见,在插图中,我们使用增量数字来表示版本。

< 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 = “truewrite - set > 
   
< TxReadWriteSet >,isDelete = “truewrite - set >  < TxReadWriteSet >,isDelete = “truewrite - set >  < TxReadWriteSet >

此外,如果transaction在模拟期间执行range query,则range query及其结果将被添加到读写集合中作为query-info

使用读写集合进行transaction验证和更新世界状态

一个committer使用读写集合的读取部分来检查transaction的有效性,用写集部分来更新相应键的版本和值。

在验证阶段,如果读集中的每个key版本和世界状态中该key的版本相同,那么就认为这个transaction是valid - 假设所有之前的validtransaction(包括同一块中的之前的transaction)被提交了(committed-state)。如果读写集合还包含一个或多个查询信息(query-info),则执行另外的验证。

附加验证应确保在query-info中没有key要被插入/删除/更新。换句话说,如果我们在对提交状态进行验证时重新执行任何range queries(在模拟期间执行的transaction),则应该和模拟期间执行的结果一样。此检查确保如果transaction在提交期间观察”phantom”项目,则该transaction应标记为无效。请注意,此phantom保护仅限于range query(即, GetStateByRange链码中的功能),还没有为其他查询(即,GetQueryResult链码中的功能)实现。其他查询有phantom的风险,因此只能用于只读的transaction,除非应用程序可以保证结果集在模拟、验证/提交期间是不变的。

如果transaction通过有效性检查,则committer使用写集更新世界状态。在更新阶段,对于写集中存在的每个键,将相同键的世界状态值设置为写集中指定的值。此外,世界状态的key版本已更改,以反映最新版本。

模拟和验证示例

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

现在考虑五个transactionT1, T2, T3, T4, and T5,全部模拟在世界状态的同一个快照上。以下代码段显示了模拟transaction的世界状态的快照,以及每个transaction执行的读取和写入活动的顺序。

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的顺序排列(可以包含在单个块或不同的块中)

  • T1通过验证,因为它不执行任何读取。此外,键k1k2世界状态的元组被更新为(k1,2,v1'), (k2,2,v2')
  • T2验证失败,因为它读取一个k1,这个键由前一个transactionT1修改。
  • T3通过验证,因为它不执行读取。此外,键k2,在世界状态更新到(k2,3,v2'')
  • T4验证失败,因为它读取k2,该键由先前transactionT1修改。
  • T5通过验证,因为它读取一个键k5,该键未被任何之前的transaction修改。

如果有转载请注明出处!

[英文原版]

Read-Write set semantics

你可能感兴趣的:(Hyperledger Fabric 读写集语义)