Leggere i dati grezzi della blockchain · Lezione 2 di 6
Blocchi e header come dati
9 min di lettura
I blocchi sono l’unità con cui una blockchain registra il tempo e l’ordine, quindi ogni linea temporale, totale giornaliero e affermazione del tipo «prima o dopo» formulata da un analista dipende dalla loro corretta lettura. I blocchi possono anche essere sostituiti: la parte più recente di qualsiasi catena è provvisoria. Sapere cosa contiene un header, quanto ci si può fidare del suo timestamp e quando è sicuro fare affidamento su un blocco evita che dati provvisori finiscano nelle conclusioni.
Cosa contiene un header
Un header di blocco è un piccolo record che riassume il blocco e lo collega al suo genitore. Un header Bitcoin è composto esattamente da 80 byte e contiene sei campi:
| Campo | Dimensione | Significato per l’analista |
|---|---|---|
| version | 4 byte | Insieme di regole e bit di segnalazione delle soft fork |
| previous block hash | 32 byte | Collegamento al genitore; la catena è costruita a partire da questi collegamenti |
| merkle root | 32 byte | Impegno crittografico relativo a ogni transazione nel blocco |
| time | 4 byte | Timestamp Unix scelto dal miner |
| bits | 4 byte | Codifica compatta del target di difficoltà |
| nonce | 4 byte | Valore che i miner variano per trovare un hash valido |
L’hash del blocco non è un campo dell’header: è il doppio SHA-256 degli 80 byte dell’header, e gli explorer lo mostrano con i byte in ordine inverso, motivo per cui inizia con degli zeri. getblock di Bitcoin Core aggiunge valori derivati come height, mediantime, chainwork e confirmations.
Un header Ethereum contiene più campi perché include anche impegni crittografici relativi allo stato e alle ricevute. Quelli più utilizzati dagli analisti sono:
| Campo | Significato |
|---|---|
number, parentHash | Altezza e collegamento al genitore |
timestamp | Ora Unix in secondi |
miner | Destinatario delle commissioni scelto dal proponente del blocco (il nome risale a prima del proof of stake) |
stateRoot, transactionsRoot, receiptsRoot | Impegni crittografici relativi a stato, transazioni e ricevute |
logsBloom | Filtro Bloom che consente ai client di ignorare i blocchi senza log corrispondenti |
gasLimit, gasUsed | Capacità e utilizzo |
baseFeePerGas | Commissione base bruciata per unità di gas (London, agosto 2021) |
withdrawalsRoot | Prelievi dei validatori (Shanghai, aprile 2023) |
blobGasUsed, excessBlobGas, parentBeaconBlockRoot | Contabilizzazione dei blob e collegamento al consenso (Cancun, marzo 2024) |
requestsHash | Richieste dall’esecuzione al consenso, EIP-7685 (Prague, maggio 2025) |
I campi sono presenti solo a partire dall’aggiornamento che li ha introdotti, quindi una pipeline deve accettare che siano assenti nei blocchi più vecchi. Dal Merge, difficulty e nonce sono zero e mixHash contiene il valore di casualità della beacon chain. I dati precedenti al Merge hanno un’altra caratteristica: i blocchi ommer (uncle), blocchi validi che hanno perso la competizione ma sono stati citati da un blocco successivo tramite sha3Uncles e l’elenco uncles. I relativi miner hanno ricevuto una ricompensa ridotta senza alcuna transazione, quindi le analisi delle ricompense nell’era del mining devono includerli; dal Merge, l’elenco è sempre vuoto.
Altezza e hash
L’altezza (number in Ethereum) è una posizione: il conteggio dei blocchi a partire dal blocco genesi. L’hash del blocco è un’identità. Due blocchi diversi possono condividere la stessa altezza quando la catena si biforca, ma solo uno di loro finisce nella catena principale. Un hash, invece, identifica un solo blocco per sempre.
Usa l’altezza per comodità e per gli intervalli («blocchi da 21.000.000 a 21.000.999») e l’hash per identificare il blocco. Nell’archiviazione, conserva entrambi e usa l’hash come chiave. Quando citi un blocco in un rapporto, indica entrambi: «altezza 880.214, hash 0000…3f1a». L’RPC Bitcoin getblockhash restituisce l’hash che si trova attualmente a una certa altezza, che può cambiare in prossimità della punta della catena; Ethereum offre sia eth_getBlockByNumber sia eth_getBlockByHash.
Timestamp e loro affidabilità
Il timestamp di un blocco è l’ora che un analista attribuisce a ogni transazione contenuta nel blocco. La sua precisione dipende dalla catena.
Bitcoin: i timestamp sono impostati dal miner secondo due regole: l’ora deve essere successiva alla mediana dei 11 blocchi precedenti (il median time past) e i nodi rifiutano i blocchi che superano di oltre due ore il proprio orologio (le versioni precedenti di Bitcoin Core usavano invece un’ora «network-adjusted» ricavata dai peer). Di conseguenza, un blocco può avere un timestamp precedente a quello del suo genitore e ogni singolo timestamp può essere impreciso di un’ora o più. Per l’ordine, usa l’altezza; per un orologio monotono, mediantime di Bitcoin Core non diminuisce mai. Nei rapporti, indica gli orari Bitcoin con una precisione supportata dai dati.
Ethereum: dal Merge (settembre 2022) ha slot fissi di 12 secondi e il timestamp di un blocco corrisponde all’ora di genesi più 12 secondi moltiplicati per il numero dello slot. I timestamp sono esatti e regolari; un intervallo di 24 o 36 secondi tra blocchi consecutivi significa che uno o due slot non hanno avuto un blocco. Prima del Merge, i miner impostavano i timestamp secondo regole meno rigide. Sui rollup, il sequencer imposta i timestamp secondo le regole specifiche di ciascun rollup.
Ovunque valgono due avvertenze. L’ora del blocco indica quando una transazione è stata inclusa, non quando è stata firmata o trasmessa. Inoltre, gli orari di «prima rilevazione» mostrati dagli explorer provengono dai rispettivi osservatori del mempool: sono indizi utili, ma specifici di un singolo osservatore.
Riorganizzazioni
Una riorganizzazione (reorg) si verifica quando i nodi passano dalla catena che stavano seguendo a un ramo concorrente. I blocchi sostituiti sono detti obsoleti o, nell’uso comune, orfani.
Su Bitcoin, talvolta due miner trovano blocchi quasi contemporaneamente alla stessa altezza. I nodi seguono il ramo con il maggior lavoro cumulativo (chainwork) e, quando il blocco successivo estende un lato, il blocco dell’altro lato diventa obsoleto. Le sue transazioni di solito ricompaiono nel ramo vincente, ma forse in un blocco e in una posizione diversi, oppure non ricompaiono affatto se viene confermata una transazione in conflitto. Bitcoin Core elenca i rami noti con getchaintips, e getblock indica confirmations pari a −1 per un blocco che non si trova nella catena principale.
Su Ethereum, il proof of stake rende le riorganizzazioni più rare e di solito limitate a un solo blocco. I log forniti tramite sottoscrizioni o filtri riportano removed: true quando una riorganizzazione li rimuove: è un segnale che le pipeline devono gestire.
Finalità per l’analisi
La finalità è il punto in cui un blocco può essere considerato permanente.
- Bitcoin: la finalità è probabilistica. Ogni blocco aggiuntivo (una conferma) rende la sostituzione esponenzialmente più costosa. Sei conferme sono una convenzione comune per i trasferimenti di valore, e le monete appena minate (output coinbase) non possono essere spese per 100 blocchi.
- Ethereum: ha una finalità economica esplicita. Gli slot sono raggruppati in epoche di 32 slot (6,4 minuti); i validatori votano i checkpoint delle epoche, che diventano giustificati e poi finalizzati, normalmente dopo circa due epoche, ovvero circa 13 minuti. Per annullare un blocco finalizzato sarebbe necessario distruggere almeno un terzo di tutti gli ETH in staking.
JSON-RPC di Ethereum espone questa funzionalità tramite tag dei blocchi utilizzabili al posto di un numero di blocco: earliest (genesi), latest (il blocco più recente seguito dal nodo), safe, finalized e pending. Il significato di safe dipende dal client di consenso: molti restituiscono l’ultimo checkpoint giustificato, alcuni minuti indietro rispetto a latest, mentre alcuni client stanno adottando una regola di conferma rapida che lo porta a pochi secondi dalla testa della catena. Verifica cosa restituisce il tuo nodo invece di darlo per scontato.
| Uso | Bitcoin | Ethereum |
|---|---|---|
| Avvisi in tempo reale | 0–1 conferme, con gestione delle riorganizzazioni | latest, con gestione delle riorganizzazioni |
| Decisioni operative | Profondità prevista dalle policy, spesso 3–6 | safe o finalized |
| Rapporti e statistiche | Ben oltre 6, oppure una data limite fissa nel passato | finalized |
La query qui sotto conta le transazioni giornaliere solo fino a una data limite recuperata dal nodo con eth_getBlockByNumber("finalized", false):
-- Conteggio giornaliero delle transazioni, mai oltre il blocco finalizzato
SELECT DATE_TRUNC('day', b.block_time) AS day_utc,
COUNT(*) AS tx_count
FROM transactions t
JOIN blocks b ON b.block_hash = t.block_hash
WHERE b.block_number <= :finalized_block
GROUP BY DATE_TRUNC('day', b.block_time)
ORDER BY day_utc;
Unire le tabelle usando block_hash invece dell’altezza esclude dal conteggio le transazioni dei blocchi obsoleti. DATE_TRUNC è disponibile in PostgreSQL e in diversi data warehouse; altri motori usano TIMESTAMP_TRUNC o una conversione del tipo in data.
Gestione dei dati orfani
Qualsiasi pipeline che acquisisce blocchi recenti si imbatterà in riorganizzazioni. Una progettazione robusta fa quattro cose: archivia block_hash e parent_hash per ogni blocco; a ogni nuovo blocco, verifica che il suo hash genitore corrisponda all’hash archiviato all’altezza inferiore di uno; se non corrisponde, risale fino all’antenato comune, contrassegna le righe dei blocchi sostituiti come non canoniche e acquisisce il nuovo ramo; infine, conserva le righe sostituite in una tabella di audit invece di eliminarle. La query qui sotto individua le interruzioni nella catena archiviata:
-- Blocchi senza il blocco genitore: lacune o riorganizzazioni non gestite
SELECT c.block_number, c.block_hash, c.parent_hash
FROM blocks c
LEFT JOIN blocks p ON p.block_hash = c.parent_hash
WHERE p.block_hash IS NULL
AND c.block_number > (SELECT MIN(block_number) FROM blocks);
La tabella di audit è importante per le indagini. Supponiamo che un deposito sia stato accreditato dopo una conferma, che il blocco sia diventato obsoleto e che sia stata invece confermata una transazione in conflitto che spende le stesse monete. La pagina memorizzata nella cache di un explorer potrebbe mostrare ancora la prima transazione. Solo i dati archiviati dei blocchi obsoleti consentono all’analista di spiegare perché un deposito «confermato» non sia mai esistito sulla catena finale.
Focus sull'esame: i sei campi dell’header Bitcoin e il fatto che l’hash del blocco viene calcolato, non archiviato; i principali campi dell’header Ethereum e gli aggiornamenti che li hanno introdotti; l’altezza come posizione e l’hash come identità; le regole dei timestamp Bitcoin (median time past, limite di due ore) e i motivi per cui i timestamp possono essere fuori ordine; gli slot Ethereum di 12 secondi e i timestamp esatti; le riorganizzazioni, i blocchi obsoleti e i logremoved: true; la profondità delle conferme, le epoche, i checkpoint giustificati e finalizzati e i tag JSON-RPClatest,safeefinalized; il rilevamento e la registrazione dei dati orfani.