Learning-Bitcoin-from-the-C.../es/18_1_Accediendo_a_Bitcoind_con_Go.md
2021-10-06 17:32:57 -05:00

15 KiB
Raw Permalink Blame History

18.1: Acceso a Bitcoind con Go

NOTA: Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.

Esta sección explica cómo interactuar con bitcoind usando el lenguaje de programación Go y el btcd rpcclient. Tenga en cuenta que tiene algunas peculiaridades y algunas limitaciones.

Configurar Go

Para prepararse para el uso de Go en su máquina UNIX, primero instale curl si aún no lo ha hecho:

$ sudo apt install curl

Luego, mire la página de descargas Go, obtenga el enlace para la última descarga y descarguelo usando curl. Para una configuración de Debian, querrá usar la versión linux-amd64:

$ curl -O https://dl.google.com/go/go1.15.1.linux-amd64.tar.gz

Una vez finalizada la descarga, compare el hash de la descarga con el hash en la página de descargas Go:

$ sha256sum go1.15.1.linux-amd64.tar.gz 
70ac0dbf60a8ee9236f337ed0daa7a4c3b98f6186d4497826f68e97c0c0413f6  go1.15.1.linux-amd64.tar.gz

Los hashes deben coincidir. Si es así, extraiga el archivo e instale Go en su sistema:

$ tar xfv go1.15.1.linux-amd64.tar.gz 
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local

Ahora necesita crear una ruta Go para especificar su entorno. Abra el archivo ~/.profile con un editor de su elección y añada lo siguiente al final de la misma:

export GOPATH=$HOME/work
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

Por último, cree el directorio de su espacio de trabajo Go:

$ mkdir $HOME/work

Configurar btcd rpcclient

Usara el rpcclient que viene con btcd, una implementación de Bitcoin escrita en Go. Aunque rpcclient fue originalmente diseñado para trabajar con el nodo completo de Bitcoin btcd , también funciona con Bitcoin Core. Tiene algunas peculiaridades que veremos.

Puede utilizar go get para descargarlo:

$ go get github.com/btcsuite/btcd/rpcclient

Para probar que funciona, vaya al directorio con los ejemplos de Bitcoin Core:

$ cd $GOPATH/src/github.com/btcsuite/btcd/rpcclient/examples/bitcoincorehttp

Modificar el archivo main.go e introduzca los detalles asociados con la configuración del núcleo de Bitcoin, que se pueden encontrar en ~/.bitcoin/bitcoin.conf:

		Host:         "localhost:18332",
		User:         "StandUp",
		Pass:         "6305f1b2dbb3bc5a16cd0f4aac7e1eba",

MAINNET VS TESTNET: El puerto 8332 sería para una configuración de mainnet.

Ahora puede realizar una prueba:

$ go run main.go

Deberia ver impreso el conteo de bloques:

2020/09/01 11:41:24 Block count: 1830861

Crear un proyecto rpcclient

Normalmente estará creando proyectos en su directorio ~/work/src/myproject/bitcoin :

$ mkdir -p ~/work/src/myproject/bitcoin
$ cd ~/work/src/myproject/bitcoin

Cada proyecto deberá tener los siguientes imports:

import (
	"log"
	"fmt"
	"github.com/btcsuite/btcd/rpcclient"
)

Esta declaración import le permite importar bibliotecas relevantes. Para cada ejemplo aquí, necesitará importar "log", "fmt" y "github.com/btcsuite/btcd/rpcclient". Es posible que necesite importar bibliotecas adicionales para algunos ejemplos.

  • log se utiliza para imprimir mensajes de error. Después de cada llamada al nodo Bitcoin, una declaración if comprobará si hay algún error. Si hay errores, log se utiliza para imprimirlos.
  • fmt se utiliza para imprimir la salida.
  • rpcclient; es obviamente la biblioteca rpcclient

Construya su conexión

Cada función bitcoind en Go comienza con la creación de la conexión RPC, usando la función ConnConfig :

   connCfg := &rpcclient.ConnConfig{
   	Host:         "localhost:18332",
   	User:         "StandUp",
   	Pass:         "431451790e3eee1913115b9dd2fbf0ac",
   	HTTPPostMode: true,
   	DisableTLS:   true,
   }
   client, err := rpcclient.New(connCfg, nil)
   if err != nil {
   	log.Fatal(err)
   }
   defer client.Shutdown()

Los parámetros connCfg le permiten elegir el puerto RPC de Bitcoin, nombre de usuario, contraseña y si está en testnet o mainnet.

NOTA: De nuevo, asegúrese de sustituir el User y Pass con el que se encuentra en su ~/.bitcoin/bitcon.conf.

Por tanto la función rpcclient. New(connCfg, nil) configura su client para conectarse a su nodo Bitcoin. La línea defer client.Shutdown() es para desconectar de su nodo Bitcoin, una vez que la función main() termina de ejecutarse. Después de la línea defer client.Shutdown() es donde va el material emocionante y será bastante fácil de usar. Eso es porque rpcclient ayuda a convertir los comandos bitcoin-cli en funciones usando PascalCase. Por ejemplo, bitcoin-cli getblockcount será client.GetBlockCount en Go.

