2022/06/21

なぜSolanaは速いのか


物理的に異なる200のノードがGPUを利用して実行した場合秒間5万件のトランザクションを処理できるスループットをサポートしている

高速なトランザクション処理を実現するSolanaの8つの革新的な技術がある

  • Proof of History
    • コンセンサス前の時計
  • Tower BFT
    • PoHを最適化したもの
  • Turbin
    • ブロック伝搬プロトコル
  • Gulf Stream
    • Mempool-lessなトランザクション転送プロトコル
  • Sealevel
    • スマートコントラクトのランタイム並列化
  • Pipelining
    • 検証最適化のためのトランザクション処理ユニット
  • Cloudbreak
    • 水平スケーリングアーキテクチャ
  • アーカイバ
    • 分散台帳ストア

バリデータのハードウェアスペック要求が高い

ハードウェアを限界まで酷使する仕組み

後々GPUも利用してより高速化していく

コンセンサス前の時計:Proof of History

分散システムにおいて最も困難な課題の一つは時間に関する合意

例えばSpannerではデータセンター間は原子時計を使って同期している

ノード間のコンセンサスが非同期なのが特徴

プーリングがない

プーリングがあるとガス代オークションが始まってしまいガス代高騰につながる

承認者が自己の利益になるような行動をしたり、利益になるトランザクションを優先させたりできるのを防ぐ狙いもある(フロントランニング)

1000台のノードに生データを伝搬させる

コンセンサス前のグローバルクロックをソースとして提供する

コンセンサスアルゴリズム:Tower BFT

PBFT(Practical Byzantine Fault Tolerance)のカスタム実装でありPoHを最適化したもの

通信のオーバーヘッドとレイテンシーを削減する

タービン経由で伝搬したブロックがそれぞれのノードで承認されたかどうか確認する

ブロック伝搬プロトコル:Turbine(タービン)

効率よく素早く生データを伝搬させる仕組み

ツリー構造を作り1MB/10MBといったブロックを小分けにして伝搬させることで低レイテンシー、大容量のデータを送ることができる

BitTorrentからヒントを得た

データがすべてのノードに行き渡ったかは確認せず、すぐに次のブロックデータを伝搬させる

Gulf Stream

mempoolとはまだネットワークで処理されていないトランザクションの集合のこと

組織

  • Solana Labs = エンジニア集団
  • Solana Foundation = 方向性を決めていく
  • Solana community = Solanaユーザーやノードを立ててくれてる人たち

Solanaを試す

公式のHello Worldプログラムをsolana上にデプロイしてJavaScriptクライアントからリクエストしてみる

https://github.com/solana-labs/example-helloworld

実行環境

OS: MacOS Monterey 12.2.1
M1 mac mini

準備

まずHello Worldプログラムをクローンしてくる

# ssh設定してないPCからだったのでhttpsでクローンしていることに注意
$ git clone <https://github.com/solana-labs/example-helloworld.git>
$ cd example-helloworld

今回はJavaScriptクライアントから接続するのでnpmをインストールする

$ brew install npm
$ npm install

次にRustもインストールする

$ curl --proto '=https' --tlsv1.2 -sSf <https://sh.rustup.rs> | sh
$ source "$HOME/.cargo/env"
$ rustc --version
rustc 1.64.0 (a55dd71d5 2022-09-19)

そしてsolana cliをインストールする

公式DOCはここ

https://docs.solana.com/cli/install-solana-cli-tools

# solanaのインストール
$ sh -c "$(curl -sSfL <https://release.solana.com/v1.14.3/install>)"

# versionの確認
$ solana-install update

# Updateしたかったら
$ solana-install update

次にsolanaのローカルクラスタに接続するため設定する

$ solana config set --url <http://127.0.0.1:8899>

鍵を作成する

シードフレーズは開発用なら特に指定しなくても良い

$ solana-keygen new

Generating a new keypair

For added security, enter a BIP39 passphrase

NOTE! This passphrase improves security of the recovery seed phrase NOT the
keypair file itself, which is stored as insecure plain text

BIP39 Passphrase (empty for none):

