Bitcoin for beginners, Part 3: The BitCoinJ API

Build a Java-based Bitcoin transaction client

For Java developers, BitCoinJ is an entry point to developing applications that interact with the Bitcoin network. In this final article in a three-part series, Dirk Merkel helps you set up BitCoinJ in an Eclipse development environment, then walks through several short exercises that will familiarize you with this lightweight implementation of the Bitcoin transaction protocol.

Previous installments in this three-part series have introduced the conceptual and technological framework of Bitcoin, a virtual currency and peer-to-peer network. This article, a tutorial introduction to the BitCoinJ API, assumes that you are familiar with Bitcoin addresses, transactions, blocks, and the block chain.

BitCoinJ is an open source Java implementation of the Bitcoin protocol. As such, it's a handy tool to have if you want to write Java applications that interact with the Bitcoin network. In order to explore the BitCoinJ API, we'll construct various sample applications that illustrate the programming steps necessary to construct more complex Bitcoin applications in Java. After using Maven to built and set up a project in the Eclipse IDE, we'll practice creating a Bitcoin address, storing it in a wallet, and saving the wallet to disk. We'll then establish a connection to the Bitcoin test network and retrieve its genesis block. Finally, we'll tie together our sample code so far by sending some Bitcoins to an address on the test network.

About BitCoinJ

BitCoinJ is a Java implementation of the Bitcoin protocol. Written by Mike Hearn, BitCoinJ is not a full implementation of the original Bitcoin client, but a more lightweight and accessible version. While it's solid enough to learn from, BitCoinJ is still under development (currently at v.0.3) and should not be used to move large numbers of Bitcoins.

Get started with BitCoinJ

BitCoinJ is hosted by Google Code in a Subversion repository, and can be anonymously checked out. Once you check out the trunk of the BitCoinJ project you'll be able to easily keep it updated. You will not, however, be able to commit any changes.

You can use the Subversion client built into your favorite IDE or simply check out the project from the command-line, as I did:

Figure 1. Check out BitCoinJ from the command-line (click to enlarge)

Once you have the code, you'll compile it with Maven, BitCoinJ's build system. Maven takes a lifecycle approach to building projects and is highly extensible with many core and third-party plugins. What Maven does exceedingly well is manage dependencies. If you look at the Maven pom.xml file in BitCoinJ's root directory, you'll see that it uses only a handful of dependencies; these include JUnit and EasyMock for unit testing, SLF4J for logging, and the Bouncy Castle Crypto APIs for cryptographic operations such as hashing and signing.

From the command-line, run mvn clean package and Maven will retrieve these and other dependencies, compile the project, run the unit test suite, and package the compiled code into a snapshot JAR file. As shown in Figure 2, Maven first executes the clean lifecycle to get rid of any artifacts from previous builds. It then executes the phases of the default lifecycle up to and including the package phase.

Figure 2. Maven compiles BitCoinJ and its dependencies (click to enlarge)

Maven has a few more helpful tricks up its sleeve. First, executing mvn site:site builds the BitCoinJ documentation, including pages about dependencies, issue tracking, mailing lists, license, development team, source repository, and others. These pages tend to be informative but basic. Executing mvn javadoc:javadoc generates the project's documentation, which will come in handy when we start to exercise the BitCoinJ API.

The documentation reveals that the API is divided into four packages:

  • Discovery deals with peer-to-peer network discovery/communication.
  • Store contains data structures for storing blocks and the block chain.
  • Examples includes a handful of simple applications based on BitCoinJ (these inspired my own examples for this article).
  • Core contains the majority of BitCoinJ's classes and functionality, including classes to communicate with peer nodes, download the block chain, and send and receive transactions.

Set up the example project in Eclipse

We'll develop the example code for this article in Eclipse, using Maven to manage BitCoinJ as a dependency. Fortunately, BitCoinJ has a continuous integration environment that builds the project, collects and reports on various artifacts, and deposits a snapshot JAR into the project's own Nexus-based Maven repository.

