> ## Documentation Index
> Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Руководство по оптимизации транзакций Solana

> Оптимизируйте транзакции Solana, чтобы минимизировать задержку подтверждения и повысить долю успешно доставленных транзакций. Узнайте о комиссиях за приоритет, вычислительных единицах и рекомендациях.

Существует два основных способа отправки транзакций в Solana:

1. Использование [стейкинговых подключений](https://www.helius.dev/staked-connections) (по умолчанию)
2. Использование специализированных сервисов доставки транзакций, таких как [Sender](https://www.helius.dev/sender) (рекомендуется)

В этой статье описаны рекомендации по оптимизации транзакций при использовании стейкинговых подключений — метода по умолчанию для всех платных тарифов Helius.

Стейкинговые подключения лучше всего подходят для сценариев, в которых задержка не критична для вашего бизнеса (например, платежи, кошельки, социальные приложения и т. д.).

Если вы опытный трейдер (например, используете propAMM, снайпер-бота, копитрейдинг, ликвидационного бота или арбитраж) и вам нужен специализированный сервис доставки транзакций со сверхнизкой задержкой, ознакомьтесь с нашим [руководством по Sender](/docs/ru/sending-transactions/sender).

## Краткое содержание

Стейкинговые подключения Helius гарантируют доставку 100% транзакций с минимальным временем подтверждения. Чтобы повысить долю успешно доставленных транзакций при использовании стейкинговых подключений, следуйте этим рекомендациям:

* Используйте уровень подтверждения "confirmed" для получения [последнего хеша блока](/docs/ru/rpc/guides/getlatestblockhash)
* Добавляйте [комиссии за приоритет](/docs/ru/sending-transactions/optimizing-transactions#установка-правильной-комиссии-за-приоритет) и рассчитывайте их динамически
* Оптимизируйте использование вычислительных единиц (CU)
* Установите `maxRetries` равным 0 и реализуйте надежную логику повторных попыток
* Отправляйте транзакции, задав для `skipPreflight` значение `true` (необязательно)

<Tip>
  Хотите узнать больше? Все основные сведения приведены в этой [публикации в блоге](https://www.helius.dev/blog/how-to-land-transactions-on-solana).
</Tip>

## Рекомендуемые оптимизации для трейдеров

Для чувствительных к задержке торговых сценариев рекомендуем [использовать Sender](/docs/ru/sending-transactions/sender).

Однако если вы используете стейкинговые подключения и хотите добиться минимально возможной задержки, рекомендуем применить следующие оптимизации в дополнение к описанным выше рекомендациям:

* Ваш клиентский сервер (компьютер, с которого вы отправляете транзакции) должен находиться на востоке США или в Западной Европе.
* Выберите FRA или PIT, если хотите разместить сервер рядом с серверами Helius, отправляющими транзакции.
* Не отправляйте транзакции из регионов, удаленных от сети валидаторов (например, из Латинской Америки или Южной Африки).
* Прогревайте региональные кеши Helius, чтобы минимизировать задержку в хвосте распределения.
* Для каждого региона достаточно одного потока прогрева — дополнительные потоки не дадут никакого преимущества.
* Каждую секунду отправляйте RPC-вызов [`getHealth`](/docs/ru/rpc/guides/gethealth), используя ту же конечную точку и ключ API, что и для отправки транзакций.

Эти преимущества будут заметны только опытным трейдерам. Разработчикам обычных приложений рекомендуем следовать указаниям из раздела «Отправка умных транзакций» ниже.

<Tip>
  Получайте ончейн-данные транзакций максимально быстро с помощью [Raw Shreds (UDP)](/docs/ru/shred-delivery/raw-shreds). [Оформите подписку в панели управления Helius](https://dashboard.helius.dev/shred-delivery-seats).
</Tip>

## Отправка умных транзакций

SDK Helius для [TypeScript](/docs/ru/sending-transactions/optimizing-transactions#sdk-для-typescript) и [Rust](/docs/ru/sending-transactions/optimizing-transactions#sdk-для-rust) поддерживают отправку умных транзакций. Этот новый метод создает и отправляет оптимизированную транзакцию, а также отслеживает состояние ее подтверждения.

Пользователи могут настраивать параметры отправки транзакции, например указывать, нужно ли пропускать предварительные проверки.

В простейшем случае пользователям достаточно предоставить свою пару ключей и инструкции, которые необходимо выполнить, — остальное мы сделаем сами.

Мы выполняем следующие действия:

* Получаем последний хеш блока
* Создаем исходную транзакцию
* Моделируем исходную транзакцию, чтобы определить количество потребленных вычислительных единиц (CU)
* Задаем лимит CU на основе количества CU, потребленных на предыдущем шаге, с небольшим запасом
* Получаем рекомендуемую Helius комиссию за приоритет через наш [Priority Fee API](/docs/ru/priority-fee-api)
* Устанавливаем комиссию за приоритет (в микролампортах на CU) равной рекомендуемой Helius комиссии
* Добавляем небольшой запас на случай, если рекомендуемая комиссия изменится в ближайшие несколько секунд
* Создаем и отправляем оптимизированную транзакцию
* В случае успеха возвращаем подпись транзакции

<Note>
  Требование использовать рекомендуемое или более высокое значение для наших стейкинговых подключений гарантирует, что Helius отправляет качественные транзакции и валидаторы не применяют к нам ограничение частоты запросов.
</Note>

Этот метод — самый простой способ создать, отправить и доставить транзакцию в Solana.

Если использовать рекомендуемую Helius комиссию, транзакции пользователей Helius на одном из наших [стандартных платных тарифов](/docs/ru/billing/plans) будут направляться через стейкинговые подключения. Это гарантирует почти 100%-ную доставку транзакций и минимальную задержку.

### SDK для TypeScript

Метод `sendSmartTransaction` доступен в нашем [SDK Helius для TypeScript](/docs/ru/sdks/typescript) в [версиях >= 1.3.2](https://www.npmjs.com/package/helius-sdk). Чтобы обновить SDK до более новой версии, выполните `npm update helius-sdk`.

В этом примере SOL переводятся на выбранный вами счет. Для отправки оптимизированной транзакции без пропуска предварительных проверок используется `sendSmartTransaction`:

```typescript theme={"system"}
import { Helius } from "helius-sdk";
import {
  Keypair,
  SystemProgram,
  LAMPORTS_PER_SOL,
  TransactionInstruction,
} from "@solana/web3.js";

const helius = new Helius("YOUR_API_KEY");
const fromKeypair = /* Your keypair goes here */;
const fromPubkey = fromKeypair.publicKey;
const toPubkey = /* The person we're sending 0.5 SOL to */;

const instructions: TransactionInstruction[] = [
  SystemProgram.transfer({
    fromPubkey: fromPubkey,
    toPubkey: toPubkey,
    lamports: 0.5 * LAMPORTS_PER_SOL, 
  }),
];

const transactionSignature = await helius.rpc.sendSmartTransaction(instructions, [fromKeypair]);
console.log(`Successful transfer: ${transactionSignature}`);
```

### SDK для Rust

Метод `send_smart_transaction` доступен в нашем [SDK для Rust](/docs/ru/sdks/rust) в [версиях >= 0.1.5](https://docs.rs/helius/latest/helius/). Чтобы обновить SDK до более новой версии, выполните `cargo update helius`.

В следующем примере 0,01 SOL переводится на выбранный вами счет.

Для отправки оптимизированной транзакции с пропуском предварительных проверок и двумя повторными попытками при необходимости используется `send_smart_transaction`:

```rust theme={"system"}
use helius::types::*;
use helius::Helius;
use solana_sdk::{
    pubkey::Pubkey,
    signature::Keypair,
    system_instruction
};

#[tokio::main]
async fn main() {
    let api_key: &str = "YOUR_API_KEY";
    let cluster: Cluster = Cluster::MainnetBeta;
    let helius: Helius = Helius::new(api_key, cluster).unwrap();
    
    let from_keypair: Keypair = /* Your keypair goes here */;
    let from_pubkey: Pubkey = from_keypair.pubkey();
    let to_pubkey: Pubkey = /* The person we're sending 0.01 SOL to */;

    // Create a simple instruction (transfer 0.01 SOL from from_pubkey to to_pubkey)
    let transfer_amount = 100_000; // 0.01 SOL in lamports
    let instruction = system_instruction::transfer(&from_pubkey, &to_pubkey, transfer_amount);

    // Create the SmartTransactionConfig
    let config = SmartTransactionConfig {
        instructions,
        signers: vec![&from_keypair],
        send_options: RpcSendTransactionConfig {
            skip_preflight: true,
            preflight_commitment: None,
            encoding: None,
            max_retries: Some(2),
            min_context_slot: None,
        },
        lookup_tables: None,
    };

    // Send the optimized transaction
    match helius.send_smart_transaction(config).await {
        Ok(signature) => {
            println!("Transaction sent successfully: {}", signature);
        }
        Err(e) => {
            eprintln!("Failed to send transaction: {:?}", e);
        }
    }
}
```

## Отправка транзакций без SDK

Рекомендуем отправлять умные транзакции с помощью одного из наших SDK, но те же возможности доступны и без SDK.

SDK для TypeScript и Rust имеют открытый исходный код, поэтому вы в любое время можете просмотреть код, реализующий отправку умных транзакций.

### Подготовка и создание исходной транзакции

Сначала подготовьте и создайте исходную транзакцию. Для этого создайте новую транзакцию с набором инструкций, добавьте последний хеш блока и назначьте плательщика комиссии.

Для версионированных транзакций создайте `TransactionMessage` и скомпилируйте его с таблицами поиска, если они имеются.

Затем создайте новую версионированную транзакцию и подпишите ее. Это необходимо для следующего шага, на котором мы моделируем транзакцию, поскольку она должна быть подписана.

Например, чтобы подготовить версионированную транзакцию:

```typescript theme={"system"}
// Prepare your instructions and set them to an instructions variable
// The payerKey is the public key that will be paying for this transaction
// Prepare your lookup tables and set them to a lookupTables variable
let recentBlockhash = (await this.connection.getLatestBlockhash()).blockhash;
const v0Message = new TransactionMessage({
    instructions: instructions,
    payerKey: pubKey,
    recentBlockhash: recentBlockhash,
}).compileToV0Message(lookupTables);
versionedTransaction = new VersionedTransaction(v0Message);
versionedTransaction.sign([fromKeypair]);
```

### Оптимизация использования вычислительных единиц (CU) транзакцией

Чтобы [оптимизировать использование вычислительных единиц (CU) транзакцией](https://www.helius.dev/blog/optimizing-solana-programs), можно смоделировать транзакцию с помощью RPC-метода `simulateTransaction`.

[Моделирование транзакции](/docs/ru/api-reference/rpc/http/simulatetransaction) вернет количество использованных CU. Это значение можно использовать для соответствующей настройки лимита вычислительных единиц.

Рекомендуется сначала использовать тестовую транзакцию с нужными инструкциями, а также добавить инструкцию, устанавливающую лимит вычислений равным 1,4 млн CU.

Это необходимо для успешного моделирования транзакции.

Например:

```typescript theme={"system"}
const testInstructions = [
    ComputeBudgetProgram.setComputeUnitLimit({ units: 1_400_000 }),
    ...instructions,
];

const testTransaction = new VersionedTransaction(
    new TransactionMessage({
        instructions: testInstructions,
        payerKey: payer,
        recentBlockhash: (await this.connection.getLatestBlockhash()).blockhash,
    }).compileToV0Message(lookupTables)
);

const rpcResponse = await this.connection.simulateTransaction(testTransaction, {
    replaceRecentBlockhash: true,
    sigVerify: false,
});

const unitsConsumed = rpcResponse.value.unitsConsumed;
```

Также рекомендуется добавить небольшой запас, чтобы транзакция выполнилась без проблем. Для этого задайте следующее:

```typescript theme={"system"}
let customersCU = Math.ceil(unitsConsumed * 1.1);
```

Затем создайте инструкцию, устанавливающую это значение в качестве лимита вычислительных единиц, и добавьте ее в массив инструкций:

```typescript theme={"system"}
const computeUnitIx = ComputeBudgetProgram.setComputeUnitLimit({
    units: customersCU
});
instructions.push(computeUnitIx);
```

### Сериализация и кодирование транзакции

Этот процесс относительно прост.

Сначала сериализуйте транзакцию. Типы Transaction и VersionedTransaction имеют для этого метод `.serialize()`. Затем закодируйте транзакцию с помощью [пакета bs58](https://www.npmjs.com/package/bs58).

Ваш код должен выглядеть примерно так: `bs58.encode(txt.serialize());`

### Установка правильной комиссии за приоритет

Сначала получите оценку комиссии за приоритет с помощью [Priority Fee API](/docs/ru/priority-fee-api). Передайте транзакцию и получите рекомендуемую Helius комиссию через параметр recommended:

```typescript theme={"system"}
const response = await fetch(HeliusURL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        jsonrpc: "2.0",
        id: "1",
        method: "getPriorityFeeEstimate",
        params: [
            {
                transaction: bs58.encode(versionedTransaction), // Pass the serialized transaction in
                options: { recommended: true },
            },
        ],   
    }),
});

const data = await response.json();
const priorityFeeRecommendation = data.result.priorityFeeEstimate;
```

Затем создайте инструкцию, устанавливающую это значение в качестве цены вычислительной единицы, и добавьте ее к предыдущим инструкциям:

```typescript theme={"system"}
const computeBudgetIx = ComputeBudgetProgram.setComputeUnitPrice({
    microLamports: priorityFeeRecommendation,
});

instructions.push(computeBudgetIx);
```

### Создание и отправка оптимизированной транзакции

Этот шаг почти полностью повторяет первый. Однако в массив исходных инструкций добавлены две инструкции, которые оптимально задают лимит и цену вычислительной единицы.

Теперь отправьте транзакцию.

Неважно, отправляете ли вы транзакцию с предварительными проверками или без них и изменяете ли другие параметры отправки: на всех платных тарифах транзакция будет направлена через наши стейкинговые подключения.

### Опрос состояния транзакции и повторная отправка

<Warning>
  Хотя стейкинговые подключения пересылают транзакцию непосредственно лидеру, она все равно может быть отброшена на [этапе банковской обработки](https://www.helius.dev/blog/solana-virtual-machine#the-banking-stage). Рекомендуем реализовать собственную логику повторной отправки, а не полагаться на RPC при повторных попытках отправки транзакции.
</Warning>

У [RPC-метода `sendTransaction`](/docs/ru/api-reference/rpc/http/sendtransaction) есть параметр `maxRetries`. Его можно задать, чтобы переопределить стандартную логику повторных попыток RPC и предоставить разработчикам больше контроля над этим процессом.

Распространенный подход — получить текущий хеш блока через [`getLatestBlockhash`](/docs/ru/rpc/guides/getlatestblockhash), сохранить `lastValidBlockHeight` и повторять отправку транзакции до истечения срока действия хеша блока.

Крайне важно повторно подписывать транзакцию только после того, как хеш блока перестанет быть действительным. В противном случае сеть может принять обе транзакции.

После отправки транзакции важно опрашивать состояние ее подтверждения, чтобы перед повторной попыткой узнать, обработала и подтвердила ли ее сеть. Используйте [RPC-метод `getSignatureStatuses`](/docs/ru/rpc/guides/getsignaturestatuses), чтобы проверить состояние подтверждения списка транзакций.

В SDK @solana/web3.js класс `Connection` также содержит метод `getSignatureStatuses` для получения текущего состояния нескольких подписей.

### Как sendSmartTransaction выполняет опрос и повторную отправку

Тайм-аут метода `sendSmartTransaction` составляет 60 секунд. Поскольку хеш блока действителен в течение 150 слотов, а идеальная продолжительность слота составляет 400 мс, можно обоснованно предположить, что хеш блока транзакции станет недействительным через одну минуту.

Метод отправляет транзакцию и опрашивает состояние ее подписи в течение этого периода ожидания:

```typescript theme={"system"}
try {
   // Create a smart transaction
   const transaction = await this.createSmartTransaction(instructions, signers, lookupTables, sendOptions);
  
   const timeout = 60000;
   const startTime = Date.now();
   let txtSig;
  
   while (Date.now() - startTime < timeout) {
     try {
       txtSig = await this.connection.sendRawTransaction(transaction.serialize(), {
         skipPreflight: sendOptions.skipPreflight,
         ...sendOptions,
       });
  
       return await this.pollTransactionConfirmation(txtSig);
     } catch (error) {
       continue;
     }
   }
} catch (error) {
   throw new Error(`Error sending smart transaction: ${error}`);
}
```

Для `txtSig` устанавливается подпись только что отправленной транзакции.

Затем метод использует `pollTransactionConfirmation()` для опроса состояния подтверждения транзакции. Этот метод проверяет состояние транзакции каждые пять секунд, но не более трех раз.

Если за это время транзакция не будет подтверждена, возвращается ошибка:

```typescript theme={"system"}
async pollTransactionConfirmation(txtSig: TransactionSignature): Promise<TransactionSignature> {
    // 15 second timeout
    const timeout = 15000;
    // 5 second retry interval
    const interval = 5000;
    let elapsed = 0;

    return new Promise<TransactionSignature>((resolve, reject) => {
      const intervalId = setInterval(async () => {
        elapsed += interval;

        if (elapsed >= timeout) {
          clearInterval(intervalId);
          reject(new Error(`Transaction ${txtSig}'s confirmation timed out`));
        }

        const status = await this.connection.getSignatureStatuses([txtSig]);

        if (status?.value[0]?.confirmationStatus === "confirmed") {
          clearInterval(intervalId);
          resolve(txtSig);
        }
      }, interval);
   });
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.