sol_trade_sdk/trading/core/
execution.rs1use anyhow::Result;
5use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signature::Keypair};
6
7use crate::perf::{hardware_optimizations::BranchOptimizer, simd::SIMDMemory};
8
9pub const BYTES_PER_ACCOUNT: usize = 32;
11
12pub const MAX_INSTRUCTIONS_WARN: usize = 64;
14
15pub struct Prefetch;
19
20impl Prefetch {
21 #[inline(always)]
22 pub fn instructions(instructions: &[Instruction]) {
23 if instructions.is_empty() {
24 return;
25 }
26 unsafe {
28 BranchOptimizer::prefetch_read_data(&instructions[0]);
29 }
30 if instructions.len() > 2 {
31 unsafe {
32 BranchOptimizer::prefetch_read_data(&instructions[instructions.len() / 2]);
33 }
34 }
35 if instructions.len() > 1 {
36 unsafe {
37 BranchOptimizer::prefetch_read_data(&instructions[instructions.len() - 1]);
38 }
39 }
40 }
41
42 #[inline(always)]
43 pub fn pubkey(pubkey: &Pubkey) {
44 unsafe {
45 BranchOptimizer::prefetch_read_data(pubkey);
46 }
47 }
48
49 #[inline(always)]
50 pub fn keypair(keypair: &Keypair) {
51 unsafe {
52 BranchOptimizer::prefetch_read_data(keypair);
53 }
54 }
55}
56
57pub struct MemoryOps;
59
60impl MemoryOps {
61 #[inline(always)]
62 pub unsafe fn copy(dst: *mut u8, src: *const u8, len: usize) {
63 SIMDMemory::copy_avx2(dst, src, len);
64 }
65
66 #[inline(always)]
67 pub unsafe fn compare(a: *const u8, b: *const u8, len: usize) -> bool {
68 SIMDMemory::compare_avx2(a, b, len)
69 }
70
71 #[inline(always)]
72 pub unsafe fn zero(ptr: *mut u8, len: usize) {
73 SIMDMemory::zero_avx2(ptr, len);
74 }
75}
76
77pub struct InstructionProcessor;
79
80impl InstructionProcessor {
81 #[inline(always)]
82 pub fn preprocess(instructions: &[Instruction]) -> Result<()> {
83 if BranchOptimizer::unlikely(instructions.is_empty()) {
84 return Err(anyhow::anyhow!("Instructions empty"));
85 }
86
87 Prefetch::instructions(instructions);
88
89 if BranchOptimizer::unlikely(instructions.len() > MAX_INSTRUCTIONS_WARN) {
90 tracing::warn!(target: "sol_trade_sdk", "Large instruction count: {}", instructions.len());
91 }
92
93 Ok(())
94 }
95
96 #[inline(always)]
97 pub fn calculate_size(instructions: &[Instruction]) -> usize {
98 let mut total_size = 0;
99
100 for (i, instr) in instructions.iter().enumerate() {
101 unsafe {
103 if let Some(next_instr) = instructions.get(i + 1) {
104 BranchOptimizer::prefetch_read_data(next_instr);
105 }
106 }
107
108 total_size += instr.data.len();
109 total_size += instr.accounts.len() * BYTES_PER_ACCOUNT;
110 }
111
112 total_size
113 }
114}
115
116pub struct ExecutionPath;
118
119impl ExecutionPath {
120 #[inline(always)]
121 pub fn is_buy(input_mint: &Pubkey) -> bool {
122 let is_buy = input_mint == &crate::constants::SOL_TOKEN_ACCOUNT
123 || input_mint == &crate::constants::WSOL_TOKEN_ACCOUNT
124 || input_mint == &crate::constants::USD1_TOKEN_ACCOUNT
125 || input_mint == &crate::constants::USDC_TOKEN_ACCOUNT;
126
127 if BranchOptimizer::likely(is_buy) {
128 return true;
129 }
130
131 false
132 }
133
134 #[inline(always)]
135 pub fn select<T>(
136 condition: bool,
137 fast_path: impl FnOnce() -> T,
138 slow_path: impl FnOnce() -> T,
139 ) -> T {
140 if BranchOptimizer::likely(condition) {
141 fast_path()
142 } else {
143 slow_path()
144 }
145 }
146}