Bitcoin für Anfänger, Teil 3: Die BitCoinJ-API

Für Java-Entwickler ist BitCoinJ ein Einstiegspunkt für die Entwicklung von Anwendungen, die mit dem Bitcoin-Netzwerk interagieren. In diesem letzten Artikel in einer dreiteiligen Reihe hilft Dirk Merkel Ihnen beim Einrichten von BitCoinJ in einer Eclipse-Entwicklungsumgebung und führt Sie dann durch einige kurze Übungen, die Sie mit dieser einfachen Implementierung des Bitcoin-Transaktionsprotokolls vertraut machen.

In früheren Abschnitten dieser dreiteiligen Reihe wurde der konzeptionelle und technologische Rahmen von Bitcoin, einer virtuellen Währung und einem Peer-to-Peer-Netzwerk, vorgestellt. In diesem Artikel, einer Einführung in die BitCoinJ-API, wird davon ausgegangen, dass Sie mit Bitcoin-Adressen, Transaktionen, Blöcken und der Blockkette vertraut sind.

BitCoinJ ist eine Open-Source-Java-Implementierung des Bitcoin-Protokolls. Daher ist es ein praktisches Tool, wenn Sie Java-Anwendungen schreiben möchten, die mit dem Bitcoin-Netzwerk interagieren. Um die BitCoinJ-API zu untersuchen, erstellen wir verschiedene Beispielanwendungen, die die Programmierschritte veranschaulichen, die zum Erstellen komplexerer Bitcoin-Anwendungen in Java erforderlich sind. Nachdem Sie Maven zum Erstellen und Einrichten eines Projekts in der Eclipse-IDE verwendet haben, üben wir das Erstellen einer Bitcoin-Adresse, das Speichern in einer Brieftasche und das Speichern der Brieftasche auf der Festplatte. Wir werden dann eine Verbindung zum Bitcoin-Testnetzwerk herstellen und dessen Genesis-Block abrufen. Schließlich verknüpfen wir unseren bisherigen Beispielcode, indem wir einige Bitcoins an eine Adresse im Testnetzwerk senden.

Über BitCoinJ

BitCoinJ ist eine Java-Implementierung des Bitcoin-Protokolls. BitCoinJ wurde von Mike Hearn geschrieben und ist keine vollständige Implementierung des ursprünglichen Bitcoin-Clients, sondern eine leichtere und zugänglichere Version. BitCoinJ ist zwar solide genug, um daraus zu lernen, befindet sich jedoch noch in der Entwicklung (derzeit auf Version 0.3) und sollte nicht zum Verschieben einer großen Anzahl von Bitcoins verwendet werden.

Beginnen Sie mit BitCoinJ

BitCoinJ wird von Google Code in einem Subversion-Repository gehostet und kann anonym ausgecheckt werden. Sobald Sie den Trunk des BitCoinJ-Projekts ausgecheckt haben, können Sie ihn problemlos auf dem neuesten Stand halten. Sie können jedoch keine Änderungen vornehmen.

Sie können den in Ihre Lieblings-IDE integrierten Subversion-Client verwenden oder das Projekt einfach wie folgt über die Befehlszeile auschecken:

Sobald Sie den Code haben, kompilieren Sie ihn mit Maven, dem Build-System von BitCoinJ. Maven verfolgt beim Erstellen von Projekten einen Lebenszyklusansatz und ist mit vielen Kern- und Drittanbieter-Plugins in hohem Maße erweiterbar. Was Maven außerordentlich gut macht, ist das Verwalten von Abhängigkeiten. Wenn Sie sich die Maven-Datei pom.xml im Stammverzeichnis von BitCoinJ ansehen, werden Sie feststellen, dass nur eine Handvoll Abhängigkeiten verwendet werden. Dazu gehören JUnit und EasyMock für Unit-Tests, SLF4J für die Protokollierung und die Bouncy Castle Crypto-APIs für kryptografische Vorgänge wie Hashing und Signieren.

Über die Befehlszeile mvn clean packagerufen run und Maven diese und andere Abhängigkeiten ab, kompilieren das Projekt, führen die Unit-Test-Suite aus und packen den kompilierten Code in eine Snapshot-JAR-Datei. Wie in Abbildung 2 dargestellt, führt Maven zuerst den sauberen Lebenszyklus aus, um Artefakte aus früheren Builds zu entfernen. Anschließend werden die Phasen des Standardlebenszyklus bis einschließlich der Paketphase ausgeführt.

