Solana Developer Hub #2: コントラクトを作らないブロックチェーンアプリケーション開発
この記事は2023/1/27に開催したSolana Developer Hub Online #2で話をさせていただいた「コントラクトを作らないブロックチェーンアプリケーション開発」を再編集したものになります。
コントラクトを作らないブロックチェーンアプリケーション開発
私はSolana 大好きおじさんやってます
ブロックチェーンをやってみたいって思う方は多いと思います。
しかし、スマートコントラクトって何か怖そう・・・ハッキングを受けてという話があったり、従来のWebアプリケーションやモバイルアプリケーションと作り方も違う。
しかも、SolanaはRustという一般的には難しいといわれる言語を使わないといけない。
その気持ちはとてもよくわかります。
ただでさえ新しいことをやるのに、そこにさらに難しさがあるのは手を出しにくいです。
でも、実はブロックチェーンアプリケーションを作りたいというときに、スマートコントラクトの開発は必須ではありません。
難しいなら難しくない方法でブロックチェーンアプリケーションを開発してみましょう。
ブロックチェーンを使うメリット
方法の話をする前にブロックチェーンを使うメリットはどのあたりにあるのかを紹介します。
で、その話をするためにも、まずSolanaチェーンの仕組みを簡単に解説します。
Solanaチェーンの仕組みはだいたいこのような形です。
クライアントからSolanaネットワークに対してトランザクション送信すると、プログラム(スマートコントラクト)が呼ばれます。
このプログラムの実行した結果をネットワークにデータを返すとチェーンに書き込まれるという仕組みになっています。
データの扱いを図で書くと、このような形でプログラムがアカウント(データ)を扱います。
アカウントを書き込むには必ずプログラムを通してしか書き込めせん。
また、アカウントはどのプログラムが所有しているのか情報を持っており、その所有しているプログラムからしか書き込めないようになっています。
このアカウントというのはデーターベースでいうレコードみたいなものになります。
プログラムはデータベースで言うプロシージャや、Web API、FaaSみたいなものを想像してもらうとイメージをしやすいかもしれません。
このように捉えていくと、ブロックチェーンというのは分散キー・バリューストアみたいなものともいえます。
このプログラムは誰でも実行することができますし、そのプログラムがチェーンに書き込んだアカウントは誰でも参照することができます。
ということはユーザーはどのプログラムを実行してもいいし、どのアカウントを参照してもよいということです。
例えばプログラムは個人の開発者や組織が提供しています。
Solana Labsが管理しているトークンプログラムや、Metaplexが管理しているNFTのためのプログラムなどいろいろなプログラムが存在しています。
これらを組み合わせて呼び出したり、組み合わせて参照して自分の使いやすいアプリケーションを作ることができます。
つまり、コントラクトを作るっていうのは、オープンなAPIとデーターベースを作るようなものです。
そのため、WebサービスなどでAPIが提供されているさいに、それを使って自分たち用のアプリケーションを作るのと同じようなことができます。
例えば、Web UIが提供されているブロックチェーンアプリケーションがあると思いますが、そのUIが気に入らないから新しいUIを作る。他のプログラムなどと組み合わせて新しいUXを作るなんてことをしてしまっても構いません。
プログラムの提供者次第ではありますが、そういうのを作られるのは結構歓迎されるとは思います。少なくとも私はそういうことをしてもらえるのはとても嬉しいです。
ここまで仕組みを見たうえで、ブロックチェーンを使うメリットは何があるかというと、いくつか考えられます。
まず、一つ目はネットワークは生きている限りは動作し続けるっていうのがあります。
90年代や00年代のインターネットを知っている方は感じていると思いますが、その頃にあったサービスなどがなくなってしまい、見れなくなった、使えなくなったものがいろいろとあります。
二つ目の話にも関わる話にはなりますが、サービスを構築して運用を続けるにはどうしてもお金がかかってしまい、お金が払えなくなる、払う価値がないとなるとそのサービスは継続できなくなってしまいます。
それに対して純粋にブロックチェーンだけでアプリケーションを作ると、ネットワークが存続する限りは残り続けるので、残すことができるという利点があります。
二つ目は初回のリリース時や変更のさいにトークンが必要にはなりますが、毎月支払いが必要だったり、ユーザー数の上下で金額が変わることはないので運用にかかる継続的なコストがありません。
ここは私のような個人開発者にはすごい推したいポイントで、コストがかかると生活を圧迫するし、仮にサービスを当ててもコストをかけられなくて継続できないとなってしまいます。そうならないように作れるというのは嬉しいです。
ただ、ここのコストはユーザーが代わりに負担することになるので、どのようにUI/UXを構築するのかは難しいポイントになると思います。
三つ目は先ほど複数のプログラムを組み合わせて作る話をした通り、複数のプログラムやアカウントの連携がしやすいです。
Webアプリケーションとかであれば、そのそのアプリケーションを提供し
ていないとできませんが、ブロックチェーンの場合は公開が強制されるので、意図しなくてもそういった形にすることができます。
四つ目は三つ目の話にも関わりますが、公開性の高さからコラボレーションを生みやすいというのがあります。元のプロジェクトから派生してプロジェクトを始めて新しいコミュニティが形成されたり、プロジェクト同士で新しいことを始めるなどがとてもやりやすいです。
簡単にまとめると、私が死んだ後も続くものを作れが可能性があるみたいなところに私はとても魅力を感じています。
ただ、メリットばかりではなく、やはりデメリットは存在します。
まず、ユースケースが合う、合わないというのははっきり出ます。
レイテンシやスループットの上限、データサイズの制限など一定の制約がかかります。
他にもこの後に紹介するデメリットの兼ね合いもあって、合うユースケースはかなり狭い印象です。もちろん今のブロックチェーン業界全体で新しくできるユースケースを増やしているので将来的には改善される可能性は十分にあります。
次にUI/UXはかなり考えて作らなければなりません。
特にウォレットを持っていない人に対してどうやってウォレットを入れてもらい、トークンを手に入れてもらうかという動線が本当に難しいです。
もちろんそういった人たちをターゲットにしないというのも1つの手ではありますが、より大きな母集団にリーチしたいと考えるならここは外すことはできません。
三つ目はアカウントの取得の柔軟性はかなり低いです。
ブロックチェーンの多くは分散キー・バリューストアって言った通り、キーをベースに値を引っ張ってくるような仕組みになってます。
そのため、特定の条件で絞り込みしたデータを一覧で持ってくる方法はちゃんと考えて設計しないといけません。
四つ目は、公開性の高さの代償に非公開情報を取り扱うことが難しいことです。
特にプライバシーの問題は難しく、単純なところでは自分の資産状況が把握されてしまうことだったり、画像データを取り扱うさいにそれがデジタルタトゥーとして使われてしまわないかなど開発者は考慮しないといけません。
ただ、このあたりは先日発表のあったToken Extensionなどのように業界として完全な解決ではないものの改善の傾向はあると思います。
ゼロ知識証明や秘密計算と呼ばれるものなので興味がある方は調べてみていただくと楽しいと思います。
ブロックチェーンから読み込むアプリケーション
それでは、ここから本題であるブロックチェーンを扱うアプリケーションの話になります。
まずはプログラムで書き込まれたアカウントをアプリケーションでどのように扱うかですね。
アカウントを読み出す方法を幾つかあります。
一つ目がRPCリクエストで、これが一番低レベルな読み込み方になります。
SolanaネットワークではJSON RPCエンドポインが公開されており、そのエンドポイントに対してHTTPリクエストする方式です。
二つ目がRPCリクエストよりもう少しだけ高級な呼び出し方で、Solana SDKやWeb3 JavaScript APIといったライブラリを使う方法です。
公式ではRustのSDKとJavaScript用のWeb3 JavaScript APIというライブラリが提供されています。他の言語は非公式な形にはなりますが、だいたいどの言語にもある印象です。
三つ目は各プロダクトが提供しているライブラリを使う方法です。
では、まずRPCリクエストでどのようにアカウントを取得するのかを見てみましょう。
これはcurlというCLIでHTTPで通信するためのツールでの例になります。
RPCのコマンドとして getAccountInfo というコマンドがあり、これを使うと指定したアカウントのアドレスに対応するアカウントを取得できます。
他にも getMultipleAccounts というコマンドで複数のアドレスを指定してアカウントを取得することもできます。
ただ、ここで取得できるのは指定した形式でエンコードされたバイナリデータになります。
そのためこの例で言えば、base58でデコードしてバイナリデータにして、そのバイナリデータをそのデータ形式に合わせてデシリアライズすることで初めて扱えるデータになります。
そのため、こういう呼び出し方をするのは手間が大きいので、あまりおすすめしません。
ただ、こういった低レベルの操作を覚えていて損はないので、頭の片隅にでも入れておくと役立つことがあると思います。
他のアカウントの取得方法として getProgramAccounts というコマンドもあります。
指定したプログラムが作成したアカウントを全て取得できるというコマンドです。
getProgramAccounts では params に dataSlice や filters というパラメータを指定して取得するアカウントを絞り込むことはできます。
ただし、注意点としてはページネーションすることはできません。
上手くプログラムとアカウントを設計すればページネーションできるかもしれませんが、私は今のところそこまでやっているプログラムを見たことはありません。もし、あれば設計の参考にしたいので教えてください。
次はもう少し高級な呼び出し方を見てみましょう。
Web3 JavaScript APIを使って同じ getAccountInfo を書いたものになります。
さきほどのRPC呼び出しと違い、記述量が減ってRPCエンドポイントとアカウントのアドレスだけで取得できることがわかると思います。
また、IDEやエディタではコードの補完ができるため、書きやすさという点でもかなり上がっています。
例ではそこまで記載していませんが、こちらもRPCリクエストと同様にバイナリデータからのデシリアライズは必要になります。そのあたりの難しさは変わらないため必要性がない限りは使わないことをおすすめします。
もちろん、必要に迫られるケースはあるので、書き方としては覚えていくとよいです。
公式としてはRustのSolana SDK、JavaScriptのWeb3 JavaScript APIが提供されている形なのでどちらで使うのが無難ですが、他言語にあるライブラリが悪いわけではないので利用されるユースケースに合わせてどうするかを決めていただくとよいです。
最後に最も高級な各プロダクトが提供しているSDKを見てみましょう。
各プロダクトのSDKはそのSDKがどのような形で提供しているかで変わります。
例はPyth NetworkのJavaScript SDKでの例で最新の通貨ペアの価格をリアルタイムで取得する例になります。
RPCリクエストやSolana SDKと違いバイナリデータを扱う必要がなく、デシリアライズ後のデータを取得することができています。
onPriceChange のコールバックで受け取っている product と price がそれになります。
プロダクトのSDKを使うことでやりたいことをすぐ実現できるのが利点です。
ただし、どのようにアカウントを取得できるか、期待している方法で取得できるかはプロダクトのSDKの実装に依存しています。
そのため、本当はこういう形で取得したいのに、プロダクトのSDKの実装では取得ができないのでSolana SDKを使うというケースは十分に起こります。
実際に起きたケースだと、通信量の最適化のためにPyth Networkでユーザーの指定した特定の通貨ペアの価格情報だけを取得したいけどできないというのは遭遇したことがあります。
このときはSolana SDKを使って直接アカウントから情報を取得するようにしたので、特定のSDKを覚えるだけでなく、低レイヤの方法も知っていると対応に幅を持つことができます。
また、利用しているプログラミング言語でSDKが提供されていないケースでは、こういったSDKを自前で実装することになります。
そのときはプログラムの実装を解析したり、他のSDKの実装を元にコードを起こすことになります。
そういった意味でも低レイヤを覚えておくと得ですし、SolanaならRustやJavaScriptを書けないまでも読めるようになっていると、こういった作業をやりやすくなります。
先ほども少し話しましたが、やはり分散キー・バリューストア特性を持っているので一覧や検索というものは弱いです。
対策としてはいくつかありますが、どれもトレードオフが発生することに注意してください。
まず、BigQueryのPublic DataにSolanaが対応しているため、そちらを元に一覧、検索用のデータセットを構築することも考えられます。
この場合は、それを定期更新することで最新データへの追従ができそうです。(未検証)
次にShyftなどSolanaネットワークからデータを取得できるAPIを提供しているSaaSを利用することです。
2024/01時点ではアカウントデータに対応しているのはShyft以外にこういったSaaSは僕はみたことがないです。今後はエコシステムとしてこういったツールが増えると嬉しいですね。
最後に、自前でサーバーを構築して、自力でトランザクションやアカウントを元に一覧、検索用のデータベースを構築することです。
これが最も柔軟でどんなユースケースにもあわせることができますが、サーバー費用や運用コストなどが必要になることを注意してください。
特にリアルタイム性が必要なさいには、フェイルオーバーは絶対に考慮する必要があり、技術的にも一定の難易度があります。
また、UI/UXとして難しさは出ますが、クライアントであらかじめ全てのデータをロードするというの一つの手です。
ただし、この場合は初回描画でユーザーにどのように見せるか、段階的に読み込むにしてもユーザーにガタつかないようにどう見せるのかなど、考えるポイントは増えます。
もしくは、こういった一覧や検索を必要としないように構築するというのも手になります。
総じて言えるのはどういったユースケースを実現したいのか。そのユースケースに合わせて最適な方法はどれなのか考えることが重要です。
一覧、検索は弱いですが、リアルタイムにデータを反映するのは強いです。
SolanaのRPCではWebsocket APIを持っており、そちらを使うことでプログラムが管理しているアカウント、特定のアカウントの変更を受け取ることができます。
"リアルタイム"と言ってしまいましたが、実際にここのパフォーマンスを検証した訳ではないので実際には準リアルタイムだったり、大きな遅延が発生するということは起こり得るかもしれません。
また、Websocketでは常に最新の状態を取得します。そのため、ローカルに保持しておいた状態から差分を更新したいみたいなユースケースでは使うことができないので注意してください。
最近、私が悩んでる話ではありますが、RPCリクエストを受け取る公開エンドポイントは制限が強く使えないケースがあります。
公式のドキュメントでは制限について記載があり、呼び出し回数やデータ量で制限があります。
特にMainnet Betaではドキュメントにも載っていないケースで制限にかかることもあり、ドキュメントを読んだだけで使えると判断すると事故にあいます。
このように制限がかかるケースでは専用のRPCノードを立ち上げてください。
HeliusやAlchemy、QuickNodeなど手軽に立ち上げることができるサービスを活用するのをおすすめします。
ただ、個人的にはそういったサービスを使ってしまうと、私が死んだタイミングで契約が切れてしまい、死んだ後も継続して動くものを作るという目的から外れてしまうのでどう解決するかは悩んでいます。
もちろん、RPCノード自体は交換可能でユーザーが指定すればいい話ではありますが、もう少し分散性の高いRPCがあると嬉しいなと思います。
また、余談にはなりますが、RPCノードを立ち上げるサービスに迷ったらこちらの記事を読まれることをおすすめします。
ここまでの話を踏まえて、ちょうど作っているアプリケーションがあるので、ユースケースの1つとして紹介します。
こちらはスタンドアローンで動作するSolana Payを実装したアプリケーションになります。
簡単に説明すると、左側の電卓で入力した金額に合わせて、Pyth Networkから取得した価格情報を元に必要な送信数を計算して、Solana PayのTransfer Requestに対応したQRコードを生成するというものになります。
こういったユースケースであれば読み込みだけでも十分に実現できます。
ブロックチェーンに書き込むアプリケーション
読み込みの話をしたので、次は書き込みの話をします。
読み込みだけでもブロックチェーンアプリケーションは作れますが、やはり制約が強く書き込みもしたくなってきます。
書き込みでもRPCリクエストや、Solana SDKの利用はできますが、実際にやるとなると各プロダクトのSDKを利用するの一択だと思います。
というのが、読み込みと違って、書き込みではやらないといけないことが多く手間が大きいです。
書き込みの流れとしてはウォレットに接続して、トランザクションを作成して、署名して、Solanaネットワークに送信するという処理をしなければなりません。
ここでトランザクション内に含めるインストラクションではプログラムが期待するバイナリデータを生成しないといけませんし、インストラクションではプログラムが期待する順序でプログラムが利用するアカウントを指定しないといけません。
他にもアカウントが署名されていることを期待されているなら、そのアカウントを署名するために必要な鍵を指定したりと本当にやることが多いです。
とはいえ、この辺りもおすすめはしないというだけで、読み込みと同様に知っていて損はありません。
もし、知りたいという方向けにWeb3 JavaScript APIのドキュメントのリンクを置いておきます。
というわけで、各プロダクトのSDKの方法だけ紹介します。
こちらの例はMetaplexでNFTをMintする例になります。
Metaplexの場合は事前に用意したCandyMachineというものを使い、NFTをMintしてそのNFT情報を取得するような動きになります。
本当に必要最小限のサンプルコードにはなっているので、もう少しちゃんとしたコードを見たい方はGitHubのサンプルを見てください。
読み込みの方でも言いましたが、どのように使うかはSDKによるので注意してください。
注意点として書き込みはウォレットと、家賃や手数料としてSolanaトークンが必要になります。
DevnetやTestnetではAirdropでトークンを取得できますが、Mainnet Betaではトークンを別途用意しないと書き込めないので注意してください。
ウォレットが別途必要になるということは、先ほども話した通りどのようにユーザーにウォレットを見せるのかは本当に考える必要があります。
定番はブラウザのエクステンションや、ウォレットアプリで接続をすることです。
ただ、やはりウォレットを持っていない人にそういったアクションをしてもらわないと使えないというのは障壁になってしまいます。
そこで例えばサーバーサイドでウォレットを管理したり、ブラウザ内のストレージに鍵情報を保管してしまうというのも選択肢になります。
ただ、こういった方法はセキュリティなどのトレードオフが発生します。また、サーバーサイドで管理する場合はそこに生殺与奪を握られてしまいます。
そのため特にDexやDeFiなどユーザーの資産に直結するようなユースケースでは選択するの難しいです。逆に、音楽などコンテンツを消費する系のアプリケーションではウォレットの流出や盗難されたさいのリスクが小さいと考えて簡易的な方法を選択することを考えてもいいかもしれません。
このあたりはゼロ知識証明を使って改善する動きもあるため、興味がある方はAccount Abstractionなどのワードで調べていただくと楽しいかと思います。
まとめ
プログラムを作らないでもアプリケーションを作れます。
ただし、プログラムを作らないのと比べると自由度は下がってしまいます。
とはいえ、気軽にブロックチェーンアプリケーション作ってみたいというユースケースにはすごい刺さるかなと思うので、ブロックチェーンアプリケーションを作ってみたいという方はこういった方法で試してみると楽しいと思います。
何でもは作れないです。特に制約が強いのでユースケースの選定がとても重要になります。
ただ、今後もエコシステムは発展していくので、このユースケースの選定の難しさってのもどんどん減っていくとは思います。
例えば、先日発表のあったのToken Extensionがでたことで、これまでプログラムを作らないとできなかったことができるようになりました。
また、ユースケースを選定するためには情報収集は結構大事になります。
僕は最近よくSolanaのBreakpoint 2023の動画を見ているのですが、これを組み合わせると面白そうとか、こういうことができるんだと知ることができるので、一定のアンテナを貼っておくと楽しいと思います。
Q&A
Q. EVMではプログラムはイーサスキャンで見れますが、Solanaもプログラムは見れるのでしょうか?
まず、ソースコードを公開しているケースでは見ることができます。
エクスプローラーもツールによってはソースコードを見る機能があり、おそらく登録などしていると見れる形だと思います。
ただ、公開してないから大丈夫かというとそんなことはなく、SolanaではBPFと呼ばれる形式にしてプログラムとしてSolanaネットワークに登録され、それは誰でも取得可能になります。
そのため逆アセンブルするなどで動作の解析はできる可能性が高いです。
※ このあたり不勉強なので正しいかはわかりません
Q. 要するにアプリ作りたかったらフロントはがんばれということですよね笑
その通りです。これはどの分野のアプリでもそうですがUI/UXにダイレクトに直結するのでこれはがんばらないといけないです。
余談ですが、フロントエンドを触れる人は多いですし、サーバーサイドを触る必要がないのでオープンなAPIやDBを扱うというのは遊びやすくていいんじゃないかなと思います。
Q. 自分が死んだ後も動くプログラムを作ろうとしたらチェーンへの書き込みは頑張る必要があるということであってますか?
既存のプログラムで十分な場合はがんばらなくても大丈夫です。
例えば読み込みのところで紹介したSolana Pay実装のアプリケーションなどでは僕がいなくなっても動作し続けると思います。
ただ、利用しているPyth Networkのアカウント構造が変わるなどすると動作しなくなるので、プログラムを自作して書き込みをするとそういうった問題が起きずに済むというのはあると思います。