跨链代码和渠道进行原子更新

您可以使用原子事务处理以原子方式完成跨渠道和链代码的多个事务处理。

原子事务处理是一系列不可分割的数据操作,这些操作要么都成功,要么都不成功。

在将多个链代码部署到单独通道的复杂情况下,原子事务处理非常有用。您可以使用原子事务处理在运行多个区块链事务处理时保持数据一致性,即使发生网络或系统故障也是如此。Oracle Blockchain Platform 使用两阶段提交协议支持原子事务处理,在两阶段提交协议中,准备每个数据操作的初始阶段后,每个数据操作实际提交一个阶段。

原子事务处理在应用程序级别起作用。通常,您不需要更改现有的链代码逻辑来支持原子事务处理。由于原子事务处理框架添加了一个或多个附加参数,因此请确保任何现有的链代码不对链代码方法中传递的参数数量执行严格检查。以下 REST API 端点支持原子事务处理:
  • restproxy/api/v2/atomicTransactions
REST API 端点可根据您的链代码定义准备事务处理,然后使用内置链代码功能来提交所有事务处理,或者在准备阶段出现任何错误时回滚所有事务处理。有关用于实施原子事务处理的 REST 端点的更多信息,请参阅原子事务处理 REST 端点

每个原子事务由两个或多个区块链事务组成。原子事务处理的结果(returnCode 值)为 SuccessFailure。在原子事务中,每个请求的区块链事务被分成两个不同的操作:准备阶段,然后是提交阶段或回退阶段。

  • 在准备阶段,每个事务处理按常规方式进行背书,但不会最终确定,而是暂存更改并锁定值,以防止其他事务处理修改暂存值。
  • 如果每个区块链事务处理的准备阶段成功,则使用内置链代码对事务处理进行背书和提交。以前锁定的值已解锁,原子事务处理的结果为 Success
  • 如果任何区块链事务处理的准备阶段失败,则准备阶段成功的所有其他事务处理将通过使用内置链代码再次回滚。暂存的更改将被删除,以前锁定的值将被取消锁定。原子事务处理的结果为 Failure
由于原子事务通过锁定密钥来工作,因此,如果不同的事务尝试修改已准备好的当前活动原子事务锁定的密钥,则可能会收到 Two_Phase_Commit_Lock 错误。这可能发生在以下两种情况之一:
  • 原子事务处理仍处于准备阶段,另一个事务处理尝试修改已准备事务处理锁定的密钥。在这种情况下,系统按设计工作。如果遇到此错误,请重试第二个事务处理。这类似于应用程序如何处理虚拟读数错误或多版本并发控制 (multi-version concurrency control,MVCC) 错误。
  • 原子事务处理返回的 GlobalStatus 值为 HeuristicOutcome。在这种情况下,由于其中一个提交操作失败,已取消原子事务处理操作。这是罕见的事件,可能需要手动解决。启发式结果的一个副作用是,某些密钥可能被无法提交或回退的事务处理锁定。在这种情况下,请使用以下 REST API 端点解锁原子事务处理:
    • restproxy/api/v2/atomicTransactions/{globalTransactionId}
    有关用于解锁原子事务处理的 REST 端点的更多信息,请参见 Unlock Atomic Transaction

方案:使用示例浏览原子事务处理

请考虑以下示例,该示例使用 Oracle Blockchain Platform 中包括的两个示例链代码:Balance Transfer 和 Marbles。“余额转移”示例表示能够在账户余额之间转移资金的两个交易方。大理石样本允许您创建大理石并在所有者之间交换它们。您可以使用个人(非原子)交易购买大理石,方法是在余额转移链代码中交换资金,并在大理石链代码中更改大理石的所有权。但是,如果其中一个事务处理出现错误,则分类账可能处于不一致的状态:资金已转移但未转移大理石,或者大理石已转移但未支付。

在此方案中,您可以将现有链代码与支持原子事务处理的 REST API 端点结合使用。资金的交换和大理石的所有权的转移必须成功或两者都失败。如果任一事务处理遇到错误,则不会提交任何事务处理。要浏览此方案,请完成以下步骤:

  1. 在不同渠道上安装余额转移和大理石样品。有关安装示例的详细信息,请参阅了解 Oracle Blockchain Platform Using Samples
  2. 在 Marbles 示例中,调用 Create a new marble 操作为各种大理石所有者创建多个大理石。
  3. 使用 Invoke Atomic Transaction REST 端点可完成同时调用大理石和余额转移抽样的原子事务处理。

例如,以下事务处理将名为 marble1 的大理石传输给 Tom,并将 50 个硬币从帐户 a 发送到帐户 b

{
 "transactions": [
   {"chaincode":"obcs-marbles","args":["transferMarble", "marble1", "tom"],"timeout":0, "channel":"goods"},
   {"chaincode":"obcs-example02","args":["invoke", "a", "b", "50"],"timeout":0, "channel":"wallet"}
 ],
 "isolationLevel": "serializable",
 "prepareTimeout": 10000,
 "sync": true
}

在上一个事务处理中,如果两个事务处理在准备阶段成功,则两个事务处理都提交到分类账。如果任一事务处理出错,则在第二阶段都不会提交任何事务处理。而是回退两个事务处理。例如,如果帐户 a 中的硬币少于 50 个,则不会从帐户中扣除任何钱,也不会将大理石转移到 Tom。

大理石样本和大理石所有者字段的默认值存在已知问题。有关详细信息,请参阅:Oracle Blockchain Platform 的已知问题