Se il modulo Inventory è la "memoria" del robot, il modulo Scout è il suo "occhio". Nell'acqua turbolenta in cui Solana genera decine di migliaia di modifiche di stato al secondo, il compito di Scout è quello di filtrare, selezionare e decodificare velocemente i segnali veramente significativi per le strategie di arbitraggio.
Nel mondo MEV, la velocità non è tutto, ma senza velocità non c'è nulla. Questo articolo esplorerà approfonditamente come costruire un sistema di ascolto e analisi delle transazioni a bassa latenza e alto parallelismo.
1. Filosofia dell'ascolto: bisturi vs. rete da pesca
Su Solana, di solito affrontiamo due esigenze di ascolto radicalmente diverse, corrispondenti a percorsi tecnologici diversi:
1.1 accountSubscribe: un bisturi preciso (modalità Arb)
Per l'arbitraggio cross-protocollo, abbiamo già bloccato un pool specifico tramite l'Inventory. A questo punto, non dobbiamo osservare l'intera rete, dobbiamo solo concentrarci sulle modifiche del campo Data di questi account di pool.
Meccanismo: una volta che il saldo o il prezzo dei token nel pool cambia, il nodo RPC invia immediatamente i dati più recenti dell'account.
Vantaggio: il segnale è estremamente diretto, salta l'analisi complessa delle transazioni, è il percorso più veloce per l'arbitraggio ad alta frequenza.
1.2 logsSubscribe: una rete da pesca globale (modalità Sniper)
Per il nuovo pool di sniping, non possiamo prevedere l'indirizzo del pool, possiamo solo catturare il segnale di istruzione "nuovo pool" o "iniezione di liquidità iniziale" ascoltando i Program Logs di protocolli specifici (come Raydium o Orca).
Meccanismo: scansiona le parole chiave specifiche nei log (come initialize2).
Sfida: rumore estremamente elevato e, una volta colpito, spesso richiede un'elaborazione "lenta" (come la richiesta getTransaction) per completare l'analisi delle informazioni sui token del pool.
2. Architettura di base: multiplexing di flussi
In un sistema maturo, potresti dover iscriverti contemporaneamente agli aggiornamenti di centinaia di pool. Se apri un thread per ogni iscrizione, il sovraccarico del sistema esploderà istantaneamente.
2.1 Fusione di flussi asincroni (Seleziona tutto)
Adottiamo l'ecosistema asincrono di Rust (Tokio + Futures), utilizzando select_all per combinare centinaia di flussi di iscrizione WebSocket in un unico flusso di eventi. È come raccogliere le immagini di centinaia di telecamere di sorveglianza su un muro di visualizzazione, gestito da un ciclo centrale (Event Loop).
2.2 Modello di thread e rimozione del "percorso lento"
La velocità di risposta del ciclo principale determina il limite di latenza del sistema.
Percorso veloce (Hot Path): ricezione dei dati -> decodifica in memoria -> attivazione del calcolo.
Percorso lento (Long Path): se è necessario richiedere informazioni RPC aggiuntive (come la modalità Sniper), è necessario utilizzare tokio::spawn per estrarre immediatamente in esecuzione di task in background, vietando rigorosamente il blocco del ciclo principale di ascolto.
3. Estrema analisi: salta informazioni inutili
I dati dell'account di Solana (Account Data) sono solitamente un buffer binario. L'approccio inefficiente è deserializzarli in oggetti completi, mentre l'approccio estremo è "analizzare su richiesta".
3.1 Zero copy e posizionamento offset
Ad esempio, quando ascolti Orca Whirlpool, potremmo aver bisogno solo di sqrt_price e tick_current_index.
Non dobbiamo analizzare l'intero stato del pool (centinaia di byte), dobbiamo solo leggere direttamente i 16 byte a un offset specifico nel flusso di dati.
In Rust, attraverso l'uso di bytemuck o semplici offset di puntatore, possiamo completare l'estrazione dei parametri di prezzo chiave a livello di microsecondi.
3.2 L'arte dei filtri
Nella fase logsSubscribe, utilizzando il filtro mentions fornito da RPC, possiamo filtrare il 90% dei log irrilevanti già sul lato del nodo, riducendo notevolmente la pressione della rete IO sul lato del Searcher.
4. Ottimizzazione delle prestazioni: dall'implementazione ingegneristica a millisecondi
Sottoscrizione sharding: per il limite di connessione dei nodi RPC pubblici, Scout suddividerà automaticamente i pool in whitelist, ricevendo in parallelo tramite più connessioni WebSocket, evitando la pressione di una connessione unica.
Meccanismo di riduzione del rumore: per i pool ad alta frequenza, implementa una logica semplice di perdita o fusione (Coalescing), se lo stesso pool genera più aggiornamenti in 1 ms, gestisce solo l'ultimo stato per risparmiare risorse computazionali del livello strategico.
Indice di prelettura: durante l'analisi dei log, carica in anticipo le informazioni Decimals dei token più utilizzati, evitando richieste secondarie durante il calcolo del differenziale di prezzo.
5. Dimostrazione tecnica: logica di fusione di eventi multipli (simulazione Python)
Sebbene il core ad alte prestazioni sia in Rust, la sua logica di distribuzione "molti a uno" può essere espressa perfettamente con asyncio:
import asyncio
import random
async def pool_monitor(pool_id: str):
"""Simula un flusso di sottoscrizione di un account indipendente"""
while True:
await asyncio.sleep(random.uniform(0.01, 0.1)) # Simula invio casuale
yield {"pool": pool_id, "data": random.random()}
async def main_scout_loop():
# Simula la lista di ascolto ottenuta dall'Inventory
watchlist = ["Pool_A", "Pool_B", "Pool_C"]
# Unisci tutti i flussi in una coda
queue = asyncio.Queue()
async def producer(pool_id):
async for update in pool_monitor(pool_id):
await queue.put(update)
# Avvia tutti i compiti dei produttori
for p in watchlist:
asyncio.create_task(producer(p))
print("[*] Il motore Scout è avviato, sta ascoltando più segnali...")
# Ciclo di consumo principale: gestione della distribuzione delle strategie
while True:
event = await queue.get()
# In questo momento, attiva immediatamente il calcolo asincrono del livello strategico
asyncio.create_task(execute_strategy(event))
async def execute_strategy(event):
print(f"⚡️ Segnale catturato: {event['pool']} -> attivazione del calcolo del modello di prezzo")
if name == "__main__":
asyncio.run(main_scout_loop())
6. Sommario: il radar più sensibile
Il livello di progettazione del modulo Scout determina direttamente la "velocità di partenza" del robot. Un eccellente Scout dovrebbe:
Sufficientemente ampio: in grado di catturare nuove opportunità tramite i log.
Sufficientemente preciso: in grado di bloccare le fluttuazioni di prezzo tramite l'iscrizione agli account.
Sufficientemente veloce: utilizzando un'architettura asincrona e analisi binaria, mantenendo la latenza a livello di microsecondi.
Anticipazione del prossimo passo
Abbiamo catturato un segnale, ottenuto i dati originali, cosa fare dopo? Dobbiamo convertire i dati binari in prezzi di asset reali. Nel prossimo articolo, entreremo nel modulo AMM, svelando come la formula del prodotto costante di Raydium e il modello matematico di liquidità centralizzata di Orca funzionano ad alta velocità in memoria.
Questo articolo è stato scritto da Levi.eth, dedicato a condividere l'arte ingegneristica estrema nel campo del MEV di Solana.

