Bitcoin and JUnit

How to unit test bitcoin with Java and JUnit.

Bitcoin and blockchain are hot topics today. Many related projects are already out there and much more are being developed right now. If you are a developer in this area, then you know how important and tricky is to have bullet proof testing in place. In this article I will briefly describe the options for testing bitcoin and then go into more detail of the one which you can run easily and offline. Please note that this article is focusing purely on Bitcoin.

Testing options

There are 3 possible modes or stages for testing bitcoin applications.

  1. Regtest mode
  2. Test on the testnet
  3. Test on the mainnet

Regtest mode is what I would recommend to start with. It allows you to run the node on your local computer just as a sandbox, completely isolated from the internet. And it has one very useful feature. You are fully in control of the block generation and new blocks can be 'mined' just by calling a simple command. This removes the need to wait for blocks to be mined. Also you have unlimited number of coins to play with, because all the mining awards go to the account on your local node.

Testnet, as name suggested, is a place which behaves almost the same as real Bitcoin network, is a fully functional network. This includes real mining, necessary waiting time and a need to account for activity of other people. Differences are that coins doesn't have any value, anyone can get small amount of free test coins and the whole network gets nuked time to time. It's a good next step after having a working system on the regtest.

Finally mainnet is the network where the real transactions are happening. Bugs can become very expensive here. So better to leave this for the final test, after being confident that everything is working as planned.

I believe that during application development you should walk through all 3 stages. The rest of this article will show how to connect regtest mode with junit. First, let's just get a little bit familiar with bitcoind, a program which implements Bitcoin protocol and can act as a node.

Running local node

Start with software installation. I prefer Bitcoin Unlimited. Download latest version of Official Bitcoin (BTC) Release for your platform and unzip / install it. Open console and navigate to the folder with binaries. Local node in the regtest mode can be started following command.

  • bitcoind -regtest -txindex=1 -server -rpcallowip=127.0.0.1 -rpcport=18332 -rpcuser=user -rpcpassword=Password1

There are many parameters you can put into the command, reference is here. Important ones are those which specify regtest mode, data directory and open JSON-RPC port for clients.

Next step is to open second console, navigate to the same directory, and use JSON-RPC client to perform actions. Following sequence generates blocks, sends coins to the specified address and generates next set of blocks to simulate transaction progress in chain.

  • bitcoin-cli -regtest -rpcport=18332 -rpcuser=user -rpcpassword=Password1 generate 101
  • bitcoin-cli -regtest -rpcport=18332 -rpcuser=user -rpcpassword=Password1 getbalance
  • bitcoin-cli -regtest -rpcport=18332 -rpcuser=user -rpcpassword=Password1 sendtoaddress put_your_address_here 10
  • bitcoin-cli -regtest -rpcport=18332 -rpcuser=user -rpcpassword=Password1 generate 7

If you have made it up to here, then you should be able to test your application and restart chain from the beginning (by deleting data directory) whenever you want. For the moment all done manually. Next chapter will show you how to automate this.

Regtest and junit

Here is the project source code. It's java maven project which contains a single unit test and can be invoked from command line just by mvn test. Bitcoin binaries for Windows are included. If you are using different platform, then please download and replace the binaries.

Coding is pretty straightforward and can be summarized in the following points.

  • Clean up the data directory and start bitcoind process inside the test setup
  • Tested client connects to the node during the test case as needed
  • New blocks are generated on demand (there is a method for that)
  • Bitcoind process is stopped during the test tear down

Note: Depending on your environment you might need to deal with 2 issues - permissions and firewall.

Here is how you start new bitcoind process.

ProcessBuilder processBuilder = new ProcessBuilder(BIN_DIR_PATH + "/bitcoind.exe", "-regtest",
        "-datadir=" + dataDir.getAbsolutePath(), "-txindex=1", "-server",
        "-rpcallowip=127.0.0.1", "-rpcport=18332", "-rpcuser=user", "-rpcpassword=Password1");
processBuilder.directory(new File("src/test/resources/bitcoinUnlimited-1.0.3/bin"));
try {
    bcProcess = processBuilder.start();
    Thread.sleep(5000);
} catch (IOException e) {
    throw new RuntimeException("error during process start", e);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}

Variable bcProcess is defined in the test class and is used in a tear down method to close the process. 5 seconds thread sleep is more tricky. processBuilder.start() method returns immediately when process is started. Unfortunately the bitcoind is not initialized at that point so connection would fail. In this particular case reasonable waiting time just makes the job.

Next how to stop the process.

        try {
            bcProcess.getInputStream().close();
            bcProcess.getErrorStream().close();
            bcProcess.getOutputStream().close();
            bcProcess.destroy();
            bcProcess = null;
            Thread.sleep(1000);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

That's the whole "magic". The rest of the code just cleans up the working directory before test and invokes the actual test. For more details, please look to the source code.

Summary

As you can see the java code to run bitcoin node and interact with it is easy and it works. You can write test cases which runs relatively fast and have guaranteed environment. Portion which I don't really like is the dependency on the native program. Especially while imagining handling multiple chains on the multiple systems. Then the amount of necessary binaries can grow up significantly. I have in my mind couple of ways how to resolve that. Please let me know if you have an elegant solution for that.

GET NEW CONTENT STRAIGHT INTO YOUR BOX


Preview

Anomaly detection using the Bag-of-words model

A practical method of finding anomalies within the set of activities using the Bag-of-words model.

Preview

Unit-Level Performance tuning in Java

How to simply improve performance of your java applications. Everything purely in IDE, without even starting the whole app.

Preview

Bitcoin and JUnit

How to unit test bitcoin with Java and JUnit.

Preview

Brittle POJO

POJO pattern is pretty popular in Java world. This article demonstrates what's wrong with that.