Interrogare le blockchain con SQL · Lezione 1 di 6
Lo stack di dati analitici
10 min di lettura
Quasi tutti i numeri in un report on-chain sono passati attraverso una pipeline tra il nodo che ha rilevato il blocco e la query che ha prodotto il dato. Un analista che sa a quale livello appartiene una tabella, chi l’ha creata, quanto è aggiornata e quali regole l’hanno determinata può distinguere un risultato reale da un artefatto della pipeline. Questa lezione illustra lo stack e le scelte da fare quando si selezionano gli strumenti.
Dal nodo alla tabella
Un nodo memorizza e fornisce i dati della blockchain nel formato richiesto dal protocollo: blocchi, transazioni, ricevute e stato, accessibili tramite chiamate RPC (vedi la lezione API dei nodi e accesso ai dati). Gli analisti hanno bisogno degli stessi dati organizzati in righe e colonne che si possano filtrare, unire e sommare. Il processo che trasforma gli uni nelle altre è una pipeline ETL: estrazione, trasformazione, caricamento.
- Estrazione. La pipeline interroga il nodo per ogni blocco di un intervallo: il blocco con le sue transazioni, le ricevute con i relativi log e, se il nodo li supporta, le tracce delle chiamate.
- Trasformazione. I JSON annidati vengono appiattiti in una riga per record. Le stringhe esadecimali vengono convertite in numeri, il timestamp del blocco viene copiato su ogni transazione e log, così che le query non debbano eseguire un join per ottenere l’orario, e gli identificatori vengono normalizzati (per esempio, gli indirizzi in minuscolo).
- Caricamento. Le righe vengono scritte nello spazio di archiviazione, di solito in file colonnari come Apache Parquet, partizionati per data o intervallo di blocchi, oppure in tabelle di database. Formati di tabelle aperti come Apache Iceberg e Delta Lake aggiungono snapshot versionati ai file.
Il concetto chiave è la granularità: che cosa rappresenta una riga. Un blocco Ethereum con 150 transazioni e 400 log di eventi diventa una riga in blocks, 150 righe in transactions e 400 righe in logs. La maggior parte degli errori nelle query deriva dal dimenticare la granularità di una tabella e dal contare o sommare al livello sbagliato.
Le pipeline funzionano in due modalità. Un backfill elabora la cronologia in grandi lotti, una sola volta. I caricamenti streaming o incrementali seguono la testa della catena, blocco per blocco. Vicino alla testa, i blocchi possono ancora essere sostituiti da una riorganizzazione, quindi una pipeline attende una certa profondità di conferma o un blocco finalizzato, oppure riscrive i blocchi recenti quando la catena cambia (vedi la lezione Blocchi e intestazioni come dati).
Esistono estrattori open source per gran parte di queste attività: Ethereum ETL e Bitcoin ETL del progetto blockchain-etl, e cryo, che scrive i dati EVM direttamente in Parquet. Vale la pena conoscerli anche se non li si esegue mai, perché molti dataset pubblici sono stati creati con questi strumenti ed ereditano i nomi delle loro colonne.
Tabelle grezze, decodificate e curate
Le tabelle di un data warehouse blockchain si dividono in tre livelli, che rispecchiano i livelli dei dati introdotti nella lezione Il punto di vista dell’analista su una blockchain.
| Livello | Contenuto | Tabelle tipiche | Rischio principale |
|---|---|---|---|
| Grezzo | Record così come restituiti dal nodo, tipizzati ma non interpretati | blocks, transactions, logs, traces; input e output per le chain UTXO | Campi esadecimali, unità di base (wei, satoshi), difficili da leggere |
| Decodificato | Record grezzi interpretati con un ABI o un parser di script | Una tabella per ogni evento o funzione del contratto, calldata decodificati | ABI mancante o errato, proxy, contratti non verificati |
| Curato | Tabelle a livello business create da diverse fonti | token_transfers, dex_trades, balances, labels, prices | Regole di inclusione nascoste, errori nelle etichette, prezzi non aggiornati |
Ogni passaggio verso l’alto rende le query più brevi e aggiunge decisioni prese da qualcun altro. Una tabella curata token_transfers permette di rispondere alle domande con una sola riga di query, ma occorre conoscerne le regole. Include i trasferimenti ERC-721 oppure solo i token fungibili? I mint e i burn sono righe con l’indirizzo zero oppure sono esclusi? L’importo è l’intero grezzo o è già stato diviso per il numero di decimali? Due dataset che chiamano entrambi una tabella token_transfers possono differire su tutti questi aspetti.
L’abitudine che ti protegge è la riconciliazione: confronta una tabella curata con il livello grezzo da cui proviene, su un intervallo ridotto di blocchi.
-- La tabella curata token_transfers corrisponde ai log grezzi da cui proviene?
SELECT 'log grezzi' AS layer, COUNT(*) AS n
FROM logs
WHERE topic0 = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
AND topic3 IS NULL -- solo trasferimenti fungibili (in stile ERC-20)
AND block_number BETWEEN 21000000 AND 21000099
UNION ALL
SELECT 'trasferimenti token', COUNT(*)
FROM token_transfers
WHERE block_number BETWEEN 21000000 AND 21000099;
La prima parte conta gli eventi Transfer grezzi (la lunga stringa esadecimale è l’hash della firma dell’evento, spiegato nella lezione Interrogare log e tracce EVM); la seconda conta le righe curate per gli stessi 100 blocchi. Se i numeri differiscono, scopri il motivo prima di usare la tabella: il livello curato potrebbe escludere alcuni token, includere NFT oppure non contenere alcuni blocchi.
Dataset pubblici di blockchain
Non serve avere una propria pipeline per iniziare. Diversi dataset pubblici gratuiti mettono a disposizione la cronologia completa delle chain nei motori di query o in file.
- Dataset pubblici Google BigQuery. I dataset
crypto_bitcoinecrypto_ethereum(oltre ad altri relativi a diverse chain) sono stati creati con gli strumenti blockchain-etl. Il dataset Ethereum contiene le tabelleblocks,transactions,logs,traces,token_transfers,contractsetokens; i log memorizzano gli argomenti come array anziché in colonne separate. Per consultarli è necessario un account cloud; i dati scansionati oltre la quota gratuita sono a pagamento. - AWS Public Blockchain Data. File Parquet compressi in un bucket di archiviazione pubblico, partizionati per data e aggiornati ogni giorno. Comprende Bitcoin, Ethereum e diverse altre chain; consulta la documentazione per l’elenco aggiornato. I file possono essere letti da qualsiasi motore compatibile con Parquet.
- Piattaforme di query ospitate. Diverse aziende gestiscono piattaforme per la community con tabelle grezze, decodificate e curate per molte chain e un piano gratuito. Sono pratiche per i dati decodificati, ma le tabelle curate seguono le regole di ciascun fornitore.
Pubblico non significa corretto o aggiornato. I dataset possono essere in ritardo rispetto alla chain di qualche minuto o di un giorno, cambiare schema e talvolta omettere blocchi dopo un errore di estrazione. Prima di fare affidamento su una tabella, analizzane il profilo.
-- Analizza il profilo di una tabella prima di fidarti: copertura, aggiornamento, duplicati
SELECT
MIN(block_number) AS first_block,
MAX(block_number) AS last_block,
MAX(block_timestamp) AS latest_data_utc,
COUNT(*) AS row_count,
COUNT(DISTINCT hash) AS distinct_hashes -- dovrebbe corrispondere a row_count
FROM transactions;
Questa query indica l’intervallo di blocchi coperto, quanto è recente la riga più nuova e se qualche transazione compare due volte. Su un’intera chain scansiona solo poche colonne, ma di una tabella molto grande; quindi, su un motore che fa pagare ogni scansione, eseguila prima su un intervallo di date recente (vedi la lezione Prestazioni, costi e riproducibilità).
Motori di query e notebook
Il motore è il software che esegue le query SQL. Gli stessi dati possono essere gestiti da motori molto diversi.
| Tipo di motore | Esempi aperti | Indicato per |
|---|---|---|
| Data warehouse cloud | Servizi gestiti dei principali provider cloud | Scansioni dell’intera cronologia senza infrastruttura; ospita dataset pubblici |
| SQL distribuito su file | Trino, Apache Spark SQL | Data lake di file Parquet su scala di team |
| Database analitico colonnare | ClickHouse | Dashboard veloci e monitoraggio continuo |
| Motore incorporato | DuckDB, SQLite | Lavoro su un’estrazione locale da laptop; casi riservati |
| Database relazionale | PostgreSQL | Dati dei casi, etichette, tabelle piccole soggette a frequenti modifiche |
Le funzionalità fondamentali di SQL (SELECT, JOIN, GROUP BY, funzioni finestra) sono condivise, ma i nomi delle funzioni, la gestione delle date, la sintassi degli array e persino i nomi delle tabelle variano.
-- Una domanda, tre modi di indicare i dati
-- Dataset pubblico in un data warehouse (progetto.dataset.tabella, quoting BigQuery):
SELECT COUNT(*) FROM `bigquery-public-data.crypto_ethereum.blocks`
WHERE DATE(timestamp) = '2024-11-01';
-- Motore incorporato che legge direttamente i file Parquet (sintassi DuckDB):
SELECT COUNT(*) FROM read_parquet('eth/blocks/date=2024-11-01/*.parquet');
-- Qualsiasi motore con lo schema generico usato in questo modulo:
SELECT COUNT(*) FROM blocks WHERE CAST(block_timestamp AS DATE) = DATE '2024-11-01';
Tutte e tre le query contano i blocchi prodotti in un giorno UTC. Cambiano solo il riferimento alla tabella e la sintassi della data; la logica è identica. Le lezioni di questo modulo usano uno schema generico e segnalano le principali differenze tra dialetti man mano che si presentano.
I notebook (Jupyter e simili) combinano celle SQL, codice in Python o R, grafici e note scritte in un unico documento, una soluzione adatta alle indagini: eseguire una query, esaminare i risultati, creare un grafico e annotare il ragionamento. Alcune attività si prestano poco a SQL, in particolare le analisi iterative dei grafi, come la ricerca di componenti connesse per il clustering; per queste, gli analisti esportano da SQL gli archi verso una libreria per grafi (vedi la lezione Interrogare i dati UTXO).
Scegliere gli strumenti
Non esiste uno stack migliore in assoluto, ma solo quello più adatto alla domanda, al budget e alla sensibilità del lavoro. Valuta i seguenti criteri:
- Copertura. Quali chain e quale intervallo di date? Include tracce ed eventi decodificati?
- Aggiornamento. Ti servono i dati dell’ultimo blocco o basta quelli di ieri?
- Modello dei costi. Pagamento per i dati scansionati, per il tempo di calcolo o infrastruttura a costo fisso gestita in autonomia.
- Riproducibilità. Puoi fissare uno snapshot o un’altezza di blocco e ottenere la stessa risposta il mese prossimo?
- Riservatezza. Le query sui servizi ospitati vengono registrate dal provider e, su alcune piattaforme community, sono pubbliche per impostazione predefinita. Inserire l’indirizzo di un sospettato in una piattaforma condivisa può rivelare un’indagine. Per attività sensibili, estrai un intervallo di blocchi ed esegui le query localmente.
- Provenienza. È possibile risalire da ogni riga a un hash del blocco e a un hash della transazione verificabili su un nodo?
Scelte adatte a situazioni tipiche:
| Situazione | Stack ragionevole |
|---|---|
| Giornalista che verifica la cronologia di due anni di un wallet | Dataset pubblico in un data warehouse o su una piattaforma ospitata, quindi esportazione delle righe utilizzate |
| Team di exchange che controlla i depositi per rilevare rischi durante tutta la giornata | Pipeline di streaming verso un database colonnare, con tabelle di etichette e prezzi |
| Studio accademico da riprodurre esattamente | Snapshot Parquet fissato, codice versionato, motore incorporato o distribuito |
| Indagine riservata | Nodo proprio o file scaricati, motore incorporato locale, nessuna query ospitata |
Qualunque sia la tua scelta, registra il dataset, la relativa versione o data dello snapshot, il testo della query e l’ora di esecuzione insieme a ogni risultato.
Focus sull'esame: le tre fasi ETL e le operazioni svolte nella fase di trasformazione; il significato di granularità e il motivo per cui un blocco diventa molte righe; la differenza tra tabelle grezze, decodificate e curate e i rischi di ciascuna; perché occorre riconciliare le tabelle curate con i dati grezzi; i principali dataset pubblici (dataset crypto di BigQuery, AWS Public Blockchain Data in Parquet) e i loro limiti; le categorie di motori di query e i casi in cui è indicato un motore incorporato; perché i notebook sono adatti alle indagini; i criteri per scegliere gli strumenti, in particolare la riservatezza delle query ospitate e la riproducibilità.