tomoima525's blog

Androidとか技術とかその他気になったことを書いているブログ。世界の秘密はカレーの中にある!サンフランシスコから発信中。

ブロックチェーン知識ゼロから Solana ハッカソンに参戦するまでの学習記録

f:id:tomoima525:20211021141217p:plain:w400

つい先日、Solana というブロックチェーンを使ったオンラインハッカソンに参加し、1 つのプロダクトをローンチしました。この記事はブロックチェーンについて全く無知の状態から2ヶ月後にスマートコントラクト(Solana ではプログラムと呼びます)を書き、アプリケーションをリリースするまでの記録です。

この2ヶ月ブロックチェーン界隈では NFT の流行を筆頭にさまざまな出来事があり、それらもかいつまんで振り返ってます。ブロックチェーンの知識がなくても 大丈夫なように用語集やコラムも添えました。だいぶ長くなっちゃったので、用語とコラムは後から読むのを推奨です。

それではどうぞ!

成果物

Solana ブロックチェーン上にエスクローエージェントを生成しそれを介して NFT を安全に取引できるサービスを開発しました。

https://www.sol-hayama.com/

f:id:tomoima525:20211021141800p:plain:w400

  • Solana では metaplex など特定のマーケット経由でしか取引できない
  • 買う側がオファーを出せない
  • ガス代が低いために詐欺が多く、ユーザー間の直接取引が安全でない

といった問題を解決しているサービスです。コードは以下に公開しています。

GitHub - tomoima525/sol-hayama: NFT - Token Escrow service for Solana

もしよかったら以下の Hackathon のイベントページにて Like してくださると嬉しいです!

devpost.com

はじまりは 退屈なサルと暗号ゾンビ

ブロックチェーンに興味を持ち始めたのは、Bored Ape Yached Club を始まりとする NFT コレクタブルの上にコミュニティが構築されているという記事がきっかけでした。

gigazine.net

7 月はちょうど NFT が2度めの盛り上がりを見せ始めた頃合いで、事業アイデア探索の一環として、技術的な観点から NFT、ブロックチェーンのリサーチを開始しました。 最初ブロックチェーンや dApps へのとっかかりがわからず、実際に Ethereum のアプリケーションに触ってみるにはどうしたらよいかわからなかったのですが、幸いにもブロックチェーンに詳しい友人がいたので相談したところ、"Crypto Zombie"なるチュートリアルを教えてもらいました。

cryptozombies.io

f:id:tomoima525:20211022065852p:plain:w300
わいの暗号ゾンビ

これは Crypto Zombie という Ethereum ブロックチェーン上のゲームの実装を通じて、Ethereum のプログラム言語である Solidity や開発ツールについて学ぶことができるサイトです。今振り返ると少々ツールなどは古くなっている印象もありますが、ブロックチェーンのスマートコントラクト開発の概要や基本を理解するには今でも最高の学習素材だと思います。

ちなみに、安全なコントラクトを書くのは厳しいなというのが、このチュートリアル完了後の Solidity に対する自分の率直な感想でした。というのも Solidity はコントラクトを何層にも渡って継承するため、それぞれのコントラクトにおける関数の振る舞いや変数の状態について把握するのが非常に難しく、容易にバグを生み出しやすい構造になっています。実際スマートコントラクトには他のコントラクトをコピーする文化がある*1のですが、セキュリティイシューなども一緒にコピーされているケースがあるなんて話も。
この点 Python で実装された Vyper はより安全なコントラクトを書くことに主眼が置かれており、自分ならコントラクトを書くならこちらを選択したいです。

Vyper — Vyper documentation

Vyper.fun | Learn Vyper by building games

(チュートリアル版権モノのキャラクターを使っている辺りまだ未熟さはありますが…)

この時期身銭を切っていろいろなブロックチェーンサービスを試してみました。Lending や staking といったよくある Defi サービスはもちろんのこと、仕事を受けるとトークンがもらえる Braintrust に登録してみたり、Play to Earn(またの名をデジタル小作農)が流行っていると聞けば Axie に送金してゲームを始めるのに$900 以上必要なことに嘆いたり、よく考えず NFT を買って価格が 1/3 以下になったり、まーいろいろ経験しました。で、わかったことは、この業界にはとんでもない量のお金と人が集まってきていることです。バブルといえばそれまでなんですが、この熱狂には奇妙な魅力があるなと思いました。

