Bitcoin pour les débutants, partie 3: l'API BitCoinJ

Pour les développeurs Java, BitCoinJ est un point d'entrée pour développer des applications qui interagissent avec le réseau Bitcoin. Dans ce dernier article d'une série en trois parties, Dirk Merkel vous aide à configurer BitCoinJ dans un environnement de développement Eclipse, puis parcourt plusieurs courts exercices qui vous familiariseront avec cette implémentation légère du protocole de transaction Bitcoin.

Les précédents épisodes de cette série en trois parties ont présenté le cadre conceptuel et technologique de Bitcoin, une monnaie virtuelle et un réseau peer-to-peer. Cet article, un didacticiel d'introduction à l'API BitCoinJ, suppose que vous connaissez les adresses Bitcoin, les transactions, les blocs et la chaîne de blocs.

BitCoinJ est une implémentation Java open source du protocole Bitcoin. En tant que tel, c'est un outil pratique à avoir si vous souhaitez écrire des applications Java qui interagissent avec le réseau Bitcoin. Afin d'explorer l'API BitCoinJ, nous allons construire divers exemples d'applications qui illustrent les étapes de programmation nécessaires pour construire des applications Bitcoin plus complexes en Java. Après avoir utilisé Maven pour créer et configurer un projet dans l'IDE Eclipse, nous nous entraînerons à créer une adresse Bitcoin, à la stocker dans un portefeuille et à enregistrer le portefeuille sur le disque. Nous établirons ensuite une connexion au réseau de test Bitcoin et récupérerons son bloc de genèse. Enfin, nous lierons notre exemple de code jusqu'à présent en envoyant des Bitcoins à une adresse sur le réseau de test.

À propos de BitCoinJ

BitCoinJ est une implémentation Java du protocole Bitcoin. Écrit par Mike Hearn, BitCoinJ n'est pas une implémentation complète du client Bitcoin d'origine, mais une version plus légère et accessible. Bien qu'il soit suffisamment solide pour en tirer des leçons, BitCoinJ est toujours en cours de développement (actuellement à la v.0.3) et ne devrait pas être utilisé pour déplacer un grand nombre de Bitcoins.

Commencez avec BitCoinJ

BitCoinJ est hébergé par Google Code dans un référentiel Subversion et peut être extrait de manière anonyme. Une fois que vous aurez vérifié le coffre du projet BitCoinJ, vous pourrez facilement le maintenir à jour. Vous ne pourrez cependant pas valider de modifications.

Vous pouvez utiliser le client Subversion intégré à votre IDE préféré ou simplement consulter le projet à partir de la ligne de commande, comme je l'ai fait:

Une fois que vous avez le code, vous le compilerez avec Maven, le système de construction de BitCoinJ. Maven adopte une approche de cycle de vie pour la création de projets et est hautement extensible avec de nombreux plugins principaux et tiers. Ce que Maven fait extrêmement bien, c'est gérer les dépendances. Si vous regardez le fichier Maven pom.xml dans le répertoire racine de BitCoinJ, vous verrez qu'il n'utilise qu'une poignée de dépendances; ceux-ci incluent JUnit et EasyMock pour les tests unitaires, SLF4J pour la journalisation et les API Bouncy Castle Crypto pour les opérations cryptographiques telles que le hachage et la signature.

À partir de la ligne de commande, exécutez mvn clean packageet Maven récupérera ces dépendances et d'autres, compilera le projet, exécutera la suite de tests unitaires et regroupera le code compilé dans un fichier JAR instantané. Comme le montre la figure 2, Maven exécute d'abord le cycle de vie propre pour se débarrasser de tous les artefacts des versions précédentes. Il exécute ensuite les phases du cycle de vie par défaut jusqu'à et y compris la phase du package.

Maven a quelques autres astuces utiles dans sa manche. Tout d'abord, l'exécution mvn site:sitecrée la documentation BitCoinJ, y compris les pages sur les dépendances, le suivi des problèmes, les listes de diffusion, la licence, l'équipe de développement, le référentiel source, etc. Ces pages ont tendance à être informatives mais basiques. L'exécution mvn javadoc:javadocgénère la documentation du projet, qui sera utile lorsque nous commencerons à exercer l'API BitCoinJ.