Figure 3 shows the Eclipse project-creation dialog that results from creating a new Maven project and selecting the "quickstart" archetype, which generates a basic Maven project. My code for this project lives in a package named com.waferthin.bitcoinj, which produces a 0.0.1-SNAPSHOT with the Maven build.

Figure 3. Creating a Maven project in Eclipse (click to enlarge)

Clicking Finish instructs the wizard to create the project, which means dropping a "Hello World" main class into the project directory -- named src/main/java/com/waferthin/bitcoinj in my case.

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|<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
002|  <modelVersion>4.0.0</modelVersion>
003|
004|  <groupId>com.waferthin.bitcoinj.explored</groupId>
005|  <artifactId>bitcoinj-explored</artifactId>
006|  <version>0.0.1-SNAPSHOT</version>
007|  <packaging>jar</packaging>
008|
009|  <name>bitcoinj-explored</name>
010|  <url>http://maven.apache.org</url>
011|
012|  <properties>
013|    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
014|  </properties>
015|
016|  <repositories>
017|    <!-- declare BitCoinJ repository name and location -->
018|    <repository>
019|      <id>bitcoinj-release</id>
020|      <releases/>
021|      022|<url>http://nexus.bitcoinj.org/content/repositories/releases</url>
023|    </repository>
024|    <repository>
025|      <id>bitcoinj-snapshot</id>
026|      <snapshots/>
027|      <url>http://nexus.bitcoinj.org/content/repositories/snapshots</url>
028|    </repository>
029|  </repositories>
030|
031|  <dependencies>
032|    <dependency>
033|      <groupId>junit</groupId>
034|      <artifactId>junit</artifactId>
035|      <version>3.8.1</version>
036|      <scope>test</scope>
037|    </dependency>
038|
039|    <!-- declare BitCoinJ dependency w/ version -->
040|    <dependency>
041|      <groupId>com.google</groupId>
042|      <artifactId>bitcoinj</artifactId>
043|      <version>0.3-SNAPSHOT</version>
044|      <scope>compile</scope>
045|    </dependency>
046|  </dependencies>
047|</project>

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|
009|    public static void main(String[] args) throws Exception {
010|
011|        // use test net by default
012|        String net = "test";
013|        
014|        if (args.length >= 1 && (args[0].equals("test") || args[0].equals("prod"))) {
015|            net = args[0];
016|            System.out.println("Using " + net + " network.");
017|        }
018|        
019|        // create a new EC Key ...
020|        ECKey key = new ECKey();
021|
022|        // ... and look at the key pair
023|        System.out.println("We created key:\n" + key);
024|        
025|        // either test or production net are possible
026|        final NetworkParameters netParams;
027|        
028|        if (net.equals("prod")) {
029|            netParams = NetworkParameters.prodNet();
030|        } else {
031|            netParams = NetworkParameters.testNet();
032|        }
033|        
034|        // get valid Bitcoin address from public key
035|        Address addressFromKey = key.toAddress(netParams);
036|        
037|        System.out.println("On the " + net + " network, we can use this address:\n" + addressFromKey);
038|    }
039|}

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

The Wallet class has a public member named keychain that is an ArrayList of type ECKey, which is used to store all EC key pairs in the wallet. The addKey(ECKey) method is used to add key pairs, but there is currently no method for removing them. This makes sense because it shouldn't be easy for users or programs to delete private keys: a private key is required to access funds sent via its corresponding public key. Without a key pair in the wallet or backed up somewhere, any sent funds would be lost forever.

Given a public key or its hash you can check whether a matching key pair is in the keychain and retrieve it using the following convenience methods:

findKeyFromPubHash(byte[] pubkeyHash)
isPubKeyHashMine(byte[] pubkeyHash)
findKeyFromPubKey(byte[] pubkey)
isPubKeyMine(byte[] pubkey)

Note that the only constructor for the Wallet class takes a NetworkParameters object as an argument. This ensures that you cannot mix transactions from the production and test networks in the same wallet.

Keys, wallet ...

