Unformatierte Blockchain-Daten lesen · Lektion 5 von 6
Node-APIs und Datenzugriff
8 Min. Lesezeit
Jeder Explorer, jeder Datensatz und jede Analyseplattform liest die Chain letztlich über die API eines Nodes aus. Wenn Sie diese APIs kennen, können Sie genau die Daten abrufen, auf denen ein Befund beruht, überprüfen, was ein Drittanbieter-Tool anzeigt, und verstehen, warum eine Abfrage, die für einen aktuellen Block funktioniert, bei einem älteren fehlschlägt. In dieser Lektion geht es um die Methoden, die Analysten am häufigsten verwenden, die dafür benötigten Node-Typen und die praktischen Einschränkungen von Anbietern und öffentlichen Datensätzen.
Zwei API-Familien
Bitcoin Core stellt eine JSON-RPC-Schnittstelle bereit: einen HTTP-POST-Aufruf mit einem method-Namen und einem params-Array, authentifiziert über eine Cookie-Datei oder einen konfigurierten Benutzer. Dieselben Methoden sind über bitcoin-cli auch auf der Kommandozeile verfügbar. Beträge werden als JSON-Zahlen in BTC zurückgegeben.
Ethereum-Ausführungsclients implementieren eine gemeinsame JSON-RPC-Spezifikation, die von der Ethereum-Community gepflegt wird. Daher verhalten sich die zentralen eth_-Methoden bei Geth, Nethermind, Besu, Erigon und Reth gleich. Die meisten EVM-Chains, einschließlich Rollups und Sidechains, bieten dieselbe Schnittstelle. Zusätzliche Namespaces wie debug_ und trace_ sind clientabhängig. Mengenangaben werden als Hexadezimalstrings zurückgegeben ("0x1b4"), und Blockargumente akzeptieren entweder eine Hexadezimalzahl oder ein Tag (latest, safe, finalized, earliest, pending), wie in der Lektion Blöcke und Header als Daten erklärt wird.
Bitcoin-Core-Methoden, die Analysten verwenden
| Methode | Gibt zurück | Hinweise |
|---|---|---|
getblockchaininfo | Chain, Höhe, Hash des besten Blocks, Pruning-Status | Erster Aufruf in jeder Sitzung |
getblockhash height | Hash des Mainchain-Blocks auf dieser Höhe | Kann sich nahe der Spitze ändern |
getblockheader hash | Header-Felder und confirmations | Schlank und schnell |
getblock hash verbosity | 0: Hexadezimal; 1: Header und txids; 2: dekodierte Transaktionen mit Gebühren; 3: ergänzt prevout für jede Eingabe | Gebühren und Prevouts erfordern Undo-Daten |
getrawtransaction txid verbosity | 0: Hexadezimal; 1: dekodiert; 2: ergänzt Gebühr und Prevouts | Für bestätigte Transaktionen ist txindex=1 oder ein Block-Hash erforderlich |
decoderawtransaction hex | Dekodierte Struktur einer Hexadezimaltransaktion | Keine Prevouts, also keine Gebühr |
gettxout txid n | Ausgabedetails, wenn sie derzeit nicht ausgegeben ist | Null, wenn sie ausgegeben oder unbekannt ist |
gettxspendingprevout | Transaktion, die die angegebenen Ausgaben ausgibt | Nur Mempool, sofern txospenderindex nicht aktiviert ist (31.0 und höher) |
getchaintips | Bekannte Zweige und ihr Status | Untersuchung von Reorgs |
Eine typische Abfolge zur Untersuchung einer Zahlung sieht so aus:
getblockhash 880214 -> "0000…3f1a"
getblock "0000…3f1a" 1 -> Header-Felder und die Liste der txids
getrawtransaction "4f3a…c21e" 2 -> dekodierte Transaktion mit Prevout-Werten und Gebühr
gettxout "4f3a…c21e" 1 -> Ausgabe 1, falls sie noch nicht ausgegeben ist, andernfalls null
Der letzte Aufruf prüft nur den aktuellen UTXO-Satz: Er zeigt an, ob eine Ausgabe jetzt nicht ausgegeben ist, nicht wann oder wodurch sie ausgegeben wurde. Um die ausgebende Transaktion zu finden, benötigte man traditionell einen Indexer oder ein Data Warehouse. Seit Version 31.0 bietet Bitcoin Core einen optionalen Spenderindex (txospenderindex), mit dem gettxspendingprevout die bestätigte Transaktion zurückgeben kann, die eine Ausgabe ausgegeben hat. Bitcoin Core verfügt weiterhin über keine Methode, die den Transaktionsverlauf einer Adresse auflistet. Dafür ist ein Adressindexer oder ein Data Warehouse erforderlich.
Ethereum-JSON-RPC-Methoden
| Methode | Gibt zurück |
|---|---|
eth_chainId | Die Chain-ID (EIP-695); bestätigt, mit welchem Netzwerk Sie verbunden sind |
eth_blockNumber | Höhe des neuesten Blocks |
eth_getBlockByNumber, eth_getBlockByHash | Header und Transaktions-Hashes oder vollständige Transaktionen, wenn der zweite Parameter true ist |
eth_getTransactionByHash | Die signierte Transaktion mit rekonstruierter Angabe von from |
eth_getTransactionReceipt | Status, Gas, Logs |
eth_getBlockReceipts | Alle Receipts eines Blocks in einem Aufruf; von Clients weitgehend implementiert, fehlt aber in älterer Dokumentation |
eth_getLogs | Logs, die einem Filter entsprechen |
eth_getBalance, eth_getCode, eth_getStorageAt, eth_call | Zustand an einem bestimmten Block |
Zwei Verhaltensweisen überraschen Einsteiger. eth_getTransactionReceipt gibt für eine ausstehende oder dem Node unbekannte Transaktion null zurück. Das ist nicht dasselbe wie ein Fehlschlag. Und die Zustandsmethoden benötigen ein Blockargument: eth_getBalance mit latest liefert alle paar Sekunden ein anderes Ergebnis. Geben Sie daher für jede Zahl, die Sie veröffentlichen möchten, eine explizite Blocknummer an.
eth_getLogs ist das wichtigste Werkzeug für die Analyse von Token und Protokollen. Sein Filter nimmt fromBlock und toBlock (oder stattdessen einen einzelnen blockHash), eine optionale address und ein positionsabhängiges topics-Array entgegen. Diese Anfrage fragt einen Token-Kontrakt nach Transfer-Ereignissen ab, die innerhalb von 1.000 Blöcken an eine Adresse gesendet wurden:
{"jsonrpc": "2.0", "id": 1, "method": "eth_getLogs",
"params": [{
"fromBlock": "0x1406f40",
"toBlock": "0x1407327",
"address": "0x5d3a…7c10",
"topics": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
null,
"0x000000000000000000000000c3d4…22e1"]
}]}
Die Blöcke reichen von 21.000.000 (0x1406f40) bis 21.000.999 (0x1407327). Topics werden positionsabhängig abgeglichen: Das erste Topic ist die Transfer-Signatur, null akzeptiert einen beliebigen Sender und das dritte Topic, topics[2], legt den Empfänger fest. Eine Position kann auch ein Array enthalten, was „einer dieser Werte“ bedeutet. Wenn Sie die gepaddete Adresse an die zweite Position verschieben, erhalten Sie stattdessen die von ihr gesendeten Transfers.
Debug- und Trace-Methoden
Interne Aufrufe erfordern eine erneute Ausführung. Clients im Geth-Stil bieten debug_traceTransaction, debug_traceBlockByNumber und debug_traceCall mit einer tracer-Option wie callTracer (dem Aufrufbaum) oder prestateTracer (dem Zustand, auf den eine Transaktion zugegriffen hat). Clients im Parity-Stil wie Erigon, Nethermind und Reth bieten außerdem trace_transaction, trace_block, trace_filter und trace_replayTransaction, die flache Aufruflisten zurückgeben.
Diese Methoden sind rechenintensiv: Ein Node spielt jeden Opcode der Transaktion erneut ab. Bei älteren Blöcken muss er zunächst den historischen Zustand wiederherstellen. Anbieter deaktivieren sie häufig, schränken sie ein oder berechnen höhere Gebühren. Die beiden Stile unterscheiden sich zudem in ihrer Struktur und in Details, etwa darin, ob Aufrufe an Precompiles erscheinen. Normalisieren Sie die Daten daher, bevor Sie Ergebnisse verschiedener Clients zusammenführen.
Welche Fragen welchen Node erfordern
| Frage | Bitcoin | Ethereum |
|---|---|---|
| Blöcke, Transaktionen, Receipts, Logs | Full Node (txindex=1 für die Suche nach txid) | Full Node; die Historie vor dem Merge ist möglicherweise abgelaufen |
| Aktueller Kontostand oder UTXO-Status | gettxout oder ein Indexer für Adressen | Full Node, eth_getBalance mit latest |
| Kontostand an einem vergangenen Block | Indexer oder Data Warehouse | Archive Node |
| Adressverlauf | Adressindexer oder Data Warehouse | Indexer oder Data Warehouse (keine native Methode) |
| Interne Aufrufe älterer Transaktionen | Nicht zutreffend | Archive Node mit Tracing |
Pruned Nodes beider Chains können ältere Blöcke überhaupt nicht bereitstellen. Ein Ethereum-Full-Node, der nach einem Zustand außerhalb seines gespeicherten Zeitfensters gefragt wird, gibt einen Fehler zurück statt einer falschen Zahl. Dieser Fehler ist ein nützlicher Hinweis darauf, dass Sie einen Archive Node benötigen.
Ratenbegrenzungen, Paginierung und Vertrauen in Anbieter
Gehostete Anbieter schützen ihre Nodes mit Ratenbegrenzungen, die in Anfragen pro Sekunde oder gewichteten „Compute Units“ gemessen werden, sowie mit Obergrenzen für eth_getLogs: einer maximalen Blockspanne, einer maximalen Ergebniszahl oder beidem. Robuster Extraktionscode teilt einen Bereich in Abschnitte auf, halbiert einen Abschnitt, wenn der Anbieter ihn zurückweist, wiederholt Anfragen mit exponentiellem Backoff und protokolliert, welche Bereiche abgeschlossen wurden. Viele Anbieter akzeptieren Batch-Anfragen im JSON-RPC-Format (ein Array von Aufrufen in einer HTTP-Anfrage). Das verringert den Overhead, wird aber auf dieselben Limits angerechnet.
Anbieter werfen außerdem Fragen des Vertrauens auf:
- Uneinheitliche Blockspitzen. Hinter einem Load Balancer können aufeinanderfolgende Aufrufe Nodes mit unterschiedlichen Höhen erreichen. Daher kann ein in einem Aufruf zurückgegebener Block beim nächsten „nicht gefunden“ sein. Richten Sie Ihre Arbeit an einem Block-Hash statt an
latestaus. - Fehler und Verzögerungen. Der Node eines Anbieters kann nicht synchronisiert oder falsch konfiguriert sein oder eine andere Client-Version verwenden. Vergleichen Sie bei Fakten, auf denen ein Befund beruht, den Block-Hash auf Ihrer Ankerhöhe über zwei unabhängige Quellen hinweg oder prüfen Sie ihn anhand Ihres eigenen Nodes. Erfassen Sie die Client-Version mit
web3_clientVersionauf Ethereum oder dem Feldsubversionvongetnetworkinfoin Bitcoin Core. - Datenschutz bei Abfragen. Ein Anbieter sieht jede Adresse und Transaktion, nach der Sie fragen. Bei sensiblen Untersuchungen lassen sich in den Protokollen eines Anbieters die Gegenstände Ihres Interesses erkennen; bei einem eigenen Node ist das nicht der Fall.
Öffentliche Datensätze und ETL-Frameworks
Für umfangreiche historische Daten ist es langsam, alles über RPC zu extrahieren. Es gibt zwei Alternativen.
Öffentliche Datensätze großer Cloud-Anbieter enthalten Bitcoin, Ethereum und andere Chains, die bereits in Tabellen geladen wurden: zum Beispiel die Krypto-Datensätze im öffentlichen Datenprogramm von Google BigQuery, erstellt vom Open-Source-Projekt blockchain-etl, sowie der AWS Public Blockchain Data set, veröffentlicht als Parquet-Dateien. Sie bieten innerhalb weniger Minuten SQL-Zugriff auf die vollständige Historie. Dafür übernehmen Sie ihr Schema, ihre Dekodierungsentscheidungen, ihre Aktualisierungsverzögerung und ihre Reorg-Richtlinien. Lesen Sie diese Punkte, bevor Sie sich auf eine Tabelle verlassen.
ETL-Frameworks ermöglichen es Ihnen, eigene Tabellen aus einem Node zu erstellen: Bitcoin ETL und Ethereum ETL (blockchain-etl), cryo (extrahiert Blöcke, Transaktionen, Logs und Traces nach Parquet oder CSV), TrueBlocks (indiziert jedes Auftreten einer Adresse) und The Graph (indiziert Ereignisse für bestimmte Protokolle über Subgraphs). Eine eigene Pipeline zu betreiben, kostet Aufwand, gibt Ihnen aber Kontrolle über den Node, die Dekodierung und die Herkunft jeder Zeile. Die Lektion Der Analytics-Datenstack vergleicht diese Optionen.
Prüfungsschwerpunkt: Die Verbosity-Stufen von Bitcoin Coresgetblockundgetrawtransactionsowie die Anforderung vontxindex; dassgettxoutnur den aktuellen UTXO-Satz prüft und Bitcoin Core keine Methode für den Adressverlauf hat; die zentralen Ethereum-Methoden, daruntereth_getBlockByNumber,eth_getTransactionReceipt,eth_getBlockReceiptsundeth_chainId; dereth_getLogs-Filter und der positionsabhängige Abgleich von Topics mitnullals Platzhalter;debug_trace*-Methoden im Geth-Stil im Vergleich zutrace_*-Methoden im Parity-Stil; welche Fragen einen Archive Node erfordern und wie Ratenbegrenzungen und Bereichsobergrenzen zu handhaben sind; das Überprüfen von Anbietern und Erfassen der Client-Versionen; öffentliche Datensätze und ETL-Frameworks sowie ihre Vor- und Nachteile.