初心者のためのビットコイン、パート3:BitCoinJ API

Java開発者にとって、BitCoinJは、ビットコインネットワークと相互作用するアプリケーションを開発するためのエントリポイントです。3部構成のシリーズのこの最後の記事では、Dirk MerkelがEclipse開発環境でのBitCoinJのセットアップを支援し、次に、ビットコイントランザクションプロトコルのこの軽量実装に慣れるためのいくつかの短い演習を行います。

この3部構成のシリーズの前回の記事では、仮想通貨およびピアツーピアネットワークであるビットコインの概念的および技術的フレームワークを紹介しました。この記事は、BitCoinJ APIのチュートリアルの紹介であり、ビットコインアドレス、トランザクション、ブロック、およびブロックチェーンに精通していることを前提としています。

BitCoinJは、ビットコインプロトコルのオープンソースJava実装です。そのため、ビットコインネットワークと相互作用するJavaアプリケーションを作成する場合に便利なツールです。BitCoinJ APIを探索するために、Javaでより複雑なビットコインアプリケーションを構築するために必要なプログラミング手順を説明するさまざまなサンプルアプリケーションを構築します。Mavenを使用してEclipseIDEでプロジェクトをビルドおよびセットアップした後、ビットコインアドレスを作成し、ウォレットに保存し、ウォレットをディスクに保存する練習をします。次に、ビットコインテストネットワークへの接続を確立し、そのジェネシスブロックを取得します。最後に、テストネットワーク上のアドレスにいくつかのビットコインを送信することにより、これまでのサンプルコードを結び付けます。

BitCoinJについて

BitCoinJは、ビットコインプロトコルのJava実装です。マイクハーンによって書かれたBitCoinJは、元のビットコインクライアントの完全な実装ではなく、より軽量でアクセスしやすいバージョンです。学ぶには十分堅実ですが、BitCoinJはまだ開発中であり(現在はv.0.3)、多数のビットコインを移動するために使用しないでください。

BitCoinJを始めましょう

BitCoinJはGoogleCodeによってSubversionリポジトリでホストされており、匿名でチェックアウトできます。BitCoinJプロジェクトのトランクをチェックアウトすると、簡単に最新の状態に保つことができます。ただし、変更をコミットすることはできません。

私が行ったように、お気に入りのIDEに組み込まれているSubversionクライアントを使用するか、コマンドラインからプロジェクトをチェックアウトすることができます。

コードを入手したら、BitCoinJのビルドシステムであるMavenを使用してコードをコンパイルします。 Mavenは、プロジェクトの構築にライフサイクルアプローチを採用しており、多くのコアおよびサードパーティのプラグインで高度に拡張可能です。 Mavenが非常にうまく機能しているのは、依存関係を管理することです。 BitCoinJのルートディレクトリにあるMavenpom.xmlファイルを見ると、ほんの一握りの依存関係しか使用していないことがわかります。これらには、ユニットテスト用のJUnitとEasyMock、ロギング用のSLF4J、ハッシュや署名などの暗号化操作用のBouncy Castle CryptoAPIが含まれます。

コマンドラインから、runmvn clean packageとMavenはこれらの依存関係やその他の依存関係を取得し、プロジェクトをコンパイルし、単体テストスイートを実行し、コンパイルされたコードをスナップショットJARファイルにパッケージ化します。図2に示すように、Mavenは最初にクリーンライフサイクルを実行して、以前のビルドからのアーティファクトを取り除きます。次に、パッケージフェーズまでのデフォルトライフサイクルのフェーズを実行します。

Mavenには、さらに役立つトリックがいくつかあります。まず、実行mvn site:siteすると、依存関係、問題追跡、メーリングリスト、ライセンス、開発チーム、ソースリポジトリなどに関するページを含む、BitCoinJドキュメントが作成されます。これらのページは有益ですが基本的な傾向があります。実行mvn javadoc:javadocすると、プロジェクトのドキュメントが生成されます。これは、BitCoinJAPIの実行を開始するときに役立ちます。

ドキュメントは、APIが4つのパッケージに分割されていることを明らかにしています。

  • ディスカバリーは、ピアツーピアネットワークのディスカバリー/通信を扱います。
  • ストアには、ブロックとブロックチェーンを格納するためのデータ構造が含まれています。
  • 例には、BitCoinJに基づくいくつかの単純なアプリケーションが含まれています(これらは、この記事の私自身の例に影響を与えました)。
  • Coreには、ピアノードとの通信、ブロックチェーンのダウンロード、トランザクションの送受信を行うクラスなど、BitCoinJのクラスと機能の大部分が含まれています。

Eclipseでサンプルプロジェクトをセットアップします

Mavenを使用してBitCoinJを依存関係として管理し、Eclipseでこの記事のサンプルコードを開発します。幸い、BitCoinJには、プロジェクトを構築し、さまざまなアーティファクトを収集してレポートし、スナップショットJARをプロジェクト自体のNexusベースのMavenリポジトリに格納する継続的インテグレーション環境があります。

図3は、新しいMavenプロジェクトを作成し、基本的なMavenプロジェクトを生成する「クイックスタート」アーキタイプを選択した結果のEclipseプロジェクト作成ダイアログを示しています。このプロジェクトの私のコードはcom.waferthin.bitcoinj、Mavenビルドで0.0.1-SNAPSHOTを生成するという名前のパッケージにあります。

[完了]をクリックすると、ウィザードにプロジェクトを作成するように指示されます。つまり、「HelloWorld」メインクラスをプロジェクトディレクトリsrc/main/java/com/waferthin/bitcoinj(私の場合は名前)にドロップします。

Finally, we need to tell Maven that the project depends on the BitCoinJ snapshot, as shown in Listing 1. I edited Maven's wizard-generated pom.xml file to declare the location and name of BitCoinJ's Nexus repository (lines 18 through 28) and set the version to depend on for the build (lines 39 through 45):

Listing 1. Maven pom.xm for the BitCoinJ project

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|

That's all there is to it. In the next section we'll import the BitCoinJ classes into our code and build a BitCoinJ project with Maven, all without having to copy the actual JAR file.

Creating a Bitcoin address

To send or receive Bitcoins, you need an address. Addresses are derived from the public portion of a public-private cryptographic key pair (see "Bitcoin for beginners, Part 2: Bitcoin as a technology and network"). The kind of cryptography used by Bitcoin is called elliptic curve cryptography (ECC). The public-key cryptography most of us know is based on the difficulty of finding the prime factors of large integers. In contrast, ECC is based on the difficulty of finding the discrete logarithm of an elliptic curve. (Explaining this in more detail would not only lead us down the rabbit-hole of higher algebra, but would also quickly exceed my college math. Fortunately, we don't need to know more in order to use BitCoinJ's ECKey class to represent and generate key pairs.)

In line 20 of Listing 2, we create a new elliptic curve key pair by instantiating an object of type ECKey. Note that the class's default toString() method is overwritten to return the public and private key in hex notation, which is used on line 23.

Listing 2. Creating an elliptic curve key pair with 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

このWalletクラスには、タイプのパブリックメンバーkeychainがあります。これは、すべてのECキーペアをウォレットに格納するために使用されます。この方法はキーペアを追加するために使用されますが、現在、それらを削除する方法はありません。ユーザーやプログラムが秘密鍵を削除するのは簡単ではないため、これは理にかなっています。対応する公開鍵を介して送金された資金にアクセスするには、秘密鍵が必要です。ウォレットにキーペアがないか、どこかにバックアップされていないと、送金された資金は永久に失われます。ArrayListECKeyaddKey(ECKey)