Bitcoin dla początkujących, część 3: API BitCoinJ

Dla programistów Java BitCoinJ jest punktem wyjścia do tworzenia aplikacji, które współdziałają z siecią Bitcoin. W tym ostatnim artykule z trzyczęściowej serii Dirk Merkel pomaga skonfigurować BitCoinJ w środowisku programistycznym Eclipse, a następnie przeprowadza kilka krótkich ćwiczeń, które zapoznają Cię z tą lekką implementacją protokołu transakcji Bitcoin.

W poprzednich częściach tej trzyczęściowej serii przedstawiono koncepcyjne i technologiczne ramy Bitcoin, wirtualnej waluty i sieci peer-to-peer. W tym artykule, samouczku wprowadzającym do interfejsu API BitCoinJ, założono, że znasz adresy Bitcoin, transakcje, bloki i łańcuch bloków.

BitCoinJ to otwarta implementacja protokołu Bitcoin w języku Java. W związku z tym jest to przydatne narzędzie, jeśli chcesz pisać aplikacje Java, które współpracują z siecią Bitcoin. Aby zbadać interfejs API BitCoinJ, skonstruujemy różne przykładowe aplikacje, które ilustrują kroki programowania niezbędne do konstruowania bardziej złożonych aplikacji Bitcoin w Javie. Po użyciu Maven do zbudowania i skonfigurowania projektu w Eclipse IDE, poćwiczymy tworzenie adresu Bitcoin, przechowywanie go w portfelu i zapisywanie portfela na dysku. Następnie nawiążemy połączenie z siecią testową Bitcoin i odzyskamy jego blok genezy. Na koniec połączymy nasz przykładowy kod do tej pory, wysyłając trochę Bitcoinów na adres w sieci testowej.

O BitCoinJ

BitCoinJ to implementacja protokołu Bitcoin w języku Java. Napisany przez Mike'a Hearn'a, BitCoinJ nie jest pełną implementacją oryginalnego klienta Bitcoin, ale bardziej lekką i dostępną wersją. Chociaż BitCoinJ jest wystarczająco solidny, aby się z niego uczyć, jest nadal w fazie rozwoju (obecnie w wersji 0.3) i nie powinien być używany do przenoszenia dużej liczby Bitcoinów.

Zacznij korzystać z BitCoinJ

BitCoinJ jest hostowany przez Google Code w repozytorium Subversion i można go anonimowo pobrać. Po sprawdzeniu pnia projektu BitCoinJ będziesz mógł łatwo go aktualizować. Nie będziesz jednak mógł dokonywać żadnych zmian.

Możesz użyć klienta Subversion wbudowanego w swoje ulubione IDE lub po prostu sprawdzić projekt z wiersza poleceń, tak jak ja:

Gdy masz już kod, skompilujesz go za pomocą Maven, systemu kompilacji BitCoinJ. Maven przyjmuje podejście oparte na cyklu życia do tworzenia projektów i jest wysoce rozszerzalny dzięki wielu rdzeniom i wtyczkom innych firm. To, co Maven robi wyjątkowo dobrze, to zarządzanie zależnościami. Jeśli spojrzysz na plik Maven pom.xml w katalogu głównym BitCoinJ, zobaczysz, że używa on tylko kilku zależności; Obejmują one JUnit i EasyMock do testowania jednostkowego, SLF4J do logowania oraz Bouncy Castle Crypto API do operacji kryptograficznych, takich jak haszowanie i podpisywanie.

Z wiersza poleceń uruchom, mvn clean packagea Maven pobierze te i inne zależności, skompiluje projekt, uruchomi zestaw testów jednostkowych i zapakuje skompilowany kod do pliku JAR migawki. Jak pokazano na rysunku 2, Maven najpierw wykonuje czysty cykl życia, aby pozbyć się wszelkich artefaktów z poprzednich kompilacji. Następnie wykonuje fazy domyślnego cyklu życia, aż do fazy pakietu włącznie.

Maven ma w zanadrzu kilka pomocnych sztuczek. Po pierwsze, wykonanie mvn site:sitetworzy dokumentację BitCoinJ, w tym strony dotyczące zależności, śledzenia problemów, list mailingowych, licencji, zespołu programistów, repozytorium źródeł i innych. Te strony mają zwykle charakter informacyjny, ale podstawowy. Wykonanie mvn javadoc:javadocgeneruje dokumentację projektu, która przyda się, gdy zaczniemy ćwiczyć API BitCoinJ.

Dokumentacja ujawnia, że ​​API jest podzielone na cztery pakiety:

  • Discovery zajmuje się wykrywaniem / komunikacją w sieci typu peer-to-peer.
  • Sklep zawiera struktury danych do przechowywania bloków i łańcucha bloków.
  • Przykłady obejmują kilka prostych aplikacji opartych na BitCoinJ (zainspirowały one moje własne przykłady do tego artykułu).
  • Core zawiera większość klas i funkcji BitCoinJ, w tym klasy do komunikacji z węzłami równorzędnymi, pobierania łańcucha bloków oraz wysyłania i odbierania transakcji.

