btcjson: The bitcoin JSON-RPC package from btcd

We recently announced btcd, an alternative full-node implementation of the bitcoin wire protocol and block validation written in Go that is under active development.

btcwire was the first package released, and now we would like to announce the public preview of our second package, btcjson, the JSON-RPC package from btcd:

Bitcoin provides an extensive API for controlling and communicating with the client using JSON RPC calls.  Package btcjson provides data structures and functions to simplify doing this when using Go.  Although btcjson was primarily written for btcd, it is a standalone library and can be used to write tools to communicate with any client that implements the same API as bitcoind.  For example, BlockSafari uses btcjson to get block and transaction data out of btcd (although in testing it has also used bitcoind).

Overall Design and Use

The overall design of the package focuses on providing functions that take input, checking that the input is correct for the command being called, generating a JSON message, sending it to the bitcoin client that is listening, and then returning a Go data structure with the reply. In actual code, use the following code to generate a message and send it:

// Generate a getblockhash message
msg, err := btcjson.CreateMessage("getblockhash", 235372)

// Send message and get the reply
reply, err := btcjson.RpcCommand(user, password, server, msg)

Other than imports and error checking, that is all the code required to ask the bitcoin client for the hash of block 235,372 (a random example).

The majority of the code in btcjson (other than testing) does error checking on the inputs in CreateMessage for the over 60 API calls for bitcoin.

Go and JSON

The most interesting thing about the code is actually the way one can deal with JSON in Go. One can simply define a struct with the fields you want and then use json.Marshal and json.Unmarshal to move between Go data structures and JSON messages. As anyone who has written code to parse machine readable formats like JSON (or XML) in other languages (Perl/XML in my case), it is rarely that simple, so using Go cut down on the amount of code needed dramatically. Combined with []interface{}, this allows for very flexible generation and reading of messages.

The next section is mainly of interest to Go coders or someone who is considering coding in Go.

For example, we define the following structure to handle the reply to the getblockhash message above:

type Reply struct {
    Result int `json:"result"`
    Id *string `json:"id"`

Then when we have received a reply as JSON, we can simple put it in the structure with:

var result Reply
err = json.Unmarshal(message, &result)

If there are several possible forms of the reply, as is the case for btcjson since each command returns different data, we can use the json.RawMessage feature of Go’s JSON library to do this in a much more flexible way. First, we modify the original struct so the Result line is replaced by an interface:

Result interface{} `json:"result"`

Then when we first unmarshal the reply, we do it this way:

var objmap map[string]json.RawMessage
err = json.Unmarshal(message, &objmap)

We can now examine the objmap and unmarshal it piece by piece to structures that match the data in it. For example:

var res InfoResult
err = json.Unmarshal(objmap["result"], &res)

where InfoResult is a struct that matches the data we expect for the info command.

For a more complete example, see the function readResultCmd in btcjson.

Test Coverage

As we stated in our previous release, we are taking code testing very seriously. This includes comparing behavior against bitcoind. In the case of btcjson, currently any difference in messages between btcd and bitcoind is being treated as a bug and dealt with. The current test coverage (using the great gocov tool) for btcjson is 88.75% although I will be working on this in the coming days and hope to reach 100% as quickly as btcwire did.

What’s Next?

We are currently releasing btcd in a staggered fashion, one package at a time. This allows us to get the code in the community’s hands faster and has the added benefit of ensuring that different parts of the code are kept in properly encapsulated packages. We plan on announcing the next piece here soon.

One thought on “btcjson: The bitcoin JSON-RPC package from btcd”

Leave a Reply

Your email address will not be published. Required fields are marked *