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

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

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

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

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

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

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

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

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

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

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

例如,以下事务处理将名为 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。