blockchainjapan’s blog

旬のブロックチェーンを記事を厳選して提供!

Aggregators:Aptosでシーケンシャルなワークロードが並列実行される仕組み


Aggregators:Aptosでシーケンシャルなワークロードが並列実行される仕組み

Aptos Labs

Aptosの各コンテンツや、学習材料へはこちらからアクセスできます!

By George Mitenkov, Satya Vusirikala, Igor Kabiljo, Alexander Spiegelman, Rati Gelashvili

要約:Aptos Labsでは、Aptosブロックチェーン上で読み書きの競合があってもスマートコントラクトを並列実行できる新しいMove機能「アグリゲーター」を設計しました。Aptosネットワークは、メインネットの立ち上げ以来、アグリゲーターを使ってネイティブトークンの総供給量を追跡しています。供給量は各トランザクションで変更されますが、アグリゲーターのおかげで並列性に影響はありません。最近のAIP-43では、限定供給のデジタル資産コレクション(例えばNFT)にアグリゲーターを使用することも可能で、ミントの速度を劇的に向上させます。最新のプレビューネットでは、アグリゲーターを活用して90秒以内に100万個のNFTをAptos上でミントすることが実証されました。

並列実行の背景

Aptosを動力とする並列実行エンジンBlock-STMは、楽観的並行処理と多バージョンデータ構造に基づいており、トランザクションを並列に推測実行します。推測実行が誤っている場合、Block-STMはそれを検出し、トランザクションを中止して後で再実行します。

並列エンジンの性能は、ワークロードに大きく依存します。特に、読み書きの競合の量が重要です。例えば、アリスからボブへの送金に続いてキャロルからデビッドへの送金という2つの順序付けられたトランザクションを考えてみましょう。これら2つのトランザクションは交換可能であり、それぞれの読み書きセットが互いに排他的であるため、並列実行が可能です。

一方、アリスからボブへの送金に続いてボブからキャロルへの送金という別のトランザクションペアを考えてみましょう。Block-STMは2番目の送金を推測的に最初に実行し、その後、先行するトランザクション(アリスからボブへの送金)との競合を検出する可能性があります。これは、2番目のトランザクションがボブの残高を読み取り、最初のトランザクションがまだそれを更新していないためです。結果として、ボブからキャロルへのトークンの送金トランザクションは中止され、アリスからボブへの送金が完了した後に再実行されます。

シーケンシャル・ワークロード

多くの読み書きの競合を伴う競合ワークロードは、効率的に並列実行することができません。シーケンシャル(順次)ワークロードは、すべてのトランザクションが互いに競合する極端なケースです。この場合、トランザクションの順次実行が本質的に最良のアプローチです。残念ながら、ワークロードが順次である可能性がある複数のブロックチェーンユースケースがあります。

供給と残高カウンター

多くのブロックチェーンは、トランザクション手数料の一部をバーンします。その結果、すべてのトランザクションはネイティブトークンの総供給量を暗黙的に更新し、すべてのトランザクションが競合することになります。

このように、単純なピアツーピアの非競合の送金でさえ、供給カウンターの読み書きの競合によって順次ワークロードになります。これは一般的な問題であり、いくつかのブロックチェーンは、並列性を可能にするために、ネイティブ通貨の総供給量をスマートコントラクトで追跡するのをやめ、代わりにプロトコルの実装(例えば、アトミックカウンターを使用する)で供給量を追跡しています。

非代替性トークン(NFT)などのデジタル資産コレクションの場合、通常、コレクションのサイズも追跡されます。例えば、これらのコレクションは音楽フェスティバルのチケットとして使用される場合があります。チケットには限られた数があるため、存在するNFTの数も限られています。

ネイティブトークンの総供給量を追跡するのと同様に、NFTコレクションのサイズは、トークンをミントまたはバーンするすべてのトランザクションによって更新する必要があります。さらに、ミントされたNFTの数が、その創作者によって固定されたコレクションのサイズを超えないことが重要です。

これらの制約の下では、NFTは順次にしかミントできず、ネットワークのスループットが大幅に低下します。私たちの知る限り、多くのブロックチェーンは大量のNFTを迅速にミントするのに苦労しており、数時間かかることもあります。

最終的には、トランザクションごとに実行手数料を支払う必要があるため、アカウント残高も読み書きの競合の原因の一つです。手数料はアカウント残高から差し引かれるため、同じ手数料支払い者の全てのトランザクションは互いに競合します。これは、ゲームのようなアプリケーションに重要な、一つのアカウントが一連のトランザクションを送るという単一送信者の並列処理を妨げます。