Wrote new keypair to /Users/suzumi1056/.config/solana/id.json
==================================================================================
pubkey: FJmFMqeX64Yi8nYB1Y8yRCgF8XmsWBgRah7ytj8PiZ1w # これがwallet address
==================================================================================
Save this seed phrase and your BIP39 passphrase to recover your new keypair:
tennis recall steak device acoustic isolate wise end reunion rebuild crater enroll
==================================================================================
src ❯ solana config set --url <https://api.devnet.solana.com>
Config File: /Users/suzumi1056/.config/solana/cli/config.yml
RPC URL: <https://api.devnet.solana.com>
WebSocket URL: wss://api.devnet.solana.com/ (computed)
Keypair Path: /Users/suzumi1056/.config/solana/id.json
Commitment: confirmed

# いつでも確認できる
$ solana address
FJmFMqeX64Yi8nYB1Y8yRCgF8XmsWBgRah7ytj8PiZ1w

ローカルクラスタの起動

$ solana-test-validator

ターミナルで別窓を開いてログをtailする

$ solana logs

JavaScriptクライアントの実行

3つ目のウィンドウを開いてビルドする

$ npm run build:program-rust
> [email protected] build:program-rust
> cargo build-bpf --manifest-path=./src/program-rust/Cargo.toml --bpf-out-dir=dist/program

Warning: cargo-build-bpf is deprecated. Please, use cargo-build-sbf
cargo-build-bpf child: /Users/suzumi49n/.local/share/solana/install/active_release/bin/cargo-build-sbf --manifest-path=./src/program-rust/Cargo.toml --sbf-out-dir=dist/program --arch bpf
   Compiling proc-macro2 v1.0.43
   Compiling unicode-ident v1.0.3
   Compiling syn v1.0.99
   Compiling serde v1.0.136
   Compiling serde_derive v1.0.136
   Compiling version_check v0.9.3
   Compiling semver v1.0.13
   Compiling typenum v1.15.0
   Compiling libc v0.2.132
   Compiling subtle v2.4.0
   Compiling cfg-if v1.0.0
   Compiling feature-probe v0.1.1
   Compiling once_cell v1.13.1
   Compiling rustversion v1.0.9
   Compiling autocfg v1.1.0
   Compiling log v0.4.14
   Compiling constant_time_eq v0.1.5
   Compiling lazy_static v1.4.0
   Compiling keccak v0.1.0
   Compiling arrayref v0.3.6
   Compiling either v1.6.1
   Compiling bs58 v0.4.0
   Compiling arrayvec v0.7.2
   Compiling generic-array v0.14.6
   Compiling ahash v0.7.6
   Compiling bv v0.11.1
   Compiling itertools v0.10.3
   Compiling num-traits v0.2.14
   Compiling rustc_version v0.4.0
   Compiling quote v1.0.9
   Compiling solana-frozen-abi-macro v1.10.35
   Compiling solana-frozen-abi v1.10.35
   Compiling solana-program v1.10.35
   Compiling hashbrown v0.11.2
   Compiling jobserver v0.1.22
   Compiling cc v1.0.68
   Compiling blake3 v1.3.1
   Compiling borsh-derive-internal v0.9.3
   Compiling borsh-schema-derive-internal v0.9.3
   Compiling thiserror-impl v1.0.30
   Compiling bytemuck_derive v1.2.1
   Compiling num-derive v0.3.3
   Compiling solana-sdk-macro v1.10.35
   Compiling bytemuck v1.12.1
   Compiling thiserror v1.0.30
   Compiling serde_bytes v0.11.5
   Compiling bincode v1.3.3
   Compiling toml v0.5.8
   Compiling block-buffer v0.10.2
   Compiling crypto-common v0.1.6
   Compiling digest v0.10.3
   Compiling sha2 v0.10.2
   Compiling sha3 v0.10.2
   Compiling proc-macro-crate v0.1.5
   Compiling borsh-derive v0.9.3
   Compiling borsh v0.9.3
   Compiling solana-bpf-helloworld v0.0.1 (/Users/suzumi49n/dev/example-helloworld/src/program-rust)
    Finished release [optimized] target(s) in 37.20s
