メインコンテンツまでスキップ

トランザクション管理

このガイドは、Aptosブロックチェーン上で拡張出来るトランザクション管理ハーネスの構築方法について解説します。

背景

Aptosでは、トランザクションとアカウントベースのシーケンスNo.を提供する署名か承認のエンティティーの観点からトランザクションはアカウントにマッピングされます。Aptosネットワークが新しいトランザクションを受信すると、以下に関したいくつかのルールへ従います。

  • アカウントから送信されたトランザクションは、アカウントによって適切に承認される必要が有ります。
  • 最新の台帳更新が定義する現在時刻は、トランザクションの期限タイムスタンプより前である必要が有ります。
  • トランザクションのシーケンス番号は、アカウントのオンチェーンのシーケンスNo.以上である必要が有ります。

最初のノードがトランザクションを受け入れると、そのトランザクションは追加のルールによってそのシステムを通過します。トランザクションシーケンスNo.が現在のオンチェーンシーケンスNo.よりも大きい場合、パスの全てのノードがオンチェーン状態と現在のシーケンスNo.間のシーケンスNo.でトランザクションを確認出来ている場合のみ、合意方向へ進行出来ます。

例 :

アリスは現在のオンチェーンシーケンスNo.が5のアカウントを所有しています。

アリスはボブのノードへシーケンスNo.6のトランザクションを提出します。

ノードを受け入れるボブはトランザクションを受け入れますが、ボブは5を見ていないためそれを進行しません。

進行させるためには、アリスがボブへトランザクションNo.5を送信するか、5がコミットされた事の合意をボブが知らされる必要があ有ります。後者ではアリスは他のノードを介してトランザクションを送信しました。

これ以外で2つの原則が残っています。

  • 単一アカウントはブロックチェーンへ送信されるコミットされていないトランザクションを最大100保持出来ます。それ以上の場合はトランザクションは拒否されます。これはアリスが最初の100をノードボブへ送信し、次の100をノードキャロルへ送信した場合、黙って起こる可能性が有ります。それら両方のノードが共通の流れを共有するなら、その流れはボブ経由で送信したアリスの100を受け入れますが、キャロル経由で送信したアリスの100は黙って拒否されます。
  • 複数のノードへの異なるトランザクションの送信は結果として、先行する全てのトランザクションがコミットされた事を”送信された”が知るまで、トランザクションが送信したノードから進行しないゆっくりとした解決となります。例えば、アリスがボブ経由で最初の50を送信し、次にキャロル経由で50を送信する場合。

トランザクションマネージャーの構築

トランザクションのニュアンスを理解したので、堅牢なトランザクション マネージャーの構築について深堀りしましょう。これは以下のコアコンポーネントで構成されます。

  • シーケンスNo.ジェネレーターは単一アカウントが使用可能なシーケンスNo.を管理し割り当てます。
  • アプリケーションかユーザーからのペイロードを受け取り、シーケンスNo.ジェネレーターからのシーケンスNo.を受け取り、アカウントキーへアクセスして実行可能な署名済トランザクションへ3ピースを組み合わせるトランザクションマネージャー。これはトランザクションをブロックチェーンへプッシュする役割も有ります。
  • オンチェーンワーカー、リーダーハーネスは複数のアカウントが単一の共有アカウントの署名者を共有出来る様にします。

現在、このフレームワークは、ネットワークが実質的なキューを構築しない、遅延が殆ど無い送信が実行、コミットされたトランザクションだと仮定します。高い需要に対応するには以下のコンポーネントでこの作業を拡張する必要が有ります。

  • トランザクションが優先してブロックチェーンへコミットする様、base_gas_unit価格を最適化します。
  • トランザクション処理レートが期限タイマーを適切に設定される様処理します。
  • トランザクションの失敗の扱いは無視するか送信し直すかのどちらかです。

注意:アカウントはトランザクションマネージャーの単一インスタンスが管理する必要が有ります。でなければ、トランザクションマネージャーの各インスタンスはメモリ内の状態が古くなり、シーケンスNo.が重複する可能性があります。

実装

シーケンスNo.の管理

各トランザクションは以前送信されたトランザクションへの連続の個別のシーケンスNo.が必要です。これは以下のプロセスで提供出来ます。

  1. 起動時にアカウントの現在のシーケンスNo.を、ブロックチェーンでクエリします。
  2. 同時に100トランザクションまでサポートします。それはコミットされたかどうかの確認無しで100シーケンスNo.が分配する事が出来ます。
  3. 実行中のトランザクションが100ある場合は、ネットワークをクエリする事で実際のコミットされた状態を確認します。これは現在のシーケンスNo.を更新します。
  4. 実行中のトランザクションが100未満の場合はステップ2へ戻ります。
  5. それ以外の場合は、0.1秒間スリープし、現在のオンチェーンシーケンスNo.の再評価を続けます。
  6. 全てのトランザクションは有効期限が必要です。有効期限が過ぎた場合は、失敗したと見なしシーケンスNo.をリセットします。簡単なケースとしては最大のトランザクションNo.が実行中、失敗のみを監視し、それ以外の場合は他のサービスがこれを管理します。

