> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbitflare.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Apex 上的交易 v1

> OrbitFlare Apex 在 sendTransaction、HTTP 发送路由和 QUIC 上接受最大 4096 字节的 Solana 交易 v1 (SIMD-0385)。了解如何对其进行序列化。

## 各格式的大小限制

交易 v1 是 SIMD-0385 引入的消息格式。对发送方而言，主要变化在于大小：v1 交易最大可达 **4096 字节**，而 legacy 和 v0 交易仍为 1232 字节。

| 格式     | 最大大小        | 接受的路由                                                      |
| ------ | ----------- | ---------------------------------------------------------- |
| Legacy | 1232 字节     | 所有路由                                                       |
| v0     | 1232 字节     | 所有路由                                                       |
| **v1** | **4096 字节** | `sendTransaction`、`/send`、`/send-bin`、`/send-batch` 和 QUIC |

Apex 根据交易字节检测格式。无需设置任何标志，也没有单独的路由。

<Note>
  [捆绑包](/cn/apex/bundles)成员无论采用何种格式，每笔都限制为 1232 字节。
</Note>

超过 1232 字节的 legacy 或 v0 交易，或任何超过 4096 字节的交易，都会因过大而被拒绝。参见[错误与速率限制](/cn/apex/errors-and-rate-limits)。

## 使用规范编码器序列化 v1

v1 交易必须使用该格式的规范编码器进行序列化。在 Rust 中即 `wincode`。较旧的 bincode 和 serde 方式对 legacy 和 v0 能生成正确的字节，但**对 v1 会生成错误的字节**，交易会因格式错误而被拒绝。

Rust 客户端通过 `apex_sender_client::serialize_transaction` 提供了正确的编码器。对于 legacy 和 v0，它与 bincode 逐字节相同，对 v1 也是正确的。`ApexSenderClient::send_transaction` 在内部使用它，因此只有在您需要字节本身时才需自行调用，例如用于 HTTP 路由。

在其他语言中，请使用实现了 SIMD-0385 序列化的 Solana 库版本。发送前请检查序列化后消息的第一个字节是否为 v1 版本前缀。

## 小费规则保持不变

v1 交易需要相同的[小费](/cn/apex/tips)：一条顶层的 SystemProgram 转账，转给已公布的小费账户，由签名者出资，且不低于您所在等级的下限。

一个区别在于计算预算。在 v1 消息中，计算预算位于消息自身的 `TransactionConfig` 中，而不是 ComputeBudget 程序指令中。`TransactionConfig` 中未设置的每一项限制都为 0，包括已加载账户数据大小。在我们 2026-09-19 的主网测试中，一笔依赖 ComputeBudget 指令的 v1 交易成功落地，随后在链上以 `MaxLoadedAccountsDataSizeExceeded` 失败。

因此请三项都设置：计算单元上限、已加载账户数据大小上限，以及用于优先级的费用。优先费是以 lamports 计的总额，而不是每计算单元的价格。使用这样的配置，276、741 和 1641 字节的 v1 交易通过 Apex 经 QUIC 在主网成功落地。其中 1641 字节的那一笔超过了 legacy 的 1232 字节上限。

## Rust 示例

该程序构建一笔带有 3,000 字节 memo 式负载的 v1 交易（legacy 交易无法容纳），并通过 QUIC 发送。除[快速入门的依赖](/cn/apex/quickstart#rust-依赖)外，它还需要 `solana-message = "=4.4.1"`。

```rust theme={null}
use std::str::FromStr;
use std::time::Duration;

use apex_sender_client::rpc::{RpcClient, SolanaRpc};
use apex_sender_client::{
    serialize_transaction, tip, tip_instruction, ApexSenderClient, Region, MIN_TIP_LAMPORTS,
};
use solana_instruction::{AccountMeta, Instruction};
use solana_keypair::read_keypair_file;
use solana_message::v1::{self, TransactionConfig};
use solana_message::VersionedMessage;
use solana_pubkey::Pubkey;
use solana_signer::Signer;
use solana_transaction::versioned::VersionedTransaction;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let api_key = std::env::var("APEX_API_KEY")?;
    let solana = SolanaRpc::new(
        std::env::var("SOLANA_RPC_URL").unwrap_or_else(|_| "https://api.mainnet-beta.solana.com".into()),
    );
    let payer = read_keypair_file(std::env::var("KEYPAIR_PATH").unwrap_or_else(|_| "payer.json".into()))?;
    let region = Region::Frankfurt;

    let client = ApexSenderClient::connect(region, &api_key).await?;
    let tip_accounts = RpcClient::new(region, &api_key).get_tip_accounts().await?;
    let tip_account = tip::pick_tip_account(&tip_accounts).ok_or("no tip accounts")?;

    // A payload far larger than a legacy transaction could carry.
    let memo = Instruction::new_with_bytes(
        Pubkey::from_str("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr")?,
        "v".repeat(3_000).as_bytes(),
        vec![AccountMeta::new(payer.pubkey(), true)],
    );
    let instructions = [
        memo,
        tip_instruction(&payer.pubkey(), &tip_account, MIN_TIP_LAMPORTS),
    ];

    // v1 sets the compute budget in the message config. Every limit left unset is 0.
    let config = TransactionConfig::empty()
        .with_compute_unit_limit(400_000)
        .with_loaded_accounts_data_size_limit(1024 * 1024)
        .with_priority_fee(4_000); // total lamports, not a price per compute unit
    let message = v1::Message::try_compile_with_config(
        &payer.pubkey(),
        &instructions,
        solana.latest_blockhash().await?,
        config,
    )?;
    let tx = VersionedTransaction::try_new(VersionedMessage::V1(message), &[&payer])?;

    let wire = serialize_transaction(&tx)?;
    println!("v1 transaction: {} bytes, prefix {:#04x}", wire.len(), wire[0]);
    assert_eq!(wire[0], v1::V1_PREFIX);

    let signature = client.send_transaction(&tx).await?;
    println!("sent: {signature}");
    println!("slot: {:?}", solana.confirm(&signature.to_string(), Duration::from_secs(30)).await?);
    Ok(())
}
```

发送超过 4096 字节的内容会在本地以 `Error::TooLarge` 失败，不会有任何数据到达网络。

## 通过 HTTP 发送 v1

一旦您持有正确序列化的 v1 字节，HTTP 路由接收它们的方式与接收任何交易完全相同：`sendTransaction` 和 `/send` 使用 base64，`/send-bin` 和 `/send-batch` 使用原始字节。

```rust theme={null}
// `tx` is the v1 transaction from the example above.
use apex_sender_client::rpc::RpcClient;
use apex_sender_client::{serialize_transaction, Region};

let rpc = RpcClient::new(Region::Frankfurt, &api_key);
let wire = serialize_transaction(&tx)?;
let signature = rpc.send_transaction_binary(&wire, false, None).await?;
println!("accepted: {signature}");
```