Maven hat noch ein paar hilfreiche Tricks im Ärmel. Beim Ausführen wird zunächst mvn site:sitedie BitCoinJ-Dokumentation erstellt, einschließlich Seiten zu Abhängigkeiten, Problemverfolgung, Mailinglisten, Lizenz, Entwicklungsteam, Quell-Repository und anderen. Diese Seiten sind in der Regel informativ, aber einfach. Durch Ausführen mvn javadoc:javadocwird die Projektdokumentation generiert, die sich als nützlich erweisen wird, wenn wir mit der Ausübung der BitCoinJ-API beginnen.

Die Dokumentation zeigt, dass die API in vier Pakete unterteilt ist:

  • Die Ermittlung befasst sich mit der Erkennung / Kommunikation von Peer-to-Peer-Netzwerken.
  • Der Speicher enthält Datenstrukturen zum Speichern von Blöcken und der Blockkette.
  • Beispiele sind eine Handvoll einfacher Anwendungen, die auf BitCoinJ basieren (diese haben meine eigenen Beispiele für diesen Artikel inspiriert).
  • Core enthält die meisten Klassen und Funktionen von BitCoinJ, einschließlich Klassen für die Kommunikation mit Peer-Knoten, das Herunterladen der Blockkette sowie das Senden und Empfangen von Transaktionen.

Richten Sie das Beispielprojekt in Eclipse ein

Wir werden den Beispielcode für diesen Artikel in Eclipse entwickeln und Maven verwenden, um BitCoinJ als Abhängigkeit zu verwalten. Glücklicherweise verfügt BitCoinJ über eine kontinuierliche Integrationsumgebung, die das Projekt erstellt, verschiedene Artefakte sammelt und meldet und eine Snapshot-JAR im projekteigenen Maven-Repository auf Nexus-Basis ablegt.

Abbildung 3 zeigt den Dialog zur Erstellung eines Eclipse-Projekts, der sich aus der Erstellung eines neuen Maven-Projekts und der Auswahl des Archetyps "Schnellstart" ergibt, mit dem ein grundlegendes Maven-Projekt generiert wird. Mein Code für dieses Projekt befindet sich in einem Paket mit dem Namen com.waferthin.bitcoinj, das einen 0.0.1-SNAPSHOT mit dem Maven-Build erzeugt.

Wenn Sie auf Fertig stellen klicken, wird der Assistent angewiesen, das Projekt zu erstellen. Dies bedeutet, dass eine Hauptklasse "Hello World" in das src/main/java/com/waferthin/bitcoinjin meinem Fall benannte Projektverzeichnis abgelegt wird.

Schließlich müssen wir Maven mitteilen, dass das Projekt vom BitCoinJ-Snapshot abhängt, wie in Listing 1 gezeigt. Ich habe die vom Assistenten generierte Datei pom.xml von Maven bearbeitet, um den Speicherort und den Namen des Nexus-Repositorys von BitCoinJ (Zeilen 18 bis 28) zu deklarieren und festzulegen die Version, von der der Build abhängen muss (Zeilen 39 bis 45):

Listing 1. Maven pom.xm für das BitCoinJ-Projekt

001| 002| 4.0.0 003| 004| com.waferthin.bitcoinj.explored 005| bitcoinj-explored 006| 0.0.1-SNAPSHOT 007| jar 008| 009| bitcoinj-explored 010| //maven.apache.org 011| 012|  013| UTF-8 014|  015| 016|  017|  018|  019| bitcoinj-release 020|  021| 022|//nexus.bitcoinj.org/content/repositories/releases 023|  024|  025| bitcoinj-snapshot 026|  027| //nexus.bitcoinj.org/content/repositories/snapshots 028|  029|  030| 031|  032|  033| junit 034| junit 035| 3.8.1 036| test 037|  038| 039|  040|  041| com.google 042| bitcoinj 043| 0.3-SNAPSHOT 044| compile 045|  046|  047|

Das ist alles dazu. Im nächsten Abschnitt importieren wir die BitCoinJ-Klassen in unseren Code und erstellen mit Maven ein BitCoinJ-Projekt, ohne die eigentliche JAR-Datei kopieren zu müssen.

Erstellen einer Bitcoin-Adresse

