ダウンロード
メニューを閉じる -

ストレステスティングRIF Consensus Nodeのワールドステート

Published on: 22 6月, 2020

Pablo Pedemonte著

はじめに

2016年、RSKは、Ethereumのワールドステートをモデル化するためのMerkle Patricia Treesの代替としてUnitrieを提案しました(Ethereum Yellow Paper、付録Dを参照)。2020年1月、オプトイン機能として、Unitrieを(Besuのコードに基づく)RIF Consensus Nodeに追加しました。その結果、ユーザーは、以下のような2種類のワールドステート実装から選択できるようになりました:

  1. Classicワールドステート(またはクラシックワールドステート)は、Yellow Paperに記載があります。
  2. Unitrieワールドステートは、 Unitrieによりバックアップされています。

2種類のワールドステート実装から選択してRIF Consensus Nodeを実行できるユーザーは、ワールドステートバリアントのメリットを比較できる立場にあります。本記事では、利用可能なストレージを使い果たす前に、両方の実装を比較し、構築/検索時間とアカウント割り当て容量を分析します。

実験1:構築時間と検索時間

構築時間と検索時間の分析用にあたり、最初は空のEthereumワールドステートに特定の数のアカウントを追加し、ベンチマーク実行中に変更を50回コミットすることで構成されるベンチマークを実行しました(つまり、作成されたアカウントをワールドステートのトライ/Unitrieに保存)。すべてのアカウントのコミット完了後は、以下のように2つのバリアントで100万アカウントを検索しました: 

  1. 100万件の既存アカウントを検索(すべてのアカウントを発見)。
  2. 100万件のランダムアカウントを検索(実際にアカウントは発見されず)。

ベンチマークは、最終的に構築時間と検索時間を報告します。300万件から1000万件の外部所有アカウントの範囲において、4Gb Javaヒープでベンチマークを一定時間実行します。アカウントの各番号に対してベンチマークを6回実行することにより、分散を処理します。以下の表は、それぞれ300万件、600万件、900万件のアカウントの平均構築時間と検索時間を示しています。 CTは構築時間、ELTは既存アカウントの検索時間、RLTはランダムアカウントの検索時間です。すべて秒単位での表記になっています。

表1 構築時間と検索時間

Unitrieの実装はメモリ効率が高くなるように設計されており、殆どの場合、実行時間とメモリフットプリントの低下をうまく両立させています。この選択により、検索時間に関してUnitrieはEthereumのトライと比較して不利になり、Unitrieは1.2倍から1.8倍遅くなります。ただし、割り当てられたアカウント数を考慮すれば、効果的です。Besuのワールドステート実装は600万件の壁に遠く及びませんが、Unitrieはメモリ内の900万件のアカウントを処理できます。実際、600万件のアカウントにおけるトライ構築は、Classicトライよりも1.47倍遅くなります。このことは、Besuが600万件のアカウントのしきい値で動作するようにJVMをスラッシングしていることを示しています。

 

表2 構築と検索のスループット

表2は、構築と検索のスループットをまとめたものです。CTpとは構築スループットのことであり、Unitrie/Ethereumワールドステートに対する1秒あたりの更新数を表します。同様に、ELTpRLTpはそれぞれ、既存アカウント検索とランダムアカウント検索スループット(1秒あたりの検索)を表します。一般的に、Unitrieは、Besuワールドステートが所定の時間内に実行する操作の55%から80%を実行できます。特に、トラッシングにより、Unitrieのスループットは、600万件のアカウントを挿入すると、Besuワールドステートのスループットの1.5倍になります。また、その数のアカウントについて、100万件のランダム要素に対するUnitrie検索ループットは、Besuワールドステートと一致しました。 

検索スループットは、最悪の場合、6万7000検索/秒であることに注意してください(900万件のアカウント、既存アカウント検索)。納得できる結果を得るには、コストが400GasであるBALANCE操作を検討してください。680万GasのRSKブロックにおける現在のGas制限を考慮すると、理想的には、ブロックで最大6.8M / 400 = 17000のバランス操作を実行できます。トライがメモリに保存されていると仮定すると、1秒あたり6万7千回の検索でも、Unitrieは0.25秒で実行されます。

図1、2および3は、それぞれ[3百万、10百万]の範囲でアカウントを割り当てる場合の構築および既存/ランダムアカウントの検索時間を示しています。プロットは、各データポイントの中心傾向と信頼区間を表示します。4Gb Javaヒープの場合、Unitrieは900万アカウントのしきい値でトラッシングを開始します(Besuワールドステート、6Mしきい値におけるトラッシングを参照)。さらに、Unitrieはより広い信頼区間を示します。これは、共有パスをソフト参照として保存するUnitrie実装に起因する可能性があり、したがって非決定論的にパス再計算オーバーヘッドがランタイムに追加されます。