La documentation révèle que l'API est divisée en quatre packages:

  • La découverte traite de la découverte / communication de réseau d'égal à égal.
  • Store contient des structures de données pour stocker les blocs et la chaîne de blocs.
  • Les exemples incluent une poignée d'applications simples basées sur BitCoinJ (celles-ci ont inspiré mes propres exemples pour cet article).
  • Core contient la majorité des classes et fonctionnalités de BitCoinJ, y compris des classes pour communiquer avec des nœuds homologues, télécharger la chaîne de blocs et envoyer et recevoir des transactions.

Configurer l'exemple de projet dans Eclipse

Nous développerons l'exemple de code pour cet article dans Eclipse, en utilisant Maven pour gérer BitCoinJ en tant que dépendance. Heureusement, BitCoinJ dispose d'un environnement d'intégration continue qui construit le projet, collecte et signale divers artefacts, et dépose un instantané JAR dans le propre référentiel Maven basé sur Nexus du projet.

La figure 3 montre la boîte de dialogue de création de projet Eclipse qui résulte de la création d'un nouveau projet Maven et de la sélection de l'archétype "quickstart", qui génère un projet Maven de base. Mon code pour ce projet réside dans un package nommé com.waferthin.bitcoinj, qui produit un 0.0.1-SNAPSHOT avec la version Maven.

Cliquer sur Terminer demande à l'assistant de créer le projet, ce qui signifie déposer une classe principale "Hello World" dans le répertoire du projet - nommé src/main/java/com/waferthin/bitcoinjdans mon cas.

Enfin, nous devons dire à Maven que le projet dépend de l'instantané BitCoinJ, comme indiqué dans la liste 1. J'ai édité le fichier pom.xml généré par l'assistant de Maven pour déclarer l'emplacement et le nom du référentiel Nexus de BitCoinJ (lignes 18 à 28) et définir la version dont dépendra la construction (lignes 39 à 45):

Listing 1. Maven pom.xm pour le projet BitCoinJ

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|

C'est tout ce qu'on peut en dire. Dans la section suivante, nous importerons les classes BitCoinJ dans notre code et créerons un projet BitCoinJ avec Maven, le tout sans avoir à copier le fichier JAR réel.

Créer une adresse Bitcoin

Pour envoyer ou recevoir des Bitcoins, vous avez besoin d'une adresse. Les adresses sont dérivées de la partie publique d'une paire de clés cryptographiques public-privé (voir «Bitcoin pour les débutants, partie 2: Bitcoin en tant que technologie et réseau»). Le type de cryptographie utilisé par Bitcoin est appelé cryptographie à courbe elliptique (ECC). La cryptographie à clé publique que la plupart d'entre nous connaissent est basée sur la difficulté de trouver les facteurs premiers de grands entiers. En revanche, ECC est basé sur la difficulté de trouver le logarithme discret d'une courbe elliptique. (Expliquer cela plus en détail nous conduirait non seulement dans le terrier de l'algèbre supérieure, mais dépasserait également rapidement mes mathématiques universitaires. Heureusement, nous n'avons pas besoin d'en savoir plus pour utiliser la ECKeyclasse de BitCoinJ pour représenter et générer des clés paires.)

À la ligne 20 du listing 2, nous créons une nouvelle paire de clés de courbe elliptique en instanciant un objet de type ECKey. Notez que la toString()méthode par défaut de la classe est écrasée pour renvoyer les clés publique et privée en notation hexadécimale, qui est utilisée à la ligne 23.

Listing 2. Création d'une paire de clés de courbe elliptique avec 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

La Walletclasse a un membre public nommé keychainqui est un ArrayListtype ECKey, qui est utilisé pour stocker toutes les paires de clés EC dans le portefeuille. La addKey(ECKey)méthode est utilisée pour ajouter des paires de clés, mais il n'existe actuellement aucune méthode pour les supprimer. Cela a du sens car il ne devrait pas être facile pour les utilisateurs ou les programmes de supprimer les clés privées: une clé privée est nécessaire pour accéder aux fonds envoyés via sa clé publique correspondante. Sans une paire de clés dans le portefeuille ou sauvegardée quelque part, tous les fonds envoyés seraient perdus à jamais.