> ## 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.

# Hướng dẫn tối ưu hóa giao dịch Solana

> Tối ưu hóa giao dịch Solana để giảm thiểu độ trễ xác nhận và tối đa hóa tỷ lệ chuyển giao. Tìm hiểu về phí ưu tiên, đơn vị tính toán và các phương pháp hay nhất.

Có hai phương thức chính để gửi giao dịch trên Solana:

1. Sử dụng [kết nối có stake](https://www.helius.dev/staked-connections) (mặc định)
2. Sử dụng các dịch vụ chuyên biệt để đưa giao dịch vào chuỗi như [Sender](https://www.helius.dev/sender) (khuyến nghị)

Bài viết này trình bày các phương pháp hay nhất để tối ưu hóa giao dịch khi sử dụng kết nối có stake, đây là phương thức mặc định cho tất cả các gói trả phí của Helius.

Kết nối có stake phù hợp nhất với các trường hợp sử dụng mà độ trễ không mang tính quyết định đối với hoạt động kinh doanh của bạn (ví dụ: thanh toán, ví, ứng dụng mạng xã hội, v.v.)

Nếu bạn là nhà giao dịch chuyên nghiệp (ví dụ: propAMM, sniper, copy trader, bot thanh lý, kinh doanh chênh lệch giá) đang tìm kiếm một dịch vụ chuyên biệt để đưa giao dịch vào chuỗi với độ trễ cực thấp, hãy đọc [hướng dẫn về Sender](/docs/vi/sending-transactions/sender).

## Tóm tắt

Kết nối có stake của Helius đảm bảo chuyển giao 100% giao dịch với thời gian xác nhận tối thiểu. Để tối ưu hóa tỷ lệ đưa giao dịch vào chuỗi bằng kết nối có stake, chúng tôi khuyến nghị các phương pháp hay nhất sau:

* Sử dụng commitment "confirmed" để truy xuất [blockhash mới nhất](/docs/vi/rpc/guides/getlatestblockhash)
* Thêm [phí ưu tiên](/docs/vi/sending-transactions/optimizing-transactions#đặt-mức-phí-ưu-tiên-phù-hợp) và tính toán phí theo cách linh hoạt
* Tối ưu hóa mức sử dụng đơn vị tính toán (CU)
* Đặt `maxRetries` thành 0 và triển khai logic thử lại mạnh mẽ
* Gửi với `skipPreflight` được đặt thành `true` (tùy chọn)

<Tip>
  Bạn muốn tìm hiểu sâu hơn? Chúng tôi trình bày tất cả kiến thức nền tảng trong [bài đăng blog](https://www.helius.dev/blog/how-to-land-transactions-on-solana) này.
</Tip>

## Các biện pháp tối ưu hóa được khuyến nghị cho nhà giao dịch

Đối với các trường hợp giao dịch nhạy cảm với độ trễ, chúng tôi khuyến nghị [sử dụng Sender](/docs/vi/sending-transactions/sender).

Tuy nhiên, nếu đang sử dụng kết nối có stake và muốn tối ưu hóa cấu hình để đạt độ trễ thấp nhất có thể, bạn nên áp dụng các biện pháp tối ưu hóa sau (ngoài các phương pháp hay nhất nêu trên):

* Máy chủ máy khách của bạn (máy dùng để gửi giao dịch) nên được đặt tại miền Đông Hoa Kỳ hoặc Tây Âu.
* Chọn FRA hoặc PIT nếu bạn muốn đặt cùng vị trí với các máy chủ gửi giao dịch của Helius.
* Tránh gửi từ các khu vực cách xa mạng lưới trình xác thực (ví dụ: Mỹ Latinh, Nam Phi).
* Làm nóng bộ nhớ đệm theo khu vực của Helius để giảm thiểu độ trễ đuôi.
* Mỗi khu vực chỉ cần một luồng làm nóng — sử dụng thêm sẽ không mang lại lợi ích nào.
* Gửi một lệnh gọi RPC [`getHealth`](/docs/vi/rpc/guides/gethealth) mỗi giây bằng cùng điểm cuối và khóa API mà bạn dùng để gửi giao dịch.

Chỉ những nhà giao dịch giàu kinh nghiệm mới nhận thấy những lợi ích này. Đối với các nhà phát triển ứng dụng nói chung, chúng tôi khuyến nghị làm theo hướng dẫn trong phần Gửi giao dịch thông minh bên dưới.

<Tip>
  Nhận dữ liệu giao dịch onchain nhanh nhất có thể bằng [Raw Shreds (UDP)](/docs/vi/shred-delivery/raw-shreds). [Đăng ký trong Bảng điều khiển Helius](https://dashboard.helius.dev/shred-delivery-seats).
</Tip>

## Gửi giao dịch thông minh

Cả SDK [TypeScript](/docs/vi/sending-transactions/optimizing-transactions#sdk-typescript) và [Rust](/docs/vi/sending-transactions/optimizing-transactions#sdk-rust) của Helius đều có thể gửi giao dịch thông minh. Phương thức mới này tạo và gửi một giao dịch đã tối ưu hóa, đồng thời xử lý trạng thái xác nhận của giao dịch.

Người dùng có thể cấu hình các tùy chọn gửi của giao dịch, chẳng hạn như có bỏ qua bước kiểm tra trước khi thực thi hay không.

Ở mức cơ bản nhất, người dùng chỉ cần cung cấp cặp khóa và các chỉ thị muốn thực thi, chúng tôi sẽ xử lý phần còn lại.

Chúng tôi sẽ:

* Truy xuất blockhash mới nhất
* Tạo giao dịch ban đầu
* Mô phỏng giao dịch ban đầu để lấy số đơn vị tính toán (CU) đã tiêu thụ
* Đặt giới hạn CU bằng số CU đã tiêu thụ ở bước trước, cộng thêm một khoảng dự phòng
* Lấy phí ưu tiên do Helius khuyến nghị thông qua [Priority Fee API](/docs/vi/priority-fee-api)
* Đặt phí ưu tiên (microlamport trên mỗi CU) thành mức phí do Helius khuyến nghị
* Thêm một khoản phí dự phòng nhỏ phòng trường hợp mức phí được khuyến nghị thay đổi trong vài giây tiếp theo
* Tạo và gửi giao dịch đã tối ưu hóa
* Trả về chữ ký giao dịch nếu thành công

<Note>
  Việc yêu cầu mức phí được khuyến nghị (hoặc cao hơn) cho các kết nối có stake đảm bảo Helius gửi các giao dịch chất lượng cao và không bị trình xác thực giới hạn tốc độ.
</Note>

Phương thức này là cách dễ nhất để tạo, gửi và đưa một giao dịch vào chuỗi trên Solana.

Khi sử dụng mức phí do Helius khuyến nghị, các giao dịch do người dùng Helius gửi bằng một trong các [gói trả phí tiêu chuẩn](/docs/vi/billing/plans) của chúng tôi sẽ được định tuyến qua kết nối có stake, đảm bảo tỷ lệ chuyển giao giao dịch gần 100% và độ trễ tối thiểu.

### SDK TypeScript

Phương thức `sendSmartTransaction` có trong [SDK TypeScript của Helius](/docs/vi/sdks/typescript) từ [phiên bản >= 1.3.2](https://www.npmjs.com/package/helius-sdk). Để cập nhật lên phiên bản SDK mới hơn, hãy chạy `npm update helius-sdk`.

Ví dụ này chuyển SOL đến một tài khoản do bạn chọn. Ví dụ sử dụng `sendSmartTransaction` để gửi một giao dịch đã tối ưu hóa mà không bỏ qua bước kiểm tra trước khi thực thi:

```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

Phương thức `send_smart_transaction` có trong [SDK Rust](/docs/vi/sdks/rust) của chúng tôi từ [phiên bản >= 0.1.5](https://docs.rs/helius/latest/helius/). Để cập nhật lên phiên bản SDK mới hơn, hãy chạy `cargo update helius`.

Ví dụ sau chuyển 0.01 SOL đến một tài khoản do bạn chọn.

Ví dụ sử dụng `send_smart_transaction` để gửi một giao dịch đã tối ưu hóa, bỏ qua bước kiểm tra trước khi thực thi và thử lại hai lần nếu cần:

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

## Gửi giao dịch mà không dùng SDK

Chúng tôi khuyến nghị gửi giao dịch thông minh bằng một trong các SDK của mình, nhưng bạn cũng có thể đạt được chức năng tương tự mà không cần sử dụng SDK.

Cả SDK TypeScript và SDK Rust đều là mã nguồn mở, vì vậy bạn có thể xem mã nguồn cơ sở của chức năng gửi giao dịch thông minh bất cứ lúc nào.

### Chuẩn bị và tạo giao dịch ban đầu

Trước tiên, hãy chuẩn bị và tạo giao dịch ban đầu. Quá trình này bao gồm việc tạo một giao dịch mới với một tập hợp chỉ thị, thêm blockhash gần đây và chỉ định người trả phí.

Đối với giao dịch có phiên bản, hãy tạo một `TransactionMessage` và biên dịch giao dịch đó với các bảng tra cứu nếu có.

Sau đó, tạo một giao dịch có phiên bản mới và ký giao dịch đó — thao tác này cần thiết cho bước tiếp theo khi chúng ta mô phỏng giao dịch vì giao dịch phải được ký.

Ví dụ, nếu muốn chuẩn bị một giao dịch có phiên bản:

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

### Tối ưu hóa mức sử dụng đơn vị tính toán (CU) của giao dịch

Để [tối ưu hóa mức sử dụng đơn vị tính toán (CU) của giao dịch](https://www.helius.dev/blog/optimizing-solana-programs), chúng ta có thể sử dụng phương thức RPC `simulateTransaction` để mô phỏng giao dịch.

[Việc mô phỏng giao dịch](/docs/vi/api-reference/rpc/http/simulatetransaction) sẽ trả về số CU đã sử dụng, vì vậy chúng ta có thể dùng giá trị này để đặt giới hạn tính toán tương ứng.

Trước tiên, bạn nên sử dụng một giao dịch thử nghiệm có các chỉ thị mong muốn, cộng thêm một chỉ thị đặt giới hạn tính toán thành 1.4 triệu CU.

Việc này nhằm đảm bảo quá trình mô phỏng giao dịch thành công.

Ví dụ:

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

Bạn cũng nên thêm một khoảng dự phòng nhỏ để đảm bảo giao dịch được thực thi mà không gặp vấn đề. Có thể thực hiện bằng cách đặt như sau:

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

Sau đó, tạo một chỉ thị đặt giới hạn đơn vị tính toán thành giá trị này và thêm chỉ thị đó vào mảng chỉ thị của bạn:

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

### Tuần tự hóa và mã hóa giao dịch

Quá trình này tương đối đơn giản.

Trước tiên, để tuần tự hóa giao dịch, cả kiểu Transaction và VersionedTransaction đều có phương thức `.serialize()`. Sau đó, sử dụng [gói bs58](https://www.npmjs.com/package/bs58) để mã hóa giao dịch.

Mã của bạn sẽ có dạng tương tự `bs58.encode(txt.serialize());`

### Đặt mức phí ưu tiên phù hợp

Trước tiên, hãy sử dụng [Priority Fee API](/docs/vi/priority-fee-api) để nhận giá trị ước tính của phí ưu tiên. Chúng ta cần truyền giao dịch vào và lấy mức phí do Helius khuyến nghị thông qua tham số 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;
```

Sau đó, tạo một chỉ thị đặt giá đơn vị tính toán thành giá trị này và thêm chỉ thị đó vào các chỉ thị trước đó:

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

instructions.push(computeBudgetIx);
```

### Tạo và gửi giao dịch đã tối ưu hóa

Bước này gần như lặp lại bước đầu tiên. Tuy nhiên, mảng chỉ thị ban đầu đã được sửa đổi để thêm hai chỉ thị nhằm đặt giới hạn và giá đơn vị tính toán ở mức tối ưu.

Bây giờ, hãy gửi giao dịch.

Việc gửi có hoặc không có bước kiểm tra trước khi thực thi hay thay đổi bất kỳ tùy chọn gửi nào khác đều không ảnh hưởng — giao dịch sẽ được định tuyến qua kết nối có stake của chúng tôi đối với tất cả các gói trả phí.

### Thăm dò trạng thái giao dịch và phát lại

<Warning>
  Mặc dù kết nối có stake sẽ chuyển tiếp giao dịch trực tiếp đến leader, giao dịch vẫn có thể bị loại bỏ trong [Giai đoạn Banking](https://www.helius.dev/blog/solana-virtual-machine#the-banking-stage). Người dùng nên triển khai logic phát lại riêng thay vì phụ thuộc vào RPC để thử lại giao dịch.
</Warning>

[Phương thức RPC `sendTransaction`](/docs/vi/api-reference/rpc/http/sendtransaction) có tham số `maxRetries` có thể được đặt để ghi đè logic thử lại mặc định của RPC, giúp nhà phát triển kiểm soát quy trình thử lại tốt hơn.

Một mô hình phổ biến là truy xuất blockhash hiện tại qua [`getLatestBlockhash`](/docs/vi/rpc/guides/getlatestblockhash), lưu `lastValidBlockHeight` và thử lại giao dịch cho đến khi blockhash hết hạn.

Điều quan trọng là chỉ ký lại giao dịch khi blockhash không còn hợp lệ; nếu không, cả hai giao dịch đều có thể được mạng chấp nhận.

Sau khi gửi giao dịch, cần thăm dò trạng thái xác nhận để xem mạng đã xử lý và xác nhận giao dịch hay chưa trước khi thử lại. Sử dụng [phương thức RPC `getSignatureStatuses`](/docs/vi/rpc/guides/getsignaturestatuses) để kiểm tra trạng thái xác nhận của danh sách giao dịch.

SDK @solana/web3.js cũng có phương thức `getSignatureStatuses` trong lớp `Connection` để truy xuất trạng thái hiện tại của nhiều chữ ký.

### Cách sendSmartTransaction xử lý việc thăm dò và phát lại

Phương thức `sendSmartTransaction` có thời gian chờ là 60 giây. Vì một blockhash hợp lệ trong 150 slot và giả định mỗi slot có thời gian chính xác là 400 mili giây, chúng ta có thể suy luận hợp lý rằng blockhash của giao dịch sẽ không còn hợp lệ sau một phút.

Phương thức này gửi giao dịch và thăm dò chữ ký của giao dịch trong khoảng thời gian chờ này:

```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` được đặt thành chữ ký của giao dịch vừa được gửi.

Sau đó, phương thức sử dụng phương thức `pollTransactionConfirmation()` để thăm dò trạng thái xác nhận của giao dịch. Phương thức này kiểm tra trạng thái của giao dịch mỗi năm giây, tối đa ba lần.

Nếu giao dịch không được xác nhận trong khoảng thời gian này, một lỗi sẽ được trả về:

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