e32e7ee6ab
Made-with: Cursor
8.9 KiB
8.9 KiB
sol-trade-sdk 代码审查报告
审查维度:逻辑准确性、可读性、模块化、超低延迟、代码质量、安全性。
1. 代码逻辑准确性
1.1 Instruction 与 IDL / 官方行为
| 模块 | 结论 | 说明 |
|---|---|---|
| PumpFun buy/sell | ✅ 一致 | 账户顺序、discriminator、track_volume 与 idl/pump.json 一致;cashback 时 remainingAccounts 顺序正确 |
| PumpSwap buy/sell | ✅ 一致 | 与 idl/pump_amm.json 一致;sell cashback 使用 quote_mint ATA |
| PDA 推导 | ✅ 一致 | bonding_curve_v2、pool_v2、user_volume_accumulator、creator_vault 等 seeds 与官方一致 |
1.2 需修正的逻辑/风格
src/instruction/utils/pumpswap.rs约 258、291 行:let program_id: &Pubkey = &&accounts::AMM_PROGRAM为双重引用,易误导且多余。建议改为&accounts::AMM_PROGRAM。
2. 代码可读性
2.1 命名与注释
- 多数模块有中英文注释,instruction 与 IDL 的对应关系有标注。
- 建议:
src/instruction/pumpfun.rs约 259 行 sell 的 discriminator 使用魔法数组[51, 230, 133, ...],建议改为SELL_DISCRIMINATOR常量(与 buy 路径一致)。
2.2 错误信息与文案
- 建议:
src/lib.rs中 “Current version only support” 应为 “only supports”;类似拼写/语法可统一检查。
2.3 过长函数
- 建议:
src/lib.rs的ensure_wsol_ata可拆为「入口 + 重试循环」与「单次尝试 + 结果判断」,便于单测和阅读。
3. 模块化
3.1 职责与分层
- instruction:按协议分(pumpfun / pumpswap / bonk / raydium_* 等),实现
InstructionBuilder,边界清晰。 - instruction/utils:PDA、常量、类型、池子解析与上层「组指令」分工明确。
- swqos:按提供商分模块,common 放序列化、确认轮询、HTTP 客户端,无循环依赖。
- 结论:分层合理,模块化良好。
4. 超低延迟
4.1 必须改:避免多余 clone
| 位置 | 问题 | 建议 |
|---|---|---|
src/instruction/pumpswap.rs 约 232、429 行 |
Instruction { accounts: accounts.clone(), data } 对已拥有的 Vec<AccountMeta> 做完整 clone |
改为直接移动:Instruction { program_id, accounts, data },不再 clone |
4.2 建议
- 若多路 SWQOS 并发发同一笔交易,可在调用方序列化一次,再传
&[u8]给各 client,减少重复 bincode 序列化。 - 热点路径未见不必要的
Mutex/RwLock竞争,当前设计可接受。
5. 代码质量
5.1 必须改:避免 panic 的 unwrap
以下 PDA 或关键 Option 使用 .unwrap(),在异常输入下会直接 panic,建议改为 Result 并向上传播错误:
| 文件 | 行号(约) | 说明 |
|---|---|---|
src/instruction/pumpfun.rs |
67, 101, 149, 221, 291, 295 | get_bonding_curve_pda、get_user_volume_accumulator_pda、get_bonding_curve_v2_pda |
src/instruction/pumpswap.rs |
184, 198, 385, 407 | get_user_volume_accumulator_pda、get_pool_v2_pda |
src/instruction/utils/pumpfun.rs |
229 | DEFAULT_CREATOR_VAULT.unwrap()(LazyLock 未初始化时可能 panic) |
src/instruction/bonk.rs |
多处 | get_pool_pda、get_vault_pda、params.rpc.as_ref().unwrap() |
src/instruction/utils/bonk.rs |
110–116, 148–152 | checked_* 链后 .unwrap(),数学假设不成立会 panic |
src/instruction/raydium_cpmm.rs |
46, 106, 189, 250 | PDA / 状态相关 unwrap |
src/instruction/utils/raydium_cpmm.rs |
83, 85, 141 | get_vault_pda(...).unwrap() |
建议:统一改为 .ok_or_else(|| anyhow!("..."))? 或返回 Result,在调用链顶层处理错误,避免进程退出。
5.2 建议
- 测试:为 instruction 构建(或至少 PDA + discriminator/data 布局)增加单元测试,固定输入与预期 bytes/accounts 比对,便于 IDL 升级时回归。
- 错误类型:
claim_cashback_*等返回Option<Instruction>;可考虑统一为Result<Instruction>并带“无法构建”原因,或在文档中明确 None 的语义。
6. 安全性
6.1 必须改:API key 不得写入日志
| 位置 | 问题 | 建议 |
|---|---|---|
src/swqos/astralane_quic.rs 约 61 行 |
info!(..., "api_key as CN: {}", api_key) |
移除 api_key 或改为占位(如 *** / 仅长度) |
src/swqos/astralane_quic.rs 约 74 行 |
info!(..., "Connected at {} (api_key: {})", addr, api_key) |
同上 |
6.2 必须改:SkipServerVerification 风险
| 位置 | 问题 | 建议 |
|---|---|---|
src/swqos/astralane_quic.rs 约 179–181 行 |
with_custom_certificate_verifier(SkipServerVerification) 完全跳过服务端证书校验 |
1)若服务端提供证书:用 RootCertStore 或固定证书做校验;2)若仅 dev/内网:用 feature 或配置限制,并在文档/日志中明确“仅受控环境使用”;3)默认/生产构建建议不跳过校验 |
6.3 建议
- 敏感配置:确保生产环境从环境变量或安全配置读取 API key,并在文档中说明。
- 依赖:定期执行
cargo audit与依赖升级。 - unsafe:
perf/hardware_optimizations.rs、realtime_tuning.rs中的unsafe使用范围可控,需保持注释中的安全约定。
7. 三库联动与超低延迟检查(sol-trade-sdk / sol-parser-sdk / solana-streamer)
7.1 逻辑一致性(已确认)
| 检查项 | sol-parser-sdk | solana-streamer | 说明 |
|---|---|---|---|
| Pump buy 账户数 | 16(fill 用 get(9) 填 creator_vault) | 16,accounts[9]=creator_vault | 与 idl/pumpfun.json 一致 |
| Pump sell 账户数 | 14(get(8)=creator_vault) | 14,accounts[8]=creator_vault | 一致 |
| PumpSwap buy 17/18 | 指令解析 + fill_buy_accounts get(17)/get(18) | 指令解析 accounts.get(17)/get(18) | coin_creator_vault_ata/authority 正确 |
| PumpSwap sell 17/18 | fill_sell_accounts 同左 | 同左 | 一致 |
| 填充顺序 | 先 parse(log 或 instruction)→ fill_accounts → push | 指令解析直接写 17/18;无单独 fill 步骤 | 两者均保证事件带齐 creator_vault / coin_creator_vault |
| find_instruction_invoke | 选「账户数最多」的 invoke,保证取到 outer buy/sell | N/A(按当前 instruction 解析) | 正确 |
7.2 版本化交易账户解析
- sol-parser-sdk:
get_instruction_account_getter正确支持 versioned tx:先account_keys,再loaded_writable_addresses,再loaded_readonly_addresses,与 Solana 约定一致。 - solana-streamer:指令的
accounts为索引,通过accounts.get(idx as usize).copied()从完整accounts: &[Pubkey]解析;调用方需传入已包含 loaded 的完整账户列表,否则高索引会得到default()。
7.3 超低延迟相关
| 项目 | 状态 / 建议 |
|---|---|
| solana-streamer 热路径 | 已改为顺序执行 inner 解析与 swap_data 提取,去掉 thread::scope + 双 spawn/join,减少 μs 级开销。 |
| sol-parser-sdk | log 与 instruction 并行(rayon::join);fill 仅在有 invoke 时做;find_instruction_invoke 为 O(invokes),单程序单 tx 下可接受。 |
| sol-trade-sdk | 见上文第 4 节;PumpSwap instruction 构建避免 accounts.clone() 已列为必须改。 |
7.4 建议
- solana-streamer:若 gRPC 上游已提供完整
accounts(含 loaded),可避免对每笔 tx 做accounts.to_vec(),仅在需要 resize 时克隆,进一步降低分配。 - 三库:保持 IDL 与账户索引注释同步(pumpfun.json / pump_amm.json),避免后续扩展时索引错位。
8. 汇总:必须改 vs 建议改
必须改(优先处理)
| 序号 | 项 | 位置 |
|---|---|---|
| 1 | 移除 astralane_quic 中 API key 的日志输出 | src/swqos/astralane_quic.rs 61、74 行 |
| 2 | SkipServerVerification:改为证书校验或仅限 dev 并文档化 | src/swqos/astralane_quic.rs 179–181 行 |
| 3 | instruction 中 PDA 等 .unwrap() 改为 Result 并传播错误 |
pumpfun.rs、pumpswap.rs、pumpfun/utils、bonk、raydium_cpmm 等 |
| 4 | PumpSwap 构建 instruction 时避免 accounts.clone(),改为移动 |
src/instruction/pumpswap.rs 232、429 行 |
建议改(可分批)
| 序号 | 项 | 位置 |
|---|---|---|
| 5 | PDA 的 program_id 从 &&AMM_PROGRAM 改为 &AMM_PROGRAM |
src/instruction/utils/pumpswap.rs 258、291 行 |
| 6 | PumpFun sell discriminator 改为命名常量 | src/instruction/pumpfun.rs 约 259 行 |
| 7 | ensure_wsol_ata 拆分;修正 “only support” 等文案 |
src/lib.rs |
| 8 | 为 instruction 构建与 PDA 增加单元测试 | 新建 tests 或模块下 |
| 9 | 生产日志用 tracing 替代 println!/eprintln! | src/swqos/astralane.rs 等 |
报告基于当前仓库与 IDL 的静态阅读;若官方 SDK 或链上程序有未公开变更,建议再与官方实现或链上行为做一次对照验证。