不換通貨トークン(NFT)の索引付けと命名 NFTは通常、発行された順に連続的に索引付けされます。また、索引を含む名前を持つこともあります。例えば、「Star #17」のようにです。この方法では、NFTコレクションがそのサイズを追跡しないため、読み書きの競合を避けても、索引付けが別の連続的なボトルネックとなるため、トークンは並列に発行できません。

Aptosの魔法

上記の問題に対処するため、Aptos Labsのエンジニアは、AIP-47でAggregatorsと呼ばれるMove機能を提案しました。これにより、アプトスネットワークは、本来は連続する作業負荷を並列で実行できます。

観察

連続して見える作業負荷は、多くの読み書きの競合を持たず、これらの競合はトランザクション実行の結果に大きな影響を与えません。競合は、ブロックチェーン状態からの読み取りを遅延させ、書き込みを状態に戻すことで避けることができます。

トランザクションの競合する部分は捉えられ、その実行結果は推測的に予測することができます。その結果、トランザクションの主要部分は完全に並列で実行できます。いくつかの例があります。

読み取りを延期することによる並列集約 カウンター(例えば、ネイティブトークンの供給量やNFTコレクションのサイズ)を更新する代わりに、Block-STMによって使用される多バージョンデータ構造を活用して、この更新をまだ適用せずに記録することができます。

例えば、ブロックチェーン状態に保存されたカウンターを更新する一連のトランザクションを考えてみてください。ここで、最初のトランザクションは10を減らし、記録された更新は-10です。次のトランザクションは20を加えて17を引きます。カウンター値を読み、新しい値を書き込む代わりに、二つの更新:+20と-17を記録し、このトランザクションによる合計更新は+3です。同様に、三番目と四番目のトランザクションはそれぞれ-10と-20の更新があります。

これらのトランザクションに他の読み書きの競合がなければ、それらは並列に実行され、最終的に任意の順序でカウンターへの更新が適用されます。例えば、カウンター値が最初に100だった場合、これら四つのトランザクションを実行した後、それは63になります。一般に、グローバルカウンターの更新による読み書きの競合は避けられ、作業負荷は完全に並列で実行できます。

連続実行は、競合が避けられない場合にのみ使用されます。例えば、カウンターが三番目のトランザクションによって読まれる場合、読み取りは、最初と二番目のトランザクションからのすべての先行する更新が事前に計算されることを強制し、並列性を制限します。

整数のオーバーフローとアンダーフローへの対処

グローバルカウンターへの更新はオーバーフローまたはアンダーフローを引き起こす可能性があります。例えば、以下の例では、二番目のトランザクションでカウンターがオーバーフローします。重要なのは、オーバーフローが正しく予測される限り、カウンターへの更新は並列で実行できるということです。そうでない場合、トランザクションはBlock-STMによって他の競合するトランザクションと同様に再実行されます。ここでの希望は、推測的予測が正しく、オーバーフローやアンダーフローが一般的ではないことです。

スナップショット — ブロックチェーン状態への競合のない書き込み

グローバルカウンターへの更新が並列化されていても、NFTの発行問題はまだ解決されていません。NFTが発行されたときのインデックスとトークンの名前(インデックスも含むことができます)は、トークンがブロックチェーン状態に保存される前にカウンター値を読みます。

それにもかかわらず、これらの操作はブロックチェーン状態への書き込みを遅らせることで遅延することができます。トークンのインデックスをすぐに状態に保存する代わりに、「スナップショット」として現在のインデックス値を取得し、後で保存することができます。例えば、トランザクションがコミットされたときです。基本的に、スナップショットはグローバルカウンター変数への現在の部分的な更新を保存します。

このアプローチは、トークンのインデックスに依存する場合、NFTの命名に簡単に一般化することができます。この場合、各トランザクションにおいて、スナップショットされたインデックス変数の文字列への変換は遅延されます。文字列名は後でグローバル状態に計算され保存されます。

AptosのAggregators

Aptos Labsでは、aptos-frameworkの下にある一般ライブラリを開発しました。このライブラリは、開発者が並列でトランザクションを実行する際の連続的なボトルネックを避けるために使用できるAggregators(集計器)を定義しています。これは、トークンコレクションのサイズ追跡などに利用できます。

