Готовність до продакшену

Локальна розробка та тестування на devnet — чудові способи почати роботу з платежами Solana. Однак, коли ви готові до розгортання на Mainnet, потрібно врахувати нюанси mainnet. Devnet прощає помилки. Mainnet — ні. Цей посібник охоплює відмінності, які мають значення для забезпечення безперебійного досвіду ваших користувачів.

DevnetMainnet
Безкоштовний SOL з кранівПридбайте справжній SOL для комісій
Низька конкуренція за місце у блоціПріоритетні комісії мають значення
Транзакції проходять легкоКонфігурація транзакцій критична
Публічний RPC підходитьПотрібен продакшн RPC
Ключі та токени devnetІнші ключі та токени — оновіть конфігурацію

RPC-інфраструктура

Публічні ендпоінти (api.mainnet-beta.solana.com) мають обмеження швидкості без SLA. Вони підходять для розробки, але не витримають продакшн платіжних потоків — це як намагатися запустити платіжний процесор через спільний API без гарантій безвідмовності.

Ніколи не використовуйте публічний RPC для продакшену

Використовуйте приватного RPC-провайдера для надійного доступу з низькою затримкою.

При виборі RPC-провайдера зверніть увагу на:

  • Надійність: SLA з гарантіями безвідмовності (99,9%+)
  • Затримка: географічна близькість до ваших користувачів
  • Функції: функції доставки транзакцій, індексація, API пріоритетних комісій

Повний список RPC-провайдерів дивіться у посібнику Провайдери RPC-інфраструктури.

Резервна конфігурація RPC

Як і будь-який постачальник мережевих послуг, RPC-провайдери можуть зазнавати простоїв або періодів погіршення продуктивності. Щоб забезпечити стійкість вашого застосунку, слід налаштувати його на використання кількох RPC-провайдерів.

Solana Kit надає бібліотеку для налаштування RPC-транспортів, що дозволяє створювати власний резервний RPC-клієнт. Ось приклад того, як ви можете використати його для створення резервного 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);
}

Якщо ви не хочете створювати власні інструменти маршрутизації, ви можете скористатися стороннім сервісом, таким як Iron Forge, щоб він обробляв маршрутизацію за вас.

Підтвердження транзакції

У Devnet транзакції підтверджуються досить легко. У Mainnet ви конкуруєте за місце в блоці. Щоб збільшити шанси включення вашої транзакції в блок, ви повинні переконатися, що правильно зібрали транзакцію. Це означає:

  • включення свіжого blockhash перед відправкою транзакції
  • включення інструкції пріоритетної комісії в транзакцію з конкурентною пріоритетною комісією
  • включення інструкції ліміту обчислювальних одиниць у транзакцію з лімітом обчислювальних одиниць на основі оцінки необхідних обчислювальних одиниць для транзакції

Крім того, ви повинні розглянути інші інструменти, такі як Jito Bundles, щоб збільшити шанси включення вашої транзакції в блок. Давайте детальніше розглянемо ці інструменти.

Конфігурація відправки транзакції

Під час відправки транзакцій у Mainnet налаштуйте ці параметри для оптимальних показників підтвердження:

Управління blockhash:

  • Отримуйте з confirmed commitment
  • Зберігайте lastValidBlockHeight, повернутий getLatestBlockhash — це вказує, коли закінчується термін дії вашої транзакції
  • Термін дії blockhash закінчується через ~150 блоків (~60-90 секунд)

Параметри відправки:

  • maxRetries: 0 — Вимкнути автоматичні повторні спроби RPC. Обробляйте повторні спроби самостійно, щоб ви могли оновити blockhash за потреби.
  • skipPreflight: true — Пропустити симуляцію перед відправкою. Використовуйте це, коли ви вже перевірили транзакцію і хочете найменшу затримку. Залишайте false під час розробки, щоб виявляти помилки на ранніх етапах.
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

Використовуйте пріоритетні комісії

Кожна транзакція Solana вимагає комісії за транзакцію, яка сплачується в SOL. Комісії за транзакції поділяються на дві частини: базову комісію та пріоритетну комісію. Базова комісія компенсує валідаторам обробку транзакції. Пріоритетна комісія — це додаткова комісія, яка збільшує ймовірність того, що поточний лідер обробить вашу транзакцію. Уявіть це як експрес-доставку: ви платите більше за швидшу та надійнішу доставку.

Як працюють комісії:

Total fee = Base fee (5,000 lamports per signature) + Priority fee
Priority fee = Compute units x Price per unit (micro-lamports per compute unit)

