Interroger les blockchains avec SQL · Leçon 1 sur 6
La pile de données analytiques
11 min de lecture
Presque tous les chiffres d’un rapport on-chain sont passés par un pipeline entre le nœud qui a observé le bloc et la requête qui a produit le résultat. Un analyste qui sait à quelle couche appartient une table, qui l’a créée, à quel point elle est à jour et quelles règles l’ont façonnée peut distinguer une véritable découverte d’un artefact du pipeline. Cette leçon présente cette pile et les choix à faire pour sélectionner les outils qui la composent.
Du nœud à la table
Un nœud stocke et fournit les données de la blockchain sous la forme dont le protocole a besoin : blocs, transactions, reçus et état, accessibles par des appels RPC (voir la leçon API des nœuds et accès aux données). Les analystes ont besoin des mêmes données sous forme de lignes et de colonnes pouvant être filtrées, jointes et additionnées. Le processus qui transforme l’une en l’autre est un pipeline ETL : extraction, transformation et chargement.
- Extraction. Le pipeline interroge le nœud pour chaque bloc d’une plage : le bloc avec ses transactions, les reçus avec leurs journaux et, lorsque le nœud le permet, les traces d’appels.
- Transformation. Le JSON imbriqué est aplati pour obtenir une ligne par enregistrement. Les chaînes hexadécimales sont converties en nombres, l’horodatage du bloc est copié dans chaque transaction et chaque journal afin que les requêtes n’aient pas besoin d’effectuer une jointure pour accéder à l’heure, et les identifiants sont normalisés (par exemple, les adresses sont converties en minuscules).
- Chargement. Les lignes sont écrites dans un espace de stockage, généralement sous forme de fichiers en colonnes tels qu’Apache Parquet, partitionnés par date ou plage de blocs, ou dans des tables de base de données. Les formats de tables ouverts tels qu’Apache Iceberg et Delta Lake ajoutent des instantanés versionnés par-dessus les fichiers.
Le concept clé est le grain : ce que représente une ligne. Un bloc Ethereum avec 150 transactions et 400 journaux d’événements donne une ligne dans blocks, 150 lignes dans transactions et 400 lignes dans logs. La plupart des erreurs de requête viennent du fait d’oublier le grain d’une table et de compter ou d’additionner au mauvais niveau.
Les pipelines fonctionnent selon deux modes. Un chargement historique traite l’historique par grands lots, une fois. Le flux en continu ou les chargements incrémentiels suivent la tête de la chaîne bloc par bloc. Près de la tête, les blocs peuvent encore être remplacés à la suite d’une réorganisation ; un pipeline attend donc un certain nombre de confirmations ou un bloc finalisé, ou réécrit les blocs récents lorsque la chaîne change (voir la leçon Les blocs et les en-têtes comme données).
Il existe des extracteurs open source pour la plupart de ces tâches : Ethereum ETL et Bitcoin ETL du projet blockchain-etl, ainsi que cryo, qui écrit directement les données EVM dans des fichiers Parquet. Il est utile de les connaître, même si vous ne les exécutez jamais, car de nombreux jeux de données publics ont été créés avec ces outils et reprennent les noms de leurs colonnes.
Tables brutes, décodées et organisées
Les tables d’un entrepôt de données blockchain se répartissent en trois couches, qui reflètent les couches de données présentées dans la leçon Le point de vue de l’analyste sur une blockchain.
| Couche | Contenu | Tables types | Risque principal |
|---|---|---|---|
| Brute | Enregistrements tels que renvoyés par le nœud, typés mais sans interprétation | blocs, transactions, journaux, traces ; entrées et sorties pour les chaînes UTXO | Champs hexadécimaux, unités de base (wei, satoshi), difficiles à lire |
| Décodée | Enregistrements bruts interprétés à l’aide d’un ABI ou d’un analyseur de scripts | Une table par événement ou fonction de contrat, calldata décodé | ABI manquant ou erroné, proxies, contrats non vérifiés |
| Organisée | Tables métier créées à partir de plusieurs sources | token_transfers, dex_trades, balances, labels, prices | Règles d’inclusion cachées, erreurs d’étiquetage, prix périmés |
Chaque niveau supplémentaire raccourcit les requêtes, mais ajoute des décisions prises par quelqu’un d’autre. Une table organisée token_transfers permet de répondre à des questions en une ligne, mais vous devez en connaître les règles. Inclut-elle les transferts ERC-721 ou seulement les jetons fongibles ? Les émissions et destructions sont-elles représentées par des lignes avec l’adresse zéro, ou sont-elles exclues ? Le montant correspond-il à l’entier brut ou est-il déjà divisé par le nombre de décimales ? Deux jeux de données qui nomment tous deux une table token_transfers peuvent diverger sur tous ces points.
La bonne habitude consiste à effectuer un rapprochement : vérifiez une table organisée par rapport à la couche brute dont elle provient, sur une petite plage de blocs.
-- La table organisée token_transfers correspond-elle aux journaux bruts dont elle provient ?
SELECT 'raw logs' AS layer, COUNT(*) AS n
FROM logs
WHERE topic0 = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
AND topic3 IS NULL -- transferts fongibles uniquement (de type ERC-20)
AND block_number BETWEEN 21000000 AND 21000099
UNION ALL
SELECT 'token_transfers', COUNT(*)
FROM token_transfers
WHERE block_number BETWEEN 21000000 AND 21000099;
La première partie compte les événements bruts Transfer (la longue chaîne hexadécimale est le hachage de signature de l’événement, expliqué dans la leçon Interroger les journaux et les traces EVM) ; la seconde compte les lignes organisées pour les mêmes 100 blocs. Si les nombres diffèrent, cherchez-en la raison avant d’utiliser la table : la couche organisée peut exclure certains jetons, inclure des NFT ou omettre des blocs.
Jeux de données publics sur les blockchains
Vous n’avez pas besoin de votre propre pipeline pour commencer. Plusieurs jeux de données publics gratuits mettent l’historique complet des chaînes à disposition dans des moteurs de requête ou sous forme de fichiers.
- Jeux de données publics de Google BigQuery. Les jeux de données
crypto_bitcoinetcrypto_ethereum(ainsi que d’autres pour plusieurs chaînes) ont été créés avec les outils blockchain-etl. Le jeu de données Ethereum comprend les tablesblocks,transactions,logs,traces,token_transfers,contractsettokens; ses journaux stockent les sujets dans un tableau plutôt que dans des colonnes séparées. Leur interrogation nécessite un compte cloud et les données analysées au-delà d’un quota gratuit sont facturées. - AWS Public Blockchain Data. Des fichiers Parquet compressés, stockés dans un compartiment public et partitionnés par date, sont mis à jour quotidiennement. Le jeu de données couvre Bitcoin, Ethereum et plusieurs autres chaînes ; consultez sa documentation pour connaître la liste à jour. Ces fichiers peuvent être lus par tout moteur compatible avec Parquet.
- Plateformes de requête hébergées. Plusieurs entreprises exploitent des plateformes communautaires proposant des tables brutes, décodées et organisées pour de nombreuses chaînes, avec une offre gratuite. Elles sont pratiques pour les données décodées, mais leurs tables organisées suivent les règles propres à chaque fournisseur.
Public ne signifie pas exact ni à jour. Les jeux de données ont un retard de quelques minutes à une journée sur la chaîne, leurs schémas changent et il arrive qu’ils omettent des blocs à la suite d’un bogue d’extraction. Avant de vous fier à une table, dressez-en le profil.
-- Dresser le profil d’une table avant de lui faire confiance : couverture, fraîcheur, doublons
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 -- devrait être égal à row_count
FROM transactions;
Cette requête indique la plage de blocs couverte, la date des données les plus récentes et si une transaction apparaît plusieurs fois. Sur une chaîne complète, elle ne parcourt que quelques colonnes, mais celles d’une table très volumineuse. Dans un moteur facturant les données analysées, commencez donc par l’exécuter sur une plage de dates récente (voir la leçon Performances, coût et reproductibilité).
Moteurs de requête et notebooks
Le moteur est le logiciel qui exécute votre SQL. Les mêmes données peuvent être accessibles par des moteurs très différents.
| Type de moteur | Exemples ouverts | Adapté à |
|---|---|---|
| Entrepôt de données cloud | Services gérés des grands fournisseurs de cloud | Analyses portant sur l’historique complet sans infrastructure à gérer ; hébergement de jeux de données publics |
| SQL distribué sur des fichiers | Trino, Apache Spark SQL | Lacs de données d’équipe constitués de fichiers Parquet |
| Base de données analytique en colonnes | ClickHouse | Tableaux de bord rapides et surveillance continue |
| Moteur embarqué | DuckDB, SQLite | Travail sur un extrait local depuis un ordinateur portable ; cas confidentiels |
| Base de données relationnelle | PostgreSQL | Données de dossiers, étiquettes, petites tables fréquemment modifiées |
Les éléments fondamentaux de SQL (SELECT, JOIN, GROUP BY, fonctions de fenêtrage) sont communs, mais les noms des fonctions, la gestion des dates, la syntaxe des tableaux et même la façon de nommer les tables varient.
-- Une question, trois façons de nommer les données
-- Jeu de données public d’un entrepôt (project.dataset.table, guillemets BigQuery) :
SELECT COUNT(*) FROM `bigquery-public-data.crypto_ethereum.blocks`
WHERE DATE(timestamp) = '2024-11-01';
-- Moteur embarqué qui lit directement les fichiers Parquet (syntaxe DuckDB) :
SELECT COUNT(*) FROM read_parquet('eth/blocks/date=2024-11-01/*.parquet');
-- Tout moteur utilisant le schéma générique de ce module :
SELECT COUNT(*) FROM blocks WHERE CAST(block_timestamp AS DATE) = DATE '2024-11-01';
Les trois requêtes comptent les blocs produits au cours d’une journée UTC. Seules la référence à la table et la syntaxe des dates changent ; la logique est identique. Les leçons de ce module utilisent un schéma générique et signalent les principales différences entre les dialectes au fur et à mesure.
Les notebooks (Jupyter et outils similaires) combinent des cellules SQL, du code Python ou R, des graphiques et des notes écrites dans un même document, ce qui convient aux enquêtes : interroger, examiner, représenter graphiquement et consigner le raisonnement. Certaines tâches se prêtent mal au SQL, notamment les traitements itératifs de graphes, comme la recherche de composantes connexes pour le regroupement ; pour ces tâches, les analystes exportent les arêtes depuis SQL vers une bibliothèque de graphes (voir la leçon Interroger les données UTXO).
Choisir ses outils
Il n’existe pas de pile idéale, mais une pile adaptée à la question, au budget et à la sensibilité du travail. Évaluez les critères suivants :
- Couverture. Quelles chaînes, quelle plage de dates, et les données comprennent-elles les traces et les événements décodés ?
- Fraîcheur. Avez-vous besoin des données du dernier bloc ou celles d’hier suffisent-elles ?
- Modèle de coût. Paiement selon le volume de données analysées, le temps de calcul ou une infrastructure fixe que vous gérez vous-même.
- Reproductibilité. Pouvez-vous fixer un instantané ou une hauteur de bloc et obtenir la même réponse le mois prochain ?
- Confidentialité. Les requêtes sur les services hébergés sont enregistrées par le fournisseur et, sur certaines plateformes communautaires, elles sont publiques par défaut. Saisir l’adresse d’un suspect sur une plateforme partagée peut révéler une enquête. Pour un travail sensible, extrayez une plage de blocs et interrogez-la localement.
- Provenance. Chaque ligne peut-elle être reliée à un hachage de bloc et à un hachage de transaction que vous pouvez vérifier sur un nœud ?
Exemples de piles adaptées :
| Situation | Pile adaptée |
|---|---|
| Journaliste qui vérifie l’historique de deux ans d’un portefeuille | Jeu de données public dans un entrepôt ou une plateforme hébergée, puis exportation des lignes utilisées |
| Équipe de risque d’une plateforme d’échange qui examine des dépôts toute la journée | Pipeline en continu vers une base de données en colonnes, avec des tables d’étiquettes et de prix |
| Étude universitaire devant être reproduite à l’identique | Instantané Parquet fixé, code versionné, moteur embarqué ou distribué |
| Enquête confidentielle | Nœud propre ou fichiers téléchargés, moteur embarqué local, aucune requête hébergée |
Quel que soit votre choix, consignez le jeu de données, sa version ou la date de son instantané, le texte de la requête et l’heure d’exécution avec chaque résultat.
Points clés pour l’examen : les trois étapes ETL et le rôle de l’étape de transformation ; le sens du grain et la raison pour laquelle un bloc donne lieu à plusieurs lignes ; la différence entre les tables brutes, décodées et organisées, ainsi que les risques associés à chacune ; la nécessité de rapprocher les tables organisées des données brutes ; les principaux jeux de données publics (jeux de données crypto de BigQuery, AWS Public Blockchain Data au format Parquet) et leurs limites ; les catégories de moteurs de requête et les situations adaptées à un moteur embarqué ; l’intérêt des notebooks pour les enquêtes ; les critères de sélection des outils, notamment la confidentialité des requêtes hébergées et la reproductibilité.