Aggregatorsは整数を包むラッパーで、初期値0で作成できます。Aggregatorを作成する際には、ユーザーがカスタムリミットを指定できます。これはAggregatorが格納できる最大値です。符号なし整数のAggregatorsを考慮しているため、Aggregatorが持つことができる最小値は0です。

// Type parameter allows one to support different integer bit widths,
// e.g., u64 or u128.
struct Aggregator<IntTy> has store {
value: IntTy,
max_value: IntTy,
}
let counter = aggregator::create(/*max_value=*/100);

Aggregatorsは、通常の整数と同様に、try_addやtry_subと呼ばれる加算および減算メソッドを使用して(並列に!)更新できます。これらのメソッドは真偽値を返し、Aggregatorの値が変更されたかどうかを示します(オーバーフローがなければ結果はtrue、そうでなければfalseです)。

let success = aggregator::try_add(&mut counter, 20);
let success = aggregator::try_sub(&mut counter, 40);
if (success) {
// Counter has been modified.
} else {
// Error handling goes here.
};

Aggregatorsへの同時更新は、Block-STMによって使用されるマルチバージョンデータ構造が既に書き込み-書き込みの競合を排除しているため、トランザクション間での競合を引き起こしません。また、Aggregatorsの動作は連続実行と一致しており、連続的に実行されても並列に実行されても結果は同じです。

Aggregatorsは読み取りも可能です。読み取りはAggregatorに格納された値を返しますが、複数のトランザクション間の並列性を制限するため、可能であれば避けた方が良いです。

// This limits the parallelism of the system.
let value = aggregator::read(&counter);
struct AggregatorSnapshot<Ty> has store {
value: Ty,
}
// Snapshot captures the value of the counter.
// This does not affect the parallelism of the system.
let snapshot = aggregator::snapshot(&counter);
// Limits the parallelism of the system, but returns the actual
// value stored inside of a snapshot.
let value = aggregator::read_snapshot(&snapshot);

Aggregatorの値を読み取ることが必要な場合(例えば、NFTコレクションの索引付けや命名のために)、Aggregatorのスナップショットを取ることもできます。

Aggregatorスナップショットは、特定の時点でのAggregatorの値をキャプチャしますが、実際の値は開示しません。

let name = aggregator::concat("star #", &snapshot, "");

私たちは最新の(メインネットのような)プレビューネットで、NFTの発行に焦点を当ててAggregatorsを評価しました。使用したNFTコレクションには限定供給があり、連続的に名前が付けられていました。私たちは90秒で100万個のコレクションを、または8分で500万個のコレクションを高いスループットで発行することができました。これはAggregatorsなしでの実行と比べて性能が約10倍向上しました。

さらに、合成ベンチマークを使用してAggregatorsのパフォーマンスをテストしました。Aggregatorsを使用することで、Moveにおける無制限のグローバルカウンターの更新がほぼ9倍速くなることが観察されました。

Aggregatorsは、アプトスのコードベースでその開始以来、ネイティブトークンの総供給量を追跡するために使用されており、これはトランザクション手数料のバーンがシステムの並列性に影響を与えないことを意味します。総供給量はすべてのトランザクションによって更新されますが、作業負荷は並列で実行できます。

AIP-47は、Aggregatorsおよびスナップショットのための新しい、より強力なAPIを提案し、それらを一般に公開しています。AIP-43により、Aggregatorsはフレームワークにもデプロイされることができます。この機能により、アプトス上のデジタルアセットコレクションは、そのサイズが追跡されていても、並列に発行およびバーンすることができます。また、コレクションはインデックス付けされ、整形された名前を持つことができます。これらのAIPが受け入れられれば、デジタルアセットの操作は並列化され、2024年第1四半期にメインネットで有効化されることになります。

次の投稿では、Aggregatorsがどのように実装され、Block-STM内のトランザクション間の競合数を減らし、より多くのスレッドでスケールするかについて、すべての答えを見つけることができます。

次回をお楽しみに!


Aptos LabsはMo ShaikhとAvery Chingによって共同設立され、分散化のメリットを世界にもたらすために、より優れたネットワークツーリングとシームレスなユーザビリティの実現に取り組んでいます。

Aptosの各コンテンツや、学習材料へはこちらからアクセスできます!

今後もウェビナーや新しいコンテンツを、技術者および非技術者向けに日本語で提供していきます。Aptos Japanの活動にご協力ください🤝