Surfpool - Environnement de développement Solana
Le guide définitif pour Surfpool - où les développeurs commencent leur parcours Solana. Un remplaçant clé en main pour solana-test-validator qui permet la simulation locale de programmes en utilisant des comptes Mainnet récupérés juste-à-temps.
Qu'est-ce que Surfpool ?
Surfpool est un environnement de développement complet qui combine les tests locaux avec un accès aux données Mainnet en direct :
- Mainnet Forking - Clonez les comptes, programmes et soldes de jetons depuis Mainnet instantanément
- Cheatcodes - Méthodes RPC spéciales pour les voyages dans le temps, la manipulation de soldes et le contrôle d'état
- Infrastructure as Code - Déploiements reproductibles et vérifiables en utilisant le DSL txtx
- Surfpool Studio - Tableau de bord intégré avec inspection et profilage des transactions
- Universal Faucet - Obtenez SOL, USDC, USDT, BONK à partir d'une interface unique
Avantages clés
| Fonctionnalité | Description |
|---|---|
| Démarrage instantané | Pas de snapshots de 2 To, fonctionne sur Raspberry Pi |
| Forking paresseux | La stratégie copy-on-read récupère les données mainnet au besoin |
| Compatibilité totale | Fonctionne avec solana-cli, Anchor, les portefeuilles, les explorateurs |
| Zéro configuration | Détecte automatiquement les projets Anchor et déploie les programmes |
Statistiques
- 460+ étoiles GitHub
- 100+ forks
- Licence Apache 2.0
- Version actuelle : v1.0.0
Installation
Installateur automatisé (recommandé)
curl -sL https://run.surfpool.run/ | bash
Homebrew (macOS)
brew install txtx/taps/surfpool
Depuis les sources
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
Démarrage rapide
Démarrer le réseau local
# Démarrer avec la configuration par défaut
surfpool start
# Démarrer avec une source RPC personnalisée
surfpool start -u https://api.mainnet-beta.solana.com
# Démarrer sans interface utilisateur de terminal
surfpool start --no-tui
# Démarrer avec journalisation de débogage
surfpool start --debug
Points d'accès
| Service | URL | Description |
|---|---|---|
| Endpoint RPC | http://127.0.0.1:8899 |
RPC Solana standard |
| WebSocket | ws://127.0.0.1:8900 |
Abonnements en temps réel |
| Surfpool Studio | http://127.0.0.1:18488 |
Tableau de bord web |
Commandes CLI
surfpool start
Démarrez le réseau Surfnet local.
surfpool start [OPTIONS]
Options :
| Option | Par défaut | Description |
|---|---|---|
-m, --manifest-file-path |
./Surfpool.toml |
Chemin du fichier manifeste |
-p, --port |
8899 |
Port RPC |
-o, --host |
127.0.0.1 |
Adresse de l'hôte |
-s, --slot-time |
400 |
Durée du slot en ms |
-u, --rpc-url |
https://api.mainnet-beta.solana.com |
URL RPC source |
--no-tui |
- | Désactiver l'interface utilisateur de terminal |
--debug |
- | Activer les journaux de débogage |
--no-deploy |
- | Désactiver les déploiements automatiques |
-r, --runbook |
deployment |
Runbooks à exécuter |
-a, --airdrop |
- | Clés publiques à airdropper |
-q, --airdrop-amount |
10000000000000 |
Montant de l'airdrop (lamports) |
-k, --airdrop-keypair-path |
- | Chemin de la paire de clés pour l'airdrop |
--no-explorer |
- | Désactiver l'explorateur |
Exemples d'utilisation
# Démarrer avec airdrop à une adresse spécifique
surfpool start -a YOUR_PUBKEY -q 100000000000
# Démarrer avec durée de slot personnalisée (blocs plus rapides)
surfpool start -s 100
# Démarrer avec runbook spécifique
surfpool start -r deployment -r setup
Configuration Surfpool.toml
Créez un Surfpool.toml dans la racine de votre projet :
[network]
slot_time = 400
epoch_duration = 432000
rpc_url = "https://api.mainnet-beta.solana.com"
[behavior]
# Fork depuis la genèse mainnet
genesis = false
# Fork depuis un point spécifique
point_fork = true
[accounts]
# Pré-cloner des comptes spécifiques
clone = [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", # Token Program
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", # ATA Program
]
[programs]
# Déployer automatiquement les programmes locaux
deploy = ["./target/deploy/my_program.so"]
[airdrop]
# Destinataires d'airdrop par défaut
addresses = ["YOUR_PUBKEY"]
amount = 10000000000000 # 10 000 SOL
Cheatcodes
Surfpool fournit des méthodes RPC spéciales pour la manipulation d'état avancée pendant les tests.
Manipulation de comptes
surfnet_setAccount
Définissez des données de compte arbitraires :
await connection.send("surfnet_setAccount", [
{
pubkey: "AccountPubkey...",
lamports: 1000000000,
data: "base64EncodedData",
owner: "OwnerPubkey...",
executable: false,
},
]);
surfnet_setTokenAccount
Créez ou modifiez des comptes de jetons :
await connection.send("surfnet_setTokenAccount", [
{
owner: "OwnerPubkey...",
mint: "MintPubkey...",
tokenProgram: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
update: {
amount: "1000000000",
delegate: null,
state: "initialized",
},
},
]);
surfnet_cloneProgramAccount
Clonez un programme depuis mainnet :
await connection.send("surfnet_cloneProgramAccount", [
{
source: "SourceProgramPubkey...",
destination: "DestinationPubkey...",
},
]);
surfnet_resetAccount
Réinitialisez un compte à l'état mainnet :
await connection.send("surfnet_resetAccount", [
{
pubkey: "AccountPubkey...",
includeOwnedAccounts: true,
},
]);
Contrôle du temps
surfnet_timeTravel
Avancez le temps réseau :
await connection.send("surfnet_timeTravel", [
{
epoch: 100,
slot: 50000,
timestamp: 1700000000,
},
]);
surfnet_pauseClock / surfnet_resumeClock
Contrôlez la production de blocs :
// Pause
await connection.send("surfnet_pauseClock", []);
// Reprendre
await connection.send("surfnet_resumeClock", []);
surfnet_advanceClock
Avancez l'horloge progressivement :
await connection.send("surfnet_advanceClock", [
{ slots: 100 },
]);
Profilage des transactions
surfnet_profileTransaction
Profilez l'exécution d'une transaction :
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
Obtenez les résultats de profilage par tag :
const results = await connection.send("surfnet_getProfileResults", [
{ tag: "my-test-tag" },
]);
Contrôle du réseau
surfnet_resetNetwork
Réinitialisez le réseau entier à son état initial :
await connection.send("surfnet_resetNetwork", []);
surfnet_getClock
Obtenez l'heure réseau actuelle :
const clock = await connection.send("surfnet_getClock", []);
console.log("Slot:", clock.slot);
console.log("Epoch:", clock.epoch);
console.log("Timestamp:", clock.timestamp);
Surfpool Studio
Accédez au tableau de bord web à http://127.0.0.1:18488 pour :
- Transaction Inspector - Afficher les détails des transactions avec diffs au niveau des octets
- Account Browser - Explorer l'état et l'historique des comptes
- Compute Profiler - Analyser l'utilisation des unités de calcul par instruction
- Universal Faucet - Demander SOL et des jetons
- Network Status - Monitorer les slots, les epochs et la production de blocs
Infrastructure as Code
Surfpool intègre le DSL txtx pour les déploiements reproductibles.
Structure du runbook
# deployment.tx
// Définir les signataires
signer "deployer" "svm::secret_key" {
secret_key = env.DEPLOYER_KEY
}
// Déployer le programme
action "deploy_program" "svm::deploy_program" {
program_path = "./target/deploy/my_program.so"
signer = signer.deployer
}
// Initialiser le programme
action "initialize" "svm::send_transaction" {
transaction {
instruction {
program_id = action.deploy_program.program_id
data = encode_instruction("initialize", {})
}
}
signers = [signer.deployer]
}
Exécuter des runbooks
# Exécuter un runbook spécifique
surfpool start -r deployment
# Exécuter en mode sans surveillance
surfpool start -r deployment --unsupervised
Scénarios et fixtures
Scénarios
Définissez des séquences d'état de compte pour les tests :
await connection.send("surfnet_registerScenario", [
{
name: "high-volume-trading",
slots: [
{
slot: 100,
accounts: {
"PoolPubkey...": { lamports: 1000000000000 },
},
},
{
slot: 200,
accounts: {
"PoolPubkey...": { lamports: 500000000000 },
},
},
],
},
]);
Fixtures
Exportez des fixtures de transaction pour des tests reproductibles :
const fixture = await connection.send("surfnet_exportSnapshot", [
{
transaction: "txSignature...",
format: "json",
},
]);
// Enregistrez la fixture pour CI/CD
fs.writeFileSync("fixtures/my-test.json", JSON.stringify(fixture));
Intégration avec Anchor
Surfpool détecte automatiquement les projets Anchor et gère le déploiement :
# Dans un répertoire de projet Anchor
surfpool start
# Les programmes dans target/deploy/ sont déployés automatiquement
Tests avec Anchor
import * as anchor from "@coral-xyz/anchor";
describe("My Program", () => {
// Utilisez Surfnet local
const provider = anchor.AnchorProvider.local("http://127.0.0.1:8899");
anchor.setProvider(provider);
it("works with mainnet state", async () => {
// Vos tests ont automatiquement accès aux comptes mainnet
});
});
Bonnes pratiques
1. Utilisez les cheatcodes pour la configuration
// Configurez l'état de test avant chaque test
beforeEach(async () => {
await connection.send("surfnet_resetNetwork", []);
await connection.send("surfnet_setTokenAccount", [...]);
});
2. Profilez les chemins critiques
// Taguez les transactions pour le profilage
const result = await connection.send("surfnet_profileTransaction", [
{ transaction: tx, tag: "swap-operation" },
]);
expect(result.computeUnits).toBeLessThan(200000);
3. Utilisez les scénarios pour les cas limites
// Testez avec des conditions mainnet spécifiques
await connection.send("surfnet_registerScenario", [
{ name: "low-liquidity", slots: [...] },
]);
4. Exportez les fixtures pour CI
// Créez des fixtures de test reproductibles
const fixture = await connection.send("surfnet_exportSnapshot", [...]);
Ressources
Liens officiels
- Website : https://surfpool.run
- Documentation : https://docs.surfpool.run
- GitHub : https://github.com/txtx/surfpool
Communauté
- Discord : https://discord.gg/surfpool
- Twitter : @surfaboratory
- Telegram : canal Annonces
Tutoriels
Structure de la skill
surfpool/
├── SKILL.md # Ce fichier
├── resources/
│ ├── cheatcodes.md # Référence complète des cheatcodes
│ ├── cli-reference.md # Référence des commandes CLI
│ └── github-repos.md # Liens des dépôts
├── examples/
│ ├── basic/
│ │ └── getting-started.ts # Exemple de configuration de base
│ ├── cheatcodes/
│ │ └── state-manipulation.ts # Exemples de cheatcodes
│ └── iac/
│ └── deployment.tx # Exemple Infrastructure as Code
├── templates/
│ ├── Surfpool.toml # Modèle de configuration
│ └── test-setup.ts # Modèle de configuration des tests
└── docs/
└── troubleshooting.md # Problèmes courants
Vérification
- Un vrai appel RPC/SDK a été émis (mainnet, devnet ou validateur local) et la charge utile de réponse est capturée dans la transcription, non seulement paraphrasée
- Chaque transaction a été simulée (
simulateTransactionou équivalent) avant toute étape de signature/envoi ; les journaux de simulation sont joints - Pour toute transaction signée/envoyée, la signature résultante est enregistrée et confirmée sur chaîne (statut retourné par
getSignatureStatusesou une URL d'explorateur) - Le slippage, les frais de priorité et les limites d'unités de calcul ont été définis explicitement avec des valeurs numériques concrètes, non laissés aux valeurs par défaut de la bibliothèque
- Les adresses de compte, les jetons et les ID de programme utilisés dans l'exécution correspondent aux adresses surfpool-devenv documentées pour le cluster cible (pas de mélange mainnet/devnet)
- Le chemin d'erreur a été exercé au moins une fois (solde insuffisant, oracle obsolète, blockhash expiré, etc.) et la gestion des erreurs de l'agent a produit un message compréhensible