以下はIOGブログに掲載された記事「Architecting DApps on the EUTXO ledger」を翻訳したものです。
EUTXO台帳上のDAppsを構築する
カルダノ上でのDAPアーキテクチャの方法を詳しく見てみる
BY Jean-Frédéric 2021年11月16日
カルダノのパフォーマンスと元帳の最適化ロードマップに関する最近のブログ記事に続き、EUTXO元帳のアーキテクチャについてより深く技術的な検討を行いました。
ここでは、アーキテクチャの例を示すとともに、トランザクションのスループットを向上させ、トランザクション処理の遅延を最小限に抑えるために可能な改善点について説明します。
カルダノのEUTXOモデルは、アカウントベースのモデルと比較してより高いスケーラビリティを可能にする並列トランザクション処理を容易にし、強化されたセキュリティ設定を提供するため、分散型金融(DeFi)や分散型アプリケーション(DApp)開発の強固な基盤となっている。
しかし、EUTXOモデルではなくアカウントベースのシステムに適用される設計や仕組みを使用すると(特に分散型取引所を構築する場合)、コンテンション問題が発生する可能性があります。この結果、新しいトランザクションが前のトランザクションの出力に依存することになり、特にトランザクションの数が多い場合には遅延が発生します。この問題を解決するためには、開発者はシングルスレッドのステートマシンの使用を避け、EUTXOの特性を考慮してアプリケーションを設計する必要があります。
整ったアーキテクチャとはどのようなものか?
オーダーブック・パターンは、スマートコントラクト・ロジックと互換性があれば、DEX開発に適用可能なアプローチの1つです。SundaeSwapのブログ記事で評価・紹介されているプロトコルアーキテクチャの多くは、以下のような一般的なアプローチに依存しています。
- ユーザーは、中間スクリプト(リクエスト・スクリプトと呼ぶ)に、提出された注文の説明(トークンやデータなど)とともに資金をロックします。
- 第三者(バッチャーと呼びます)が、リクエスト・スクリプトにある注文を1つの取引に集約し、以下のようにします。
- ロックされた注文は、メイン・スクリプト(例:流動性プール)のグローバルな状態を保持するUTXOとともに使用され、更新されます。
- 実行された注文の結果が元のユーザーに返信される。
- 更新されたグローバル状態を保持する新しいUTXOが、メイン・スクリプトのアドレスに存在する。
このようなバッチ・パターンを採用する場合、リクエスト・スクリプトにあるN個の注文が1つのトランザクション内で消費されるたびに、トランザクションの送信時にリクエスト・スクリプトがN回実行されることに留意する必要があります。さらに、(トランザクションの送信時にトリガされる)メモリ制限のチェックは、各単一のリクエストスクリプトの実行、メインスクリプトの実行、および(プロトコル設計に従って)実行される可能性のある MintingPolicy スクリプトのメモリ消費量を集約することによって実現されます。さらに、消費された注文数に比例した同じトランザクションコンテキストが、各スクリプト実行の引数として渡されます。
これは良いアプローチではありますが、さらに良くするための改善点が考えられます。
N回のリクエスト・スクリプトの実行(つまり、集約されたトランザクション内での実行)のトリガーを避けるための潜在的な解決策の一つは、ユーザーが代わりに自分の公開鍵アドレスに直接注文を送信することです。リクエスト・スクリプトは、保留中の注文の存在を通知するためと、注文が処理された後にバッチャーが請求できる取引手数料をロックするためにのみ使用されます。このソリューションでは、ユーザーは、注文の支出を承認するために、集約されたトランザクションに署名する必要があります。また、このような場合、バッチ内のすべてのユーザーがオンラインで参加しなければならないことにも注意が必要です。このようなソリューションの簡略化されたアーキテクチャは、以下のように要約されます。
注文の送信
- 特定のMintingPolicyスクリプトを使用して、ユーザーの公開鍵アドレスに送信された「注文」トークンを鋳造することができます。
- ユーザーの公開鍵アドレスのハッシュは、注文内容と必要な取引手数料とともに、注文通知用のリクエストスクリプトに送信することができます。
注文処理
- バッチャーは、リクエストスクリプトのアドレスにあるUTXOを検査して、「オーダー」トークンを集め、集約された トランザクションを構築する。対応する公開鍵アドレスに「オーダー」トークンが存在しない場合、そのオーダーは無効とみなされることに注意。
- リクエスト・スクリプトにあるUTXOは、集約されたトランザクションで消費されない。これらは、「注文」トークンを保持するUTXOを集めるためにのみ使用される。
- バッチャーは、集約されたトランザクションを送信するために署名するよう、関連するユー ザーに通知する。
- メイン スクリプトにバインドされた MintingPolicy は、処理された各注文に対して「領収書」トー クンを生成するために使用される。この「領収書」トークンは、リクエスト スクリプトでロックされたトランザクション料金を請求するために、バッチャーによって使用されます。
トランザクションフィーの回収
- バッチャーは、対応する「レシート」トークンを提供することで、リクエストスクリプトにある各UTXOを消費することができます。
公開されているテストネットで行われたベンチマークによると、このシンプルなアーキテクチャでは、1つのトランザクション内で約25~30件の注文を、1,000万ユニットのメモリ制限を超えることなく簡単に処理できることがわかりました。この数字を増やすためには、さらにいくつかの最適化を行うことができると考えています。
また、開発者はこのアーキテクチャを拡張して、決定性のある注文の保証、特定の時間内でのユーザーによる注文のキャンセル、悪意のあるバッチャーに対する追加の保護など、より高度なメカニズムを検討することができます。
これは、DAppの設計において、EUTXOに特化したアプローチをとることができる一例です。私たちは現在、ドキュメントを拡張している最中で、他の例も順次公開していく予定です。現時点では、マルチシグネチャを使用して同時実行を回避するためのいくつかのコードサンプルをご覧いただけます。
また、開発コミュニティがさらに多くのモデルを見つけてくれることを期待しています。これらのモデルをリポジトリに追加して、今後数ヶ月の間にPlutus開発コミュニティのためのリソースを構築していきたいと思います。
このブログ記事の作成にあたり、John Woods氏をはじめとするチームの皆様のご意見とご協力に感謝いたします。