Skip to content

Commit 0ca4a04

Browse files
authored
Merge pull request #243 from KoreaComK/chapter15
Chapter 15 Translated by @KoreaComK and revised by @lukedevj
2 parents 3854c66 + 3d9d4ee commit 0ca4a04

File tree

4 files changed

+830
-0
lines changed

4 files changed

+830
-0
lines changed

pt/15_0_Talking_to_Bitcoind.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
# Capítulo 15: Conversando com Bitcoind usando C
3+
4+
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.
5+
6+
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).
7+
8+
## Objetivos deste capítulo
9+
10+
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
11+
12+
* Criar programas C que usam RPC para conversar com o Bitcoind;
13+
* Criar programas C que usam ZMQ para conversar com o Bitcoind.
14+
15+
Os objetivos secundários do capítulo incluem a capacidade de:
16+
17+
* Entender como usar uma biblioteca RPC;
18+
* Entender como usar uma biblioteca JSON;
19+
* Compreender as capacidades do ZMQ;
20+
* Entender como usar uma biblioteca ZMQ.
21+
22+
## Tabela de conteúdo
23+
24+
* [Seção 1: Acessando o Bitcoind usando C com Bibliotecas RPC](15_1_Accessing_Bitcoind_with_C.md)
25+
* [Seção 2: Programando o Bitcoind usando C com Bibliotecas RPC](15_2_Programming_Bitcoind_with_C.md)
26+
* [Seção 3: Recebendo notificações usando C com bibliotecas ZMQ](15_3_Receiving_Bitcoind_Notifications_with_C.md)
27+
Lines changed: 294 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,294 @@
1+
2+
# 15.1: Acessando o Bitcoind usando C com bibliotecas RPC
3+
4+
> :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.
5+
6+
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.
7+
8+
## Configurando o libbitcoinrpc
9+
10+
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).
11+
12+
```
13+
$ sudo apt-get install make gcc libcurl4-openssl-dev libjansson-dev uuid-dev
14+
Suggested packages:
15+
libcurl4-doc libidn11-dev libkrb5-dev libldap2-dev librtmp-dev libssh2-1-dev
16+
The following NEW packages will be installed:
17+
libcurl4-openssl-dev libjansson-dev uuid-dev
18+
0 upgraded, 3 newly installed, 0 to remove and 4 not upgraded.
19+
Need to get 358 kB of archives.
20+
After this operation, 1.696 kB of additional disk space will be used.
21+
Do you want to continue? [Y/n] y
22+
```
23+
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.
24+
25+
```
26+
$ sudo apt-get install git
27+
$ git clone https://github.com/gitmarek/libbitcoinrpc
28+
```
29+
30+
> :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.
31+
32+
### Compilando o libbitcoinrpc.
33+
34+
Antes de compilarmos e instalarmos o pacote, provavelmente precisaremos ajustar nosso ``$PATH``, para que possamos acessar o ``/sbin/ldconfig``:
35+
```
36+
$ PATH="/sbin:$PATH"
37+
```
38+
39+
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``:
40+
41+
```
42+
$ emacs ~/libbitcoinrpc/Makefile
43+
...
44+
INSTALL_LIBPATH := $(INSTALL_PREFIX)/usr/lib
45+
```
46+
47+
(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).
48+
49+
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``:
50+
51+
```
52+
...
53+
INSTALL_HEADERPATH := $(INSTALL_PREFIX)/usr/include
54+
```
55+
56+
Agora, podemos compilar:
57+
```
58+
$ cd libbitcoinrpc
59+
~/libbitcoinrpc$ make
60+
61+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_err.o -c src/bitcoinrpc_err.c
62+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_global.o -c src/bitcoinrpc_global.c
63+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc.o -c src/bitcoinrpc.c
64+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_resp.o -c src/bitcoinrpc_resp.c
65+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_cl.o -c src/bitcoinrpc_cl.c
66+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -o src/bitcoinrpc_method.o -c src/bitcoinrpc_method.c
67+
gcc -fPIC -O3 -g -Wall -Werror -Wextra -std=c99 -D VERSION=\"0.2\" -shared -Wl,-soname,libbitcoinrpc.so.0 \
68+
src/bitcoinrpc_err.o src/bitcoinrpc_global.o src/bitcoinrpc.o src/bitcoinrpc_resp.o src/bitcoinrpc_cl.o src/bitcoinrpc_method.o \
69+
-o .lib/libbitcoinrpc.so.0.2 \
70+
-Wl,--copy-dt-needed-entries -luuid -ljansson -lcurl
71+
ldconfig -v -n .lib
72+
.lib:
73+
libbitcoinrpc.so.0 -> libbitcoinrpc.so.0.2 (changed)
74+
ln -fs libbitcoinrpc.so.0 .lib/libbitcoinrpc.so
75+
```
76+
Se tudo correr bem, podemos instalar o pacote:
77+
```
78+
$ sudo make install
79+
Installing to
80+
install .lib/libbitcoinrpc.so.0.2 /usr/local/lib
81+
ldconfig -n /usr/local/lib
82+
ln -fs libbitcoinrpc.so.0 /usr/local/lib/libbitcoinrpc.so
83+
install -m 644 src/bitcoinrpc.h /usr/local/include
84+
Installing docs to /usr/share/doc/bitcoinrpc
85+
mkdir -p /usr/share/doc/bitcoinrpc
86+
install -m 644 doc/*.md /usr/share/doc/bitcoinrpc
87+
install -m 644 CREDITS /usr/share/doc/bitcoinrpc
88+
install -m 644 LICENSE /usr/share/doc/bitcoinrpc
89+
install -m 644 Changelog.md /usr/share/doc/bitcoinrpc
90+
Installing man pages
91+
install -m 644 doc/man3/bitcoinrpc*.gz /usr/local/man/man3
92+
```
93+
94+
## Preparando o código
95+
96+
``libbitcoinrpc`` tem métodos simples e bem estruturados para conectar-se ao nosso `bitcoind`, executando chamadas RPC e decodificando a resposta.
97+
98+
Para usar o ``libbitcoinrpc``, é importante certificar de que nossos arquivos do código incluam os cabeçalhos apropriados:
99+
``` c
100+
#include <jansson.h>
101+
#include <bitcoinrpc.h>
102+
```
103+
104+
Precisaremos também vincular as bibliotecas apropriadas sempre que possamos compilar:
105+
106+
```
107+
$ cc yourcode.c -lbitcoinrpc -ljansson -o yourcode
108+
```
109+
110+
## Construindo a conexão
111+
112+
Para construir a conexão com o servidor ``bitcoind`` é necessário alguns simples passos.
113+
114+
Primeiro, inicialize a biblioteca:
115+
```
116+
bitcoinrpc_global_init();
117+
```
118+
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``.
119+
```
120+
$ cat bitcoin.conf
121+
server=1
122+
dbcache=1536
123+
par=1
124+
maxuploadtarget=137
125+
maxconnections=16
126+
rpcuser=StandUp
127+
rpcpassword=6305f1b2dbb3bc5a16cd0f4aac7e1eba
128+
rpcallowip=127.0.0.1
129+
debug=tor
130+
prune=550
131+
testnet=1
132+
[test]
133+
rpcbind=127.0.0.1
134+
rpcport=18332
135+
[main]
136+
rpcbind=127.0.0.1
137+
rpcport=8332
138+
[regtest]
139+
rpcbind=127.0.0.1
140+
rpcport=18443
141+
```
142+
Com essas informações, vamos colocá-las no ``bitcoinrpc_cl_init_params``:
143+
``` c
144+
bitcoinrpc_cl_t *rpc_client;
145+
rpc_client = bitcoinrpc_cl_init_params("StandUp", "6305f1b2dbb3bc5a16cd0f4aac7e1eba", "127.0.0.1", 18332);
146+
```
147+
148+
> **MAINNET VS TESTNET:** A porta seria a 8332 caso estivéssemos usando a configuração da rede principal.
149+
150+
Se o ``rpc_client`` for inicializado com sucesso, poderemos enviar os comandos do RPC.
151+
152+
Mais tarde, quando tivermos feito com a conexão de ``bitcoind``, poderemos fechar da seguinte maneira:
153+
``` c
154+
bitcoinrpc_global_cleanup();
155+
```
156+
157+
### Testando o código de teste
158+
159+
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).
160+
161+
Podemos compilar e executar o código da seguinte maneira:
162+
```
163+
$ cc testbitcoin.c -lbitcoinrpc -ljansson -o testbitcoin
164+
$ ./testbitcoin
165+
Successfully connected to server!
166+
```
167+
168+
> :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``.
169+
170+
## Fazendo uma chamada ao RPC
171+
172+
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).
173+
``` c
174+
bitcoinrpc_method_t *getmininginfo = NULL;
175+
getmininginfo = bitcoinrpc_method_init(BITCOINRPC_METHOD_GETMININGINFO);
176+
```
177+
Normalmente definiríamos os parâmetros em seguida, mas o ``GetMiningInfo`` não requer parâmetros, por isso podemos pular essa parte.
178+
179+
Também devemos criar outros dois objetos, um "objeto de resposta" e um "objeto de erro". Eles podem ser inicializados da seguinte forma:
180+
``` c
181+
bitcoinrpc_resp_t *btcresponse = NULL;
182+
btcresponse = bitcoinrpc_resp_init();
183+
184+
bitcoinrpc_err_t btcerror;
185+
```
186+
Vamos usar a variável ``rpc_client`` que aprendemos no teste anterior e vamos adicionar nosso método ``getmininginfo`` e os outros dois objetos:
187+
``` c
188+
bitcoinrpc_call(rpc_client, getmininginfo, btcresponse, &btcerror);
189+
```
190+
191+
### Mostrando o retorno da chamada
192+
193+
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``:
194+
``` c
195+
json_t *jsonresponse = NULL;
196+
jsonresponse = bitcoinrpc_resp_get(btcresponse);
197+
```
198+
Se quisermos gerar os resultados completos da chamada RPC no JSON, podemos fazer com uma simples invocação do ``json_dumps``, da biblioteca ``jansson``:
199+
``` c
200+
printf("%s\n", json_dumps(j, JSON_INDENT(2)));
201+
```
202+
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.
203+
204+
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``.
205+
206+
A função ``json_object_get`` permite recuperar um valor (como o ``result``) de um objeto JSON usando chaves:
207+
``` c
208+
json_t *jsonresult = NULL;
209+
jsonresult = json_object_get(jsonresponse,"result");
210+
printf("%s\n", json_dumps(jsonresult, JSON_INDENT(2)));
211+
```
212+
213+
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``:
214+
``` c
215+
json_t *jsonblocks = NULL;
216+
jsonblocks = json_object_get(jsonresult,"blocks");
217+
218+
int blocks;
219+
blocks = json_integer_value(jsonblocks);
220+
printf("Block Count: %d\n",blocks);
221+
```
222+
223+
> :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.
224+
225+
### Testando o código de informação
226+
227+
Vamos recuperar o código de teste que está no [diretório src](15_1_GetMiningInfo.c).
228+
```
229+
$ cc getmininginfo.c -lbitcoinrpc -ljansson -o getmininginfo
230+
$ ./getmininginfo
231+
Full Response: {
232+
"result": {
233+
"blocks": 1804406,
234+
"difficulty": 4194304,
235+
"networkhashps": 54842097951591.781,
236+
"pooledtx": 127,
237+
"chain": "test",
238+
"warnings": "Warning: unknown new rules activated (versionbit 28)"
239+
},
240+
"error": null,
241+
"id": "474ccddd-ef8c-4e3f-93f7-fde72fc08154"
242+
}
243+
244+
Just the Result: {
245+
"blocks": 1804406,
246+
"difficulty": 4194304,
247+
"networkhashps": 54842097951591.781,
248+
"pooledtx": 127,
249+
"chain": "test",
250+
"warnings": "Warning: unknown new rules activated (versionbit 28)"
251+
}
252+
253+
Block Count: 1804406
254+
```
255+
256+
## Fazendo uma chamada RPC usando argumentos
257+
258+
Mas e se a sua chamada RPC tiver argumentos?
259+
260+
### Criando uma matriz JSON
261+
262+
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.
263+
264+
Vamos criar a matriz JSON usando a função ``json_array do`` do ``jansson``:
265+
``` c
266+
json_t *params = NULL;
267+
params = json_array();
268+
```
269+
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:
270+
``` c
271+
json_array_append_new(params,json_string(tx_rawhex));
272+
```
273+
274+
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.
275+
276+
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``.
277+
278+
### Atribuindo os parâmetros
279+
280+
Quando criamos o parâmetro array no JSON, simplesmente o atribuímos depois de inicializar o método RPC, da seguinte maneira:
281+
``` c
282+
bitcoinrpc_method_set_params(rpc_method, params)
283+
```
284+
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.
285+
286+
## Resumo do capítulo Acessando o Bitcoind usando C com bibliotecas RPC
287+
288+
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.
289+
290+
* :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.
291+
292+
## O Que Vem Depois?
293+
294+
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).

0 commit comments

Comments
 (0)