著者: toly、Solana 共同創設者

編集者: Felix、PANews

 

毎日約 100 万の新しいアカウントが Solana に追加され、状態の総数は現在 5 億を超え、スナップショットのサイズは約 70 GB です。ハードウェアが改良されると、これらの数値自体は完全に管理可能になりますが、SVM ランタイムの目標は、ハードウェアへの最も安価なアクセスを提供することであり、これを達成するには、現在のハードウェアの制限内で状態とメモリを管理する必要があります。

PCI帯域幅

2024 年の時点で、最新の PCI 帯域幅は 0.5 Tb ~ 1 Tb のスループットを達成できます。または 1 秒あたり 64GB ~ 128GB。膨大に聞こえるかもしれませんが、TX が 128MB の読み取り/書き込みを行う場合、128GBps の PCI 帯域幅ではチェーンの TPS が約 1000 に制限されます。実際、ほとんどの TX は、最近ロードされて RAM にキャッシュされたメモリにアクセスします。理想的な設計では、128MB の新しい状態を含む 1000 個の TX をロードできるほか、キャッシュされた既存の状態を読み書きできる 10,000 以上の TX が可能になります。

アカウントインデックス

新しいアカウントを作成するには、そのアカウントが現在存在しないことを証明する必要があります。各バリデータには現在アクティブなすべてのアカウントの完全なインデックスがあるため、これは通常、各バリデータで自動的に行われます。アカウント データがデータのハッシュのみでローカルに保存されていない場合でも、5 億アカウントの場合、キー 32 バイト + データ ハッシュ 32 バイト、または項目ごとに 64 バイト、つまり 32 GB になります。これは、RAM とディスクを確実に分離するには十分です。

スナップショットのサイズ

特定のスナップショット サイズでは、ネットワークの一部でハードウェア障害が発生した場合に、新しいシステムをコールドスタートするのに必要な時間は、最悪の場合の再起動時間を延長するのに十分な時間です。帯域幅とハードウェアが向上するにつれて状況は日々変化しており、Solana がその制限に近づくことはありませんが、その制限はどの時点でも存在します。

概要

メモリとディスクには、異なるパフォーマンス特性と制限があります。 SVM が区別しない場合は、トランザクションと制限に最悪のケースを考慮して価格を設定する必要があり、パフォーマンスが制限されます。少なくとも、トランザクションの実行中にすべてのアカウント キーが使用可能である必要があり、アカウントの総数は RAM とディスクの PCIi 帯域幅の使用率に影響します。スナップショットを任意に大きくすることはできません。理想的な解決策は次のとおりです。

  • PCI リソースを必要としないより多くの TX をチャンクにパックできるようにする

  • インデックスの合計サイズとスナップショットのサイズを管理する

チリー、アボカド、LSR。悪い名前は、多くの場合、ソフトウェア設計が優れていることを示しています。 Anza と Firedancer のエンジニアは、次の解決策を考え出しました。

肌寒い

アカウントのランタイム キャッシュは、すべてのインスタンスによって決定的に管理されます。高レベルでは、これはアクセス状態の LRU キャッシュです。この実装により、LRU キャッシュをロックしたり反復したりする必要がなく、ブロックの構築およびスケジューリング中にアカウントを簡単にチェックできるようになります。キャッシュは、非常に単純なカウンター メカニズムを使用して実装されます。

  • ロードされた合計バイト数は Bank::loaded_bytes:u64 として追跡されます。

  • 各アカウントは、使用時に現在の累計アカウント::load_counter:u64 でタグ付けされます。

  • アカウントをロードするときに、Bank::loaded_bytes - Account::load_counter > CACHE_SIZE の場合、アカウントはコールド アカウントとみなされ、そのサイズはブロックごとの LOAD_LIMIT に基づいて計算されます。

  • 新しいアカウントのload_counterは0なので、すべての新しいアカウントはコールドアカウントです

  • リーダーのスケジューラは、書き込みロック CU 制限と同様に、LOAD_LIMIT をウォーターマークとして扱います。

このデザインの優れた点は、現在のスケジューラに自然に適合することです。ユーザーは優先料金についてのみ心配する必要があります。スケジューラは、LOAD_LIMIT およびアカウント書き込みロック制限を下回るすべての TX をナップザックに入れることに対処する必要があります。最も優先度の高い TX を最初にロードし、LOAD_LIMIT を使用できます。この制限に達しても、他のすべての TX をブロックに入れることができます。したがって、バリデーターは、TXS のキャッシュ局所性の軽減を最大化できます。

アボカド

Avacado は、状態圧縮とインデックス圧縮の 2 つの部分で構成されます。まずアカウント データをハッシュに置き換え、次にアカウント インデックスをバイナリ トライ/パトリシア トライに移行します。新しいアカウントは、「トライ」に参加していないことを証明する必要があります。

状態圧縮

大まかなデザインは次のとおりです。

  • 割り当て中、各アカウントはバイトごとに X 個の lamport にバインドされます。

  • もし

  • 圧縮は、エポックにわたって実行される複数ステップのプロセスです。

  • アカウントデータをハッシュ(データ)に置き換える

  • アカウントキーはまだステータスです

  • 圧縮アカウントを参照するトランザクションが失敗しました

  • 解凍にはローダーと同様のデータをアップロードする必要があります

  • 解凍のコストは、新しいアカウントを割り当てるコストと同じである必要があります。

