Tengo problemas para comunicarme entre Java y bitcoind: todas las bibliotecas JSON RPC que pruebo tienen algunos problemas. ¿Alguien puede proporcionar una implementación funcional incluso de la comunicación JSON RPC más básica entre Java y bitcoind?
Aquí hay uno de los primeros clientes experimentales con los que había jugado hace un tiempo . Admite getInfo, getBalance y getNewAddress, y se puede expandir fácilmente. Para ejecutarlo, las credenciales de su bitcoind local deben coincidir con los valores de la clase de cliente:
httpclient.getCredentialsProvider().setCredentials(new AuthScope("localhost", 8332),
new UsernamePasswordCredentials("btc", "123"));
Siéntase libre de usar este código de cualquier manera, pero comprenda que son solo 5 minutos de trabajo al principio, no una implementación de cliente realista. ¡Espero que te ayude a generar algunas ideas!
También puede probar https://github.com/clanie/bitcoind-client : se encuentra en desarrollo temprano, pero ya es compatible con casi todos los métodos proporcionados por bitcoind.
Tuve el mismo problema y creé una implementación aquí: https://github.com/johannbarbie/BitcoindClient4J
Debido a que esto parece una colección de enlaces, simplemente agregaré otro:
Biblioteca bajo licencia Apache: https://github.com/SulacoSoft/BitcoindConnector4J
https://github.com/nitinsurana/Litecoin-Bitcoin-RPC-Java-Connector
Utiliza Htmlunit en lugar de Apache Http Library, lo que lo hace un poco fácil de entender y ampliar.
De hecho, lo escribí y lo probé para Litecoin para uno de mis proyectos. Pero se ha ampliado para admitir bitcoin y todos los métodos RPC están disponibles.
Como no pude encontrar un fragmento de código de trabajo en ninguna parte, aquí hay un ejemplo de trabajo completo (en Scala):
Primero creé un objeto auxiliar:
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
}
}
Entonces, lo usé de la siguiente manera:
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"}"""
)
Uno de los problemas de Java es la verbosidad del lenguaje. Sin embargo, también es cierto que la vida de la lengua es muy antigua en estos que.
Caí en el problema de hablar con la interfaz rpc de bitcoin para uno de mis proyectos paralelos en c-lightning y no pude encontrar una biblioteca limpia que pudiera hablar también con otras interfaces rpc derivadas del núcleo de bitcoin, como litecoin. Además, también encontré una biblioteca que es fácil como una biblioteca de python.
Mi resultado de diseñar una biblioteca que respeta este requisito, se llama lite-bitcoin-rpc y está disponible en GitHub https://github.com/clightning4j/lite-bitcoin-rpc
Esta es una biblioteca fácil porque brinda la posibilidad de escribir el contenedor JSON en una clase Java y usarlo para decodificar la respuesta. El usuario final solo necesita sentir un mapa con parámetros y crear la clase Java donde decodificar la carga útil JSON recibida del núcleo de bitcoin.
Se puede encontrar un ejemplo en el directorio de prueba https://github.com/clightning4j/lite-bitcoin-rpc/tree/main/lib/src/test
y un ejemplo de código puede ser
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());
}
}
Si Scala no es lo tuyo, aquí está el código de Jus12 en 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
}
lurf jurv