
Solana: ZK Compression調査
この記事はSolana Advent Calendar 2024の19日目の記事です。
Superteam JapanのDiscordでトークンのエアドロップするときに、それにかかる費用を下げる方法はあるか?という質問があり、回答としてZK Compressionベースのairshipを使うと安くなるという話がありました。
_人人人人_
> 何で <
 ̄Y^Y^Y^Y^ ̄
というので調べることにしました。
疑問に思ったこと
まず前提としてエアドロップを行うのに必要な手数料は下記です
トランザクション送信にかかる手数料(fee)
送り先の関連トークンアカウントの家賃(rent)
送信先の数だけ家賃が必要
ZK CompressionはcNFTsなどで利用されており、大量のアカウント作成時に家賃を減らすことができる技術です。(参考: https://zenn.dev/ki4themecha2q/articles/7dcb9753783a23)
そのため、今回のケースでも有効に思えるかもしれませんが、関連トークンアカウントはトークンプログラムが管理するアカウントです。
そのアカウントを圧縮してしまうとトークンプログラムから呼び出せない、操作できないアカウントになってしまう気がします。少なくともそのあたりをフォローした実装を見た記憶はありません。
というので圧縮することで家賃を減らすことができるのはわかる。わかるが、何でそれでトークンプログラムが動作するのかがわからない・・・!この疑問を解決するのが本記事の目的です。(これを書いている時点ではまだ解決していません)
3行まとめ
ZK CompressionはSolana上でアカウントの状態を圧縮できる
圧縮されたアカウントは専用のプログラムとRPCを介して扱うことができる
専用のプログラムが必要になるのでサポートしていないクライアントでは利用できない
ZK Compression概要
ZK Compressionの目的は「オンチェーン状態を圧縮して格納し、コストを大幅に削減する」ことにになります。
つまりデータ部をState TreeとしてSolanaチェーン外に保持し、Solanaチェーン上ではState Treeのハッシュを保持することでアカウントサイズを圧縮します。
ZK証明を活用することで、圧縮された状態が正しいことをオンチェーンで検証し不正な状態にならないことを保証しています。
これらの仕組みは専用のプログラムと専用のRPCを利用することで実現しています。
そのため、最初の疑問にあったトークンプログラムで扱えなくなるというのはまさにその通りで、専用のプログラムと専用のRPCに対応したクライアント(ウォレット)を使うことでトークンプログラムと同様の動作を行うことができるもののようです。
専用のプログラム
ZK Compressionにおいて重要なポイントは、圧縮アカウントを直接Solana標準のトークンプログラムで操作するのではなく、専用のプログラムを使うことです。
この専用プログラムにはLight SystemプログラムやCompressed Tokenプログラムなどが用意されています。
RustのドキュメントでInstructionを確認するとトークンプログラムに似たようなInstructionが提供されていることがわかります。
プログラムの実装を見るとCompressed Tokenプログラムから、専用のCPI用プログラムを呼び出し、そこから対象のプログラムを呼び出すという動きのようです。
(Instructionにトークンプログラム、システムプログラムを指定する口があるので最終的にトークンプログラムが呼ばれると想像していますが、本当にそうかまでは読めてません)
圧縮アカウントとは
圧縮アカウントはオフチェーン上に保持される木構造のデータです。


Solanaのアカウントアドレスの代わりにハッシュが使われ、データが変わる度に新しいハッシュに変わり、
もしアドレスのように固定された一意のキーが必要であれば別途アドレスを付与することもできます。
専用のRPCの役割
専用のRPCでは主に2つの役割があります
圧縮アカウントの情報をクライアントに提供する
圧縮アカウントの有効性を証明する
1は圧縮されたアカウントの情報をクライアントに提供することで、例えばアカウント内の残高はいくらかといった情報を渡し、新しいトランザクションを作成できるようにします。
2は圧縮アカウントの有効性を検証するためのZK証明を提供し、それを含めてオンチェーンに送信することで圧縮アカウントが正しいデータを保持していることを証明できるようにします。(本当か?ちゃんとわかってない)
実際にクライアントから呼び出す例
詳細はドキュメントを参照。
ZK Compressionの制約、注意点
ZK Compressionはアカウントサイズを削減できる、家賃を節約できるという利点はありますが、トレードオフも存在します。
サポートしていないウォレットやアプリケーションで利用できない
Solanaの利点はプログラムやアカウントの再利用性の高さがあると思っていますが、ZK Compressionを利用するとZK Compression経由でしかそのアカウントを扱えなくなります(最近のウォレットなどであれば普通にサポートしているとは思いますが)
トランザクションサイズは増加する
Solanaではトランザクションサイズ上限があるため、これを超えないにしなければなりません
Compute Unitの増加
有効性の証明などでCUは必要になります。転送を例にすると29万2千CUが必要になります
高頻度のアクセスなど向かないユースケースもある
個人的な印象では初めに大量の生成を行い、あとは滅多に更新されないものではとても有効に使えそうだと思いました。
cNFTsなんかまさにというユースケースですよね。
まとめ
というわけで、最初の僕の疑問に答えるなら「お前の考えは間違っていない。あっている。」と言うところですね。
ZKのためにノードに証明の仕組みを入れているとは思っていましたが、まさか専用プログラムと専用RPC構成で、アカウントを別管理しているのは完全に想像の範囲外でした。
(Agave 2.0でこの辺の汎用的証明機構が入りましたが、それより前からある仕組みなので)
仕組み的にDEXやDeFi側もサポート入りそうだけどどうなんだろ、別に通常のアカウントへのマイグレート機構が必要だったりするのかなとか、いろいろ疑問は残っていますが、一旦概要は確認できたので満足できました。
とりあえず、どこかで時間ができたら実際にコードを書いて遊んでみたい気持ちでいっぱいです☺️