In Listing 3 we default to the testnet (line 13) and declare a Wallet object (line 16) that will later require a File object (line 17) to persist itself to disk. In our main try-catch block, we then initialize the Wallet object to use the testnet (line 20). Next, we loop five times, each time creating a brand-new key pair in the form of an ECKey object, which we add to the wallet (line 26).

Having something in our wallet, we then proceed to save it to disk (line 30). If you were to take a look at your file system now, you would see a file named test.wallet. On line 37, we grab the first key in the keychain ArrayList and output it (line 40), followed by the dump of the whole wallet (line 43). Finally, we want to determine whether a particular key has been added to the wallet, so we ask the wallet to compare a given hash to the hashes of the public keys in the wallet (line 47).

Listing 3. CreateWallet

001|package com.waferthin.bitcoinj;
002|
003|import java.io.File;
004|import java.io.IOException;
005|
006|import com.google.bitcoin.core.*;
007|
008|public class CreateWallet {
009|
010|    public static void main(String[] args) {
011|
012|        // work with testnet
013|        final NetworkParameters netParams = NetworkParameters.testNet();
014|
015|        // Try to read the wallet from storage, create a new one if not possible.
016|        Wallet wallet = null;
017|        final File walletFile = new File("test.wallet");
018|        
019|        try {
020|            wallet = new Wallet(netParams);
021|            
022|            // 5 times
023|            for (int i = 0; i < 5; i++) {
024|                
025|                // create a key and add it to the wallet
026|                wallet.addKey(new ECKey());
027|            }
028|            
029|            // save wallet contents to disk
030|            wallet.saveToFile(walletFile);
031|            
032|        } catch (IOException e) {
033|            System.out.println("Unable to create wallet file.");
034|        }
035|        
036|        // fetch the first key in the wallet directly from the keychain ArrayList
037|        ECKey firstKey = wallet.keychain.get(0);
038|
039|        // output key 
040|        System.out.println("First key in the wallet:\n" + firstKey);
041|        
042|        // and here is the whole wallet
043|        System.out.println("Complete content of the wallet:\n" + wallet);
044|        
045|        // we can use the hash of the public key
046|        // to check whether the key pair is in this wallet
047|        if (wallet.isPubKeyHashMine(firstKey.getPubKeyHash())) {
048|            System.out.println("Yep, that's my key.");
049|        } else {
050|            System.out.println("Nope, that key didn't come from this wallet.");
051|        }
052|    }
053|}

Here is the output produced by the CreateWallet class:

First key in the wallet:
pub:04cf1b56e809dd615663d918824688264d81dbd3642550a82545df5bfa0dfeb5c1e1ba0d97fa278853e121678d13eb2f7e061281957933e9d4bd03893e80e14e0e priv:00e657901ce15ec38c234060e79dd99cda6f1d82ef4b3c90da65c84d6e9ce06a9e
Complete content of the wallet:
Wallet containing 0.00 BTC in:
  0 unspent transactions
  0 spent transactions
  0 pending transactions
  0 inactive transactions
  0 dead transactions