Hacer una llamada RPC

Todo lo que se requiere ahora es hacer una llamada informativa como GetBlockCount o GetBlockHash usando su client:

	blockCount, err := client.GetBlockCount()
	if err != nil {
		log.Fatal(err)
	}
	blockHash, err := client.GetBlockHash(blockCount)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%d\n", blockCount)
	fmt.Printf("%s\n", blockHash.String())

Hacer una llamada RPC con argumentos

Las funciones rpcclient también pueden tomar entradas; por ejemplo cliente.GetBlockHash(blockCount) toma el conteo de bloques como una entrada. El cliente client.GetBlockHash(blockCount) visto anteriormente se vería como un comando bitcoin-cli:

$ bitcoin-cli getblockhash 1830868
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c

Sin embargo, una peculiaridad con hashes en rpcclient es que típicamente se imprimirán en una codificación diferente si se va a imprimir normalmente usando blockHash. Para imprimirlos como una cadena, es necesario utilizar blockHash.String().

Ejecute su código

Puede descargar el código completo desde el src directory.

A continuación, puede ejecutar:

$ go run blockinfo.go 
1830868
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c

El último número de bloque junto con su hash debe imprimirse.

Buscar fondos

Debido a las limitaciones de la función btcd rpcclient, no se puede hacer un uso de la función getwalletinfo. Sin embargo, usted puede hacer uso de la llamada RPC getbalance:

	wallet, err := client.GetBalance("*")
	if err != nil {
		log.Fatal(err)
	}

client.GetBalance("*") requiere la entrada "*", debido a una peculiaridad con btcd. El asterisco significa que usted quiere conseguir el saldo de todas sus carteras. Si ejecuta el código src, debería obtener una salida similar a esta:

$ go run getbalance.go 
0.000689 BTC

Crear una dirección

Puede generar direcciones en Go, pero no puede especificar el tipo de dirección:

Esto requiere el uso de una función especial chaincfg, para especificar para qué red se están creando las direcciones. Esta especificación solo se requiere durante la generación de direcciones, por lo que solo se utiliza en este ejemplo. También puede incluir esto en otros ejemplos, pero no es necesario.

Asegúrese de importar "github.com/btcsuite/btcd/chaincfg":

import (
	"log"
	"fmt"
	"github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcd/chaincfg"
)