+ curl -L <https://github.com/Snaipe/Criterion/releases/download/v2.3.2/criterion-v2.3.2-osx-x86_64.tar.bz2> -o criterion-v2.3.2-osx-x86_64.tar.bz2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  176k  100  176k    0     0   206k      0 --:--:-- --:--:-- --:--:--  555k
+ tar --strip-components 1 -jxf criterion-v2.3.2-osx-x86_64.tar.bz2
+ ./bpf-tools/rust/bin/rustc --version
+ ./bpf-tools/rust/bin/rustc --print sysroot
+ set +e
+ rustup toolchain uninstall bpf
info: uninstalling toolchain 'bpf'
info: toolchain 'bpf' uninstalled
+ set -e
+ rustup toolchain link bpf bpf-tools/rust
+ exit 0

⚠️ ※ Monterey 12.5.1(M1 pro)でRustプログラムをビルドしようとすると以下のようなエラーでビルドに失敗した
$ npm run build:program-rust
[email protected] build:program-rust cargo build-bpf --manifest-path=./src/program-rust/Cargo.toml --bpf-out-dir=dist/program
Warning: cargo-build-bpf is deprecated. Please, use cargo-build-sbf cargo-build-bpf child: /Users/suzumi1056/.local/share/solana/install/active_release/bin/cargo-build-sbf --manifest-path=./src/program-rust/Cargo.toml --sbf-out-dir=dist/program --arch bpf error: no such subcommand: +bpf
Did you mean b?

次にローカルクラスタにデプロイする

$ solana program deploy dist/program/helloworld.so
Program Id: 2tc7sxFnCgu42XmnXw7dcAsuA1vAhCMrDohnsQfbXZRQ

そしてクライアントを実行する

以下のようにSuccessが表示されればOK

$ npm run start
> [email protected] start
> ts-node src/client/main.ts

Let's say hello to a Solana account...
Connection to cluster established: <http://127.0.0.1:8899> { 'feature-set': 940802714, 'solana-core': '1.14.3' }
Using account 3xHrMtvg1eo5QQRv2cdjwF8N1mtQxvUBxKPoqrFGNibT containing 499999999.3433822 SOL to pay for fees
Using program 2tc7sxFnCgu42XmnXw7dcAsuA1vAhCMrDohnsQfbXZRQ
Creating account 8asunBAm4EpSFhqn9yDDzTWof9rVxtNDJeETxBVN61T1 to say hello to # 初回時のみこの行が表示される
Saying hello to 8asunBAm4EpSFhqn9yDDzTWof9rVxtNDJeETxBVN61T1
8asunBAm4EpSFhqn9yDDzTWof9rVxtNDJeETxBVN61T1 has been greeted 1 time(s)
Success

別窓で開いてるsolana logも以下のように表示されているはず(3回目のリクエストのログなのでGreeted 3 time(s)!と表示されている)

Transaction executed in slot 72963:
  Signature: 3ME5cdU4HjojuTg1VthyWFwRYJUjeUTk7fzprNbhZT2V7BLNrShwaAm7LqDEapF3gAa58MRJJbqeReVhdXVbN2sp
  Status: Ok
  Log Messages:
    Program 2tc7sxFnCgu42XmnXw7dcAsuA1vAhCMrDohnsQfbXZRQ invoke [1]
    Program log: Hello World Rust program entrypoint
    Program log: Greeted 3 time(s)!
    Program 2tc7sxFnCgu42XmnXw7dcAsuA1vAhCMrDohnsQfbXZRQ consumed 1116 of 200000 compute units
    Program 2tc7sxFnCgu42XmnXw7dcAsuA1vAhCMrDohnsQfbXZRQ success

開発していくためにdev netにつなげていく

$ solana config set --url <https://api.devnet.solana.com>

Etherium facetのように無料でdev net用のSOLが貰えるのでとりあえず10SOL貰ってみる

$ solana airdrop 10
Requesting airdrop of 10 SOL

Signature: 3ucDPpnQdVgAYUu7dKTy27oASdKkS5XFZuXzt4wbchNi3uKv7oT7LQBon5dCNAZ7yryKG6yxN2j5B4Bcw8TWw2fF

Balance unchanged
Run `solana confirm -v 3ucDPpnQdVgAYUu7dKTy27oASdKkS5XFZuXzt4wbchNi3uKv7oT7LQBon5dCNAZ7yryKG6yxN2j5B4Bcw8TWw2fF` for more info

Balance Unchangedと言われてしまった

solana confirmで詳細を確認できるそうなので確認してみる

