Dacă modulul Inventory este „memoria” robotului, atunci modulul Scout este „ochii” săi. Într-un flux turbulent în care Solana generează zeci de mii de modificări de stare pe secundă, sarcina lui Scout este să filtreze, evalueze și decodeze rapid semnalele care au o importanță reală pentru strategiile de arbitraj.

În lumea MEV, viteza nu este totul, dar fără viteză nu este nimic. În acest articol vom explora în profunzime cum se construiește un sistem de ascultare și analiză a tranzacțiilor cu întârziere minimă și concurență ridicată.

1. Filosofia ascultării: Cătușa chirurgicală vs. rețeaua de pescuit mare

Pe Solana, de obicei ne confruntăm cu două cerințe de ascultare complet diferite, corespunzătoare unor căi tehnologice diferite:

1.1 accountSubscribe: un bisturiu precis (modul Arb)

Pentru arbitrajul interprotocolar (Arbitrage), deja am blocat anumite lacături prin Inventory. În acest moment, nu avem nevoie să monitorizăm întregul net, ci doar să urmărim cu strășnicie modificările câmpului Data ale acestor conturi.

  • Mecanism: imediat ce soldul sau prețul unui token dintr-un lacăt se modifică, nodul RPC trimite imediat datele actualizate ale contului.

  • Avantaj: semnalele sunt extrem de directe, trecând peste analiza complicată a tranzacțiilor, fiind calea cea mai rapidă pentru arbitrajul de înaltă frecvență.

1.2 logsSubscribe: o rețea uriașă care acoperă întregul net (modul Sniper)

Pentru sniperul de noi lacături (Sniping), nu putem cunoaște dinainte adresa lacătului, ci trebuie să ascultăm semnalele de tip "creare lacăt" sau "injectare de lichiditate inițială" prin logs de protocol (de exemplu, Raydium sau Orca).

  • Mecanism: scanarea logurilor după cuvinte-cheie specifice (de exemplu, initialize2).

  • Provocare: zgomot extrem, iar după detectare este necesar de obicei un proces "lent" (de exemplu, solicitarea getTransaction) pentru a completa analiza informațiilor despre tokenul din lacăt.

2. Arhitectură principală: fluxuri multiplexate

Într-un sistem matur, este posibil să trebuie să abonezi simultan la actualizările a sute de lacături. Dacă deschizi un fir pentru fiecare abonament, consumul de resurse va explodea imediat.

2.1 Combinare fluxuri asincrone (Select All)

Folosim ecosistemul asincron Rust (Tokio + Futures), combinând prin select_all sute de fluxuri WebSocket într-un singur flux de evenimente. Acesta este ca și cum am aduna imaginile de la sute de camere de supraveghere pe un singur ecran, gestionate de un ciclu central (Event Loop) care le distribuie uniform.

2.2 Modelul de fire și izolarea "calei lente"

Viteza de răspuns a ciclului principal de ascultare determină limita superioară a latenței sistemului.

  • Cale rapidă (Hot Path): primire date -> decodare în memorie -> declanșare calcul.

  • Cale lentă (Long Path): dacă este necesară o cerere RPC suplimentară pentru a completa informațiile (de exemplu, în modul Sniper), trebuie folosit tokio::spawn pentru a separa imediat execuția într-o sarcină de fundal, fără a bloca ciclul principal de ascultare.

3. Analiză extremă: sărirea informațiilor inutile

Datele contului Solana (Account Data) sunt de obicei o secvență binară. Abordarea ineficientă este să le deserializăm în obiecte complete, în timp ce abordarea extremă este "parsarea la cerere".

3.1 Zero-copy și localizare prin offset

De exemplu, la ascultarea Orca Whirlpool, poate că avem nevoie doar de valorile sqrt_price și tick_current_index.

  • Nu avem nevoie să analizăm întregul stat al lacătului (sute de octeți), ci doar să citim direct din fluxul de date la un Offset (deplasare) specific, 16 octeți.

  • În Rust, prin combinarea cu bytemuck sau deplasări simple de pointer, extragerea parametrilor cheie pentru prețare poate fi realizată în microsecunde.

