When writing software that interacts with the Bitcoin network, it is very important to have tools that allow rapid development. If you are interacting with a Bitcoin node, this can be a little bit of a hassle to do. At TokenSoft, our development environment has evolved so that each developer spins up a dockerized bcoin node running in Regtest for local testing. The path to get it up and running wasn’t immediately obvious, so I wanted to share how we did it.

What is Regtest?

Regtest is a mode of running bcoin where it doesn’t need to connect to any other nodes, it does not require proof of work to generate and mine a block, and it follows the rules of the Bitcoin network to make it easy to test and validate your code. As you are testing or running your software, you can mine blocks to get bitcoin in your wallets. Then you can create a transaction to send the fund and immediately mine a block to see it get mined, without having to wait 10 minutes, as the mainnet or testnet would require.

Setting up the Docker Container

For our setup, we used the bcoin docker file as a starting point. Ours is a bit different, but the main things it does are:

Installs build dependencies like Python and build tools

Clones the bcoin repo for a specific version

Installs the production bcoin

Sets the startup command to a bash script

The bash script will launch bcoin using the regtest flag, set an API password, and also a coinbase address so it can mine.

Additionally we have another shell script that runs in the background that will mine blocks every 10 seconds.

The last item to note is the ports that the RPC API and the Wallet API are running on (48332 and 48334 respectively). Make sure those are open for incoming connections.

You can see the full setup here on Github.

Sending a Transaction

Once you get the docker instance running, the first thing to play around with is the command line client tools. You can install them by running:

> npm install -g bclient

Once this is installed, save off the common command line params and you can execute commands against the node:

> export params="--network=regtest --http-host=0.0.0.0 --wallet-http-host=0.0.0.0 --api-key=secretpw"

> bcoin-cli $params info

Next, we can use the default account to test with. First we can get an address for the wallet

> bwallet-cli $params --id=primary --account=default address

...

"address": "RN4QRNUF1BFkT4Xz3vxhPPawbA33DHY6k5"

Then we can mine some BTC to it:

> bcoin-cli $params rpc generatetoaddress 1 RN4QRNUF1BFkT4Xz3vxhPPawbA33DHY6k5

Then we can send some BTC to a random address:

> bwallet-cli $params send --id=primary --value=1 --address=RLzyQ3AAHEdijrZvmTPWsWrSi8YwZ8VV3T

Error: Not enough funds. (available=0.0, required=1.0000156)

Wait… why did it fail? Let’s see the balance:

> bcoin-cli $params info

"confirmed": 2500000000

If we have enough BTC, why did it tell us we didn’t? Welcome to Bitcoin, where all error messages are not helpful and just be happy when it did give you an error message at all. In this case, the bitcoin network is preventing us from sending it out since newly mined BTC cannot be spent until after 100 confirmations. Not to worry… we can mine more blocks easily and try again.

> bcoin-cli $params rpc generatetoaddress 100 RN4QRNUF1BFkT4Xz3vxhPPawbA33DHY6k5 > bwallet-cli $params send --id=primary --value=1 --address=RLzyQ3AAHEdijrZvmTPWsWrSi8YwZ8VV3T {

"hash": "91ffc7834df017512f...

...

}

And there you have it… we were able to send some BTC out of the wallet and then in 10 seconds it will get mined.

Other Gotchas:

Addresses have a unique header (format) that are not compatible with other networks or bitcoin nodes. This can be a bit of a pain if you are trying to test with other software since it will tell you that your address is invalid.

Segwit isn’t immediately active since the bcoin node simulates going through the activation logic. To get around this we sometimes just mine 500 blocks at startup to not need to worry about it.

Block halving is only 150 blocks. This means that the rewards for mining drop off dramatically as you run the node. You could fork it and just update it to a larger number:

(networks.js)

regtest.halvingInterval = 150; // Change this to a larger number

And here’s our requisite Bitcoin-related image

Support

The bcoin team is pretty awesome, so if you have any questions, make sure to check out the api docs and then reach out to them on their slack channel.