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

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

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

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

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

  1. 異なるチャネルに残高転送およびMarblesサンプルをインストールします。サンプルのインストールの詳細は、「サンプルを使用した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に転送されません。

MarblesサンプルおよびMarble Ownerフィールドのデフォルト値に既知の問題があります。詳細は、Oracle Blockchain Platformの既知の問題を参照してください。