$ solana confirm -v 3ucDPpnQdVgAYUu7dKTy27oASdKkS5XFZuXzt4wbchNi3uKv7oT7LQBon5dCNAZ7yryKG6yxN2j5B4Bcw8TWw2fF
RPC URL: <https://api.devnet.solana.com>
Default Signer Path: /Users/suzumi1056/.config/solana/id.json
Commitment: confirmed

Transaction executed in slot 145204176:
  Block Time: 2022-07-03T00:14:07+09:00
  Version: legacy
  Recent Blockhash: DYaejfF4x5RkszPBuYEkRFk52Nx6icsJFxp7aNaCCvWy
  Signature 0: 3ucDPpnQdVgAYUu7dKTy27oASdKkS5XFZuXzt4wbchNi3uKv7oT7LQBon5dCNAZ7yryKG6yxN2j5B4Bcw8TWw2fF
  Account 0: srw- 9B5XszUGdMaxCZ7uSQhPzdks5ZQSmWxrmzCSvtJ6Ns6g (fee payer)
  Account 1: -r-x MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr
  Instruction 0
    Program:   MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr (1)
    Data: "request too large; req: ◎10, cap: ◎2"
  Status: Ok
    Fee: ◎0.000005
    Account 0 balance: ◎25815724.36171025 -> ◎25815724.36170525
    Account 1 balance: ◎0.52149888
  Log Messages:
    Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr invoke [1]
    Program log: Memo (len 40): "request too large; req: ◎10, cap: ◎2"
    Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr consumed 33124 of 200000 compute units
    Program MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr success

Finalized

下の方に以下のログが出てる

request too large; req: ◎10, cap: ◎2

10SOLは欲張りすぎたようだ

最大でも2SOLしか貰えないみたいなのでリクエストしてみる

$ solana airdrop 2
Requesting airdrop of 2 SOL

Signature: 4fKszHsAygz6QchCJQ94dRcuNp4ZKavdRyYRDnYk5wnTjhRk2S415AVzkgSccahK546evKZx6PrYhZgJNJxPXGyF

2 SOL

無事もらえた

念の為残高があることを確認する

ACCOUNT_ADDRESSはsolana-keygen newでウォレットを作成したときに表示されたpubkeyを指定すればOK

$ solana balance <ACCOUNT_ADDRESS> --url <https://api.devnet.solana.com>
2 SOL

以下のコマンドでもwalletのアドレスを確認できる

$ solana address
FJmFMqeX64Yi8nYB1Y8yRCgF8XmsWBgRah7ytj8PiZ1w

Anchorを使ってカウンターアプリを作ってみる

Ref: https://betterprogramming.pub/how-to-create-smart-contracts-in-solana-and-anchor-e67ff0747c63

Anchorとは

Anchorとはsolana program(スマートコントラクト)を簡単に作れるフレームワークのこと

まずはAnchorをインストールする

$ cargo install --git <https://github.com/project-serum/anchor> avm --locked --force
$ avm --version
avm 0.25.0

$ anchor --version
anchor-cli 0.25.0

プロジェクトを作成する

$ anchor init counterapp
Error: yarn install failed: No such file or directory (os error 2)

エラーが出る

どうやらnodeとyarnがインストールされている必要があるらしい

ということでnpmインストール

めんどくさいのでhomebrew経由で入れる

# nodeのインストール
$ brew install npm
$ npm -v
8.19.2
$ node -v
v18.10.0

# yarnのインストール
$ npm install -g yarn
$ yarn -v

再度実行するとちゃんとプロジェクトが作成できた

$ anchor init counterapp
$ ls -la
total 0
drwxr-xr-x   5 suzumi1056  staff  160 10  6 11:11 .
drwxr-xr-x   6 suzumi1056  staff  192  5 12 07:22 ..
drwxr-xr-x  15 suzumi1056  staff  480 10  6 11:11 counterapp

バイナリーオプションプログラムを作ってみる

ウォレットの作成、残高の取得まで準備できたから実際にRustでバイナリーオプションのプログラムをデプロイするところまでやってみる

今回は5分後のSOL/USDが上か下かを一人で賭けるプログラムを実装する

プログラムの内容はこれをそのまま写景した

https://labs.septeni.co.jp/entry/2021/11/08/090000

プロジェクトを作成する

# Rustがインストールされてること確認
$ rustc --version
rustc 1.61.0


$ cargo new solana-bo --lib
$ cd solana-bo