Zum Senden oder Empfangen von Bitcoins benötigen Sie eine Adresse. Adressen werden aus dem öffentlichen Teil eines öffentlich-privaten kryptografischen Schlüsselpaars abgeleitet (siehe "Bitcoin für Anfänger, Teil 2: Bitcoin als Technologie und Netzwerk"). Die von Bitcoin verwendete Art der Kryptographie wird als elliptische Kurvenkryptographie (ECC) bezeichnet. Die Kryptographie mit öffentlichen Schlüsseln, die die meisten von uns kennen, basiert auf der Schwierigkeit, die Primfaktoren großer Ganzzahlen zu finden. Im Gegensatz dazu basiert ECC auf der Schwierigkeit, den diskreten Logarithmus einer elliptischen Kurve zu finden. (Eine genauere Erklärung würde uns nicht nur in das Kaninchenloch der höheren Algebra führen, sondern auch meine College-Mathematik schnell übertreffen. Glücklicherweise müssen wir nicht mehr wissen, um die BitCoinJ- ECKeyKlasse zum Darstellen und Generieren von Schlüsseln zu verwenden Paare.)

In Zeile 20 von Listing 2 erstellen wir ein neues Schlüsselpaar für elliptische Kurven, indem wir ein Objekt vom Typ instanziieren ECKey. Beachten Sie, dass die Standardmethode der Klasse toString()überschrieben wird, um den öffentlichen und den privaten Schlüssel in Hex-Notation zurückzugeben, die in Zeile 23 verwendet wird.

Listing 2. Erstellen eines Schlüsselpaars für elliptische Kurven mit ECKey

001|package com.waferthin.bitcoinj; 002| 003|import com.google.bitcoin.core.ECKey; 004|import com.google.bitcoin.core.NetworkParameters; 005|import com.google.bitcoin.core.Address; 006| 007|public class CreateAddress  008

You might recall that the public part of a Bitcoin key pair should be an address. But the public part of the key generated by the above code will initially look nothing like the addresses the Bitcoin client displays in its UI. The address form we're used to seeing in a Bitcoin transaction is derived by repeated hash operations to the public key. This form includes a flag that indicates which of the two Bitcoin networks the key belongs to -- Bitcoin's production network or its test network. (See the Bitcoin wiki page for a more detailed description of the algorithmic creation of Bitcoin key pairs.)

Differentiating Bitcoin networks

Currently there are two Bitcoin networks, one for production and one that is used for development. Both networks have their own genesis block and subsequent block chain. Later in this article, we'll use the Bitcoin testnet to execute a Bitcoin transaction. For now, you only need to know that the networks are differentiated by pre-pending a single byte to the input to one of the cryptographic hashes in the ECC algorithm: 0x6f indicates the production network and 0x00 the test one.

We don't need to apply the sequence of cryptographic hashes ourselves because the ECKey class provides the same functionality with the toAddress() method. After invoking that method and passing in the type of network via a NetworkParameters object (see line 26 in Listing 2), the toAddress() method returns an Address object. That object's toString() method will yield a true Bitcoin address. After compiling and executing the class I get the following address for Bitcoin's test network:

mpJ9UDd4qtNhMiGefK8NM1V5PMq9jMb7ck

Testnet addresses typically start with m or n, whereas production addresses start with 1. Try executing the same code on your own machine and you will get a different, unique address.

Wallets and keys

If you participate in the Bitcoin economy, you likely keep all of your riches in your wallet. The wallet is nothing more than a local data file that contains serialized objects representing all of your Bitcoin transactions and a cache of unused addresses. The sum of your incoming and outgoing transaction amounts is the amount of Bitcoins in your wallet. In this section we'll use BitCoinJ's Wallet object to create a wallet data file, populate it with five addresses, and save it to disk.

The Wallet class implements the Serializable interface to enable us to persist it to disk or some other more permanent storage medium. Specifically, methods loadFromFile(File) and the corresponding saveToFile(File) read and write wallet files. We'll be using loadFromFile(File) to write a newly created wallet object to a file.

Note that BitCoinJ wallet files are not compatible with wallet files created by the official Bitcoin client.

Creating and storing keys

Die WalletKlasse verfügt über ein öffentliches Mitglied benannt , keychaindas eine ist ArrayListder Typ ECKey, der alle EG - Schlüsselpaare in der Brieftasche speichern verwendet wird. Die addKey(ECKey)Methode wird zum Hinzufügen von Schlüsselpaaren verwendet, es gibt jedoch derzeit keine Methode zum Entfernen dieser Paare. Dies ist sinnvoll, da es für Benutzer oder Programme nicht einfach sein sollte, private Schlüssel zu löschen: Für den Zugriff auf über den entsprechenden öffentlichen Schlüssel gesendete Gelder ist ein privater Schlüssel erforderlich. Ohne ein Schlüsselpaar in der Brieftasche oder irgendwo gesichert, würde jedes gesendete Geld für immer verloren gehen.