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

# Giao dịch dựa trên các giao dịch được tiền xử lý

> Theo dõi các giao dịch Solana của một chương trình trước khi chúng đạt mức cam kết processed bằng preprocessedSubscribe.

`preprocessedSubscribe` truyền trực tiếp các giao dịch đã ký trước khi chúng đạt mức cam kết `processed`. Các giao dịch này được giải mã từ các shred khi chúng đến trình xác thực mà không yêu cầu bạn phải có hạ tầng ghép shred.

Hướng dẫn này xây dựng một trình giám sát để theo dõi chương trình giao dịch trước khi thực thi, loại bỏ dữ liệu trùng lặp trong luồng, duy trì dưới giới hạn backpressure của máy chủ và đối soát với dữ liệu đã xử lý trước khi hành động.

<Tip>
  [Các giao dịch được tiền xử lý](/docs/vi/preprocessed-transactions/overview) có trên tất cả các gói trả phí và có giá 0,1 credit cho mỗi thông báo, với tối đa 10 kết nối đồng thời cho mỗi khóa API.
</Tip>

## Giới hạn phạm vi đăng ký vào mục tiêu

Không có luồng không lọc: `accountInclude` và `accountRequired` phải chỉ định tổng cộng ít nhất một tài khoản. Đối với trình giám sát giao dịch, hãy bao gồm chương trình mà bạn giao dịch với và loại trừ dữ liệu nhiễu mà nếu không bạn vẫn phải trả phí:

```json theme={"system"}
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "preprocessedSubscribe",
  "params": {
    "accountInclude": ["JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4"],
    "accountExclude": ["Vote111111111111111111111111111111111111111"],
    "accountRequired": []
  }
}
```

Các bộ lọc được kết hợp bằng AND, mỗi danh sách chấp nhận tối đa 5.000 địa chỉ và Helius phân giải các bảng tra cứu địa chỉ ở phía máy chủ, vì vậy tài khoản được tải qua ALT vẫn khớp. Để theo dõi tương tác của một ví cụ thể với chương trình, hãy đặt cả hai vào trường `accountRequired`.

## Giải mã các frame và loại bỏ trùng lặp theo chữ ký

Thông báo đến dưới dạng frame nhị phân: tiền tố 73 byte, sau đó là giao dịch được tuần tự hóa bằng bincode. Chữ ký nằm trong tiền tố, vì vậy bạn có thể loại bỏ trùng lặp mà không cần giải mã phần nội dung. Luồng tổng hợp nhiều nguồn trước khi thực thi và cùng một giao dịch có thể xuất hiện nhiều lần:

```javascript monitor.js theme={"system"}
const WebSocket = require('ws');
const bs58module = require('bs58');
const bs58 = bs58module.default ?? bs58module;

const ws = new WebSocket('wss://beta.helius-rpc.com/?api-key=YOUR_API_KEY');
const seen = new Set(); // rotate or expire entries in production
const queue = [];       // decode off the receive path; see next step

ws.on('open', () => {
  ws.send(JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'preprocessedSubscribe',
    params: {
      accountInclude: ['JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4'],
      accountExclude: ['Vote111111111111111111111111111111111111111'],
      accountRequired: []
    }
  }));
  setInterval(() => ws.ping(), 30_000);
});

ws.on('message', (data, isBinary) => {
  if (!isBinary) {
    const msg = JSON.parse(data.toString());
    if (msg.id === 1) console.log('Subscribed, ID:', msg.result);
    return;
  }

  // version (u8) | slot (u64 LE) | signature ([u8; 64]) | bincode(VersionedTransaction)
  const buf = Buffer.from(data);
  if (buf.readUInt8(0) !== 1) return; // unknown schema version; update your decoder
  const signature = bs58.encode(buf.subarray(9, 73));
  if (seen.has(signature)) return;
  seen.add(signature);

  queue.push({
    slot: buf.readBigUInt64LE(1),
    signature,
    txBytes: buf.subarray(73)
  });
});

ws.on('error', console.error);
ws.on('close', () => process.exit(1)); // supervisor restarts and resubscribes
```

## Duy trì vòng lặp nhận nhanh hơn luồng

Helius không lưu vào bộ đệm vô thời hạn cho các trình tiêu thụ chậm: nếu có hơn 4.000 thông báo tồn đọng ở phía máy chủ, kết nối sẽ bị đóng. Đó là lý do trình xử lý ở trên chỉ đọc tiền tố 73 byte rồi đưa vào hàng đợi.

Logic giải tuần tự hóa và chiến lược chạy trong một vòng lặp riêng:

```javascript theme={"system"}
setImmediate(async function drain() {
  const { VersionedTransaction } = require('@solana/web3.js');
  while (true) {
    const item = queue.shift();
    if (!item) { await new Promise(r => setTimeout(r, 1)); continue; }
    const tx = VersionedTransaction.deserialize(item.txBytes);
    strategy.onPreExecution(item.slot, item.signature, tx);
  }
});
```

Nếu hàng đợi tăng không giới hạn, hãy siết chặt các bộ lọc. Các giao dịch bạn loại bỏ ở phía máy khách vẫn tốn 0,1 credit cho mỗi giao dịch và vẫn được tính vào giới hạn backpressure.

## Đối soát với dữ liệu đã xử lý

Một giao dịch được tiền xử lý cho biết người gửi đã cố gắng thực hiện điều gì, chứ không phải điều gì thực sự đã xảy ra. Giao dịch này không chứa trạng thái thực thi, thay đổi số dư hoặc nhật ký và có thể thất bại, bị loại bỏ hoặc được đưa vào một fork khác. Việc phân phối được thực hiện theo khả năng tốt nhất, không có tính năng phát lại lịch sử, vì vậy:

* Đối soát với [`transactionSubscribe`](/docs/vi/rpc/websocket/transaction-subscribe) ở mức cam kết `processed` hoặc `confirmed` trước khi chiến lược của bạn ghi nhận bất kỳ điều gì là dữ kiện.
* Khi bị ngắt kết nối, hãy đăng ký lại ngay lập tức và chấp nhận khoảng trống dữ liệu vì không có tính năng phát lại để bổ sung dữ liệu còn thiếu.
* Nếu cần trạng thái tài khoản theo thời gian thực thay vì ý định giao dịch, dữ liệu đó chỉ tồn tại sau khi thực thi: hãy sử dụng [LaserStream gRPC](/docs/vi/laserstream) ở mức cam kết `processed`.

## Hướng dẫn liên quan

<CardGroup cols={2}>
  <Card title="preprocessedSubscribe reference" icon="code" href="/docs/vi/preprocessed-transactions/preprocessed-subscribe">
    Bố cục payload đầy đủ, quy tắc lọc, backpressure và giá
  </Card>

  <Card title="Trade on Preconfirmations" icon="stopwatch" href="/docs/vi/pre-confirmations/guides/trade-on-preconfirmations">
    Tín hiệu giao dịch sớm nhất mà Helius cung cấp, trực tiếp từ bộ lập lịch
  </Card>
</CardGroup>
