Solana共同創設者:Solanaの状態成長にはどのような解決策があるのか?
著者:toly、Solana共同創設者
編訳:Felix、PANews
毎日約100万の新しいアカウントがSolanaに追加され、現在の総状態は5億を超え、スナップショットのサイズは約70GBです。ハードウェアの改善に伴い、これらの数字自体は完全に管理可能ですが、SVMランタイムの目標は最も安価なハードウェアアクセス方法を提供することです。そのためには、現在のハードウェア制限内で状態とメモリを管理する必要があります。
PCI帯域幅
2024年までに、最新のPCI帯域幅は0.5Tbから1Tbのスループットに達する可能性があります。つまり、毎秒64GBから128GBです。大きく聞こえますが、1つのtxが128MBを読み書きする場合、128GBpsのPCI帯域幅はチェーンのTPSを約1000に制限します。実際には、ほとんどのtxは最近読み込まれ、RAMにキャッシュされたメモリにアクセスします。理想的な設計は、128MBの新しい状態を持つ1000のtxを読み込むことを許可し、さらに10k以上の既存のキャッシュ状態を読み書きするtxを追加するべきです。
アカウントインデックス
新しいアカウントを作成するには、そのアカウントが現在存在しないことを証明する必要があります。これは通常、各バリデーターで自動的に行われます。なぜなら、各バリデーターは現在のすべての有効なアカウントの完全なインデックスを持っているからです。アカウントデータがローカルに保存されていなくても、データのハッシュのみが保存されている場合、5億のアカウントは32バイトのキー+32バイトのデータハッシュ、つまり各項目64バイトで、合計32GBになります。これにより、RAMとディスクの分離が保証されます。
スナップショットサイズ
特定のスナップショットサイズの下で、ネットワークの一部にハードウェア障害が発生した場合、新しいシステムを冷起動するのに必要な時間は、最悪のケースの再起動時間を延長するのに十分です。帯域幅とハードウェアの改善に伴い、状況は日々変化しており、Solanaはこの制限に近づいていませんが、この制限は常に存在します。
概要
メモリとディスクは異なる性能特性と制限を持っています。SVMが区別しない場合、取引と制限は最悪のケースに基づいて価格設定され、パフォーマンスが制限されます。取引実行中、すべてのアカウントキーは少なくとも利用可能でなければならず、総アカウント数はRAMとディスクのPCIe帯域幅の利用率に影響を与えます。スナップショットは任意に増加できません。理想的な解決策は:
PCIリソースを必要としないtxをブロックにパッケージ化することを許可する
総インデックスサイズとスナップショットサイズを管理する
Chilly、Avocado、LSR。悪い名前は通常、優れたソフトウェア設計の兆候です。AnzaとFiredancerのエンジニアは以下のソリューションを考案しました。
Chilly
アカウントランタイムのキャッシュは、すべてのインスタンスによって決定論的に管理されます。より高いレベルでは、これは状態へのLRUキャッシュへのアクセスです。ブロック構築とスケジューリングの間に、この実装はアカウントを簡単にチェックでき、ロックやLRUキャッシュの反復は必要ありません。キャッシュは非常にシンプルなカウンターメカニズムで実装されています。
総読み込みバイトはBank::loaded_bytes:u64として追跡されます
各アカウントは使用時に現在の実行総数account::load_counter:u64でマークされます
アカウントを読み込むとき、もしBank::loadedbytes - Account::loadcounter > CACHESIZEであれば、そのアカウントは冷アカウントと見なされ、そのサイズは各ブロックのLOADLIMITに基づいて計算されます
新しいアカウントのload_counterは0であるため、すべての新しいアカウントは冷アカウントです
リーダーのスケジューラーはLOAD_LIMITを水印として使用し、書き込みロックCU制限に似ています。
この設計の素晴らしさは、現在のスケジューラーに自然に適合することです。ユーザーは自分の優先費用を心配するだけで済みます。スケジューラーは、すべてのLOADLIMITとアカウント書き込みロック制限を下回るtxをバックパックに入れる問題を処理しなければなりません。最高の優先度のtxは最初に読み込まれ、LOADLIMITを使用します。この制限に達すると、他のすべてのtxはまだ1つのブロックに入れることができます。したがって、バリデーターはtxのキャッシュ局所性を最大化できます。
Avocado
Avocadoは、状態圧縮とインデックス圧縮の2つの部分で構成されています。最初にハッシュでアカウントデータを置き換え、その後アカウントインデックスをバイナリトライ/パトリシアトライに移行します。新しいアカウントは、「トライ」に存在しないことを証明する必要があります。
状態圧縮
大まかな設計は次のとおりです:
割り当て中、各アカウントはバイトごとにX個のlamportsにバインドされます。
もしX < 現在の経済的底値であれば、そのアカウントはメモリに保持され、そのアカウントは圧縮されます。
圧縮は複数のステップのプロセスで、1つのエポックで実行されます。
アカウントデータはハッシュ値(data)に置き換えられます。
アカウントキーは依然として状態にあります。
圧縮されたアカウントを参照する取引は失敗します。
解凍には、ローダーに似たデータをアップロードする必要があります。
解凍のコストは、新しいアカウントを割り当てるコストと同じであるべきです。
推定では、75%のアカウントは6か月以上アクセスされておらず、永遠にアクセスされない可能性が高いです。それらを圧縮することで、スナップショットサイズを50%削減できます。
インデックス圧縮
これはより難しい問題です。状態圧縮だけでは、バリデーターはシステム内のすべての可能な有効アカウントを保持しています。新しいアカウントを作成するには、このデータベースをチェックする必要があります。バリデーターがこのデータベースを保存するコストは非常に高いですが、ユーザーが新しいアカウントを作成するコストは非常に低いです。新しい秘密鍵が既存のアカウントと衝突しないことを保証する必要があります。
バイナリトライマイニング
バイナリトライはスナップショットの一部として追跡されます。
追加のsolを得たいバリデーターは、取引を作成して状態から圧縮されたアカウントkvペアを削除し、それらをバイナリトライに追加できます。
ユーザーは解凍中にトライからkvを削除することができ、許可されていない場合にこの操作を逆に実行することができます(これは、バックエンドサービスがアカウントを圧縮する際に、解凍時に原子操作を行う必要があるかもしれません)。
バリデーターにとって、kvペアがいくつ含まれていても、トライのルートのサイズは一定です。
zkpを使用すると、各txは約30のアカウントを圧縮できます。
各ブロックに1つだけあると仮定すると、5億のアカウントを圧縮するには約80日かかります。
このプロセスの重要な点は、この操作を実行するバリデーターが報酬を得ることですが、すべてのバリデーターがこの操作を実行する必要はないということです。すべてのバリデーターがこの操作を実行する必要がある場合、すべてのバリデーターは現在のバイナリトライの内容を維持しなければならず、これは全体の状態がスナップショットの一部であることを意味します。全体の状態を維持したいバリデーターは、インデックス内のN個のアカウントをトライに圧縮する取引を提出する必要があります。
新アカウント証明
新しいアカウントを作成するには、ユーザーはそのアカウントがトライに存在しないことを証明する必要があります。全体の状態を維持するバリデーターは、アカウントがトライに存在しないことを証明することができます。これにより、ユーザーは常に大規模な状態提供者に接続してこれらの証明を生成する負担を負うことになります。
または、ユーザーは自分のアカウントが最近のPoHハッシュで作成されたことを証明できます。これをサポートする最も簡単な方法は:
新しいPKIを生成する
アカウントアドレスはハッシュ(最近のPoHハッシュ、PKI::public_key)です。
トライ内のアカウントは最初に状態圧縮を行う必要があるため、これは完全なエポックを必要とします。トライ内の任意のアカウントは、最近のPoHハッシュを使用してアドレスを生成することは不可能です。
他にサポートできる方法は、PKIの作成自体が、秘密鍵がハッシュ(ユーザーの隠された秘密、最近のPoHハッシュ)で作成されたことを証明する証明を提供できることです。
LSR
Lightweight Simple Rent、またはLess Stupid Rent。新しいアカウントの割り当てコストをどのように価格設定し、古い廃止されたアカウントが最終的に圧縮され、システム全体の負荷と新しいユーザーの価格をどのように減少させるか?
賃貸制度(Rent)を復活させる必要があります。Rentは、現在の状態のアカウントがXドル/バイト/日の費用を支払うべきであることを意味します。これは、AWS上のアカウントがストレージ費用を支払うのと同様です。
Rent Rate bonding curve
RentRate = K*(state_size)\^N
現在の状態サイズに関係なく、サイズが小さい場合は料金が低く、スナップショット制限に近い場合は料金が非常に高くなるべきです。
Allocation Minimum Bonding Price
アカウントは少なくとも1エポック存在する必要があります。割り当てにはアカウントをホット状態にする必要があります。ホットアカウントはキャッシュ期間中に存在するべきです。
New Account bond = Epoch Slots * RentRate * Account::size
新アカウントの残高には、これだけのlamportsが必要です。
Hot Account Burn
lruturnverrate = 各アカウントがLRUキャッシュ内で平均的に占有する時間、最大値は1エポック。この値は定数であるか、オフチェーンで計算され、中央値の権益加重定数としてSVMに報告されることがあります。
圧縮
(current slot - account::creation_slot) * RentRate * account::size > account::lamportsの場合、アカウントを圧縮し、すべてのlamportsを焼却します。
上記の解決策は、状態を非常に安価にするはずです。なぜなら、時間が経つにつれて未使用のアカウントは最終的にlamports 0に達し、圧縮されるからです。したがって、データのオーバーヘッドは減少し、インデックスのオーバーヘッドも減少し、現在の状態のサイズが減少します。状態のサイズを減少させることで、超二次割り当てのコストが低下します。