Реальні витрати:

  • Простий переказ USDC: ~$0.001-0.005 за звичайних умов
  • Під час перевантаження: ~$0.01-0.05
  • Пікове перевантаження: може зростати вище

Приклад реалізації:

Пакет @solana-program/compute-budget надає допоміжну функцію для легкого оновлення або додавання інструкції ціни обчислювальної одиниці (у мікролампортах) до транзакції.

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

Отримання оцінок комісій: більшість RPC-провайдерів пропонують API пріоритетних комісій:

Для повної механіки комісій дивіться Комісії за транзакції та наш посібник: Як додати пріоритетні комісії до транзакції.

Оптимізуйте обчислювальні одиниці

Обчислення в Solana — це фактично міра обсягу роботи, яку виконує програма. Існує ліміт на кількість обчислень, які можна використати в транзакції (наразі 1,4 мільйона обчислювальних одиниць), та ліміт на кількість обчислень, які можна використати на акаунт за блок (наразі 100 мільйонів обчислювальних одиниць).

Коли ви надсилаєте транзакцію, вам потрібно оцінити кількість обчислень, які будуть використані, та відповідно встановити ліміт обчислювальних одиниць — це фактично запит на те, яка частина загальної потужності має бути зарезервована для вашої транзакції. На практиці це означає, що правильна оцінка обчислювальних одиниць, необхідних для вашої транзакції, є критично важливою для включення вашої транзакції в блок (і важливою для управління вашими пріоритетними комісіями).

Solana JSON RPC API має метод simulatetransaction, який можна використовувати для оцінки обчислювальних одиниць, необхідних для транзакції, включаючи оцінку обчислювальних одиниць, які будуть використані. @solana/kit надає допоміжні функції, які оцінюють ліміти ресурсів транзакції та встановлюють їх у повідомленні за один крок (використовуючи метод simulatetransaction під капотом). Для транзакцій версії 1 ці помічники також оцінюють ліміт розміру даних завантажених акаунтів.

import {
estimateResourceLimitsFactory,
estimateAndSetResourceLimitsFactory
} from "@solana/kit";
const estimateResourceLimits = estimateResourceLimitsFactory({ rpc });
const estimateAndSetResourceLimits = estimateAndSetResourceLimitsFactory(
estimateResourceLimits
);
const txWithResourceLimits = await estimateAndSetResourceLimits(tx);

Якщо ви збираєте та надсилаєте транзакції за допомогою клієнта з плагіном kit, вам зазвичай не потрібен цей крок — клієнт додає інструкції бюджету обчислень за вас під час надсилання (.sendTransaction()). Ручний процес вище призначений для випадків, коли ви збираєте транзакції безпосередньо за допомогою @solana/kit.

У продакшні, якщо ви повторюєте один і той самий тип транзакції кілька разів, вам слід розглянути можливість кешування оцінки обчислень для цього типу транзакції, щоб уникнути накладних витрат на оцінку обчислювальних одиниць щоразу.

Jito Bundles

Jito bundles — це інструмент для керування атомарним виконанням кількох транзакцій. Це досягається шляхом надсилання кількох транзакцій до мережі Jito з чайовими. Чайові можна використовувати для стимулювання мережі Jito до включення ваших транзакцій у блок.

Ресурси:

Стратегії повторних спроб

Транзакції можуть зазнати невдачі з багатьох причин. На відміну від традиційних платіжних API, які негайно повертають успіх/невдачу, блокчейн-транзакції потребують відстеження підтвердження.

Ключові концепції:

  • Закінчення терміну дії блокхешу: Транзакції дійсні протягом ~150 блоків (~60–90 секунд)
  • Ідемпотентність: Одна й та сама підписана транзакція завжди породжує однаковий підпис — повторне надсилання є безпечним
  • Експоненційне відкладення: Уникайте перевантаження мережі частими повторними спробами
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 з @solana/kit автоматично обробляє підтвердження та відстеження висоти блоку. Він викидає SOLANA_ERROR__BLOCK_HEIGHT_EXCEEDED, коли blockhash транзакції закінчується, сигналізуючи про необхідність перебудувати транзакцію з новим blockhash.

Додаткові ресурси

Розуміння рівнів підтвердження

Solana пропонує три рівні підтвердження. У термінах традиційних фінансів:

РівеньВизначення SolanaТрадиційний еквівалентВипадок використання
processedУ блоці, ще не проголосованоАвторизація в очікуванніОновлення UI в реальному часі
confirmedПроголосовано супербільшістюКошти зарахованоБільшість платежів
finalizedУкорінено, незворотноКошти розрахованоВисока вартість, відповідність вимогам