Keys:
  addr:n1QCia54L1MDR4xjQStM48vGnfQf62kh8p pub:04cf1b56e809dd615663d918824688264d81dbd3642550a82545df5bfa0dfeb5c1e1ba0d97fa278853e121678d13eb2f7e061281957933e9d4bd03893e80e14e0e priv:00e657901ce15ec38c234060e79dd99cda6f1d82ef4b3c90da65c84d6e9ce06a9e
  addr:moMovkB3uGTZrf66f5WddcNVhq6MuZUajJ pub:0423a79d67d612e44d06228bc47c9ac1ead8124929280ac827c2aa301075e27909ec2b5502eee7be40e08fba42a7e5c2daa91b1641fe1c0368068f65ea14c27d60 priv:00862ef8769d848ae56eebd211652f72667b353093f5db6139e81b7a787544a039
  addr:mrukZip4D6TG8TxEhhBLkKZvQY4fCPZxZn pub:04c11cdfbc6fbf838a03bd4d49df1957330a4105529054002f87a83d726a632ad7da257c0997aa52fa484382c675d6835f9f78b3c65366a2f36953e992404de63f priv:460343ee1e983fd0ad0ca0023f1b1aa4269ba34c7f17e8463856085669c0bc23
  addr:mgro3Ned1KakmVbP8hPf4iDDo6KDTpCzGL pub:046212ef2216273af27185493de1197ee4a21fef46dee0c27f026b765473c0cd1e1d62ea9f1ea2dbb16103b3c96bb31d78e102b2387ac0b03d67d671226dbb2117 priv:5a42597d63515df1a60ac0090ae55f52e0a8e6ec74e320041cb52605a643c178
  addr:myQqSQpk5mN1e4it1r3dxdyB6Cuu1tWjjo pub:04222d33fb1f89a217804a0400d34b48c08808fbbd22af5e408f04e45597ca3c061ca6dcfe04e4b483c3099caa718e4e5ba6260501b7d24ae9dcfa15844afffe13 priv:00ec4b1abee48a43fe4b12eff1e8fdacabd392554dc12f1cf1156467218cd92189

Yep, that's my key.

You may have noticed the the Wallet object's toString() method also reported on various types of transactions, such as unspent, spent, pending, inactive, and dead. Before the end of this article we'll use a wallet to generate an actual transaction and send it over to the network to a recipient.

Getting the genesis block

Next, we'll connect to a peer node on the Bitcoin network and request from it a single block. Specifically, we'll connect to a locally running Bitcoin node and retrieve the testnet's genesis block. The genesis block is the first in the sequence of blocks in the block chain. If you recall, the block chain is a data structure similar to a linked list that contains blocks of hierarchically organized transaction hashes, as well as the transactions themselves.

Each block header contains a hash that is a pointer to the previous block in the block chain. We can use the hash pointer to request a block from its network peers. Doing so lets us traverse the block chain and retrieve all the blocks needed to reconstruct the complete transaction history of the Bitcoin economy. The only block without a valid hash pointer is the genesis block, which has no previous block. In this example we will learn how to retrieve the genesis block by its hash, but we could use the same technique to retrieve any other block or to traverse the block chain.

You can also view the testnet's genesis block using Bitcoin Block Explorer: http://blockexplorer.com/testnet/b/0.

Rather than asking the node to return a single block, we could be downloading all blocks that would, in the right sequence, constitute the block chain. But before we look at the code itself, we need to study a couple of the classes in detail.

BlockChain and BlockStore

The BlockChain class understands the kind of data structure the block chain represents. Using the add(Block) method, one can add any number of blocks to the chain and the BlockChain class will verify the block's validity and try to place it at its correct location within the block chain list. As the Bitcoin economy expands, the block chain will continue to get longer. Clients download, store, and access the complete block chain. With the requirements this places on disk space and memory, it makes sense that BitCoinJ's developers decided to decouple the actual storage of the blocks in the chain from the data structure and logic, hence the BlockStore interface.

BlockStore contains four method signatures that must be implemented by any class that provides the actual block storage: put(StoredBlock) and get(Sha256Hash) allow developers to add and retrieve blocks, respectively. getChainHead() and setChainHead(StoredBlock) are accessor methods for the most recent block in the chain, the head.(As previously mentioned, BitCoinJ is not a full implementation of the Bitcoin protocol. One significant difference is that it stores only the block headers and discards the underlying transactions that are usually part of the block.)

Three classes currently implement the BlockStore interface and provide block storage. MemoryBlockStore keeps block headers in memory, which is fast and convenient, but not sustainable as the block chain grows. DiskBlockStore functions like MemoryBlockStore, but also saves the headers to disk. Lastly, BoundedOverheadBlockStore is an implementation intended for resource constrained environments, trading constant resource usage for performance predictability.

Given that we will not be downloading the whole block chain, the MemoryBlockStore will work just fine for our example. The above three BlockStore implementations are the ones currently included in the Bitcoin project. Various others are being worked on, however, including ones based on SQLite and various flavors of NoSQL. These are often glorified HashMaps and thus a perfect fit for Bitcoin.

