Tworzenie lokalnie i testowanie na devnecie to świetny sposób, by zacząć pracę z płatnościami w Solanie. Jednak gdy jesteś gotowy na wdrożenie na Mainnet, musisz być świadomy specyfiki mainnetu. Devnet wybacza błędy. Mainnet – nie. Ten przewodnik omawia kluczowe różnice, które pozwolą zapewnić użytkownikom płynne doświadczenie.
| Devnet | Mainnet |
|---|---|
| Darmowe SOL z faucetów | Zdobądź prawdziwe SOL na opłaty |
| Niska konkurencja o miejsce w bloku | Opłaty priorytetowe mają znaczenie |
| Transakcje przechodzą łatwo | Konfiguracja transakcji jest kluczowa |
| Publiczny RPC wystarcza | Wymagany produkcyjny RPC |
| Klucze i minty z devnetu | Inne klucze i minty tokenów — zaktualizuj konfigurację |
Infrastruktura RPC
Publiczne endpointy
(api.mainnet-beta.solana.com) mają limity zapytań i brak SLA. Są odpowiednie
do developmentu, ale zawiodą w produkcyjnych płatnościach — to jak próba
uruchomienia procesora płatności przez współdzielone API bez gwarancji
dostępności.
Nigdy nie używaj publicznego RPC w produkcji
Korzystaj z prywatnego dostawcy RPC dla niezawodnego i niskolatencyjnego dostępu.
Wybierając dostawcę RPC, zwróć uwagę na:
- Niezawodność: SLA z gwarancją dostępności (99,9%+)
- Opóźnienia: Bliskość geograficzna do użytkowników
- Funkcje: Funkcje szybkiego zatwierdzania transakcji, indeksowanie, API opłat priorytetowych
Pełną listę dostawców RPC znajdziesz w przewodniku RPC Infrastructure Providers.
Redundantna konfiguracja RPC
Jak każdy dostawca usług sieciowych, dostawcy RPC mogą mieć przestoje lub okresy pogorszonej wydajności. Aby Twoja aplikacja była odporna, skonfiguruj ją do korzystania z wielu dostawców RPC.
Solana Kit to biblioteka umożliwiająca dostosowanie transportu RPC, co pozwala zbudować własnego redundantnego klienta RPC. Oto przykład, jak można jej użyć do stworzenia redundantnego klienta RPC:
import { RpcTransport } from "@solana/rpc-spec";import { RpcResponse } from "@solana/rpc-spec-types";import { createHttpTransport } from "@solana/rpc-transport-http";// Create a transport for each RPC serverconst transports = [createHttpTransport({ url: "https://mainnet-beta.my-server-1.com" }),createHttpTransport({ url: "https://mainnet-beta.my-server-2.com" }),createHttpTransport({ url: "https://mainnet-beta.my-server-3.com" })];// Create a wrapper transport that distributes requests to themlet nextTransport = 0;async function roundRobinTransport<TResponse>(...args: Parameters<RpcTransport>): Promise<RpcResponse<TResponse>> {const transport = transports[nextTransport];nextTransport = (nextTransport + 1) % transports.length;return await transport(...args);}
Jeśli nie chcesz budować własnych narzędzi do routingu, możesz skorzystać z usług firm trzecich, takich jak Iron Forge, aby obsłużyć routing za Ciebie.
Lądowanie transakcji
Na Devnecie transakcje są realizowane dość łatwo. Na Mainnecie konkurujesz o miejsce w bloku. Aby zwiększyć szanse na włączenie transakcji do bloku, powinieneś upewnić się, że transakcja została poprawnie złożona. Oznacza to:
- dołączenie świeżego blockhasha przed wysłaniem transakcji
- dodanie instrukcji opłaty priorytetowej z konkurencyjną opłatą priorytetową
- dodanie instrukcji limitu jednostek obliczeniowych z limitem opartym na szacowanej liczbie jednostek obliczeniowych wymaganych dla transakcji
Dodatkowo warto rozważyć inne narzędzia, takie jak Jito Bundles, aby zwiększyć szanse na włączenie transakcji do bloku. Przyjrzyjmy się tym narzędziom bliżej.
Konfiguracja wysyłania transakcji
Wysyłając transakcje na Mainnecie, skonfiguruj te parametry, aby uzyskać optymalny wskaźnik lądowania:
Zarządzanie blockhashem:
- Pobierz z
confirmedcommitment - Zapisz
lastValidBlockHeightzwrócony przezgetLatestBlockhash— to informuje, kiedy Twoja transakcja wygaśnie - Blockhashe wygasają po ok. 150 blokach (ok. 60–90 sekund)
Opcje wysyłania:
maxRetries: 0— Wyłącz automatyczne ponawianie RPC. Obsłuż ponowienia samodzielnie, aby móc odświeżyć blockhash w razie potrzeby.skipPreflight: true— Pomijaj symulację przed wysłaniem. Użyj tego, jeśli transakcja została już zweryfikowana i zależy Ci na najniższym opóźnieniu. Pozostaw tofalsepodczas developmentu, aby wcześnie wychwycić błędy.
import { createSolanaRpc } from "@solana/kit";const rpc = createSolanaRpc(process.env.RPC_URL!);// 1. Get blockhash with confirmed commitmentconst { value: latestBlockhash } = await rpc.getLatestBlockhash({ commitment: "confirmed" }).send();// 2. Build and sign your transaction with the blockhash// ... (transaction building code)// 3. Send with production settingsconst signature = await rpc.sendTransaction(encodedTransaction, {encoding: "base64",maxRetries: 0n, // Handle retries yourselfskipPreflight: true, // Skip simulation for speed (use false during dev)preflightCommitment: "confirmed"}).send();// 4. Track expiration using lastValidBlockHeightconst { lastValidBlockHeight } = latestBlockhash;// Stop retrying when current block height exceeds lastValidBlockHeight
Używaj opłat priorytetowych
Każda transakcja w sieci Solana wymaga opłaty transakcyjnej, płatnej w SOL. Opłaty transakcyjne dzielą się na dwie części: opłatę bazową i opłatę priorytetową. Opłata bazowa rekompensuje walidatorom przetwarzanie transakcji. Opłata priorytetowa to opcjonalna opłata, która zwiększa szansę, że obecny lider przetworzy Twoją transakcję. Można to porównać do ekspresowej wysyłki: płacisz więcej za szybszą i bardziej niezawodną realizację.
Jak działają opłaty:
Total fee = Base fee (5,000 lamports per signature) + Priority feePriority fee = Compute units x Price per unit (micro-lamports per compute unit)
Koszty w praktyce:
- Prosty transfer USDC: ~0,001-0,005 USD w normalnych warunkach
- W czasie przeciążenia: ~0,01-0,05 USD
- Szczytowe przeciążenie: Może wzrosnąć jeszcze bardziej
Przykładowa implementacja:
Pakiet
@solana-program/compute-budget
udostępnia funkcję pomocniczą, która pozwala łatwo zaktualizować lub dodać
instrukcję ceny jednostki obliczeniowej (w mikro-lamportach) do transakcji.
import { updateOrAppendSetComputeUnitPriceInstruction } from "@solana-program/compute-budget";const tx = pipe(createTransactionMessage({ version: 0 }),(m) => setTransactionMessageFeePayerSigner(payer, m),(m) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, m),(m) => appendTransactionMessageInstructions([myInstructions], m),(m) => updateOrAppendSetComputeUnitPriceInstruction(1000n as MicroLamports, m));
Jak uzyskać szacunkowe opłaty: Większość dostawców RPC oferuje API opłat priorytetowych:
Pełną mechanikę opłat znajdziesz w Opłaty transakcyjne oraz w naszym przewodniku: Jak dodać opłaty priorytetowe do transakcji.
Optymalizuj jednostki obliczeniowe
Obliczenia na Solanie to w praktyce miara ilości pracy wykonywanej przez program. Istnieje limit ilości obliczeń, które można wykorzystać w jednej transakcji (obecnie 1,4 miliona jednostek obliczeniowych) oraz limit na ilość obliczeń na konto na blok (obecnie 100 milionów jednostek obliczeniowych).
Podczas wysyłania transakcji musisz oszacować ilość jednostek obliczeniowych, które zostaną użyte, i odpowiednio ustawić limit jednostek obliczeniowych – jest to w praktyce prośba o zarezerwowanie określonej części całkowitej pojemności dla Twojej transakcji. W praktyce oznacza to, że prawidłowe oszacowanie wymaganych jednostek obliczeniowych jest kluczowe, aby Twoja transakcja została uwzględniona w bloku (i ważne dla zarządzania opłatami priorytetowymi).
Solana JSON RPC API posiada metodę
simulatetransaction, która pozwala
oszacować liczbę jednostek obliczeniowych wymaganych do wykonania transakcji, w
tym przewidywaną liczbę jednostek, które zostaną użyte. Pakiet
@solana-program/compute-budget
zawiera funkcję pomocniczą, która umożliwia łatwe oszacowanie liczby jednostek
obliczeniowych potrzebnych do transakcji (wykorzystuje ona metodę
simulatetransaction w tle).
import {estimateComputeUnitLimitFactory,updateOrAppendSetComputeUnitLimitInstruction} from "@solana-program/compute-budget";const estimateComputeUnitLimit = estimateComputeUnitLimitFactory({ rpc });const computeUnitLimit = await estimateComputeUnitLimit(tx);const txWithComputeUnitLimit = updateOrAppendSetComputeUnitLimitInstruction(computeUnitLimit,tx);
W środowisku produkcyjnym, jeśli wielokrotnie wykonujesz ten sam typ transakcji, warto rozważyć cache'owanie oszacowania jednostek obliczeniowych dla danego typu transakcji, aby uniknąć narzutu związanego z każdorazowym szacowaniem.
Jito Bundles
Jito bundles to narzędzie do zarządzania atomowym wykonaniem wielu transakcji. Osiąga się to poprzez wysyłanie wielu transakcji do sieci Jito z tipem. Tipy mogą być używane do zachęcania sieci Jito do włączenia twoich transakcji do bloku.
Zasoby:
Strategie ponawiania
Transakcje mogą się nie powieść z wielu powodów. W przeciwieństwie do tradycyjnych API płatności, które natychmiast zwracają sukces/porażkę, transakcje blockchain wymagają śledzenia potwierdzenia.
Kluczowe pojęcia:
- Wygaśnięcie blockhasha: Transakcje są ważne przez ok. 150 bloków (ok. 60–90 sekund)
- Idempotencja: Ta sama podpisana transakcja zawsze generuje ten sam podpis—ponowne wysłanie jest bezpieczne
- Exponential backoff: Unikaj przeciążania sieci zbyt szybkimi próbami ponowienia
import {createSolanaRpc,createSolanaRpcSubscriptions,sendAndConfirmTransactionFactory,isSolanaError,SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED} from "@solana/kit";const rpc = createSolanaRpc(process.env.RPC_URL!);const rpcSubscriptions = createSolanaRpcSubscriptions(process.env.RPC_WSS_URL!);const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({rpc,rpcSubscriptions});// Send with automatic confirmation tracking and block height monitoringtry {await sendAndConfirmTransaction(signedTransaction, {commitment: "confirmed",// Optional: abort after 75 secondsabortSignal: AbortSignal.timeout(75_000)});} catch (e) {if (isSolanaError(e, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) {// Blockhash expired—rebuild transaction with fresh blockhash and retryrebuildAndRetryTransaction(); // implement your own logic for rebuilding and retrying the transaction}throw e;}
sendAndConfirmTransactionFactory z @solana/kit automatycznie obsługuje
polling potwierdzeń i śledzenie wysokości bloku. Zgłasza
SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED, gdy blockhash transakcji wygaśnie,
sygnalizując konieczność zbudowania transakcji na nowo z aktualnym blockhashem.
Dodatkowe zasoby
- Przewodnik: Potwierdzanie i wygasanie transakcji
- Helius: Jak zatwierdzać transakcje na Solanie
- QuickNode: Strategie optymalizacji transakcji na Solanie
Poziomy potwierdzenia – wyjaśnienie
Solana oferuje trzy poziomy potwierdzenia. W kategoriach finansów tradycyjnych:
| Poziom | Definicja Solana | Odpowiednik tradycyjny | Przykład użycia |
|---|---|---|---|
processed | W bloku, jeszcze niezatwierdzone głosowaniem | Oczekuje na autoryzację | Aktualizacje UI w czasie rzeczywistym |
confirmed | Zatwierdzone przez superwiększość | Środki rozliczone | Większość płatności |
finalized | Zakorzenione, nieodwracalne | Środki rozliczone ostatecznie | Wysokie kwoty, zgodność z przepisami |
Kiedy używać którego:
- Aktualizacje UI: Pokazuj
processeddla natychmiastowej informacji zwrotnej ("Płatność wysłana") - Zaksięgowanie środków użytkownika: Poczekaj na
confirmed(bezpieczne dla większości transakcji) - Wysyłka towarów fizycznych: Poczekaj na
finalized - Duże wypłaty: Poczekaj na
finalized - Zgodność/audyt: Zawsze rejestruj status
finalized
Więcej o sprawdzaniu statusu transakcji znajdziesz w Interakcja z Solaną.
Obsługa błędów
Solana Kit udostępnia typowane błędy przez isSolanaError(). Używaj konkretnych
kodów błędów zamiast dopasowywania tekstu:
import {isSolanaError,SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED,SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS_FOR_FEE,SOLANA_ERROR__TRANSACTION_ERROR__BLOCKHASH_NOT_FOUND,SOLANA_ERROR__INSTRUCTION_ERROR__INSUFFICIENT_FUNDS} from "@solana/kit";function handlePaymentError(error: unknown): {message: string;retryable: boolean;} {// Blockhash expired—rebuild and retryif (isSolanaError(error, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED) ||isSolanaError(error, SOLANA_ERROR__TRANSACTION_ERROR__BLOCKHASH_NOT_FOUND)) {return { message: "Transaction expired—rebuilding", retryable: true };}// Insufficient SOL for feesif (isSolanaError(error,SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS_FOR_FEE)) {return { message: "Not enough SOL for fees", retryable: false };}// Insufficient token balanceif (isSolanaError(error, SOLANA_ERROR__INSTRUCTION_ERROR__INSUFFICIENT_FUNDS)) {return { message: "Insufficient balance", retryable: false };}// Unknown errorconsole.error("Payment error:", error);return { message: "Payment failed—please retry", retryable: true };}
Najczęstsze kody błędów:
| Kod błędu | Przyczyna | Rozwiązanie |
|---|---|---|
BLOCK_HEIGHT_EXCEEDED | Wygasł blockhash | Zbuduj ponownie z nowym blockhashem |
BLOCKHASH_NOT_FOUND | Nie znaleziono blockhash | Zbuduj ponownie z nowym blockhashem |
INSUFFICIENT_FUNDS_FOR_FEE | Za mało SOL | Zasil konto opłat lub użyj abstrakcji opłat |
INSUFFICIENT_FUNDS | Za mało tokenów | Użytkownik musi zwiększyć saldo |
ACCOUNT_NOT_FOUND | Brak token account | Utwórz ATA w transakcji |
Transakcje bez opłat (gasless)
Użytkownicy oczekują płatności w stablecoinach, bez konieczności kupowania SOL na opłaty sieciowe. Transakcje bez opłat rozwiązują ten problem—podobnie jak użytkownicy Venmo nie myślą o opłatach ACH. Pełną implementację znajdziesz w sekcji Abstrakcja opłat.
Bezpieczeństwo
Zarządzanie kluczami
- Nigdy nie ujawniaj kluczy prywatnych w kodzie frontendowym. Używaj podpisywania po stronie backendu, portfeli sprzętowych, portfeli multisig lub usług zarządzania kluczami.
- Oddziel portfele gorące od zimnych. Gorący portfel do operacji, zimny do przechowywania środków.
- Wykonaj kopie zapasowe wszystkich kluczy produkcyjnych. Przechowuj zaszyfrowane kopie w kilku bezpiecznych lokalizacjach. Utrata klucza oznacza trwałą utratę dostępu.
- Używaj różnych kluczy dla devnetu i mainnetu. Klucze devnet nie powinny być używane na mainnecie. Skonfiguruj środowiska tak, by ładowały odpowiednie klucze dla każdej sieci.
Infrastruktura podpisywania
W przypadku podpisywania po stronie backendu w środowisku produkcyjnym rozważ użycie solana-keychain—zunifikowanej biblioteki do podpisywania, która abstrahuje wiele backendów zarządzania kluczami poprzez jeden interfejs: Memory, Vault, Privy, Turnkey, AWS KMS, Fireblocks, GCP KMS, CDP, Para, Dfns. Pozwala to na lokalne programowanie z kluczami w pamięci, a następnie przełączenie na backendy klasy produkcyjnej bez zmiany kodu aplikacji.
Dostępne zarówno dla Rust, jak i TypeScript.
Sprawdź przewodnik dodawania signerów, aby zintegrować dodatkowe usługi zarządzania kluczami.
Bezpieczeństwo RPC
Traktuj endpointy RPC jak klucze API—nie ujawniaj ich w kodzie frontendowym, gdzie mogą zostać wydobyte i nadużyte. Użyj proxy backendowego lub zmiennych środowiskowych, które nie są pakowane do kodu klienta.
- QuickNode: Najlepsze praktyki bezpieczeństwa endpointów
- Helius: Chroń swoje klucze API Solana: Najlepsze praktyki bezpieczeństwa
Monitorowanie
Śledź te metryki w środowisku produkcyjnym:
| Metryka | Dlaczego |
|---|---|
| Wskaźnik sukcesu transakcji | Wczesne wykrywanie problemów |
| Opóźnienie potwierdzenia | Monitorowanie zdrowia sieci |
| Wydatki na opłatę priorytetową | Zarządzanie kosztami |
| Wskaźnik błędów RPC | Zdrowie dostawcy |
Skonfiguruj alerty dla:
- Transferów powyżej progu z treasury
- Gwałtownych wzrostów wskaźnika nieudanych transakcji
- Nietypowych wzorców odbiorców
- Wzrostów wskaźnika błędów RPC
W celu monitorowania transakcji w czasie rzeczywistym na dużą skalę zobacz nasz przewodnik po indeksowaniu.
Weryfikuj adresy
Każdy token i program ma dokładnie jeden poprawny adres na mainnecie. Sfałszowane tokeny imitujące USDC lub inne stablecoiny są powszechne—będą miały tę samą nazwę i symbol, ale inny adres mint. Twoja aplikacja powinna zakodować na stałe lub umieścić na liście dozwolonych adresy mint (w zależności od wymagań), nigdy nie akceptuj ich dynamicznie z niezaufanych źródeł.
Konfiguracja oparta na środowisku: Devnet i Mainnet często używają całkowicie różnych mintów tokenów. Skonfiguruj swoją aplikację tak, aby ładowała właściwe adresy dla każdego środowiska—nie koduj na sztywno adresów mainnet i nie zapomnij o ich zamianie podczas testowania, a co gorsza, nie wysyłaj adresów devnet do produkcji.
Niektóre popularne minty stablecoinów to:
| Token | Emitent | Adres Mint |
|---|---|---|
| USDC | Circle | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Tether | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| PYUSD | PayPal | 2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo |
| USDG | Paxos | 2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH |
Adresy programów również mają znaczenie. Wysyłanie instrukcji do niewłaściwego programu zakończy się niepowodzeniem—lub co gorsza, spowoduje nieodwracalną utratę środków. Adresy Token Program to:
| Program | Adres |
|---|---|
| Token Program | TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA |
| Token-2022 Program | TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb |
Lista kontrolna przed uruchomieniem
- Zakupiono SOL na Mainnet na opłaty i rent
- Skonfigurowano produkcyjny RPC (nie publiczny endpoint)
- Skonfigurowano zapasowy endpoint RPC
- Zaimplementowano opłaty priorytetowe z dynamiczną wyceną
- Logika ponownych prób obsługuje wygaśnięcie blockhash
- Poziom potwierdzenia odpowiedni dla przypadku użycia
- Wszystkie typowe błędy obsługiwane prawidłowo
- Skonfigurowano Gasless (jeśli dotyczy)
- Zweryfikowano adresy tokenów Mainnet (nie minty devnet)
- Wszystkie klucze bezpiecznie zarchiwizowane
- Przejrzano zarządzanie kluczami (brak kluczy we frontendzie)
- Aktywne monitorowanie transakcji i alerty
- Przeprowadzono testy obciążeniowe przy oczekiwanym wolumenie
Wdrażanie programów
Jeśli wdrażasz niestandardowy program Solana jako część swojej infrastruktury płatności, należy wziąć pod uwagę dodatkowe kwestie.
Przed wdrożeniem
- Wersja Solana CLI: Upewnij się, że używasz najnowszej wersji Solana CLI.
- Para kluczy programu: Twój program będzie miał inny adres w sieci mainnet
niż w devnet (chyba że ponownie używasz tej samej pary kluczy). Zaktualizuj
wszystkie odniesienia w konfiguracji swojej aplikacji. Przechowuj parę kluczy
programu w bezpiecznej lokalizacji (pamiętaj, że uruchomienie
cargo cleanprawdopodobnie usunie parę kluczy programu). - Inicjalizacja kont: Jeśli Twój program wymaga kont administratora, PDA lub innych kont stanu, upewnij się, że są one utworzone w sieci mainnet, zanim użytkownicy będą wchodzić w interakcje z Twoją aplikacją. To samo dotyczy wszelkich powiązanych kont tokenów (ATA), których potrzebuje Twój program.
Proces wdrożenia
- Konta buforowe: Duże programy są wdrażane za pomocą kont buforowych.
Polecenie
solana program deployobsługuje to automatycznie, ale pamiętaj, że wdrożenie nie jest atomowe — jeśli zostanie przerwane, może być konieczne odzyskanie lub zamknięcie kont buforowych. Zobacz Wdrażanie programów. - Uprawnienia do aktualizacji: Zdecyduj, czy Twój program powinien być aktualizowalny po uruchomieniu. Aby zapewnić niezmienność, cofnij uprawnienia do aktualizacji po wdrożeniu. Dla elastyczności, odpowiednio zabezpiecz klucz uprawnień do aktualizacji.
- Opłata za wynajem: Upewnij się, że Twój portfel wdrożeniowy ma wystarczającą ilość SOL, aby pokryć minimalne kwoty zwolnione z czynszu dla wszystkich kont programu.
- Weryfikacja: Zweryfikuj swój program, aby upewnić się, że program wykonywalny wdrożony w sieci Solana odpowiada kodowi źródłowemu w Twoim repozytorium
Aby uzyskać pełne wskazówki dotyczące wdrażania programów, zobacz Wdrażanie programów.
Is this page helpful?