Luego llame a connCfG con el parámetro chaincfg.TestNet3Params.Name :

	connCfg := &rpcclient.ConnConfig{
		Host:         "localhost:18332",
		User:         "bitcoinrpc",
		Pass:         "431451790e3eee1913115b9dd2fbf0ac",
		HTTPPostMode: true,
		DisableTLS:   true,
		Params: chaincfg.TestNet3Params.Name,
	}
	client, err := rpcclient.New(connCfg, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Shutdown()

MAINNET VS TESTNET: Params: chaincfg.TestNet3Params.Name, debe ser Parameters: chaincfg.MainNetParams.Name, en mainnet.

A continuación, puede crear su dirección:

	address, err := client.GetNewAddress("")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(address)

Una peculiaridad con client.GetNewAddress(") es que se debe incluir una cadena vacía para que funcione.

Ejecutando la fuente se obtienen los siguientes resultados:

$ go run getaddress.go 
tb1qutkcj34pw0aq7n9wgp3ktmz780szlycwddfmza

Decodificar una dirección

La creación de una dirección tomó un trabajo adicional, en especificar la cadena apropiada. Usar una dirección también lo hará porque tendrá que decodificarla antes de usarla.

Los medios que usted tendrá que importar tanto las librerías "github.com/btcsuite/btcutil" como "github.com/btcsuite/btcd/chaincfg".

  • btcutil permite que una dirección de Bitcoin sea decodificada de una manera que el cliente rpcclient pueda entender. Esto es necesario cuando se trabaja con direcciones en rpcclient.
  • chaincfg se utiliza (de nuevo) para configurar su cadena como la cadena Testnet. Esto es necesario para la decodificación de direcciones ya que las direcciones utilizadas en Mainnet y Testnet son diferentes.
import (
	"log"
	"fmt"
	"github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcd/chaincfg"
)

La variable defaultNet ahora se utiliza para especificar si su nodo Bitcoin está en testnet o en mainnet. Esa información (y el objeto btcutil ) se utiliza para decodificar la dirección.

MAINNET VS TESTNET: &chaincfg.TestNet3Params debe ser &chaincfg.MainNetParams en mainnet.

	defaultNet := &chaincfg.TestNet3Params
	addr, err := btcutil.DecodeAddress("mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha", defaultNet)
	if err != nil {
		log.Fatal(err)
	}

NOTA: Cambie la dirección (mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha) para una de su billetera actual; puede utilizar bitcoin-cli listunspent para encontrar algunas direcciones con fondos para esta prueba. Si quiere ser realmente elegante, modifique el código Go para tomar un argumento, luego escriba un script que ejecute listunspent, guarde la información en una variable, y ejecute el código Go con eso.

Solo después de esto, use la dirección getreceivedbyaddress RPC, en su dirección decodificada:

	wallet, err := client.GetReceivedByAddress(addr)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(wallet)

Cuando ejecute el código, debería obtener una salida similar a:

$ go run getamountreceived.go 
0.0085 BTC

Enviar una transacción

Ahora tiene todas las piezas del rompecabezas en su lugar para enviar una transacción. Va a querer:

  1. Importar las bibliotecas correctas, incluyendo chaincfg para especificar una red y btcutil para decodificar una dirección.
  2. Elija una dirección para enviar.
  3. Descifre esa dirección.
  4. Ejecute sendtoaddress para enviar los fondos de la manera fácil.
package main

import (
	"log"
	"fmt"
	"github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcd/chaincfg"
)

func main() {
	connCfg := &rpcclient.ConnConfig{
		Host:         "localhost:18332",
		User:         "StandUp",
		Pass:         "431451790e3eee1913115b9dd2fbf0ac",
		HTTPPostMode: true,
		DisableTLS:   true,
	}
	client, err := rpcclient.New(connCfg, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Shutdown()

	defaultNet := &chaincfg.TestNet3Params
	addr, err := btcutil.DecodeAddress("n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi", defaultNet)
	if err != nil {
		log.Fatal(err)
	}
	sent, err := client.SendToAddress(addr, btcutil.Amount(1e4))
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(sent)
}

Cuando se ejecuta el código, el txid de la transacción se emite:

$ go run sendtransaction.go
9aa4cd6559e0d69059eae142c35bfe78b71a8084e1fcc2c74e2a9675e9e7489d

Buscar una transacción

Para buscar una transacción, como la que acaba de enviar, tendrá que volver a hacer algunas conversiones, esta vez de txid. "github.com/btcsuite/btcd/chaincfg/chainhash" se importa para permitir que los hashes se almacenen en el código Go. chainhash.NewHashFromStr("hash") convierte un hash en una cadena a un formato que funciona con rpcclient.

package main

import (
	"log"
	"fmt"
	"github.com/btcsuite/btcd/rpcclient"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
)

func main() {
	connCfg := &rpcclient.ConnConfig{
		Host:         "localhost:18332",
		User:         "StandUp",
		Pass:         "431451790e3eee1913115b9dd2fbf0ac",
		HTTPPostMode: true,
		DisableTLS:   true,
	}
	client, err := rpcclient.New(connCfg, nil)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Shutdown()

	chash, err := chainhash.NewHashFromStr("1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df")
	if err != nil {
		log.Fatal(err)
	}
	transactions, err := client.GetTransaction(chash)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(transactions)
}

NOTA: De nuevo, querrá cambiar el txid por uno realmente reconocido por su sistema.

Cuando ejecute el código imprimirá los detalles asociados con una transacción, como su cantidad y cuántas veces se ha confirmado:

$ go run lookuptransaction.go
{
  "amount": 0.00100000,
  "confirmations": 4817,
  "blockhash": "000000006628870b0a8a66abea9cf0d4e815c491f079e3fa9e658a87b5dc863a",
  "blockindex": 117,
  "blocktime": 1591857418,
  "txid": "1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df",
  "walletconflicts": [
  ],
  "time": 1591857343,
  "timereceived": 1591857343,
  "bip125-replaceable": "no",
  "details": [
    {
      "address": "mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha",
      "category": "receive",
      "amount": 0.00100000,
      "label": "",
      "vout": 0
    }
  ],
  "hex": "02000000000101e9e8c3bd057d54e73baadc60c166860163b0e7aa60cab33a03e89fb44321f8d5010000001716001435c2aa3fc09ea53c3e23925c5b2e93b9119b2568feffffff02a0860100000000001976a914600c8c6a4abb0a502ea4de01681fe4fa1ca7800688ac65ec1c000000000017a91425b920efb2fde1a0277d3df11d0fd7249e17cf8587024730440220403a863d312946aae3f3ef0a57206197bc67f71536fb5f4b9ca71a7e226b6dc50220329646cf786cfef79d60de3ef54f702ab1073694022f0618731902d926918c3e012103e6feac9d7a8ad1ac6b36fb4c91c1c9f7fff1e7f63f0340e5253a0e4478b7b13f41fd1a00"
}

Resumen: Acceso a Bitcoind con Go

Aunque btcd y rpcclient tienen algunos límites, aún es posible realizar los comandos principales de RPC en Go. La documentación para rpcclient está disponible en Godoc. Si la documentación no tiene lo que está buscando, consulte también el repositorio btcd. Generalmente está bien documentado y es fácil de leer. Sobre la base de estos ejemplos debería ser capaz de incorporar Bitcoin en un proyecto Go y hacer cosas como enviar y recibir monedas.

¿Que sigue?

Obtenga más información sobre "Hablando con Bitcoin en otros lenguages" en 18.2: Accediendo a Bitcoin con Java.