推定 75% のアカウントは 6 か月以上アクセスされておらず、おそらく今後もアクセスされることはありません。圧縮すると、スナップショットのサイズが 50% 節約されます。

インデックスの圧縮

これは解決するのがさらに難しい問題です。状態圧縮だけを使用しても、バリデーターはシステム内のすべての有効なアカウントを引き続き所有します。新しいアカウントを作成するには、このデータベースを確認する必要があります。バリデーターがこのデータベースを保存するコストは高くなりますが、ユーザーが新しいアカウントを作成するコストは低いです。新しい秘密キーが既存のアカウントと競合しないことを確認してください。

バイナリトライマイニング

  • バイナリ トライはスナップショットの一部として追跡されます

  • 追加の sol を獲得したいバリデーターは、圧縮されたアカウントと KV のペアを状態から削除し、バイナリ トライに追加するトランザクションを作成できます。

  • ユーザーは、解凍中に Trie から kv を削除することで、許可されていなくてもこれを逆に行うことができます (これには、バックグラウンドで圧縮アカウントを提供する際の処理を容易にするために、解凍時にアトミックな操作が必要になる場合があります)。

  • バリデーターの場合、含まれる kv ペアの数に関係なく、トライ ルートのサイズは一定です。

  • zkp を使用すると、TX ごとに約 30 アカウントを圧縮できます

  • ブロックごとに 1 つのブロックしかないと仮定すると、5 億のアカウントを圧縮するには約 80 日かかります。

このプロセスで重要なのは、このアクションを実行するバリデーターには報酬が与えられますが、すべてのバリデーターがこのアクションを実行する必要があるわけではないということです。すべてのバリデーターがこれを行う必要がある場合、すべてのバリデーターは現在のバイナリ トライの内容を維持する必要があります。つまり、状態全体がスナップショットの一部である必要があります。状態全体を維持したいバリデーターは、インデックス内の N アカウントをトライに圧縮するトランザクションを送信する必要があります。

新しいアカウントの証明

新しいアカウントを作成するには、ユーザーはそのアカウントが Trie に存在しないことを証明する必要があります。状態全体を維持するバリデーターは、アカウントがトライに含まれていないことの証明を生成できます。これは、これらの証明を生成するために常に大規模な州プロバイダーに接続する必要があるユーザーに負担を与えます。

あるいは、ユーザーは自分のアカウントが最近の PoH ハッシュを使用して作成されたことを証明できます。これをサポートする最も簡単な方法は次のとおりです。

  • 新しい PKI を生成する

  • アカウントアドレスはハッシュ(最も近いPoHハッシュ、PKI::public_key)です

トライ内のアカウントが最初に状態圧縮を受ける必要があることを考えると、これには完全なエポックが必要です。 Trie 内のどのアカウントでも、最新の PoH ハッシュを使用してアドレスを生成することは不可能です。

サポートされる可能性のある他の方法は、PKI の作成自体が、秘密キーがハッシュ (ユーザーの隠し秘密、最近の PoH ハッシュ) を使用して作成されたことの証明を提供できることです。

LS-R の

Lightweight Simple Rent、Less Stupid Rent とも呼ばれます。新しいアカウントを割り当てるコストをどのように見積もるのですか?また、古い放棄されたアカウントが最終的に圧縮されて、システム全体の負荷と新規ユーザーの料金が確実に削減されるようにするにはどうすればよいですか?

家賃(Rent)システムを復活させる必要がある。レンタルとは、AWS のアカウントがストレージに対して支払うのと同じように、現在の状態のアカウントに 1 バイトあたり X ドル/日が請求されることを意味します。

家賃率結合曲線

家賃率 = K*(州の大きさ)^N

現在の状態のサイズに関係なく、レートが小さい場合はレートを低くし、スナップショットの制限に近い場合はレートを非常に高くする必要があります。

割り当て最低保証価格

アカウントは少なくとも 1 エポックの間存在する必要があります。アカウントをホットステータスにするには割り当てが必要です。キャッシュ中にホット アカウントが存在する必要があります。

新しいアカウントのボンド = エポックスロット * レンタルレート * アカウント::サイズ

新しいアカウントを作成するには、残高に少なくともこの数のラムポートが必要です。

ホットアカウントバーン

lruturnverrate = 各アカウントが LRU キャッシュ内で費やす平均時間、最大 1 エポック。この値は定数にすることも、オフチェーンで計算して中央値ステーク加重定数として SVM に報告することもできます。

圧縮

(現在のスロット - account::creation_slot) * RentRate * account::size > account::lamports の場合、アカウントを圧縮し、すべての Ramports を書き込みます。

上記の解決策は、時間の経過とともに未使用のアカウントが最終的に lamborts 0 に達し、圧縮されるため、State を安価にするはずです。したがって、データのオーバーヘッドが削減され、さらにインデックス作成のオーバーヘッドも削減され、現在の状態のサイズが縮小します。状態のサイズを縮小すると、超二次割り当てのコストが削減されます。