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

# 在预处理交易上进行交易

> 通过 preprocessedSubscribe 观察程序的 Solana 交易，在它们达到处理承诺级别之前。

`preprocessedSubscribe` 在交易到达 `processed` 承诺级别之前流式传输签名交易，从切碎的交易中解码，无需在您这一侧进行取消切碎的基础设施。

本指南构建了一个监视器，观察交易程序的前执行，消除重复的数据流，保持在服务器的背压限制以下，并在操作前与处理过的数据进行对账。

<Tip>
  [预处理交易](/docs/zh/preprocessed-transactions/overview) 在所有付费计划中可用，每条消息消耗 0.1 个积分，每个 API 密钥最多允许 10 个并发连接。
</Tip>

## 将订阅范围缩小到您的目标

没有未过滤的数据流：`accountInclude` 和 `accountRequired` 必须在它们之间至少命名一个账户。对于交易监视器，请包含您针对的程序并排除其他噪声，否则您将为其付费：

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

过滤器与 AND 结合使用，每个列表最多接受 5,000 个地址，并且 Helius 在服务器端解析地址查找表，因此通过 ALT 加载的帐户仍然匹配。要监视特定钱包与程序的交互，请将它们都放在 `accountRequired` 字段中。

## 解码帧并通过签名去重

通知以二进制帧的形式到达：一个73字节的前缀，然后是经过bincode序列化的交易。签名在前缀中，因此您可以在不解码主体的情况下进行去重。数据流聚合了几个前执行源，同一交易可能不止一次到达：

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

## 接收循环保持比数据流快

Helius 不会无限期缓冲慢速消费者：如果服务器端积压超过 4,000 条消息，连接将关闭。这就是为什么上面的处理器只读取 73 字节前缀并排队的原因。

反序列化和策略逻辑在一个单独的循环中运行：

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

如果队列无限增长，请收紧过滤器。您在客户端丢弃的交易每笔仍然消耗 0.1 个积分，并且仍然计入背压限制。

## 与处理过的数据进行对账

预处理的交易显示发送者尝试做的事情，而不是实际发生的事。它不包含执行状态、余额变化或日志，并且可能失败、被丢弃或进入不同的分叉。传递是尽力而为，没有历史重播，因此：

* 在您的策略将任何内容记录为事实之前，与 [`transactionSubscribe`](/docs/zh/rpc/websocket/transaction-subscribe) 在 `processed` 或 `confirmed` 承诺上进行对账。
* 在断开连接时，立即重新订阅并接受间隙，因为没有重播来填补它。
* 如果您需要实时账户状态而不是交易意图，那只有在执行后才存在：使用 [LaserStream gRPC](/docs/zh/laserstream) 在 `processed`。

## 相关指南

<CardGroup cols={2}>
  <Card title="preprocessedSubscribe 参考" icon="code" href="/docs/zh/preprocessed-transactions/preprocessed-subscribe">
    完整的负载布局、过滤规则、背压和定价
  </Card>

  <Card title="在预确认上进行交易" icon="stopwatch" href="/docs/zh/pre-confirmations/guides/trade-on-preconfirmations">
    Helius 提供的最早的交易信号，来自调度程序本身
  </Card>
</CardGroup>