実験2:コントラクトアカウント

Unitrieは、アドレスハッシュから派生したキーの下に各アカウントを格納します。構造により、アカウントキーにはランダムなプレフィックスと同じ長さがあるため、平均すると、リーフにアカウントを持つバイナリバランスツリーになります。つまり、N個の外部所有アカウントには2N – 1個のノードが必要ということです。

コントラクトアカウントの場合、Unitrieのストレージ容量は、以前の計算と比較して必然的に減少します。これは、Unitrieがコードを対応するアカウントノードの正しい子として保存するためです。したがって、Nアカウントの場合、αはコントラクト間の比率です。

図1. ワールドステートコントラクト時間

図2. 検索時間(既存アカウント)

図3. 検索時間(ランダムアカウント)

外部所有アカウントの場合、Unitrieのサイズは(2 +α)N – 1ノードになります。これは、α= 0の場合の2N – 1ノード(したがって、Nの外部所有アカウントの初期計算を含む)から、α= 1の場合の3N – 1ノード(すべてのアカウントがコントラクト)の範囲です。逆に、Ethereumのワールドステートはトライの外部にアカウントコードを格納しているため、コントラクトアカウントを検討する際にトライのストレージ容量は影響を受けません。

αの様々な値によって引き起こされるUnitrieストレージ容量の変動を測定するために、トラッシングを行う前に、4Gb Javaヒープにできるだけ多くのアカウントを割り当てるベンチマークを実行しました。[0, 1]の区間でαのいくつかの値について実験を実行しました。ベンチマークは、アカウントコードに対して実際の2114バイトのERC20コントラクトを使用します。図4は、UnitrieがBesu Ethereumのワールドステート最大ストレージ容量と交差するポイントとしてα= 0.8を正確に示した結果を表しています。また、4GbヒープでのUnitrieの動作範囲も表しています。これは、950万件/900万件の外部所有アカウント(α= 0)と490万件のコントラクトアカウント(α= 1)の間のどこにでも格納できます。

図4. コントラクトアカウントによって引き起こされるストレージ容量の変動

結論

Unitrieは、メモリフットプリントと計算時間をトレードします。図2と図3は、[300万、500万]の範囲のアカウントでは、Unitrie検索時間が約1.5倍から2倍遅いことを示しています。しかし、Besuのワールドステートがメモリに十分収まらないため、最終的にディスクからノードを読み取る設定では、この違いはなくなります。その場合、ディスクI/Oレイテンシが検索時間を支配します。当社の実験によれば、Unitrieが4Gbのヒープに9百万件の外部所有アカウントで構成されるワールドステートを保存できる一方で、Besuのワールドステートは600万件のアカウント制限で低下し始めます。概して、UnitrieはディスクI/Oを回避する可能性が高くなりますが、Besuのワールドステートと比較して(最悪の場合)検索が1.8倍遅くなります。

コントラクトアカウントの場合、ストレージ容量は、コントラクトアカウントと外部所有アカウントの比率であるαによって決定されます。αの値が小さいほどメモリに収まるノードが多くなり、再度ディスクI/Oレイテンシを回避する可能性が最大化します。実験2は、Unitrieのストレージ容量がα<0.8の間Besuのストレージ容量を超えていることを示しています。

αの推定値はどうでしょうか?2020年11月の時点において、Etherscanは、Mainnet上の8028万件の一意アカウントの存在を報告しています。同日のコントラクトアカウント数は、1240万件でした。よって、α=0.154となります。執筆時点では、Mainnetには9414万の一意のアドレスが存在しています。非現実的ですが、2020年11月以降に作成されたすべてのアカウントがコントラクトと仮定すると、上限がα= 0.28という著しく過大な数値が出ます。その場合でも、Unitrieのコンフォートゾーンに収まります。

付録A:実験の実行

すべての実験コードはGithubプロジェクトのRIF-Consensus-Nodeでホストされており、JDK 11以降が必要です。プロジェクトのクローン作成後、プロジェクトのルートフォルダに移動して実行することにより、UnitrieストレステストまたはEthereumのクラシックワールドステートテストを実行できます:

ここでは、accounts_to_createは作成するアカウントの数を定義し、パラメータalpha_ratioは実験2で定義されたコントラクトアカウントと外部所有アカウントの比率に対応します。

実験は、Intel i5 2.3 GHzデュアルコアプロセッサ、16GBのRAM、250GBのSSDを搭載したMacBook Proで実行されました。すべての実験は、G1ガベージコレクタを使用して最大サイズ4GbのJVMヒープで実行されました。