Коли використовувати кожен:

  • Оновлення UI: показуйте processed для миттєвого зворотного зв'язку («Платіж надіслано»)
  • Зарахування на рахунок користувача: чекайте confirmed (безпечно для більшості транзакцій)
  • Відправка фізичних товарів: чекайте finalized
  • Великі виведення коштів: чекайте finalized
  • Відповідність вимогам/аудит: завжди записуйте статус finalized

Докладніше про перевірку статусу транзакцій див. у розділі Взаємодія з Solana.

Обробка помилок

Solana Kit надає типізовані помилки через isSolanaError(). Використовуйте конкретні коди помилок замість зіставлення рядків:

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

Поширені коди помилок:

Код помилкиПричинаВідновлення
BLOCK_HEIGHT_EXCEEDEDBlockhash закінчивсяПеребудувати з новим blockhash
BLOCKHASH_NOT_FOUNDBlockhash не знайденоПеребудувати з новим blockhash
INSUFFICIENT_FUNDS_FOR_FEEНедостатньо SOLПоповніть рахунок платника комісії або скористайтесь абстракцією комісії
INSUFFICIENT_FUNDSНедостатньо токенівКористувачу потрібно більше балансу
ACCOUNT_NOT_FOUNDtoken account відсутнійСтворіть ATA в транзакції

Транзакції без комісії

Користувачі очікують платити стейблкоїнами, а не купувати SOL для оплати мережевих комісій. Транзакції без комісії вирішують цю проблему — подібно до того, як користувачі Venmo не замислюються про комісії ACH. Дивіться Абстракція комісій для повної інструкції з реалізації.

Безпека

Управління ключами

  • Ніколи не розкривайте приватні ключі у фронтенд-коді. Використовуйте підписання на бекенді, апаратні гаманці, мультипідписні гаманці або сервіси управління ключами.
  • Розділяйте гарячі та холодні гаманці. Гарячий гаманець — для операцій, холодний — для скарбниці.
  • Робіть резервні копії всіх виробничих ключів. Зберігайте зашифровані резервні копії в кількох захищених місцях. Втрата ключа означає безповоротну втрату доступу.
  • Використовуйте різні ключі для devnet і mainnet. Ваші ключі для devnet не повинні збігатися з ключами для mainnet. Використовуйте конфігурацію на основі середовища, щоб забезпечити завантаження правильних ключів для кожної мережі.

Інфраструктура підписання

Для підписання на виробничому бекенді використовуйте Keychain — уніфіковану бібліотеку підписання, яка абстрагує кілька бекендів управління ключами через єдиний інтерфейс: Memory, Vault, Privy, Turnkey, AWS KMS, Fireblocks, GCP KMS, CDP, Para, Dfns, Crossmint, Openfort та Utila. Це дозволяє розробляти локально з ключами в пам'яті, а потім переходити на бекенди виробничого рівня без зміни коду застосунку.

Не впевнені, який бекенд підходить? Дивіться Вибір бекенду. Keychain доступний як для Rust, так і для TypeScript.

Безпека RPC

Ставтеся до RPC ендпоінтів як до API ключів—не розкривайте їх у фронтенд-коді, де вони можуть бути вилучені та використані неналежним чином. Використовуйте проксі на бекенді або змінні оточення, які не включаються в клієнтський код.

Моніторинг

Відстежуйте ці метрики у виробництві:

МетрикаЧому
Відсоток успішних транзакційРаннє виявлення проблем
Затримка підтвердженняМоніторинг здоров'я мережі
Витрати на пріоритетні комісіїУправління витратами
Відсоток помилок RPCЗдоров'я провайдера

Налаштуйте сповіщення для:

  • Переказів вище порогу з казначейства
  • Сплесків кількості невдалих транзакцій
  • Незвичайних шаблонів одержувачів
  • Зростання частоти помилок RPC

Для моніторингу транзакцій у реальному часі в масштабі ознайомтеся з нашим посібником з індексації.

Перевіряйте адреси

Кожен токен і програма мають рівно одну правильну адресу в мейннеті. Підроблені токени, що імітують USDC або інші стейблкоіни, є поширеними—вони матимуть ту саму назву і символ, але іншу адресу mint. Ваш застосунок повинен жорстко кодувати або дозволяти лише адреси mint (залежно від ваших вимог), ніколи не приймати їх динамічно з ненадійних джерел.

