
Solana共同創設者:Solanaのステート成長に対する解決策とは?
TechFlow厳選深潮セレクト

Solana共同創設者:Solanaのステート成長に対する解決策とは?
現在のハードウェア制限内で状態とメモリを管理する必要がある。
執筆:toly、Solana共同創設者
翻訳:Felix、PANews
Solanaには毎日約100万の新規アカウントが追加され、現在の総ステートは5億を超えており、スナップショットサイズは約70GBである。ハードウェアの進化により、これらの数値自体は完全に管理可能だが、SVMランタイムの目標は最も安価なハードウェアでもアクセスできるようにすることであり、これを実現するには現在のハードウェア制限内でステートとメモリを管理しなければならない。
PCI帯域幅
2024年時点で、最新のPCI帯域幅は0.5Tbpsから1Tbpsのスループットに達することができる。つまり毎秒64GBから128GBである。一見非常に大きいように思えるが、もし1トランザクション(tx)が128MBの読み書きを行う場合、128GB/sのPCI帯域幅ではチェーンのTPSが約1000に制限されることになる。実際には、ほとんどのtxは直近でロードされRAMにキャッシュされたメモリにアクセスする。理想的な設計とは、128MBの新しいステートを持つ1000件のtxに加え、1万件以上の既存キャッシュステートに対する読み書きを行うtxを許容できる構造のことである。
アカウントインデックス
新規アカウントを作成するには、そのアカウントが現在存在しないことを証明する必要がある。これは通常各バリデータ上で自動的に処理される。なぜなら各バリデータは有効なすべてのアカウントの完全なインデックスを持っているためである。アカウントデータがローカルに保存されていなくても、データのハッシュだけを保持した場合でも、5億のアカウントは32バイトのキー+32バイトのデータハッシュ、つまり1項目あたり64バイトとなり、合計で32GBとなる。これはすでにRAMとディスクを分離するのに十分な量である。
スナップショットサイズ
あるスナップショットサイズにおいて、ネットワークの一部にハードウェア障害が発生した場合、新規システムの冷間起動に必要な時間が、最悪ケースの再起動時間を延長するほど長くなる可能性がある。帯域幅やハードウェアは日々改善されているため状況は変化しており、Solanaはこの制限に近づいていないが、あらゆる時点でこの制限は存在する。
概要
メモリとディスクはそれぞれ異なるパフォーマンス特性と制限を持つ。SVMがこれらを区別しなければ、トランザクションと制限は常に最悪のケースに基づいて価格設定され、結果としてパフォーマンスが制限される。トランザクション実行中にはすべてのアカウントキーが少なくとも利用可能でなければならず、総アカウント数はRAMおよびディスクのPCI帯域幅使用率に影響を与える。スナップショットは無制限に大きくすることはできない。理想の解決策は以下の通りである。
-
PCIリソースを必要としないより多くのtxをブロックに詰め込むことを許可する
-
総インデックスサイズとスナップショットサイズを管理する
Chilly、Avocado、LSR。名前はひどいが、優れたソフトウェア設計の兆候である。AnzaおよびFiredancerのエンジニアが考案した以下のスキームについて述べる。
Chilly
アカウントランタイムのキャッシュは、すべてのインスタンスによって決定論的に管理される。高レベルで言えば、これはステートへのアクセス用LRUキャッシュである。ブロック生成およびスケジューリング中に、この実装はLRUキャッシュのロックや反復なしに簡単にアカウントをチェックできる。キャッシュは非常にシンプルなカウンタ機構によって実現されている。
-
Bank::loaded_bytes:u64として、ロードされたバイト総数が追跡される
-
各アカウントは使用時に、現在の実行回数であるaccount::load_counter:u64でマークされる
-
アカウントをロードする際、Bank::loaded_bytes - Account::load_counter > CACHE_SIZEの場合、そのアカウントは「コールドアカウント」と見なされ、そのサイズは各ブロックのLOAD_LIMITに基づいて計算される
-
新規アカウントのload_counterは0であるため、すべての新規アカウントはコールドアカウントとなる
-
リーダーのスケジューラは、LOAD_LIMITを書き込みロックCU制限と同様のウォーターマークとして扱う
この設計の優れた点は、現在のスケジューラに自然に適合することにある。ユーザーは単に自身の優先料金を気にすればよい。スケジューラは、LOAD_LIMITおよびアカウントの書き込みロック制限を下回るすべてのtxを「ナップサック問題」のように処理しなければならない。最も高い優先度を持つtxが最初にロードされ、LOAD_LIMITを使用できる。この制限に達した後も、他のすべてのtxは依然としてブロックに含まれることができる。これにより、バリデータはtxのキャッシュ局所性を最大限に活かせる。
Avocado
Avocadoは二つの部分からなる:ステート圧縮とインデックス圧縮。まずアカウントデータをハッシュで置き換え、次にアカウントインデックスをBinary TrieまたはPatricia Trieに移行する。新規アカウントは、「trie」内に存在しないことを証明しなければならない。
ステート圧縮
おおまかな設計は以下の通り:
-
割り当て時、各アカウントは1バイトあたりX lamportsをバインドする
-
Xが現在の経済的最低価格より低い場合、そのアカウントはメモリ内に保たれず、圧縮される
-
圧縮はエポック単位で行われる多段階プロセスである
-
アカウントデータはハッシュ値(data)に置き換えられる
-
アカウントキーは依然としてステート内に存在する
-
圧縮されたアカウントを参照するトランザクションは失敗する
-
解凍にはローダプログラムのようなデータのアップロードが必要
-
解凍コストは新規アカウントを割り当てるコストと同等であるべき
推定では、75%のアカウントが6ヶ月以上アクセスされておらず、おそらく今後もアクセスされないだろう。それらを圧縮することでスナップショットサイズの50%を節約できる。
インデックス圧縮
こちらはより難しい課題である。ステート圧縮のみでは、バリデータは依然としてシステム内のすべての有効なアカウントを保持している。新規アカウント作成にはこのデータベースをチェックする必要がある。バリデータがこのデータベースを保持するコストは高く、一方でユーザーが新規アカウントを作成するコストは低い。新たな秘密鍵が既存アカウントと一切衝突しないことを保証しなければならない。
Binary Trieマイニング
-
Binary Trieはスナップショットの一部として追跡される
-
追加のSOLを得たいバリデータは、圧縮されたアカウントのkvペアをステートから削除し、それをBinary Trieに追加するトランザクションを作成できる
-
ユーザーは解凍プロセス中にkvをTrieから削除することで、この操作を逆に行える(ただし解凍時にアトミック操作が必要になる可能性があり、バックグラウンドサービスが圧縮アカウントを処理しやすくなるようにする)
-
バリデータにとって、含まれるkvペアの数に関わらず、Trieルートのサイズは一定である
-
zkpを使用することで、各txは約30のアカウントを圧縮できる
-
各ブロックに1つだけだと仮定すると、5億のアカウントを圧縮するには約80日かかる
このプロセスの肝は、この操作を行うバリデータに報酬が与えられることだが、すべてのバリデータがこの操作を行う必要はないということだ。すべてのバリデータがこれを実行しなければならない場合、すべてのバリデータが現在のBinary Trieの内容を維持しなければならず、つまり全ステートがスナップショットの一部でなければならない。全ステートを維持したいバリデータは、インデックス内のN個のアカウントをTrieに圧縮するトランザクションを提出すべきである。
新規アカウントの証明
新規アカウントを作成するには、ユーザーがそのアカウントがTrie内に存在しないことを証明しなければならない。全ステートを維持するバリデータは、アカウントがTrieに存在しないことの証明を生成できる。しかし、これによりユーザーは常に大規模なステートを持つプロバイダに接続して証明を生成する負担を負うことになる。
あるいは、ユーザーは自分のアカウントが最近のPoHハッシュを使って作成されたことを証明できる。これをサポートする最も簡単な方法は以下の通り:
-
新しいPKIを生成する
-
アカウントアドレスは、ハッシュ(最近のPoHハッシュ、PKI::public_key)となる
Trie内のアカウントはまずステート圧縮を経る必要があり、これにはフルエポックが必要である。したがって、Trie内のアカウントが最近のPoHハッシュを使ってアドレスを生成することは不可能である。
他に可能な方法として、PKI作成自体が「秘密(ユーザーが隠した秘密、最近のPoHハッシュ)」を使って秘密鍵が作成されたことを証明できるようにする方法がある。
LSR
Lightweight Simple Rent(軽量簡易リース)、通称Less Stupid Rent(より馬鹿げていないリース)。新規アカウントの割り当てコストをどう価格付けし、古い不要なアカウントが最終的に圧縮され、システム全体の負荷と新規ユーザーの価格が低下するようにするか?
リース(Rent)制度の復活が必要である。リースとは、現在のステートにあるアカウントがAWS上のストレージ料金のように、Xドル/バイト/日を支払う仕組みである。
Rent Rate bonding curve
RentRate = K*(state_size)^N
現在のステートサイズが小さければレートは低く、スナップショット制限に近づけば非常に高くなるべきである。
割り当て最小バウンディング価格
アカウントは少なくとも1エポックは存在しなければならない。割り当て時にはアカウントをホット状態にする必要がある。ホットアカウントはキャッシュ期間中は存在すべきである。
新規アカウントのバウンド = エポックスロット数 * RentRate * アカウント::サイズ
新規アカウントを作成するには、残高にこれだけのlamportsを最低限保有しなければならない。
ホットアカウントのバーン
lruturnoverrate = LRUキャッシュ内で各アカウントが平均して占める時間。最大は1エポック。この値は定数でもよく、あるいはチェーン外で計算され、中央値権益加重定数としてSVMに報告される。
圧縮
(current slot - account::creation_slot) * RentRate * account::size > account::lamports のとき、アカウントを圧縮し、すべてのlamportsをバーンする。
上記の解決策により、未使用のアカウントは時間とともに最終的にlamportsが0になり、圧縮されるため、ステートは安価になるはずである。これによりデータオーバーヘッドだけでなく、インデックスオーバーヘッドも減少し、現在のステートサイズが縮小される。ステートサイズの縮小は、超二次的な割り当てコストを低下させる。
TechFlow公式コミュニティへようこそ
Telegram購読グループ:https://t.me/TechFlowDaily
Twitter公式アカウント:https://x.com/TechFlowPost
Twitter英語アカウント:https://x.com/BlockFlow_News














