surfpool

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Surfpool - Solana Development Environment

Surfpool - Solana开发环境

The definitive guide for Surfpool - where developers start their Solana journey. A drop-in replacement for
solana-test-validator
that enables local program simulation using Mainnet accounts fetched just-in-time.
这是Surfpool的权威指南——开发者开启Solana开发之旅的起点。它是
solana-test-validator
的直接替代工具,可使用实时获取的主网账户进行本地程序模拟。

What is Surfpool?

什么是Surfpool?

Surfpool is a comprehensive development environment that combines local-first testing with real Mainnet data access:
  • Mainnet Forking - Clone accounts, programs, and token balances from Mainnet instantly
  • Cheatcodes - Special RPC methods for time travel, balance manipulation, and state control
  • Infrastructure as Code - Reproducible, auditable deployments using txtx DSL
  • Surfpool Studio - Embedded dashboard with transaction inspection and profiling
  • Universal Faucet - Get SOL, USDC, USDT, BONK from a single interface
Surfpool是一个综合性开发环境,将本地优先测试与真实主网数据访问相结合:
  • 主网分叉 - 即时克隆主网中的账户、程序和代币余额
  • 作弊码 - 用于时间跳转、余额操控和状态控制的特殊RPC方法
  • 基础设施即代码 - 使用txtx DSL实现可复现、可审计的部署
  • Surfpool Studio - 内置仪表盘,支持交易检查和性能分析
  • 通用水龙头 - 通过单一界面获取SOL、USDC、USDT、BONK

Key Benefits

核心优势

FeatureDescription
Instant BootNo 2TB snapshots, runs on Raspberry Pi
Lazy ForkingCopy-on-read strategy pulls mainnet data as needed
Full CompatibilityWorks with solana-cli, Anchor, wallets, explorers
Zero ConfigAuto-detects Anchor projects and deploys programs
特性描述
快速启动无需2TB快照,可在树莓派上运行
延迟分叉采用读时复制策略,按需拉取主网数据
完全兼容可与solana-cli、Anchor、钱包、区块浏览器配合使用
零配置自动检测Anchor项目并部署程序

Statistics

项目数据

  • 460+ GitHub stars
  • 100+ forks
  • Apache 2.0 license
  • Current version: v1.0.0
  • 460+ GitHub星标
  • 100+ 复刻数量
  • Apache 2.0许可证
  • 当前版本:v1.0.0

Installation

安装

Automated Installer (Recommended)

自动安装器(推荐)

bash
curl -sL https://run.surfpool.run/ | bash
bash
curl -sL https://run.surfpool.run/ | bash

Homebrew (macOS)

Homebrew(macOS系统)

bash
brew install txtx/taps/surfpool
bash
brew install txtx/taps/surfpool

From Source

从源码安装

bash
git clone https://github.com/txtx/surfpool.git
cd surfpool
cargo surfpool-install
bash
git clone https://github.com/txtx/surfpool.git
cd surfpool
cargo surfpool-install

Docker

Docker安装

bash
docker pull surfpool/surfpool
docker run -p 8899:8899 -p 18488:18488 surfpool/surfpool
bash
docker pull surfpool/surfpool
docker run -p 8899:8899 -p 18488:18488 surfpool/surfpool

Quick Start

快速开始

Start Local Network

启动本地网络

bash
undefined
bash
undefined

Start with default configuration

Start with default configuration

surfpool start
surfpool start

Start with custom RPC source

Start with custom RPC source

Start without terminal UI

Start without terminal UI

surfpool start --no-tui
surfpool start --no-tui

Start with debug logging

Start with debug logging

surfpool start --debug
undefined
surfpool start --debug
undefined

Access Points

访问地址

ServiceURLDescription
RPC Endpoint
http://127.0.0.1:8899
Standard Solana RPC
WebSocket
ws://127.0.0.1:8900
Real-time subscriptions
Surfpool Studio
http://127.0.0.1:18488
Web dashboard
服务地址描述
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 Commands

CLI命令

surfpool start

surfpool start

