Lire les données brutes d’une blockchain · Leçon 2 sur 6
Les blocs et leurs en-têtes en tant que données
10 min de lecture
Les blocs sont l’unité dans laquelle une blockchain enregistre le temps et l’ordre. Ainsi, chaque chronologie, total quotidien et affirmation du type « avant ou après » formulés par un analyste dépendent d’une lecture correcte des blocs. Les blocs peuvent également être remplacés : la partie la plus récente de toute chaîne est provisoire. Savoir ce que contient un en-tête, dans quelle mesure son horodatage est fiable et à partir de quand on peut se fier à un bloc permet d’éviter que des données provisoires ne se retrouvent dans vos conclusions.
Contenu d’un en-tête
Un en-tête de bloc est un petit enregistrement qui résume le bloc et le relie à son parent. Un en-tête Bitcoin fait exactement 80 octets et comporte six champs :
| Champ | Taille | Signification pour l’analyste |
|---|---|---|
| version | 4 octets | Ensemble de règles et bits de signalement des soft forks |
| hachage du bloc précédent | 32 octets | Lien vers le parent ; la chaîne est constituée de ces liens |
| racine de Merkle | 32 octets | Engagement envers chaque transaction du bloc |
| heure | 4 octets | Horodatage Unix choisi par le mineur |
| bits | 4 octets | Encodage compact de la cible de difficulté |
| nonce | 4 octets | Valeur que les mineurs font varier pour trouver un hachage valide |
Le hachage du bloc n’est pas un champ de l’en-tête : il correspond au double SHA-256 des 80 octets de l’en-tête. Les explorateurs l’affichent dans l’ordre inverse des octets, raison pour laquelle il commence par des zéros. La commande getblock de Bitcoin Core ajoute des valeurs dérivées telles que height, mediantime, chainwork et confirmations.
Un en-tête Ethereum comporte davantage de champs, car il contient également des engagements envers l’état et les reçus. Les champs les plus utilisés par les analystes sont les suivants :
| Champ | Signification |
|---|---|
number, parentHash | Hauteur et lien vers le parent |
timestamp | Heure Unix en secondes |
miner | Destinataire des frais choisi par le proposant du bloc (le nom est antérieur à la preuve d’enjeu) |
stateRoot, transactionsRoot, receiptsRoot | Engagements envers l’état, les transactions et les reçus |
logsBloom | Filtre de Bloom qui permet aux clients d’ignorer les blocs sans journal correspondant |
gasLimit, gasUsed | Capacité et utilisation |
baseFeePerGas | Frais de base brûlés par unité de gaz (London, août 2021) |
withdrawalsRoot | Retraits des validateurs (Shanghai, avril 2023) |
blobGasUsed, excessBlobGas, parentBeaconBlockRoot | Comptabilisation des blobs et lien de consensus (Cancun, mars 2024) |
requestsHash | Requêtes d’exécution vers le consensus, EIP-7685 (Prague, mai 2025) |
Les champs n’apparaissent qu’à partir de la mise à niveau qui les a introduits. Un pipeline doit donc accepter leur absence dans les blocs plus anciens. Depuis la Fusion, difficulty et nonce valent zéro et mixHash contient la valeur aléatoire de la chaîne Beacon. Les données antérieures à la Fusion présentent une autre particularité : les blocs ommer (oncles), des blocs valides qui ont perdu la course, mais auxquels un bloc ultérieur a fait référence via sha3Uncles et la liste uncles. Leurs mineurs recevaient une récompense réduite sans aucune transaction ; l’analyse des récompenses de l’ère du minage doit donc les inclure. Depuis la Fusion, cette liste est toujours vide.
Hauteur et hachage
La hauteur (number dans Ethereum) est une position : le nombre de blocs depuis le bloc de genèse. Le hachage du bloc est une identité. Deux blocs différents peuvent partager une hauteur lorsque la chaîne bifurque, mais un seul d’entre eux finit par intégrer la chaîne principale. En revanche, un hachage identifie exactement un bloc, pour toujours.
Utilisez la hauteur par commodité et pour définir des plages (« blocs 21 000 000 à 21 000 999 »), et le hachage pour identifier un bloc. Dans le stockage, conservez les deux et utilisez le hachage comme clé. Dans un rapport, indiquez les deux lorsqu’un bloc est cité : « hauteur 880 214, hachage 0000…3f1a ». La commande RPC Bitcoin getblockhash renvoie le hachage qui correspond actuellement à une hauteur ; celui-ci peut changer près de la pointe de la chaîne. Ethereum propose eth_getBlockByNumber et eth_getBlockByHash.
Horodatages et fiabilité
L’horodatage d’un bloc est l’heure que l’analyste attribue à toutes les transactions qu’il contient. Sa précision dépend de la chaîne.
Bitcoin : les horodatages sont définis par le mineur selon deux règles : l’heure doit être postérieure à la médiane des 11 blocs précédents (la médiane des temps passés) et les nœuds rejettent les blocs dont l’horodatage dépasse leur propre horloge de plus de deux heures (les anciennes versions de Bitcoin Core utilisaient plutôt une heure « ajustée au réseau » à partir des pairs). Un bloc peut donc avoir un horodatage antérieur à celui de son parent, et un horodatage donné peut être décalé d’une heure ou plus. Pour l’ordre, utilisez la hauteur ; pour une horloge monotone, mediantime de Bitcoin Core ne diminue jamais. Dans les rapports, indiquez les heures Bitcoin avec un niveau de précision que les données permettent.
Ethereum, depuis la Fusion (septembre 2022), utilise des créneaux fixes de 12 secondes, et l’horodatage d’un bloc est égal à l’heure de genèse plus 12 secondes multipliées par le numéro de son créneau. Les horodatages sont exacts et réguliers ; un écart de 24 ou 36 secondes entre des blocs consécutifs signifie qu’un ou deux créneaux n’ont pas produit de bloc. Avant la Fusion, les mineurs définissaient les horodatages selon des règles moins strictes. Sur les rollups, le séquenceur définit les horodatages selon les règles propres à chaque rollup.
Deux mises en garde s’appliquent partout. L’heure du bloc correspond au moment où une transaction a été incluse, et non au moment où elle a été signée ou diffusée. De plus, les heures « vues pour la première fois » affichées par les explorateurs proviennent des observateurs de leur propre mempool : ce sont des indices utiles, mais qui ne concernent qu’un seul observateur.
Réorganisations
Une réorganisation (reorg) se produit lorsque les nœuds abandonnent la chaîne qu’ils suivaient au profit d’une branche concurrente. Les blocs remplacés sont appelés stales ou, dans l’usage courant, orphelins.
Sur Bitcoin, il arrive que deux mineurs trouvent des blocs presque à la même hauteur et au même moment. Les nœuds suivent la branche dont le travail cumulé (chainwork) est le plus important. Lorsque le bloc suivant prolonge l’un des deux côtés, le bloc de l’autre côté devient stale. Ses transactions réapparaissent généralement dans la branche gagnante, mais éventuellement dans un bloc et à une position différents, voire pas du tout si une transaction concurrente a été confirmée à la place. Bitcoin Core répertorie les branches connues avec getchaintips, et getblock indique une valeur confirmations de −1 pour un bloc qui ne fait pas partie de la chaîne principale.
Sur Ethereum, la preuve d’enjeu rend les réorganisations plus rares et généralement limitées à une profondeur d’un bloc. Les journaux fournis par les abonnements ou les filtres contiennent removed: true lorsqu’une réorganisation les supprime ; les pipelines doivent prendre ce signal en charge.
Finalité pour l’analyse
La finalité est le moment à partir duquel un bloc peut être considéré comme permanent.
- Bitcoin : la finalité est probabiliste. Chaque bloc supplémentaire (une confirmation) rend le remplacement exponentiellement plus coûteux. Six confirmations constituent une convention courante pour les transferts de valeur, et les pièces nouvellement minées (sorties coinbase) ne peuvent pas être dépensées avant 100 blocs.
- Ethereum : la finalité économique est explicite. Les créneaux sont regroupés en époques de 32 créneaux (6,4 minutes) ; les validateurs votent sur des points de contrôle d’époque, qui deviennent justifiés puis finalisés, normalement après environ deux époques, soit approximativement 13 minutes. Pour révoquer un bloc finalisé, il faudrait détruire au moins un tiers de tous les ETH mis en jeu.
JSON-RPC Ethereum expose cette fonctionnalité au moyen de balises de bloc, acceptées à la place d’un numéro de bloc : earliest (genèse), latest (le bloc le plus récent suivi par le nœud), safe, finalized et pending. La signification de safe dépend du client de consensus : beaucoup renvoient le dernier point de contrôle justifié, quelques minutes derrière latest, et certains clients adoptent une règle de confirmation rapide qui le rapproche de la tête en quelques secondes. Vérifiez ce que renvoie votre nœud au lieu de faire des suppositions.
| Utilisation | Bitcoin | Ethereum |
|---|---|---|
| Alertes en temps réel | 0–1 confirmations, avec gestion des réorganisations | latest, avec gestion des réorganisations |
| Décisions opérationnelles | Profondeur définie par la politique, souvent 3–6 | safe ou finalized |
| Rapports et statistiques | Bien au-delà de 6, ou une limite fixe correspondant à une ancienne date | finalized |
La requête ci-dessous compte les transactions quotidiennes uniquement jusqu’à une limite récupérée auprès du nœud avec eth_getBlockByNumber("finalized", false) :
-- Nombre de transactions quotidiennes, sans jamais dépasser le bloc finalisé
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;
La jointure sur block_hash plutôt que sur la hauteur exclut du décompte les transactions des blocs stales. DATE_TRUNC existe dans PostgreSQL et plusieurs entrepôts de données ; d’autres moteurs utilisent TIMESTAMP_TRUNC ou une conversion en date.
Gestion des données orphelines
Tout pipeline qui ingère des blocs récents sera confronté à des réorganisations. Une conception robuste fait quatre choses : elle stocke block_hash et parent_hash pour chaque bloc ; à chaque nouveau bloc, elle vérifie que son hachage parent correspond au hachage stocké à la hauteur immédiatement inférieure ; en cas de divergence, elle remonte jusqu’à l’ancêtre commun, marque les lignes des blocs remplacés comme non canoniques et ingère la nouvelle branche ; enfin, elle conserve les lignes remplacées dans une table d’audit au lieu de les supprimer. La requête ci-dessous repère les ruptures dans la chaîne stockée :
-- Blocs dont le parent est absent : lacunes ou réorganisations non prises en charge
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 table d’audit est importante dans le cadre d’une enquête. Supposons qu’un dépôt ait été crédité après une confirmation, que le bloc soit devenu stale et qu’une transaction concurrente dépensant les mêmes pièces ait été confirmée à la place. La page mise en cache d’un explorateur peut encore afficher la première transaction. Seules les données conservées sur les blocs stales permettent à un analyste d’expliquer pourquoi un dépôt « confirmé » n’a jamais existé sur la chaîne finale.
Points clés pour l’examen : les six champs de l’en-tête Bitcoin et le fait que le hachage du bloc est calculé, et non stocké ; les principaux champs des en-têtes Ethereum et les mises à niveau qui les ont ajoutés ; la hauteur comme position, par opposition au hachage comme identité ; les règles d’horodatage de Bitcoin (médiane des temps passés, limite de deux heures) et les raisons pour lesquelles les horodatages peuvent être dans le désordre ; les créneaux de 12 secondes et les horodatages exacts d’Ethereum ; les réorganisations, les blocs stales et les journauxremoved: true; la profondeur de confirmation, les époques, les points de contrôle justifiés et finalisés, ainsi que les balises JSON-RPClatest,safeetfinalized; la détection et l’enregistrement des données orphelines.