Merge pull request #399 from KoreaComK/chapter17

Chapter 17 Translated by @koreacomk need review
This commit is contained in:
Shannon Appelcline 2021-08-31 08:58:11 -10:00 committed by GitHub
commit 37c8cf47ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 2371 additions and 830 deletions

View File

@ -1,27 +0,0 @@
# Capítulo 15: Conversando com Bitcoind usando C
Enquanto trabalhamos com Bitcoin Scripts, atingimos os limites do que era possível com o `bitcoin-cli`: Atualmente, ele não pode ser usado para gerar transações contendo scripts incomuns. Os scripts shell também não são bons para algumas coisas, como criar programas de escuta que estão constantemente em polling. Felizmente, existem outras maneiras de acessar a rede Bitcoin: Através de APIs programáveis.
Esta seção se concentra em três diferentes bibliotecas que podem ser usadas como base de programação C sofisticada: Uma biblioteca RPC e uma biblioteca JSON que juntas permitem recriar muito do que fazemos nos scripts de shell, porém, usando C; enquanto uma biblioteca ZMQ nos conecta a notificações, algo que não conseguiríamos acessar até agora. (O próximo capítulo cobrirá uma biblioteca ainda mais sofisticada chamada Libwally, para finalizar esta introdução à programação do Bitcoin com C).
## Objetivos deste capítulo
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
* Criar programas C que usam RPC para conversar com o Bitcoind;
* Criar programas C que usam ZMQ para conversar com o Bitcoind.
Os objetivos secundários do capítulo incluem a capacidade de:
* Entender como usar uma biblioteca RPC;
* Entender como usar uma biblioteca JSON;
* Compreender as capacidades do ZMQ;
* Entender como usar uma biblioteca ZMQ.
## Tabela de conteúdo
* [Seção 1: Acessando o Bitcoind usando C com Bibliotecas RPC](15_1_Accessing_Bitcoind_with_C.md)
* [Seção 2: Programando o Bitcoind usando C com Bibliotecas RPC](15_2_Programming_Bitcoind_with_C.md)
* [Seção 3: Recebendo notificações usando C com bibliotecas ZMQ](15_3_Receiving_Bitcoind_Notifications_with_C.md)

View File

