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

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

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

アトミック・トランザクションは、複数のチェーンコードが別々のチャネルにデプロイされる複雑な状況で役立ちます。アトミック・トランザクションを使用すると、複数のブロックチェーン・トランザクションの実行中にネットワークやシステムに障害が発生した場合でも、データの一貫性を維持できます。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とMarbles)を使用する次の例を考えてみます。Balance Transferサンプルは、アカウント残高間で資金を転送できる2つの当事者を表します。Marblesサンプルでは、marbleを作成し、所有者間で交換できます。Balance Transferチェーンコードで資金を交換し、Marblesチェーンコードでmarbleの所有権を変更することで、個々の(アトミックでない)トランザクションを使用してmarbleを購入できます。ただし、これらのトランザクションのいずれかでエラーが発生した場合、台帳は一貫性のない状態(資金は転送されたがmarbleは転送されなかった、またはmarbleは転送されたが支払われなかった)のままになる可能性があります。

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

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

たとえば、次のトランザクションでは、marble1というmarbleが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未満の場合、そのアカウントからお金は取られず、marbleはTomに転送されません。