Конфігурація на основі середовища: Devnet і Mainnet часто використовують абсолютно різні токен-монети. Налаштуйте конфігурацію вашого застосунку для завантаження правильних адрес для кожного середовища — не використовуйте жорстко закодовані адреси mainnet і не забувайте змінювати їх під час тестування, або, що ще гірше, не випускайте devnet-адреси у продакшн.

Деякі поширені монети стейблкоїнів:

ТокенЕмітентАдреса монети
USDCCircleEPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
USDTTetherEs9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB
PYUSDPayPal2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo
USDGPaxos2u1tszSeqZ3qBWF3uNGPFc8TzMk2tdiwknnRMWGWjGWH

Адреси програм також мають значення. Надсилання інструкцій не до тієї програми призведе до помилки — або, що ще гірше, до незворотної втрати коштів. Адреси Token Program:

ПрограмаАдреса
Token ProgramTokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA
Token-2022 ProgramTokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb

Додавання правильних адрес до списку дозволених захищає від підроблених токенів, але не захищає від надсилання на неправильний тип облікового запису. Адреса отримувача може бути гаманцем, token account, монетним двором або програмою, і кожен варіант вимагає окремої обробки. Нативний SOL, надісланий на будь-що, крім гаманця, виходить із контролю відправника — безповоротно втрачений у разі монетного двору або програми, і може бути повернутий лише власником облікового запису у випадку token account — без жодної помилки транзакції, яка б попередила користувача.

Перевіряйте отримувачів перед надсиланням

Класифікуйте кожну адресу отримувача перед підписанням переказу. Дивіться Перевірка адреси для повного дерева рішень та референсного коду, що розрізняє гаманці, token account, монетні двори та програми.

Контрольний список перед запуском

  • Отримано SOL у мережі Mainnet для оплати комісій та rent
  • Налаштовано робочий RPC (не публічний endpoint)
  • Налаштовано резервний RPC endpoint
  • Реалізовано пріоритетні комісії з динамічним ціноутворенням
  • Логіка повторних спроб обробляє закінчення терміну дії blockhash
  • Рівень підтвердження відповідає варіанту використання
  • Всі поширені помилки обробляються коректно
  • Налаштовано Gasless (якщо застосовно)
  • Перевірено адреси токенів у Mainnet (не devnet mints)
  • Перевірка адреси отримувача перед надсиланням (гаманець, token account, монетний двір або програма)
  • Всі ключі надійно збережено в резервній копії
  • Перевірено управління ключами (без ключів у frontend)
  • Активовано моніторинг транзакцій та сповіщення
  • Проведено навантажувальне тестування при очікуваному обсязі

Розгортання програм

Якщо ви розгортаєте власну програму Solana як частину вашої платіжної інфраструктури, існують додаткові міркування.

Перед розгортанням

  • Версія Solana CLI: Переконайтеся, що ви використовуєте найновішу версію Solana CLI.
  • keypair програми: Ваша програма матиме іншу адресу в mainnet, ніж у devnet (якщо ви не використовуєте той самий keypair повторно). Оновіть усі посилання у конфігурації вашого застосунку. Зберігайте keypair програми в надійному місці (зверніть увагу, що запуск cargo clean, швидше за все, видалить ваш keypair програми).
  • Ініціалізація акаунтів: Якщо ваша програма потребує адміністративних акаунтів, PDA або інших акаунтів стану, переконайтеся, що вони створені в mainnet до того, як користувачі почнуть взаємодіяти з вашим застосунком. Те саме стосується будь-яких associated token account (ATA), необхідних вашій програмі.

Процес розгортання

  • Буферні акаунти: Великі програми розгортаються через буферні акаунти. Команда solana program deploy обробляє це автоматично, однак майте на увазі, що розгортання не є атомарним — якщо його перервати, може знадобитися відновити або закрити буферні акаунти. Дивіться Deploying Programs.
  • Права на оновлення: Вирішіть, чи повинна ваша програма бути придатною до оновлення після запуску. Для забезпечення незмінності відкличте права на оновлення після розгортання. Для гнучкості надійно захистіть ключ прав на оновлення.
  • Оренда: Переконайтеся, що ваш гаманець для розгортання має достатньо SOL для покриття мінімумів звільнення від оренди для всіх program account.
  • Верифікація: Верифікуйте вашу програму, щоб переконатися, що виконуваний файл програми, який ви розгортаєте в мережі Solana, відповідає вихідному коду у вашому репозиторії

Для отримання повного керівництва з розгортання програм дивіться Deploying Programs.

Is this page helpful?