なぜ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 meanb
?
次にローカルクラスタにデプロイする
$ 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