Wie kommuniziert man zwischen Java und Bitcoin?

Ich habe Probleme bei der Kommunikation zwischen Java und Bitcoin - jede JSON-RPC-Bibliothek, die ich versuche, hat einige Probleme. Kann jemand eine funktionierende Implementierung selbst der grundlegendsten JSON-RPC-Kommunikation zwischen Java und Bitcoin bereitstellen?

Es gibt eine Bitcoin-Bibliothek für Java ... Das könnte der Grund sein, warum nur wenige Leute an einem JSON-RPC für Java arbeiten.

Antworten (9)

Hier ist ein früher experimenteller Client, mit dem ich vor einiger Zeit herumgespielt hatte . Es unterstützt getInfo, getBalance und getNewAddress und kann einfach erweitert werden. Um es auszuführen, müssen die Anmeldeinformationen für Ihre lokale Bitcoin mit den Werten in der Client-Klasse übereinstimmen:

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

Fühlen Sie sich frei, diesen Code in irgendeiner Weise zu verwenden, aber verstehen Sie, dass es am Anfang nur 5 Minuten Arbeit sind, keine realistische Client-Implementierung. Hoffe, es hilft Ihnen, einige Ideen zu generieren!

Ich mag diese Lösung sehr, das einzige Problem ist, dass der erste Anruf auf diesem Client sehr lange dauert. Ein 'getrawtransaction'-Aufruf auf meinem Laptop dauert 288 ms, um diesen http-Client zu verklagen, während ein Prozess von Java ausgeführt wird, dauert ~ 5 ms. Dieser Client ist jedoch auf lange Sicht effizienter und benötigt für alle anderen Anrufe im Durchschnitt etwa 4 ms. Ich habe versucht, es zu beschleunigen, indem ich versucht habe, die Cookie-Authentifizierung zu verwenden, aber es war nicht möglich ... Lösungen für dieses Problem sind willkommen!

Gerne können Sie auch https://github.com/clanie/bitcoind-client ausprobieren – es befindet sich in einer frühen Entwicklungsphase, unterstützt aber bereits fast alle von Bitcoin bereitgestellten Methoden.

Ich hatte das gleiche Problem und habe hier eine Implementierung erstellt: https://github.com/johannbarbie/BitcoindClient4J

Da dies wie eine Sammlung von Links aussieht, füge ich einfach einen weiteren hinzu:

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

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

Es verwendet Htmlunit anstelle der Apache Http Library, wodurch es etwas einfacher zu verstehen und zu erweitern ist.

Ich habe es tatsächlich für Litecoin für eines meiner Projekte geschrieben und getestet. Aber es wurde erweitert, um Bitcoin zu unterstützen, und alle RPC-Methoden sind verfügbar.

Da ich nirgendwo ein funktionierendes Code-Snippet finden konnte, ist hier ein vollständiges funktionierendes Beispiel (in Scala):

Zuerst habe ich ein Hilfsobjekt erstellt:

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
  }
}

Dann habe ich es wie folgt verwendet:

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"}"""
) 

Eines der Probleme von Java ist die Ausführlichkeit der Sprache. Es ist jedoch auch wahr, dass das Leben der Sprache in diesen sehr alt ist.

Ich habe das Problem, mit der Bitcoin-RPC-Schnittstelle für eines meiner Nebenprojekte auf c-Lightning zu sprechen, und ich konnte keine saubere Bibliothek finden, die auch mit anderen vom Bitcoin-Kern abgeleiteten RPC-Schnittstellen wie Litecoin kommunizieren kann. Außerdem habe ich auch eine Bibliothek gefunden, die einfach wie eine Python-Bibliothek ist.

Mein Ergebnis der Entwicklung einer Bibliothek, die diese Anforderung erfüllt, heißt lite-bitcoin-rpc und ist auf GitHub https://github.com/clightning4j/lite-bitcoin-rpc verfügbar

Dies ist eine einfache Bibliothek, da sie die Möglichkeit bietet, den JSON-Wrapper in eine Java-Klasse zu schreiben und ihn zum Decodieren der Antwort zu verwenden. Der Endbenutzer muss nur eine Karte mit Parametern fühlen und die Java-Klasse erstellen, in der die vom Bitcoin-Kern empfangene JSON-Nutzlast decodiert wird.

Ein Beispiel findet sich im Testverzeichnis https://github.com/clightning4j/lite-bitcoin-rpc/tree/main/lib/src/test

und ein Codebeispiel sein kann

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());
    }
  }

Wenn Scala nicht Ihr Ding ist, hier ist der Code von Jus12 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
}