Start the local Surfnet network.
bash
surfpool start [OPTIONS]
Options:
OptionDefaultDescription
-m, --manifest-file-path
./Surfpool.toml
Path to manifest file
-p, --port
8899
RPC port
-o, --host
127.0.0.1
Host address
-s, --slot-time
400
Slot time in ms
-u, --rpc-url
https://api.mainnet-beta.solana.com
Source RPC URL
--no-tui
-Disable terminal UI
--debug
-Enable debug logs
--no-deploy
-Disable auto deployments
-r, --runbook
deployment
Runbooks to execute
-a, --airdrop
-Pubkeys to airdrop
-q, --airdrop-amount
10000000000000
Airdrop amount (lamports)
-k, --airdrop-keypair-path
-Keypair path for airdrop
--no-explorer
-Disable explorer
启动本地Surfnet网络。
bash
surfpool start [OPTIONS]
选项:
选项默认值描述
-m, --manifest-file-path
./Surfpool.toml
清单文件路径
-p, --port
8899
RPC端口
-o, --host
127.0.0.1
主机地址
-s, --slot-time
400
插槽时间(毫秒)
-u, --rpc-url
https://api.mainnet-beta.solana.com
源RPC地址
--no-tui
-禁用终端UI
--debug
-启用调试日志
--no-deploy
-禁用自动部署
-r, --runbook
deployment
要执行的运行手册
-a, --airdrop
-要空投的公钥
-q, --airdrop-amount
10000000000000
空投数量(lamports)
-k, --airdrop-keypair-path
-空投用的密钥对路径
--no-explorer
-禁用区块浏览器

Example Usage

示例用法

bash
undefined
bash
undefined

Start with airdrop to specific address

Start with airdrop to specific address

surfpool start -a YOUR_PUBKEY -q 100000000000
surfpool start -a YOUR_PUBKEY -q 100000000000

Start with custom slot time (faster blocks)

Start with custom slot time (faster blocks)

surfpool start -s 100
surfpool start -s 100

Start with specific runbook

Start with specific runbook

surfpool start -r deployment -r setup
undefined
surfpool start -r deployment -r setup
undefined

Surfpool.toml Configuration

Surfpool.toml配置

Create a
Surfpool.toml
in your project root:
toml
[network]
slot_time = 400
epoch_duration = 432000
rpc_url = "https://api.mainnet-beta.solana.com"

[behavior]
在项目根目录创建
Surfpool.toml
文件:
toml
[network]
slot_time = 400
epoch_duration = 432000
rpc_url = "https://api.mainnet-beta.solana.com"

[behavior]

Fork from mainnet genesis

Fork from mainnet genesis

genesis = false
genesis = false

Fork from specific point

Fork from specific point

point_fork = true
[accounts]
point_fork = true
[accounts]

Pre-clone specific accounts

Pre-clone specific accounts

