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

# Cách sử dụng preconfSubscribe

> Truyền phát các giao dịch Solana với độ trễ thấp nhất có thể bằng phương thức WebSocket preconfSubscribe — đăng ký, lọc và giải mã payload.

<Tip>
  **Sử dụng [Sender Max](/docs/vi/sending-transactions/sender-max) (tiền tip tối thiểu: 0.001 SOL) để
  hành động dựa trên Preconfirmations.** Một preconfirmation chỉ mang lại lợi ích nếu giao dịch của bạn
  được ghi nhận
  trước tiên — Sender Max là cách nhanh nhất để làm điều đó. Hãy xây dựng trên Sender Max ngay từ
  đầu để tận dụng toàn bộ lợi ích của Preconfirmations.
</Tip>

## `preconfSubscribe` là gì?

`preconfSubscribe` là một phương thức WebSocket của Helius dùng để truyền phát [Preconfirmations](/docs/vi/pre-confirmations/overview) — các giao dịch được phân phối trước khi chúng được tập hợp thành các entry và chia thành shred. Đây là tín hiệu giao dịch có độ trễ thấp nhất mà Helius cung cấp. Một lượt đăng ký cung cấp cả preconfirmation của Helius, được phát ngay khi leader thực thi giao dịch và chứa trạng thái thực thi của giao dịch, lẫn [preconfirmation của BAM](/docs/vi/pre-confirmations/overview#bam-preconfirmations) từ các validator chạy ứng dụng khách Block Assembly Marketplace của Jito, được phát khi validator cam kết thực thi giao dịch. Quyền truy cập yêu cầu [gói Professional trở lên](/docs/vi/billing/plans) — xem [Mức giá](#mức-giá).

<Note>
  Luồng không liên tục. Phạm vi bao phủ tăng theo tỷ lệ stake
  chuyển tiếp đến Helius hoặc chạy BAM, vì vậy có thể sẽ có các slot không có thông báo — hãy xử lý
  các khoảng trống này một cách phù hợp. Xem [Phạm vi bao phủ](/docs/vi/pre-confirmations/overview#phạm-vi-phủ).
</Note>

`preconfSubscribe` được cung cấp từ `wss://beta.helius-rpc.com` — endpoint [Gatekeeper](/docs/vi/gatekeeper/overview) của Helius — thay vì `mainnet.helius-rpc.com`. Xác thực bằng khóa API của bạn dưới dạng tham số truy vấn.

```
wss://beta.helius-rpc.com/?api-key=<API_KEY>
```

<Note>
  Tên máy chủ `beta` đề cập đến quá trình triển khai [Gatekeeper](/docs/vi/gatekeeper/overview),
  không phải mức độ hoàn thiện của Preconfirmations. Preconfirmations được ra mắt trước tiên trên
  endpoint Gatekeeper; endpoint này sẽ trở thành endpoint tiêu chuẩn khi Helius
  di chuyển lưu lượng truy cập sang Gatekeeper.
</Note>

## Đăng ký

Gửi một yêu cầu JSON-RPC bằng phương thức `preconfSubscribe`. Máy chủ phản hồi bằng ID đăng ký, sau đó truyền phát một thông báo cho mỗi giao dịch. Truyền một [bộ lọc](#lọc) tùy chọn làm phần tử `params` đầu tiên để chỉ nhận các giao dịch khớp; bỏ qua `params` để nhận toàn bộ luồng từ cả Helius và BAM.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe"
}
```

### Phản hồi đăng ký

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": 24040,
  "id": 1
}
```

Lưu `result` — đây là ID đăng ký bạn dùng để [hủy đăng ký](#hủy-đăng-ký). Sau thông báo xác nhận này, các thông báo sẽ được truyền phát dưới dạng frame nhị phân (xem bên dưới).

## Lọc

Theo mặc định, `preconfSubscribe` truyền phát mọi giao dịch từ cả hai nguồn. Để thu hẹp luồng, hãy truyền một đối tượng bộ lọc làm phần tử đầu tiên của `params`. Quá trình lọc diễn ra ở phía máy chủ, vì vậy bạn chỉ trả phí và nhận các giao dịch mình quan tâm.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [
    {
      "includeBam": true,
      "failed": false,
      "regionInclude": ["ewr", "fra"],
      "accountInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"],
      "accountExclude": ["TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"],
      "accountRequired": ["11111111111111111111111111111111"]
    }
  ]
}
```

Mọi trường đều là tùy chọn — trường bị thiếu có nghĩa là "không có ràng buộc" đối với vị từ đó, vì vậy bộ lọc trống (hoặc không có `params`) sẽ khớp với mọi giao dịch từ cả hai nguồn.

| Trường            | Kiểu       | Ngữ nghĩa                                                                                                                                                                                                                        |
| ----------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `includeBam`      | `boolean`  | Mặc định là `true`. `false` loại bỏ các preconfirmation của BAM để bạn chỉ nhận preconfirmation của Helius.                                                                                                                      |
| `failed`          | `boolean`  | `true` chỉ trả về các giao dịch thất bại (bị hoàn nguyên); `false` chỉ trả về các giao dịch thành công. Cả hai giá trị đều loại trừ các giao dịch Helius có trạng thái không xác định. Bỏ qua trường này để nhận mọi trạng thái. |
| `regionInclude`   | `string[]` | Nếu không trống, giao dịch phải bắt nguồn từ **một trong các** [khu vực](#lọc-theo-vị-trí) này.                                                                                                                                  |
| `accountInclude`  | `string[]` | Nếu không trống, giao dịch phải tham chiếu đến **ít nhất một** trong các tài khoản này.                                                                                                                                          |
| `accountExclude`  | `string[]` | Giao dịch bị loại bỏ nếu tham chiếu đến **bất kỳ** tài khoản nào trong số này. Được ưu tiên hơn `accountInclude`.                                                                                                                |
| `accountRequired` | `string[]` | Giao dịch phải tham chiếu đến **tất cả** các tài khoản này.                                                                                                                                                                      |

Quy tắc lọc:

* Tất cả vị từ được kết hợp bằng phép AND và được đánh giá theo thứ tự `includeBam` → `failed` → `regionInclude` → `accountExclude` → `accountRequired` → `accountInclude`.
* Preconfirmation có trạng thái không xác định sẽ bỏ qua bộ lọc trạng thái `failed` và vẫn được phân phối nếu khớp với các bộ lọc nguồn, khu vực và tài khoản.
* Tài khoản là các khóa công khai được mã hóa base58. Giá trị không hợp lệ trả về lỗi JSON-RPC `-32602` (tham số không hợp lệ).
* Mỗi danh sách tài khoản bị giới hạn ở **500** mục.

Để chỉ nhận preconfirmation của Helius:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "includeBam": false }]
}
```

### Phân giải bảng tra cứu địa chỉ (ALT)

Bộ lọc tài khoản khớp với nhiều dữ liệu hơn các khóa tài khoản tĩnh của giao dịch — Helius phân giải [bảng tra cứu địa chỉ](/docs/vi/glossary#bảng-tra-cứu-địa-chỉ-alt) v0 ở phía máy chủ, vì vậy `accountInclude`, `accountExclude` và `accountRequired` cũng khớp với các tài khoản mà giao dịch tải thông qua ALT.

Điều này có nghĩa là bạn có thể lọc theo bất kỳ tài khoản nào mà giao dịch tương tác, ngay cả khi tài khoản đó chỉ xuất hiện phía sau bảng tra cứu — bạn không cần tự duy trì ánh xạ ALT hoặc phân giải bảng. Chỉ cần truyền khóa công khai của tài khoản và Helius sẽ xử lý việc phân giải trước khi áp dụng bộ lọc.

### Lọc theo vị trí

Sử dụng `regionInclude` để chỉ nhận các giao dịch bắt nguồn từ những khu vực cụ thể. Truyền một hoặc nhiều mã khu vực; giao dịch được chấp nhận khi khu vực nguồn khớp với bất kỳ mã nào trong số đó.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preconfSubscribe",
  "params": [{ "regionInclude": ["ewr", "fra"] }]
}
```

Khu vực nguồn phụ thuộc vào nguồn dữ liệu. Đối với preconfirmation của Helius, đó là khu vực Helius đã tiếp nhận giao dịch. Đối với preconfirmation của BAM, đó là endpoint BAM theo khu vực đã phát preconfirmation, không phải nơi Helius tiếp nhận giao dịch. Các endpoint Singapore và Dallas của BAM ánh xạ tới `sgp` và `dal`.

Các mã khu vực hợp lệ:

| Mã    | Vị trí          |
| ----- | --------------- |
| `slc` | Salt Lake City  |
| `fra` | Frankfurt       |
| `lon` | London          |
| `pit` | Pittsburgh      |
| `sgp` | Singapore       |
| `ewr` | Newark          |
| `tyo` | Tokyo           |
| `ams` | Amsterdam       |
| `dal` | Dallas          |
| `dub` | Dublin          |
| `mia` | Miami           |
| `lax` | Los Angeles     |
| `iad` | Ashburn         |
| `sea` | Seattle         |
| `hkg` | Hồng Kông       |
| `sqq` | Šiauliai, Litva |

<Note>
  Khi `regionInclude` được đặt, các giao dịch không chứa thông tin khu vực sẽ bị loại bỏ. Mã khu vực không được nhận dạng sẽ trả về lỗi JSON-RPC `-32602` (tham số không hợp lệ).
</Note>

## Payload thông báo

Thông báo được phân phối dưới dạng frame WebSocket **nhị phân** (không phải JSON). Preconfirmation của Helius và BAM có cùng bố cục. Mỗi frame là một bố cục byte được đóng gói, chứa một giao dịch duy nhất:

| Byte | Trường        | Kiểu                  | Mô tả                                                                                                                                                                                                         |
| ---- | ------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 0    | `version`     | `u8`                  | Phiên bản lược đồ payload. Hiện là `1`.                                                                                                                                                                       |
| 1–8  | `slot`        | `u64` (little-endian) | Slot chứa giao dịch.                                                                                                                                                                                          |
| 9–16 | `tx_index`    | `u64` (little-endian) | Chỉ mục của giao dịch trong slot. Luôn là `0` đối với preconfirmation của BAM — BAM sắp xếp giao dịch theo ID trình tự và vị trí bundle thay vì chỉ mục slot, và cả hai đều không được truyền trên luồng này. |
| 17   | `status`      | `u8`                  | Trạng thái giao dịch: `0` = thất bại, `1` = thành công, `2` = không xác định.                                                                                                                                 |
| 18+  | `transaction` | `bytes`               | Giao dịch ở định dạng wire của Solana. Xem [Giải mã giao dịch](#giải-mã-giao-dịch).                                                                                                                           |

Payload không có trường nguồn. Không suy luận nguồn BAM từ `tx_index = 0` vì preconfirmation của Helius có thể chứa các giá trị tương tự.

### Phân biệt hai nguồn

Vì không có trường nguồn, bạn không thể gắn nhãn tùy ý cho một thông báo là Helius hay BAM. Byte `status` cung cấp một bộ phân loại một chiều:

* **`status` là `0` hoặc `1`** — thông báo là preconfirmation của Helius và giao dịch đã được thực thi. BAM không bao giờ báo cáo các giá trị này.
* **`status` là `2`** — nguồn không rõ ràng: có thể là preconfirmation của BAM hoặc preconfirmation của Helius không có trạng thái thực thi.

Không có trường nào khác có thể phân biệt nguồn. ID trình tự và vị trí bundle của BAM không được truyền trên luồng này, vì vậy không có siêu dữ liệu thứ tự BAM để làm khóa; còn `regionInclude` là bộ lọc đăng ký chứ không phải trường payload, nên không thể đọc riêng cho từng thông báo.

Nếu cần mọi thông báo trên một luồng chứa cùng một loại bằng chứng, hãy đặt `includeBam: false` — khi đó chỉ còn preconfirmation của Helius, tất cả đều được phát khi leader thực thi. Không có bộ lọc chỉ dành cho BAM.

<Warning>
  **Luôn đọc và kiểm tra byte `version` trước tiên.** Hiện byte này là `1`. Nếu
  Helius cần cập nhật định dạng payload, phiên bản sẽ tăng — hãy phân nhánh
  theo phiên bản để bộ giải mã của bạn tiếp tục hoạt động khi lược đồ thay đổi.
</Warning>

<Note>
  Preconfirmation là tín hiệu sớm, không phải sự bảo đảm. Giao dịch chưa
  được ghi nhận onchain và vẫn có thể bị loại bỏ — trạng thái thực thi của preconfirmation
  Helius phản ánh kết quả cục bộ của leader, kết quả này chưa phải cuối cùng cho đến khi
  block được xác nhận. Hãy xác nhận việc ghi nhận bằng các bước kiểm tra commitment tiêu chuẩn
  trước khi coi giao dịch là cuối cùng.
</Note>

### Giải mã giao dịch

Các byte giao dịch được chuyển tiếp chính xác như cách validator tuần tự hóa chúng, theo mã hóa wire tiêu chuẩn dành cho phiên bản giao dịch. Giao dịch legacy và v0 sử dụng bố cục chữ ký trước do `bincode` tạo ra. Giao dịch v1 ([SIMD-0385](https://github.com/solana-foundation/solana-improvement-documents/blob/main/proposals/0385-transaction-v1.md)) sử dụng bố cục thông điệp trước với chữ ký ở cuối, vì vậy `bincode` không xử lý được payload v1. Hãy sử dụng bộ giải mã hỗ trợ mọi phiên bản:

* **Rust:** [`agave-transaction-view`](https://docs.rs/agave-transaction-view) phân tích trực tiếp các giao dịch legacy, v0 và v1 mà không cần bản sao trung gian. Đây là lựa chọn được khuyến nghị. [`wincode`](https://docs.rs/wincode), trình tuần tự hóa tương thích với bincode được các Solana SDK hiện tại sử dụng, cũng giải mã v1 thành `VersionedTransaction`.
* **JavaScript / TypeScript:** hãy bảo đảm phiên bản thư viện của bạn hỗ trợ giao dịch v1. Các bản triển khai `VersionedTransaction.deserialize` cũ chỉ xử lý legacy và v0. Sử dụng `@solana/kit` 8.0+ hoặc `@solana/web3.js` v3. Xem [Hỗ trợ giao dịch v1](/docs/vi/rpc/transaction-v1).

```rust theme={"system"}
use agave_transaction_view::transaction_view::TransactionView;

// `frame` is the full binary WebSocket message
let tx_bytes = &frame[18..];
let tx = TransactionView::try_new_unsanitized(tx_bytes)?;

println!("version: {:?}", tx.version()); // Legacy, V0, or V1
println!("signature: {}", tx.signatures()[0]);
for ix in tx.instructions_iter() {
    println!("program index {}: {} bytes", ix.program_id_index, ix.data.len());
}
```

## Thông báo trùng lặp

Preconfirmation của Helius và BAM được loại bỏ trùng lặp theo từng nguồn, không phải giữa các nguồn. Một tỷ lệ nhỏ giao dịch đến Helius qua cả hai nguồn, vì vậy bạn có thể nhận cùng một chữ ký hai lần và hai bản sao có thể báo cáo các slot khác nhau.

Loại bỏ trùng lặp theo chữ ký ở phía ứng dụng khách và thiết kế các hành động do giao dịch kích hoạt theo hướng idempotent để thông báo thứ hai không kích hoạt cùng một hành động hai lần. Xác nhận việc thực thi và ghi nhận bằng các bước kiểm tra commitment tiêu chuẩn.

## Ví dụ

```javascript theme={"system"}
const WebSocket = require('ws');

const ws = new WebSocket('wss://beta.helius-rpc.com/?api-key=<API_KEY>');

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'preconfSubscribe' // Helius and BAM preconfirmations by default
    // Optional: txs from EWR/FRA touching a given account; Helius txs must be successful.
    // BAM ignores the status filter; region and account filters still apply.
    // params: [{ failed: false, regionInclude: ['ewr', 'fra'], accountInclude: ['9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'] }]
    // Optional: Helius preconfirmations only
    // params: [{ includeBam: false }]
  }));

  // Keep the connection alive
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data, isBinary) => {
  // The subscribe acknowledgement arrives as a JSON text frame
  if (!isBinary) {
    const msg = JSON.parse(data.toString());
    if (msg.id === 1) console.log('Subscribed, ID:', msg.result);
    return;
  }

  // Notifications arrive as binary frames:
  // version (u8) | slot (u64 LE) | tx_index (u64 LE) | status (u8) | transaction bytes
  const buf = Buffer.from(data);
  const version = buf.readUInt8(0); // currently 1 — branch on this if it changes
  if (version !== 1) return; // unknown schema version; update your decoder
  const slot = buf.readBigUInt64LE(1);
  const txIndex = buf.readBigUInt64LE(9); // always 0 for BAM preconfirmations
  const status = buf.readUInt8(17); // 0 = failed, 1 = success, 2 = unknown
  const txBytes = buf.subarray(18); // transaction in Solana wire format (legacy, v0, or v1)

  console.log('Preconfirmation:', { version, slot, txIndex, status, bytes: txBytes.length });
  // Decode txBytes with a decoder that supports transaction v1 (see "Decoding the transaction")
});

