mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-07 16:06:26 +00:00
Merge pull request #396 from KoreaComK/chapter16
Chapter 16 Translated by @koreacomk need review
This commit is contained in:
commit
e9bda63a98
29
pt/17_0_Programming_with_Libwally.md
Normal file
29
pt/17_0_Programming_with_Libwally.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Capítulo 17: Programando com Libwally
|
||||
|
||||
O capítulo anterior apresentou três bibliotecas C, para RPC, JSON e ZMQ, todas destinadas a interagir diretamente com o `bitcoind`, assim como você vem fazendo desde o início. Mas às vezes você pode querer codificar sem acesso direto a um `bitcoind`. Isso pode ser devido a um cliente offline ou apenas porque você deseja manter algumas funcionalidades internas de seu programa C. Você também pode querer se aprofundar na funcionalidade da carteira, como criação de palavras mnemônicas ou derivação de endereços. É aí que entra Libwally: é uma biblioteca de carteira para C, C ++, Java, NodeJS ou Python, com wrappers também disponíveis para outras linguagens, como Swift.
|
||||
|
||||
Este capítulo aborda a funcionalidade possível dentro do Libwally, a maioria das quais complementa o trabalho que você fez através do acesso RPC ao `bitcoind`, mas algumas das quais o replicam. Ele também mostra como integrar esse trabalho com os clientes RPC com os quais você está mais familiarizado. No entanto, observe que esta é apenas uma introdução básica ao Libwally. Vários de seus conjuntos de funções mais importantes são destacados, mas nunca fazemos mais do que apresentar uma introdução. Se você acha suas funções úteis ou intrigantes, então você precisará se aprofundar muito mais do que este curso pode cobrir.
|
||||
|
||||
## Objetivos Deste Capítulo
|
||||
|
||||
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
|
||||
|
||||
* Usar as funções de carteira com o Libwally;
|
||||
* Realizar manipulações de PSBTs e transações com o Libwally;
|
||||
* Implementar designs que combinem o Libwally e o RPC.
|
||||
|
||||
Os objetivos secundários do capítulo incluem a capacidade de:
|
||||
|
||||
* Compreender palavras mnemônicas BIP39;
|
||||
* Conhecer mais sobre as carteiras hierárquicas BIP32;
|
||||
* Sintetizar a profundidade funcional do Libwally.
|
||||
|
||||
## Tabela de Conteúdo
|
||||
|
||||
* [Seção 1: Configurando a Libwally](17_1_Setting_Up_Libwally.md)
|
||||
* [Seção 2: Usando BIP39 na Libwally](17_2_Using_BIP39_in_Libwally.md)
|
||||
* [Seção 3: Usando BIP32 na Libwally](17_3_Using_BIP32_in_Libwally.md)
|
||||
* [Seção 4: Usando PSBTs na Libwally](17_4_Using_PSBTs_in_Libwally.md)
|
||||
* [Seção 5: Usando Scripts na Libwally](17_5_Using_Scripts_in_Libwally.md)
|
||||
* [Seção 6: Usando Outras Funções na Libwally](17_6_Using_Other_Functions_in_Libwally.md)
|
||||
* [Seção 7: Integrando Libwally e Bitcoin-CLI](17_7_Integrating_Libwally_and_Bitcoin-CLI.md)
|
195
pt/17_1_Setting_Up_Libwally.md
Normal file
195
pt/17_1_Setting_Up_Libwally.md
Normal file
@ -0,0 +1,195 @@
|
||||
# 16.1: Configurando a Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
Esta primeira seção explicará como fazer o download da Biblioteca Libwally C e como colocá-la em funcionamento.
|
||||
|
||||
> :book: ***O que é a Libwally?*** A Libwally é uma biblioteca de primitivas útil para a criação de carteiras que é totalmente multiplataforma, de modo que as mesmas funções possam ser usadas em qualquer lugar. Há uma [documentação online](https://wally.readthedocs.io/en/latest/), caso esteja interessado. A Libwally está disponível como parte do [Elements Project](https://github.com/ElementsProject) da Blockstream.
|
||||
|
||||
## Instalando a Libwally
|
||||
|
||||
Como de costume, precisaremos de alguns pacotes no nosso sistema:
|
||||
```
|
||||
$ sudo apt-get install git
|
||||
$ sudo apt-get install dh-autoreconf
|
||||
```
|
||||
Podemos então fazer o download do Libwally com base no seu repositório Git:
|
||||
```
|
||||
$ git clone https://github.com/ElementsProject/libwally-core
|
||||
```
|
||||
Depois, podemos começar com o processo de configuração.
|
||||
```
|
||||
$ ./tools/autogen.sh
|
||||
```
|
||||
Como no ```libbitcoinrpc```, podemos querer instalar no caminho `/usr/include` e no `/usr/lib` para facilitar o uso. Basta modificar a linha apropriada no arquivo `configure` do programa:
|
||||
```
|
||||
< ac_default_prefix=/usr
|
||||
---
|
||||
> ac_default_prefix=/usr/local
|
||||
```
|
||||
Depois, podemos terminar nossa preparação:
|
||||
```
|
||||
$ ./configure
|
||||
$ make
|
||||
```
|
||||
Agora, podemos verificar se os testes estão funcionando:
|
||||
```
|
||||
$ make check
|
||||
Making check in src
|
||||
make[1]: Entering directory '/home/standup/libwally-core/src'
|
||||
Making check in secp256k1
|
||||
make[2]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make check-TESTS
|
||||
make[3]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[4]: Entering directory '/home/standup/libwally-core/src/secp256k1'
|
||||
============================================================================
|
||||
Testsuite summary for libsecp256k1 0.1
|
||||
============================================================================
|
||||
# TOTAL: 0
|
||||
# PASS: 0
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
make[4]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[3]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[2]: Leaving directory '/home/standup/libwally-core/src/secp256k1'
|
||||
make[2]: Entering directory '/home/standup/libwally-core/src'
|
||||
make check-TESTS check-local
|
||||
make[3]: Entering directory '/home/standup/libwally-core/src'
|
||||
make[4]: Entering directory '/home/standup/libwally-core/src'
|
||||
PASS: test_bech32
|
||||
PASS: test_psbt
|
||||
PASS: test_psbt_limits
|
||||
PASS: test_tx
|
||||
============================================================================
|
||||
Testsuite summary for libwallycore 0.7.8
|
||||
============================================================================
|
||||
# TOTAL: 4
|
||||
# PASS: 4
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
make[4]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[3]: Nothing to be done for 'check-local'.
|
||||
make[3]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[2]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[1]: Leaving directory '/home/standup/libwally-core/src'
|
||||
make[1]: Entering directory '/home/standup/libwally-core'
|
||||
make[1]: Nothing to be done for 'check-am'.
|
||||
make[1]: Leaving directory '/home/standup/libwally-core'
|
||||
```
|
||||
Finalmente, podemos instalar:
|
||||
```
|
||||
$ sudo make install
|
||||
```
|
||||
|
||||
## Nos Preparando Para a Libwally
|
||||
|
||||
Então, como usamos a Libwally em um programa? Como de costume, precisaremos incluir os arquivos e vincular as bibliotecas apropriadas em nosso código.
|
||||
|
||||
### Incluindo os Arquivos
|
||||
|
||||
Há um número considerável de arquivos que podemos incluir:
|
||||
|
||||
```
|
||||
$ ls /usr/include/wally*
|
||||
/usr/include/wally_address.h /usr/include/wally_bip39.h /usr/include/wally_elements.h /usr/include/wally_script.h
|
||||
/usr/include/wally_bip32.h /usr/include/wally_core.h /usr/include/wally.hpp /usr/include/wally_symmetric.h
|
||||
/usr/include/wally_bip38.h /usr/include/wally_crypto.h /usr/include/wally_psbt.h /usr/include/wally_transaction.h
|
||||
```
|
||||
Felizmente, os nomes dos arquivos correspondem amplamente às seções da [documentação](https://wally.readthedocs.io/en/latest/), então devemos ser capazes de incluir os arquivos corretos com base no que estamos fazendo, depois de incluir o onipresente `wally_core.h`.
|
||||
|
||||
### Vinculando as Bibliotecas
|
||||
|
||||
Também precisaremos vincular as bibliotecas apropriadas:
|
||||
```
|
||||
$ ls /usr/lib/libsecp* /usr/lib/libwally*
|
||||
/usr/lib/libsecp256k1.a /usr/lib/libwallycore.la /usr/lib/libwallycore.so.0
|
||||
/usr/lib/libsecp256k1.la /usr/lib/libwallycore.so /usr/lib/libwallycore.so.0.0.0
|
||||
```
|
||||
Usaremos principalmente a `libwallycore`.
|
||||
|
||||
## Configurando um Programa Libwally
|
||||
|
||||
Comparado com algumas das bibliotecas anteriores, a Libwally é ridiculamente fácil de ser inicializada:
|
||||
```
|
||||
lw_response = wally_init(0);
|
||||
```
|
||||
E então, quando terminarmos, há uma função útil para limpar qualquer memória alocada:
|
||||
```
|
||||
wally_cleanup(0);
|
||||
```
|
||||
Em ambos os casos, o argumento é para flags, mas atualmente está definido como `0`.
|
||||
|
||||
## Testando um Programa de Teste da Libwally
|
||||
|
||||
O diretório src contém o arquivo [testwally.c](src / 16_1_testwally.c), que apenas mostra como funcionam as funções de inicialização e de limpeza.
|
||||
|
||||
Podemos compilá-lo da seguinte maneira:
|
||||
```
|
||||
$ cc testwally.c -lwallycore -o testwally
|
||||
```
|
||||
Depois, podemos executá-lo:
|
||||
```
|
||||
$ ./testwally
|
||||
Startup: 0
|
||||
```
|
||||
O valor "Startup" é o retorno do comando `wally_init`. O valor `0` pode inicialmente parecer desanimador, mas é o que desejamos ver no momento:
|
||||
```
|
||||
include/wally_core.h:#define WALLY_OK 0 /** Success */
|
||||
```
|
||||
|
||||
## Instalando o Libsodium
|
||||
|
||||
Também precisamos instalar o Libsodium para obter acesso a um gerador de números aleatórios de alta qualidade para fins de teste.
|
||||
|
||||
> :warning: **AVISO:** A geração de números aleatórios pode ser um dos maiores pontos de vulnerabilidade em qualquer software do Bitcoin. Se fizermos isso de maneira errada, podemos expor nossos usuários a ataques porque eles acabam tendo chaves privadas do Bitcoin inseguras, e isso não é um [problema teórico](https://github.com/BlockchainCommons/SmartCustodyBook/blob/master/manuscript/03-adversaries.md#adversary-systemic-key-compromise). A BlockchainInfo gerou incorretamente 0,0002% das suas chaves, o que resultou na perda temporária de 250 Bitcoins. Resumindo: precisamos nos certificar de estar totalmente confortável com a geração de números aleatórios. Podemos usar o Libsodium ou qualquer outro método TRNG ainda mais robusto.
|
||||
|
||||
Podemos baixar um [Libsodium tarball](https://download.libsodium.org/libsodium/releases/) e seguir as instruções em [instalação do Libsodium](https://doc.libsodium.org/installation) para deixarmos tudo pronto em nosso computador.
|
||||
|
||||
Primeiro, descompactamos:
|
||||
```
|
||||
$ tar xzfv /tmp/libsodium-1.0.18-stable.tar.gz
|
||||
```
|
||||
Então, ajustamos o arquivo `configure` exatamente como fizemos nas outras bibliotecas até o momento:
|
||||
```
|
||||
< ac_default_prefix=/usr
|
||||
---
|
||||
> ac_default_prefix=/usr/local
|
||||
```
|
||||
Finalmente, usamos os comandos `make`,`check` e `install`:
|
||||
```
|
||||
$ make
|
||||
$ make check
|
||||
...
|
||||
============================================================================
|
||||
Testsuite summary for libsodium 1.0.18
|
||||
============================================================================
|
||||
# TOTAL: 77
|
||||
# PASS: 77
|
||||
# SKIP: 0
|
||||
# XFAIL: 0
|
||||
# FAIL: 0
|
||||
# XPASS: 0
|
||||
# ERROR: 0
|
||||
============================================================================
|
||||
...
|
||||
$ sudo make install
|
||||
```
|
||||
Este curso usará apenas `libsodium` para um pequeno (mas crucial!) bit de geração de entropia, mas precisamos prestar muita atenção na próxima seção.
|
||||
|
||||
## Resumo: Configurando a Libwally
|
||||
|
||||
Ao instalar os includes e as bibliotecas da Libwally (e do Libsodium), ganhamos acesso a uma série de funções criptográficas e de carteira, que podem complementar nossas bibliotecas RPC e ZMG (ou nossa linha de comando `bitcoin-cli`).
|
||||
|
||||
Então, o que exatamente podemos fazer agora? É para dar essa resposta que temos todas as seções deste capítulo.
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando Bitcoin com Libwally" na seção [§16.2: Usando BIP39 na Libwally](16_2_Using_BIP39_in_Libwally.md).
|
106
pt/17_2_Using_BIP39_in_Libwally.md
Normal file
106
pt/17_2_Using_BIP39_in_Libwally.md
Normal file
@ -0,0 +1,106 @@
|
||||
# 16.2: Usando BIP39 na Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
Um dos maiores poderes da Libwally é que ela pode revelar o trabalho oculto da geração de seeds, chaves privadas e, também, de endereços. Para começar, ela suporta o [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), que é o BIP que define códigos mnemônicos para o Bitcoin, algo que era totalmente incompatível, na época, com o Bitcoin Core.
|
||||
|
||||
> :book: ***O que é um código mnemônico?*** Os endereços de Bitcoin (e suas chaves privadas correspondentes e as suas seeds) são listas longas e ininteligíveis de caracteres e números que não apenas são impossíveis de serem lembrados, mas também fáceis de serem digitados erroneamente. Os códigos mnemônicos são uma solução para isso que permitem aos usuários gravar 12 (ou 24) palavras em inglês, algo que é muito menos sujeito a erros. Esses códigos podem ser usados para restaurar totalmente uma seed BIP32 que é a base de uma carteira Determinística Hierárquica (HD).
|
||||
|
||||
> :book: ***O que é uma seed?*** Nós falamos brevemente das seeds na seção [§3.5: Compreendendo o Descritor](03_5_Understanding_the_Descriptor.md). É o número aleatório usado para gerar uma sequência inteira de chaves privadas (e, portanto, endereços) em uma carteira HD. Voltaremos às seeds na próxima seção, onde falaremos sobre as carteiras HD e a Libwally. Por enquanto, apenas é necessário saber que um código mnemônico BIP39 corresponde à seed para uma carteira HD do BIP32.
|
||||
|
||||
## Criando Códigos Mnemônicos
|
||||
|
||||
Todas as chaves Bitcoin começam com a entropia. Este primeiro uso da Libwally, e os mnemônicos BIP39, mostram como gerar entropia e obter um código mnemônico a partir disso.
|
||||
|
||||
> :book: ***O que é entropia?*** Entropia é uma maneira sofisticada de dizer aleatoriedade, mas é uma aleatoriedade medida cuidadosamente que é usada como a base de um número aleatório gerado verdadeiramente (no inglês, true-random-number generated, TRG). É medido em "bits", com mais bits de entropia resultando em mais aleatoriedade (e, portanto, mais proteção para o que está sendo gerado). Para o Bitcoin, a entropia é a base de nossa seed, que em uma carteira HD gera todos os seus endereços.
|
||||
|
||||
Sempre começaremos a trabalhar com a Libwally inicializando a biblioteca e testando os resultados, conforme demonstrado pela primeira vez na seção [§17.1](17_1_Setting_Up_Libwally.md):
|
||||
```
|
||||
int lw_response;
|
||||
|
||||
lw_response = wally_init(0);
|
||||
|
||||
if (lw_response) {
|
||||
|
||||
printf("Error: Wally_init failed: %d\n",lw_response);
|
||||
exit(-1);
|
||||
|
||||
}
|
||||
```
|
||||
Agora estamos prontos para a entropia.
|
||||
|
||||
### Criando Entropia
|
||||
|
||||
Usando o `libsodium`, podemos criar entropia com o comando `randombytes_buf`:
|
||||
```
|
||||
unsigned char entropy[16];
|
||||
randombytes_buf(entropy, 16);
|
||||
```
|
||||
Este exemplo, que será a única maneira de usarmos a biblioteca `libsodium`, cria 16 bytes de entropia. Geralmente, para criar um código mnemônico seguro, devemos usar entre 128 e 256 bits de entropia, que é 16 a 32 bytes.
|
||||
|
||||
> :warning: **AVISO:** Mais uma vez, certifique-se de estar muito confortável com o método de geração de entropia antes de usá-lo em um programa do mundo real.
|
||||
|
||||
### Traduzindo para um Mnemônico
|
||||
|
||||
16 bytes de entropia são suficientes para criar um código Mnemônico de 12 caracteres, que é feito com a função `bip39_mnemonic_from_bytes` da Libwally:
|
||||
```
|
||||
char *mnem = NULL;
|
||||
lw_response = bip39_mnemonic_from_bytes(NULL,entropy,16,&mnem);
|
||||
```
|
||||
Observe que temos que passar o tamanho do byte, então se quisermos aumentar o tamanho da entropia, para gerar uma frase mnemônica mais longa, também precisaríamos aumentar o valor nesta função.
|
||||
|
||||
> **NOTA:** Existem listas de palavras mnemônicas para diferentes idiomas! O padrão é usar a lista do idioma inglês, que é a variável `NULL` nesses comandos mnemônicos da Libwally, mas podemos, alternativamente, solicitar um idioma diferente!
|
||||
|
||||
É isso! Nós criamos uma frase mnemônica!
|
||||
|
||||
> :book: ***Como a frase mnemônica é criada?*** Podemos aprender mais sobre isso no [BIP39](https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki), mas, se preferir, Greg Walker tem um [excelente exemplo](https://learnmeabitcoin.com/technical/mnemonic): de maneira geral, adicionamos um checksum e convertemos cada conjunto de 11 bits em uma palavra da lista de palavras. Podemos fazer isso com os comandos `bip39_get_wordlist` e `bip39_get_word` se não confiarmos no comando `bip39_mnemonic_from_bytes`.
|
||||
|
||||
### Traduzindo para uma Seed
|
||||
|
||||
Existem algumas funções, como o `bip32_key_from_seed` (que veremos na próxima seção) que requerem que tenhamos os bits ao invés do Mnemônico. As duas coisas são funcionalmente idênticas: se temos a seed, podemos gerar o mnemônico e vice-versa.
|
||||
|
||||
Se precisarmos gerar a seed a partir do nosso mnemônico, basta usar o comando `bip39_mnemonic_to_seed`:
|
||||
```
|
||||
unsigned char seed[BIP39_SEED_LEN_512];
|
||||
size_t seed_len;
|
||||
|
||||
lw_response = bip39_mnemonic_to_seed(mnem,NULL,seed,BIP39_SEED_LEN_512,&seed_len);
|
||||
```
|
||||
Observe que todas as seeds do BIP39 têm 512 bytes; no entanto, devemos definir o tamanho de nossa variável apropriadamente e passar o tamanho para o `bip39_mnemonic_to_seed`.
|
||||
|
||||
### Vendo a Nossa Seed
|
||||
|
||||
Se quisermos ver como nossa seed é em hexadecimal, podemos usar a função `wally_hex_from_bytes` para transformar nossa seed em um código hexadecimal legível (mas isso não é muito bom para pessoas):
|
||||
```
|
||||
char *seed_hex;
|
||||
wally_hex_from_bytes(seed,sizeof(seed),&seed_hex);
|
||||
printf("Seed: %s\n",seed_hex);
|
||||
```
|
||||
Se dizermos tudo certo, devemos obter uma seed de 64 bytes. (Essa é a variável `BIP39_SEED_LEN_512` que estamos usando, que define um comprimento de seed padrão de 512 bits ou 64 bytes.)
|
||||
|
||||
> :warning: **ATENÇÃO:** Definitivamente devemos testar se o comprimento da nossa seed é de 64 bytes de alguma forma, porque é fácil errar em alguma coisa, por exemplo, usando o tipo de variável errado quando executamos o `bip39_mnemonic_to_seed`.
|
||||
|
||||
## Testando o Código Mnemônico
|
||||
|
||||
O código completo para gerar entropia, gerar um mnemônico BIP39, validar o mnemônico e gerar uma seed pode ser encontrado no [diretório src/](src/17_2_genmnemonic.c). Podemos fazer o download e compilar:
|
||||
```
|
||||
$ cc genmnemonic.c -lwallycore -lsodium -o genmnemonic
|
||||
```
|
||||
Então podemos executar o teste:
|
||||
```
|
||||
Mnemonic: parent wasp flight sweet miracle inject lemon matter label column canyon trend
|
||||
Mnemonic validated!
|
||||
Seed: 47b04cfb5d8fd43d371497f8555a27a25ca0a04aafeb6859dd4cbf37f6664b0600c4685c1efac29c082b1df29081f7a46f94a26f618fc6fd38d8bc7b6cd344c7
|
||||
```
|
||||
|
||||
## Resumo: Usando BIP39 na Libwally
|
||||
|
||||
O BIP39 nos permite gerar um conjunto de 12-24 palavras Mnemônicas a partir de uma seed (e a biblioteca Libwally também permite que a validemos!).
|
||||
|
||||
> :fire: ***Qual é o poder do BIP39?*** Seeds de Bitcoin e chaves privadas estão sujeitas a todos os tipos de perda. Se digitarmos errado um único dígito, nosso dinheiro será perdido para sempre. Palavras mnemônicas são uma forma muito mais amigável de representar os mesmos dados, mas como são palavras no idioma de escolha do usuário, são menos sujeitas a erros. O poder do BIP39 é, portanto, melhorar a acessibilidade, usabilidade e segurança do Bitcoin.
|
||||
|
||||
> :fire: ***Qual é o poder do BIP39 na Libwally?*** O Bitcoind atualmente não suporta palavras mnemônicas, então usar a Libwally pode permitir que geremos palavras mnemônicas em conjunto com endereços mantidos no `bitcoind`, embora como veremos na seção §17.7, é necessário um pouco de gambiarra para importar suas chaves para o Bitcoin Core.
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando o Bitcoind usando o Libwally" na seção [§17.3: Usando o BIP32 no Libwally](16_3_Using_BIP32_in_Libwally.md).
|
142
pt/17_3_Using_BIP32_in_Libwally.md
Normal file
142
pt/17_3_Using_BIP32_in_Libwally.md
Normal file
@ -0,0 +1,142 @@
|
||||
# 17.3: Usando o BIP32 na Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
Na seção [§17.2](17_2_Using_BIP39_in_Libwally.md), fomos capazes de usar entropia para gerar uma semente e nosso mnemônico relacionado. Como devemos nos lembrar da seção [§3.5: Compreendendo o Descritor](03_5_Understanding_the_Descriptor.md), uma seed é a base de uma Carteira Determinística Hierárquica (no inglês Hierchical Deterministic, HD), onde aquela única seed pode ser usada para gerar muitos endereços. Então, como passamos da seed para os endereços reais? É aí que entra o [BIP32](https://en.bitcoin.it/wiki/BIP_0032).
|
||||
|
||||
## Criando uma Raiz HD
|
||||
|
||||
Para criar um endereço HD, é necessário começar com uma seed e, em seguida, descer na hierarquia até o ponto em que criamos os endereços.
|
||||
|
||||
Isso começa com bastante facilidade, gerando uma seed, o que já fizemos na seção anterior:
|
||||
```
|
||||
unsigned char entropy[16];
|
||||
randombytes_buf(entropy, 16);
|
||||
|
||||
char *mnem = NULL;
|
||||
lw_response = bip39_mnemonic_from_bytes(NULL,entropy,16,&mnem);
|
||||
|
||||
unsigned char seed[BIP39_SEED_LEN_512];
|
||||
size_t seed_len;
|
||||
lw_response = bip39_mnemonic_to_seed(mnem,NULL,seed,BIP39_SEED_LEN_512,&seed_len);
|
||||
```
|
||||
### Gerando uma Chave Raiz
|
||||
|
||||
Com uma seed em mãos, podemos gerar uma chave mestra estendida com a função `bip32_key_from_seed_alloc` (ou, alternativamente, com o comando `bip32_key_from_seed`, que não faz o `alloc`):
|
||||
```
|
||||
struct ext_key *key_root;
|
||||
lw_response = bip32_key_from_seed_alloc(seed,sizeof(seed),BIP32_VER_TEST_PRIVATE,0,&key_root);
|
||||
```
|
||||
Como podemos ver, precisaremos dizer ao comando qual versão da chave retornar, neste caso `BIP32_VER_TEST_PRIVATE`, uma chave privada testnet.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Na mainnet, iríamos passar `BIP32_VER_MAIN_PRIVATE`.
|
||||
|
||||
### Gerando a xpub e a xprv
|
||||
|
||||
Sempre que tivermos uma chave em mãos, podemos transformá-la em chaves xpub ou xprv para distribuição com o comando `bip32_key_to_base58`. Basta dizer se desejamos uma chave `PRIVATE` (xprv) ou `PUBLIC` (xpub):
|
||||
```
|
||||
char *xprv;
|
||||
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PRIVATE, &xprv);
|
||||
|
||||
char *xpub;
|
||||
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PUBLIC, &xpub);
|
||||
```
|
||||
|
||||
## Compreendendo a Hierarquia
|
||||
|
||||
Antes de prosseguir, precisamos entender como funciona a hierarquia de uma carteira HD. Conforme discutido na seção [§3.5](03_5_Understanding_the_Descriptor.md), um caminho de derivação descreve a árvore que seguimos para obter uma chave hierárquica, então `[0/1/0]` é o 0º filho do 1º filho do 0º filho de uma chave raiz. Às vezes, parte dessa derivação é marcada com `'`s ou `h`s para mostrar derivações endurecidas, que aumentam a segurança: `[0'/1'/0']`.
|
||||
|
||||
No entanto, para carteiras HD, cada um desses níveis da hierarquia é usado de uma forma muito específica. Isso foi definido originalmente no [BIP44](https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki) e foi atualizado posteriormente para o Segwit no [BIP84](https://github.com/bitcoin/bips/blob/master/bip-0084.mediawiki).
|
||||
|
||||
Ao todo, um caminho de derivação BIP32 é definido para ter cinco níveis:
|
||||
|
||||
1. **Propósito.** Isso geralmente é definido como `44'` ou `84'`, dependendo do BIP que estamos seguindo;
|
||||
2. **Moeda.** Para bitcoins Mainnet, é `0'`, para testnet é `1'`;
|
||||
3. **Conta.** Uma carteira pode conter várias contas discretas, começando com `0'`;
|
||||
4. **Troco.** Os endereços externos (para distribuição) são definidos como `0`, enquanto os endereços internos (para troco) são definidos como `1`;
|
||||
5. **Índice.** O enésimo endereço da hierarquia, começando com `0`.
|
||||
|
||||
Então, na testnet, o endereço zero para um endereço externo para a conta zero para moedas testnet usando os padrões BIP84 é `[m/84'/1'/0'/0/0]`. Esse é o endereço que criaremos neste momento.
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** Para a mainnet, seria `[m/84'/0'/0'/0/0]`.
|
||||
|
||||
### Entendendo a Hierarquia no Bitcoin Core
|
||||
|
||||
Estaremos usando a hierarquia acima para todas as chaves HD na Libwally, mas observe que este padrão não é usado no `bitcoin-cli` do Bitcoin Core, que ao invés disso usa `[m/0'/0'/0']` para o enésimo endereço externo e `[m/0'/1'/0']` para o enésimo endereço de troco.
|
||||
|
||||
## Gerando um Endereço
|
||||
|
||||
Para gerar um endereço, devemos explorar toda a hierarquia.
|
||||
|
||||
### Gerando uma Chave de Conta
|
||||
|
||||
Uma maneira de fazer isso é usar a função `bip32_key_from_parent_path_alloc` para descer vários níveis de uma hierarquia. Podemos incorporar os níveis em uma matriz:
|
||||
```
|
||||
uint32_t path_account[] = {BIP32_INITIAL_HARDENED_CHILD+84, BIP32_INITIAL_HARDENED_CHILD+1, BIP32_INITIAL_HARDENED_CHILD};
|
||||
```
|
||||
Aqui, veremos a enésima filha endurecida (essa é a conta) ou a primeira filha endurecida (que são as moedas testnet) da 84ª filha endurecida (esse é o padrão BIP84): `[m/84'/1'/0']`.
|
||||
|
||||
Podemos então usar esse caminho para gerar uma nova chave a partir da nossa antiga chave:
|
||||
```
|
||||
struct ext_key *key_account;
|
||||
lw_response = bip32_key_from_parent_path_alloc(key_root,path_account,sizeof(path_account),BIP32_FLAG_KEY_PRIVATE,&key_account);
|
||||
```
|
||||
Sempre que tiviermos uma nova chave, poderemos usá-la para gerar novas chaves xprv e xpub, se desejarmos:
|
||||
```
|
||||
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PRIVATE, &a_xprv);
|
||||
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PUBLIC, &a_xpub);
|
||||
```
|
||||
|
||||
### Gerando uma Chave de Endereço
|
||||
|
||||
Alternativamente, podemos usar a função `bip32_key_from_parent_alloc`, que apenas desce um nível da hierarquia por vez. O exemplo a seguir desce para o enésimo filho da chave da conta (que é o endereço externo) e, em seguida, o enésimo filho dessa chave. Isso seria útil porque poderíamos continuar gerando o primeiro endereço, o segundo endereço e assim por diante a partir dessa chave externa:
|
||||
```
|
||||
struct ext_key *key_external;
|
||||
lw_response = bip32_key_from_parent_alloc(key_account,0,BIP32_FLAG_KEY_PRIVATE,&key_external);
|
||||
|
||||
struct ext_key *key_address;
|
||||
lw_response = bip32_key_from_parent_alloc(key_external,0,BIP32_FLAG_KEY_PRIVATE,&key_address);
|
||||
```
|
||||
> :warning: **AVISO:** Em algum ponto desta hierarquia, podemos decidir gerar o `BIP32_FLAG_KEY_PUBLIC` ao invés do `BIP32_FLAG_KEY_PRIVATE`. Obviamente, essa decisão será baseada na nossa segurança e nas nossas necessidades, mas precisamos lembrar de que só precisamos de uma chave pública para gerar o endereço real.
|
||||
|
||||
### Gerando um Endereço
|
||||
|
||||
Finalmente, estamos prontos para gerar um endereço a partir de sua chave final. Tudo que fazemos é executar `wally_bip32_to_addr_segwit` usando nossa chave final e uma descrição de que tipo de endereço é este.
|
||||
```
|
||||
char *segwit;
|
||||
lw_response = wally_bip32_key_to_addr_segwit(key_address,"tb",0,&segwit);
|
||||
|
||||
printf("[m/84'/1'/0'/0/0]: %s\n",segwit);
|
||||
```
|
||||
|
||||
> :link: **TESTNET vs MAINNET:** O argumento `tb` define um endereço Testnet. Para a Mainnet, usamos o `bc`.
|
||||
|
||||
Há também uma função `wally_bip32_key_to_address`, que pode ser usada para gerar um endereço legado ou um endereço Segwit aninhado.
|
||||
|
||||
## Testando o Código HD
|
||||
|
||||
O código para esses exemplos HD pode, como de costume, ser encontrado no [diretório src/](src/17_3_genhd.c).
|
||||
|
||||
Podemos compilá-lo e testá-lo:
|
||||
```
|
||||
$ cc genhd.c -lwallycore -lsodium -o genhd
|
||||
$ ./genhd
|
||||
Mnemonic: behind mirror pond finish borrow wood park foam guess mail regular reflect
|
||||
Root xprv key: tprv8ZgxMBicQKsPdLFXmZ6VegTxcmeieNpRUq8J2ahXxSaK2aF7CGqAc14ZADLjdHJdCr8oR2Zng9YH1x1A7EBaajQLVGNtxc4YpFejdE3wyj8
|
||||
Root xpub key: tpubD6NzVbkrYhZ4WoHKfCm64685BoAeoi1L48j5K6jqNiNhs4VspfeknVgRLLiQJ3RkXiA9VxguUjmEwobtmrXNbhXsPHfm9W5HJR9DKRGaGJ2
|
||||
Account xprv key: tprv8yZN7h6SPvJXrhAk56z6cwHQE6qZBRreB9fqqZJ1Xd1nLci3Rw8HTmqNkpFNgf3eZx8hYzhFWafUhHSt3HgF13aHvCE6kveS7gZAyfQwMDi
|
||||
Account xpub key: tpubDWFQG78gYHzCkACXxkeh2LwWo8MVLm3YkTGd85LJwtpBB6xp4KwseGTEvxjeZNhnCNPdfZqRcgcZZAka4tD3xGS2J53WKHPMRhG357VKsqT
|
||||
[m/84'/1'/0'/0/0]: tb1q0knqq26ek59pfl7nukzqr28m2zl5wn2f0ldvwu
|
||||
```
|
||||
|
||||
## Resumo: Usando o BIP32 na Libwally
|
||||
|
||||
Uma carteira HD permite gerar um grande número de chaves a partir de uma única seed. Agora sabemos como essas chaves são organizadas no BIP44, BIP84 e no Bitcoin Core, além de como derivá-las, começando com uma seed ou palavras mnemônicas.
|
||||
|
||||
> :fire: ***Qual é o poder do BIP32?*** As chaves são o elemento mais difícil (e mais perigoso) da maioria das operações criptográficas. Se as perdermos, perderemos tudo o que a chave protegeu. O BIP32 garante que só precisamos conhecer uma chave, a semente, ao invés de um grande número de chaves diferentes para endereços diferentes.
|
||||
|
||||
> :fire: ***Qual é o poder do BIP32 na Libwally?*** O Bitcoind já faz a criação de endereços baseada em HD para nós, o que significa que normalmente não precisamos nos preocupar em derivar endereços dessa maneira. No entanto, usar as funções BIP32 da Libwally pode ser muito útil se tivermos uma máquina offline onde precisamos derivar endereços, possivelmente com base em uma semente passada do `bitcoind` para nosso dispositivo offline (ou vice-versa).
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando Bitcoin com Libwally" na seção [§17.4: Usando PSBTs na Libwally](16_4_Using_PSBTs_in_Libwally.md).
|
376
pt/17_4_Using_PSBTs_in_Libwally.md
Normal file
376
pt/17_4_Using_PSBTs_in_Libwally.md
Normal file
@ -0,0 +1,376 @@
|
||||
# 17.4: Usando PSBTs na Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
Nós aprendemos tudo sobre as transações parcialmente assinadas no Bitcoin (PSBTs) na seção [§7.1](07_1_Creating_a_Partially_Signed_Bitcoin_Transaction.md) e na [§7.2](07_2_Using_a_Partially_Signed_Bitcoin_Transaction.md), e como vimos na [§7.3: Integrando com Hardware Wallets](/github.com/BlockchainCommons/Learning-Bitcoin-from-the-Command-Line/blob/master/07_3_Integrating_with_Hardware_Wallets.md), uma das nossas principais vantagens é a capacidade de integração com nodes offline, como Hardware Wallets. O HWI permitiu que passássemos comandos para uma carteira de hardware, mas o que a própria carteira usa para gerenciar os PSBTs? Por acaso, podemos usar algo na Libwally, como esta seção irá demonstrar.
|
||||
|
||||
Basicamente, a Libwally tem todas as funcionalidades PSBT, então se há algo que podemos fazer com o `bitcoind`, também podemos fazer usando a Libwally, mesmo se nosso dispositivo estiver offline. O que segue é uma introdução básica a um tópico bem complexo.
|
||||
|
||||
## Convertendo um PSBT
|
||||
|
||||
Converter um PSBT na estrutura interna da Libwally é incrivelmente fácil, basta executar `wally_psbt_from_base64` com um PSBT base64, que são as saídas produzidas pelo `bitcoin-cli`, como:
|
||||
|
||||
`cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA==`
|
||||
|
||||
No entanto, é um pouco mais difícil de lidar com o resultado, porque a Libwally o converte em uma estrutura `wally_psbt` muito complexa.
|
||||
|
||||
Veja como é definido no arquivo `/usr/include/wally_psbt.h`:
|
||||
```
|
||||
struct wally_psbt {
|
||||
unsigned char magic[5];
|
||||
struct wally_tx *tx;
|
||||
struct wally_psbt_input *inputs;
|
||||
size_t num_inputs;
|
||||
size_t inputs_allocation_len;
|
||||
struct wally_psbt_output *outputs;
|
||||
size_t num_outputs;
|
||||
size_t outputs_allocation_len;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
uint32_t version;
|
||||
};
|
||||
|
||||
struct wally_psbt_input {
|
||||
struct wally_tx *non_witness_utxo;
|
||||
struct wally_tx_output *witness_utxo;
|
||||
unsigned char *redeem_script;
|
||||
size_t redeem_script_len;
|
||||
unsigned char *witness_script;
|
||||
size_t witness_script_len;
|
||||
unsigned char *final_script_sig;
|
||||
size_t final_script_sig_len;
|
||||
struct wally_tx_witness_stack *final_witness;
|
||||
struct wally_keypath_map *keypaths;
|
||||
struct wally_partial_sigs_map *partial_sigs;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
uint32_t sighash_type;
|
||||
};
|
||||
|
||||
struct wally_psbt_output {
|
||||
unsigned char *redeem_script;
|
||||
size_t redeem_script_len;
|
||||
unsigned char *witness_script;
|
||||
size_t witness_script_len;
|
||||
struct wally_keypath_map *keypaths;
|
||||
struct wally_unknowns_map *unknowns;
|
||||
};
|
||||
```
|
||||
Estes, por sua vez, usam algumas estruturas de transação definidas em `/usr/include/wally_transaction.h`:
|
||||
```
|
||||
struct wally_tx {
|
||||
uint32_t version;
|
||||
uint32_t locktime;
|
||||
struct wally_tx_input *inputs;
|
||||
size_t num_inputs;
|
||||
size_t inputs_allocation_len;
|
||||
struct wally_tx_output *outputs;
|
||||
size_t num_outputs;
|
||||
size_t outputs_allocation_len;
|
||||
};
|
||||
|
||||
struct wally_tx_output {
|
||||
uint64_t satoshi;
|
||||
unsigned char *script;
|
||||
size_t script_len;
|
||||
uint8_t features;
|
||||
};
|
||||
```
|
||||
Tem muita coisa aí! Embora muito disso deva ser familiar dos capítulos anteriores, é um pouco intimidador ver tudo disposto em estruturas C.
|
||||
|
||||
## Lendo um PSBT Convertido
|
||||
|
||||
Obviamente, podemos ler qualquer coisa de uma estrutura PSBT chamando os elementos individuais das várias subestruturas. A seguir, veja uma breve visão geral que mostra como captar alguns dos elementos.
|
||||
|
||||
Aqui está um exemplo de recuperação dos valores e os `scriptPubKeys` das entradas:
|
||||
```
|
||||
int inputs = psbt->num_inputs;
|
||||
printf("TOTAL INPUTS: %i\n",inputs);
|
||||
|
||||
for (int i = 0 ; i < inputs ; i++) {
|
||||
printf("\nINPUT #%i: %i satoshis\n",i, psbt->inputs[i].witness_utxo->satoshi);
|
||||
|
||||
char *script_hex;
|
||||
wally_hex_from_bytes(psbt->inputs[i].witness_utxo->script,psbt->inputs[i].witness_utxo->script_len,&script_hex);
|
||||
printf("scriptPubKey: %s\n",script_hex);
|
||||
wally_free_string(script_hex);
|
||||
|
||||
}
|
||||
```
|
||||
Este padrão de programação será usado em muitas partes do PSBT. Podemos olhar para o tamanho do array de entrada e depois o percorrer, recuperando o que desejamos observar (neste caso, satoshis e scripts).
|
||||
|
||||
Aqui está um exemplo semelhante para as saídas:
|
||||
```
|
||||
int outputs = psbt->num_outputs;
|
||||
printf("\nTOTAL OUTPUTS: %i\n",outputs);
|
||||
for (int i = 0 ; i < outputs ; i++) {
|
||||
|
||||
char *pubkey_hex;
|
||||
wally_hex_from_bytes(psbt->tx->outputs[i].script,psbt->tx->outputs[i].script_len,&pubkey_hex);
|
||||
printf("\nINPUT #%i\n",i);
|
||||
printf("scriptPubKey: %s\n",pubkey_hex);
|
||||
wally_free_string(pubkey_hex);
|
||||
}
|
||||
```
|
||||
Obviamente, há muito mais coisas que poderemos observar nos PSBTs. Na verdade, olhar é o ponto principal de um PSBT: podemos verificar entradas e saídas de um computador offline.
|
||||
|
||||
> :warning: **AVISO:** Estas funções de leitura são _muito_ rudimentares e não funcionarão corretamente para situações extremamente normais como uma entrada ou saída que ainda está vazia ou que inclui um `non_witness_utxo`. Elas darão um segfault se não forem entregues um PSBT precisamente esperado. Um leitor de verdade precisaria ser consideravelmente mais robusto, para cobrir todas as situações possíveis, mas vamos deixar isso como um exercício para o leitor.
|
||||
|
||||
### Testando Nosso Leitor PSBT
|
||||
|
||||
Novamente, o código para este leitor PSBT (extremamente rudimentar e específico) está no [diretório src/](src/17_4_examinepsbt.c).
|
||||
|
||||
Podemos compilá-lo normalmente:
|
||||
```
|
||||
$ cc examinepsbt.c -lwallycore -o examinepsbt
|
||||
```
|
||||
O seguinte PSBT da seção [§7.3](07_3_Integrating_with_Hardware_Wallets.md) pode ser usado para o teste, pois atende aos critérios muito restritos exigidos por esta implementação limitada:
|
||||
```
|
||||
psbt=cHNidP8BAJoCAAAAAri6BLjKQZGO9Y1iVIYbxlxBJ2kqsTPWnxGaH4HrSjxbAAAAAAD+////leV0hwJ0fO40RmhuFVIYtO16ktic2J4vJFLAsT5TM8cBAAAAAP7///8CYOMWAAAAAAAWABTHctb5VULhHvEejvx8emmDCtOKBU+gBwAAAAAAFgAU9Ojd5ds3CJi1fIRWbj92CYhQgX0AAAAAAAEBH0BCDwAAAAAAFgAUABk8i/Je8Fb41FcaHD9lEj5f54giBgMBaNlILisC1wJ/tKie3FStqhrfcJM09kfQobBTOCiuxRiaHVILVAAAgAEAAIAAAACAAAAAADkCAAAAAQEfQEIPAAAAAAAWABQtTxOfqohTBNFWFqFm0tUVdK9KXSIGAqATz5xLX1aJ2SUwNqPkd8+YaJYm94FMlPCScm8Rt0GrGJodUgtUAACAAQAAgAAAAIAAAAAAAAAAAAAAIgID2UK1nupSfXC81nmB65XZ+pYlJp/W6wNk5FLt5ZCSx6kYmh1SC1QAAIABAACAAAAAgAEAAAABAAAAAA==
|
||||
```
|
||||
Ao executar o comando `examinepsbt` com esse PSBT, deveremos ver os scripts nas entradas e saídas:
|
||||
```
|
||||
$ ./examinepsbt $psbt
|
||||
TOTAL INPUTS: 2
|
||||
|
||||
INPUT #0: 1000000 satoshis
|
||||
scriptPubKey: 001400193c8bf25ef056f8d4571a1c3f65123e5fe788
|
||||
|
||||
INPUT #1: 1000000 satoshis
|
||||
scriptPubKey: 00142d4f139faa885304d15616a166d2d51574af4a5d
|
||||
|
||||
TOTAL OUTPUTS: 2
|
||||
|
||||
INPUT #0
|
||||
scriptPubKey: 0014c772d6f95542e11ef11e8efc7c7a69830ad38a05
|
||||
|
||||
INPUT #1
|
||||
scriptPubKey: 0014f4e8dde5db370898b57c84566e3f76098850817d
|
||||
```
|
||||
E, claro, você pode verificar tudo isso com o comando RPC `decodepsbt` para` bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"hash": "45f996d4ff8c9e9ab162f611c5b6ad752479ede9780f9903bdc80cd96619676d",
|
||||
"version": 2,
|
||||
"size": 154,
|
||||
"vsize": 154,
|
||||
"weight": 616,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "5b3c4aeb811f9a119fd633b12a6927415cc61b8654628df58e9141cab804bab8",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
},
|
||||
{
|
||||
"txid": "c733533eb1c052242f9ed89cd8927aedb41852156e684634ee7c74028774e595",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967294
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.01500000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"hex": "0014c772d6f95542e11ef11e8efc7c7a69830ad38a05",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qcaedd724gts3aug73m78c7nfsv9d8zs9q6h2kd"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 0.00499791,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"hex": "0014f4e8dde5db370898b57c84566e3f76098850817d",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1q7n5dmewmxuyf3dtus3txu0mkpxy9pqtacuprak"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 00193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"hex": "001400193c8bf25ef056f8d4571a1c3f65123e5fe788",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1qqqvnezljtmc9d7x52udpc0m9zgl9leugd2ur7y"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "030168d9482e2b02d7027fb4a89edc54adaa1adf709334f647d0a1b0533828aec5",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/569"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"witness_utxo": {
|
||||
"amount": 0.01000000,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"hex": "00142d4f139faa885304d15616a166d2d51574af4a5d",
|
||||
"type": "witness_v0_keyhash",
|
||||
"address": "tb1q948388a23pfsf52kz6skd5k4z4627jja2evztr"
|
||||
}
|
||||
},
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "02a013cf9c4b5f5689d9253036a3e477cf98689626f7814c94f092726f11b741ab",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/0/0"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
},
|
||||
{
|
||||
"bip32_derivs": [
|
||||
{
|
||||
"pubkey": "03d942b59eea527d70bcd67981eb95d9fa9625269fd6eb0364e452ede59092c7a9",
|
||||
"master_fingerprint": "9a1d520b",
|
||||
"path": "m/84'/1'/0'/1/1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fee": 0.00000209
|
||||
}
|
||||
```
|
||||
Podemos ver a entrada de satoshis e o `scriptPubKey` claramente listadOs nos `inputs` e a nova `scriptPubKey` no `vout` do `tx`.
|
||||
|
||||
Então, está tudo lá para utilizarmos!
|
||||
|
||||
## Criando um PSBT
|
||||
|
||||
Conforme observado no início desta seção, todas as funções necessárias para criar e processar os PSBTs estão disponíveis na Libwally. Na verdade, percorrer todo o processo para fazer isso é tão complexo que foge do escopo desta seção, mas aqui está um resumo rápido das funções necessárias. Observe que a [documentação](https://wally.readthedocs.io/en/latest/psbt/) está desatualizada para os PSBTs, portanto, precisaremos consultar o `/usr/include/wally_psbt.h` para obter as informações completas.
|
||||
|
||||
Conforme discutido na seção [§7.1](07_1_Creating_a_Partially_Signed_Bitcoin_Transaction.md), existem várias funções envolvidas na criação de PSBTs.
|
||||
|
||||
### Assumindo o Papel de Criador
|
||||
|
||||
A função de criador tem a tarefa de criar um PSBT com pelo menos uma entrada.
|
||||
|
||||
Um PSBT é criado com um simples uso do comando `wally_psbt_init_alloc`, informando quantas entradas e saídas eventualmente adicionaremos:
|
||||
```
|
||||
struct wally_psbt *psbt;
|
||||
lw_response = wally_psbt_init_alloc(0,1,1,0,&psbt);
|
||||
```
|
||||
Mas o que temos ainda não é um PSBT legal, por falta de entradas. Podemos criá-las criando uma transação e definindo-a como a transação global no PSBT, que atualiza todas as entradas e saídas:
|
||||
```
|
||||
struct wally_tx *gtx;
|
||||
lw_response = wally_tx_init_alloc(0,0,1,1,>x);
|
||||
lw_response = wally_psbt_set_global_tx(psbt,gtx);
|
||||
```
|
||||
### Testando nosso PSBT Criado
|
||||
|
||||
Neste ponto, devemos ter um PSBT vazio, mas funcionando, que pode ser visto compilando e executando [o programa](src/17_4_createemptypsbt.c).
|
||||
```
|
||||
$ cc createemptypsbt.c -lwallycore -o createemptypsbt
|
||||
$ ./createemptypsbt
|
||||
cHNidP8BAAoAAAAAAAAAAAAAAA==
|
||||
```
|
||||
Podemos até usar o `bitcoin-cli` para testar o resultado:
|
||||
```
|
||||
$ psbt=$(./createpsbt)
|
||||
$ bitcoin-cli decodepsbt $psbt
|
||||
{
|
||||
"tx": {
|
||||
"txid": "f702453dd03b0f055e5437d76128141803984fb10acb85fc3b2184fae2f3fa78",
|
||||
"hash": "f702453dd03b0f055e5437d76128141803984fb10acb85fc3b2184fae2f3fa78",
|
||||
"version": 0,
|
||||
"size": 10,
|
||||
"vsize": 10,
|
||||
"weight": 40,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
],
|
||||
"vout": [
|
||||
]
|
||||
},
|
||||
"unknown": {
|
||||
},
|
||||
"inputs": [
|
||||
],
|
||||
"outputs": [
|
||||
],
|
||||
"fee": 0.00000000
|
||||
}
|
||||
```
|
||||
## Assumindo as Demais Funções
|
||||
|
||||
Assim como na leitura de PSBT, estamos introduzindo o conceito de criação do PSBT e, em seguida, deixando o resto como um exercício para o leitor.
|
||||
|
||||
A seguir está uma lista aproximada de funções para cada papel. Mais funções serão necessárias para criar alguns dos elementos que são adicionados aos PSBTs.
|
||||
|
||||
**Criador:**
|
||||
|
||||
* wally_psbt_init_alloc
|
||||
* wally_psbt_set_global_tx
|
||||
|
||||
**Atualizador:**
|
||||
|
||||
* wally_psbt_input_set_non_witness_utxo
|
||||
* wally_psbt_input_set_witness_utxo
|
||||
* wally_psbt_input_set_redeem_script
|
||||
* wally_psbt_input_set_witness_script
|
||||
* wally_psbt_input_set_keypaths
|
||||
* wally_psbt_input_set_unknowns
|
||||
* wally_psbt_output_set_redeem_script
|
||||
* wally_psbt_output_set_witness_script
|
||||
* wally_psbt_output_set_keypaths
|
||||
* wally_psbt_output_set_unknowns
|
||||
|
||||
**Assinante:**
|
||||
|
||||
* wally_psbt_input_set_partial_sigs
|
||||
* wally_psbt_input_set_sighash_type
|
||||
* wally_psbt_sign
|
||||
|
||||
**Combinador:**
|
||||
|
||||
* wally_psbt_combine
|
||||
|
||||
**Finalizador:**
|
||||
* wally_psbt_finalize
|
||||
* wally_psbt_input_set_final_script_sig
|
||||
* wally_psbt_input_set_final_witness
|
||||
|
||||
**Extrator:**
|
||||
|
||||
* wally_psbt_extract
|
||||
|
||||
## Resumo: Usando PSBTs na Libwally
|
||||
|
||||
Esta seção poderia ser um capítulo inteiro, já que trabalhar com os PSBTs em um nível baixo é um trabalho muito intenso que requer uma manipulação muito mais intensiva de entradas e saídas como foi o caso do [Capítulo 7](07_0_Expanding_Bitcoin_Transactions_PSBTs.md). Ao invés disso, esta seção mostra o básico: como extrair informações de um PSBT e como começar a criar um.
|
||||
|
||||
> :fire: ***Qual é o poder dos PSBTs na Libwally?*** Obviamente, já podemos fazer tudo isso nos `bitcoin-cli`, e é mais simples porque o Bitcoin Core gerencia muito do trabalho penoso. A vantagem de usar a Libwally é que ela pode ser executada offline, então pode ser a Libwally que está do outro lado de um dispositivo de hardware com o qual nosso `bitcoin-cli` está se comunicando com o HWI. Este é, de fato, um dos principais pontos dos PSBTs: ser capaz de manipular transações parcialmente assinadas sem a necessidade de um node completo. A Libwally permite isso.
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando Bitcoin com Libwally" na seção [§17.5: Usando Scripts na Libwally](17_5_Using_Scripts_in_Libwally.md).
|
179
pt/17_5_Using_Scripts_in_Libwally.md
Normal file
179
pt/17_5_Using_Scripts_in_Libwally.md
Normal file
@ -0,0 +1,179 @@
|
||||
# 17.5: Usando Scripts na Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
Na seção 3 deste capítulo, ao apresentar os scripts, dissemos que era provável que criássemos transações usando scripts com uma API e dissemos que este era um tópico para o futuro. Bem, agora o futuro chegou.
|
||||
|
||||
## Criando o Script
|
||||
|
||||
Criar o script é a coisa _mais fácil_ de se fazer na Libwally. Veja o exemplo a seguir, um simples [Script Quebra-Cabeça](13_1_Writing_Puzzle_Scripts.md) ao qual retornamos de vez em quando:
|
||||
```
|
||||
OP_ADD 99 OP_EQUAL
|
||||
```
|
||||
Usando o `btcc`, podemos serializar isto.
|
||||
```
|
||||
$ btcc OP_ADD 99 OP_EQUAL
|
||||
warning: ambiguous input 99 is interpreted as a numeric value; use 0x99 to force into hexadecimal interpretation
|
||||
93016387
|
||||
```
|
||||
Anteriormente, construímos o script P2SH padrão manualmente, mas a Libwally pode fazer isso por nós.
|
||||
|
||||
Primeiro, a Libwally precisa converter o hex em bytes, uma vez que os bytes são o que realmente funciona:
|
||||
```
|
||||
int script_length = strlen(script)/2;
|
||||
unsigned char bscript[script_length];
|
||||
|
||||
lw_response = wally_hex_to_bytes(script,bscript,script_length,&written);
|
||||
```
|
||||
Então, executamos o comando `wally_scriptpubkey_p2sh_from_bytes` com os bytes, dizendo à Libwally para também fazer o `HASH160` para nós:
|
||||
```
|
||||
unsigned char p2sh[WALLY_SCRIPTPUBKEY_P2SH_LEN];
|
||||
|
||||
lw_response = wally_scriptpubkey_p2sh_from_bytes(bscript,sizeof(bscript),WALLY_SCRIPT_HASH160,p2sh,WALLY_SCRIPTPUBKEY_P2SH_LEN,&written);
|
||||
```
|
||||
Se olharmos os resultados do `p2sh`, veremos o seguinte:
|
||||
```
|
||||
a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87
|
||||
```
|
||||
Que [devemos nos lembrar](10_2_Building_the_Structure_of_P2SH.md) se divide em:
|
||||
```
|
||||
a9 / 14 / 3f58b4f7b14847a9083694b9b3b52a4cea2569ed / 87
|
||||
```
|
||||
Este é o nosso velho amigo `OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL`.
|
||||
|
||||
Basicamente, a Libwally pegou nosso script de resgate serializado, fez o hash para nós com SHA-256 e RIPEMD-160 e aplicou o enquadramento padrão para transformá-lo em um P2SH adequado. Fizemos um trabalho semelhante ao feito na seção [§10.2](10_2_Building_the_Structure_of_P2SH.md), mas com um excesso de comandos shell.
|
||||
|
||||
Na verdade, podemos verificar novamente o nosso trabalho usando os mesmos comandos do §10.2:
|
||||
```
|
||||
$ redeemScript="93016387"
|
||||
$ echo -n $redeemScript | xxd -r -p | openssl dgst -sha256 -binary | openssl dgst -rmd160
|
||||
(stdin)= 3f58b4f7b14847a9083694b9b3b52a4cea2569ed
|
||||
```
|
||||
|
||||
## Criando uma Transação
|
||||
|
||||
A fim de fazer uso do `pubScriptKey` que acabamos de criar, precisamos criar uma transação e incorporar o `pubScriptKey` dentro dela (e esta é a grande mudança do `bitcoin-cli`: podemos criar manualmente uma transação com um script P2SH).
|
||||
|
||||
O processo de criação de uma transação na Libwally é muito intenso, assim como o processo de criação de um PSBT, portanto, vamos apenas esboçá-lo, pegando um atalho e, em seguida, deixando um método sem atalhos para investigação futura.
|
||||
|
||||
Criar uma transação em si é fácil, só precisamos dizer ao comando `wally_tx_init_alloc` nosso número de versão, o tempo de bloqueio e o número de entradas e saídas:
|
||||
```
|
||||
struct wally_tx *tx;
|
||||
lw_response = wally_tx_init_alloc(2,0,1,1,&tx);
|
||||
```
|
||||
Preencher essas entradas e saídas é onde as coisas ficam complicadas!
|
||||
|
||||
### Criando uma Saída de Transação
|
||||
|
||||
Para criar uma saída, dizemos a `wally_tx_output_init_alloc` quantos satoshis estamos gastando, além de entregar o script de bloqueio:
|
||||
```
|
||||
struct wally_tx_output *tx_output;
|
||||
lw_response = wally_tx_output_init_alloc(95000,p2sh,sizeof(p2sh),&tx_output);
|
||||
```
|
||||
Essa parte não foi nem um pouco difícil e nos permitiu que finalmente incorporássemos um P2SH em um `vout`.
|
||||
|
||||
Mais um comando o adiciona à nossa transação:
|
||||
```
|
||||
lw_response = wally_tx_add_output(tx,tx_output);
|
||||
```
|
||||
|
||||
### Criando uma Entrada de Transação
|
||||
|
||||
Criar a entrada é muito mais difícil porque temos que empilhar informações nas rotinas de criação, nem todas as quais são intuitivamente acessíveis quando usamos a Libwally. Então, ao invés de mergulharmos fundo nessa biblioteca, é neste momento que pegamos nosso atalho. Escrevemos o código de forma que seja passado o código hexadecimal para uma transação que já foi criada e, em seguida, apenas reutilizamos a entrada.
|
||||
|
||||
A conversão do código hexadecimal é feita com `wally_tx_from_hex`:
|
||||
```
|
||||
struct wally_tx *utxo;
|
||||
lw_response = wally_tx_from_hex(utxo_hex,0,&utxo);
|
||||
```
|
||||
Então podemos roubar as entradas de nosso código hexadecimal para criar uma entrada com a Libwally:
|
||||
```
|
||||
struct wally_tx_input *tx_input;
|
||||
lw_response = wally_tx_input_init_alloc(utxo->inputs[0].txhash,sizeof(utxo->inputs[0].txhash),utxo->inputs[0].index,0,utxo->inputs[0].script,utxo->inputs[0].script_len,utxo->inputs[0].witness,&tx_input);
|
||||
assert(lw_response == WALLY_OK);
|
||||
```
|
||||
Como seria de se esperar, adicionamos essa entrada à nossa transação:
|
||||
```
|
||||
lw_response = wally_tx_add_input(tx,tx_input);
|
||||
```
|
||||
|
||||
> **NOTA:** Obviamente, iremos querer criar nossas próprias entradas se estivermos usando Libwally para aplicações reais, mas isso é uma primeira etapa. E, na verdade, pode ser útil para integração com o `bitcoin-cli`, como veremos na seção [§17.7](17_7_Integrating_Libwally_and_Bitcoin-CLI.md).
|
||||
|
||||
### Vendo uma Transação
|
||||
|
||||
Teoricamente, poderíamos assinar e enviar esta transação para nosso programa C construído na Libwally, mas mantendo a ideia de que estamos apenas usando um programa C simples para substituir um P2SH, vamos imprimir o novo hex. Isto é feito com a ajuda de `wally_tx_to_hex`:
|
||||
```
|
||||
char *tx_hex;
|
||||
lw_response = wally_tx_to_hex(tx,0, &tx_hex);
|
||||
|
||||
printf("%s\n",tx_hex);
|
||||
```
|
||||
Mostraremos como fazer uso disso na seção §17.7.
|
||||
|
||||
## Testando Nosso Script de Substituição
|
||||
|
||||
Podemos pegar o código de teste do [diretório src/](src/17_5_replacewithscript.c) e compilá-lo:
|
||||
```
|
||||
$ cc replacewithscript.c -lwallycore -o replacewithscript
|
||||
```
|
||||
Depois, preparamos uma transação hexadecimal e um script hexadecimal serializado:
|
||||
```
|
||||
hex=020000000001019527cebb072524a7961b1ba1e58fc18dd7c6fc58cd6c1c45d7e1d8fc690b006e0000000017160014cc6e8522f0287b87b7d0a83629049c2f2b0e972dfeffffff026f8460000000000017a914ba421212a629a840492acb2324b497ab95da7d1e87306f0100000000001976a914a2a68c5f9b8e25fdd1213c38d952ab2be2e271be88ac02463043021f757054fa61cfb75b64b17230b041b6d73f25ff9c018457cf95c9490d173fb4022075970f786f24502290e8a5ed0f0a85a9a6776d3730287935fb23aa817791c01701210293fef93f52e6ce8be581db62229baf116714fcb24419042ffccc762acc958294e6921b00
|
||||
|
||||
script=93016387
|
||||
```
|
||||
Podemos então executar o programa de substituição:
|
||||
```
|
||||
$ ./replacewithscript $hex $script
|
||||
02000000019527cebb072524a7961b1ba1e58fc18dd7c6fc58cd6c1c45d7e1d8fc690b006e0000000017160014cc6e8522f0287b87b7d0a83629049c2f2b0e972d0000000001187301000000000017a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed8700000000
|
||||
```
|
||||
Podemos ver os resultados com o `bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $newhex
|
||||
{
|
||||
"txid": "f4e7dbab45e759a7ac6e2fb0f10720cd29d047efad89fe1b569f5f4ba61fd8e6",
|
||||
"hash": "f4e7dbab45e759a7ac6e2fb0f10720cd29d047efad89fe1b569f5f4ba61fd8e6",
|
||||
"version": 2,
|
||||
"size": 106,
|
||||
"vsize": 106,
|
||||
"weight": 424,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "6e000b69fcd8e1d7451c6ccd58fcc6d78dc18fe5a11b1b96a7242507bbce2795",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "0014cc6e8522f0287b87b7d0a83629049c2f2b0e972d",
|
||||
"hex": "160014cc6e8522f0287b87b7d0a83629049c2f2b0e972d"
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00095000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
O `vin` deve apenas corresponder à entrada que substituímos, mas é o `vout` que é empolgante. Criamos uma transação com um `scripthash`!
|
||||
|
||||
## Resumo: Usando Scripts na Libwally
|
||||
|
||||
A criação de transações na Libwally é outro tópico que pode ocupar um capítulo inteiro, mas o melhor é que uma vez que demos esse salto, podemos introduzir um P2SH `scriptPubKey`, e só essa parte é muito fácil. Embora a metodologia detalhada neste capítulo exija que já tenhamos um hex de transação em mãos (provavelmente criado com o `bitcoin-cli`), se nos aprofundarmos na Libwally, podemos fazer tudo sozinhos.
|
||||
|
||||
> :fire: ***Qual é o poder dos scripts na Libwally?*** De maneira bem simples, podemos fazer algo que não podíamos antes. Criar uma transação bloqueada com um P2SH arbitrário.
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando Bitcoin com Libwally" na seção [§17.6: Usando Outras Funções na Libwally](17_6_Using_Other_Functions_in_Libwally.md).
|
125
pt/17_6_Using_Other_Functions_in_Libwally.md
Normal file
125
pt/17_6_Using_Other_Functions_in_Libwally.md
Normal file
@ -0,0 +1,125 @@
|
||||
# 17.6: Usando Outras Funções na Libwally
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
A Libwally é uma biblioteca extensa que fornece uma quantidade considerável de funcionalidades relacionadas a carteiras, muitas delas não disponíveis por meio do `bitcoin-cli`. A seguir, está uma visão geral de algumas funcionalidades não abordadas anteriormente neste capítulo.
|
||||
|
||||
## Usando Funções Criptográficas
|
||||
|
||||
Diversas funções criptográficas podem ser acessadas diretamente na Libwally:
|
||||
|
||||
* `wally_aes` - Usa criptografia ou descriptografia AES;
|
||||
* `wally_aes_cbc` - Usa criptografia ou descriptografia AES no modo CBC;
|
||||
* `wally_hash160` - Usa hash RIPEMD-160 (SHA-256);
|
||||
* `wally_scrypt` - Usa derivação de chave Scrypt;
|
||||
* `wally_sha256` - Usa hash SHA256;
|
||||
* `wally_sha256_midstate` - Usa SHA256 para fazer hash apenas do primeiro bloco de dados;
|
||||
* `wally_sha256d` - Conduz um hash duplo SHA256;
|
||||
* `wally_sha512` - Usa hash SHA512.
|
||||
|
||||
Existem também funções HMAC para os dois hashes SHA, que são usados para gerar códigos de autenticação de mensagem com base nos hashes. Eles são usados no [BIP32](https://en.bitcoin.it/wiki/BIP_0032), entre outros lugares.
|
||||
|
||||
* `wally_hmac_sha256`
|
||||
* `wally_hmac_sha512`
|
||||
|
||||
Funções adicionais cobrem derivação de chave PBKDF2 e matemática de curva elíptica.
|
||||
|
||||
## Usando Funções de Endereço
|
||||
|
||||
A Libwally contém várias funções que podem ser usadas para importar, exportar e traduzir endereços de Bitcoin.
|
||||
|
||||
Alguns convertem entre endereços e bytes `scriptPubKey`:
|
||||
|
||||
* `wally_addr_segwit_from_bytes` - Converte um programa witness (em bytes) em um endereço Segwit;
|
||||
* `wally_addr_segwit_to_bytes` - Converte um endereço Segwit em um `scriptPubKey` (em bytes);
|
||||
* `wally_address_to_scriptpubkey` - Converte um endereço legado em um `scriptPubKey` (em bytes);
|
||||
* `wally_scriptpubkey_to_address` - Converte um `scriptPubKey` (em bytes) em um endereço legado.
|
||||
|
||||
Alguns estão relacionados ao formato de importação de carteira (WIF):
|
||||
|
||||
* `wally_wif_from_bytes` - Converte uma chave privada (em bytes) para um WIF;
|
||||
* `wally_wif_is_uncompressed` - Determina se um WIF está descompactado;
|
||||
* `wally_wif_to_address` - Deriva um endereço P2PKH de um WIF;
|
||||
* `wally_wif_to_bytes` - Converte um WIF em uma chave privada (em bytes);
|
||||
* `wally_wif_to_public_key` - Deriva uma chave pública (em bytes) de um WIF.
|
||||
|
||||
## Usando Funções do BIP32
|
||||
|
||||
Existem funções adicionais de carteira HD do BIP32, além do que foi abordado na seção [§17.3: Usando o BIP32 na Libwally](17_3_Using_BIP32_in_Libwally.md).
|
||||
|
||||
* `bip32_key_get_fingerprint` - Gera uma impressão digital BIP32 para uma chave estendida;
|
||||
* `bip32_key_serialize` - Transforma uma chave estendida em bytes serializados;
|
||||
* `bip32_key_strip_private_key` - Converte uma chave privada estendida em uma chave pública estendida;
|
||||
* `bip32_key_unserialize` - Transforma bytes serializados em uma chave estendida.
|
||||
|
||||
Existem também vários outros comandos, dependendo se desejamos alocar memória ou fazer com que a Libwally faça o `_alloc` para nós.
|
||||
|
||||
## Usando Funções do BIP38
|
||||
|
||||
O [BIP38](https://github.com/bitcoin/bips/blob/master/bip-0038.mediawiki) permite a criação de uma chave privada protegida por senha. Não o ensinamos porque consideramos perigoso inserir este tipo de fator humano no gerenciamento de chaves. Se duvida disso, consulte [#SmartCustody](https://www.smartcustody.com/index.html).
|
||||
|
||||
As principais funções são:
|
||||
|
||||
* `bip38_from_private_key` - Codifica uma chave privada usando BIP38;
|
||||
* `bip38_to_private_key` - Decodifica uma chave privada usando BIP38.
|
||||
|
||||
## Usando Funções do BIP39
|
||||
|
||||
Algumas funções de palavras mnemônicas do BIP39 foram resumidas recentemente na seção [§17.2: Usando o BIP39 na Libwally](17_2_Using_BIP39_in_Libwally.md):
|
||||
|
||||
* `bip39_get_languages` - Veja a lista de idiomas suportados;
|
||||
* `bit39_get_word` - Recupera uma palavra específica da lista de palavras de um idioma;
|
||||
* `bip39_get_wordlist` - Veja uma lista de palavras para um idioma.
|
||||
|
||||
## Usando Funções de PSBT
|
||||
|
||||
As listas da maioria das funções de PSBT podem ser encontradas na seção [17.4: Usando PSBTs na Libwally](17_4_Using_PSBTs_in_Libwally.md).
|
||||
|
||||
## Usando Funções de Script
|
||||
|
||||
A seção [§17.5: Usando Scripts na Libwally](17_5_Using_Scripts_in_Libwally.md) apenas tocou nas funções de scripts da Libwally.
|
||||
|
||||
Há outra função que permite determinar o tipo de script encontrado em uma transação:
|
||||
|
||||
* `wally_scriptpubkey_get_type` - Determina o tipo de script de uma transação.
|
||||
|
||||
Depois, há uma série de funções que criam `scriptPubKey` a partir de bytes, `scriptSig` a partir de assinaturas e Witness a partir de bytes ou assinaturas.
|
||||
|
||||
* `wally_script_push_from_bytes`
|
||||
* `wally_scriptpubkey_csv_2of2_then_1_from_bytes`
|
||||
* `wally_scriptpubkey_csv_2of3_then_2_from_bytes`
|
||||
* `wally_scriptpubkey_multisig_from_bytes`
|
||||
* `wally_scriptpubkey_op_return_from_bytes`
|
||||
* `wally_scriptpubkey_p2pkh_from_bytes`
|
||||
* `wally_scriptpubkey_p2sh_from_bytes`
|
||||
* `wally_scriptsig_multisig_from_bytes`
|
||||
* `wally_scriptsig_p2pkh_from_der`
|
||||
* `wally_scriptsig_p2pkh_from_sig`
|
||||
* `wally_witness_multisig_from_bytes`
|
||||
* `wally_witness_p2wpkh_from_der`
|
||||
* `wally_witness_p2wpkh_from_sig`
|
||||
* `wally_witness_program_from_bytes`
|
||||
|
||||
## Usando Funções de Transação
|
||||
|
||||
Também mal tocamos nas funções que podem ser usadas para criar e converter funções na seção [§17.5](17_5_Using_Scripts_in_Libwally.md).
|
||||
|
||||
Existem inúmeras funções informativas, algumas das mais interessantes são:
|
||||
|
||||
* `wally_tx_get_length`
|
||||
* `wally_tx_get_total_output_satoshi`
|
||||
* `wally_tx_get_weight`
|
||||
|
||||
Também existem funções que afetam um `wally_tx`, um `wally_tx_input`, um `wally_tx_output`, ou um `wally_tx_witness_stack` e que criam assinaturas.
|
||||
|
||||
## Usando Funções do Elements
|
||||
|
||||
A Libwally pode ser compilada para ser usada com os Elements da Blockstream, que inclui acesso às funções dos ativos.
|
||||
|
||||
## Resumo: Usando Outras Funções na Libwally
|
||||
|
||||
Há muito mais coisas que podemos fazer com a Libwally, mais do que podemos abordar neste capítulo ou mesmo listar nesta seção. Notavelmente, podemos executar funções criptográficas, codificar chaves privadas, criar transações completas e usar Elements. A [documentação da Libwally](https://wally.readthedocs.io/en/latest/) é o lugar onde podemos obter mais informações, embora, no momento da criação deste livro, a documentação esteja limitada e desatualizada. Os cabeçalhos dos arquivos da Libwally são um backup se os documentos estiverem incompletos ou incorretos.
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Vamos aprender mais sobre "Programando Bitcoin com Libwally" na seção [§17.7: Integrando Libwally e Bitcoin-CLI](17_7_Integrating_Libwally_and_Bitcoin-CLI.md).
|
330
pt/17_7_Integrating_Libwally_and_Bitcoin-CLI.md
Normal file
330
pt/17_7_Integrating_Libwally_and_Bitcoin-CLI.md
Normal file
@ -0,0 +1,330 @@
|
||||
# 17.7: Integranda Libwally e Bitcoin-CLI
|
||||
|
||||
> :information_source: **NOTA:** Esta seção foi adicionada recentemente ao curso e é um rascunho inicial que ainda pode estar aguardando revisão.
|
||||
|
||||
A Libwally é limitada. Trata-se de manipular seeds, chaves, endereços e outros elementos de carteiras, com algumas funções adicionais relacionadas a transações e PSBTs que podem ser úteis para serviços que não estão conectados a nodes completos na Internet. No final das contas, no entanto, precisaremos de serviços de nodes completos para aproveitar as vantagens da Libwally.
|
||||
|
||||
Esta última seção oferecerá alguns exemplos de uso de programas Libwally para complementar um ambiente `bitcoin-cli`. Embora esses exemplos impliquem que esses serviços estão todos na mesma máquina, eles podem se tornar ainda mais poderosos se o serviço `bitcoin-cli` estiver diretamente conectado à internet e o serviça Libwally não.
|
||||
|
||||
## Compartilhando uma Transação
|
||||
|
||||
Na seção [§17.5: Usando Scripts na Libwally](17_5_Using_Scripts_in_Libwally.md) detalhamos como a Libwally poderia ser usada para reescrever uma transação existente, para fazer algo que o `bitcoin-cli` não pode, ou seja, produzir uma transação que contém um P2SH único. Obviamente, esta é uma parte essencial, mas não o todo; se você decidir se aprofundar na Libwally, poderá criar transações inteiras por conta própria. Mas esta metodologia abreviada também tem seu próprio uso, mostrar como as transações podem ser passadas de um lado para outro entre `bitcoin-cli` e Libwally, demonstrando um primeiro exemplo de como usá-los de forma complementar.
|
||||
|
||||
Para demonstrar totalmente essa metodologia, criaremos uma transação com o `bitcoin-cli`, usando este UTXO:
|
||||
```
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"address": "mvLyH7Rs45c16FG2dfV7uuTKV6pL92kWxo",
|
||||
"label": "",
|
||||
"scriptPubKey": "76a914a2a68c5f9b8e25fdd1213c38d952ab2be2e271be88ac",
|
||||
"amount": 0.00094000,
|
||||
"confirmations": 17375,
|
||||
"spendable": true,
|
||||
"solvable": true,
|
||||
"desc": "pkh([ce0c7e14/0'/0'/5']0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65)#qldtsl65",
|
||||
"safe": true
|
||||
}
|
||||
```
|
||||
Agora, já sabemos como configurar uma transação com o `bitcoin-cli`:
|
||||
```
|
||||
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||
$ recipient=tb1qycsmq3jas5wkhf8xrfn8k7438cm5pc8h9ae2k0
|
||||
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.0009 }''')
|
||||
```
|
||||
Embora tenhamos colocado um destinatário e uma quantia na saída, isto é irrelevante, porque nós o reescreveremos. Um código mais elaborado poderia ler as informações `vout` existentes antes de reescrever, mas estamos mantendo as coisas muito próximas do nosso [código original](src/17_5_replacewithscript.c).
|
||||
|
||||
Aqui está a única alteração necessária, para permitir que especifiquemos os satoshis no `vout`, sem ter que codificá-lo, como no original:
|
||||
```
|
||||
...
|
||||
int satoshis = atoi(argv[3]);
|
||||
...
|
||||
lw_response = wally_tx_output_init_alloc(satoshis,p2sh,sizeof(p2sh),&tx_output);
|
||||
...
|
||||
```
|
||||
Então executamos as coisas como antes:
|
||||
```
|
||||
$ newtxhex=$(./replacewithscript $rawtxhex $script 9000)
|
||||
```
|
||||
Esta é a aparência da transação original:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
{
|
||||
"txid": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
|
||||
"hash": "438d50edd7abeaf656c5abe856a00a20af5ff08939df8fdb9f8bfbfb96234fcb",
|
||||
"version": 2,
|
||||
"size": 82,
|
||||
"vsize": 82,
|
||||
"weight": 328,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "0 2621b0465d851d6ba4e61a667b7ab13e3740e0f7",
|
||||
"hex": "00142621b0465d851d6ba4e61a667b7ab13e3740e0f7",
|
||||
"reqSigs": 1,
|
||||
"type": "witness_v0_keyhash",
|
||||
"addresses": [
|
||||
"tb1qycsmq3jas5wkhf8xrfn8k7438cm5pc8h9ae2k0"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
E aqui está a transação reescrita pela Libwally para usar em um P2SH:
|
||||
```
|
||||
standup@btctest:~/c$ bitcoin-cli decoderawtransaction $newtxhex
|
||||
{
|
||||
"txid": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
|
||||
"hash": "badb57622ab5fe029fc1a71ace9f7b76c695f933bceb0d38a155c2e5c984f4e9",
|
||||
"version": 2,
|
||||
"size": 83,
|
||||
"vsize": 83,
|
||||
"weight": 332,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Depois, podemos assiná-la normalmente com o `bitcoin-cli`:
|
||||
```
|
||||
$ signedtx=$(bitcoin-cli signrawtransactionwithwallet $newtxhex | jq -r '.hex')
|
||||
```
|
||||
E, como podemos ver, o resultado é uma transação legítima pronta para ir para a rede Bitcoin:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $signedtx
|
||||
{
|
||||
"txid": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
|
||||
"hash": "3061ca8c01d029c0086adbf8b7d4280280c8aee151500bab7c4f783bbc8e75e6",
|
||||
"version": 2,
|
||||
"size": 189,
|
||||
"vsize": 189,
|
||||
"weight": 756,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
{
|
||||
"txid": "c0a110a7a84399b98052c6545018873b13ee3128fa74f7a697779174a36ea33a",
|
||||
"vout": 1,
|
||||
"scriptSig": {
|
||||
"asm": "3044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe0[ALL] 0368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65",
|
||||
"hex": "473044022026c81b6ff4a15135d10c7f4b1ae6e44ac4fdb25c4a3c03161b17b8ab8d04850502200b448d070f418de1ca07e76943d23d447bc95c7c5e0322bcc153cadb5d9befe001210368d0fffa651783524f8b934d24d03b32bf8ff2c0808943a556b3d74b2e5c7d65"
|
||||
},
|
||||
"sequence": 0
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.00090000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_HASH160 3f58b4f7b14847a9083694b9b3b52a4cea2569ed OP_EQUAL",
|
||||
"hex": "a9143f58b4f7b14847a9083694b9b3b52a4cea2569ed87",
|
||||
"reqSigs": 1,
|
||||
"type": "scripthash",
|
||||
"addresses": [
|
||||
"2My2ApqGcoNXYceZC4d7fipBu4GodkbefHD"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Pronto! Esse é o poder da Libwally com o `bitcoin-cli`.
|
||||
|
||||
Obviamente, também podemos passar um PSBT usando as funções descritas na seção [§17.4](17_4_Using_PSBTs_in_Libwally.md) e esta é uma metodologia mais atualizada para o uso moderno do Bitcoin; mas em qualquer um dos exemplos, o conceito de passar transações do `bitcoin-cli` para códiga Libwally e vice-versa deve ser semelhante.
|
||||
|
||||
## Importando e Exportando Seeds BIP39
|
||||
|
||||
Infelizmente, nem todas as interações entre a Libwally e o `bitcoin-cli` são fáceis. Por exemplo, seria bom se pudéssemos exportar uma seed HD do `bitcoin-cli` para gerar a frase mnemônica com a Libwally, ou gerar uma seed de uma frase mnemônica usando a Libwally e depois importá-la para o `bitcoin-cli `. Infelizmente, nada disso é possível neste momento. Uma frase mneômica é traduzida em uma seed usando HMAC-SHA512, o que significa que o resultado é 512 bits. No entanto, o `bitcoin-cli` exporta seeds HD (usando `dumpwallet`) e importa seeds HD (usando `sethdseed`) com um comprimento de 256 bits. Até que isso seja mudado, não há nada que possamos fazer.
|
||||
|
||||
> :book: ***Qual é a diferença entre entropia e uma seed?*** A Libwally diz que criamos nossas frases mnemônicas a partir de entropia. Isso é essencialmente a mesma coisa que uma seed, pois ambos são números grandes e aleatórios. Portanto, se o `bitcoin-cli` fosse compatível com as seeds de frase mnemônica de 512 bits, poderíamos usar uma para gerar as frases mnemônicas e obter os resultados esperados.
|
||||
|
||||
> :book: ***Qual é a diferença entre entropia e entropia bruta?*** Nem toda entropia é a mesma. Quando inserimos entropia em um comando que cria uma seed mnemônica, ela tem um comprimento específico e bem conhecido. Mudar de entropia bruta para entropia requer alterar a entropia bruta até que se tenha o comprimento e o formato corretos, e nesse ponto podemos reutilizar essa entropia (não bruta) para sempre recriar os mesmos mnemônicos (razão pela qual a entropia é efetivamente a mesma coisa que uma seed naquele ponto, mas a entropia bruta não).
|
||||
|
||||
## Importando Chaves Privadas
|
||||
|
||||
Felizmente, podemos fazer quase a mesma coisa importando uma chave privada gerada na Libwally. Dê uma olhada no [genhd-for-import.c](src/17_7_genhd_for_import.c), uma versão simplificada do programa `genhd` da seção [§17.3](17_3_Using_BIP32_in_Libwally.md) que também usa a biblioteca `jansson` da seção [§16.1](16_1_Accessing_Bitcoind_with_C.md) para saída regularizada.
|
||||
|
||||
O código atualizado também contém uma alteração importante, pois ele solicita uma impressão digital da Libwally para que se possa criar um caminho de derivação de maneira adequada:
|
||||
```
|
||||
char account_fingerprint[BIP32_KEY_FINGERPRINT_LEN];
|
||||
lw_response = bip32_key_get_fingerprint(key_account,account_fingerprint,BIP32_KEY_FINGERPRINT_LEN);
|
||||
|
||||
char *fp_hex;
|
||||
lw_response = wally_hex_from_bytes(account_fingerprint,BIP32_KEY_FINGERPRINT_LEN,&fp_hex);
|
||||
```
|
||||
|
||||
> :aviso: **AVISO:** Lembre-se de que a impressão digital nos caminhos de derivação é arbitrária. Como a Libwally fornece um, nós o estamos usando, mas se não tivéssemos um, poderíamos adicionar um código hexadecimal arbitrário de 4 bytes como uma impressão digital em nosso caminho de derivação.
|
||||
|
||||
Certifique-se de compilar o novo código com a biblioteca `jansson`, após instalá-lo (se necessário) de acordo com a seção [§16.1](16_1_Accessing_Bitcoind_with_C.md).
|
||||
```
|
||||
$ cc genhd-for-import.c -lwallycore -lsodium -ljansson -o genhd-for-import
|
||||
```
|
||||
Quando executarmos o novo programa, ele nos dará uma lista de saída com todas as informações:
|
||||
```
|
||||
$ ./genhd-for-import
|
||||
{
|
||||
"mnemonic": "physical renew say quit enjoy eager topic remind riot concert refuse chair",
|
||||
"account-xprv": "tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn",
|
||||
"address": "tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n",
|
||||
"derivation": "[d1280779/84h/1h/0h]"
|
||||
}
|
||||
```
|
||||
Temos o `mnemonic` que podemos recuperar, um `account-xprv` que podemos importar, uma `derivation` para usar para a importação e um `address` de amostra, que podemos usar para testar a importação.
|
||||
|
||||
Agora podemos recorrer às lições aprendidas na seção [§3.5](03_5_Understanding_the_Descriptor.md) sobre como transformar esse xprv em um descritor e importá-lo.
|
||||
|
||||
Primeiro, precisamos descobrir o checksum:
|
||||
```
|
||||
$ xprv=tprv8yxn8iFNgsLktEPkWKQpMqb7bcx5ViFQEbJMtqrGi8LEgvy8es6YeJvyJKrbYEPKMw8JbU3RFhNRQ4F2pataAtTNokS1JXBZVg62xfd5HCn
|
||||
$ dp=[d1280779/84h/1h/0h]
|
||||
$ bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)"
|
||||
{
|
||||
"descriptor": "wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHFv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z",
|
||||
"checksum": "46c00dk5",
|
||||
"isrange": true,
|
||||
"issolvable": true,
|
||||
"hasprivatekeys": true
|
||||
}
|
||||
```
|
||||
|
||||
Há três coisas a serem observadas aqui:
|
||||
|
||||
1. Usamos o `wpkh` como a função em nosso caminho de derivação. Isso porque queremos gerar endereços Segwit modernos, não endereços legados. Isso corresponde ao uso na Libwally da função `wally_bip32_key_to_addr_segwit`. A coisa mais importante, entretanto, é ter as mesmas expectativas com a Libwally e o `bitcoin-cli` (e nosso descritor) de que tipo de endereço estamos gerando, para que tudo dê certo;
|
||||
2. Usamos o caminho `/0/*` porque queríamos os endereços externos para esta conta. Se, em vez disso, quiséssemos alterar os endereços, usaríamos `/1/*`;
|
||||
3. Não vamos usar a linha `descriptor` que foi retornada, pois é para um endereço `xpub`. Ao invés disso, aplicaremos o `checksum` retornado ao `xprv` que já temos.
|
||||
```
|
||||
$ cs=$(bitcoin-cli getdescriptorinfo "wpkh($dp$xprv/0/*)" | jq -r ' .checksum')
|
||||
```
|
||||
Então conectamos isso em um `importmulti` para importar esta chave no `bitcoin-cli`:
|
||||
```
|
||||
$ bitcoin-cli importmulti '''[{ "desc": "wpkh('$dp''$xprv'/0/*)#'$cs'", "timestamp": "now", "range": 10, "watchonly": false, "label": "LibwallyImports", "keypool": false, "rescan": false }]'''
|
||||
[
|
||||
{
|
||||
"success": true
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
Aqui, importamos/geramos os primeiros dez endereços para a chave privada.
|
||||
|
||||
Vamos examinar o novo rótulo `LibwallyImports`:
|
||||
```
|
||||
$ bitcoin-cli getaddressesbylabel "LibwallyImports"
|
||||
{
|
||||
"tb1qzeqrrt77xhvazq5g8sc9th0lzjwstknan8gzq7": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q8fsgxt0z9r9hfl5mst5ylxka2yljjxlxlvaf8j": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qg6dayhdk4qc6guutxvdweh6pctc9dpguu6awqc": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qdphaj0exvemxhgfpyh4p99wn84e2533u7p96l6": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qwv9mdqkpx6trtmvgw3l95npq8gk9pgllucvata": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qwh92pkrv6sps62udnmez65vfxe9n5ceuya56xz": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q4e98ln8xlym64qjzy3k8zyfyt5q60dgcn39d90": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qhzje887fyl65j4mulqv9ysmntwn95zpgmgvtqd": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1q62xf9ec8zcfkh2qy5qnq4qcxrx8l0jm27dd8ru": {
|
||||
"purpose": "receive"
|
||||
},
|
||||
"tb1qlw85usfk446ssxejm9dmxsfn40kzsqce77aq20": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
O segundo em nossa lista realmente corresponde ao que temos de amostra (`tb1q9lhru6k0ymwrtr5w98w35n3lz22upml23h753n`). A importação desta chave privada e a derivação de dez endereços foram bem-sucedidas.
|
||||
|
||||
Se olharmos agora para trás na seção [§7.3](07_3_Integrating_with_Hardware_Wallets.md), veremos que esta era a mesma metodologia que usamos para importar endereços de uma hardware wallet (embora desta vez também importamos a chave privada como prova de conceito). A maior diferença é que anteriormente a informação era criada por uma caixa preta (literalmente: era um dispositivo Ledger), e desta vez nós mesmos criamos a informação usando a Libwally, mostrando como podemos fazer esse tipo de trabalho de maneira airgaped ou em outro dispositivo remoto e, em seguida, levá-lo ao `bitcoin-cli`.
|
||||
|
||||
## Importando Endereços
|
||||
|
||||
Obviamente, se podemos importar chaves privadas, também podemos importar endereços, o que geralmente significa importar endereços somente para observação _sem_ as chaves privadas.
|
||||
|
||||
Uma maneira de fazer isso é utilizar a metodologia `importmulti` acima, mas neste caso, usamos o endereço xpub fornecido (`wpkh([d1280779/84'/1'/0']tpubDWepH8HcqF2RmhRYPy5QmFFEAeU1f3SJotu9BMta8Q8dXRDuHFv8poYqUUtEiWftBjtKn1aNhi9Qg2P4NdzF66dShYvB92z78WJbYeHTLTz/0/*)#f8rmqc0z`) ao invés do xprv original. Essa é a melhor maneira de importar uma sequência inteira de endereços somente para observação.
|
||||
|
||||
Como alternativa, podemos importar endereços individuais. Por exemplo, considere o único endereço de amostra retornado pelo programa `genhd-for-import`:
|
||||
```
|
||||
$ ./genhd-for-import
|
||||
{
|
||||
"mnemonic": "finish lady crucial walk illegal ride hamster strategy desert file twin nature",
|
||||
"account-xprv": "tprv8xRujYeVN7CwBHxLoTHRdmzwdW7dKUzDfruSo56GqqfRW9QXtnxnaRG8ke7j65uNjxmCVfcagz5uuaMi2vVJ8jpiGZvLwahmNB8F3SHUSyv",
|
||||
"address": "tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d",
|
||||
"derivation": "[6214ecff/84h/1h/0h]"
|
||||
}
|
||||
```
|
||||
Podemos importá-lo como um endereço de observação com `importaddress`:
|
||||
```
|
||||
$ bitcoin-cli -named importaddress address=tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d label=LibwallyWO rescan=false
|
||||
$ bitcoin-cli getaddressesbylabel "LibwallyWO"
|
||||
{
|
||||
"tb1qtvcchgyklp6cyleth85c7pfr4j72z2vyuwuj3d": {
|
||||
"purpose": "receive"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Resumo: Integrando Libwally e Bitcoin-CLI
|
||||
|
||||
Com um conhecimento básico de Libwally, agora podemos complementar todo o trabalho das lições anteriores. A transferência de endereços, chaves, transações e PSBTs são apenas algumas das maneiras pelas quais podemos usar esses dois poderosos métodos de programação do Bitcoin juntos. Também há muito mais profundidade potencial se quisermos nos aprofundar na extensa biblioteca de funções da Libwally.
|
||||
|
||||
> :fire: ***Qual é o poder de integrar Libwally e Bitcoin-CLI?*** Uma das maiores vantagens da Libwally é que ela tem muitas funções que podem ser usadas offline. Em comparação, o Bitcoin Core é um programa em rede. Isso pode ajudá-lo a aumentar a segurança fazendo com que o `bitcoin-cli` passe chaves, endereços, transações ou PSBTs para uma fonte offline (que estaria executando programas Libwally). Além disso, a Libwally pode fazer coisas que o Bitcoin Core não pode, como gerar uma seed a partir de um mnemônico BIP39 (e mesmo se não pudermos importá-la para o Bitcoin Core, _podemos_ importar a chave mestra, conforme mostrado aqui).
|
||||
|
||||
## O Que Vem Depois?
|
||||
|
||||
Saiba mais sobre outras linguagens de programação no [Capítulo 18: Conversando com o Bitcoind com Outras Linguagens](18_0_Talking_to_Bitcoind_Other.md).
|
59
pt/README.md
59
pt/README.md
@ -101,44 +101,47 @@ Se você gostaria de fazer a sua própria tradução, por favor veja [Contribuin
|
||||
* [14.2: Mudando Seus Serviços Ocultos do Bitcoin](14_2_Changing_Your_Bitcoin_Hidden_Services.md)
|
||||
* [14.3: Adicionando SSH aos Seus Serviços Ocultos](14_3_Adding_SSH_Hidden_Services.md)
|
||||
|
||||
* [15.0: Usando i2p](15_0_Using_i2p.md)
|
||||
* [15.1: Bitcoin Core como um Serviço I2P (Invisible Internet Project)](15_1_i2p_service.md)
|
||||
|
||||
### PARTE CINCO: PROGRAMANDO COM RPC
|
||||
|
||||
**Estado:** Finalizado.
|
||||
|
||||
* [15.0: Conversando com o Bitcoind com C](15_0_Talking_to_Bitcoind.md)
|
||||
* [15.1: Acessando o Bitcoind em C com Livrarias RPC](15_1_Accessing_Bitcoind_with_C.md)
|
||||
* [15.2: Programando o Bitcoind em C com Livrarias RPC](15_2_Programming_Bitcoind_with_C.md)
|
||||
* [15.3: Recebendo Notificações em C com Livrarias ZMQ](15_3_Receiving_Bitcoind_Notifications_with_C.md)
|
||||
* [16.0: Programando Bitcoin com Libwally](16_0_Programming_with_Libwally.md)
|
||||
* [16.1: Configurando a Libwally](16_1_Setting_Up_Libwally.md)
|
||||
* [16.2: Usando BIP39 na Libwally](16_2_Using_BIP39_in_Libwally.md)
|
||||
* [16.3: Usando BIP32 na Libwally](16_3_Using_BIP32_in_Libwally.md)
|
||||
* [16.4: Usando PSBTs na Libwally](16_4_Using_PSBTs_in_Libwally.md)
|
||||
* [16.5: Usando Scripts na Libwally](16_5_Using_Scripts_in_Libwally.md)
|
||||
* [16.6: Usando Outras Funções na Libwally](16_6_Using_Other_Functions_in_Libwally.md)
|
||||
* [16.7: Integrando Libwally e Bitcoin-CLI](16_7_Integrating_Libwally_and_Bitcoin-CLI.md)
|
||||
* [17.0: Conversando com o Bitcoind com Outras Linguagens](17_0_Talking_to_Bitcoind_Other.md)
|
||||
* [17.1: Acessando o Bitcoind com Go](17_1_Accessing_Bitcoind_with_Go.md)
|
||||
* [17.2: Acessando o Bitcoind com Java](17_2_Accessing_Bitcoind_with_Java.md)
|
||||
* [17.3: Acessando o Bitcoind com Node JS](17_3_Accessing_Bitcoind_with_NodeJS.md)
|
||||
* [17.4: Acessando o Bitcoind com Python](17_4_Accessing_Bitcoind_with_Python.md)
|
||||
* [17.5: Acessando o Bitcoind com Rust](17_5_Accessing_Bitcoind_with_Rust.md)
|
||||
* [17.6: Acessando o Bitcoind com Swift](17_6_Accessing_Bitcoind_with_Swift.md)
|
||||
* [16.0: Conversando com o Bitcoind com C](15_0_Talking_to_Bitcoind.md)
|
||||
* [16.1: Acessando o Bitcoind em C com Livrarias RPC](15_1_Accessing_Bitcoind_with_C.md)
|
||||
* [16.2: Programando o Bitcoind em C com Livrarias RPC](15_2_Programming_Bitcoind_with_C.md)
|
||||
* [16.3: Recebendo Notificações em C com Livrarias ZMQ](15_3_Receiving_Bitcoind_Notifications_with_C.md)
|
||||
* [17.0: Programando Bitcoin com Libwally](16_0_Programming_with_Libwally.md)
|
||||
* [17.1: Configurando a Libwally](16_1_Setting_Up_Libwally.md)
|
||||
* [17.2: Usando BIP39 na Libwally](16_2_Using_BIP39_in_Libwally.md)
|
||||
* [17.3: Usando BIP32 na Libwally](16_3_Using_BIP32_in_Libwally.md)
|
||||
* [17.4: Usando PSBTs na Libwally](16_4_Using_PSBTs_in_Libwally.md)
|
||||
* [17.5: Usando Scripts na Libwally](16_5_Using_Scripts_in_Libwally.md)
|
||||
* [17.6: Usando Outras Funções na Libwally](16_6_Using_Other_Functions_in_Libwally.md)
|
||||
* [17.7: Integrando Libwally e Bitcoin-CLI](16_7_Integrating_Libwally_and_Bitcoin-CLI.md)
|
||||
* [18.0: Conversando com o Bitcoind com Outras Linguagens](17_0_Talking_to_Bitcoind_Other.md)
|
||||
* [18.1: Acessando o Bitcoind com Go](17_1_Accessing_Bitcoind_with_Go.md)
|
||||
* [18.2: Acessando o Bitcoind com Java](17_2_Accessing_Bitcoind_with_Java.md)
|
||||
* [18.3: Acessando o Bitcoind com Node JS](17_3_Accessing_Bitcoind_with_NodeJS.md)
|
||||
* [18.4: Acessando o Bitcoind com Python](17_4_Accessing_Bitcoind_with_Python.md)
|
||||
* [18.5: Acessando o Bitcoind com Rust](17_5_Accessing_Bitcoind_with_Rust.md)
|
||||
* [18.6: Acessando o Bitcoind com Swift](17_6_Accessing_Bitcoind_with_Swift.md)
|
||||
|
||||
### PARTE SEIS: USANDO LIGHTNING-CLI
|
||||
|
||||
**Estado:** Finalizado.
|
||||
|
||||
* [18.0: Compreendendo Sua Configuração Lightning](18_0_Understanding_Your_Lightning_Setup.md)
|
||||
* [18.1: Verificando Sua Configuração c-lightning](18_1_Verifying_Your_Lightning_Setup.md)
|
||||
* [18.2: Conhecendo Sua Configuração c-lightning](18_2_Knowing_Your_lightning_Setup.md)
|
||||
* [19.0: Compreendendo Sua Configuração Lightning](18_0_Understanding_Your_Lightning_Setup.md)
|
||||
* [19.1: Verificando Sua Configuração c-lightning](18_1_Verifying_Your_Lightning_Setup.md)
|
||||
* [19.2: Conhecendo Sua Configuração c-lightning](18_2_Knowing_Your_lightning_Setup.md)
|
||||
* [Prefácio: Acessando um Segundo Node Lightning](18_2__Interlude_Accessing_a_Second_Lightning_Node.md)
|
||||
* [18.3: Criando um Canal Lightning](18_3_Setting_Up_a_Channel.md)
|
||||
* [19.0: Usando Lightning](19_0_Using_Lightning.md)
|
||||
* [19.1: Gerando um Pedido de Pagamento](19_1_Generate_a_Payment_Request.md)
|
||||
* [19.2: Pagando uma Fatura](19_2_Paying_a_Invoice.md)
|
||||
* [19.3: Fechando um Canal Lighnting]((19_3_Closing_a_Channel.md))
|
||||
* [19.4: Expandindo a Rede Lightning](19_4_Lightning_Network_Review.md)
|
||||
* [19.3: Criando um Canal Lightning](18_3_Setting_Up_a_Channel.md)
|
||||
* [20.0: Usando Lightning](19_0_Using_Lightning.md)
|
||||
* [20.1: Gerando um Pedido de Pagamento](19_1_Generate_a_Payment_Request.md)
|
||||
* [20.2: Pagando uma Fatura](19_2_Paying_a_Invoice.md)
|
||||
* [20.3: Fechando um Canal Lighnting]((19_3_Closing_a_Channel.md))
|
||||
* [20.4: Expandindo a Rede Lightning](19_4_Lightning_Network_Review.md)
|
||||
|
||||
### APÊNDICES
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user