clone = [ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", # Token Program "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", # ATA Program ]
[programs]
clone = [ "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", # Token Program "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", # ATA Program ]
[programs]

Auto-deploy local programs

Auto-deploy local programs

deploy = ["./target/deploy/my_program.so"]
[airdrop]
deploy = ["./target/deploy/my_program.so"]
[airdrop]

Default airdrop recipients

Default airdrop recipients

addresses = ["YOUR_PUBKEY"] amount = 10000000000000 # 10,000 SOL
undefined
addresses = ["YOUR_PUBKEY"] amount = 10000000000000 # 10,000 SOL
undefined

Cheatcodes

作弊码

Surfpool provides special RPC methods for advanced state manipulation during testing.
Surfpool提供特殊的RPC方法,用于测试期间的高级状态操控。

Account Manipulation

账户操控

surfnet_setAccount

surfnet_setAccount

Set arbitrary account data:
typescript
await connection.send("surfnet_setAccount", [
  {
    pubkey: "AccountPubkey...",
    lamports: 1000000000,
    data: "base64EncodedData",
    owner: "OwnerPubkey...",
    executable: false,
  },
]);
设置任意账户数据:
typescript
await connection.send("surfnet_setAccount", [
  {
    pubkey: "AccountPubkey...",
    lamports: 1000000000,
    data: "base64EncodedData",
    owner: "OwnerPubkey...",
    executable: false,
  },
]);

surfnet_setTokenAccount

surfnet_setTokenAccount

Create or modify token accounts:
typescript
await connection.send("surfnet_setTokenAccount", [
  {
    owner: "OwnerPubkey...",
    mint: "MintPubkey...",
    tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    update: {
      amount: "1000000000",
      delegate: null,
      state: "initialized",
    },
  },
]);
创建或修改代币账户:
typescript
await connection.send("surfnet_setTokenAccount", [
  {
    owner: "OwnerPubkey...",
    mint: "MintPubkey...",
    tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
    update: {
      amount: "1000000000",
      delegate: null,
      state: "initialized",
    },
  },
]);

surfnet_cloneProgramAccount

surfnet_cloneProgramAccount

Clone a program from mainnet:
typescript
await connection.send("surfnet_cloneProgramAccount", [
  {
    source: "SourceProgramPubkey...",
    destination: "DestinationPubkey...",
  },
]);
从主网克隆程序:
typescript
await connection.send("surfnet_cloneProgramAccount", [
  {
    source: "SourceProgramPubkey...",
    destination: "DestinationPubkey...",
  },
]);

surfnet_resetAccount

surfnet_resetAccount

Reset account to mainnet state:
typescript
await connection.send("surfnet_resetAccount", [
  {
    pubkey: "AccountPubkey...",
    includeOwnedAccounts: true,
  },
]);
将账户重置为主网状态:
typescript
await connection.send("surfnet_resetAccount", [
  {
    pubkey: "AccountPubkey...",
    includeOwnedAccounts: true,
  },
]);

Time Control

时间控制

surfnet_timeTravel

surfnet_timeTravel

Advance network time:
typescript
await connection.send("surfnet_timeTravel", [
  {
    epoch: 100,
    slot: 50000,
    timestamp: 1700000000,
  },
]);
推进网络时间:
typescript
await connection.send("surfnet_timeTravel", [
  {
    epoch: 100,
    slot: 50000,
    timestamp: 1700000000,
  },
]);

surfnet_pauseClock / surfnet_resumeClock

surfnet_pauseClock / surfnet_resumeClock

Control block production:
typescript
// Pause
await connection.send("surfnet_pauseClock", []);

// Resume
await connection.send("surfnet_resumeClock", []);
控制区块生成:
typescript
// Pause
await connection.send("surfnet_pauseClock", []);

// Resume
await connection.send("surfnet_resumeClock", []);

surfnet_advanceClock

surfnet_advanceClock

Advance clock incrementally:
typescript
await connection.send("surfnet_advanceClock", [
  { slots: 100 },
]);
逐步推进时钟:
typescript
await connection.send("surfnet_advanceClock", [
  { slots: 100 },
]);

Transaction Profiling

交易性能分析

surfnet_profileTransaction

surfnet_profileTransaction

Profile transaction execution:
typescript
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);
分析交易执行情况:
typescript
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

surfnet_getProfileResults

Get profiling results by tag:
typescript
const results = await connection.send("surfnet_getProfileResults", [
  { tag: "my-test-tag" },
]);
按标签获取性能分析结果:
typescript
const results = await connection.send("surfnet_getProfileResults", [
  { tag: "my-test-tag" },
]);

Network Control

网络控制

surfnet_resetNetwork

surfnet_resetNetwork

Reset entire network to initial state:
typescript
await connection.send("surfnet_resetNetwork", []);
将整个网络重置为初始状态:
typescript
await connection.send("surfnet_resetNetwork", []);

surfnet_getClock

surfnet_getClock

Get current network time:
typescript
const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);
获取当前网络时间:
typescript
const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);

Surfpool Studio

Surfpool Studio

Access the web dashboard at
http://127.0.0.1:18488
for:
  • Transaction Inspector - View transaction details with byte-level diffs
  • Account Browser - Explore account state and history
  • Compute Profiler - Analyze compute unit usage per instruction
  • Universal Faucet - Request SOL and tokens
  • Network Status - Monitor slots, epochs, and block production
