rounded

執筆:Tia、Techub News

 

ブロックチェーンはその非中央集権的な設計によって効率を犠牲にしているため、実行速度の向上は常に解決すべき重要な問題の一つです。ブロックチェーンの「実行層」は、各取引を処理し、それをチェーンに追加する重要な部分です。処理能力を加速するために、実行層の向上が核心戦略の一つとなり、並行実行がその重要な突破口です。

 

伝統的なブロックチェーンは通常、逐次方式で取引を一つずつ処理します。これにより、取引速度は大きく制限され、特に取引が集中しているネットワークでは混雑を引き起こすことがあります。しかし、並行実行を通じて、複数の取引を同時に処理することができ、実行効率を大幅に向上させ、チェーン上の負荷を軽減します。

 

並行処理とは何かをよりよく理解するために、まず実行の開始について説明し、その後、マージ後のPBSモデル下のイーサリアムを例にして実行とは何かを説明し、実行が取引の全ライフサイクルにおいてどの位置にあるかを示します。

 

取引実行の具体的な段階

 

  1. 取引はメモリプールに入り、フィルタリングとソートが行われます:これは取引が提出された後の前処理段階であり、Mempool、Searcher、およびBuilderの相互作用を含み、取引のフィルタリングとソートを完了します。

 

  1. Builderがブロックを構築(ただし実行はしない):Builderは利益のある取引を並べてブロックを構築し、取引のパッキングとソートを完了します。

 

  1. 提案者がブロックを検証し、提出します:ブロックが構築された後、Builderはブロックの提案をProposerに送信します。Proposerはブロックの構造と取引内容を検証し、正式にブロックをネットワークに提出して実行を開始します。

 

  1. 取引の実行:ブロックが提出された後、ノードはブロック内の取引を一つずつ実行します。これは状態更新の重要な段階であり、各取引はスマートコントラクトの呼び出し、アカウント残高の変化、または状態の変更を引き起こします。

 

  1. ウィットネスの証明:バリデーターはブロックの実行結果と状態ルートを証明し、最終確認として使用します。これにより、ブロックが実行層において真実であり、有効であることが保証され、不整合を防ぎます。

 

  1. 状態同期:各ノードはブロックの実行結果(アカウント残高、契約状態の更新など)を自分のローカル状態に同期します。各取引の後、ノードは新しい状態ルートを計算し、次のブロックで初期状態として使用します。

 

もちろん、これはブロック単位での取引の状態同期に過ぎません。最新のチェーン上の状態を保持するために、通常、ノードは逐次ブロック同期データを行い、ブロックと状態の検証を継続します。しかし、POSメカニズムにおける最終性を達成するためには、アグリゲーターが各Slot内のウィットネスの署名を集約して完全な署名を形成し、次のSlotの提案者に渡す必要があります。また、バリデーターはエポックを経て、投票数に基づいてそのエポック内のすべてのブロックの状態を確認し、一時的な合意状態のチェックポイントを形成する必要があります。連続して2つのエポックが大多数のバリデーターからの証人の支持を得た場合、ブロックと取引は最終性を達成します。

 

取引の全ライフサイクルを通じて、実行はProposerがBuilderから送信されたブロックの構造と取引内容を検証した後に発生します。実際の実行プロセスでは、取引を一つずつ処理し、対応するアカウントまたは契約の状態を更新する必要があります。すべての取引が実行を完了した後、Proposerは新しい状態ルート(メルクルルート)を計算します。これは現在のブロックのすべての取引の実行結果と最終的なグローバル状態の要約です。簡単に言えば、完全なブロック実行プロセスには、イーサリアムが前の状態から次の状態に変わるために完了する必要がある一連の計算が含まれ、各取引の実行からメルクルルートの計算までのプロセスが含まれます。

 

逐次実行

 

並行処理に対する相対的なものは逐次実行であり、これは現在のブロックチェーンで一般的な実行方式です。通常、取引は順番に逐次実行されます。一つの取引が実行を完了した後、イーサリアムはアカウントの状態や関連情報(例えば残高、契約ストレージデータ)をアカウント状態ツリーに更新し、新しいアカウント状態ハッシュが生成されます。すべてのアカウント状態ツリーが更新された後、状態メルクルルートと呼ばれる状態ツリーのルートノードハッシュが形成されます。状態メルクルルート、取引メルクルルート、及び領収書メルクルルートが完成した後、ブロックヘッダーはハッシュ計算を行い、そのブロックのブロックハッシュを生成します。

 

この中で、取引の実行順序は非常に重要です。メルクルツリーはハッシュ値の二分木であり、異なる順序で形成されたメルクルルート値は異なります。

 

並行実行

 