Peer

Another class we need to understand for our example is the Peer class. It handles the high-level communications between our client and a particular node on the network. Under the hood, it depends on classes such as NetworkConnection, Block, and BlockChain to do its work. In standard use of BitCoinJ, the application will connect to any number of nodes and instantiate as many Peer objects to handle the connections. After calling the connect() method on the Peer object, the code handling messages from other nodes runs in a loop and needs to run in a thread, which is what you will see in the next example.

Requesting the genesis block from a network peer

Given that knowledge of BitCoinJ's internals we can quickly step through the next example. Listing 4 starts by instantiating an object representing parameters for the testnet (line 19) and uses it to initialize a MemoryBlockStore object (line 22). We declare a BlockChain object (line 25) and initialize it inside a try-catch block (line 30). The BlockChain object requires both a NetworkParameters and BlockStore object as arguments.

We then instantiate a Peer object while telling it to use the testnet, connect to a node on localhost, and use the previously instantiated BlockChain object for storage (line 33). After actually connecting to the peer node (line 36), we execute the Peer object's message handling loop (line 39). A more typical use case would be to have multiple peer node connections, in which case we would probably run each Peer object's message-handling loop in its own thread. Because we're dealing with a single node directly, that is not necessary in our example. Having found the hash of the testnet's genesis block on the Bitcoin Block Explorer site, we create a Sha256Hash object (line 50) and ask the peer object to request the block with the corresponding hash from the peer node (line 54). After receiving the block (line 58), we output it, which the Block class's overwritten toString() method does quite nicely (line 59).

Listing 4. FetchGenesisBlock

