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

# preconfSubscribe

> Dùng preconfSubscribe để truyền phát các giao dịch Solana trước khi chúng được chuyển thành shred — các xác nhận trước của Helius chứa trạng thái thực thi, còn các xác nhận trước của BAM đến trước khi thực thi.

Bắt đầu đăng ký [Preconfirmations](/docs/vi/pre-confirmations/overview) — các giao dịch được phân phối trước khi được tập hợp thành entry và chuyển đổi 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ý truyền phát cả các xác nhận trước 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 [các xác nhận trước của BAM](/docs/vi/pre-confirmations/overview#bam-preconfirmations), được phát khi validator cam kết thực thi giao dịch; đặt `includeBam: false` để chỉ nhận các xác nhận trước của Helius.

## Điểm cuối

`preconfSubscribe` được cung cấp từ điểm cuối [Gatekeeper](/docs/vi/gatekeeper/overview) của Helius:

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

Tên máy chủ `beta` đề cập đến quá trình triển khai Gatekeeper, không phải mức độ hoàn thiện của Preconfirmations — đây sẽ trở thành điểm cuối tiêu chuẩn khi lưu lượng được chuyển sang Gatekeeper.

<Note>
  Luồng không liên tục. Phạm vi bao phủ tăng theo tỷ lệ stake mạng
  chuyển tiếp đến Helius hoặc chạy BAM, vì vậy có thể 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>

## Xác thực

<ParamField query="api-key" type="string" required>
  Khóa API Helius của bạn, được truyền dưới dạng tham số truy vấn `api-key`. Yêu cầu gói Professional trở lên.
</ParamField>

## Nội dung yêu cầu

<ParamField body="params" type="array">
  Không bắt buộc. Bỏ qua `params` để nhận mọi giao dịch từ cả Helius và BAM. Để 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 — quá trình lọc diễn ra ở phía máy chủ, nên bạn chỉ trả phí và nhận các giao dịch mình quan tâm.

  <Expandable title="Filter" defaultOpen>
    Mọi trường đều không bắt buộc — trường bị thiếu có nghĩa là "không có ràng buộc" đối với điều kiện đó, vì vậy bộ lọc trống khớp với mọi giao dịch từ cả hai nguồn. Các trường đã đặt được kết hợp bằng **AND** và đánh giá theo thứ tự `includeBam` → `failed` → `regionInclude` → `accountExclude` → `accountRequired` → `accountInclude`.

    <ParamField body="includeBam" type="boolean" default="true">
      `false` loại bỏ các xác nhận trước của BAM để bạn chỉ nhận các xác nhận trước của Helius. `true`, tương tự như khi bỏ qua trường này, giữ lại cả hai nguồn.
    </ParamField>

    <ParamField body="failed" type="boolean">
      `true` chỉ trả về các giao dịch thất bại (bị hoàn tác); `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. Các xác nhận trước có trạng thái không xác định vẫn được phân phối nếu khớp với bộ lọc nguồn, khu vực và tài khoản.
    </ParamField>

    <ParamField body="regionInclude" type="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](#mã-khu-vực) này. Các giao dịch không có thông tin khu vực sẽ bị loại bỏ khi trường này được đặt.
    </ParamField>

    <ParamField body="accountInclude" type="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 (khóa công khai base58). Tối đa 500 mục.
    </ParamField>

    <ParamField body="accountExclude" type="string[]">
      Giao dịch sẽ 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`. Tối đa 500 mục.
    </ParamField>

    <ParamField body="accountRequired" type="string[]">
      Giao dịch phải tham chiếu đến **tất cả** các tài khoản này. Tối đa 500 mục.
    </ParamField>
  </Expandable>
</ParamField>

Giá trị tài khoản không hợp lệ hoặc 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ệ).

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 qua ALT.

### Mã khu vực

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

Đối với các xác nhận trước của Helius, khu vực là nơi Helius tiếp nhận giao dịch. Đối với các xác nhận trước của BAM, đó là điểm cuối BAM theo khu vực đã phát xác nhận trước, không phải nơi Helius tiếp nhận giao dịch. Các điểm cuối Singapore và Dallas của BAM ánh xạ lần lượt tới `sgp` và `dal`.

## Phản hồi