並行実行環境では、ノードはブロック内の取引を並行して処理しようとします。取引を順番に一つずつ実行するのではなく、取引を異なる「実行パス」に割り当てて同時に実行します。並行実行を通じて、システムはブロック内の取引をより効率的に処理し、スループットを向上させることができます。

 

すべての取引が実行を完了した後、ノードは実行結果(つまり取引によって影響を受けた状態の更新)を集約し、新しいブロック状態を形成します。この状態はブロックチェーンに追加され、チェーン上の最新のグローバル状態を表します。

 

状態衝突

 

並行処理では異なるパスで同時に取引を処理するため、並行処理の大きな難点は状態衝突です。つまり、複数の取引が同じ時間帯にブロックチェーン上の同じデータ部分(状態)に対して読み取りまたは書き込み操作を行う可能性があるということです。この状態を適切に処理しないと、実行結果が不確定になる場合があります。状態の更新順序が異なると、最終的な計算結果も異なります。例えば、

 

2つの取引、取引Aと取引Bがあり、両方が同じアカウントの残高を更新しようとしています:

 

  • 取引A:アカウント残高を10増加させます。

  • 取引B:アカウント残高を20増加させます。

 

アカウントの初期残高は100です。

 

もし逐次実行を行えば、実行順序の結果は確定的です:

 

1. 取引Aを先に実行し、次に取引Bを実行します:

  • アカウント残高は最初に10増加し、110になります。

  • さらに20増加し、最終的に130になります。

2. 取引Bを先に実行し、次に取引Aを実行します:

  • アカウント残高は最初に20増加し、120になります。

  • さらに10増加し、最終的に130になります。

 

この2つの順序では、最終残高は130であり、システムは取引実行の順序の一貫性を保証しています。

 

ただし、並行実行環境では、取引Aと取引Bが同時に初期残高100を読み取り、それぞれの演算を行う可能性があります:

 

1. 取引Aは残高100を読み取り、その後計算して残高を110に更新します。

2. 取引Bも残高100を読み取り、計算後に残高を120に更新します。

 

この場合、取引が同時に実行されたため、最終的な残高が120にしか更新されず、130にならなかったのは、取引Aと取引Bの操作が互いの結果を「上書き」し、状態衝突が発生したためです。

 

この種の状態の衝突問題は「データ上書き」と呼ばれます。すなわち、取引が同じデータを同時に変更しようとすると、互いの計算結果を上書きし、最終的な状態が不正確になる可能性があります。もう一つの状態衝突が引き起こす可能性のある問題は、実行順序を保証することができないことです。複数の取引が異なる時間帯に処理を完了すると、異なる実行順序が生じます。順序が異なると、計算結果も異なる可能性があり、結果が不確定になります。

 

この不確実性を避けるために、ブロックチェーンの並行実行システムは通常、いくつかの衝突検出とロールバックメカニズムを導入したり、取引の依存関係を事前に分析したりして、最終的な状態の一貫性に影響を与えない形で並行実行することを保証します。

 

楽観的並行と決定的並行

 

存在する可能性のある状態衝突の問題に対処する方法は2つあります:決定的並行と楽観的並行です。これら2つのモデルは、効率と設計の複雑さにおいてそれぞれトレードオフがあります。

 

決定的な並行処理は、事前に状態アクセスを宣言する必要があります。バリデーターまたはシーケンサーは、取引の並びを決定する際に宣言された状態アクセスを確認します。同じ状態に書き込もうとする複数の取引がある場合、これらの取引は衝突としてマークされ、同時に実行されないようにします。異なるチェーンでは、状態アクセスを事前に宣言する形式が異なりますが、一般的には以下のいくつかの方法が含まれます:

  • 契約仕様による制約:開発者はスマートコントラクト内で直接状態アクセスの範囲を規定します。たとえば、ERC-20トークンの転送には送信者と受信者の残高フィールドへのアクセスが必要です。

  • 取引構造化データ宣言による:取引に特別なフィールドを追加して状態アクセスをマークします。

  • コンパイラ分析を通じて:高級言語のコンパイラは契約コードを静的に分析し、状態アクセスの集合を自動生成できます。

  • フレームワークによる強制宣言:特定のフレームワークは、開発者が関数呼び出し時に明示的に必要な状態を指定することを要求します。

 

楽観的並行処理は、取引を先に処理し、衝突が発生した場合に影響を受けた取引を順番に再実行します。衝突を可能な限り避けるために、楽観的並行設計の核心は、履歴データや静的分析などを通じて状態を迅速に予測し、仮定することです。つまり、システムは未完全な検証の下で、特定の操作や状態更新が有効であると仮定し、すべての検証プロセスを待つことを避け、性能とスループットを向上させます。

 

楽観的並行処理は状態に対する迅速な予測と仮定を通じて衝突を可能な限り回避できますが、特に契約の実行やクロスチェーントランザクションに関与する場合、避けられない課題がいくつかあります。衝突が頻繁に発生すると、再実行がシステムの性能を著しく低下させ、計算資源の消費が増加する可能性があります。

 