Braintrust は登録すればだれでも 20 トークンほどもらえるので、トークンが何ぞやという人は以下のリンクから登録してみるとよいです。トークンは Coinbase などで売ることができます。

app.usebraintrust.com

用語集その 1

  • トークン ... いわゆる暗号通貨。ブロックチェーンの上のデジタルアセット。Ethereum では ERC-20 の仕様を満たしている。
  • dApp ... decentralized Application。主に Ethereum上に作られたアプリケーションを指す。
  • Lending ... 自分の持っている暗号通貨を預けることで、利息をもらうサービス。人気のある通貨だと年利 数百%に達することも。預けた通貨は通貨の交換に利用され、その利用料の差分が報酬になっている。
  • Staking ... 自分の持っている暗号通貨をブロックチェーンノードに貸すこと。Proof of Stake コンセンサスで利用される。
  • NFT ... non-fungible token。貨幣などとちがって代替ができないデジタルアセット。Ethereum では ERC-721 という規格でトークンとしての仕様が定義されている

コラム 1: 開発者目線でみるブロックチェーン

開発者目線で Ethereum などのメジャーなブロックチェーンを言い表すと"従量課金型パブリッククラウド開発プラットフォーム(認証は利用者まかせ)"なのかなと思います。

ブロックチェーンは誰でもプログラムをデプロイできて、巨大な DB はどんなデータであろうと書き込みや読み込みも自由自在。ただしすべてのデータはパブリックな上に、書き込み量に応じて利用者に課金されるので開発にはセキュリティやデータ量について注意が必要なわけです。認証に関しては、各エンドユーザーが non custodial wallet で private Key を持つことで責任を分散化し、サードパーティの認証認可を不要としています。これをトラストレスと呼びます。

Solana Summer

さてそんなふうに Ethereum のブロックチェーンについて学びを深めている間にふって湧いたように起きたのが空前の Solana ブームです。きっかけは degenenate ape academy という NFT が Solana でリリースされたことだと思います。

f:id:tomoima525:20211022065008p:plain:w400

www.degenape.academy

Solana の特徴はガス代が非常に低いこと、トランザクション速度が現行のブロックチェーンでも最速であることから、Ethereum 上のガス代の高騰にうんざりしていた人たちが一気に流れ込んできました。まだ mainnet もベータですが、雨後の筍のように NFT プロジェクトがローンチし、Solana の暗号通貨である Sol の価格も一ヶ月で 3 倍以上になりました。取引量が増えると貨幣の流動性を保つためにレンディングサービスの利息が上がり、さらに資金が流入するという猛烈なマネーサイクルが回りだしました。

f:id:tomoima525:20211021160340p:plain
一年前から9500 % 値上がりしてます

ちなみに速度の指標であるブロック生成時間について、Solanaは 400 msec であり、Eth 1.0 の 10 - 20 sec をはるかに凌駕しています。

自分が Solana に興味をもった点が2つありました。ひとつは Solidity よりも安全にスマートコントラクトがかけそうなこと、もうひとつは Solana が Rust で書かれていることです。
安全にスマートコントラクトがかける理由としては、Solana では状態とロジックが分離されていることが挙げられます。Solana のスマートコントラクトはプログラムと呼ばれますが、このプログラムには状態を更新する機能、すなわちコントラクトのロジックしか持ち合わせていません。プログラムも含めてあらゆるステートはアカウントと呼ばれ、アカウントは Solana ブロックチェーンにステーキングすることで存在できます。

この状態とロジックが分離されているというのは Solidity と大きく異なる点です。Soildity の複雑性は状態も Solidity のコード上で定義されるがために生じているし、コントラクトの変更も困難です。Solana は非常にシンプルにプログラムを実装できるだけでなく、プログラムの変更も容易です。 興味をもったふたつめの理由については、常々 Rust に興味を持っていたので、単純にその勉強も兼ねられると思ったからです。実際 Solana を学んでいくと、Rust が処理速度や安全なプログラムを書く上で重要な役割を果たしていると気づきます。その点については次のセクションで話しましょう。