<ResponseField name="result" type="integer">
  ID đăng ký (cần thiết để hủy đăng ký)
</ResponseField>

<RequestExample>
  ```json Request theme={"system"}
  {
    "jsonrpc": "2.0",
    "id": 1,
    "method": "preconfSubscribe",
    "params": [
      {
        "failed": false,
        "regionInclude": ["ewr", "fra"],
        "accountInclude": ["9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM"]
      }
    ]
  }
  ```

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

  ```javascript 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 filter:
      // params: [{ failed: false, accountInclude: ['9WzDXwBbmkg8ZTbNMqUxvQRAyrZzDsGYdLVL9zYtAWWM'] }]
      // Helius preconfirmations only:
      // params: [{ includeBam: false }]
    }));

    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);
    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:', { slot, txIndex, status, bytes: txBytes.length });
  });
  ```
</RequestExample>

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

  ```text Notification (binary frame) theme={"system"}
  version   u8              payload schema version, currently 1
  slot      u64 (LE)        slot the transaction is scheduled in
  tx_index  u64 (LE)        index of the transaction within the slot (always 0 for BAM)
  status    u8              0 = failed, 1 = success, 2 = unknown
  tx        bytes           transaction in Solana wire format (legacy, v0, or v1)
  ```
</ResponseExample>

## Thông báo

Sau thông báo xác nhận JSON, các thông báo được phân phối dưới dạng khung WebSocket **nhị phân** (không phải JSON). Các xác nhận trước của Helius và BAM dùng chung một bố cục. Mỗi khung 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 mà giao dịch được lên lị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 các xác nhận trước của BAM, vốn chứa ID trình tự và vị trí trong bundle thay cho chỉ mục slot. |
| 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 gốc BAM từ `tx_index = 0`, vì các xác nhận trước của Helius có thể chứa cùng các giá trị đó.

<Warning>
  **Luôn đọc và kiểm tra byte `version` trước tiên.** Giá trị hiện tại 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ã tiếp tục hoạt động khi lược đồ thay đổi.
</Warning>

Xác nhận trước là một tín hiệu sớm, không phải sự đảm bảo. Giao dịch chưa được ghi nhận onchain và vẫn có thể thất bại hoặc bị loại bỏ. Hãy xác nhận giao dịch đã được ghi nhận thông qua các bước kiểm tra mức cam kết tiêu chuẩn trước khi coi giao dịch là hoàn tất.

### 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. Các 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, nên `bincode` không xử lý được payload v1.

Hãy dùng bộ giải mã xử lý được mọi phiên bản. Trong Rust, [`agave-transaction-view`](https://docs.rs/agave-transaction-view) phân tích tại chỗ các giao dịch legacy, v0 và v1 và là lựa chọn được đề xuất; [`wincode`](https://docs.rs/wincode) với `VersionedTransaction` của Solana SDK hiện hành cũng hoạt động. Trong JavaScript, hãy đảm bảo phiên bản thư viện hỗ trợ giao dịch v1. Xem [hướng dẫn](/docs/vi/pre-confirmations/preconf-subscribe#giải-mã-giao-dịch) để tham khảo ví dụ Rust.

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

Các xác nhận trước của Helius và BAM được loại bỏ trùng lặp riêng 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. Hãy loại bỏ trùng lặp theo chữ ký ở phía máy khách và đảm bảo các hành động được kích hoạt bởi giao dịch có tính lũy đẳng. Xem [hướng dẫn](/docs/vi/pre-confirmations/preconf-subscribe#thông-báo-trùng-lặp).

## Giá

Preconfirmations yêu cầu **gói Professional trở lên** và có giá **10 tín dụng cho mỗi thông báo** — một thông báo cho mỗi giao dịch được truyền phát. Xem [Tín dụng](/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 phân phối bởi cả Helius và BAM sẽ được tính hai lần. Đặt `includeBam: false` nếu bạn chỉ muốn nhận các xác nhận trước của Helius.

## 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 quy trình xử lý của validator.
  </Card>

  <Card title="preconfUnsubscribe" icon="circle-stop" href="/docs/vi/api-reference/pre-confirmations/preconfunsubscribe">
    Dừng một lượt đăng ký bằng ID của lượt đăng ký đó.
  </Card>
</CardGroup>
