7

I am having problems communicating between Java and bitcoind - every JSON RPC library I try has some issues. Can anyone provide a working implementation of even the most basic JSON RPC communication between Java and bitcoind ?

1
  • There's a bitcoin library for java... That could be why few people are working on a JSON RPC for java.
    – lurf jurv
    Commented Feb 10, 2013 at 16:40

9 Answers 9

7

Here's an early experimental client I had played around with a while back. It supports getInfo, getBalance and getNewAddress, and can easily be expanded. In order to run it, the credentials for your local bitcoind have to match the values in the client class:

httpclient.getCredentialsProvider().setCredentials(new AuthScope("localhost", 8332),
                    new UsernamePasswordCredentials("btc", "123"));

Feel free to use this code in any way, but understand that it's only 5 minutes of work on a start, not a realistic client implementation. Hope it helps you generate some ideas!

1
  • I like this solution a lot, the only issue is that the first call on this client takes very long. A 'getrawtransaction' call on my laptop takes 288 ms suing this http client while running a process from Java takes ~ 5 ms. However, this client is more efficient in the long run taking about 4 ms on average for all other calls. I tried to speed it up by trying to use cookie authentification but was not able... Solutions to this problem are welcome!
    – Pedro
    Commented Jan 19, 2020 at 20:14
4

You are also very welcome to try out https://github.com/clanie/bitcoind-client - it is in early development, but already supports almost all the methods provided by bitcoind.

3

I had the same issue and created an implementation here: https://github.com/johannbarbie/BitcoindClient4J

3

Because this seems like a collection of links, I will just add another one:

https://github.com/priiduneemre/btcd-cli4j

2

Library under Apache Licence: https://github.com/SulacoSoft/BitcoindConnector4J

2

https://github.com/nitinsurana/Litecoin-Bitcoin-RPC-Java-Connector

It uses Htmlunit instead of Apache Http Library, which makes it a bit easy to understand and extend.

I actually wrote & tested it for Litecoin for one of my projects. But it has been extended to support bitcoin and all the RPC methods are available.

1

Since I could not find working code snippet anywhere, here is a complete working example (in Scala):

First I created a helper object:

import java.net.URL
import java.net.HttpURLConnection
import org.apache.commons.io.IOUtils

object CurlJsonData {
  def curl(url:String, jsonEncodedString:String) = {
    val httpcon = new URL(url).openConnection.asInstanceOf[HttpURLConnection]
    httpcon.setDoOutput(true);
    httpcon.setRequestProperty("Content-Type", "application/json");
    httpcon.setRequestProperty("Accept", "application/json");
    httpcon.setRequestMethod("POST");
    httpcon.connect;

    val outputBytes = jsonEncodedString.getBytes("UTF-8");

    // 'using' method from: https://stackoverflow.com/a/5218279/243233

    using(httpcon.getOutputStream){os =>
      os.write(outputBytes)
    }
    val code = httpcon.getResponseCode
    val isError = code >= 400 && code <= 500
    val resp = using{
      if (isError) httpcon.getErrorStream else httpcon.getInputStream
    }{is =>
      val writer = new StringWriter;
      IOUtils.copy(is, writer, "UTF-8");
      writer.toString;
    }
    httpcon.disconnect
    if (isError) throw new Exception(
      s"Resp code $code. Error: ${resp.take(200)}"
    ) else resp
  }
}

Then, I used it as follows:

import java.net.Authenticator
import java.net.PasswordAuthentication

val rpcuser = "alice";
val rpcpassword = "secret";

Authenticator.setDefault(
  new Authenticator {
    override def getPasswordAuthentication:PasswordAuthentication = {
      new PasswordAuthentication (rpcuser, rpcpassword.toCharArray)
    }
  }
)  

CurlJsonData.curl(
  "http://localhost:8332", 
  """{"method":"getblockchaininfo","params":[],"id":1,"jsonrpc":"1.0"}"""
) 
1

One of the problems of Java is the verbosity of the language. However, it is also true that the life of the language it is very old in these that.

I fall into the problem to talk with the bitcoin rpc interface for one of my side projects on c-lightning and I was not able to find a clean library that is able to talk also with other rpc interfaces derived from bitcoin core, like litecoin. In addition, I found also a library that is easy like a python library.

My result of designing a library that respect this requirement, it is called lite-bitcoin-rpc and it is available on GitHub https://github.com/clightning4j/lite-bitcoin-rpc

This is an easy library because with gives the possibility to write the JSON wrapper in a Java class and use it to decode the response. The end-user need only to feel a map with parameters and create the Java class where decode the JSON payload received from bitcoin core.

An example can be found in the test directory https://github.com/clightning4j/lite-bitcoin-rpc/tree/main/lib/src/test

and a code example can be

public class LiteBitcoinRPCTest {

  private LiteBitcoinRPC bitcoinRPC;

  public LiteBitcoinRPCTest() {
    this.bitcoinRPC = new LiteBitcoinRPC("sandbox", "sandbox", "http://127.0.0.1:18333/");
  }

  @Test
  public void getBlockchainInfo() {
    try {
      BlockchainInfo info =
          bitcoinRPC.makeBitcoinRequest("getblockchaininfo", BlockchainInfo.class);
      TestCase.assertEquals(info.getChain(), "regtest");
    } catch (Exception e) {
      e.printStackTrace();
      TestCase.fail(e.getLocalizedMessage());
    }
  }

  @Test
  public void estimateFeeRateWithError() {
    Parameters parameters = new Parameters("estimatesmartfee");
    parameters.addParameter("conf_target", 6);
    try {
      BitcoinEstimateFee feee = bitcoinRPC.makeBitcoinRequest(parameters, BitcoinEstimateFee.class);
      TestCase.assertFalse(feee.getErrors().isEmpty());
    } catch (LiteBitcoinRPCException | BitcoinCoreException e) {
      TestCase.fail(e.getMessage());
    }
  }
0

If Scala is not your thing, here is Jus12's code in Kotlin:

package com.my.blockchainparser

import java.net.Authenticator
import java.net.PasswordAuthentication
import java.net.URL
import java.net.HttpURLConnection

fun main(args: Array<String>) {
    val rpcuser = "user"
    val rpcpassword = "password"
    Authenticator.setDefault(object : Authenticator() {
        override fun getPasswordAuthentication(): PasswordAuthentication {
            return PasswordAuthentication(rpcuser, rpcpassword.toCharArray())
        }
    })

    System.out.println(curl(
            "http://localhost:8332",
            """{"method":"getblockchaininfo","params":[],"id":1,"jsonrpc":"1.0"}"""
    ))
}

fun curl(url:String, jsonEncodedString:String): String {
    val httpcon = URL(url).openConnection() as HttpURLConnection
    httpcon.setDoOutput(true);
    httpcon.setRequestProperty("Content-Type", "application/json");
    httpcon.setRequestProperty("Accept", "application/json");
    httpcon.setRequestMethod("POST");
    httpcon.connect();

    val outputBytes = jsonEncodedString.toByteArray();

    httpcon.getOutputStream().use {
        it.write(outputBytes)
    }
    val code = httpcon.getResponseCode()
    val isError = code >= 400 && code <= 500
    val text = (if (isError) httpcon.getErrorStream() else httpcon.getInputStream())
            ?.bufferedReader()?.use {
        it.readText()
    } ?: "no connection"
    if (isError) throw Exception(
            "Resp code $code. Error: ${text.take(200)}"
    )
    return text
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.