Gotowość produkcyjna

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.

DevnetMainnet
Darmowe SOL z faucetówZdobądź prawdziwe SOL na opłaty
Niska konkurencja o miejsce w blokuOpłaty priorytetowe mają znaczenie
Transakcje przechodzą łatwoKonfiguracja transakcji jest kluczowa
Publiczny RPC wystarczaWymagany produkcyjny RPC
Klucze i minty z devnetuInne 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 server
const 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 them
let 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 confirmed commitment
  • Zapisz lastValidBlockHeight zwrócony przez getLatestBlockhash — 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 to false podczas developmentu, aby wcześnie wychwycić błędy.
import { createSolanaRpc } from "@solana/kit";
const rpc = createSolanaRpc(process.env.RPC_URL!);
// 1. Get blockhash with confirmed commitment
const { value: latestBlockhash } = await rpc
.getLatestBlockhash({ commitment: "confirmed" })
.send();
// 2. Build and sign your transaction with the blockhash
// ... (transaction building code)
// 3. Send with production settings
const signature = await rpc
.sendTransaction(encodedTransaction, {
encoding: "base64",
maxRetries: 0n, // Handle retries yourself
skipPreflight: true, // Skip simulation for speed (use false during dev)
preflightCommitment: "confirmed"
})
.send();
// 4. Track expiration using lastValidBlockHeight
const { 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 fee
Priority 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 monitoring
try {
await sendAndConfirmTransaction(signedTransaction, {
commitment: "confirmed",
// Optional: abort after 75 seconds
abortSignal: AbortSignal.timeout(75_000)
});
} catch (e) {
if (isSolanaError(e, SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED)) {
// Blockhash expired—rebuild transaction with fresh blockhash and retry
rebuildAndRetryTransaction(); // 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

Poziomy potwierdzenia – wyjaśnienie

Solana oferuje trzy poziomy potwierdzenia. W kategoriach finansów tradycyjnych:

PoziomDefinicja SolanaOdpowiednik tradycyjnyPrzykład użycia
processedW bloku, jeszcze niezatwierdzone głosowaniemOczekuje na autoryzacjęAktualizacje UI w czasie rzeczywistym
confirmedZatwierdzone przez superwiększośćŚrodki rozliczoneWiększość płatności
finalizedZakorzenione, nieodwracalneŚrodki rozliczone ostatecznieWysokie kwoty, zgodność z przepisami

Kiedy używać którego:

  • Aktualizacje UI: Pokazuj processed dla 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 retry
if (
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 fees
if (
isSolanaError(
error,
SOLANA_ERROR__TRANSACTION_ERROR__INSUFFICIENT_FUNDS_FOR_FEE
)
) {
return { message: "Not enough SOL for fees", retryable: false };
}
// Insufficient token balance
if (
isSolanaError(error, SOLANA_ERROR__INSTRUCTION_ERROR__INSUFFICIENT_FUNDS)
) {
return { message: "Insufficient balance", retryable: false };
}
// Unknown error
console.error("Payment error:", error);
return { message: "Payment failed—please retry", retryable: true };
}

Najczęstsze kody błędów:

Kod błęduPrzyczynaRozwiązanie
BLOCK_HEIGHT_EXCEEDEDWygasł blockhashZbuduj ponownie z nowym blockhashem
BLOCKHASH_NOT_FOUNDNie znaleziono blockhashZbuduj ponownie z nowym blockhashem
INSUFFICIENT_FUNDS_FOR_FEEZa mało SOLZasil konto opłat lub użyj abstrakcji opłat
INSUFFICIENT_FUNDSZa mało tokenówUżytkownik musi zwiększyć saldo
ACCOUNT_NOT_FOUNDBrak token accountUtwó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.

Monitorowanie

Śledź te metryki w środowisku produkcyjnym:

MetrykaDlaczego
Wskaźnik sukcesu transakcjiWczesne wykrywanie problemów
Opóźnienie potwierdzeniaMonitorowanie zdrowia sieci
Wydatki na opłatę priorytetowąZarządzanie kosztami
Wskaźnik błędów RPCZdrowie 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:

TokenEmitentAdres Mint
USDCCircleEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTTetherEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
PYUSDPayPal2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
USDGPaxos2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH

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:

ProgramAdres
Token ProgramTokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Token-2022 ProgramTokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb

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 clean prawdopodobnie 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 deploy obsł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?

Zarządzane przez

© 2026 Solana Foundation.
Wszelkie prawa zastrzeżone.
Bądź na bieżąco