文章/教程 如何调优先费让交易快速上链——从 agave 源码剖析为什么 jito 适合套利?什么时候用优先费什么时候用 jito?

wuaoxiang · 2024年11月20日 · 最后由 youda 回复于 2024年11月20日 · 1316 次阅读

可否量化 SOL 网络拥堵的指标区调整优先费提高上链速度呢?判断 SOL 网络拥堵的指标,SOL 域名解析商 sns.id 网页上右上角显示 Congested network, 从区块浏览器上看 TPS 普遍都有 4000+ 但 true TPS 真正属于用户交易的其实就只有几百 TPS,其余的 TPS 都是网络共识层投票等。

网络拥堵时,交易员/开发者/套利者等发出去的交易常常等很久都不上链,也听 space 上开发者抱怨交易很难上链或者优先费用卷的很高,如何利用优先费用 (priority fee)或者jito 小费 (jito tips)机制提高交易成功率和上链速度呢?

优先费用机制

  1. 交易带 SetComputeUnitPrice 指令才启用 优先费机制
  2. 交易带 SetComputeUnitPrice 但没 SetComputeUnitLimit 指令 默认按 20 万 ComputeUnitLimit/每条指令
  3. 交易同时带 CU price/limit 两个指令 (不管指令顺序),不管交易成功或失败都收取 price*limit 的优先费用

ComputeUnit 往后简称为 CU, sol 官方文档 how-to-use-priority-fees 中有个规则 2 的示例交易 (solscan)

文档说 set the Compute Unit Limit to 300 CUs while also adding a priority fee of 20000 micro-lamports

应该是这篇文章里面的 tx 太旧了,是以前验证者节点代码,最新的 agave 源码中如果是内置指令没有加 CUlimit 也会自动设置成 150, 第三方指令就 20 万

实际上这个交易忘了设置 CU limit 变成默认的 20 万 CU limit 每条指令 (最新验证者节点这个交易 CU limit 应该自动是 300 可能过于古老了) 所以收取了每笔交易基本费用,注意 CU price 单位是 micro lamports 要乘以 1e-6 转换成 SOL_lamports per CU 的量纲

5000 + (20000*1e-6 * 200000) = 9000 lamports SOL = 0.000009SOL

交易费用=5000lamports 基础费 + 账户租金费/开户费 + 优先费用,优先费用总值的竞价排名决定了交易在验证者出块的优先级

源码在 agave(solana 2.0 之后改名成 agave 项目继续维护了,原 github 地址不更新) 的 cost-model crate 中可以看到常量 DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT 就是 20 万