访问
http://127.0.0.1:18488
打开Web仪表盘,可使用以下功能:
  • 交易检查器 - 查看交易详情,支持字节级差异对比
  • 账户浏览器 - 浏览账户状态与历史记录
  • 计算资源分析器 - 分析每条指令的计算单元使用情况
  • 通用水龙头 - 请求SOL和代币
  • 网络状态监控 - 监控插槽、纪元和区块生成情况

Infrastructure as Code

基础设施即代码

Surfpool integrates txtx DSL for reproducible deployments.
Surfpool集成txtx DSL,实现可复现的部署。

Runbook Structure

运行手册结构

hcl
undefined
hcl
undefined

deployment.tx

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] }
undefined
// 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] }
undefined

Running Runbooks

运行运行手册

bash
undefined
bash
undefined

Run specific runbook

Run specific runbook

surfpool start -r deployment
surfpool start -r deployment

Run in unsupervised mode

Run in unsupervised mode

surfpool start -r deployment --unsupervised
undefined
surfpool start -r deployment --unsupervised
undefined

Scenarios and Fixtures

场景与测试夹具

Scenarios

场景

Define account state sequences for testing:
typescript
await connection.send("surfnet_registerScenario", [
  {
    name: "high-volume-trading",
    slots: [
      {
        slot: 100,
        accounts: {
          "PoolPubkey...": { lamports: 1000000000000 },
        },
      },
      {
        slot: 200,
        accounts: {
          "PoolPubkey...": { lamports: 500000000000 },
        },
      },
    ],
  },
]);
定义用于测试的账户状态序列:
typescript
await connection.send("surfnet_registerScenario", [
  {
    name: "high-volume-trading",
    slots: [
      {
        slot: 100,
        accounts: {
          "PoolPubkey...": { lamports: 1000000000000 },
        },
      },
      {
        slot: 200,
        accounts: {
          "PoolPubkey...": { lamports: 500000000000 },
        },
      },
    ],
  },
]);

Fixtures

测试夹具

Export transaction fixtures for reproducible tests:
typescript
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));
导出交易夹具,用于可复现的测试:
typescript
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));

Integration with Anchor

与Anchor的集成

Surfpool auto-detects Anchor projects and handles deployment:
bash
undefined
Surfpool会自动检测Anchor项目并处理部署:
bash
undefined

In an Anchor project directory

In an Anchor project directory

surfpool start
surfpool start

Programs in target/deploy/ are automatically deployed

Programs in target/deploy/ are automatically deployed

undefined
undefined

Testing with Anchor

使用Anchor进行测试

typescript
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
  });
});
typescript
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
  });
});

Best Practices

最佳实践

1. Use Cheatcodes for Setup

1. 使用作弊码进行测试准备

typescript
// Set up test state before each test
beforeEach(async () => {
  await connection.send("surfnet_resetNetwork", []);
  await connection.send("surfnet_setTokenAccount", [...]);
});
typescript
// Set up test state before each test
beforeEach(async () => {
  await connection.send("surfnet_resetNetwork", []);
  await connection.send("surfnet_setTokenAccount", [...]);
});

2. Profile Critical Paths

2. 分析关键路径性能

typescript
// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
  { transaction: tx, tag: "swap-operation" },
]);

expect(result.computeUnits).toBeLessThan(200000);
typescript
// Tag transactions for profiling
const result = await connection.send("surfnet_profileTransaction", [
  { transaction: tx, tag: "swap-operation" },
]);

expect(result.computeUnits).toBeLessThan(200000);

3. Use Scenarios for Edge Cases

3. 使用场景测试边缘情况

typescript
// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
  { name: "low-liquidity", slots: [...] },
]);
typescript
// Test with specific mainnet conditions
await connection.send("surfnet_registerScenario", [
  { name: "low-liquidity", slots: [...] },
]);

4. Export Fixtures for CI

4. 导出测试夹具用于CI/CD

typescript
// Create reproducible test fixtures
const fixture = await connection.send("surfnet_exportSnapshot", [...]);
typescript
// Create reproducible test fixtures
const fixture = await connection.send("surfnet_exportSnapshot", [...]);

Resources

资源

Official Links

官方链接

Community

社区

Tutorials

教程

Skill Structure

技能结构

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
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