さらに付け加えると、Solana が Layer 1 のブロックチェーンであるというのも魅力的でした。Ethereum 上ではガス代高騰やトランザクション速度を解決するためにもう一段上にブロックチェーンを構築する Layer2 またはサイドブロックチェーンと呼ばれるソリューションがあります。Polygon や arbitrium というブロックチェーンが現在人気ですが、ブロックチェーン間でデータをやり取りすることが困難だったり、それぞれに独自のツールがあるために学習コストがかかるなどの課題があります。Solana のような Layer 1 ブロックチェーンであれば一度学べばあらゆるブロックチェーン上のサービスが扱えるので ROI がとても高いです。

用語集その 2

  • mainnet ... ブロックチェーンの本番環境。一般的なブロックチェーンには検証環境の testnet, 開発環境の devnet などが存在する。
  • ガス代 ... ブロックチェーンで取引するためにかかる手数料。Ethereum は書き込むデータ量や優先度合いでガス代が変化する。
  • Solana の Staking ... ストレージの利用料であり、英語では rent fee(貸し代)と呼ばれる。各バリデーターがブロックというトランザクションの塊を持ち、その取引をメモリやハードウェアに保持する報酬として rent fee が支払われている。

Solana ことはじめ

Solana のコードはすべてオープンソースであるだけでなく、ERC-20 に準拠したトークンのような基本的な機能やアカウントはすでに Solana lab によって開発されています。ブロックチェーンへのアクセスは JSON-RPC の API が提供されているだけでなく、Solana 版 web3.js もあります。自分はまず web3.js を使った Example である以下のチュートリアルを眺めて振る舞いを学ぶことからはじめました。

その後作ったトイアプリがウォレットに接続すると取引履歴が参照できるビューワーです。

GitHub - tomoima525/solana-transaction-tool: Simple transaction tool for Solana Block Chain

さらに公式ドキュメントを流し読みすることで、なんとなく Solana におけるブロックチェーンの挙動が理解できました。
公式ドキュメントはアーキテクチャといったかなり深い内容まで網羅されているので、すべてに目を通さず、まずはターミノロジーcli などのツールの使い方などから読むのが良いと思います。

その他に最初に役立った動画や資料を紹介すると

www.youtube.com
web3.js の基本的な振る舞いや簡単なプログラムの挙動を理解する助けになりました。

www.youtube.com
Solana lab のソフトウェアエンジニアが Solana のターミノロジーアーキテクチャについて説明しています。アカウントの概念はこれが一番理解できました。

コラムその 2: Solana はなぜ速いのか

Solana が速い理由はそのコンセンサスの仕組みにあります。これだけで一つの記事になってしまうので、ここでは短く説明すると、Solana では Proof of Stake に加えさらに処理速度を最適化した Proof of History という仕組みを導入しているためです。

Proof of Stake は Ethererum2.0 でも採用されているコンセンサスの仕組みで、ステークされた暗号資産の量に基づき次のブロックを作るバリデーターをランダムに選ぶことで、Proof of Work で時間がかかっていたマイニングと同期が不要になり、従来のProof of Workより高速化しています。Proof of Stake の課題として各ブロックの timestamp にノードのマシンパワーなどの影響でズレが発生し、ノード間のブロックの順番が狂う可能性があります。これに対処するために wall of clock という複数の timestamp の中央値を基準とすることで、同期をとっています。

Proof of History ではリードノードと呼ばれるノードが timestamp をブロックに書き込むことで、"少なくとも各ブロックはこの timestamp より前/後に生成された"ことを担保に各バリデーターがトランザクションチェックを行うという手法を採用しています。この結果各ノードの同期時間が不要になり、高速化されています。

参考資料:

用語集その 3

Solana ではじめる Rust

次のステップとして Solana のプログラムを読み始めました。一番簡単な例はレポジトリにある hello-world です。
ところがこれが全然わかりません。例えば以下のようなコードがあります。

#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    pub counter: u32,
}
pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult { ... }

[derive()] は  Solana が提供しているものなのかはたまた Rust が提供しているものなのか、引数はなぜ &[] で渡されているのか、などなど、なにもわからない状態でした。

そこでひとまず Rust のキャッチアップからスタートしました。まずは Learn Rust という本がありがたいことにオンラインで配布されているので、それを読み始めました。