ws.on('error', console.error);
ws.on('close', () => process.exit(1));
```

## Hủy đăng ký

Để ngừng nhận thông báo, hãy gọi `preconfUnsubscribe` bằng ID đăng ký do `preconfSubscribe` trả về.

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "preconfUnsubscribe",
  "params": [24040]
}
```

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "result": true,
  "id": 2
}
```

## Mức giá

Preconfirmations yêu cầu **gói Professional trở lên** và có giá **10 credit cho mỗi thông báo** — một thông báo cho mỗi giao dịch được truyền phát — được tính vào gói của bạn. Xem [Credit](/docs/vi/billing/credits) để biết chi tiết.

Phí được tính theo từng thông báo, không phải theo từng chữ ký duy nhất. Một giao dịch được cả Helius và BAM phân phối sẽ được tính hai lần. Đặt `includeBam: false` nếu bạn chỉ muốn nhận preconfirmation của Helius.

<Note>
  Preconfirmations là sản phẩm mới và mức giá có thể thay đổi.
</Note>

## Nội dung liên quan

<CardGroup cols={2}>
  <Card title="Preconfirmations Overview" icon="bolt" href="/docs/vi/pre-confirmations/overview">
    Preconfirmations là gì và nằm ở đâu trong pipeline của validator.
  </Card>

  <Card title="transactionSubscribe" icon="tower-broadcast" href="/docs/vi/rpc/websocket/transaction-subscribe">
    Truyền phát các giao dịch ở mức commitment confirmed với khả năng lọc nâng cao.
  </Card>

  <Card title="preconfSubscribe API reference" icon="code" href="/docs/vi/api-reference/pre-confirmations/preconfsubscribe">
    Tham số yêu cầu, trường bộ lọc và bố cục thông báo nhị phân.
  </Card>
</CardGroup>