決定的な並行処理は取引前に状態依存性のチェックを行い、楽観的並行処理による衝突を回避しますが、取引提出前に状態依存性を正確に宣言する必要があるため、開発者にとってはより高い要求が課せられ、実装の複雑性が増します。

 

EVM並行のジレンマ

 

状態の衝突に対するアプローチには、決定的なものと楽観的なものがあり、並行処理の具体的な実装プロセスにおいては、ブロックチェーンデータベースアーキテクチャの観点からも考慮する必要があります。並行処理における状態の衝突問題は、メルクルツリーアーキテクチャ下のEVMにおいて特に困難です。メルクルツリーは階層的なハッシュ構造であり、取引が特定の状態データを変更するたびに、メルクルツリーのルートハッシュも更新する必要があります。この更新プロセスは再帰的であり、リーフノードから上に向かって逐次計算され、ルートノードに至ります。ハッシュは不可逆的であり、下位のデータ変更が完了するまで上位の計算ができないため、この特性は並行更新を難しくします。

 

もし2つの取引が並行して実行され、同じ状態(例えばアカウント残高)にアクセスすると、メルクルツリーのノードに衝突が発生します。この衝突を解決するには通常、追加のトランザクション管理メカニズムが必要であり、複数のブランチで一貫したルートハッシュを得ることを保証します。これはEVMにとって容易ではなく、並行化と状態の一貫性の間で妥協が求められます。

 

非EVM並行解決策

 

ソラナ

 

イーサリアムのグローバル状態ツリーとは異なり、ソラナはアカウントモデルを採用しています。各アカウントは独立したストレージスペースであり、帳簿に保存されているため、パスの競合問題を回避しています。

 

ソラナは決定的並行処理を採用しています。ソラナでは、各取引は提出時にアクセスするアカウントと必要なアクセス権(読み取り専用または読み書き)を明示的に宣言する必要があります。この設計により、ブロックチェーンノードは取引実行前に各取引が必要とするリソースを事前に分析できます。取引が実行を開始する前にすべてのアカウント依存関係が明示されているため、ノードはどの取引が同じアカウントにアクセスするか、どの取引が安全に並行して実行できるかを判断でき、インテリジェントなスケジューリングを実現し、衝突を避け、並行スケジューリングの基盤を実現します。

 

各取引が実行前にアクセスする必要があるアカウントと権限を宣言しているため、ソラナは取引間のアカウント依存関係(シーラーレベルモデル)をチェックできます。取引間に共有の読み書きアカウントがなければ、システムはそれらを異なるプロセッサに割り当てて並行して実行できます。

 

Aptos

 

Aptosの並行実行設計はイーサリアムとは大きく異なり、アーキテクチャとメカニズムにおいていくつかの重要な革新を行っており、主にアカウントモデルと状態ストレージに現れています。

 

イーサリアムは取引を実行する際に、グローバル状態ツリー(MPT)を頻繁に更新する必要があります。すべてのアカウントと契約の状態は共有状態ツリーに保存され、任意の取引はこの状態ツリーの一部にアクセスし、更新する必要があります。一方、Aptosはアカウントを独立した状態ユニットに分けており、各オブジェクトは独立したキーと値のペアとして存在し、オブジェクト間は独立して存在し、互いに影響を与えません。明確な参照関係がある場合のみ関連します。オブジェクト間には共有のツリーパスがなく、ロック競合は発生せず、完全に並行処理が可能です。

 

Aptosの基盤となるデータ構造はジェリーフィッシュメルクルツリーです。各オブジェクトの状態は最終的にJMTに保存され、独立したキーと値のペアとして存在します。イーサリアムのMPTとは異なり、ジェリーフィッシュメルクルツリーは完全な二分木構造であり、この形式によりノードのストレージパスとクエリパスが簡素化され、検証時間が大幅に短縮されます。また、各アカウントのツリー内の位置は固定されており、ツリー内のノードは独立して保存されているため、複数のアカウントの更新と検索を並行して行うことができます。

 

Aptosは楽観的並行処理を採用しており、事前に宣言されたすべてのアカウントの依存関係を提供する必要はありません。これを実現するために、AptosはBlock-STMを使用し、Block-STMは事前に設定された取引順序を利用して依存関係を推定し、中止の回数を減らします。

 

並行EVM

 

非EVM並行と比較して、並行EVMは状態依存性、衝突検出、ガス管理、ロールバックメカニズムなどの問題に対する技術的難易度が高いです。この点をよりよく理解するために、いくつかの並行EVMプロジェクト(Sui、Monad、Canto)がこれらの問題をどのように解決しているかを参考にすることができます。

 

Sui

 