Learn Rust - Rust Programming Language

5 章まで目を通した結果、Rust の重要な概念である Ownership についてぼんやりと理解できました。Learn Rust は非常に良いガイドですが、ここで日本語でもう一度読んで理解をしたいと思い、日本語の本を購入しました。

本書は Rust の基本だけでなく、開発する web アプリケーションや組み込み例などについても書かれており、勉強になりました。しかし Ownership や trait などについてはあっさりとしか触れられておらず、Solana で使われているような実装例についてはほとんど触れられていません。もっと踏み込んだ内容を学びたいと思い次に買ったのはこの本です。

レビューでは途中のガイドが長大すぎる、というコメントがいくつかありましたが、その後の言語仕様の解説は深い理解に基づいた詳細な説明で、仕組みを理解する上で大きな助けになりました。こと Solana に関して言えば Rust の言語機能をふんだんに利用しているので、個人的には2冊目の方が参考になると思います。

ここであたらめて Solana のプログラムに戻ってみると、ようやく振る舞いがわかってきました。プログラムは、実は非常にわかりやすい構成になっています。

Solana のプログラムはBPFと呼ばれるという kernel 上で実行されるプログラムです。ライブラリ形式でコンパイルされます。

プログラムを読む場合はプロジェクト内の以下の構成を理解しておけば辿れるはずです。

  • lib.rs ...各モジュールをつなげるヘッダ的なファイル
  • entry_point.rs ... エントリポイント。Solana の entrypoint という関数がコールされてインストラクションが実行される
  • instruction.rs ... トランザクションのまとまりをインストラクションと呼ぶ。ここに渡されるデータなどの概要が記載されている
  • processor.rs ... 実際の処理内容