001|package com.waferthin.bitcoinj;
002|
003|import java.io.IOException;
004|import java.net.InetAddress;
005|import java.net.UnknownHostException;
006|import java.util.concurrent.ExecutionException;
007|import java.util.concurrent.Future;
008|
009|import com.google.bitcoin.core.*;
010|import com.google.bitcoin.store.BlockStore;
011|import com.google.bitcoin.store.BlockStoreException;
012|import com.google.bitcoin.store.MemoryBlockStore;
013|
014|public class FetchGenesisBlock {
015|
016|    public static void main(String[] args) {
017|
018|        // work with testnet
019|        final NetworkParameters netParams = NetworkParameters.testNet();
020|
021|        // data structure for block chain storage
022|        BlockStore blockStore = new MemoryBlockStore(netParams);
023|
024|        // declare object to store and understand block chain
025|        BlockChain chain;
026|        
027|        try {
028|            
029|            // initialize BlockChain object
030|            chain = new BlockChain(netParams, blockStore);
031|            
032|            // instantiate Peer object to handle connections
033|            final Peer peer = new Peer(netParams, new PeerAddress(InetAddress.getLocalHost()), chain);
034|
035|            // connect to peer node on localhost
036|            peer.connect();
037|            
038|            // run Peer's message handling loop in a thread
039|            new Thread(new Runnable() {
040|                public void run() {
041|                    try {
042|                        peer.run();
043|                    } catch (PeerException e) {
044|                        throw new RuntimeException(e);
045|                    }
046|                }
047|            }).start();
048|
049|            // we found the hash of the genesis block on Bitcoin Block Explorer 
050|            Sha256Hash blockHash = new Sha256Hash("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
051|            
052|            // ask the node to which we're connected for the block
053|            // and wait for a response
054|            Future<Block> future = peer.getBlock(blockHash);
055|            System.out.println("Waiting for node to send us the requested block: " + blockHash);
056|            
057|            // get and use the Block's toString() to output the genesis block
058|            Block block = future.get();
059|            System.out.println("Here is the genesis block:\n" + block);
060|            
061|            // we're done; disconnect from the peer node
062|            peer.disconnect();
063|
064|        // handle the various exceptions; this needs more work
065|        } catch (BlockStoreException e) {
066|            e.printStackTrace();
067|        } catch (UnknownHostException e) {
068|            e.printStackTrace();
069|        } catch (PeerException e) {
070|            e.printStackTrace();
071|        } catch (IOException e) {
072|            e.printStackTrace();
073|        } catch (InterruptedException e) {
074|            e.printStackTrace();
075|        } catch (ExecutionException e) {
076|            e.printStackTrace();
077|        }
078|    }
079|}

Below is the output produced by running our example.

Waiting for node to send us the requested block: 00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008
Here is the genesis block:
v1 block: 
   previous block: 0000000000000000000000000000000000000000000000000000000000000000
   merkle root: 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b
   time: [1296688602] Wed Feb 02 15:16:42 PST 2011
   difficulty target (nBits): 487063544
   nonce: 384568319
   with 1 transaction(s):
     == COINBASE TXN (scriptSig [4]ffff001d ?(4) [69]5468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73 )  (scriptPubKey [65]04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f CHECKSIG )

Sending Bitcoins

For our last exercise we will create a small application to send Bitcoins from our wallet to a Bitcoin address. For this task, we will use the Wallet class's sendCoins(Peer peer, Address to, BigInteger nanocoins) method.

If you want to experiment with the test network, you can get Bitcoins for free from Bitcoin Faucet.

Unlike in the other examples, this time we will get all our input from the command line. Our application will require the following arguments in the order given:

  1. Which network ("test" or "prod")
  2. The name of the wallet file containing Bitcoins
  3. Number of nano Bitcoins to send
  4. Bitcoin address of the recipient

In Listing 5 we handle the command-line arguments (lines 18 to 29) and initialize various components we have seen before, including instances of the NetworkParameters, BlockChain, Wallet, and Peer classes. The amount to send is specified as a BigInteger, where each unit represents 1/100000000th of a Bitcoin (line 59). We instantiate an Address object based on a Bitcoin address provided by the standard client (line 71). We then invoke the Wallet class's sendCoins() method to initiate the transaction (line 74). A return value of null would indicate that not enough funds were in the wallet for the requested transaction. Otherwise, we output a confirmation and a link to our send transaction on the Bitcoin Block Explorer site.

Listing 5. SendCoins

001|package com.waferthin.bitcoinj;
002|
003|import java.io.File;
004|import java.io.IOException;
005|import java.math.BigInteger;
006|import java.net.InetAddress;
007|import java.net.UnknownHostException;
008|
009|import com.google.bitcoin.core.*;
010|import com.google.bitcoin.store.BlockStore;
011|import com.google.bitcoin.store.BlockStoreException;
012|import com.google.bitcoin.store.MemoryBlockStore;
013|
014|public class SendCoins {
015|
016|    public static void main(String[] args) {
017|
018|        if (args.length != 4) {
019|            System.out.println("Usage: java SendCoins prod|test wallet amount recipient");
020|            System.exit(1);
021|        }
022|        
023|        // we get the following from the command line ...
024|        // (this is not secure - needs validation)
025|        String network          = args[0];  // "test" or "prod"
026|        String walletFileName   = args[1];  // wallet file name
027|        String amountToSend     = args[2];  // milli-BTC
028|        String recipient        = args[3];  // Bitcoin address
029|
030|        // the Bitcoin network to use
031|        final NetworkParameters netParams;
032|        
033|        // check for production Bitcoin network ...
034|        if (network.equalsIgnoreCase("prod")) {
035|            netParams = NetworkParameters.prodNet();
036|        // ... otherwise use the testnet
037|        } else {
038|            netParams = NetworkParameters.testNet();
039|        }
040|
041|        // data structure for block chain storage
042|        BlockStore blockStore = new MemoryBlockStore(netParams);
043|
044|        // declare object to store and understand block chain
045|        BlockChain chain;
046|        
047|        // declare wallet
048|        Wallet wallet;
049|        
050|        try {
051|            
052|            // wallet file that contains Bitcoins we can send
053|            final File walletFile = new File(walletFileName);
054|
055|            // load wallet from file
056|            wallet = Wallet.loadFromFile(walletFile);
057|            
058|            // how man milli-Bitcoins to send
059|            BigInteger btcToSend = new BigInteger(amountToSend);
060|                    
061|            // initialize BlockChain object
062|            chain = new BlockChain(netParams, wallet, blockStore);
063|
064|            // instantiate Peer object to handle connections
065|            final Peer peer = new Peer(netParams, new PeerAddress(InetAddress.getLocalHost()), chain);
066|
067|            // connect to peer node on localhost
068|            peer.connect();
069|            
070|            // recipient address provided by official Bitcoin client
071|            Address recipientAddress = new Address(netParams, recipient);
072|
073|            // tell peer to send amountToSend to recipientAddress
074|            Transaction sendTxn = wallet.sendCoins(peer, recipientAddress, btcToSend);
075|            
076|            // null means we didn't have enough Bitcoins in our wallet for the transaction
077|            if (sendTxn == null) {
078|                System.out.println("Cannot send requested amount of " + Utils.bitcoinValueToFriendlyString(btcToSend)
079|                                + " BTC; wallet only contains " + Utils.bitcoinValueToFriendlyString(wallet.getBalance()) + " BTC.");
080|            } else {
081|                
081|                // once communicated to the network (via our local peer),
083|                // the transaction will appear on Bitcoin explorer sooner or later
084|                System.out.println(Utils.bitcoinValueToFriendlyString(btcToSend) + " BTC sent. You can monitor the transaction here:\n"
085|                                + "http://blockexplorer.com/tx/" + sendTxn.getHashAsString());
086|            }
087|
088|            // save wallet with new transaction(s)
089|            wallet.saveToFile(walletFile);
090|
091|        // handle the various exceptions; this needs more work
092|        } catch (BlockStoreException e) {
093|            e.printStackTrace();
094|        } catch (UnknownHostException e) {
095|            e.printStackTrace();
096|        } catch (PeerException e) {
097|            e.printStackTrace();
098|        } catch (AddressFormatException e) {
099|            e.printStackTrace();
100|        } catch (IOException e) {
101|            e.printStackTrace();
102|        }
103|    }
104|}

Following is the output from running the command line: java com.waferthin.bitcoinj.SendCoins prod sendcoins-prodnet.wallet 2000000 13RwREqwoNhVkcbpKSUMg9Ea6JnNuy85Qz:

0.02 BTC sent. You can monitor the transaction here:
http://blockexplorer.com/tx/078e0fc3577a039afac327c6509aa0e0cc680a51011ebb67486b5fc05e28a139

Figure 4 shows the coins being received at the recipient address.

Figure 4. Coins being received (click to enlarge)

After a few minutes we can view the transaction online at the Bitcoin Block Explorer link provided by the application:

Figure 5. View the transaction with Bitcoin Block Explorer (click to enlarge)

In conclusion

That's it for our whirlwind tour of the BitCoinJ project. There is still much functionality that was not covered in this article, but with a solid understanding of the basic components provided by BitCoinJ, you should be able fill in the blanks. A worthwhile followup exercise would be downloading the whole block chain and iterating over it while outputting some piece of information about each block. Also, figuring out how to receive Bitcoins would be another instructive exercise.

Hopefully you can take what you have learned in this article as a starting point for creating more complex applications. Maybe you can even start contributing to the BitCoinJ project itself.

Dirk Merkel is the CTO at VivanTech Inc. He has been developing software in a variety of languages for over 25 years and has been getting paid for it for over 15 years. In his spare time, he likes to learn about new technologies and ruin perfectly good open-source projects by submitting unsolicited patches. He also writes about technology, software development, and architecture. He lives in San Diego with his lovely wife and two wonderful daughters. Dirk can be reached at dmerkel@vivantech.com.

Learn more about this topic

More from JavaWorld

  • See the JavaWorld Site Map for a complete listing of research centers focused on client-side, enterprise, and core Java development tools and topics.
  • JavaWorld's Java Technology Insider is a podcast series that lets you learn from Java technology experts on your way to work.
Join the discussion
Be the first to comment on this article. Our Commenting Policies