@ -1,294 +0,0 @@
# 15.1: Acessando o Bitcoind usando C com bibliotecas RPC
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um esboço que ainda pode estar aguardando revisão. Portanto, leitor, tenha cuidado.
Você já viu uma maneira alternativa de acessar as portas RPC do Bitcoind: Usando o ``curl``, que cobrimos no [Capítulo 4 Prefácio](04_4__interlude_using_curl.md). Interagir com o ``Bitcoind`` através de uma biblioteca de RPC usando C não é diferente do que já vimos, só precisamos de boas bibliotecas para nos auxiliar. Esta seção introduz um pacote chamado ``libbitcoinrpc``, que permite acessar a porta JSON-RPC do ``bitcoind``. Ele usa uma biblioteca ``curl`` para acessar os dados e usa a biblioteca ``jansson`` para codificar e decodificar o JSON.
## Configurando o libbitcoinrpc
Para usar o ``libbitcoinrpc``, precisaremos instalar uma configuração básica C e os pacotes dependentes, que são ``libcurl``, ``libjansson``, e ``libuuid``. Depois faremos isso no seu servidor Standup Bitcoin (ou em qualquer outro servidor Ubuntu).
```
$ sudo apt-get install make gcc libcurl4-openssl-dev libjansson-dev uuid-dev
Suggested packages:
libcurl4-doc libidn11-dev libkrb5-dev libldap2-dev librtmp-dev libssh2-1-dev
The following NEW packages will be installed:
libcurl4-openssl-dev libjansson-dev uuid-dev
0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded.
Need to get 358 kB of archives.
After this operation, 1.696 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
```
Agora, podemos baixar o [libbitcoinrpc no github](https://github.com/gitmarek/libbitcoinrpc/blob/master/readme.md). Vamos clonar ou pegar um arquivo zip, do jeito que preferir.
```
$ sudo apt-get install git
$ git clone https://github.com/gitmarek/libbitcoinrpc
```
> :warning: **ATENÇÃO** Uma alteração no RPC "signrawtransaction" causou uma assinatura com ``libbitcoinrpc`` para o segfault no Bitcoin 0.17 ou superior. O [Pull Request foi submetido](https://github.com/gitmarek/libbitcoinrpc/pull/1/commits) para resolver o problema, mas se ainda não tiver sido feito o merge, podemos simplesmente fazer uma simples mudança no código-fonte para ``src/bitcoinrpc_method.c`` antes de compilarmos.
### Compilando o libbitcoinrpc.
Antes de compilarmos e instalarmos o pacote, provavelmente precisaremos ajustar nosso ``$PATH``, para que possamos acessar o ``/sbin/ldconfig``:
```
$ PATH="/sbin:$PATH"
```
Para o Ubuntu, também precisaremos ajustar o ``install_libpath`` no ``makefile`` do ``libbitcoinrpc`` para instalar no ``/usr/lib`` ao invés do ``/usr/local/lib``:
```
$ emacs ~/libbitcoinrpc/Makefile
...
INSTALL_LIBPATH := $(INSTALL_PREFIX)/usr/lib
```
(Se preferir não usar o ``/usr/lib``, precisará alterar o ``etc/ld.so.conf`` ou os arquivos dependentes de maneira apropriada... Porém, para uma configuração de teste em uma máquina de teste, acredito que isso não seja um problema).
Da mesma forma, vamos precisar ajustar o ``install_headerpath`` no ``Makefile`` do ``libbitcoinrpc`` para instalar no caminho ``/usr/include`` ao invés do ``/usr/local/inclusve``:
```
...
INSTALL_HEADERPATH := $(INSTALL_PREFIX)/usr/include
```
Agora, podemos compilar:
```
$ cd libbitcoinrpc
~/libbitcoinrpc$ make
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_err.o -c src/bitcoinrpc_err.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_global.o -c src/bitcoinrpc_global.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc.o -c src/bitcoinrpc.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_resp.o -c src/bitcoinrpc_resp.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_cl.o -c src/bitcoinrpc_cl.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_method.o -c src/bitcoinrpc_method.c
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -shared -Wl,-soname,libbitcoinrpc.so.0 \
src/bitcoinrpc_err.o src/bitcoinrpc_global.o src/bitcoinrpc.o src/bitcoinrpc_resp.o src/bitcoinrpc_cl.o src/bitcoinrpc_method.o \
-o .lib/libbitcoinrpc.so.0.2 \
-Wl,--copy-dt-needed-entries -luuid -ljansson -lcurl
ldconfig -v -n .lib
.lib:
libbitcoinrpc.so.0 -> libbitcoinrpc.so.0.2 (changed)
ln -fs libbitcoinrpc.so.0 .lib/libbitcoinrpc.so
```
Se tudo correr bem, podemos instalar o pacote:
```
$ sudo make install
Installing to
install .lib/libbitcoinrpc.so.0.2 /usr/local/lib
ldconfig -n /usr/local/lib
ln -fs libbitcoinrpc.so.0 /usr/local/lib/libbitcoinrpc.so
install -m 644 src/bitcoinrpc.h /usr/local/include
Installing docs to /usr/share/doc/bitcoinrpc
mkdir -p /usr/share/doc/bitcoinrpc
install -m 644 doc/*.md /usr/share/doc/bitcoinrpc
install -m 644 CREDITS /usr/share/doc/bitcoinrpc
install -m 644 LICENSE /usr/share/doc/bitcoinrpc
install -m 644 Changelog.md /usr/share/doc/bitcoinrpc
Installing man pages
install -m 644 doc/man3/bitcoinrpc*.gz /usr/local/man/man3
```
## Preparando o código
``libbitcoinrpc`` tem métodos simples e bem estruturados para conectar-se ao nosso `bitcoind`, executando chamadas RPC e decodificando a resposta.
Para usar o ``libbitcoinrpc``, é importante certificar de que nossos arquivos do código incluam os cabeçalhos apropriados:
``` c
#include <jansson.h>
#include <bitcoinrpc.h>
```
Precisaremos também vincular as bibliotecas apropriadas sempre que possamos compilar:
```
$ cc yourcode.c -lbitcoinrpc -ljansson -o yourcode
```
## Construindo a conexão
Para construir a conexão com o servidor ``bitcoind`` é necessário alguns simples passos.
Primeiro, inicialize a biblioteca:
```
bitcoinrpc_global_init();
```
Em seguida, vamos conectar ao ``Bitcoind`` com ``bitcoinrpc_cl_init_params``. Os quatro argumentos necessários para o ``bitcoinrpc_cl_init_params`` são o nome de usuário, a senha, o endereço IP e a porta. A esta altura, você deve saber todas essas informações, já que foram necessárias para realizar o trabalho com o [curl](04_4__interlude_using_curl.md). Apenas para recordar, o endereço de IP é 127.0.0.1 e a porta 18332 devem estar corretos para a configuração padrão da testenet descrita neste documento, enquanto podemos encontrar o usuário e a senha no arquivo ``~/.bitcoin/bitcoin.conf``.
```
$ cat bitcoin.conf
server=1
dbcache=1536
par=1
maxuploadtarget=137
maxconnections=16
rpcuser=StandUp
rpcpassword=6305f1b2dbb3bc5a16cd0f4aac7e1eba
rpcallowip=127.0.0.1
debug=tor
prune=550
testnet=1
[test]
rpcbind=127.0.0.1
rpcport=18332
[main]
rpcbind=127.0.0.1
rpcport=8332
[regtest]
rpcbind=127.0.0.1
rpcport=18443
```
Com essas informações, vamos colocá-las no ``bitcoinrpc_cl_init_params``:
``` c
bitcoinrpc_cl_t *rpc_client;
rpc_client = bitcoinrpc_cl_init_params("StandUp", "6305f1b2dbb3bc5a16cd0f4aac7e1eba", "127.0.0.1", 18332);
```
> **MAINNET VS TESTNET:** A porta seria a 8332 caso estivéssemos usando a configuração da rede principal.
Se o ``rpc_client`` for inicializado com sucesso, poderemos enviar os comandos do RPC.
Mais tarde, quando tivermos feito com a conexão de ``bitcoind``, poderemos fechar da seguinte maneira:
``` c
bitcoinrpc_global_cleanup();
```
### Testando o código de teste
O código de teste pode ser encontrado [no diretório src com o nome 15_1_testbitcoin.c](src/15_1_testbitcoin.c). Vamos fazer o download para a nossa máquina TestNet e depois inserir a senha correta do RPC (e alterar o usuário RPC se não tivermos criado o servidor com StandUp).
Podemos compilar e executar o código da seguinte maneira:
```
$ cc testbitcoin.c -lbitcoinrpc -ljansson -o testbitcoin
$ ./testbitcoin
Successfully connected to server!
```
> :warning: **ATENÇÃO:** Se esquecermos de inserir a senha RPC nesta ou em qualquer outro código que possuem dependências do RPC, receberemos um misterioso ``ERROR CODE 5``.
## Fazendo uma chamada ao RPC
Para usarmos um método RPC usando ``libbitcoinrpc``, devemos inicializar uma variável do tipo ``bitcoinrpc_method_t``. Podemos fazer com o valor apropriado para o método que desejamos utilizar, que estão todos listados na [Referências do BitcoinRPC](https://github.com/gitmarek/libbitcoinrpc/blob/master/doc/reference.md).
``` c
bitcoinrpc_method_t *getmininginfo = NULL;
getmininginfo = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETMININGINFO);
```
Normalmente definiríamos os parâmetros em seguida, mas o ``GetMiningInfo`` não requer parâmetros, por isso podemos pular essa parte.
Também devemos criar outros dois objetos, um "objeto de resposta" e um "objeto de erro". Eles podem ser inicializados da seguinte forma:
``` c
bitcoinrpc_resp_t *btcresponse = NULL;
btcresponse = bitcoinrpc_resp_init();
bitcoinrpc_err_t btcerror;
```
Vamos usar a variável ``rpc_client`` que aprendemos no teste anterior e vamos adicionar nosso método ``getmininginfo`` e os outros dois objetos:
``` c
bitcoinrpc_call(rpc_client, getmininginfo, btcresponse, &btcerror);
```
### Mostrando o retorno da chamada
Com certeza iremos querer saber o que a RPC retornou. Para fazermos isso, vamos recuperar a saída da nossa chamada como sendo um objeto JSON com ``bitcoinrpc_resp_get`` e vamos salvá-la em um objeto padrão ``jansson``, do tipo ``json_t``:
``` c
json_t *jsonresponse = NULL;
jsonresponse = bitcoinrpc_resp_get(btcresponse);
```
Se quisermos gerar os resultados completos da chamada RPC no JSON, podemos fazer com uma simples invocação do ``json_dumps``, da biblioteca ``jansson``:
``` c
printf("%s\n", json_dumps(j, JSON_INDENT(2)));
```
No entanto, como agora estamos escrevendo programas completos, provavelmente iremos querer fazer um trabalho mais sutil, como retirar valores individuais do JSON para algum uso específico. A [Referência do Jansson](https6//jansson.readthedocs.Io/en/2.10/apiref.html) traz detalhes de como fazer.
Assim como estávamos usando o [curl](04_4__interlude_using_curl.md), descobrimos que o RPC retorna um objeto JSON contendo um ``ID``, um ``error`` e, mais importante, um objeto JSON do tipo ``result``.
A função ``json_object_get`` permite recuperar um valor (como o ``result``) de um objeto JSON usando chaves:
``` c
json_t *jsonresult = NULL;
jsonresult = json_object_get(jsonresponse,"result");
printf("%s\n", json_dumps(jsonresult, JSON_INDENT(2)));
```
No entanto, provavelmente iremos querer analisar informações ainda mais profundas, para obter uma variável específica. Depois de recuperar o valor apropriado, precisaremos convertê-lo em um objeto C padrão usando a função ``JSON_*_value``. Por exemplo, para acessar um integer usamos o ``json_integer_value``:
``` c
json_t *jsonblocks = NULL;
jsonblocks = json_object_get(jsonresult,"blocks");
int blocks;
blocks = json_integer_value(jsonblocks);
printf("Block Count: %d\n",blocks);
```
> :warning: **ATENÇÃO:** É extremamente fácil ocasionar erros de segmentação no código C quando estivermos trabalhando com os objetos ``jansson`` caso fiquemos confusos com que tipo de objeto estamos recuperando. Por isso, precisamos fazer isso com cuidado usando o ``bitcoin-cli help`` para saber o que devemos esperar, e se tivermos uma falha de segmentação, primeiro precisamos analisar se nossas funções de recuperação JSON estão corretas.
### Testando o código de informação
Vamos recuperar o código de teste que está no [diretório src](15_1_GetMiningInfo.c).
```
$ cc getmininginfo.c -lbitcoinrpc -ljansson -o getmininginfo
$ ./getmininginfo
Full Response: {
"result": {
"blocks": 1804406,
"difficulty": 4194304,
"networkhashps": 54842097951591.781,
"pooledtx": 127,
"chain": "test",
"warnings": "Warning: unknown new rules activated (versionbit 28)"
},
"error": null,
"id": "474ccddd-ef8c-4e3f-93f7-fde72fc08154"
}
Just the Result: {
"blocks": 1804406,
"difficulty": 4194304,
"networkhashps": 54842097951591.781,
"pooledtx": 127,
"chain": "test",
"warnings": "Warning: unknown new rules activated (versionbit 28)"
}
Block Count: 1804406
```
## Fazendo uma chamada RPC usando argumentos
Mas e se a sua chamada RPC tiver argumentos?
### Criando uma matriz JSON
Para enviar parâmetros para a nossa chamada RPC usando ``libbitcoinrpc`` teremos que envolvê-los em uma matriz json. Como uma matriz é apenas uma simples listagem de valores, tudo o que precisamos fazer é codificar os parâmetros como elementos ordenados na matriz.
Vamos criar a matriz JSON usando a função ``json_array do`` do ``jansson``:
``` c
json_t *params = NULL;
params = json_array();
```
Vamos fazer o processo inverso que fizemos para acessar valores do JSON: Vamos converter objetos no C para objetos no JSON usando as funções ``JSON_*``. Depois, vamos anexar tudo à matriz:
``` c
json_array_append_new(params,json_string(tx_rawhex));
```
Observe que existem duas variantes para o comando de anexação: ``json_array_apend_new``, que acrescenta uma variável recém-criada, e ``json_array_apend``, que anexa uma variável existente.
Esta metodologia simples ``json_array_apend_new`` servirá para a maioria dos comandos RPC com parâmetros, mas alguns dos comandos RPC exigem entradas mais complexas. Nesses casos, precisaremos criar objetos JSON ou arrays em JSON, que anexaremos ao parâmetros de array como de costume. A próxima seção contém um exemplo de como fazer isso usando o ``CrayAwTransaction``, que contém uma matriz JSON de objetos JSON para as entradas, um objeto JSON para as saídas e o parâmetro ``locktime``.
### Atribuindo os parâmetros
Quando criamos o parâmetro array no JSON, simplesmente o atribuímos depois de inicializar o método RPC, da seguinte maneira:
``` c
bitcoinrpc_method_set_params(rpc_method, params)
```
Esta seção não inclui uma amostra abrangente dessa metodologia mais complexa, mas vamos vê-la em ação várias vezes no nosso primeiro programa C mais abrangente usando o RPC, na próxima seção.
## Resumo do capítulo Acessando o Bitcoind usando C com bibliotecas RPC
Ao vincular às bibliotecas ``BitcoinRPC`` do RPC e as bibliotecas ``jansson`` do JSON, podemos acessar facilmente o ``bitcoind`` usando chamadas RPC de uma biblioteca C. Para fazer isso, criamos uma conexão RPC, que faz as chamadas individuais de RPC, algumas delas passando alguns parâmetros. O ``jansson`` permite decodificar as respostas no formato JSON. A próxima seção demonstrará como isso pode ser usado para um programa de uso do mundo real.
* :fire: ***Qual é o poder de C?*** O C permite que façamos o próximo passo muito além do script shell, permitindo a criação de programas mais complexos e robustos.
## O Que Vem Depois?
Vamos falar mais um pouco no "Conversando com o Bitcoind usando C" no capítulo [15.2: Programando o Bitcoind usando C com bibliotecas RPC](15_2_Programming_bitcoind_with_c.md).

View File

@ -1,354 +0,0 @@
# 15.2: Programando o Bitcoind usando C com bibliotecas RPC
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho que pode estar aguardando revisão. Portanto, leitor, tenha cuidado.
A sessão [§15.1](15_1_Accessing_Bitcoind_with_C.md) apresentou a metodologia para a criação de programas C usando bibliotecas RPC e JSON. Agora vamos mostrar o potencial dessas bibliotecas C fazendo algumas coisas um pouco mais avançadas usando o programa real do Bitcoin.
## Planejando o código
Esta seção irá criar uma versão simples do ``sendtoaddress``, permitindo ao usuário enviar as moedas para um endereço, desde que tenha um UTXO grande o suficiente para isso. Aqui está o que precisamos fazer:
1. Solicitar um endereço e uma quantia;
2. Definir uma taxa arbitrária;
3. Preparar nosso RPC;
4. Encontrar um UTXO que seja grande o suficiente para pagar o valor + a taxa;
5. Criar uma mudança de endereço;
6. Criar uma transação bruta que envie o UTXO para o endereço e altere o endereço;
7. Assinar a transação;
8. Enviar a transação.
### Planejando para o futuro
Como este é o nosso primeiro programa C funcional, vamos mantê-lo simples (ou seja, vamos usar a filosofia, _Keep it Simple_ ou também conhecida como KISS). Se estivéssemos produzindo um programa para estar em produção, desejaríamos pelo menos os seguintes passos:
1. Testar e/ou higienizar as entradas;
2. Calcular uma taxa automaticamente;
3. Pensar logicamente sobre qual UTXO seria válido utilizar;
4. Combinar vários UTXOs, caso seja necessário;
5. Ficar atento a mais erros nos comandos ``libbitcoinrpc`` ou no ``jansson``;
6. Observar se há erros nas respostas RPC.
Se deseja continuar a expandir este exemplo, seria ótimo começar a lidar com as inadequações do programa.
## Escrevendo o sistema de transação
Agora estamos prontos para realizar o passo a passo do nosso plano
### Etapa 1: Solicitando um endereço e uma quantia
Inserir as informações é bem simples se usarmos os argumentos na linha de comando:
``` c
if(argc != 3) {
printf("ERROR: Only %i arguments! Correct usage is '%s [recipient] [amount]'\n",argc-1,argv[0]);
exit(-1);
}
char *tx_recipient = argv[1];
float tx_amount = atof(argv[2]);
printf("Sending %4.8f BTC to %s\n",tx_amount,tx_recipient);
```
> :aviso: **ATENÇÃO:** Um programa real precisaria de uma higienização muito melhor dessas variáveis.
### Etapa 2: Definindo uma taxa arbitrária
Este exemplo colocamos uma taxa arbitrária de 0.0005 BTC para garantir que as transações do teste sejam processadas rapidamente:
``` c
float tx_fee = 0.0005;
float tx_total = tx_amount + tx_fee;
```
> :warning: **ATENÇÃO:** Um programa real calcularia uma taxa que minimizasse o custo, garantindo que a velocidade fosse aquela que o remetente estivesse disposto a utilizar.
### Etapa 3: Preparando nosso RPC
Obviamente, precisaremos preparar todas as nossas variáveis novamente, conforme discutido na sessão [§15.1: Acessando o Bitcoind usando C](15_1_Accessing_Bitcoind_with_C.md). Também precisaremos inicializar a nossa biblioteca, conectar o cliente RPC e preparar nosso objeto de resposta:
``` c
bitcoinrpc_global_init();
rpc_client = bitcoinrpc_cl_init_params("bitcoinrpc", "YOUR-RPC-PASSWD", "127.0.0.1", 18332);
btcresponse = bitcoinrpc_resp_init();
```
### Etapa 4: Encontrando um UTXO
Para encontrar um UTXO, precisaremos chamar a função RPC ``listunspent``:
``` c
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_LISTUNSPENT);
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
```
No entanto, o verdadeiro trabalho consiste em decodificar a resposta. Na seção anterior vimos que a biblioteca ``jansson`` era "um tanto quanto desajeitada" e esta é a razão: Precisamos criar (e limpar) um conjunto muito grande de objetos ``json_t`` para descobrir o que queremos.
Primeiro, precisamos nos recuperar o campo ``result`` do JSON:
``` c
json_t *lu_response = NULL;
json_t *lu_result = NULL;
lu_response = bitcoinrpc_resp_get(btcresponse);
lu_result = json_object_get(lu_response,"result");
```
> :warning: **ATENÇÃO:** Só obteremos um resultado se não houver nenhum erro. Aqui temos um momento para melhorar nossa verificação de erros no código que iremos colocar em produção.
Em seguida, vamos fazer um laço, examinando cada transação que não foi gasta, que aparece como um elemento em sua matriz do resultado JSON:
``` c
int i;
const char *tx_id = 0;
int tx_vout = 0;
double tx_value = 0.0;
for(i = 0 ; i < json_array_size(lu_result) ; i++) {
json_t *lu_data = NULL;
lu_data = json_array_get(lu_result, i);
json_t *lu_value = NULL;
lu_value = json_object_get(lu_data,"amount");
tx_value = json_real_value(lu_value);
```
O UTXO é grande o suficiente para pagar sua transação? Se sim, pegue-o!
> :warning: **ATENÇÃO:** Um programa em produção pensaria com mais cuidado sobre qual UTXO utilizar, com base no tamanho e em outros fatores. Provavelmente não pegaria apenas o primeiro mais simples e pronto.
``` c
if(tx_value > tx_total) {
json_t *lu_txid = NULL;
lu_txid = json_object_get(lu_data,"txid");
tx_id = strdup(json_string_value(lu_txid));
json_t *lu_vout = NULL;
lu_vout = json_object_get(lu_data,"vout");
tx_vout = json_integer_value(lu_vout);
json_decref(lu_value);
json_decref(lu_txid);
json_decref(lu_vout);
json_decref(lu_data);
break;
}
```
Você também deve limpar os principais elementos do JSON:
``` c
}
json_decref(lu_result);
json_decref(lu_response);
```
> :warning: **ATENÇÃO:** Um programa em produção também se certificaria de que os UTXOs são passíveis de serem `gastos`.
Se não encontramos nenhum UTXOs grande o suficiente, teremos que relatar este infortúnio ao usuário... E talvez, sugerir que ele deva usar um programa melhor, que irá mesclar os UTXOs de maneira correta.
``` c
if(!tx_id) {
printf("Very Sad: You don't have any UTXOs larger than %f\n",tx_total);
exit(-1);
}
```
> **ATENÇÃO** Um programa em produção usaria sub-rotinas para este tipo de pesquisa, de forma que pudéssemos chamar vários RPCs de uma biblioteca de funções C. Vamos apenas colocar tudo em um `main` como parte da nossa filosofia KISS.
### Etapa 5: Criando um endereço de troco
Repita a metodologia padrão de pesquisa RPC para obter um endereço de troco:
``` c
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETRAWCHANGEADDRESS);
if(!rpc_method) {
printf("ERROR: Unable to initialize listunspent method!\n");
exit(-1);
}
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
if(btcerror.code != BITCOINRPCE_OK) {
printf("Error: listunspent error code %d [%s]\n", btcerror.code,btcerror.msg);
exit(-1);
}
lu_response = bitcoinrpc_resp_get(btcresponse);
lu_result = json_object_get(lu_response,"result");
char *changeaddress = strdup(json_string_value(lu_result));
```
A única diferença é quais informações específicas são extraídas do objeto JSON.
> :warning: **ATENÇÃO:** Aqui temos uma sub-rotina que seria bem legal: Abstrair toda a inicialização e chamada do método RPC.
### Etapa 6: Criando uma transação bruta
Criar a transação bruta real é outra parte complicada da programação da substituição do ``sendtoaddress``. Isso porque requer a criação de um objeto JSON complexo como parâmetro.
Para criarmos esses parâmetros corretamente, precisaremos revisar o que o RPC ``createrawtransaction`` espera que passemos como argumento. Felizmente, isso é fácil de determinar usando a funcionalidade ``bitcoin-cli help``:
```
$ bitcoin-cli help createrawtransaction
createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,"data":"hex",...} ( locktime )
```
Para relembrar, as entradas serão uma matriz JSON contendo um objeto JSON para cada UTXO. Então, as saídas estarão todas em um objeto JSON. É mais fácil criar esses elementos JSON de dentro para fora, usando os comandos ``jansson``.
#### Etapa 6.1: Criando os parâmetros de entrada
Para criar o objeto de entrada para nosso UTXO, vamos usar o ``json_object`` e preencher com os valores-chave usando ``json_object_set_new`` (para referências recém-criadas) ou ``json_object_set`` (para referências já existentes):
``` c
json_t *inputtxid = NULL;
inputtxid = json_object();
json_object_set_new(inputtxid,"txid",json_string(tx_id));
json_object_set_new(inputtxid,"vout",json_integer(tx_vout));
```
Pode-se notar que teremos que traduzir novamente cada tipo de variável C em um tipo de variável JSON usando a função apropriada, como ``json_string`` ou ``json_integer``.
Para criar o array de entrada para todos os UTXOs, vamos usar o ``json_array`` e, em seguida, preenchê-lo com os objetos usando o ``json_array_append``:
``` c
json_t *inputparams = NULL;
inputparams = json_array();
json_array_append(inputparams,inputtxid);
```
#### Etapa 6.2: Criando os parâmetros de saída
Para criar a matriz de saída para a transação, vamos seguir o mesmo processo, criando um objeto JSON com ``json_object`` e, em seguida, vamos preenchê-lo com o ``json_object_set``:
``` c
json_t *outputparams = NULL;
outputparams = json_object();
char tx_amount_string[32];
sprintf(tx_amount_string,"%.8f",tx_amount);
char tx_change_string[32];
sprintf(tx_change_string,"%.8f",tx_value - tx_total);
json_object_set(outputparams, tx_recipient, json_string(tx_amount_string));
json_object_set(outputparams, changeaddress, json_string(tx_change_string));
```
> :warning: **ATENÇÃO:** É possível pensar que teremos que inserir os valores do Bitcoin como sendo números, usando a função ``json_real``. Infelizmente, isso expõe um dos maiores problemas com a integração da biblioteca ``jansson`` e o Bitcoin. O Bitcoin só é válido até oito dígitos depois da casa decimal. Devemos nos lembrar que 0,00000001 BTC é um satoshi, e essa é a menor divisão possível de um Bitcoin. O tipo ``double`` no C oferecem mais dígitos do que precisamos, embora sejam frequentemente imprecisos depois das oito casas decimais. Se tentarmos convertê-los diretamente do nosso valor ``double`` no C (ou de um tipo ``float``, neste caso) para um valor Bitcoin, a imprecisão frequentemente criará um valor Bitcoin com mais de oito dígitos. Antes da versão Bitcoin Core 0.12, isso não era problema, e podíamos usar a função ``json_real``. Mas à partir dessa versão, se tentarmos usar a função ``createrawtransaction`` com mais do que oito dígitos, obteremos um erro e a transação não será criada. Como resultado, se o valor do Bitcoin _sempre_ se tornar um ``double`` ou ``float``, devemos deixar com apenas oito casas decimais antes de transformá-lo em uma ``string``. Obviamente, isso é um erro, portanto, certifique-se disso para que o código continue funcionando nas versões mais novas do Bitcoin Core.
#### Etapa 6.3: Criando a Matriz de Parâmetros
Para terminarmos de criar os parâmetros, só precisaremos agrupá-los em uma matriz JSON:
``` c
json_t *params = NULL;
params = json_array();
json_array_append(params,inputparams);
json_array_append(params,outputparams);
```
#### Etapa 6.4: Fazendo a chamada ao RPC
Vamos usar o método normal para criar uma chamada ao RPC:
``` c
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_CREATERAWTRANSACTION);
```
Agora, porém, devemos adicionar os nossos parâmetros. Isso pode ser feito facilmente com a função ``bitcoinrpc_method_set_params``:
``` c
if(bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
fprintf(stderr, "Error: Could not set params for createrawtransaction");
}
```
Depois, é só executar o RPC e obter os resultados:
``` c
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
lu_response = bitcoinrpc_resp_get(btcresponse);
lu_result = json_object_get(lu_response,"result");
char *tx_rawhex = strdup(json_string_value(lu_result));
```
### Etapa 7. Assinando a transação
É muito mais fácil atribuir um parâmetro simples a uma função. Basta criar uma matriz JSON e, em seguida, atribuir o parâmetro à matriz:
``` c
params = json_array();
json_array_append_new(params,json_string(tx_rawhex));
```
Por fim, vamos assinar a transação seguindo o rigamarole típico para criar uma chamada RPC:
``` c
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SIGNRAWTRANSACTION);
if(bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
fprintf(stderr, "Error: Could not set params for signrawtransaction");
}
json_decref(params);
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
lu_response = bitcoinrpc_resp_get(btcresponse);
```
Novamente, usar a função ``jansson`` para acessar a saída pode ser complicado. Devemos lembrar que ``hex`` é parte de um objeto JSON, não um resultado independente, como era quando criamos a transação bruta. Claro, sempre podemos acessar essas informações a partir da ajuda da linha de comando: ``bitcoin-cli help signrawtransaction``
``` c
lu_result = json_object_get(lu_response,"result");
json_t *lu_signature = json_object_get(lu_result,"hex");
char *tx_signrawhex = strdup(json_string_value(lu_signature));
json_decref(lu_signature);
```
> :warning: ***ATENÇÃO:*** Um programa em produção obviamente iria testar cuidadosamente a resposta de cada comando RPC para se certificar de que não teria erros. Isso é ainda mais verdadeiro para a função ``signrawtransaction``, porque podemos acabar com uma transação parcialmente assinada. Ou ainda pior, se não verificarmos os erros no objeto JSON, veremos apenas o ``hex`` e não iremos saber que ele não está assinado ou se está parcialmente assinado.
### Etapa 8. Enviando a transação
Agora podemos enviar a transação, usando todas as técnicas aprendidas anteriormente:
``` c
params = json_array();
json_array_append_new(params,json_string(tx_signrawhex));
rpc_method = bitcoinrpc_method_init(BITCOINRPC_METHOD_SENDRAWTRANSACTION);
if(bitcoinrpc_method_set_params(rpc_method, params) != BITCOINRPCE_OK) {
fprintf(stderr, "Error: Could not set params for sendrawtransaction");
}
json_decref(params);
bitcoinrpc_call(rpc_client, rpc_method, btcresponse, &btcerror);
lu_response = bitcoinrpc_resp_get(btcresponse);
lu_result = json_object_get(lu_response,"result");
char *tx_newid = strdup(json_string_value(lu_result));
printf("Txid: %s\n",tx_newid);
```
O código inteiro, com um _pouco_ mais verificação de erros, está disponível no Apêndice.
## Testando o código
O código completo pode ser encontrado no [diretório src/](src/15_2_sendtoaddress.c).
Compile-o como de costume:
```
$ cc sendtoaddress.c -lbitcoinrpc -ljansson -o sendtoaddress
```
Agora, é possível utilizá-lo para enviar fundos para um endereço:
```
./sendtoaddress tb1qynx7f8ulv4sxj3zw5gqpe56wxleh5dp9kts7ns .001
Txid: b93b19396f8baa37f5f701c7ca59d3128144c943af5294aeb48e3eb4c30fa9d2
```
Você pode ver as informações sobre esta transação que enviamos clicando [aqui](https://mempool.space/pt/testnet/tx/b93b19396f8baa37f5f701c7ca59d3128144c943af5294aeb48e3eb4c30fa9d2/).
## Resumo do Programando o Bitcoind usando C com bibliotecas RPC
Com acesso a uma biblioteca C, podemos criar programas com muito mais recursos quando comparados aos scripts no shell. Mas isso pode dar muito trabalho! Mesmo com 316 linhas de código, o ``sendtoaddress.c`` não cobre todos os detalhes necessários para transacionar bitcoins de forma segura e inteligente.
## O Que Vem Depois?
Aprenda mais sobre "Programando o Bitcoind usando C" na próxima sessão [15.3: Recebendo notificações usando C com a biblioteca ZMQ](15_3_Receiving_Bitcoind_Notifications_with_C.md).

View File

@ -1,155 +0,0 @@
# 15.3 Recebendo notificações usando C com a biblioteca ZMQ
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho que pode estar aguardando revisão. Portanto, leitor, tenha cuidado.
As sessões [§15.1](15_1_Accessing_Bitcoind_with_C.md) e [§15.2](15_2_Programming_Bitcoind_with_C.md) introduziram as bibliotecas RPC e JSON no C e, também mostrou uma das vantagens de acessar os comandos RPC do Bitcoin por meio de uma linguagem de programação: A capacidade de criar programas razoavelmente complexos. Este capítulo apresenta uma terceira biblioteca, a [ZMQ](http://zeromq.org/) e, ao fazer isso, revela outra vantagem: A capacidade de monitorar as notificações. Iremos usá-la para codificar para ouvirmos a blockchain.
> :book: ***O que é ZMQ?*** O ZeroMQ (ZMQ) é uma biblioteca de mensagens assíncronas de alto desempenho que fornece uma fila de mensagens. A biblioteca oferece suporte a padrões de mensagens comuns (pub/sub, request/reply, client/server e outros) em uma variedade de transportes (TCP, in-process, inter-process, multicast, WebSocket e mais), tornando mensagens entre processos tão simples quanto mensagens entre threads. Podemos encontrar mais detalhes sobre as notificações do ZMQ e outros tipos de mensagens [neste repositório](https://github.com/Actinium-project/ChainTools/blob/master/docs/chainlistener.md).
## Configurando o ZMQ
Antes de podemos ouvir a blockchain, precisaremos configurar o ``bitcoind`` para permitir as notificações ZMQ. Por isso, precisamos instalar a biblioteca ZMQ para tirar proveito dessas notificações.
### Configurando o ``bitcoind`` para usar o ZMQ
O Bitcoin Core está pronto para ZMQ, mas devemos especificar os endpoints do ZMQ. O ZeroMQ publish-sockets prefixa cada item de dados com um prefixo de tópico arbitrário que permite aos clientes assinantes solicitarem apenas os itens com um prefixo correspondente. Existem atualmente quatro tópicos suportados pelo ``bitcoind``:
```
$ bitcoind --help | grep zmq | grep address
-zmqpubhashblock=<address>
-zmqpubhashtx=<address>
-zmqpubrawblock=<address>
-zmqpubrawtx=<address>
```
Podemos executar o ``bitcoind`` com argumentos de linha de comando para endpoints ZMQ, como mostrado acima, mas também podemos criar um endpoint acessível adicionando linhas apropriadas ao nosso arquivo ``~/.bitcoin/bitcoin.conf`` e reiniciando o sistema.
```
zmqpubrawblock=tcp://127.0.0.1:28332
zmqpubrawtx=tcp://127.0.0.1:28333
```
Podemos então testar se os nossos endpoints estão funcionando usando o RPC ``getzmqnotifications``:
```
$ bitcoin-cli getzmqnotifications
[
{
"type": "pubrawblock",
"address": "tcp://127.0.0.1:28332",
"hwm": 1000
},
{
"type": "pubrawtx",
"address": "tcp://127.0.0.1:28333",
"hwm": 1000
}
]
```
Nosso ``bitcoind`` agora irá emitir as notificações ZMQ
### Instalando o ZMQ
Para aproveitar essas notificações, precisamos de uma biblioteca ZMQ para usar com o C, portanto, estaremos usando uma nova biblioteca ZMQ ao invés da biblioteca ``libbitcoinrpc`` nesta seção, mas no futuro, podemos combinar ambas.
Felizmente, as bibliotecas ZMQ estão disponíveis por meio de pacotes Debian padrão:
```
$ sudo apt-get install libzmq3-dev
$ sudo apt-get install libczmq-dev
```
Agora estamos pronto para escrever o código!
## Escrevendo o programa de notificação
O programa C à seguir é um cliente simples que se inscreve em um ponto da conexão ZMQ servido pelo ``bitcoind`` e lê as mensagens recebidas.
O programa requer dois parâmetros: O primeiro é o "servidor", que é o ponto de conexão TCP exposto pelo ``bitcoind``. O segundo é o "tópico", que atualmente é o ``zmqpubhashblock``,``zmqpubhashtx``, ``zmqpubrawblock`` ou ``zmqpubrawtx``. O tópico precisa ter suporte do ``bitcoin.conf`` e o endereço IP e a porta do servidor devem corresponder ao que está definido no arquivo de configuração.
``` c
#include <czmq.h>
int main(int argc, char ** argv) {
char *zmqserver;
char *topic;
if(argc < 3) {
printf("\nUSAGE:\nchainlistener <tcp://localhost:port> <topic>\n\n");
return 0;
} else {
zmqserver = argv[1];
topic = argv[2];
}
```
Abriremos um soquete ZMQ para o servidor e para o tópico definido:
``` c
zsock_t *socket = zsock_new_sub(zmqserver, topic);
assert(socket);
```
Depois, vamos esperar:
``` c
while(1) {
zmsg_t *msg;
int rc = zsock_recv(socket, "m", &msg);
assert(rc == 0);
char *header = zmsg_popstr(msg);
zframe_t *zdata = zmsg_pop(msg);
unsigned int *no = (unsigned int*)zmsg_popstr(msg);
char *data = zframe_strhex(zdata);
int len = zframe_size(zdata);
printf("Size: %d\n", len);
printf("Data: %s", data);
printf("\nNo: %d\n", *no);
free(header);
free(data);
free(no);
free(zdata);
zmsg_destroy(&msg);
sleep(1);
}
```
Enquanto esperamos, observamos as mensagens no soquete ZMQ. Sempre que recebermos uma mensagem, iremos retirá-la da pilha, relatando o número, comprimento e, o os dados que foram importante para nós.
É isso!
Claro, quando terminar o processo, precisamos limpar tudo:
``` c
zsock_destroy(&socket);
return 0;
}
```
### Testando o código de notificação
O código-fonte completo está no [diretório src/](src/15_3_chainlistener.c) como de costume. Precisamos compilá-lo:
```
$ cc -o chainlistener chainlistener.c -I/usr/local/include -L/usr/local/lib -lzmq -lczmq
```
Depois, podemos executá-lo com os tópicos e endereços que definimos no nosso ``bitcoin.conf``:
```
$ ./chainlistener tcp://127.0.0.1:28333 rawtx
Size: 250
Data: 02000000000101F5BD2032E5A9E6650D4E411AD272E391F26AFC3C9102B7C0C7444F8F74AE86010000000017160014AE9D51ADEEE8F46ED2017F41CD631D210F2ED9C5FEFFFFFF0203A732000000000017A9147231060F1CDF34B522E9DB650F44EDC6C0714E4C8710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC02483045022100AE316D5F21657E3525271DE39EB285D8A0E89A20AB6413824E88CE47DCD0EFE702202F61E10C2A8F4A7125D5EB63AEF883D8E3584A0ECED0D349283AABB6CA5E066D0121035A77FE575A9005E3D3FF0682E189E753E82FA8BFF0A20F8C45F06DC6EBE3421079111B00
No: 67
Size: 249
Data: 0200000000010165C986992F7DAD22BBCE3FCF0BF546EDBC3C599618B04CFA22D9E64EF0CE4C030000000017160014B58E0A5CD68B249F1C407E9AAE9CD0332AAA3067FEFFFFFF02637932000000000017A914CCC47261489036CB6B9AA610857793FF5752E5378710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC0247304402206CCC3F3B4BE01D4E532A01C2DC6BC3B53E4FFB6B494C8B87DD603EFC648A159902201653841E8B16A814DC375129189BB7CF01CFF7D269E91178645B6A97F5C7F4F10121030E20F3D2F172281B8DC747F007DF24B352248AC09E48CA64016942A8F01D317079111B00
No: 68
Size: 250
Data: 02000000000101E889CFC1FFE127BA49F6C1011388606A194109AE1EDAAB9BEE215E123C14A7920000000017160014577B0B3C2BF91B33B5BD70AE9E8BD8144F4B87E7FEFFFFFF02C34B32000000000017A914A9F1440402B46235822639C4FD2F78A31E8D269E8710270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC02483045022100B46318F53E1DCE63E7109DB4FA54AF40AADFC2FEB0E08263756BC3B7A6A744CB02200851982AF87DBABDC3DFC3362016ECE96AECFF50E24D9DCF264AE8966A5646FE0121039C90FCB46AEA1530E5667F8FF15CB36169D2AD81247472F236E3A3022F39917079111B00
No: 69
Size: 250
Data: 0200000000010137527957C9AD6CFF0C9A74597E6EFCD7E1EBD53E942AB2FA34A831046CA11488000000001716001429BFF05B3CD79E9CCEFDB5AE82139F72EB3E9DB0FEFFFFFF0210270000000000001976A914262437B129CF8592AB2EDC59C07D19C57729F72888AC231E32000000000017A9146C8D5FE29BFDDABCED0D6F4D8E82DCBFD9D34A8B8702483045022100F259846BAE29EB2C7A4AD711A3BC6109DE69AE91E35B14CA2742157894DD9760022021464E09C00ABA486AEAA0C49FEE12D2850DC03F57F04A1A9E2CC4D0F4F1459C012102899F24A9D60132F4DD1A5BA6DCD1E4E4B6C728927BA482C2C4E511679F60CA5779111B00
No: 70
.......
```
### Resumo do capítulo Recebendo Notificações Usando C com a Biblioteca ZMQ
Ao usar a estrutura ZMQ, podemos receber notificações facilmente, inscrevendo-as em um ponto de conexão exposto pelo ``bitcoind`` através do nosso arquivo de configuração.
> :fire: ***Qual é o poder das notificações?*** Com as notificações, não dependemos mais dos usuários para emitir os comandos. Ou seja, podemos criar programas que monitoram o blockchain do Bitcoin e tomar as ações apropriadas quando certas coisas ocorrem. Isso, por sua vez, pode ser utilizado juntamente com os comandos RPC que programamos nas seções anteriores. Este também é um grande passo além do que poderíamos fazer com os scripts shell: Certamente, podemos criar scripts shell que fica ouvindo infinitamente, mas existem outras linguagens de programação que possuem ferramentas melhores para isso.
## O Que Vem Depois?
Saiba mais sobre "como Programar com RPC" no [Capítulo 16: Programando Bitcoin com Libwally](16_0_Programming_with_Libwally.md).

View File

@ -0,0 +1,26 @@
# Capítulo 18: Conversando com o Bitcoind com Outras Linguagens
Agora devemos ter uma base sólida para trabalhar com Bitcoin usando a linguagem C, não apenas usando as bibliotecas RPC, JSON e ZMQ para interagir diretamente com o `bitcoind`, mas também, utilizando as bibliotecas Libwally para complementar esse trabalho. O C é uma ótima linguagem para prototipagem e abstração, porém provavelmente não é o que estamos usando para programar. Este capítulo, portanto, faz uma apresentação rápida de seis outras linguagens de programação, demonstrando a funcionalidade mais básica do Bitcoin em cada uma, permitindo que possamos expandir as lições da linha de comando e do C para a linguagem de programação que desejarmos.
Cada uma das seções contém aproximadamente as mesmas informações, o foco será: criar uma conexão RPC, examinar a carteira, criar um novo endereço e criar uma transação. No entanto, há alguma mudança entre as linguagens, mostrando diferentes aspectos dos comandos RPC do Bitcoin em diferentes exemplos. Em particular, algumas linguagens usam a metodologia fácil do `sendtoaddress`, enquanto outras usam uma metodologia mais difícil para a criação de uma transação bruta do zero.
## Objetivos Deste Capítulo
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
* Preparar ambientes de desenvolvimento para o Bitcoin para uma variedade de linguagens;
* Usar as funções de carteira em várias linguagens;
* Usar funções de transação em uma variedade de linguagens.
Os objetivos secundários do capítulo incluem a capacidade de:
* Saber mais sobre o Bitcoin RPC por meio de interações com uma variedade de linguagens.
## Tabela de Conteúdo
* [Seção 1: Acessando o Bitcoind com Go](18_1_Accessing_Bitcoind_with_Go.md)
* [Seção 2: Acessando o Bitcoind com Java](18_2_Accessing_Bitcoind_with_Java.md)
* [Seção 3: Acessando o Bitcoind com NodeJS](18_3_Accessing_Bitcoind_with_NodeJS.md)
* [Seção 4: Acessando o Bitcoind com Python](18_4_Accessing_Bitcoind_with_Python.md)
* [Seção 5: Acessando o Bitcoind com Rust](18_5_Accessing_Bitcoind_with_Rust.md)
* [Seção 6: Acessando o Bitcoind com Swift](18_6_Accessing_Bitcoind_with_Swift.md)

View File

@ -0,0 +1,420 @@
# 18.1: Acessando o Bitcoind com Go
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com o `bitcoind` usando a linguagem de programação Go e o [btcd rpcclient](https://github.com/btcsuite/btcd/tree/master/rpcclient). É importante observar que ele tem algumas peculiaridades e limitações.
## Configurando o Go
Para nos preparamos para o uso do Go em nossa máquina UNIX, primeiro precisamos instalar o curl, caso ainda não o tenhamos feito:
```
$ sudo apt install curl
```
Então, vamos ler a [página de downloads do Go](https://golang.org/dl/) para obtermos o link para o download mais recente e posteriormente fazer o download usando `curl`. Para uma configuração Debian, vamos querer usar a versão `linux-amd64`:
```
$ curl -O https://dl.google.com/go/go1.15.1.linux-amd64.tar.gz
```
Assim que terminarmos o download, comparamos o hash com o hash na [página de downloads do Go](https://golang.org/dl/):
```
$ sha256sum go1.15.1.linux-amd64.tar.gz
70ac0dbf60a8ee9236f337ed0daa7a4c3b98f6186d4497826f68e97c0c0413f6 go1.15.1.linux-amd64.tar.gz
```
Os hashes devem corresponder. Em caso afirmativo, extraímos o tarball e instalamos o Go em nosso sistema:
```
$ tar xfv go1.15.1.linux-amd64.tar.gz
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local
```
Agora precisamos criar um caminho no Go para especificar nosso ambiente. Abra o arquivo `~ / .profile` com o editor de texto de sua escolha e adicione o seguinte ao final dele:
```
export GOPATH=$HOME/work
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
```
Em seguida, atualizamos nosso perfil:
```
$ source ~/.profile
```
Por fim, vamos criar o diretório para o nosso espaço de trabalho Go:
```
$ mkdir $HOME/work
```
### Configurando o `btcd` e o `rpcclient`
Usaremos o `rpcclient` que advém do `btcd`, uma implementação Bitcoin escrita em Go. Embora o `rpcclient` tenha sido originalmente projetado para funcionar com o full node `btcd` do Bitcoin, ele também funciona com o Bitcoin Core. Ele tem algumas peculiaridades que veremos mais adiante.
Podemos usar o ```go get``` para baixá-lo:
```
$ go get github.com/btcsuite/btcd/rpcclient
```
Para testar seu funcionamento, vmaos navegar até o diretório com os exemplos do Bitcoin Core:
```
$ cd $GOPATH/src/github.com/btcsuite/btcd/rpcclient/examples/bitcoincorehttp
```
Vamos modificar o arquivo `main.go` e inserir os detalhes associados à configuração do Bitcoin Core, que pode ser encontrado no caminho `~ /.bitcoin/bitcoin.conf`:
```
Host: "localhost:18332",
User: "StandUp",
Pass: "6305f1b2dbb3bc5a16cd0f4aac7e1eba",
```
> **MAINNET VS TESTNET:** A porta seria 8332 para uma configuração na Mainnet.
Agora podemos executar um teste:
```
$ go run main.go
```
Devemos ver a contagem de blocos impressa:
```
2020/09/01 11:41:24 Block count: 1830861
```
### Criando um Projeto `rpcclient`
Normalmente, iríamos criar projetos no diretório `~/work/src/myproject/bitcoin`:
```
$ mkdir -p ~/work/src/myproject/bitcoin
$ cd ~/work/src/myproject/bitcoin
```
Cada projeto deve ter os seguintes `imports`:
```
import (
"log"
"fmt"
"github.com/btcsuite/btcd/rpcclient"
)
```
Esta declaração `import` permite que importemos bibliotecas relevantes. Para cada exemplo aqui, precisaremos importar `"log", "fmt"` e `"github.com/btcsuite/btcd/rpcclient"`. Podemos precisar importar bibliotecas adicionais em alguns exemplos.
* O `log` é usado para mostrar mensagens de erro na tela. Após cada vez que o node Bitcoin for chamado, uma instrução `if` irá verificar se há algum erro. Se houver erros, o `log` é usado para imprimi-los;
* O `fmt` é usado para imprimir a saída;
* O `rpcclient` é obviamente a biblioteca do `rpcclient`;
## Construindo Nossa Conexão
Cada função do `bitcoind` no Go começa com a criação da conexão RPC, usando a função `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()
```
Os parâmetros da `connCfg` permitem que escolhamos a porta Bitcoin RPC, nome de usuário, senha e se estamos usando a testnet ou mainnet.
> **NOTA:** Novamente, precisamos nos certificar de substituir o `User` e o `Pass` com aqueles encontrados no nosso `~/.bitcoin/bitcon.conf`.
A função `rpcclient.New(connCfg, nil)` configura o`client` para nos conectarmos ao nosso node Bitcoin.
A linha `defer client.Shutdown()` é para desconectar do nosso node Bitcoin, uma vez que a função `main()` termina de ser executada. Após a linha `defer client.Shutdown()` é onde as coisas interessantes acontecem e será muito fácil de utilizar. Isso porque o `rpcclient` ajuda a transformar os comandos `bitcoin-cli` em funções, usando PascalCase. Por exemplo, `bitcoin-cli getblockcount` se transformará em `client.GetBlockCount` no Go.
### Fazendo uma Chamada RPC
Agora, tudo o que precisamos fazer é uma chamada informativa como `GetBlockCount` ou` GetBlockHash` usando nosso `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())
```
### Fazendo uma Chamada RPC com Argumentos
As funções `rpcclient` também podem receber entradas, por exemplo, `client.GetBlockHash(blockCount)` recebe a contagem de blocos como uma entrada. O `client.GetBlockHash (blockCount)` de cima seria parecido com um comando `bitcoin-cli`:
```
$ bitcoin-cli getblockhash 1830868
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c
```
No entanto, uma peculiaridade com hashes no `rpcclient` é que normalmente eles irão ser mostrados em uma codificação diferente se imprimirmos normalmente com o ` blockHash`. Para imprimi-los como uma string, precisamos usar o `blockHash.String()`.
### Executando Nosso Código
Podemos baixar o código completo do [diretório src](src/18_1_blockinfo.go).
Podemos então, executar:
```
$ go run blockinfo.go
1830868
00000000000002d53b6b9bba4d4e7dc44a79cebd1024d1bcfb9b3cc07d6cad9c
```
O último número do bloco, junto com nosso hash, devem ser impressos.
## Procurando por Fundos
Devido às limitações do `btcd` no `rpcclient`, não podemos fazer uso da função `getwalletinfo`. No entanto, podemos usar o RPC `getbalance`:
```
wallet, err := client.GetBalance("*")
if err != nil {
log.Fatal(err)
}
fmt.Println(wallet)
```
O `client.GetBalance("*")` requer a entrada `"*"` devido a uma peculiaridade do `btcd`. O asterisco significa que desejamos obter o saldo de todas as nossas carteiras.
Se executarmos [o código src](src/18_1_getbalance.go), deveremos obter uma saída semelhante a esta:
```
$ go run getbalance.go
0.000689 BTC
```
## Criando um Endereço
Podemos gerar endereços em Go, mas não podemos especificar o tipo do endereço:
Isso requer o uso de uma função especial `chaincfg`, para especificar para qual rede os endereços estão sendo criados. Esta especificação é necessária apenas durante a geração do endereço, por isso é usada apenas neste exemplo. Também podemos incluir isso nos demais exemplos, mas não é necessário.
Certifique-se de importar o `"github.com/btcsuite/btcd/chaincfg"`:
```
import (
"log"
"fmt"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcd/chaincfg"
)
```
Em seguida, vamos chamar o `connCfG` com o 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:** O `Params: chaincfg.TestNet3Params.Name` deve ser `Params: chaincfg.MainNetParams.Name,` na Mainnet.
Podemos então criar nosso endereço:
```
address, err := client.GetNewAddress("")
if err != nil {
log.Fatal(err)
}
fmt.Println(address)
```
Uma peculiaridade com o `client.GetNewAddress("")` é que uma string vazia precisa ser incluída para que tudo funcione perfeitamente.
Executando o [código fonte](18_1_getaddress.go) teremos os seguintes resultados:
```
$ go run getaddress.go
tb1qutkcj34pw0aq7n9wgp3ktmz780szlycwddfmza
```
### Decodificando um Endereço
Criar um endereço exigia um trabalho extra, em especificar a blockchain correta. Usar um endereço também exigirá, porque teremos que decodificá-lo antes de usá-lo.
Isso significa que teremos que importar as bibliotecas `"github.com/btcsuite/btcutil"` e `"github.com/btcsuite/btcd/chaincfg"`.
* O `btcutil` permite que um endereço Bitcoin seja decodificado de uma forma que o `rpcclient` possa entender. Isso é necessário ao trabalhar com endereços no `rpcclient`;
* O `chaincfg` é (novamente) usado para configurar nossa chain como a chain Testnet. Isso é necessário para a decodificação de endereços, pois os endereços usados na Mainnet e na Testnet são diferentes.
```
import (
"log"
"fmt"
"github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcutil"
"github.com/btcsuite/btcd/chaincfg"
)
```
A variável defaultNet agora é usada para especificar se nosso node Bitcoin está na Testnet ou na Mainnet. Essa informação (e o objeto `btcutil`) é então usada para decodificar o endereço.
> **MAINNET VS TESTNET:** `&chaincfg.TestNet3Params` deve ser `& chaincfg.MainNetParams` na Mainnet.
```
defaultNet := &chaincfg.TestNet3Params
addr, err := btcutil.DecodeAddress("mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha", defaultNet)
if err != nil {
log.Fatal(err)
}
```
> **NOTA:** Precisamos alterar o endereço (`mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha`) para um que seja da nossa carteira. Podemos usar o `bitcoin-cli listunspent` para encontrar alguns endereços com fundos para teste. Se quisermos ser realmente sofisticados, podemos modificar o código Go para obter um argumento e, em seguida, escrever um script que executa o `listunspent`, para depois salvarmos a informação em uma variável e executar o código Go nela.
Só depois disso usamos o RPC `getreceivedbyaddress` no nosso endereço decodificado:
```
wallet, err := client.GetReceivedByAddress(addr)
if err != nil {
log.Fatal(err)
}
fmt.Println(wallet)
```
Ao executar [o código](src/18_1_getamountreceived.go), devemos obter uma saída semelhante a esta:
```
$ go run getamountreceived.go
0.0085 BTC
```
## Enviando uma Transação
Agora temos todas as peças do quebra-cabeça no lugar para enviar uma transação. Vamos querer:
1. Importar as bibliotecas corretas, incluindo a `chaincfg` para especificar uma rede e o `btcutil` para decodificar um endereço;
2. Escolher um endereço para enviar;
3. Decodificar esse endereço;
4. Executar o `sendtoaddress` para enviar fundos da maneira 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)
}
```
Quando executamos [o código](src/18_1_sendtransaction.go), o txid da transação nos será retornado:
```
$ go run sendtransaction.go
9aa4cd6559e0d69059eae142c35bfe78b71a8084e1fcc2c74e2a9675e9e7489d
```
### Consultando uma Transação
Para consultar uma transação, como a que acabamos de enviar, precisaremos fazer mais uma vez algumas conversões, desta vez do txid. O `"github.com/btcsuite/btcd/chaincfg/chainhash"` é importado para permitir que os hashes sejam armazenados no código Go. O `chainhash.NewHashFromStr("hash")` converte um hash em uma string para um formato que funciona com o 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:** Novamente, vamos querer trocar o txid por um que realmente será reconhecido pelo nosso sistema.
Ao executar [o código](src/18_1_lookuptransaction.go), ele imprimirá os detalhes associados a uma transação, como seu valor e quantas vezes foi confirmada:
```
$ 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"
}
```
## Resumo: Acessando o Bitcoind com Go
Embora o `btcd` e o `rpcclient` tenham alguns limites, ainda podemos executar os principais comandos RPC no Go. A documentação para o `rpcclient` está disponível no [Godoc](https://godoc.org/github.com/btcsuite/btcd/rpcclient). Se a documentação não tiver o que procuramos, podemos consultar também o [repositório btcd](https://github.com/btcsuite/btcd). Geralmente é bem documentado e fácil de ler. Com base nesses exemplos, devemos ser capazes de incorporar o Bitcoin em um projeto Go e fazer coisas como enviar e receber moedas.
## O Que Vem Depois?
Vamos aprender mais sobre "Conversando com o Bitcoind com Outras Linguagens" na seção [§18.2: Acessando Bitcoin com Java](18_2_Accessing_Bitcoind_with_Java.md).

View File

@ -0,0 +1,332 @@
# 18.2: Acessando o Bitcoind com Java
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com `bitcoind` usando a linguagem de programação Java e o [JavaBitcoindRpcClient](https://github.com/Polve/JavaBitcoindRpcClient).
## Configurando o Java
Podemos instalar o Java em nosso servidor, usando o comando `apt-get`. Também precisaremos instalar o [Apache Maven](http://maven.apache.org/) para gerenciar as dependências.
```
$ sudo apt-get install openjdk-11-jre-headless maven
```
Podemos verificar a instalação do Java usando o comando abaixo:
```
$ java -version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment (build 11.0.8+10-post-Debian-1deb10u1)
OpenJDK 64-Bit Server VM (build 11.0.8+10-post-Debian-1deb10u1, mixed mode, sharing)
```
### Criando um Projeto Maven
Para programar o Bitcoin usando o java, criaremos um projeto Maven:
```
$ mvn archetype:generate -DgroupId=com.blockchaincommons.lbtc -DartifactId=java-project -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
```
Isso irá baixar algumas dependências:
```
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/2.5/maven-clean-plugin-2.5.pom (4 KB at 4.2 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/22/maven-plugins-22.pom (13 KB at 385.9 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/21/maven-parent-21.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/21/maven-parent-21.pom (26 KB at 559.6 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/apache/10/apache-10.pom
..............
```
Ele também criará um arquivo de configuração `pom.xml`:
```
$ cd java-project
$ ls -lagh
total 16K
drwxr-xr-x 3 sudo 4.0K Sep 1 13:58 .
drwxr-xr-x 15 sudo 4.0K Sep 1 13:58 ..
-rw-r--r-- 1 sudo 663 Sep 1 13:58 pom.xml
drwxr-xr-x 4 sudo 4.0K Sep 1 13:58 src
```
Para incluir o `JavaBitcoindRpcClient`, devemos adicionar nossa dependência a `<dependendencies>` no arquivo `pom.xml`.
```xml
<dependency>
<groupId>wf.bitcoin</groupId>
<artifactId>bitcoin-rpc-client</artifactId>
<version>1.2.1</version>
</dependency>
```
Também precisamos adicionar propriedades do compilador para indicar qual versão do JDK compilará o código-fonte.
```
<properties>
<!-- https://maven.apache.org/general.html#encoding-warning -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
```
Sempre que adicionarmos um código-fonte às nossas classes, poderemos testá-lo com:
```
$ mvn compile
```
Também podemos executá-lo com `exec: java`
```
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
```
### Criando Projetos Alternativos
Se usarmos o [Gradle](https://gradle.org/releases/), poderemos executar o seguinte comando:
```groovy
compile 'wf.bitcoin:JavaBitcoindRpcClient:1.2.1'
```
Se quisermos um projeto de amostra e algumas instruções sobre como executá-lo no servidor que acabamos de criar, podemos consultar o [Projeto de amostra do Bitcoind Java](https://github.com/bvolpato/bitcoind-java-client-sample). Também podemos navegar por todo o código de origem do [bitcoin-rpc-client](https://github.com/Polve/bitcoin-rpc-client).
## Construindo Nossa Conexão
Para usar o `JavaBitcoindRpcClient`, precisamos criar uma instância `BitcoindRpcClient`. Fazemos isso criando um URL com argumentos de nome de usuário, senha, endereço IP e porta. Como devemos nos lembrar, o endereço IP `127.0.0.1` e a porta `18332` devem estar corretos para a configuração testnet padrão descrita neste curso, enquanto podemos extrair o usuário e a senha abrindo o arquivo `~/.bitcoin/bitcoin.conf`.
```java
BitcoindRpcClient rpcClient = new BitcoinJSONRPCClient("http://StandUp:6305f1b2dbb3bc5a16cd0f4aac7e1eba@localhost:18332");
```
Podemos observar que também precisaremos importar as informações apropriadas:
```
import wf.bitcoin.javabitcoindrpcclient.BitcoinJSONRPCClient;
import wf.bitcoin.javabitcoindrpcclient.BitcoindRpcClient;
```
> **MAINNET VS TESTNET:** A porta seria 8332 para uma configuração da mainnet.
Se o `rpcClient` for inicializado com sucesso, poderemos enviar comandos RPC.
Mais tarde, quando terminarmos nossa conexão `bitcoind`, precisaremos fechá-la:
```
rpcClient.stop();
```
### Fazendo uma Chamada RPC
Você verá que o `BitcoindRpcClient` fornece a maioria das funcionalidades que podem ser acessadas através do `bitcoin-cli` ou outros métodos RPC, usando o mesmo método que o nome, mas em camelCase.
Por exemplo, para executar o comando `getmininginfo` para obter as informações do bloco e a dificuldade na rede, devemos usar o método `getMiningInfo()`:
```java
MiningInfo info = rpcClient.getMiningInfo();
System.out.println("Mining Information");
System.out.println("------------------");
System.out.println("Chain......: " + info.chain());
System.out.println("Blocks.....: " + info.blocks());
System.out.println("Difficulty.: " + info.difficulty());
System.out.println("Hash Power.: " + info.networkHashps());
```
O retorno para esta linha deve algo próximo a isso:
```
Mining Information
------------------
Chain......: test
Blocks.....: 1830905
Difficulty.: 4194304
Hash Power.: 40367401348837.41
```
### Fazendo uma Chamada RPC com Argumentos
Podemos procurar os endereços em nossa carteira passando o endereço como um argumento para o comando `getAddressInfo`:
```java
String addr1 = "mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo";
AddressInfo addr1Info = rpcClient.getAddressInfo(addr1);
System.out.println("Address: " + addr1Info.address());
System.out.println("MasterFingerPrint: " + addr1Info.hdMasterFingerprint());
System.out.println("HdKeyPath: " + addr1Info.hdKeyPath());
System.out.println("PubKey: " + addr1Info.pubKey());
```
O resultado será mais ou menos assim:
```
Address: mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo
MasterFingerPrint: ce0c7e14
HdKeyPath: m/0'/0'/5'
PubKey: 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65
```
### Executando Nosso Código
O código para esses exemplos pode ser encontrado no [diretório src/](src/18_2_App-getinfo.java) e deve ser instalado na estrutura de diretório padrão criada neste caso como `~/java-project/src/main/java/com/blockchaincommons/lbtc/App.java`. Ele pode então ser compilado e executado.
```
$ mvn compile
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
Chain......: test
Blocks.....: 1831079
Difficulty.: 4194304
Hash Power.: 38112849943221.16
Address: mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo
MasterFingerPrint: ce0c7e14
HdKeyPath: m/0'/0'/5'
PubKey: 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65
```
Você também verá muito mais informações sobre a compilação, é claro.
## Consultando Fundos
Recuperar o saldo de uma conta inteira é tão fácil quanto:
```
System.out.println("Balance: " + rpcClient.getBalance());
```
## Criando um Endereço
Podemos criar um novo endereço em nossa carteira, anexando um rótulo específico a ela e até mesmo descartando nossa chave privada.
```java
String address = rpcClient.getNewAddress("Learning-Bitcoin-from-the-Command-Line");
System.out.println("New Address: " + address);
String privKey = rpcClient.dumpPrivKey(address);
System.out.println("Priv Key: " + privKey);
```
Retorno:
```
New Address: mpsFtZ8qTJPRGZy1gaaUw37fHeUSPLkzzs
Priv Key: cTy2AnmAALsHokYzJzTdsUBSqBtypmWfmSNYgG6qQH43euUZgqic
```
## Enviando uma Transação
A biblioteca `JavaBitcoindRpcClient` possui algumas ferramentas interessantes que facilitam a criação de uma transação desde o início.
### Criando uma Transação
Podemos criar uma transação bruta usando o método `createRawTransaction`, passando como argumentos dois objetos ArrayList contendo entradas e saídas a serem utilizadas.
Primeiro configuramos nossos novos endereços, aqui um endereço existente em nosso sistema e um novo endereço.
```
String addr1 = "tb1qdqkc3430rexxlgnma6p7clly33s6jjgay5q8np";
System.out.println("Used address addr1: " + addr1);
String addr2 = rpcClient.getNewAddress();
System.out.println("Created address addr2: " + addr2);
```
Então, podemos usar o RPC `listUnspent` para encontrar UTXOs para o endereço existente.
```
List<Unspent> utxos = rpcClient.listUnspent(0, Integer.MAX_VALUE, addr1);
System.out.println("Found " + utxos.size() + " UTXOs (unspent transaction outputs) belonging to addr1");
```
Aqui está um resultado de todas as informações:
```java
System.out.println("Created address addr1: " + addr1);
String addr2 = rpcClient.getNewAddress();
System.out.println("Created address addr2: " + addr2);
List<String> generatedBlocksHashes = rpcClient.generateToAddress(110, addr1);
System.out.println("Generated " + generatedBlocksHashes.size() + " blocks for addr1");
List<Unspent> utxos = rpcClient.listUnspent(0, Integer.MAX_VALUE, addr1);
System.out.println("Found " + utxos.size() + " UTXOs (unspent transaction outputs) belonging to addr1");
```
As transações são criadas com o comando `BitcoinRawTxBuilder`:
```
BitcoinRawTxBuilder txb = new BitcoinRawTxBuilder(rpcClient);
```
Primeiro preenchemos as entradas com os UTXOs que estamos gastando:
```
TxInput in = utxos.get(0);
txb.in(in);
```
> :warning: **AVISO:** Obviamente, em um programa real, selecionaríamos um UTXO de forma inteligente, porém, neste caso, pegamos apenas o enésimo, uma tática que usaremos ao longo deste capítulo.
Em segundo lugar, preenchemos as saídas, cada uma com um valor e um endereço:
```
BigDecimal estimatedFee = BigDecimal.valueOf(0.00000200);
BigDecimal txToAddr2Amount = utxos.get(0).amount().subtract(estimatedFee);
txb.out(addr2, txToAddr2Amount);
System.out.println("unsignedRawTx in amount: " + utxos.get(0).amount());
System.out.println("unsignedRawTx out amount: " + txToAddr2Amount);
```
Agora estamos prontos para realmente criar a transação:
```
String unsignedRawTxHex = txb.create();
System.out.println("Created unsignedRawTx from addr1 to addr2: " + unsignedRawTxHex);
```
### Assinando uma Transação
Agora podemos assinar a transação com o método `signRawTransactionWithKey`. Este método recebe como parâmetros uma transação de string bruta não assinada, a chave privada do endereço de envio e o objeto TxInput.
```java
SignedRawTransaction srTx = rpcClient.signRawTransactionWithKey(
unsignedRawTxHex,
Arrays.asList(rpcClient.dumpPrivKey(addr1)), //
Arrays.asList(in),
null);
System.out.println("signedRawTx hex: " + srTx.hex());
System.out.println("signedRawTx complete: " + srTx.complete());
```
### Enviando uma Transação
Finalmente, o envio requer o comando `sendRawTransaction`:
```java
String sentRawTransactionID = rpcClient.sendRawTransaction(srTx.hex());
System.out.println("Sent signedRawTx (txID): " + sentRawTransactionID);
```
### Executando Nosso Código
Agora podemos executar [o código da transação](src/18_2_App-sendtx.java) como `~/java-project/src/main/java/com/blockchaincommons/lbtc/App.java`.
```
$ mvn compile
$ mvn exec:java -Dexec.mainClass=com.blockchaincommons.lbtc.App
Used address addr1: tb1qdqkc3430rexxlgnma6p7clly33s6jjgay5q8np
Created address addr2: tb1q04q2wzlhfqlrnz95ynfj7gp4t3yynrj0542smv
Found 1 UTXOs (unspent transaction outputs) belonging to addr1
unsignedRawTx in amount: 0.00850000
unsignedRawTx out amount: 0.00849800
Created unsignedRawTx from addr1 to addr2: 0200000001d2a90fc3b43e8eb4ae9452af43c9448112d359cac701f7f537aa8b6f39193bb90100000000ffffffff0188f70c00000000001600147d40a70bf7483e3988b424d32f20355c48498e4f00000000
signedRawTx hex: 02000000000101d2a90fc3b43e8eb4ae9452af43c9448112d359cac701f7f537aa8b6f39193bb90100000000ffffffff0188f70c00000000001600147d40a70bf7483e3988b424d32f20355c48498e4f024730440220495fb64d8cf9dee9daa8535b8867709ac8d3763d693fd8c9111ce610645c76c90220286f39a626a940c3d9f8614524d67dd6594d9ee93818927df4698c1c8b8f622d01210333877967ac52c0d0ec96aca446ceb3f51863de906e702584cc4da2780d360aae00000000
signedRawTx complete: true
Sent signedRawTx (txID): 82032c07e0ed91780c3369a1943ea8abf49c9e11855ffedd935374ecbc789c45
```
## Escutando Transações ou Blocos
Tal como acontece com [C e suas bibliotecas ZMQ](16_3_Receiving_Bitcoind_Notifications_with_C.md), existem maneiras fáceis de usar o Java para escutar a blockchain, além de executar o código específico quando algo acontece, como uma transação que envolve um endereço em nossa carteira, ou até a geração de um novo bloco na rede.
Para fazer isso, podemos usar a classe `BitcoinAcceptor` do `JavaBitcoindRpcClient`, que nos permite anexar "ouvintes" à rede.
```java
String blockHash = rpcClient.getBestBlockHash();
BitcoinAcceptor acceptor = new BitcoinAcceptor(rpcClient, blockHash, 6, new BitcoinPaymentListener() {
@Override
public void transaction(Transaction tx) {
System.out.println("Transaction: " + tx);
}
@Override
public void block(String block) {
System.out.println("Block: " + block);
}
});
acceptor.run();
```
Veja [o diretório src/](src/18_2_App-listen.java) para o código completo. Cada vez que uma transação é enviada ou um novo bloco é gerado, devemos ver a saída em nosso console:
```
Transaction: {account=Tests, address=mhopuJzgmTwhGfpNLCJ9CRknugY691oXp1, category=receive, amount=5.0E-4, label=Tests, vout=1, confirmations=0, trusted=false, txid=361e8fcff243b74ebf396e595a007636654f67c3c7b55fd2860a3d37772155eb, walletconflicts=[], time=1513132887, timereceived=1513132887, bip125-replaceable=unknown}
Block: 000000004564adfee3738314549f7ca35d96c4da0afc6b232183917086b6d971
```
### Resumo: Acessando o Bitcoind com Java
Usando a biblioteca `javabitcoinrpc`, podemos acessar facilmente o `bitcoind` por meio de chamadas RPC com Java. Também teremos acesso a recursos adicionais interessantes, como o serviço de escuta usando o comando `bitcoinAcceptor`.
## O Que Vem Depois?
Vamos aprender mais sobre "Conversando com o Bitcoind com Outras Linguagens" na seção [§18.3: Acessando o Bitcoind com NodeJS](18_3_Accessing_Bitcoind_with_NodeJS.md).

View File

@ -0,0 +1,273 @@
# 18.3: Acessando o Bitcoind com NodeJS
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com o `bitcoind` usando a linguagem de programação NodeJS e o [pacote BCRPC](https://github.com/dgarage/bcrpc).
## Configurando o Node.js
O BCRPC é construído em node.js. Portanto, primeiro precisamos instalar os pacotes `node.js` e o `npm` (o gerenciador de pacotes do node) em nosso sistema.
Se estiver usando uma máquina Ubuntu, podemos executar os seguintes comandos para obter uma nova versão do `node.js`, ao invés da versão terrivelmente desatualizada no sistema de pacotes do Ubuntu.
```
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo bash -
$ sudo apt-get install -y nodejs
$ sudo npm install mocha -g
```
### Configurando o BCRPC
Agora podemos clonar o pacote BCRPC do GitHub e instalar as dependências.
```
$ git clone https://github.com/dgarage/bcrpc.git
$ cd bcrpc
$ npm install
```
Para testar o pacote BCRPC, devemos primeiro definir as variáveis de ambiente para o rpcuser e rpcpassword. Como de costume, elas vêm do `~/.bitcoin/bitcoin.conf`. Também devemos definir a porta RPC como sendo 18332, que deve ser a correta para a configuração Testnet padrão descrita nos documentos.
```
$ export BITCOIND_USER=StandUp
$ export BITCOIND_PASS=d8340efbcd34e312044c8431c59c792c
$ export BITCOIND_PORT=18332
```
> :warning: **AVISO:** Obviamente, você nunca colocaria sua senha em uma variável de ambiente em um ambiente de produção.
> :link: **MAINNET VS TESTNET:** A porta seria 8332 para uma configuração na Mainnet.
Agora podemos verificar se tudo está funcionando corretamente:
```
$ npm test
> bcrpc@0.2.2 test /home/user1/bcrpc
> mocha tests.js
BitcoinD
✓ is running
bcrpc
✓ can get info
2 passing (36ms)
```
Parabéns, agora temos um wrapper RPC pronto para ser usado no Bitcoin com o Node.js e que está funcionando com as nossas configurações do Bitcoin.
### Criando um Projeto BCRPC
Agora podemos criar um novo projeto Node.js e instalar o BCRPC via npm.
```
$ cd ~
$ mkdir myproject
$ cd myproject
$ npm init
[continue with default options]
$ npm install bcrpc
```
## Construindo Nossa Conexão
Em nosso diretório `myproject`, criamos um arquivo `.js` onde nosso código JavaScript será executado.
Podemos iniciar uma conexão RPC criando um `RpcAgent`:
```
const RpcAgent = require('bcrpc');
agent = new RpcAgent({port: 18332, user: 'StandUp', pass: 'd8340efbcd34e312044c8431c59c792c'});
```
Obviamente, nosso `user` e `pass` devem coincidir novamente com o que está em nosso `~/.bitcoin/bitcoin.conf`, e usamos a `port 18332` se estivermos na Testnet.
### Fazendo uma chamada RPC
Usando o BCRPC, podemos usar os mesmos comandos RPC que normalmente usaríamos via `bitcoin-cli` com nosso `RpcAgent`, exceto que eles precisam estar em camelCase. Por exemplo, `getblockhash` seria `getBlockHash`.
Para imprimir o número do bloco mais recente, basta chamar o `getBlockCount` através do nosso `RpcAgent`:
```
agent.getBlockCount(function (err, blockCount) {
if (err)
throw Error(JSON.stringify(err));
console.log(blockCount.result);
});
```
### Fazendo uma chamada RPC com argumentos
As funções BCRPC podem aceitar argumentos. Por exemplo, o `getBlockHash` recebe o `blockCount.result` como uma entrada.
```
agent.getBlockHash(blockCount.result, function (err, hash) {
if (err)
throw Error(JSON.stringify(err));
console.log(hash.result);
})
```
O resultado das funções BCRPC é um objeto JSON contendo informações sobre quaisquer erros e o id da solicitação. Ao acessar nosso resultado, adicionamos o `.result` no final dele para especificar que estamos interessados no resultado real, não em informações sobre os erros.
### Executando Nosso Código
Podemos encontrar o código `getinfo` no [diretório src/](src/18_3_getinfo.js).
```
$ node getinfo.js
1831094
00000000000002bf8b522a830180ad3a93b8eed33121f54b3842d8838580a53c
```
Isso é com o que a saída do exemplo acima se pareceria se substituíssemos o `console.log(blockCount.result);` e o `console.log(hash.result);` por `console.log(blockCount);` e `console.log (hash);`, respectivamente:
```
{ result: 1774686, error: null, id: null }
{
result: '00000000000000d980c495a2b7addf09bb0a9c78b5b199c8e965ee54753fa5da',
error: null,
id: null
}
```
## Pesquisando por Fundos
É útil, ao aceitar Bitcoin, verificar o Bitcoin recebido em um endereço específico em nossa carteira. Por exemplo, se administrássemos uma loja online que aceita Bitcoin, para cada pagamento de um cliente, geraríamos um novo endereço, mostraríamos esse endereço ao cliente e, em seguida, verificaríamos o saldo do endereço após algum tempo, para certificar-se de que o montante foi recebido:
```
agent.getReceivedByAddress('mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha', function (err, addressInfo) {
if (err)
throw Error(JSON.stringify(err));
console.log(addressInfo.result);
});
```
> :information_source: **NOTA:** Obviamente, precisaremos inserir um endereço reconhecido por nossa máquina.
Por padrão, esta função verifica as transações que foram confirmadas uma vez, no entanto, podemos aumentar para um número maior, como 6:
```
agent.getReceivedByAddress('mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha', 6, function (err, addressInfo) {
if (err)
throw Error(JSON.stringify(err));
console.log(addressInfo.result);
});
```
### Pesquisando Informações da Carteira
Também podemos procurar informações adicionais sobre nossa carteira e visualizar nosso saldo, contagem de transações etc.
```
agent.getWalletInfo(function (err, walletInfo) {
if (err)
throw Error(JSON.stringify(err));
console.log(walletInfo.result);
});
```
O código está disponível como [walletinfo.js](src/18_3_walletinfo.js).
```
$ node walletinfo.js
0.008498
{
walletname: '',
walletversion: 169900,
balance: 0.010438,
unconfirmed_balance: 0,
immature_balance: 0,
txcount: 4,
keypoololdest: 1596567843,
keypoolsize: 999,
hdseedid: 'da5a1b058deb9e51ecffef1b0ddc069a5dfb2c5f',
keypoolsize_hd_internal: 1000,
paytxfee: 0,
private_keys_enabled: true,
avoid_reuse: false,
scanning: false
}
```
Ao invés de imprimirmos todos os detalhes associados à nossa carteira, podemos imprimir informações específicas, como nosso saldo. Como um objeto JSON está sendo acessado, podemos fazer isso alterando a linha `console.log(walletInfo.result);` para `console.log(walletInfo.result.balance);`:
## Criando um Endereço
Também podemos passar argumentos adicionais para os comandos RPC. Por exemplo, o seguinte gera um novo endereço legado, com o sinalizador `-addresstype`.
```
agent.getNewAddress('-addresstype', 'legacy', function (err, newAddress) {
if (err)
throw Error(JSON.stringify(err));
console.log(newAddress.result);
});
```
Isso é o mesmo que executar o seguinte na linha de comando:
```
$ bitcoin-cli getnewaddress -addresstype legacy
mtGPcBvRPZFEHo2YX8un9qqPBydhG82uuZ
```
No BCRPC, geralmente podemos usar os mesmos sinalizadores que no `bitcoin-cli` no BCRPC. Embora usamos o camelCase (`getNewAddress`) para os métodos, os sinalizadores, que normalmente são separados por espaços na linha de comando, são colocados em strings e separados por vírgulas.
## Enviando uma Transação
Podemos enviar saldos para um endereço muito facilmente, usando a função `sendToAddress`:
```
agent.sendToAddress(newAddress.result, 0.00001, function(err, txid) {
if (err)
throw Error(JSON.stringify(err));
console.log(txid.result);
});
```
Isso deve retornar o txid da transação:
```
1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9
```
### Pesquisando uma Transação
Agora podemos desejar visualizar uma transação, como a que acabamos de enviar.
```
agent.getTransaction(txid.result, function (err, transaction) {
if (err)
throw Error(JSON.stringify(err));
console.log(transaction.result);
});
```
Devemos obter uma saída semelhante a esta:
```
{
amount: 0.001,
confirmations: 4776,
blockhash: '000000006628870b0a8a66abea9cf0d4e815c491f079e3fa9e658a87b5dc863a',
blockindex: 117,
blocktime: 1591857418,
txid: '1661ce322c128e053b8ea8fcc22d17df680d2052983980e2281d692b9b4ab7df',
walletconflicts: [],
time: 1591857343,
timereceived: 1591857343,
'bip125-replaceable': 'no',
details: [
{
address: 'mpGpCMX6SuUimDZKiVViuhd7EGyVxkNnha',
category: 'receive',
amount: 0.001,
label: '',
vout: 0
}
],
hex: '02000000000101e9e8c3bd057d54e73baadc60c166860163b0e7aa60cab33a03e89fb44321f8d5010000001716001435c2aa3fc09ea53c3e23925c5b2e93b9119b2568feffffff02a0860100000000001976a914600c8c6a4abb0a502ea4de01681fe4fa1ca7800688ac65ec1c000000000017a91425b920efb2fde1a0277d3df11d0fd7249e17cf8587024730440220403a863d312946aae3f3ef0a57206197bc67f71536fb5f4b9ca71a7e226b6dc50220329646cf786cfef79d60de3ef54f702ab1073694022f0618731902d926918c3e012103e6feac9d7a8ad1ac6b36fb4c91c1c9f7fff1e7f63f0340e5253a0e4478b7b13f41fd1a00'
}
```
O código completo está disponível no [sendtx.js](src/18_3_sendtx.js).
## Resumo: Acessando o Bitcoind com NodeJS
Com o BCRPC podemos acessar todos os comandos RPC disponíveis através do `bitcoin-cli`, usando o JavaScript. O [BCRPC README](https://github.com/dgarage/bcrpc) tem alguns exemplos que usam promises (os exemplos neste livro usam callbacks). O [JavaScript por trás dele](https://github.com/dgarage/bcrpc/blob/master/index.js) é curto e bem legível.
Com base nesses exemplos, devemos ser capazes de incorporar Bitcoin em um projeto Node.js e fazer coisas como enviar e receber fundos.
## O Que Vem Depois?
Vamos aprender mais sobre "Conversando com o Bitcoind com Outras Linguagens" na seção [§18.4: Acessando o Bitcoind com Python](18_4_Accessing_Bitcoind_with_Python.md).

View File

@ -0,0 +1,495 @@
# 18.4: Acessando o Bitcoind com Python
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com o `bitcoind` usando a linguagem de programação Python e o [Python-BitcoinRPC](https://github.com/jgarzik/python-bitcoinrpc).
## Configurando o Python
Se já temos o Bitcoin Core instalado, provavelmente temos o Python 3 disponível.
Podemos verificar isso executando:
```$ python3 --version```
Se ele retornar um número de versão (por exemplo, `3.7.3` ou `3.8.3`), então temos o python3 instalado.
No entanto, se não tivermos o Python instalado, precisaremos compilá-lo a partir do código-fonte. Devemos consultar como fazer isso em ["Construindo Python da Fonte"](18_4_Accessing_Bitcoind_with_Python.md#variant-build-python-from-source) antes de continuarmos.
### Configurando o BitcoinRPC
Quer tenhamos usado um Python existente ou compilado a partir da fonte, agora estamos prontos para instalar a biblioteca `python-bitcoinrpc`:
```
$ pip3 install python-bitcoinrpc
```
Se não instalamos o `pip`, precisaremos executar o seguinte:
```
$ sudo apt install python3-pip
```
Em seguida, vamos repetir o comando `pip3 install python-bitcoinrpc`.
### Criando um Projeto BitcoinRPC
Geralmente, precisaremos incluir declarações apropriadas do `bitcoinrpc` em nosso projetos Bitcoin usando o Python. O seguinte fornecerá acesso aos comandos baseados em RPC:
```py
from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException
```
Também podemos achar o seguinte comando útil:
```py
from pprint import pprint
import logging
```
O `pprint` irá imprimir a resposta `json` do `bitcoind`.
O `logging` irá imprimir a chamada que fizemos para o respose do `bitcoind` e o próprio `bitcoind`, o que é útil quando fazemos um monte de chamadas juntas. Se não quisermos um retorno muito grande no terminal, podemos comentar o bloco `logging`.
## Construindo a Nossa Conexão
Agora estamos prontos para começar a interagir com o `bitcoind` estabelecendo uma conexão. Vamos criar um arquivo chamado `btcrpc.py` e digitar o seguinte:
```py
logging.basicConfig()
logging.getLogger("BitcoinRPC").setLevel(logging.DEBUG)
# rpc_user e rpc_password estão configurados no arquivo bitcoin.conf
rpc_user = "StandUp"
rpc_pass = "6305f1b2dbb3bc5a16cd0f4aac7e1eba"
rpc_host = "127.0.0.1"
rpc_client = AuthServiceProxy(f"http://{rpc_user}:{rpc_pass}@{rpc_host}:18332", timeout=120)
```
Os argumentos na URL são `<rpc_username>:<rpc_password>@<host_IP_address>:<port>`. Como de costume, o `user` e o `pass` são encontrados no arquivo `~/.bitcoin/bitcoin.conf`, enquanto o `host` é o nosso localhost, e a porta é `18332` para Testnet. O argumento `timeout` é especificado desde o tempo limite dos sockets sob grande demanda na rede principal. Se obtivermos a resposta `socket.timeout: timed out`, precisamos ser pacientes e aumentar o` timeout`.
> :link: **MAINNET VS TESTNET:** A porta seria 8332 para uma configuração na Mainnet.
### Fazendo uma Chamada RPC
Se o `rpc_client` for inicializado com sucesso, seremos capazes de enviar comandos RPC para o nosso node do Bitcoin.
Para usar um método RPC do `python-bitcoinrpc`, usaremos o objeto `rpc_client` que criamos, que fornece a maior parte da funcionalidade que pode ser acessada através do `bitcoin-cli`, usando os mesmos nomes do método.
Por exemplo, o comando a seguir irá recuperar a contagem de blocos do nosso node:
```py
block_count = rpc_client.getblockcount()
print("---------------------------------------------------------------")
print("Block Count:", block_count)
print("---------------------------------------------------------------\n")
```
Devemos obter a seguinte resposta com o `logging` habilitado:
```sh
DEBUG:BitcoinRPC:-3-> getblockcount []
DEBUG:BitcoinRPC:<-3- 1773020
---------------------------------------------------------------
Block Count: 1773020
---------------------------------------------------------------
```
### Fazendo uma Chamada RPC com Argumentos
Podemos usar esse blockcount como um argumento para recuperar o blockhash de um bloco e também para recuperar os detalhes do bloco.
Isso é feito enviando nossos comandos do objeto `rpc_client` com um argumento:
```py
blockhash = rpc_client.getblockhash(block_count)
block = rpc_client.getblock(blockhash)
```
O `getblockhash` retornará um único valor, enquanto o `getblock` retornará um array associativo de informações sobre o bloco, que inclui um array em `block['tx']` fornecendo detalhes sobre cada transação dentro do bloco:
```py
nTx = block['nTx']
if nTx > 10:
it_txs = 10
list_tx_heading = "First 10 transactions: "
else:
it_txs = nTx
list_tx_heading = f"All the {it_txs} transactions: "
print("---------------------------------------------------------------")
print("BLOCK: ", block_count)
print("-------------")
print("Block Hash...: ", blockhash)
print("Merkle Root..: ", block['merkleroot'])
print("Block Size...: ", block['size'])
print("Block Weight.: ", block['weight'])
print("Nonce........: ", block['nonce'])
print("Difficulty...: ", block['difficulty'])
print("Number of Tx.: ", nTx)
print(list_tx_heading)
print("---------------------")
i = 0
while i < it_txs:
print(i, ":", block['tx'][i])
i += 1
print("---------------------------------------------------------------\n")
```
### Executando nosso código
Podemos usar [o código que está no src/](src/18_4_getinfo.py) e executá-lo com `python3`:
```
$ python3 getinfo.py
---------------------------------------------------------------
Block Count: 1831106
---------------------------------------------------------------
---------------------------------------------------------------
BLOCK: 1831106
-------------
Block Hash...: 00000000000003b2ea7c2cdfffd86156ad1f5606ab58e128940a2534d1348b04
Merkle Root..: 056a547fe59208167eef86fa694263728fb684119254b340c1f86bdd423a8082
Block Size...: 52079
Block Weight.: 128594
Nonce........: 1775583700
Difficulty...: 4194304
Number of Tx.: 155
First 10 transactions:
---------------------
0 : d228d55112e3aa26265b0118cfdc98345c229d20fe074b9afb87107c03ce11b5
1 : 92822e8e34fafb472b87c99ea3f3e16440452b3f361ed86c6fa62175173fb750
2 : fa7c67600c14d4aa350a9674688f1429577954f4a6c5e4639d06c8964824f647
3 : 3a91d1527e308e5603dafde7ab17824f441a73a779d2571d073466dc9e8451b2
4 : 30fd0e5527b1522e7b26a4818b9edac80fe47c0c39fc34705478a49e684708d0
5 : 24c5372b38c78cbaf5b0b305925502a491bc0c1b5758f50c0bd335abb6ae85f5
6 : be70e125a5793efc5e32051fecba0668df971bdf371138c8261201c2a46b2d38
7 : 41ebf52c847a59ba0aeb4425c74e89a01e91defa86a82785ff53ed4668054561
8 : dc8211b4ce122f87692e7c203672e3eb1ffc44c0a307eafcc560323fcc5fae78
9 : 59e2d8e11cad287eacf3207e64a373f65059286b803ef0981510193ae29cbc8c
---------------------------------------------------------------
```
## Pesquisando Fundos
Da mesma forma, podemos recuperar as informações da nossa carteira com o RPC `getwalletinfo`:
```py
wallet_info = rpc_client.getwalletinfo()
print("---------------------------------------------------------------")
print("Wallet Info:")
print("-----------")
pprint(wallet_info)
print("---------------------------------------------------------------\n")
```
Devemos obter um retorno semelhante ao que tivemos abaixo com o `logging` desabilitado:
```sh
---------------------------------------------------------------
Wallet Info:
-----------
{'avoid_reuse': False,
'balance': Decimal('0.07160443'),
'hdseedid': '6dko666b1cc0d69b7eb0539l89eba7b6390kdj02',
'immature_balance': Decimal('0E-8'),
'keypoololdest': 1542245729,
'keypoolsize': 999,
'keypoolsize_hd_internal': 1000,
'paytxfee': Decimal('0E-8'),
'private_keys_enabled': True,
'scanning': False,
'txcount': 9,
'unconfirmed_balance': Decimal('0E-8'),
'walletname': '',
'walletversion': 169900}
---------------------------------------------------------------
```
Outros comandos informativos como `getblockchaininfo`, `getnetworkinfo`, `getpeerinfo` e `getblockchaininfo` funcionarão de forma semelhante.
Outros comandos podem fornecer informações específicas sobre elementos selecionados na sua carteira.
### Recuperando um Array
O RPC `listtransactions` permite que observemos as 10 transações mais recentes do nosso sistema (ou algum conjunto arbitrário de transações usando os argumentos `count` e `skip`). Ele mostra como um comando RPC pode retornar uma matriz simples de ser manipulada:
```py
tx_list = rpc_client.listtransactions()
pprint(tx_list)
```
### Explorando um UTXO
Da mesma forma, podemos usar o `listunspent` para obter uma matriz de UTXOs:
```py
print("Exploring UTXOs")
## List UTXOs
utxos = rpc_client.listunspent()
print("Utxos: ")
print("-----")
pprint(utxos)
print("------------------------------------------\n")
```
Para manipular uma matriz como a retornada de `listtransactions` ou` listunpsent`, você apenas pega o item apropriado do elemento apropriado da matriz:
```
## Select a UTXO - first one selected here
utxo_txid = utxos[0]['txid']
```
Para o `listunspent`, obtemos um `txid`. Podemos recuperar as informações sobre ele com o comando `gettransaction` e, em seguida, decodificá-lo com um `decoderawtransaction`:
```
utxo_hex = rpc_client.gettransaction(utxo_txid)['hex']
utxo_tx_details = rpc_client.decoderawtransaction(utxo_hex)
print("Details of Utxo with txid:", utxo_txid)
print("---------------------------------------------------------------")
print("UTXO Details:")
print("------------")
pprint(utxo_tx_details)
print("---------------------------------------------------------------\n")
```
Este código está disponível no arquivo [walletinfo.py](src/18_4_walletinfo.py).
```
$ python3 walletinfo.py
---------------------------------------------------------------
Wallet Info:
-----------
{'avoid_reuse': False,
'balance': Decimal('0.01031734'),
'hdseedid': 'da5a1b058deb9e51ecffef1b0ddc069a5dfb2c5f',
'immature_balance': Decimal('0E-8'),
'keypoololdest': 1596567843,
'keypoolsize': 1000,
'keypoolsize_hd_internal': 999,
'paytxfee': Decimal('0E-8'),
'private_keys_enabled': True,
'scanning': False,
'txcount': 6,
'unconfirmed_balance': Decimal('0E-8'),
'walletname': '',
'walletversion': 169900}
---------------------------------------------------------------
Utxos:
-----
[{'address': 'mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg',
'amount': Decimal('0.00001000'),
'confirmations': 1180,
'desc': "pkh([ce0c7e14/0'/0'/25']02d0541b9211aecd25913f7fdecfc1b469215fa326d52067b1b3f7efbd12316472)#n06pq9q5",
'label': '-addresstype',
'safe': True,
'scriptPubKey': '76a914a080d1a10f5e7a02d0a291f118982ed19e8cfcd788ac',
'solvable': True,
'spendable': True,
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
'vout': 0},
{'address': 'tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4',
'amount': Decimal('0.01029734'),
'confirmations': 1180,
'desc': "wpkh([ce0c7e14/0'/1'/26']02c581259ba7e6aef6d7ea23adb08f7c7f10c4c678f2e097a4074639e7685d4805)#j3pctfhf",
'safe': True,
'scriptPubKey': '00141e127c28a5d696c01aee1adaa8662396a5902fff',
'solvable': True,
'spendable': True,
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
'vout': 1},
{'address': 'mzDxbtYY3LBBBJ6HhaBAtnHv6c51BRBTLE',
'amount': Decimal('0.00001000'),
'confirmations': 1181,
'desc': "pkh([ce0c7e14/0'/0'/23']0377bdd176f985b4af2f6bdbb22c2925b6007b6c07ba171f75e65990c002615e98)#3y6ef6vu",
'label': '-addresstype',
'safe': True,
'scriptPubKey': '76a914cd339342b06042bb986a45e73d56db46acc1e01488ac',
'solvable': True,
'spendable': True,
'txid': '1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9',
'vout': 1}]
------------------------------------------
Details of Utxo with txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e
---------------------------------------------------------------
UTXO Details:
------------
{'hash': '0c6c27f58f122329bbc53a91f290b35ce23bd2708706b21a04cdc387dc8e2fd9',
'locktime': 1831103,
'size': 225,
'txid': '84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e',
'version': 2,
'vin': [{'scriptSig': {'asm': '', 'hex': ''},
'sequence': 4294967294,
'txid': '1679bee019c61608340b79810377be2798efd4d2ec3ace0f00a1967af70666b9',
'txinwitness': ['3044022014b3e2359fb46d8cbc4cd30fa991b455edfa4b419a4c64a53fcdfc79e3ca89db022010cefc3268bc252d55f1982c426328b709b47d02332def9e2efb3b12de2cf0d301',
'0351b470e87b44e8e9607acf09b8d4543c51c93c17dc741176319e60202091f2be'],
'vout': 0}],
'vout': [{'n': 0,
'scriptPubKey': {'addresses': ['mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg'],
'asm': 'OP_DUP OP_HASH160 '
'a080d1a10f5e7a02d0a291f118982ed19e8cfcd7 '
'OP_EQUALVERIFY OP_CHECKSIG',
'hex': '76a914a080d1a10f5e7a02d0a291f118982ed19e8cfcd788ac',
'reqSigs': 1,
'type': 'pubkeyhash'},
'value': Decimal('0.00001000')},
{'n': 1,
'scriptPubKey': {'addresses': ['tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4'],
'asm': '0 1e127c28a5d696c01aee1adaa8662396a5902fff',
'hex': '00141e127c28a5d696c01aee1adaa8662396a5902fff',
'reqSigs': 1,
'type': 'witness_v0_keyhash'},
'value': Decimal('0.01029734')}],
'vsize': 144,
'weight': 573}
---------------------------------------------------------------
```
## Crindo um Endereço
Criar um novo endereço com Python 3 requer apenas o uso de um RPC como `getnewaddress` ou `getrawchangeaddress`.
```
new_address = rpc_client.getnewaddress("Learning-Bitcoin-from-the-Command-Line")
new_change_address = rpc_client.getrawchangeaddress()
```
Neste exemplo, usamos o comando `getnewaddress` junto com um argumento: o rótulo `Learning-Bitcoin-from-the-Command-Line`.
## Enviando uma Transação
A criação de uma transação no Python 3 requer a combinação de alguns dos exemplos anteriores, de criação de endereços e de recuperação de UTXOs, com alguns comandos novos do RPC para criar, assinar e enviar uma transação, da mesma forma que fizemos anteriormente na linha de comando.
Existem cinco etapas:
0. Criar dois endereços, um que funcionará como destinatário e outro para o troco;
1. Selecionar um UTXO e definir os detalhes da transação;
2. Criar uma transação bruta;
3. Assinar a transação bruta com a chave privada do UTXO;
4. Transmitir a transação na Testnet do bitcoin.
### 1. Selecionando o UTXO e Definindo os Detalhes da Transação
No trecho de código a seguir, primeiro selecionaremos o UTXO que gostaríamos de gastar. Em seguida, iremos obter o endereço, id da transação e o índice vetorial da saída.
```py
utxos = rpc_client.listunspent()
selected_utxo = utxos[0] # novamente, selecionando o primeiro utxo aqui
utxo_address = selected_utxo['address']
utxo_txid = selected_utxo['txid']
utxo_vout = selected_utxo['vout']
utxo_amt = float(selected_utxo['amount'])
```
Em seguida, também recuperamos o endereço do destinatário para o qual desejamos enviar os bitcoins, calculamos a quantidade de bitcoins que desejamos enviar e calculamos a taxa de minerador e o valor do troco. Aqui, o valor é dividido arbitrariamente em dois e uma taxa de minerador é definida arbitrariamente.
```py
recipient_address = new_address
recipient_amt = utxo_amt / 2 # enviando metade das moedas para o recebedor
miner_fee = 0.00000300 # escolha uma taxa apropriada baseada no tamanho da sua transação
change_address = new_change_address
change_amt = float('%.8f'%((utxo_amt - recipient_amt) - miner_fee))
```
> :warning: **AVISO:** Obviamente, um programa real faria escolhas mais sofisticadas sobre qual UTXO usar, o que fazer com os fundos e qual taxa de mineração pagar.
### 2. Criando uma Transação Bruta
Agora temos todas as informações para enviar uma transação, mas antes de enviá-la, devemos criá-la.
```py
txids_vouts = [{"txid": utxo_txid, "vout": utxo_vout}]
addresses_amts = {f"{recipient_address}": recipient_amt, f"{change_address}": change_amt}
unsigned_tx_hex = rpc_client.createrawtransaction(txids_vouts, addresses_amts)
```
Lembre-se de que o formato do comando `createrawtransaction` é:
```$ bitcoin-cli createrawtransaction '[{"txid": <utxo_txid>, "vout": <vector_id>}]' '{"<address>": <amount>}'```
O `txids_vouts` é, portanto, uma lista, e o `address_amts` é um dicionário python, para combinar com o formato de `createrawtransaction`.
Se quisermos ver mais sobre os detalhes da transação que criamos, podemos usar `decoderawtransaction`, tanto no Python 3 quanto com `bitcoin-cli`.
### 3. Assinar Transação Bruta
Assinar uma transação geralmente é a parte mais complicada do envio de uma transação, quando olhamos a parte de programação. Aqui recuperamos uma chave privada de um endereço com `dumpprivkey` e a colocamos em uma matriz:
```py
address_priv_key = [] # list of priv keys of each utxo
address_priv_key.append(rpc_client.dumpprivkey(utxo_address))
```
Depois, usamos esse array, que deve conter as chaves privadas de cada UTXO que está sendo gasto, para assinar nosso `unsigned_tx_hex`:
```py
signed_tx = rpc_client.signrawtransactionwithkey(unsigned_tx_hex, address_priv_key)
```
Isso retornará um objeto JSON com o hex da transação assinada e se foi assinado completamente ou não:
### 4. Transmitindo a Transação
Finalmente, estamos prontos para transmitir a transação assinada na rede Bitcoin:
```py
send_tx = rpc_client.sendrawtransaction(signed_tx['hex'])
```
### Executando Nosso Código
[Este código](src/18_4_sendtx.py) está cheio de instruções com `print` para demonstrar todos os dados disponíveis a cada momento:
```
$ python3 sendtx.py
Creating a Transaction
---------------------------------------------------------------
Transaction Details:
-------------------
UTXO Address.......: mv9cjEnS2o1EygBMdrz99LzhM8KeEMoXDg
UTXO Txid..........: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e
Vector ID of Output: 0
UTXO Amount........: 1e-05
Tx Amount..........: 5e-06
Recipient Address..: tb1qca0elxxqzw5xc0s3yq5qhapzzj90ka0zartu6y
Change Address.....: tb1qrveukqrvqm9h6fua99xvcxgnvdx507dg8e8hrt
Miner Fee..........: 3e-06
Change Amount......: 2e-06
---------------------------------------------------------------
---------------------------------------------------------------
Unsigned Transaction Hex: 02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f20840000000000ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000
---------------------------------------------------------------
---------------------------------------------------------------
Signed Transaction:
----------------------
{'complete': True,
'hex': '02000000015e53fb6f63b7defa28e61c28cfc3033361138a0d33dd1fad29ae58c6fe7f2084000000006a47304402205da9b2234ea057c9ef3b7794958db6c650c72dedff1a90d2915147a5f6413f2802203756552aba0dd8ebd71b0f28341becc01b28d8b28af063d7c8ce89f9c69167f8012102d0541b9211aecd25913f7fdecfc1b469215fa326d52067b1b3f7efbd12316472ffffffff02f401000000000000160014c75f9f98c013a86c3e1120280bf422148afb75e2c8000000000000001600141b33cb006c06cb7d279d294ccc1913634d47f9a800000000'}
---------------------------------------------------------------
---------------------------------------------------------------
TXID of sent transaction: 187f8baa222f9f37841d966b6bad59b8131cfacca861cbe9bfc8656bd16a44cc
```
## Resumo: Acessando o Bitcoind com Python
Acessar Bitcoind com Python é muito fácil usando a biblioteca `python-bitcoinrpc`. A primeira coisa a se fazer é estabelecer uma conexão com nossa instância `bitcoind`, então podemos fazer todas as chamadas da API do Bitcoin conforme descrito nos documentos do Bitcoin Core. Isso torna mais fácil criar programas pequenos ou grandes para gerenciar nosso próprio node, verificando saldos ou criando aplicações interessantes, conforme acessamos todo o poder do `bitcoin-cli`.
## O Que Vem Depois?
Vamos aprender mais sobre "Conversando com o Bitcoind com Outras Linguagens" na seção [§18.5: Acessando o Bitcoind com Rust](18_5_Accessing_Bitcoind_with_Rust.md).
## Variante: Construindo Python da Fonte
Se precisarmos instalar o Python 3 a partir do código-fonte, precisaremos seguir estas instruções, e então continuar com ["Criando um projeto BitcoinRPC"](18_4_Accessing_Bitcoind_with_Python.md#creating-a-bitcoinrpc-project).
### 1. Instalando as Dependências
```sh
$ sudo apt-get install build-essential checkinstall
$ sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev zlib1g-dev
```
### 2. Baixando e Extraindo o Python
```sh
$ wget https://www.python.org/ftp/python/3.8.3/Python-3.8.3.tgz
$ tar -xzf Python-3.8.3.tgz
```
### 3. Compilando o Código-Fonte Python e Verificando a Instalação:
```sh
$ cd Python-3.8.3
$ sudo ./configure --enable-optimizations
$ sudo make -j 8 # coloque o número de núcleos que você quer usar do seu sistema para acelerar o processo
$ sudo make altinstall
$ python3.8 --version
```
Depois de obter o retorno da versão, podemos remover o arquivo de instalação:
```sh
$ rm Python-3.8.3.tgz
```

View File

@ -0,0 +1,362 @@
# 18.5: Acessando o Bitcoind com Rust
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com o `bitcoind` usando a linguagem de programação Rust e o [`bitcoincore-rpc` crate](https://github.com/rust-bitcoin/rust-bitcoincore-rpc).
## Configurando o Rust
Precisaremos instalar o Rust e o Cargo.
Eles podem ser instalados via `curl`. Basta usar a instalação "padrão":
```vim
$ curl https://sh.rustup.rs -sSf | sh
```
Se tudo correr bem, veremos:
```vim
Rust is installed now. Great!
```
Em seguida, precisaremos fazer o logout e o login novamente ou então adicionar o diretório binário do Cargo ao nosso caminho manualmente:
```
$ source $HOME/.cargo/env
```
### Configurando o `bitcoincore-rpc`
Para a maioria das linguagens de programação, precisamos instalar uma biblioteca Bitcoin RPC antes de criar nosso primeiro projeto, mas aqui iremos fazê-lo como parte da criação do nosso projeto.
### Criando um Projeto `bitcoincore-rpc`
Podemos criar um novo projeto usando `cargo new btc_test`:
```
$ cargo new btc_test
Created binary (application) `btc_test` package
```
Isso criará um diretório `btc_test` que contém um exemplo de código-fonte "hello world" que está no `src/main.rs` e um arquivo `Cargo.toml`.
Vamos compilar e executar nosso código com `cargo run`:
```
$ cd btc_test
$ cargo run
Compiling btc_test v0.1.0 (/home/standup/btc_test)
Finished dev [unoptimized + debuginfo] target(s) in 0.14s
Running `target/debug/btc_test`
Hello, world!
```
> :information_source: **NOTA:** se encontrarmos o erro `linker cc not found`, teremos que instalar um
Compilador C. Se estivermos no Linux, podemos instalar com as [ferramentas de desenvolvimento](https://www.ostechnix.com/install-development-tools-linux/).
Para acessar o crate (biblioteca) `bitcoincore-rpc`, devemos adicioná-lo ao nosso arquivo `Cargo.toml` na seção `dependencies`:
```rust
[dependencies]
bitcoincore-rpc = "0.11.0"
```
Quando usarmos o comando `cargo run` novamente, ele irá instalar os crates e suas (numerosas) dependências.
```
$ cargo run
Updating crates.io index
...
Compiling bitcoin v0.23.0
Compiling bitcoincore-rpc-json v0.11.0
Compiling bitcoincore-rpc v0.11.0
Compiling btc_test v0.1.0 (/home/standup/btc_test)
Finished dev [unoptimized + debuginfo] target(s) in 23.56s
Running `target/debug/btc_test`
Hello, world!
```
Quando estivermos usando o `bitcoin-rpc`, normalmente precisaremos incluir o seguinte:
```
use bitcoincore_rpc::{Auth, Client, RpcApi};
```
## Construindo Nossa Conexão
Para criarmos um `RPC client` do Bitcoin, vamos modificar o `src/main.rs`:
```rust
use bitcoincore_rpc::{Auth, Client, RpcApi};
fn main() {
let rpc = Client::new(
"http://localhost:18332".to_string(),
Auth::UserPass("StandUp".to_string(), "password".to_string()),
)
.unwrap();
}
```
Como de costume, vamos nos certificar de inserir nosso nome de usuário e senha corretos no `~/.bitcoin/bitcoin.conf`. Aqui, eles serão usados como argumentos para `Auth :: UserPass`.
> :link: **TESTNET vs MAINNET:** E, como de costume, use a porta 8332 para a Mainnet.
Quando terminarmos, também devemos fechar nossa conexão:
```rust
let _ = rpc.stop().unwrap();
```
O `cargo run` deve compilar e executar o exemplo com sucesso com um aviso `warning: unused variable: rpc`
### Fazendo uma Chamada RPC
As chamadas RPC são feitas usando o `rpc Client` que criamos:
```rust
let mining_info = rpc.get_mining_info().unwrap();
println!("{:#?}", mining_info);
```
Geralmente, as palavras na chamada RPC são separadas por `_`s. Uma lista completa está disponível na [documentação do crate](https://crates.io/crates/bitcoincore-rpc).
### Fazendo uma Chamada RPC com Argumentos
O envio de uma chamada RPC com argumentos usando Rust requer apenas o conhecimento de como a função é apresentada. Por exemplo, a função `get_block` é definida da seguinte forma na [documentação](https://docs.rs/bitcoincore-rpc/0.11.0/bitcoincore_rpc/trait.RpcApi.html#method.get_block):
```rust
fn get_block(&self, hash: &BlockHash) -> Result<Block>
```
Só precisamos permitir que ele pegue emprestado um blockhash, que pode ser recuperado (por exemplo) usando o comando `get_best_block_hash`.
Aqui está o código completo para recuperar um hash de bloco, transformando-o em um bloco e imprimi-lo.
```
let hash = rpc.get_best_block_hash().unwrap();
let block = rpc.get_block(&hash).unwrap();
println!("{:?}", block);
```
> **NOTA:** Outra chamada possível que consideramos para esta seção é a `get_address_info`, mas, infelizmente, no momento de escrita, a função `bitcoincore-rpc` não funciona com versões recentes do Bitcoin Core devido ao crate não abordar as mais recentes mudanças de API no Bitcoin Core. Esperamos que isso seja resolvido no próximo lançamento do crate, mas, enquanto isso programador, _cuidado_.
### Executando Nosso Código
Podemos acessar o [código src](src/18_5_main-getinfo.rs) e executá-lo. Infelizmente, a informação do "Block" sairá um pouco feia porque este exemplo não inclui uma biblioteca para embelezá-la.
```
$ cargo run
Compiling btc_test v0.1.0 (/home/standup/btc_test)
Finished dev [unoptimized + debuginfo] target(s) in 1.61s
Running `target/debug/btc_test`
GetMiningInfoResult {
blocks: 1832335,
current_block_weight: None,
current_block_tx: None,
difficulty: 4194304.0,
network_hash_ps: 77436285865245.1,
pooled_tx: 4,
chain: "test",
warnings: "Warning: unknown new rules activated (versionbit 28)",
}
Block { header: BlockHeader { version: 541065216, prev_blockhash: 000000000000027715981d5a3047daf6819ea3b8390b73832587594a2074cbf5, merkle_root: 4b2e2c2754b6ed9cf5c857a66ed4c8642b6f6b33b42a4859423e4c3dca462d0c, time: 1599602277, bits: 436469756, nonce: 218614401 }, txdata: [Transaction { version: 1, lock_time: 0, input: [TxIn { previous_output: OutPoint { txid: 0000000000000000000000000000000000000000000000000000000000000000, vout: 4294967295 }, script_sig: Script(OP_PUSHBYTES_3 8ff51b OP_PUSHBYTES_22 315448617368263538434f494e1d00010320a48db852 OP_PUSHBYTES_32 <push past end>), sequence: 4294967295, witness: [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] }], output: [TxOut { value: 19721777, script_pubkey: Script(OP_HASH160 OP_PUSHBYTES_20 011beb6fb8499e075a57027fb0a58384f2d3f784 OP_EQUAL) }, TxOut { value: 0, script_pubkey: Script(OP_RETURN OP_PUSHBYTES_36 aa21a9ed63363f3620ab5e38b8860a50c84050e5ec31af3636bbd73f01ba9f14103100ee) }] }, Transaction { version: 2, lock_time: 1832282, input: [TxIn { previous_output: OutPoint { txid: cbf880f73d421baf0aa4f0d28e63ba00e5bc6bd934b91eb0641354ce5ca42f7e, vout: 0 }, script_sig: Script(OP_PUSHBYTES_22 00146b8dbd32e5deb90d22934e1513bae6e70156cd50), sequence: 4294967294, witness: [[48, 68, 2, 32, 13, 89, 205, 30, 67, 24, 196, 83, 65, 224, 44, 138, 98, 58, 81, 135, 132, 209, 23, 166, 23, 44, 3, 228, 95, 102, 166, 214, 62, 38, 155, 147, 2, 32, 119, 2, 34, 246, 148, 255, 166, 10, 90, 52, 242, 32, 74, 241, 123, 148, 89, 199, 197, 3, 152, 134, 242, 215, 109, 61, 241, 241, 13, 70, 86, 207, 1], [2, 192, 145, 170, 206, 55, 4, 36, 138, 145, 217, 50, 19, 73, 130, 136, 245, 131, 184, 142, 239, 75, 13, 67, 17, 177, 57, 86, 151, 139, 89, 35, 109]] }], output: [TxOut { value: 1667908, script_pubkey: Script(OP_HASH160 OP_PUSHBYTES_20 908ca2b8b49ccf53efa2226afa85f6cc58dfd7e7 OP_EQUAL) }, TxOut { value: 9093, script_pubkey: Script(OP_DUP OP_HASH160 OP_PUSHBYTES_20 42ee67664ce16edefc68ad0e4c5b7ce2fc2ccc18 OP_EQUALVERIFY OP_CHECKSIG) }] }, ...] }
```
## Procurando por Fundos
Podemos procurar fundos sem argumentos opcionais usando a função `get_balance`:
```rust
let balance = rpc.get_balance(None, None).unwrap();
println!("Balance: {:?} BTC", balance.as_btc());
```
Conforme mostrado, a função `as_btc()` ajuda a gerar o saldo em um formato legível:
```
Balance: 3433.71692741 BTC
```
## Criando um Endereço
A criação de um endereço demonstra como fazer uma chamada RPC com vários argumentos opcionais especificados (por exemplo, um rótulo e um tipo de endereço).
```rust
// Gerar um novo endereço
let myaddress = rpc
.get_new_address(Option::Some("BlockchainCommons"), Option::Some(json::AddressType::Bech32))
.unwrap();
println!("address: {:?}", myaddress);
```
Isso também exigirá que tragamos a definição `json` para o escopo:
```rust
use bitcoincore_rpc::{json, Auth, Client, RpcApi};
```
## Enviando uma Transação
Agora temos tudo de que precisamos para criar uma transação, o que será feito em cinco partes:
1. Listar UTXOs;
2. Preencher variáveis;
3. Criar transação bruta;
4. Assinar transação;
5. Enviar transação.
### 1. Listando os UTXOs
Para iniciar a criação de uma transação, primeiro encontramos um UTXO para usar. O seguinte pega o primeiro UTXO com pelo menos 0,01 BTC:
```rust
let unspent = rpc
.list_unspent(
None,
None,
None,
None,
Option::Some(json::ListUnspentQueryOptions {
minimum_amount: Option::Some(Amount::from_btc(0.01).unwrap()),
maximum_amount: None,
maximum_count: None,
minimum_sum_amount: None,
}),
)
.unwrap();
let selected_tx = &unspent[0];
println!("selected unspent transaction: {:#?}", selected_tx);
```
Isso nos exigirá trazer mais estruturas para o escopo:
```rust
use bitcoincore_rpc::bitcoin::{Address, Amount};
```
Podemos observar que estamos passando cinco variáveis ao comando `list_unspent`. Os primeiros quatro (`minconf`,` maxconf`, `address` e `include_unsafe`) não são usados aqui. O quinto é o `query_options`, que não usamos antes, mas temos algumas opções de filtragem poderosas, incluindo a capacidade de olhar apenas para os UTXOs com um certo valor, mínimo ou máximo.
### 2. Preenchendo as Variáveis
Para começar a preencher as variáveis que precisaremos para criar uma nova transação, criamos a entrada do `txid` e do `vout` ao UTXO que selecionamos:
```rust
let selected_utxos = json::CreateRawTransactionInput {
txid: selected_tx.txid,
vout: selected_tx.vout,
sequence: None,
};
```
Em seguida, podemos calcular a quantia que vamos gastar subtraindo uma taxa de mineração dos fundos no UTXO:
```rust
// enviar todo o bitcoin no UTXO exceto um valor pequeno que será pago aos mineradores
let unspent_amount = selected_tx.amount;
let amount = unspent_amount - Amount::from_btc(0.00001).unwrap();
```
Por fim, podemos criar um mapa do hash do endereço e da quantidade para formar a saída:
```rust
let mut output = HashMap::new();
output.insert(
myaddress.to_string(),
amount,
);
```
Outra característica é necessária para a variável de saída: o `HashMap`. Ele nos permite armazenar
valores por chave, que iremos precisar para representar a informação `{address: amount}`.
```rust
use std::collections::HashMap;
```
### 3. Criando a Transação Bruta
Agora estamos prontos para criar uma transação bruta:
```rust
let unsigned_tx = rpc
.create_raw_transaction(&[selected_utxos], &output, None, None)
.unwrap();
```
### 4. Assinando a Transação
A assinatura da transação pode ser feita com um simples uso do `sign_raw_transaction_with_wallet`:
```rust
let signed_tx = rpc
.sign_raw_transaction_with_wallet(&unsigned_tx, None, None)
.unwrap();
println!("signed tx {:?}", signed_tx.transaction().unwrap());
```
### 5. Enviando a Transação
Finalmente, podemos transmitir a transação:
```rust
let txid_sent = rpc
.send_raw_transaction(&signed_tx.transaction().unwrap())
.unwrap();
println!("{:?}", txid_sent);
```
### Executando Nosso Código
Agora podemos executar o código completo do [src](src/18_5_main-sendtx.rs).
```
$ cargo run
Compiling btc_test v0.1.0 (/home/standup/btc_test)
warning: unused variable: `unspent_amount`
--> src/main.rs:86:9
|
86 | let unspent_amount = selected_tx.amount;
| ^^^^^^^^^^^^^^ help: if this is intentional, prefix it with an underscore: `_unspent_amount`
|
= note: `#[warn(unused_variables)]` on by default
warning: 1 warning emitted
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target/debug/btc_test`
Balance: 0.01031434 BTC
address: tb1qx5jz36xgt9q2rkh4daee8ewfj0g5z05v8qsua2
selected unspent transaction: ListUnspentResultEntry {
txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e,
vout: 1,
address: Some(
tb1qrcf8c29966tvqxhwrtd2se3rj6jeqtll3r46a4,
),
label: None,
redeem_script: None,
witness_script: None,
script_pub_key: Script(OP_0 OP_PUSHBYTES_20 1e127c28a5d696c01aee1adaa8662396a5902fff),
amount: Amount(1029734 satoshi),
confirmations: 1246,
spendable: true,
solvable: true,
descriptor: Some(
"wpkh([ce0c7e14/0\'/1\'/26\']02c581259ba7e6aef6d7ea23adb08f7c7f10c4c678f2e097a4074639e7685d4805)#j3pctfhf",
),
safe: true,
}
unsigned tx Transaction {
version: 2,
lock_time: 0,
input: [
TxIn {
previous_output: OutPoint {
txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e,
vout: 1,
},
script_sig: Script(),
sequence: 4294967295,
witness: [],
},
],
output: [
TxOut {
value: 1028734,
script_pubkey: Script(OP_0 OP_PUSHBYTES_20 352428e8c85940a1daf56f7393e5c993d1413e8c),
},
],
}
signed tx Transaction { version: 2, lock_time: 0, input: [TxIn { previous_output: OutPoint { txid: 84207ffec658ae29ad1fdd330d8a13613303c3cf281ce628fadeb7636ffb535e, vout: 1 }, script_sig: Script(), sequence: 4294967295, witness: [[48, 68, 2, 32, 98, 230, 199, 113, 156, 242, 158, 42, 148, 229, 239, 44, 9, 226, 127, 219, 72, 51, 26, 135, 44, 212, 179, 200, 213, 63, 56, 167, 0, 55, 236, 235, 2, 32, 41, 43, 30, 109, 60, 162, 124, 67, 20, 126, 4, 107, 124, 95, 9, 200, 132, 246, 147, 235, 176, 55, 59, 45, 190, 18, 211, 201, 143, 62, 163, 36, 1], [2, 197, 129, 37, 155, 167, 230, 174, 246, 215, 234, 35, 173, 176, 143, 124, 127, 16, 196, 198, 120, 242, 224, 151, 164, 7, 70, 57, 231, 104, 93, 72, 5]] }], output: [TxOut { value: 1028734, script_pubkey: Script(OP_0 OP_PUSHBYTES_20 352428e8c85940a1daf56f7393e5c993d1413e8c) }] }
b0eda3517e6fac69e58ae315d7fe7a1981e3a858996cc1e3135618cac9b79d1a
```
## Resumo: Acessando o Bitcoind com Rust
O `bitcoincore-rpc` é um crate simples e robusto que nos permitirá interagir com o Bitcoin RPC usando Rust. No entanto, no momento em que este livro foi escrito, ele ficou para trás no Bitcoin Core, o que pode causar alguns problemas de uso.
## O Que Vem Depois?
Vamos aprender mais sobre "Conversando com o Bitcoind com Outras Linguagens" na seção [§18.6: Acessando o Bitcoind com Swift](18_6_Accessing_Bitcoind_with_Swift.md).

View File

@ -0,0 +1,463 @@
# 18.6: Acessando o Bitcoind com Swift
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
Esta seção explica como interagir com o `bitcoind` usando a linguagem de programação Swift e seu próprio cliente RPC.
## Configurando o Swift no Mac
Até o momento, construímos todos os nossos ambientes de desenvolvimento de linguagem de programação alternativa em nosso node virtual no Debian. No entanto, essa não é a melhor plataforma para o Swift. Embora haja uma versão do Swift disponível para plataformas Ubuntu, ela não possui todos os recursos e funciona de maneira um pouco diferente do Swift nativo do Mac. Uma "variante" no final desta seção explica como configurá-lo, mas esteja avisado de que estaremos em um território desconhecido.
Ao invés disso, sugerimos a criação de um ambiente Swift ideal em um Mac. Existem quatro etapas principais para fazer isso.
### 1. Instalando o Xcode
Vamos precisar do `Xcode`, o ambiente de desenvolvimento integrado para o Swift e para o Objective-C. Isso pode ser facilmente instalado acessando a Mac App Store e baixando o Xcode.
#### Alternativa: Instalando Manualmente
Algumas pessoas desaconselham a instalação da App Store porque é tudo ou nada. Também não funcionará se estivermos usando o Mojave, pois desejaremos evitar as incompatibilidades do Catalina. Nesse caso, podemos fazer o download diretamente da [Área do desenvolvedor](https://developer.apple.com/download/more/) na Apple.
Se estivermos usando o Mojave, precisaremos do arquivo `xip` para o Xcode 10.3.1. Caso contrário, podemos utilizar o mais recente.
Depois de baixado, podemos clicar no `xip` para extraí-lo e mover o aplicativo Xcode para a pasta de Aplicativos.
De qualquer forma, devemos ter o Xcode instalado na pasta de Aplicativos no final desta etapa.
### 2. Instalando o Servidor Gordian
Também vamos precisar de um node Bitcoin em nosso Mac, para que possamos nos comunicar com ele. Tecnicamente, poderíamos usar um node remoto e acessá-lo com o login e senha RPC pela rede. No entanto, sugerimos a instalação do full node diretamente no Mac, porque essa é a configuração mais segura e limpa, garantindo que nenhuma das comunicações saia de nossa máquina.
Para instalar facilmente um full node em nosso Mac, podemos usar o [GordianServer for MacOS](https://github.com/BlockchainCommons/GordianServer-macOS) da Blockchain Commons. Podemos seguir as [instruções de instalação](https://github.com/BlockchainCommons/GordianServer-macOS#installation-instructions) no README, mas geralmente tudo que precisamos fazer é baixar o arquivo `dmg` atual, abri-lo e instalar a aplicação em nosso diretório de aplicações.
Depois, vamos executar o aplicativo GordianServer e dizer a ele para `Start` na Testnet.
> :link: **TESTNET vs. MAINNET:** Ou `Start` na Mainnet.
#### 3. Tornando Nosso bitcoin-cli Gordian Acessível
Quando desejarmos acessar o `bitcoin-cli` criado pelo GordianServer em nosso Mac local, podemos encontrá-lo em `~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli`.
Podemos criar um alias para isso:
```
alias bitcoin-cli="~/.standup/BitcoinCore/bitcoin-0.20.1/bin/bitcoin-cli -testnet"
```
> :link: **TESTNET vs. MAINNET:** Obviamente, o parâmetro `-testnet` só é necessário se estivermos rodando na testnet.
### 4. Encontrando Nossas Informações do GordianServer
Finalmente, precisaremos de nossas informações de `rpcuser` e `rpcpassword`. Essas informações estarão em `~/Library/Application Support/Bitcoin/bitcoin.conf` por padrão no Gordian.
```
$ grep rpc ~/Library/Application\ Support/Bitcoin/bitcoin.conf
rpcuser=oIjA53JC2u
rpcpassword=ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU
...
```
## Construindo Nossa Conexão Manualmente
No momento em que este artigo foi escrito, não havia uma biblioteca Bitcoin RPC atualizada e simples de ser usada, que fosse específica para Swift, algo que pudéssemos baixar e começar a usar imediatamente. Portanto, faremos algo que nunca fizemos antes: construir uma conexão RPC manualmente.
### Grave o Transmissor RPC
Isso requer apenas a escrita de uma função que passe os comandos RPC para o `bitcoind` no formato correto:
```
func makeCommand(method: String, param: Any, completionHandler: @escaping (Any?) -> Void) -> Void {
```
As conexões RPC para o `bitcoind` usam o protocolo HTML, o que significa que precisamos fazer três coisas: Criar uma URL, fazer um URLRequest e iniciar uma URLSession.
#### 1. Criando uma URL
Dentro da função, precisamos criar uma URL a partir do nosso IP, porta, `rpcuser`, `rpcpassword` e wallet:
```
let testnetRpcPort = "18332"
let nodeIp = "127.0.0.1:\(testnetRpcPort)"
let rpcusername = "oIjA53JC2u"
let rpcpassword = "ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU"
let walletName = ""
```
A conexão RPC real com o Bitcoin Core é construída usando uma URL no formato "http://rpcusername:rpcpassword@nodeIp/walletName":
```
let walletUrl = "http://\(rpcusername):\(rpcpassword)@\(nodeIp)/\(walletName)"
let url = URL(string: walletUrl)
```
Isso significa que nossas variáveis de amostra resultam na seguinte URL:
```
http://oIjA53JC2u:ebVCeSyyM0LurvgQyi0exWTqm4oU0rZU@127.0.0.1:18332/
```
Que deve se parecer muito com a URL usada em algumas das seções anteriores para conexões RPC.
#### 2. Criando uma URLRequest
Com essa URL em mãos, agora podemos criar um URLRequest, com o método `POST` e o tipo de conteúdo `text/plain`. O corpo HTTP será então o objeto JSON familiar que enviamos sempre que nos conectamos diretamente às portas RPC do Bitcoin Core, conforme demonstrado pela primeira vez ao usar o Curl na seção [§4.4](04_4__Interlude_Using_Curl.md).
```
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.setValue("text/plain", forHTTPHeaderField: "Content-Type")
request.httpBody = "{\"jsonrpc\":\"1.0\",\"id\":\"curltest\",\"method\":\"\(method)\",\"params\":[\(param)]}".data(using: .utf8)
```
#### 3. Criando uma URLSession
Finalmente, estamos prontos para construir uma URLSession em torno da nossa URLRequest.
```
let session = URLSession(configuration: .default)
let task = session.dataTask(with: request as URLRequest) { data, response, error in
```
O manipulador de conclusão para `dataTask` precisa verificar se há erros:
```
do {
if error != nil {
//Handle the error
} else {
```
E então analisar os dados que estamos recebendo. Aqui, estamos pegando os resultados JSON e colocando-os em um `NSDictionary`:
```
if let urlContent = data {
do {
let json = try JSONSerialization.jsonObject(with: urlContent, options: JSONSerialization.ReadingOptions.mutableLeaves) as! NSDictionary
```
Depois disso, há mais manipulação de erros e então podemos eventualmente retornar o `result` do dicionário usando o `CompletHandler` que definimos para a nova função `makeCommand`:
```
if let errorCheck = json["error"] as? NSDictionary {
if let errorMessage = errorCheck["message"] as? String {
print("FAILED")
print(errorMessage)
}
} else {
let result = json["result"]
completionHandler(result)
}
} catch {
//Handle error here
}
```
Claro que eventualmente teremos que dizer à `task` para que ela seja iniciada:
```
task.resume()
```
E isso é "tudo" o que precisamos fazer nessa interação RPC manual, usando uma linguagem de programação como o Swift.
> :pray: **AGRADECIMENTO:** Obrigado @Fonta1n3, que forneceu o [código principal](https://github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/issues/137) para nosso Transmissor RPC.
### Fazendo uma Chamada RPC
Tendo escrito a função RPC `makeCommand`, podemos enviar uma chamada RPC executando-a. Aqui está `getblockchaininfo`:
```
let method = "getblockchaininfo"
let param = ""
makeCommand(method: method,param: param) { result in
print(result!)
}
```
### Fazendo uma Chamada RPC com Argumentos
Poderíamos da mesma forma obter a contagem de bloco atual a partir dessa informação e usá-la de modo redundante para obter o hash do bloco atual, usando o parâmetro `param`:
```
let method = "getblockchaininfo"
let param = ""
makeCommand(method: method,param: param) { result in
let blockinfo = result as! NSDictionary
let block = blockinfo["blocks"] as! NSNumber
let method = "getblockhash"
makeCommand(method: method,param: block) { result in
print("Blockhash for \(block) is \(result!)")
}
}
```
### Executando Nosso Código
O código completo está disponível no [diretório src/](src/18_6_getinfo.playground). Carregue-o no playground Xcode e, em seguida, "Editor -> Executar Playground" e devemos obter resultados como:
```
{
bestblockhash = 00000000000000069725608ebc5b59e520572a8088cbc57ffa5ba87b7f300ac7;
blocks = 1836745;
chain = test;
chainwork = 0000000000000000000000000000000000000000000001cc3e9f8e0bc6b71196;
difficulty = "16508683.81195478";
headers = 1836745;
initialblockdownload = 0;
mediantime = 1601416765;
pruned = 0;
"size_on_disk" = 28205538354;
softforks = {
bip34 = {
active = 1;
height = 21111;
type = buried;
};
bip65 = {
active = 1;
height = 581885;
type = buried;
};
bip66 = {
active = 1;
height = 330776;
type = buried;
};
csv = {
active = 1;
height = 770112;
type = buried;
};
segwit = {
active = 1;
height = 834624;
type = buried;
};
};
verificationprogress = "0.999999907191804";
warnings = "Warning: unknown new rules activated (versionbit 28)";
}
Blockhash for 1836745 is 00000000000000069725608ebc5b59e520572a8088cbc57ffa5ba87b7f300ac7
```
## Procurando por Fundos
Com nosso novo `makeCommand` para funções RPC, podemos executar um comando como `getwalletinfo` ou `getbalance`:
```
var method = "getwalletinfo"
var param = ""
makeCommand(method: method,param: param) { result in
print(result!)
}
method = "getbalance"
makeCommand(method: method,param: param) { result in
let balance = result as! NSNumber
print("Balance is \(balance)")
}
```
Que irá retornar:
```
Balance is 0.01
{
"avoid_reuse" = 0;
balance = "0.01";
hdseedid = bf493318f548df8e25c390d6a7f70758fd6b3668;
"immature_balance" = 0;
keypoololdest = 1599723938;
keypoolsize = 999;
"keypoolsize_hd_internal" = 1000;
paytxfee = 0;
"private_keys_enabled" = 1;
scanning = 0;
txcount = 1;
"unconfirmed_balance" = 0;
walletname = "";
walletversion = 169900;
}
```
## Criando um Endereço
Criar um endereço é bastante simples, mas que tal criar um endereço legado com um rótulo específico? Isso requer dois parâmetros na nossa chamada RPC.
Uma vez que a simples função `makeCommand` desta seção apenas passa nossos `param`s como as entranhas de um objeto JSON, tudo o que precisamos fazer é formatar corretamente essas entranhas. Aqui está uma maneira para fazermos isso:
```
method = "getnewaddress"
param = "\"learning-bitcoin\", \"legacy\""
makeCommand(method: method,param: param) { result in
let address = result as! NSString
print(address)
}
```
Executá-lo no playground do Xcode produz o seguinte resultado:
```
mt3ZRsmXHVMMqYQPJ8M74QjF78bmqrdHZF
```
Esse resultado é obviamente um endereço legado; seu rótulo pode então ser verificado na linha de comando:
```
$ bitcoin-cli getaddressesbylabel "learning-bitcoin"
{
"mt3ZRsmXHVMMqYQPJ8M74QjF78bmqrdHZF": {
"purpose": "receive"
}
}
```
Sucesso!
> :information_source: **NOTA:** Como costumamos dizer nesses exemplos de programação, um programa do mundo real seria muito mais sofisticado. Em particular, gostaríamos de poder enviar um objeto JSON real como um parâmetro e, em seguida, ter no nosso programa um `makeCommand` analisando-o e inserindo-o na URLSession de forma adequada. O que temos aqui maximiza a legibilidade e a simplicidade sem enfocar na facilidade de uso.
## Enviando uma Transação
Como de costume, o envio de uma transação (da maneira mais difícil) é um processo de várias etapas:
0. Gerar ou receber um endereço de recebimento;
1. Encontrar um UTXO não gasto;
2. Criar uma transação bruta;
3. Assinar a transação bruta;
4. Enviar a transação bruta.
Usando o `address` gerado na etapa anterior como nosso destinatário.
### 1. Encontrando um UTXO Não Gasto
O RPC `listunspent` permite que encontremos nosso UTXO:
```
method = "listunspent"
param = ""
makeCommand(method: method,param: param) { result in
let unspent = result as! NSArray
let utxo = unspent[0] as! NSDictionary
let txid = utxo["txid"] as! NSString
let vout = utxo["vout"] as! NSInteger
let amount = utxo["amount"] as! NSNumber
let new_amount = amount.floatValue - 0.0001
```
Como em outros exemplos, vamos arbitrariamente pegar o enésimo UTXO e pegar o `txid`, `vout` e `amount` dele.
> :information_source **NOTA:** Mais uma vez, um programa real seria muito mais sofisticado.
### 2. Criando uma Transação Bruta
Criar uma transação bruta é a coisa mais complicada, porque precisamos acertar todos os nossos objetos JSON, arrays e aspas. Veja como fazer isso no Swift, usando a formatação `param` muito básica do transmissor:
```
method = "createrawtransaction"
param="[ { \"txid\": \"\(txid)\", \"vout\": \(vout) } ], { \"\(address)\": \(new_amount)}"
makeCommand(method: method,param: param) { result in
let hex = result as! NSString
```
### 3. Assinando a Transação Bruta
Assinar nossa transação requer apenas que executemos o RPC `signrawtransactionwithwallet`, usando nosso novo `hex`:
```
method = "signrawtransactionwithwallet"
param = "\"\(hex)\""
makeCommand(method: method,param: param) { result in
let signedhexinfo = result as! NSDictionary
let signedhex = signedhexinfo["hex"] as! NSString
```
### 4. Enviando a Transação Bruta
Enviar nossa transação é igualmente simples:
```
method = "sendrawtransaction"
param = "\"\(signedhex)\""
makeCommand(method: method,param: param) { result in
let new_txid = result as! NSString
print("TXID: \(new_txid)")
}
}
}
}
}
```
O código para este remetente de transação pode ser encontrado no [diretório src/](src/18_6_sendtx.playground).
## Usando o Swift de Outras Maneiras
Isso cobre nossas discussões habituais sobre a programação do Bitcoin RPC usando uma linguagem, mas o Swift é uma linguagem particularmente importante, pois pode ser implantada em dispositivos móveis, um dos principais locais para nossas carteiras. Como tal, podemos querer considerar algumas outras bibliotecas:
* O [framework ios-Bitcoin](https://github.com/BlockchainCommons/iOS-Bitcoin) da Blockchain Commons converte a biblioteca Libbitcoin de C++ para Swift;
* [Libwally Swift](https://github.com/blockchain/libwally-swift) é um wrapper Swift para a Libwally.
## Resumo: Acessando o Bitcoind com Swift
O Swift é uma linguagem de programação robusta e moderna que infelizmente ainda não tem nenhuma biblioteca RPC fácil de ser utilizada... o que acabou de nos dar a oportunidade de escrever uma função de acesso ao RPC. Com isso em mãos, podemos interagir com o `bitcoind` em um Mac ou criar aplicativos complementares em um iPhone, o que é uma combinação perfeita para usar o Bitcoin com airgap.
## O Que Vem Depois?
Aprenda sobre o Lightning em [Capítulo 19: Compreendendo Sua Configuração da Lightning](19_0_Understanding_Your_Lightning_Setup.md).
## Variante: Implantando o Swift no Ubuntu
Se preferirmos implantar o Swift no Ubuntu, podemos fazê-lo, embora a funcionalidade não seja a mesma. Parte do código neste capítulo provavelmente gerará erros que precisaremos resolver e também precisaremos trabalhar mais para vincular as bibliotecas C.
Para começar, vamos instalar algumas bibliotecas Debian necessárias:
```
$ sudo apt-get install clang
$ sudo apt-get install libcurl4 libpython2.7 libpython2.7-dev
```
Se estivermos usando o Debian 10 ou superior (e realmente deveríamos estar usando), também precisaremos retroagir algumas bibliotecas para obter as versões mais antigas:
```
$ sudo apt-get install libtinfo5 libncurses5
```
Posteriormente, podemos baixar e instalar o Swift:
```
$ wget https://swift.org/builds/swift-5.1.3-release/ubuntu1804/swift-5.1.3-RELEASE/swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
$ tar xzfv swift-5.1.3-RELEASE-ubuntu18.04.tar.gz
$ sudo mv swift-5.1.3-RELEASE-ubuntu18.04 /usr/share/swift
```
Para poder usar nossa nova configuração do Swift, precisaremos atualizar nosso `PATH` em nosso arquivo `.bashrc`:
```
$ echo "export PATH=/usr/share/swift/usr/bin:$PATH" >> ~/.bashrc
$ source ~/.bashrc
```
Agora podemos testar o Swift com o argumento `--version`:
```
$ swift --version
Swift version 5.1.3 (swift-5.1.3-RELEASE)
Target: x86_64-unknown-linux-gnu
```
### Criando um Projeto
Depois de instalar o Swift em nossa máquina Ubuntu, podemos criar projetos com o comando `package init`:
```
$ mkdir swift-project
$ cd swift-project/
/swift-project$ swift package init --type executable
Creating executable package: swift-project
Creating Package.swift
Creating README.md
Creating .gitignore
Creating Sources/
Creating Sources/swift-project/main.swift
Creating Tests/
Creating Tests/LinuxMain.swift
Creating Tests/swift-projectTests/
Creating Tests/swift-projectTests/swift_projectTests.swift
Creating Tests/swift-projectTests/XCTestManifests.swift
```
Também editaremos o `Sources/.../main.swift` e, quando estivermos pronto para compilar, podemos usar o comando `build`:
```
$ swift build
[4/4] Linking swift-project
```
Finalmente, seremos capazes de executar o programa a partir do diretório `.build/debug`:
```
$ .build/debug/swift-project
Hello, world!
```
Boa sorte!