Skonfiguruj przykładowy projekt w Eclipse

Przykładowy kod tego artykułu opracujemy w Eclipse, używając Maven do zarządzania BitCoinJ jako zależnością. Na szczęście BitCoinJ ma środowisko ciągłej integracji, które buduje projekt, zbiera i raportuje różne artefakty oraz umieszcza migawkowy plik JAR we własnym repozytorium Maven opartym na Nexusie.

Rysunek 3 przedstawia okno dialogowe tworzenia projektu Eclipse, które jest wynikiem utworzenia nowego projektu Maven i wybrania archetypu „quickstart”, który generuje podstawowy projekt Mavena. Mój kod tego projektu znajduje się w pakiecie o nazwie com.waferthin.bitcoinj, który tworzy 0.0.1-SNAPSHOT z kompilacją Mavena.

Kliknięcie przycisku Zakończ nakazuje kreatorowi utworzenie projektu, co oznacza upuszczenie klasy głównej „Hello World” do katalogu projektu - nazwanego src/main/java/com/waferthin/bitcoinjw moim przypadku.

Na koniec musimy powiedzieć Mavenowi, że projekt zależy od migawki BitCoinJ, jak pokazano na Listingu 1. Edytowałem plik pom.xml wygenerowany przez kreatora Mavena, aby zadeklarować lokalizację i nazwę repozytorium Nexus BitCoinJ (wiersze od 18 do 28) i ustawić wersja, od której ma zależeć kompilacja (wiersze od 39 do 45):

Listing 1. Maven pom.xm dla projektu 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|

To wszystko. W następnej sekcji zaimportujemy klasy BitCoinJ do naszego kodu i zbudujemy projekt BitCoinJ za pomocą Maven, wszystko bez konieczności kopiowania rzeczywistego pliku JAR.

Tworzenie adresu Bitcoin

Aby wysyłać lub odbierać Bitcoiny, potrzebujesz adresu. Adresy pochodzą z publicznej części publicznej-prywatnej pary kluczy kryptograficznych (patrz „Bitcoin dla początkujących, Część 2: Bitcoin jako technologia i sieć”). Rodzaj kryptografii używany przez Bitcoin nazywa się kryptografią krzywych eliptycznych (ECC). Kryptografia klucza publicznego, którą większość z nas zna, opiera się na trudności w znalezieniu czynników pierwszych dużych liczb całkowitych. Natomiast ECC opiera się na trudności w znalezieniu dyskretnego logarytmu krzywej eliptycznej. (Wyjaśnienie tego bardziej szczegółowo nie tylko doprowadziłoby nas do króliczej dziury wyższej algebry, ale także szybko przekroczyłoby moją matematykę na uczelni. Na szczęście nie musimy wiedzieć więcej, aby użyć ECKeyklasy BitCoinJ do reprezentowania i generowania klucza pary.)

W wierszu 20. listy 2 tworzymy nową parę kluczy krzywych eliptycznych, tworząc instancję obiektu typu ECKey. Zauważ, że domyślna toString()metoda klasy jest nadpisywana w celu zwrócenia klucza publicznego i prywatnego w notacji szesnastkowej, która jest używana w linii 23.

Listing 2. Tworzenie pary kluczy krzywych eliptycznych za pomocą 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

Możesz sobie przypomnieć, że publiczną częścią pary kluczy Bitcoin powinien być adres. Ale publiczna część klucza wygenerowana przez powyższy kod początkowo nie będzie wyglądać jak adresy, które klient Bitcoin wyświetla w swoim interfejsie użytkownika. Forma adresu, do której przyzwyczailiśmy się widzieć w transakcjach Bitcoin, pochodzi z powtarzających się operacji mieszania klucza publicznego. Ten formularz zawiera flagę wskazującą, do której z dwóch sieci Bitcoin należy klucz - do sieci produkcyjnej Bitcoin czy do sieci testowej. (Zobacz stronę wiki Bitcoin, aby uzyskać bardziej szczegółowy opis algorytmicznego tworzenia par kluczy Bitcoin.)

Różnicowanie sieci Bitcoin

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

WalletKlasa ma człon publicznego o nazwie keychain, która jest ArrayListtypu ECKey, który jest używany do przechowywania wszystkich par kluczy WE w portfelu. addKey(ECKey)Metoda służy do dodawania par kluczy, ale obecnie nie istnieje metoda usuwania ich. Ma to sens, ponieważ użytkownikom lub programom nie powinno być łatwo usunąć klucze prywatne: klucz prywatny jest wymagany, aby uzyskać dostęp do środków przesłanych za pośrednictwem odpowiadającego mu klucza publicznego. Bez pary kluczy w portfelu lub bez kopii zapasowej wszelkie wysłane środki zostaną utracone na zawsze.