Solana ではデータはバイナリデータでやりとりされるため、データのシリアライズ、デシリアライズが頻繁に発生します。そのため新しいデータ構造を定義する際は厳密にデータサイズを考慮する必要があります。
例えば 1 つのフラグ、3つの Pubkey(Solana のアドレス)、2 つの unsigned 64 bit integer を渡したい場合は 113 byte(1 (bool) + 3 * 32 (Pubkey) + 2 * 8 (u64) = 113) のデータ領域を確保します。

  /// 1 (bool) + 3 * 32 (Pubkey) + 2 * 8 (u64) = 113
  const LEN: usize = 113;
  fn unpack_from_slice(src: &[u8]) -> Result<Self, ProgramError> {
    let src = array_ref![src, 0, Escrow::LEN];
    let (
      is_initialized,
      initializer_pubkey,
      temp_token_account_pubkey,
      initializer_token_to_receive_account_pubkey,
      expected_amount,
      fee,
    ) = array_refs![src, 1, 32, 32, 32, 8, 8];
    ...

この辺は書き慣れた JavaScript などとは勝手が違うので新鮮でした。

写経&写経、Solanaブロックチェーン大停止事件

本来ならこの辺で理解したことを人に話してフィードバックをもらいたかったのですが、あいにく周りに Solana を書いている人はいませんでした。しょうがないので、たんたんとプログラムの写経を行い、それを Solana のコミュニティに投稿するようになりました。

Solana の素晴らしい点は開発チームや利用企業より提供されている機能が非常に充実していることです。NFT マーケットプレイスを簡単に構築できる metaplex や ERC-20 準拠のトークンである Solana Program Library など、教材が山のようにあります。 自分は手始めに metaplex からスタートし、様々な実装パターンを写経していきました。

その記録はこのレポジトリに記録しています。

GitHub - tomoima525/solana-sandbox: sandbox to play around numerous functionalities on Solana

Solana の日本語コミュニティにも更新するたびに投稿していました。(反応はなかったですが...)

f:id:tomoima525:20211021141553p:plain:w400

Solana に関するブログもいくつか読んだのですが、一番勉強になったのは以下のブログです。

Programming on Solana - An Introduction | paulx

エスクローの実装を通じてそれぞれの program や account の役割を理解するのに役に立ちました。

ちょうどこのころ、Solana のブロックチェーンがキューの滞留によって 12 時間以上に渡って停止するという事件がありました。最終的にバリデーターコミュニティの住人たちが立ち上がり、ネットワークを再起動させることでブロックチェーンは復活。世界中のバリデーター達が一丸となってネットワーク再起動に取り組む様子は、サマーウォーズの最後の戦いを観ているような、熱くなる展開でした。

自分は Discord でのやりとりをかたずを飲んで見守っているしかできなかったのですが、開発コミュニティが熱狂的だと思った出来事でした。

質問ドリブン学習

写経の合間に暇を見つけては solana の discord dev-support channel で投げられる質問に答えるようにしていました。多い日は 20 件近くの質問に対応していたと思います。単純な知識に関する質問だけでなく、実装の実現可能性などについても議論したりすることで知識を整理し深めることができたと思います。

f:id:tomoima525:20211021155128p:plain:w400

dev-support channel に頻繁に顔を出していたよかったのは、solana lab のメンバーとつながりができたことです。Hackathon 用のプログラムを mainnet にリリースする折も内部の人に直接相談できたので、質問ドリブン学習はメリットの多い学習方法だと思います。

PM at day and a developer at night

Hackathon 締め切り 2 週間を前にしていよいよ成果物の検討をはじめました。Solana のブロックチェーンが停止したときに慌てた人たちが直接 NFT を交換しようとして詐欺にあっていたのがずっと気になっていたので、NFT をエスクローで取引できる仕組みを作ろうと思いつきました。

前述した paulx のブログはトークン同士のエスクロー実装が解説されていたのですが、キャンセル機能やウォレットの接続方法が存在しない不完全なコードです。目的のツールを作るためには

  • NFT と Sol を交換するために WrappedToken という特殊なトークンを扱えるようにする
  • ウォレットを利用して取引にシグネチャ(取引の認証)を追加する
  • 不要なアカウントを適宜 close し、ステークされた Sol を回収する

などといった機能開発が必要でした。
ひとまず最低限の仕様を決めて、コントラクトの開発から着手し始めました。 ちょうど本業である事業の方もリサーチや仕様策定が立て込んでいたので、開発は夜の 2-3 時間集中して行いました。

f:id:tomoima525:20211021155645p:plain
二週間ごりごりやりました

ブロックチェーン開発で考慮すべき点として、どこまでのデータをオフチェーンにするか線引することがあげられます。個人的な感覚では参照したいデータを設計することがオフチェーン/オンチェーンの切り分けで重要になると思います。
今回のプロダクトのケースでは、取引履歴を取得するときに、JSON-RPC を使って参照するとその他の取引情報からフィルターする必要が出てきて、非効率になります。またブロックチェーン上の取引情報には現在の取引状態などの情報がないため、独自でデータを追加する必要もあります。そこでサービス上で発生する取引は別途クラウドサービスに保存し、ウォレットアドレスから参照できるようにしました。構成をシンプルにするためにこの部分は AWS App Sync + DynamoDB で実装しています。

そんなこんなで夜なべしたプロダクトは無事締め切り 2 日前にローンチし、余裕を持ってサブミットもできました。

そして学びは続く

Solana を使ったプロダクトの開発は一段落し、今はまた Ethereum のブロックチェーン開発について勉強しています。特に本事業に関係しそうな DAO を構築するスマートコントラクトや Polygon などの 2nd Layer 周辺の技術について手を動かして理解を進めている状況です。

ここまで読んでいただいた方、どうもありがとうございます!
最後に投機的な観点からブロックチェーンや暗号通貨について話すと、個人的にはソフトウェアエンジニアにとって暗号通貨は結構良い投資手段なのではないかと思います。通常の金融資産と大きく異なる点としてブロックチェーンは純粋なソフトウェアであり、新しいブロックチェーンには最新技術が用いられ過去のブロックチェーンの課題を解決したり、新しい価値を生み出したりしています。Ethereum はとても良い例で、ブロックチェーン上にチューリング完全なコンピュータ言語を携えることで、既存の金融をディスラプトすることが可能になりました。

ソフトウェアエンジニアとしてはそういう技術革新やそれを支える開発コミュニティを観察することで、今後伸びる暗号通貨かどうかというのを見定め投資するのは楽しい運用の仕方なのかと思います。

*1:ブロックチェーンにおいてこれは一概に悪い文化ではないのが面白いところです。すでにブロックチェーン上で動いているコントラクトはある程度安全が担保されているはずという考えがあるようです