Données on-chain et SQL · Leçon 1 sur 9
Blocs, en-têtes et API des nœuds
14 min de lecture
Les blocs sont le moyen par lequel une blockchain enregistre le temps et l'ordre ; toute chronologie, tout total journalier et toute affirmation « avant ou après » dans un dossier dépendent donc de leur bonne lecture. La partie la plus récente de toute chaîne est provisoire : les blocs proches de la tête peuvent être remplacés. Derrière chaque explorateur, jeu de données et plateforme d'analyse se trouve un nœud qui répond à des appels d'API. Un enquêteur qui sait ce que contient un en-tête, dans quelle mesure son horodatage est fiable, quand il est possible de s'appuyer sur un bloc et quel appel au nœud a produit un chiffre peut exclure les données provisoires de ses conclusions et vérifier ce qu'affiche un outil tiers.
Ce que contient 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 mesure exactement 80 octets et comporte six champs :
| Champ | Taille | Signification pour l'analyste |
|---|---|---|
| version | 4 octets | Ensemble de règles et bits de signalisation des soft forks |
| hachage du bloc précédent | 32 octets | Lien vers le parent ; la chaîne est construite à partir de ces liens |
| racine de Merkle | 32 octets | Engagement cryptographique couvrant toutes les transactions du bloc |
| temps | 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 s'agit du double SHA-256 des 80 octets de l'en-tête, et les explorateurs l'affichent dans l'ordre inverse des octets, ce qui explique pourquoi il commence par des zéros. La méthode getblock de Bitcoin Core ajoute des valeurs dérivées telles que height, mediantime, chainwork et confirmations.
Un en-tête Ethereum comporte également des engagements cryptographiques sur 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 | Temps Unix en secondes |
miner | Bénéficiaire des frais choisi par le proposant du bloc (ce nom est antérieur à la preuve d'enjeu) |
stateRoot, transactionsRoot, receiptsRoot | Engagements cryptographiques sur l'état, les transactions et les reçus |
logsBloom | Filtre de Bloom permettant aux clients d'ignorer les blocs sans journaux correspondants |
gasLimit, gasUsed, baseFeePerGas | Capacité, utilisation et frais de base détruits par unité de gas (London, août 2021) |
withdrawalsRoot | Retraits des validateurs (Shanghai, avril 2023) |
blobGasUsed, excessBlobGas, parentBeaconBlockRoot | Comptabilisation des blobs et lien avec le consensus (Cancun, mars 2024) |
requestsHash | Requêtes de la couche d'exécution vers la couche de 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 le Merge, difficulty et nonce valent zéro, et mixHash contient la valeur aléatoire de la chaîne beacon. Les données antérieures au Merge contiennent également des blocs ommer (oncles) : des blocs valides qui ont perdu une course, mais qui ont été référencés par un bloc ultérieur au moyen de sha3Uncles et de la liste uncles. Leurs mineurs recevaient une récompense réduite sans aucune transaction ; l'analyse des récompenses de l'époque du minage doit donc les inclure.
Hauteur et hachage
La hauteur (number sur Ethereum) est une position : le nombre de blocs depuis le bloc de genèse. Le hachage du bloc est une identité. Deux blocs peuvent partager une même hauteur lorsque la chaîne bifurque, et un seul finit dans la chaîne principale ; un hachage identifie exactement un bloc, pour toujours. Utilisez la hauteur pour les plages (« blocs 21 000 000 à 21 000 999 ») et le hachage comme clé de stockage. Dans un rapport, citez les deux : « hauteur 880 214, hachage 0000…3f1a ». La méthode getblockhash de Bitcoin renvoie le hachage actuellement associé à une hauteur, lequel peut changer près de la tête.
Horodatages et fiabilité
L'horodatage d'un bloc est l'heure qu'un analyste associe à chacune des transactions qu'il contient.
Les horodatages Bitcoin sont définis par le mineur dans le respect de deux règles : l'heure doit être supérieure à la médiane des 11 blocs précédents (le temps médian passé), et les nœuds rejettent les blocs dont l'heure est en avance de plus de deux heures sur leur propre horloge (les anciennes versions de Bitcoin Core utilisaient une heure « ajustée au réseau » à partir des pairs). Un bloc peut donc porter un horodatage antérieur à celui de son parent, et un horodatage isolé peut présenter un décalage d'une heure ou plus. Utilisez la hauteur pour établir l'ordre ; mediantime ne diminue jamais et sert d'horloge monotone. N'indiquez les heures Bitcoin qu'avec une précision compatible avec les données.
Depuis le Merge (septembre 2022), Ethereum utilise des créneaux fixes de 12 secondes : l'horodatage d'un bloc est égal à l'heure de genèse plus 12 secondes multipliées par son numéro de créneau. Un intervalle de 24 ou 36 secondes entre deux blocs consécutifs signifie qu'un ou deux créneaux n'ont eu aucun bloc. Avant le Merge, les mineurs définissaient les horodatages selon des règles plus souples ; sur les rollups, le séquenceur les définit selon les règles propres à chaque rollup.
Deux précautions s'appliquent partout. L'heure du bloc est celle de l'inclusion d'une transaction, et non celle de sa signature ou de sa diffusion. Les heures de « première observation » affichées par les explorateurs proviennent quant à elles de leurs propres observateurs du mempool : ce sont des indices utiles, mais locaux à un observateur donné.
Réorganisations et finalité
Une réorganisation (reorg) se produit lorsque les nœuds basculent vers une branche concurrente. Les blocs remplacés sont obsolètes ou, dans l'usage courant, orphelins. Sur Bitcoin, les nœuds suivent la branche qui cumule le plus de travail (chainwork) ; les transactions d'un bloc obsolète réapparaissent généralement dans la branche gagnante, éventuellement dans un bloc et à une position différents, ou ne réapparaissent pas du tout si une transaction conflictuelle a été confirmée à leur place. getchaintips répertorie les branches connues, et getblock indique une valeur de confirmations de −1 pour un bloc situé hors de la chaîne principale. Sur Ethereum, la preuve d'enjeu rend les réorganisations plus rares et généralement limitées à un seul bloc de profondeur ; les journaux transmis par les abonnements ou les filtres portent removed: true lorsqu'une réorganisation les retire.
La finalité est le point à partir duquel un bloc peut être considéré comme permanent. La finalité de Bitcoin est probabiliste : chaque confirmation rend le remplacement exponentiellement plus coûteux, six confirmations constituent une convention courante pour les transferts de valeur, et les sorties coinbase ne peuvent pas être dépensées avant 100 blocs. Ethereum dispose d'une finalité économique explicite : les créneaux forment des époques de 32 créneaux (6,4 minutes), et les points de contrôle deviennent justifiés puis finalisés, normalement après environ deux époques (soit environ 13 minutes). Annuler un bloc finalisé nécessiterait la destruction d'au moins un tiers de tous les ETH mis en jeu.
L'API JSON-RPC d'Ethereum expose ces états au moyen de balises de bloc acceptées à la place d'un numéro : earliest, latest, safe, finalized et pending. Ce que renvoie safe dépend du client de consensus (souvent le dernier point de contrôle justifié, bien que certains clients le fassent avancer à quelques secondes de la tête) ; vérifiez donc le comportement de votre nœud au lieu de faire une supposition.
| Usage | 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 ancienne fixe | finalized |
Gestion des données orphelines
Un pipeline robuste stocke le hachage et le hachage parent de chaque bloc, vérifie à chaque nouveau bloc que son hachage parent correspond au hachage stocké à la hauteur immédiatement inférieure et, si ce n'est pas le cas, remonte jusqu'à l'ancêtre commun, ingère la nouvelle branche et déplace les lignes remplacées vers une table d'audit au lieu de les supprimer. Les requêtes ci-dessous utilisent le schéma générique de la leçon 2.7, dans lequel blocks contient la chaîne canonique et transactions porte son block_hash :
-- Nombre quotidien de transactions, jamais au-delà du bloc finalisé
SELECT DATE_TRUNC('day', b.block_timestamp) AS day_utc,
COUNT(*) AS tx_count
FROM transactions t
JOIN blocks b ON b.hash = t.block_hash -- hachage, pas hauteur : exclut les lignes des blocs obsolètes
WHERE b.number <= :finalized_block -- issu de eth_getBlockByNumber("finalized", false)
GROUP BY DATE_TRUNC('day', b.block_timestamp)
ORDER BY day_utc;
-- Blocs dont le parent est absent : lacunes ou réorganisations non gérées
SELECT c.number, c.hash, c.parent_hash
FROM blocks c
LEFT JOIN blocks p ON p.hash = c.parent_hash
WHERE p.hash IS NULL
AND c.number > (SELECT MIN(number) FROM blocks);
La table d'audit est importante dans le traitement des dossiers. Supposons qu'une plateforme d'échange ait crédité un dépôt après une confirmation, que le bloc soit devenu obsolète et qu'une transaction conflictuelle dépensant les mêmes fonds ait été confirmée à sa place. La page mise en cache d'un explorateur peut encore afficher la première transaction ; seules les données conservées du bloc obsolète expliquent pourquoi un dépôt « confirmé » n'a jamais existé sur la chaîne définitive.
Lecture de la chaîne au moyen des API des nœuds
Bitcoin Core expose une API JSON-RPC (une requête HTTP POST avec un method et un tableau params, authentifiée par un fichier cookie ou un utilisateur configuré), également accessible via bitcoin-cli. Les montants sont renvoyés en BTC sous forme de nombres JSON. Les clients d'exécution Ethereum (Geth, Nethermind, Besu, Erigon, Reth) implémentent une spécification JSON-RPC commune, et la plupart des chaînes EVM, des rollups et des chaînes latérales proposent la même interface. Les quantités sont des chaînes hexadécimales ("0x1b4") ; les espaces de noms tels que debug_ et trace_ sont propres à chaque client.
Méthodes de Bitcoin Core
| Méthode | Valeur renvoyée | Remarques |
|---|---|---|
getblockchaininfo | Chaîne, hauteur, meilleur hachage, état d'élagage | Premier appel de toute session |
getblockhash height / getblockheader hash | Hachage à une hauteur / en-tête et confirmations | Le hachage peut changer près de la tête |
getblock hash verbosity | 0 : hexadécimal ; 1 : en-tête et txid ; 2 : transactions décodées avec frais ; 3 : ajoute prevout pour chaque entrée | Les frais et les prevout nécessitent des données d'annulation |
getrawtransaction txid verbosity | 0 : hexadécimal ; 1 : décodée ; 2 : ajoute les frais et les prevout | Les transactions confirmées nécessitent txindex=1 ou un hachage de bloc |
gettxout txid n | Détails de la sortie si elle est actuellement non dépensée | Null si elle est dépensée ou inconnue |
gettxspendingprevout | Transaction dépensant les sorties indiquées | Mempool uniquement, sauf si txospenderindex est activé (31.0 et versions ultérieures) |
getchaintips | Branches connues et leur état | Investigation des réorganisations |
Séquence typique pour examiner un paiement :
getblockhash 880214 -> "0000…3f1a"
getblock "0000…3f1a" 1 -> champs de l'en-tête et liste des txid
getrawtransaction "4f3a…c21e" 2 -> transaction décodée avec valeurs prevout et frais
gettxout "4f3a…c21e" 1 -> sortie 1 si elle est encore non dépensée, sinon null
gettxout vous indique si une sortie est non dépensée maintenant, et non quand ni par quelle transaction elle a été dépensée. Bitcoin Core ne dispose d'aucune méthode répertoriant l'historique d'une adresse ; cela nécessite un indexeur d'adresses ou un entrepôt de données.
Méthodes Ethereum
| Méthode | Valeur renvoyée |
|---|---|
eth_chainId | Identifiant de chaîne (EIP-695) : confirme sur quel réseau vous vous trouvez |
eth_blockNumber, eth_getBlockByNumber, eth_getBlockByHash | Dernière hauteur ; en-tête avec les hachages des transactions, ou transactions complètes lorsque le deuxième paramètre vaut true |
eth_getTransactionByHash, eth_getTransactionReceipt | Transaction signée avec from récupéré ; statut, gas et journaux |
eth_getBlockReceipts | Tous les reçus d'un bloc en un seul appel |
eth_getLogs | Journaux correspondant à un filtre |
eth_getBalance, eth_getCode, eth_getStorageAt, eth_call | État à un bloc donné |
Deux comportements surprennent les débutants. Un reçu valant null signifie que la transaction est en attente ou inconnue du nœud, et non qu'elle a échoué. De plus, les méthodes d'état répondent pour le bloc que vous leur transmettez : eth_getBalance à latest change toutes les quelques secondes ; transmettez donc un numéro de bloc explicite pour tout chiffre que vous présentez dans un rapport.
eth_getLogs accepte fromBlock et toBlock (ou un seul blockHash), un paramètre address facultatif et un tableau positionnel topics. Cette requête demande à un contrat de jeton les événements Transfer à destination d'une adresse sur les blocs 21 000 000 (0x1406f40) à 21 000 999 (0x1407327) :
{"jsonrpc": "2.0", "id": 1, "method": "eth_getLogs",
"params": [{
"fromBlock": "0x1406f40", "toBlock": "0x1407327",
"address": "0x5d3a…7c10",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
null,
"0x000000000000000000000000c3d4…22e1"]
}]}
La correspondance des topics dépend de leur position : le premier est la signature de Transfer, null accepte n'importe quel expéditeur et topics[2] fixe le destinataire. Une position peut également contenir un tableau signifiant « n'importe laquelle de ces valeurs » ; déplacer l'adresse complétée par des zéros en deuxième position renvoie les transferts envoyés par cette adresse.
Méthodes de débogage et de traçage
Les appels internes nécessitent une réexécution. Les clients de type Geth proposent debug_traceTransaction, debug_traceBlockByNumber et debug_traceCall avec un tracer tel que callTracer (arbre d'appels) ou prestateTracer (état touché). Les clients de type Parity (Erigon, Nethermind, Reth) proposent trace_transaction, trace_block, trace_filter et trace_replayTransaction, qui renvoient des listes d'appels à plat. Les deux approches sont coûteuses, souvent désactivées ou facturées en supplément par les fournisseurs, et leurs formats diffèrent (par exemple, quant à la présence des appels aux contrats précompilés) ; normalisez-les donc avant de mélanger les résultats.
Quel nœud pour quelle question
| Question | Bitcoin | Ethereum |
|---|---|---|
| Blocs, transactions, reçus, journaux | Nœud complet (txindex=1 pour une recherche par txid) | Nœud complet ; l'historique antérieur au Merge peut avoir expiré |
| Solde actuel ou état des UTXO | gettxout, ou un indexeur pour les adresses | Nœud complet, eth_getBalance |
| Solde à un bloc passé | Indexeur ou entrepôt de données | Nœud d'archive |
| Historique d'une adresse | Indexeur d'adresses ou entrepôt de données | Indexeur ou entrepôt de données (aucune méthode native) |
| Appels internes d'anciennes transactions | Sans objet | Nœud d'archive avec traçage |
Les nœuds élagués ne peuvent pas du tout fournir les anciens blocs. Un nœud complet Ethereum auquel on demande un état plus ancien que sa fenêtre de conservation renvoie une erreur plutôt qu'un chiffre erroné : c'est le signe qu'un nœud d'archive est nécessaire.
Fournisseurs, limites de débit et confiance
Les fournisseurs de services hébergés imposent des limites de débit (requêtes par seconde ou « unités de calcul » pondérées) et limitent eth_getLogs selon la plage de blocs, le nombre de résultats, ou les deux. Une extraction robuste divise une plage en segments, réduit de moitié un segment refusé par le fournisseur, réessaie avec un délai exponentiel entre les tentatives et consigne les plages terminées. Les requêtes JSON-RPC par lots réduisent les surcoûts, mais sont comptabilisées dans les mêmes limites. Les fournisseurs soulèvent également des questions de confiance :
- Têtes incohérentes. Derrière un répartiteur de charge, des appels consécutifs peuvent atteindre des nœuds à des hauteurs différentes. Fixez le travail sur un hachage de bloc, et non sur
latest. - Erreurs et retard. Pour les faits dont dépend une conclusion, comparez le hachage du bloc à votre hauteur de référence entre deux sources indépendantes ou avec votre propre nœud, et consignez la version du client (
web3_clientVersion, ou le champsubversiondegetnetworkinfo). - Confidentialité des requêtes. Un fournisseur voit chaque adresse sur laquelle vous l'interrogez ; ses journaux peuvent révéler le sujet d'une enquête. Votre propre nœud ne présente pas ce risque.
Pour un historique volumineux, l'extraction RPC est lente. Les jeux de données publics (les jeux de données crypto de Google BigQuery, construits avec les outils open source blockchain-etl ; le jeu de données AWS Public Blockchain Data au format Parquet) et les frameworks ETL (Ethereum ETL, Bitcoin ETL, cryo, TrueBlocks, The Graph) sont les solutions de remplacement ; la leçon 2.7 les compare.
Points clés pour l'examen : attendez-vous à des questions vous demandant de choisir la bonne source de données ou la bonne limite pour étayer une conclusion : les six champs de l'en-tête Bitcoin et le fait que le hachage du bloc est calculé ; la hauteur comme position et le hachage comme identité ; le temps médian passé, la règle des deux heures et les horodatages Bitcoin non ordonnés, par opposition aux créneaux Ethereum exacts de 12 secondes ; les réorganisations, les journauxremoved: trueet les données d'audit des blocs obsolètes ; les confirmations, les époques et les baliseslatest,safeetfinalized; les niveaux de verbosité degetblocketgetrawtransaction, ainsi quetxindex; les limites degettxout; la correspondance positionnelle des topics danseth_getLogs; les méthodesdebug_par rapport aux méthodestrace_; les cas nécessitant un nœud d'archive ; la vérification des fournisseurs.