fn get_transaction_cost(
    transaction: &impl TransactionWithMeta,
    feature_set: &FeatureSet,
) -> (u64, u64, u64) {
    let mut programs_execution_costs = 0u64;
    let mut compute_unit_limit_is_set = false;
    let mut has_user_space_instructions = false;
    for (program_id, instruction) in transaction.program_instructions_iter() {
        let ix_execution_cost =
            if let Some(builtin_cost) = BUILTIN_INSTRUCTION_COSTS.get(program_id) {
                *builtin_cost
            } else {
                has_user_space_instructions = true;
                u64::from(DEFAULT_INSTRUCTION_COMPUTE_UNIT_LIMIT)
            };
        programs_execution_costs = programs_execution_costs
            .saturating_add(ix_execution_cost)
            .min(u64::from(MAX_COMPUTE_UNIT_LIMIT));
        if compute_budget::check_id(program_id) {
            if let Ok(ComputeBudgetInstruction::SetComputeUnitLimit(_)) =
                try_from_slice_unchecked(instruction.data)

再看一个同时设置了 CU price 和 limit 的例子:https://solscan.io/tx/BcBCS61y3GpYCHVzUZ3KK7v1M7PgYqNM8oyqx3oLq7XcxaYDW5SH1GQqvL5pkR91jypxh9sPDpztMby32oxEnre

agave 源码中 solana_compute_budget_program DEFAULT_COMPUTE_UNITS 是 150, 设置 CU limit/price和转账都是150

上述交易 CU limit 设置了 3000,交易有 2 个设置 CU 的指令和 18 次 SOL 转账的指令,加起来刚好是 (2+18)*150=3000 CU

10000*1e-6 * 3000 = 300 lamports

CU limit 如何设置

即便交易只用了 300CU 但设置了 20 万的 CU limit(如上述例子 1 的 tx), 也是按照 CU limit 20 万收取优先费用

所以交易中尽可能设置更低的 CU Limit,而且根据helius 文档 CULimit 越低的交易上链的优先级更大

常见的交易指令中消耗的 CU

  • transfer/SetCU: 150
  • 智能合约部署:约 2500-3000
  • token transfer: 5000(不需要开户时)
  • create ATA account(token 开户): 约 30000
  • raydium AMM swap: 约 33000-40000
  • jupiter swap: 约 100000-400000

像 jup swap 这样不确定的 CU 消耗 推荐用 simulate rpc 模拟执行获取 CU 消耗

优先费用价格 CU price 设置算法

  1. 交易预期利润的 60% 除以 CU limit 得到单价的套利贿赂矿工算法
  2. Helius Priority Fee API 的推荐
  3. rpc getRecentPrioritizationFees
  4. triton Improved Priority Fees API
  5. jupiter,raydium,metaora 这样的产品也内置了优先费用的计算,无需开发者处理

原版 rpc 优先费 API 返回的是某个智能合约地址最近 150 区块交易中的最小值 (at least one successfully landed)

其实更推荐用 triton 增强型优先费 API 能查询到某智能合约最近大伙给的优先费的中位数

一般网络拥堵的时候我个人经验是 jupiter TURBO 等级的优先费用都要给到 0.2u~0.4u 不等

SOL 跟 EVM 不同的是,EVM 如果交易失败了 收取的是 gasPrice * gasUsed(实际消耗的 CU)

那么问题来了,对于一个预期利润是 10SOL 的套利交易,拿出了 80% 预期利润 8SOL 的优先费用贿赂矿工

但是交易因为滑点过大没抢单成功,交易失败了也要支付 8SOL 的优先费用,是非常昂贵的成本了

为套利者而生的 jito

jito 的出现就解决了这个问题,jito 的交易不需要设置优先费用 CU price 的指令 (CU limit 还是建议要)

而是让交易最后加一个给 jito 8 个小费地址随机选一个转账的指令,为什么要随机选一个呢

如果大伙都往第一个小费地址打钱,8 个地址随机选一个可以提高吞吐量同时有 8 个 jito 小费指令可并行执行

所以发送给 jito 的交易失败发生回滚的话,最后一条小费指令不会执行,也就损失 5000lamports 的基础交易费用

bloXroute加速上链服务

很多 bot 的交易不直接发给 jito,而是通过 bloXroute 转发给 jito。因为 bloXroute 有一个 super bundle 的功能,能打包不冲突的交易,bundle 的 tip 也给的高,所以比直接发 jito 速度更快。

bloXroute 也是 jito 最大的合作伙伴之一,在 jito 那里有很高的账户等级;tip 给的高,只是快速上链的条件之一。其实还有其他一些基础设施上的配置,包括全球的节点布置,合作节点,网络拓扑优化等等

据说主要是交易机器人和一些 dex,做市商等采购 bloXroute 服务,我没用过就不评价了

什么时候用 jito 什么时候用优先费

§ 适用于 jito 加速交易的业务

  1. 套利交易
  2. 狙击 pump/raydium 等开盘
  3. 防夹
  4. 价格波动大的 LP 建仓
  5. 失败率高允许重试有希望快点上链的业务

笔者有次 LP 建仓发交易就说价格波动导致 tick 滑点变动交易失败,连续失败 4-5 次 每次亏损 0.4$的优先费用 如果用 jito 不断重试交易就不必亏这么多了

§ 适用于优先费用加速交易的业务

  1. memecoin swap 交易
  2. 快点转账

§ 既不要 jito 也不要优先费的业务

  1. 转账 (钱包软件基本不给优先费)
  2. 智能合约部署
  3. LP 超出区间了移除流动性等不是很急的业务

智能合约部署我的经验是推荐用 aws 免费节点+helius 免费 rpc 上传/部署智能合约

项目不急着上线失败就重试几次 (急的话 deploy 可加优先费用的命令行参数),失败的话会出现一些 program buffer 占用资金,稍后 solana program close 关掉后就能回收 SOL 了

谁当 leader 就给谁发

由于 SOL 网络中当前 epoch POS 的 leader 顺序是确定的,也可以预测下个 leader 是 jito 的节点就给 jito 发交易,如果是 helius/triton 节点就用优先费给他们发

还有一种思路 nonceAccount 同时签名两个交易一个发 jito 一个发 helius,一个成功另一个自然因为 nonce 无效而失败

swqos 机制加速上链

swqos 简单说就是质押量越大的验证者节点,在下个区块出块中能提交给 leader 节点的交易数更多,所以走质押量更大的节点 rpc 上链更快

听 solayer 在 space 说 要把 swqos 加速上链的机制做成 restaking 奖励,用户质押给项目方更多 SOL,项目的上链速度更快体验更好,项目方应该奖励给质押用户额外奖励这样的经济模型

swqos 节点基本是被 triton,helius 这样的大户厂商垄断了,quicknode 这样的知名厂商也没有,所以 solayer 能否打破这种垄断呢 (支持华语区项目打破垄断)

由于 triton 服务不对外公开销售了,所以也就只能用 helius 付费的 staked connection rpc 消耗的额度是普通 rpc 的 50 倍

如何确认交易成功/交易重试

由于 solana 网络拥堵时,发出去的交易可能被 rpc 节点丢弃没有发成功给 leader 节点了,或者等很久很久才上链,因此重试策略推荐阅读 triton 这篇文章 https://docs.triton.one/chains/solana/sending-txs

  1. 计算下签名交易用的 blockhash 还有多久过期
  2. ws 订阅交易的 signature
  3. 发送交易
  4. 每隔一段时间获取交易状态,定时重发交易

直到 http 轮询交易成功或者 ws 推送交易成功

由于笔者做的是套利业务对时效性要求极高 (行情过几秒后可能滑点巨大),所以我的做法是交易中插入一条超时 5s 指令

ws+http 轮询交易状态超过 5s 就认为是超时了,这样交易很久之后才上链会因为超时而失败

1 楼 已删除
youda 回复

不是智能合约标准库的指令,是我自己套利智能合约里面的指令

wuaoxiang 回复

感谢回复,明白了

需要 登录 后方可回复, 如果你还没有账号请 注册新账号