surfpool について
surfpool は Solana 開発者向けのローカル開発環境で、`solana-test-validator` の代替として必要に応じて Mainnet のデータを取得します。状態操作、デプロイ自動化、トランザクション分析を組み合わせ、オンチェーンアカウントを使ったテストに対応します。
主な機能
- 01Mainnet のアカウントとプログラムを必要時にフォーク
- 02RPC チートコードで状態と時刻を操作
- 03Anchor プロジェクトを検出してプログラムを自動デプロイ
- 04Surfpool Studio でトランザクションと計算量を確認
- 05txtx DSL で再現可能なデプロイを記述
活用シーン
- 01Mainnet のアカウント状態を使った Solana プログラムのテスト
- 02残高、アカウントデータ、ネットワーク時刻を設定した境界条件の確認
- 03トランザクションの計算量分析とアカウント状態の確認
- 04テストや CI 用の再現可能なトランザクションスナップショットの出力
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ sendaifun/ skills --skill surfpoolインストール後、Claude Code で/surfpoolを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
docs/troubleshooting.mdexamples/basic/getting-started.tsexamples/cheatcodes/state-manipulation.tsexamples/iac/deployment.txresources/cheatcodes.mdcli-reference.mdgithub-repos.mdtemplates/Surfpool.tomltest-setup.ts詳細
Surfpool - Solana 開発環境
Surfpool の決定版ガイドです。開発者が Solana の開発を始める場所です。solana-test-validator のドロップイン代替として、Mainnet のアカウントを必要なタイミングで取得し、ローカルでプログラムをシミュレーションできます。
Surfpool とは?
Surfpool は、ローカル優先のテストと実際の Mainnet データへのアクセスを組み合わせた、包括的な開発環境です。
- Mainnet フォーク - Mainnet のアカウント、プログラム、トークン残高を即座に複製します
- チートコード - 時間の操作、残高の変更、状態の制御に使える特別な RPC メソッドです
- Infrastructure as Code - txtx DSL を使用して、再現可能で監査可能なデプロイを実現します
- Surfpool Studio - トランザクションの検査とプロファイリング機能を備えた組み込みダッシュボードです
- ユニバーサル・フォーセット - 1 つのインターフェースから SOL、USDC、USDT、BONK を取得できます
主なメリット
| 機能 | 説明 |
|---|---|
| 即時起動 | 2 TB のスナップショットは不要で、Raspberry Pi でも動作します |
| 遅延フォーク | 読み取り時にコピーする方式で、必要に応じて mainnet データを取得します |
| 完全な互換性 | solana-cli、Anchor、ウォレット、エクスプローラーで動作します |
| 設定不要 | Anchor プロジェクトを自動検出し、プログラムをデプロイします |
統計
- GitHub スター 460 件以上
- フォーク 100 件以上
- Apache 2.0 ライセンス
- 現在のバージョン:v1.0.0
インストール
自動インストーラー(推奨)
curl -sL https://run.surfpool.run/ | bash
Homebrew(macOS)
brew install txtx/taps/surfpool
ソースからインストール
git clone https://github.com/txtx/surfpool.git
cd surfpool
cargo surfpool-install
Docker
docker pull surfpool/surfpool
docker run -p 8899:8899 -p 18488:18488 surfpool/surfpool
クイックスタート
ローカルネットワークを起動する
# Start with default configuration
surfpool start
# Start with custom RPC source
surfpool start -u https://api.mainnet-beta.solana.com
# Start without terminal UI
surfpool start --no-tui
# Start with debug logging
surfpool start --debug
アクセスポイント
| サービス | URL | 説明 |
|---|---|---|
| RPC エンドポイント | http://127.0.0.1:8899 | 標準の Solana RPC |
| WebSocket | ws://127.0.0.1:8900 | リアルタイムのサブスクリプション |
| Surfpool Studio | http://127.0.0.1:18488 | Web ダッシュボード |
CLI コマンド
surfpool start
ローカルの Surfnet ネットワークを起動します。
surfpool start [OPTIONS]
オプション:
| オプション | デフォルト | 説明 |
|---|---|---|
-m, --manifest-file-path | ./Surfpool.toml | マニフェストファイルのパス |
-p, --port | 8899 | RPC ポート |
-o, --host | 127.0.0.1 | ホストアドレス |
-s, --slot-time | 400 | スロット時間(ms) |
-u, --rpc-url | https://api.mainnet-beta.solana.com | ソース RPC URL |
--no-tui | - | ターミナル UI を無効にします |
--debug | - | デバッグログを有効にします |
--no-deploy | - | 自動デプロイを無効にします |
-r, --runbook | deployment | 実行するランブック |
-a, --airdrop | - | エアドロップ先の公開鍵 |
-q, --airdrop-amount | 10000000000000 | エアドロップ量(lamports) |
-k, --airdrop-keypair-path | - | エアドロップに使うキーペアのパス |
--no-explorer | - | エクスプローラーを無効にします |
使用例
# Start with airdrop to specific address
surfpool start -a YOUR_PUBKEY -q 100000000000
# Start with custom slot time (faster blocks)
surfpool start -s 100
# Start with specific runbook
surfpool start -r deployment -r setup
Surfpool.toml の設定
プロジェクトのルートに Surfpool.toml を作成します。
[network]
slot_time = 400
epoch_duration = 432000
rpc_url = "https://api.mainnet-beta.solana.com"
[behavior]
# Fork from mainnet genesis
genesis = false
# Fork from specific point
point_fork = true
[accounts]
# Pre-clone specific accounts
clone = [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", # Token Program
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", # ATA Program
]
[programs]
# Auto-deploy local programs
deploy = ["./target/deploy/my_program.so"]
[airdrop]
# Default airdrop recipients
addresses = ["YOUR_PUBKEY"]
amount = 10000000000000 # 10,000 SOL
チートコード
Surfpool は、テスト中に高度な状態操作を行うための特別な RPC メソッドを提供します。
アカウント操作
surfnet_setAccount
任意のアカウントデータを設定します。
await connection.send("surfnet_setAccount", [
{
pubkey: "AccountPubkey...",
lamports: 1000000000,
data: "base64EncodedData",
owner: "OwnerPubkey...",
executable: false,
},
]);
surfnet_setTokenAccount
トークンアカウントを作成または変更します。
await connection.send("surfnet_setTokenAccount", [
{
owner: "OwnerPubkey...",
mint: "MintPubkey...",
tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
update: {
amount: "1000000000",
delegate: null,
state: "initialized",
},
},
]);
surfnet_cloneProgramAccount
mainnet からプログラムを複製します。
await connection.send("surfnet_cloneProgramAccount", [
{
source: "SourceProgramPubkey...",
destination: "DestinationPubkey...",
},
]);
surfnet_resetAccount
アカウントを mainnet の状態にリセットします。
await connection.send("surfnet_resetAccount", [
{
pubkey: "AccountPubkey...",
includeOwnedAccounts: true,
},
]);
時間制御
surfnet_timeTravel
ネットワークの時間を進めます。
await connection.send("surfnet_timeTravel", [
{
epoch: 100,
slot: 50000,
timestamp: 1700000000,
},
]);
surfnet_pauseClock / surfnet_resumeClock
ブロック生成を制御します。
// Pause
await connection.send("surfnet_pauseClock", []);
// Resume
await connection.send("surfnet_resumeClock", []);
surfnet_advanceClock
クロックを段階的に進めます。
await connection.send("surfnet_advanceClock", [
{ slots: 100 },
]);
トランザクションのプロファイリング
surfnet_profileTransaction
トランザクションの実行をプロファイリングします。
const result = await connection.send("surfnet_profileTransaction", [
{
transaction: "base64EncodedTx",
tag: "my-test-tag",
},
]);
console.log("Compute units:", result.computeUnits);
console.log("Account changes:", result.accountChanges);
surfnet_getProfileResults
タグを指定してプロファイリング結果を取得します。
const results = await connection.send("surfnet_getProfileResults", [
{ tag: "my-test-tag" },
]);
ネットワーク制御
surfnet_resetNetwork
ネットワーク全体を初期状態にリセットします。
await connection.send("surfnet_resetNetwork", []);
surfnet_getClock
現在のネットワーク時刻を取得します。
const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);
Surfpool Studio
http://127.0.0.1:18488 でウェブダッシュボードにアクセスすると、次の機能を利用できます。
- トランザクションインスペクター - バイトレベルの差分とともにトランザクションの詳細を表示します
- アカウントブラウザー - アカウントの状態と履歴を確認します
- コンピュートプロファイラー - 命令ごとのコンピュートユニットの使用量を分析します
- ユニバーサルファウセット - SOL とトークンをリクエストします
- ネットワークステータス - スロット、エポック、ブロック生成を監視します
Infrastructure as Code
Surfpool は、再現可能なデプロイのために txtx DSL と連携します。
Runbook の構造
# deployment.tx
// Define signers
signer "deployer" "svm::secret_key" {
secret_key = env.DEPLOYER_KEY
}
// Deploy program
action "deploy_program" "svm::deploy_program" {
program_path = "./target/deploy/my_program.so"
signer = signer.deployer
}
// Initialize program
action "initialize" "svm::send_transaction" {
transaction {
instruction {
program_id = action.deploy_program.program_id
data = encode_instruction("initialize", {})
}
}
signers = [signer.deployer]
}
Runbook の実行
# Run specific runbook
surfpool start -r deployment
# Run in unsupervised mode
surfpool start -r deployment --unsupervised
シナリオとフィクスチャ
シナリオ
テスト用のアカウント状態のシーケンスを定義します。
await connection.send("surfnet_registerScenario", [
{
name: "high-volume-trading",
slots: [
{
slot: 100,
accounts: {
"PoolPubkey...": { lamports: 1000000000000 },
},
},
{
slot: 200,
accounts: {
"PoolPubkey...": { lamports: 500000000000 },
},
},
],
},
]);
フィクスチャ
再現可能なテストのためにトランザクションフィクスチャをエクスポートします。
const fixture = await connection.send("surfnet_exportSnapshot", [
{
transaction: "txSignature...",
format: "json",
},
]);
// Save fixture for CI/CD
fs.writeFileSync("fixtures/my-test.json", JSON.stringify(fixture));
Anchor との連携
Surfpool は Anchor プロジェクトを自動検出し、デプロイを処理します。
# In an Anchor project directory
surfpool start
# Programs in target/deploy/ are automatically deployed
Anchor を使ったテスト
import * as anchor from "@coral-xyz/anchor";
describe("My Program", () => {
// Use local Surfnet
const provider = anchor.AnchorProvider.local("http://127.0.0.1:8899");
anchor.setProvider(provider);
it("works with mainnet state", async () => {
// Your tests automatically have access to mainnet accounts
});
});
ベストプラクティス
1. セットアップにはチートコードを使用する
// Set up test state before each test
beforeEach(async () => {
await connection.send("surfnet_resetNetwork", []);
await connection.send("surfnet_setTokenAccount", [...]);
});
2. 重要な処理経路をプロファイリングする
// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
{ transaction: tx, tag: "swap-operation" },
]);
expect(result.computeUnits).toBeLessThan(200000);
3. エッジケースにはシナリオを使用する
// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
{ name: "low-liquidity", slots: [...] },
]);
4. CI 用にフィクスチャをエクスポートする
// Create reproducible test fixtures
const fixture = await connection.send("surfnet_exportSnapshot", [...]);
リソース
公式リンク
- ウェブサイト: https://surfpool.run
- ドキュメント: https://docs.surfpool.run
- GitHub: https://github.com/txtx/surfpool
コミュニティ
- Discord: https://discord.gg/surfpool
- Twitter: @surfaboratory
- Telegram: お知らせチャンネル
チュートリアル
スキルの構造
surfpool/
├── SKILL.md # This file
├── resources/
│ ├── cheatcodes.md # Complete cheatcodes reference
│ ├── cli-reference.md # CLI commands reference
│ └── github-repos.md # Repository links
├── examples/
│ ├── basic/
│ │ └── getting-started.ts # Basic setup example
│ ├── cheatcodes/
│ │ └── state-manipulation.ts # Cheatcode examples
│ └── iac/
│ └── deployment.tx # Infrastructure as Code example
├── templates/
│ ├── Surfpool.toml # Configuration template
│ └── test-setup.ts # Test setup template
└── docs/
└── troubleshooting.md # Common issues