並行して、送信された新しいトランザクションを監視します。最も早いトランザクションの有効期限が切れたら、そのトランザクションまで同期します。次のトランザクションでこのプロセスを繰り返します。

何かが失敗した場合は、全ての未解決のトランザクションがタイムアウトするまで待機し、アプリケーションに続行方法の決定を任せます。失敗したトランザクションを再生する等。未処理のトランザクションを待機する最善の方法は、元帳のタイムスタンプをクエリし、少なくとも最後のトランザクションの送信時刻から最大タイムアウトが経過していることを確認する事です。そこから、最後にコミットされたトランザクション以降の全てのトランザクションがコミットされているか、メモリプール内に長く存在しない事をメモリプールで検証します。これは、特定のアカウントのトランザクションのREST APIをクエリし、現在評価されているシーケンスNo.を指定して、制限を1へ設定することで実行できます。これらのチェックが完了すると、ローカルトランザクションNo.を再同期できます。

これらの失敗の処理手順は以下の事由から重要です。

  • メモリプールは期限切れのトランザクションを即座に削除しません。
  • 有効期限が切れている場合でも、新しいトランザクションが既存のトランザクションを上書きすることはできません。
  • コンセンサス、つまり元帳のタイムスタンプが有効期限を決定し、ローカルノードは、トランザクションの期限切れでガベージコレクションが発生した後にコミットされたタイムスタンプを確認した後にのみ有効期限が切れます。

トランザクションの管理

トランザクションが送信されると、さまざまな手順が実行されます。

  1. REST エンドポイントへの送信。
  2. 送信中のメモリプールでの実行前検証。
  3. 各上流ノードで実行前検証が行われるメモリプールからメモリプールへの送信。
  4. コンセンサス提案への組み込み。
  5. 実行前検証をもうひとつ。
  6. ストレージへのコミットと実行。 Execution and committing to storage.

考慮すべき潜在的な失敗のケースが数多くあります。

  • トランザクション送信時の失敗 (1と2):
    • 可視性: アプリケーションは、ネットワークが利用できないか、トランザクションが実行前の検証に失敗したというエラーを受け取ります。
    • エラーが可用性または重複したシーケンスNo.と関連している場合は、アクセスが可能となり、シーケンスNo.が再同期されるまで待ちます。
    • 実行前検証の失敗は現在対象外です。 重複するシーケンス番号に関連する失敗以外では、アカウントが無効なアカウントのキーを発行している可能性が高い、またはアカウントの発行でガス用の充分な資金が不足している可能性があります。
  • 提出から実行までの失敗(3、4、5)
    • 可視性: トランザクションの有効期限が切れるまで待つ事でのみわかります。
    • これらは、以前のトランザクションの実行時にアカウントが変更された際の他の実行前検証エラーと同じです。シーケンス番号が重複しているか、アカウントのガス用の資金が不足している可能性があります。
  • 実行中の失敗 (6):
    • 可視性: これらはブロックチェーンへコミットされます。
    • これらのエラーは、オンチェーン状態の問題の結果として発生します。これらは、新しい入札が実際には現在の入札より安い可能性があるオークションなど、アプリケーション固有である傾向があります。

ワーカーとアイデンティティー

上記のフレームワークを使用すると、1つのアカウントでブロックの先頭からブロックの最後まで100以上のトランザクションをプッシュできます。100のトランザクションが全て1つのブロック内で消費されると仮定すると、次の100スロットが利用可能となるまで少し時間がかかります。これは、ネットワークの遅延と複数段階のパイプラインによる物です。

ブロックチェーンを最大限に活用して大量のスループットを実現するには、単一のユーザーアカウントを使用するだけでは不充分です。代わりに、Aptosは、 共有アカウント(リソースアカウントとしても知られています)を通じて作業をプッシュする責任を共有できる ワーカーアカウントの概念をサポートしています。

このモデルでは、各従業員は共有アカウントのSignerCapにアクセスできるため、共有アカウントになりすましたり、共有アカウントのsignerを生成したりできます。signerを取得するとトランザクションは共有アカウントの署名者によってゲートされたロジックを実行できます。

実行可能であれば、別のモデルとしてsignerから許可を完全に切り離し、アプリケーション固有の機能を作成します。その後、この機能を各ワーカーへ付与し、共有インフラストラクチャ上で操作出来る様にします。

注意: トランザクションが読み込みもしくは書き込みで何か衝突が有る場合、共有のインフラ上の並列化は制限される可能性があります。これはブロックで複数のトランザクションが実行されるのを防ぎませんが、最大ブロックチェーンパフォーマンスへ影響を与える可能性が有ります。