3.2 Artă a filtrării

În etapa logsSubscribe, folosind filtrul mentions oferit de RPC, se poate filtra la nivelul nodului până la 90% din logurile inutile, reducând semnificativ presiunea de I/O de rețea de pe partea Searcher.

4. Puncte de optimizare performanță: câștigăm milisecunde din implementare

  1. Abonament fragmentat (Sharding): în fața limitărilor de conexiune ale nodurilor RPC comune, Scout împarte automat lacăturile din listă albă în fragmente, primind date în mod concurent prin mai multe conexiuni WebSocket, evitând astfel backpressure-ul pe o singură conexiune.

  2. Mecanism de reducere a zgomotului: pentru lacături cu schimbări frecvente, se implementează logica simplă de pierdere sau coalescere a pachetelor (Coalescing); dacă într-un interval de 1 ms se generează mai multe actualizări pentru același lacăt, se procesează doar ultimul statut, economisind astfel resursele de calcul din stratul strategiei.

  3. Index preîncărcat: în timpul analizei logurilor, se încarcă anticipat informațiile despre Decimals pentru tokenurile frecvent utilizate, evitând astfel cereri secundare în timpul calculului diferenței de preț.

5. Demonstrație tehnică: logică de combinare a fluxurilor multiple de evenimente (simulare Python)

Deși nucleul de performanță este în Rust, logica de combinare și distribuție "multi-versus-unu" poate fi exprimată perfect prin asyncio:

import asyncio
import random

async def pool_monitor(pool_id: str):
"""Simulează un flux de abonament pentru un cont independent"""
while True:
await asyncio.sleep(random.uniform(0.01, 0.1)) # Simulează livrare aleatorie
yield {"pool": pool_id, "data": random.random()}

async def main_scout_loop():
# Simulare: obținerea listei de ascultare din Inventory
watchlist = ["Pool_A", "Pool_B", "Pool_C"]

# Combinarea tuturor fluxurilor într-o singură coadă
queue = asyncio.Queue()

async def producer(pool_id):
async for update in pool_monitor(pool_id):
await queue.put(update)

# Porniți toate sarcinile de productor
for p in watchlist:
asyncio.create_task(producer(p))

print("[*] Motorul Scout este pornit, ascultă semnale multiple...")

# Ciclu principal de consum: distribuirea strategiilor
while True:
event = await queue.get()
# În acest moment declanșăm imediat calculul asincron la nivelul strategiei
asyncio.create_task(execute_strategy(event))

async def execute_strategy(event):
print(f"⚡️ Semnal primit: {event['pool']} -> declanșare calcul model prețuri")

if name == "__main__":
asyncio.run(main_scout_loop())

6. Concluzie: cea mai sensibilă radar

Nivelul de proiectare al modulului Scout determină direct viteza de pornire a robotului. Un Scout bun ar trebui să fie:

  • Suficient de larg: poate detecta noi oportunități prin loguri.

  • Suficient de precis: poate bloca schimbările de preț prin abonament la conturi.

  • Suficient de rapid: folosește arhitectură asincronă și analiză binară, menținând latența sub nivelul microsecundelor.

Anunț pentru următorul pas

Am primit semnalul, am obținut datele brute. Ce urmează? Trebuie să transformăm datele binare în prețuri reale ale activelor. În articolul următor vom intra în modul AMM, dezvăluind cum formula de produs constant al Raydium și modelul matematic al lichidității concentrate Orca funcționează în memorie cu viteză maximă.

Acest articol a fost scris de Levi.eth, dedicat împărtășirii artei extreme a ingineriei în domeniul Solana MEV.

$SOL $JTO

JTO
JTOUSDT
0.2557
+3.56%

SOL
SOL
86.44
+5.63%