SuiもAptosと同様に、状態を処理するためにオブジェクトモデルを使用し、各オブジェクト(例えばアカウント、スマートコントラクトの状態)を独立したリソースとして扱います。これらのオブジェクトはオブジェクトの一意の識別子によって区別されます。取引が異なるオブジェクトに関与する場合、これらの取引は異なる状態を操作するため、並行して処理できます。

 

Suiはオブジェクトモデルを使用して状態を管理していますが、EVMとの互換性を持たせるために、Suiのアーキテクチャは追加の適応層や抽象メカニズムを通じてオブジェクトモデルとEVMのアカウントモデルを橋渡ししています。

 

Suiでは、トランザクションのスケジューリングに楽観的並行戦略を使用し、トランザクション間に衝突がないと仮定します。衝突が発生した場合、システムはロールバックメカニズムを使用して状態を復元します。

 

Suiはオブジェクトモデルと状態隔離技術を使用しており、状態依存性の問題を効果的に回避できます。各オブジェクトは独立したリソースとして扱われ、異なる取引が並行して実行できるため、スループットと効率が向上します。しかし、この方法のトレードオフは、オブジェクトモデルの複雑さとロールバックメカニズムのコストです。取引間に衝突が発生した場合、一部の状態をロールバックする必要があり、システムに負担をかけ、並行処理の効率に影響を与える可能性があります。非EVM並行システム(ソラナなど)と比較して、Suiは高い並行性を維持するためにより多くの計算およびストレージリソースを必要とします。

 

モナド

 

Suiと同様に、モナドも楽観的並行を採用しています。しかし、モナドの楽観的並行は具体的な取引実行前に、依存関係のある取引の予測を行います。この予測は、モナドの静的コード分析器を通じて行われます。予測には状態へのアクセスが必要ですが、イーサリアムのデータベースにおける状態の保存方法は状態へのアクセスを非常に困難にします。並行して状態を読み取る過程で効率を向上させるために、モナドはデータベースを再構築しました。

 

モナドの状態ツリーはパーティションによって分割され、各パーティションは独自の状態サブツリーを維持します。更新時には関連するシャードのみを変更し、全体の状態ツリーを再構築する必要はありません。状態インデックステーブルを使用してパーティション内の状態を迅速に特定し、パーティション間の相互作用を減少させます。

 

ブロックチェーンTPSノードのハードウェア要件 バーチャルマシン 特徴 ソラナ 65,000+ 12コアCPU、256GB RAM、バリデーターノード500GB SSD、アーカイブノード1TB SSD、そしてOSに500GBを残しておくことが推奨されます ソラナVM 高い同時実行をサポートし、Proof of History (PoH)を採用し、非常に高いスループットを持つ、比較的軽量なコンセンサスメカニズム Aptos 160,000+ 32コアCPU、64GB+ RAM、3.0 TB SSDストレージ Move VM Move言語に基づいており、並行実行をサポートし、高スループットと低遅延を最適化 Sui 120,000+ 8コアCPU、128GB RAM、4 TB NVMe SSDストレージ Sui VM並行実行、リソースベースのモデルを採用し、低遅延高スループットをサポート Monad 10000+ 16コアCPU、32GB RAM、2 TB NVMe SSDストレージ EVM(互換性レイヤー) 高い並行性能を持ち、非同期実行と軽量なEVM仮想マシン設計でスループットを最適化 イーサリアム(マージ後) 30-100+ 4コアCPU、32GB RAM、4TB SSDストレージ EVM伝統的なスマートコントラクトプラットフォーム、マージ後にProof of Stakeに移行し、依然として限られた並行性をサポートします。

 

まとめ

 

並行処理の核心は、多経路実行の方式で実行層の効率を向上させることであり、多経路実行を実現するために、チェーンは衝突検出やロールバックメカニズムなどの一連のプロセスを実施する必要があり、最終的な状態の一貫性に影響を与えない形で並行実行を行い、データベースをある程度改良する必要があります。

 

もちろん、実行層の効率向上は、並行処理だけに限られません。実行プロセスの最適化は、取引がデータベースに必要な読み書き操作を減らすことによっても実現できます。チェーン速度の向上が関わる範囲はさらに広範であり、コンセンサス層の効率向上も含まれます。

 

各技術には特定の制限条件が存在します。並行処理は効率を向上させる方法の一つであり、最終的にその技術を使用するかどうかは、開発者にとっての使いやすさや、非中央集権的な方法での実現可能性などを考慮する必要があります。技術の積み重ねは多ければ良いわけではなく、少なくともイーサリアムに関しては、並行処理はそれほど魅力的ではありません。効率向上の観点から見ると、並行処理を導入することはイーサリアムにとって最適解ではありません。シンプルさを考慮しても、現在のイーサリアムのロールアップを中心としたロードマップを考慮しても、そうです。