チェーンコードおよびチャネル全体でのアトミック更新の実行

原子性トランザクションを使用して、複数のチャネルおよびチェーンコードにわたる複数のトランザクションを原子的な方法で完了できます。

アトミック・トランザクションは、すべて成功するか、またはいずれも成功しない、分割できない一連のデータ操作です。

原子性トランザクションは、複数のチェーンコードが別々のチャネルにデプロイされる複雑な状況で役立ちます。原子性トランザクションを使用して、ネットワークまたはシステム障害が発生した場合でも、複数のブロックチェーン・トランザクションの実行中にデータの一貫性を維持できます。Oracle Blockchain Platformでは、2フェーズ・コミット・プロトコルを使用して原子性トランザクションがサポートされます。このプロトコルでは、各データ操作が準備される初期フェーズの後に、各データ操作が実際にコミットされるフェーズが続きます。

原子性トランザクションはアプリケーション・レベルで機能します。通常、原子性トランザクションをサポートするために、既存のチェーンコード・ロジックを変更する必要はありません。1つ以上の引数がアトミック・トランザクション・フレームワークによって追加されるため、既存のチェーンコードがチェーンコード・メソッドで渡された引数の数に対して厳密なチェックを実行しないことを確認してください。原子性トランザクションは、次のREST APIエンドポイントでサポートされています。
  • restproxy/api/v2/atomicTransactions
REST APIエンドポイントは、チェーンコードで定義されたとおりにトランザクションを準備し、組込みのチェーンコード関数を使用してすべてのトランザクションをコミットするか、準備フェーズ中にエラーが発生した場合はすべてのトランザクションをロールバックします。原子性トランザクションの実装に使用するRESTエンドポイントの詳細は、原子性トランザクションのRESTエンドポイントを参照してください。

各原子性トランザクションは、2つ以上のブロックチェーン・トランザクションで構成されます。原子性トランザクションの結果(returnCode値)は、SuccessまたはFailureです。原子性トランザクションでは、リクエストされた各ブロックチェーン・トランザクションは、準備フェーズとコミットまたはロールバック・フェーズの2つの異なる操作に分割されます。

  • 準備フェーズでは、各トランザクションは通常どおり承認されますが、最終決定されるのではなく、変更がステージングされ、他のトランザクションでステージングされた値が変更されないように値がロックされます。
  • ブロックチェーン・トランザクションごとに準備フェーズが成功した場合、トランザクションは組込みチェーンコードを使用して承認およびコミットされます。以前にロックされた値はロック解除され、アトミック・トランザクションの結果はSuccessです。
  • ブロックチェーン・トランザクションに対して準備フェーズが失敗した場合、準備フェーズが成功した他のすべてのトランザクションは、組込みチェーンコードを使用して再度ロールバックされます。ステージングされた変更は削除され、以前にロックされた値はロック解除されます。アトミック・トランザクションの結果はFailureです。
アトミック・トランザクションはキーをロックすることで機能するため、準備されている現在アクティブなアトミック・トランザクションによってロックされているキーを変更しようとすると、Two_Phase_Commit_Lockエラーが発生することがあります。これは、次の2つのシナリオのいずれかで発生する可能性があります。
  • アトミック・トランザクションはまだ準備フェーズにあり、準備されたトランザクションによってロックされたキーの変更が別のトランザクションによって試行されます。この場合、システムは設計どおりに動作します。このエラーが発生する場合は、2番目のトランザクションを再試行してください。これは、アプリケーションがファントム読取りエラーまたはマルチバージョン同時実行性制御(MVCC)エラーを処理する方法に似ています。
  • 原子性トランザクションによって返されるGlobalStatus値はHeuristicOutcomeです。この場合、コミット操作の1つが失敗したため、アトミック・トランザクション操作が取り消されました。これはまれに発生するため、手動で解決する必要がある場合があります。ヒューリスティックな結果の1つの副作用として、コミットまたはロールバックに失敗したトランザクションによって一部のキーがロックされたままになることがあります。この場合、次のREST APIエンドポイントを使用して、アトミック・トランザクションのロックを解除します。
    • restproxy/api/v2/atomicTransactions/{globalTransactionId}
    アトミック・トランザクションのロック解除に使用するRESTエンドポイントの詳細は、アトミック・トランザクションのロック解除を参照してください。

シナリオ: サンプルを使用した原子性トランザクションの確認

Oracle Blockchain Platformに含まれる2つのサンプル・チェーンコード(残高転送と大理石)を使用する次の例を考えてみます。Balance Transferサンプルは、勘定科目残高間で資金を転送できる2つのパーティを表します。Marblesサンプルを使用すると、大理石を作成し、所有者間で交換できます。残高転送チェーンコードで資金を交換し、Marblesチェーンコードで大理石の所有権を変更することで、個人(非原子性)トランザクションを使用して大理石を購入できます。ただし、これらのトランザクションのいずれかでエラーが発生した場合、元帳は一貫性のない状態のままになる可能性があります。つまり、資金は転送されたが大理石は転送されなかったか、大理石は転送されたが支払われなかったかのいずれかです。

このシナリオでは、原子性トランザクションをサポートするREST APIエンドポイントで既存のチェーンコードを使用できます。資金の交換と大理石の所有権の移転は、両方とも成功するか、両方とも失敗しなければなりません。いずれかのトランザクションでエラーが発生した場合、どちらのトランザクションもコミットされません。このシナリオを調べるには、次のステップを実行します。

  1. 残高転送および大理石のサンプルを異なるチャネルにインストールします。サンプルをインストールする方法の詳細は、「サンプルを使用したOracle Blockchain Platformの確認」を参照してください。
  2. Marblesサンプルで、Create a new marbleアクションを起動して、様々な大理石の所有者に多数の大理石を作成します。
  3. Invoke Atomic Transaction RESTエンドポイントを使用して、MarblesサンプルとBalance Transferサンプルの両方を起動する原子性トランザクションを完了します。

たとえば、次のトランザクションでは、marble1という大理石がTomに転送され、アカウントaからアカウントbに50コインが送信されます。

{
 "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
}

前のトランザクションで、両方のトランザクションが準備フェーズで成功した場合は、両方のトランザクションが元帳にコミットされます。いずれかのトランザクションでエラーが発生した場合、2番目のフェーズではトランザクションはコミットされません。かわりに、両方のトランザクションがロールバックされます。たとえば、アカウントaにコインが50未満の場合、そのアカウントからお金は取られず、大理石はTomに転送されません。