mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-08 00:16:26 +00:00
Merge pull request #292 from namcios/Chapter06
Chapter 6 - translated by @KoreaComK and reviewed by @namcios
This commit is contained in:
commit
67523d4b0c
19
pt/06_0_Expanding_Bitcoin_Transactions_Multisigs.md
Normal file
19
pt/06_0_Expanding_Bitcoin_Transactions_Multisigs.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
# Capítulo 6: Expandindo Transações no Bitcoin com Multisigs
|
||||||
|
|
||||||
|
Transações básicas no Bitcoin: (1) enviam fundos; (2) para um único destinatário P2PKH ou SegWit; (3) de uma única máquina; (4) imediatamente. No entanto, todas as quatro partes desta definição podem ser expandidas usando transações mais complexas no Bitcoin. Este primeiro capítulo sobre "Expansão" mostra como variar os pontos (2) e (3) enviando saldos para um endereço que representa vários destinatários (ou, pelo menos, vários assinantes).
|
||||||
|
|
||||||
|
## Objetivos deste capítulo
|
||||||
|
|
||||||
|
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
|
||||||
|
* Criar endereços de Bitcoin multi-assinatura (multisig) usando os fundamentos do Bitcoin;
|
||||||
|
* Criar endereços de Bitcoin multi-assinatura (multisig) usando mecanismos mais fáceis.
|
||||||
|
|
||||||
|
Os objetivos secundários do capítulo incluem a capacidade de:
|
||||||
|
* Entender como gastar fundos enviados para um multisig;
|
||||||
|
* Planejar para obter o máximo do poder dos multisigs.
|
||||||
|
|
||||||
|
## Tabela de Conteúdo
|
||||||
|
|
||||||
|
* [Seção 1: Enviando uma Transação com Multsig](06_1_Sending_a_Transaction_to_a_Multisig.md)
|
||||||
|
* [Seção 2: Gastando uma Transação com Multsig](06_2_Spending_a_Transaction_to_a_Multisig.md)
|
||||||
|
* [Seção 3: Enviando e Gastando um Multisig de Maneira Automatizada](06_3_Sending_an_Automated_Multisig.md)
|
206
pt/06_1_Sending_a_Transaction_to_a_Multisig.md
Normal file
206
pt/06_1_Sending_a_Transaction_to_a_Multisig.md
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
# 6.1: Enviando uma Transação com Multisig
|
||||||
|
|
||||||
|
A primeira maneira de variar a forma como enviamos uma transação básica é usando um multisig. Isso nos dá a capacidade de exigir que várias pessoas (ou, ao menos, várias chaves privadas) autorizem o uso dos fundos.
|
||||||
|
|
||||||
|
## Entendendo como Funcionam os Multisigs
|
||||||
|
|
||||||
|
Em uma transação P2PKH ou SegWit padrão, os bitcoins são enviados para um endereço baseado na chave pública, o que significa que a chave privada relacionada é necessária para desbloquear a transação, resolvendo o quebra-cabeça criptográfico e permitindo que reutilizemos o saldo. Mas e se pudéssemos bloquear uma transação com _múltiplas_ chaves privadas? Isso efetivamente permitiria que os fundos fossem enviados a um grupo de pessoas, onde todas teriam que concordar em reutilizar o saldo.
|
||||||
|
|
||||||
|
> :book: ***O que é uma multi-assinatura?*** Uma multi-assinatura é uma metodologia que permite que mais de uma pessoa crie uma assinatura digital em conjunto. É uma técnica geral para o uso criptográfico de chaves que vai muito além do Bitcoin.
|
||||||
|
|
||||||
|
Tecnicamente, um quebra-cabeça criptográfico com várias assinaturas é criado pelo Bitcoin usando o comando OP_CHECKMULTISIG e, normalmente, é encapsulado em um endereço P2SH. A seção [§10.4: Programando um Multisig](10_4_Scripting_a_Multisig.md) irá detalhar como isso funciona com mais precisão. Por enquanto, tudo que precisamos saber é que podemos usar o comando ```bitcoin-cli``` para criar endereços multi-assinatura. Os fundos podem ser enviados para esses endereços como qualquer endereço P2PKH ou Segwit normal, mas várias chaves privadas serão necessárias para que o saldo seja resgatado.
|
||||||
|
|
||||||
|
> :book: ***O que é uma transação multisig?*** Uma transação multisig é uma transação no Bitcoin enviada para um endereço com várias assinaturas, exigindo assim que certas pessoas do grupo multi-assinatura precisem assinar a transação para poder reutilizar o saldo.
|
||||||
|
|
||||||
|
Multisigs simples exigem que todos no grupo assinem o UTXO quando for gasto. No entanto, há mais complexidade possível. Multisigs são geralmente descritos como sendo "m de n". Isso significa que a transação está trancada com um grupo de chaves "n", mas apenas "m" delas são necessárias para desbloquear a transação.
|
||||||
|
|
||||||
|
> :book: ***O que é um multisg m-de-n?*** Em um multisig, "m" assinaturas de um grupo de "n" são necessárias para formar a assinatura, onde "m ≤ n".
|
||||||
|
|
||||||
|
## Criando um Endereço Multisig
|
||||||
|
|
||||||
|
Para trancar um UTXO com várias chaves privadas, devemos primeiro criar um endereço multi-assinatura. Os exemplos usados aqui mostram a criação (e uso) de um multisig 2-de-2.
|
||||||
|
|
||||||
|
### Criando os Endereços
|
||||||
|
|
||||||
|
Para criar um endereço multisig, devemos primeiro preparar os endereços que o multisig irá combinar. A prática recomendada sugere que sempre criemos novos endereços. Isso significa que cada participante irá executar o comando ```getnewaddress``` em sua própria máquina:
|
||||||
|
```
|
||||||
|
machine1$ address1=$(bitcoin-cli getnewaddress)
|
||||||
|
```
|
||||||
|
E:
|
||||||
|
```
|
||||||
|
machine2$ address2=$(bitcoin-cli getnewaddress)
|
||||||
|
```
|
||||||
|
Posteriormente, um dos destinatários (ou talvez algum terceiro) precisará combinar ambos endereços.
|
||||||
|
|
||||||
|
#### Coletando Chaves Públicas
|
||||||
|
|
||||||
|
No entanto, não podemos criar um multisig com os endereços, pois esses são os hashes das chaves públicas: Ao invés disso, precisamos das próprias chaves públicas.
|
||||||
|
|
||||||
|
Esta informação está disponível facilmente com o comando ```getaddressinfo```.
|
||||||
|
|
||||||
|
Na máquina remota, que assumimos aqui que é ```machine2```, podemos obter as informações em uma lista.
|
||||||
|
```
|
||||||
|
machine2$ bitcoin-cli -named getaddressinfo address=$address2
|
||||||
|
{
|
||||||
|
"address": "tb1qr2tkjh8rs9xn5xaktf5phct0wxqufplawrfd9q",
|
||||||
|
"scriptPubKey": "00141a97695ce3814d3a1bb65a681be16f7181c487fd",
|
||||||
|
"ismine": true,
|
||||||
|
"solvable": true,
|
||||||
|
"desc": "wpkh([fe6f2292/0'/0'/1']02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3)#zc64l8dw",
|
||||||
|
"iswatchonly": false,
|
||||||
|
"isscript": false,
|
||||||
|
"iswitness": true,
|
||||||
|
"witness_version": 0,
|
||||||
|
"witness_program": "1a97695ce3814d3a1bb65a681be16f7181c487fd",
|
||||||
|
"pubkey": "02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3",
|
||||||
|
"ischange": false,
|
||||||
|
"timestamp": 1592957904,
|
||||||
|
"hdkeypath": "m/0'/0'/1'",
|
||||||
|
"hdseedid": "1dc70547f2b80e9bb5fde5f34fb3d85f8d8d1dab",
|
||||||
|
"hdmasterfingerprint": "fe6f2292",
|
||||||
|
"labels": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
O endereço ```pubkey``` (` 02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3`) é o que precisamos. Vamos copiá-lo para nossa máquina local por qualquer meio que acharmos mais eficiente e _que seja menos sujeito a erros_.
|
||||||
|
|
||||||
|
Este processo precisa ser realizado para _cada_ endereço de uma máquina diferente daquela onde o multisig está sendo construído. Obviamente, se algum terceiro estiver criando o endereço, precisaremos fazer isso para cada endereço.
|
||||||
|
|
||||||
|
> :warning: **ATENÇÃO:** O uso de hashes de chave pública pelo Bitcoin como endereços, ao invés de chaves públicas, na verdade representa uma camada adicional de segurança. Portanto, o envio de uma chave pública aumenta ligeiramente a vulnerabilidade do endereço associado, devido a alguma possibilidade do comprometimento da curva elíptica em um futuro distante. Não devemos nos preocupar em termos que enviar ocasionalmente uma chave pública para um uso como esse, mas devemos estar cientes de que os hashes de chave pública representam segurança e, portanto, as chaves públicas reais não devem ser enviadas de qualquer jeito para qualquer pessoa.
|
||||||
|
|
||||||
|
Se um dos endereços foi criado em nossa máquina local, que assumimos aqui que seja ```machine1```, podemos simplesmente colocar o endereço ```pubkey``` em uma nova variável.
|
||||||
|
```
|
||||||
|
machine1$ pubkey1=$(bitcoin-cli -named getaddressinfo address=$address1 | jq -r '.pubkey')
|
||||||
|
```
|
||||||
|
|
||||||
|
### Criando o Endereço
|
||||||
|
|
||||||
|
Um multisig agora pode ser criado com o comando ```createmultisig```:
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey1'","02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3"]'''
|
||||||
|
{
|
||||||
|
"address": "2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr",
|
||||||
|
"redeemScript": "522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae",
|
||||||
|
"descriptor": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
> :warning: **AVISO DE VERSÃO:** Algumas versões do ```createmultisig``` permitem a entrada de chaves públicas ou endereços, algumas requerem apenas as chaves públicas. Atualmente, ambas parecem funcionar.
|
||||||
|
|
||||||
|
Ao criar o endereço multisig, listamos quantas assinaturas são necessárias com o argumento ```nrequired``` (que é o "m" em um multisig "m-de-n"), então listamos o conjunto total de assinaturas possíveis com a argumento ```keys``` (que é o "n"). Observe que as entradas ```keys``` provavelmente vieram de lugares diferentes. Nesse caso, incluímos ```$pubkey1``` da máquina local e ```02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3``` de uma máquina remota.
|
||||||
|
|
||||||
|
> :information_source: **NOTA –– M-DE-N VS N-DE-N:** Este exemplo mostra a criação de um multisig simples 2-de-2 . Se quisermos criar uma assinatura m-de-n onde "m < n", precisamos apenas ajustar o campo ```nrequired``` e/ou o número de assinaturas ```keys``` no objeto JSON. Para um multisig 1-de-2, seria definido como ```nrequired = 1``` e também listaria duas chaves, enquanto para um multisig 2-de-3, seria necessário um ```nrequired = 2```, mas adicionaria mais uma chave pública à lista de ```keys```.
|
||||||
|
|
||||||
|
Quando usado corretamente, o ```createmultisig``` retorna três resultados, todos criticamente importantes.
|
||||||
|
|
||||||
|
O _endereço_ é o que iremos distribuir para as pessoas que desejam enviar os fundos. Podemos notar que ele tem um novo prefixo ```2```, exatamente como os endereços P2SH-SegWit. Isso porque, como eles, o comando ```createmultisig``` está na verdade criando um tipo de endereço totalmente novo chamado endereço P2SH. Ele funciona exatamente como um endereço P2PKH padrão para envio de fundos, mas como este foi criado para exigir vários endereços, precisaremos trabalhar um pouco mais para utilizá-los.
|
||||||
|
|
||||||
|
> :link: **TESTNET vs MAINNET:** Na testenet, o prefixo para endereços P2SH é ```2```, enquanto na Mainnet é ```3```.
|
||||||
|
|
||||||
|
O _redeemScript_ é o que precisaremos para resgatar os fundos (junto com as chaves privadas de "m" dos "n" endereços). Este script é outro recurso especial dos endereços P2SH e será explicado com mais detalhes na seção [§10.3: Rodando um Script no Bitcoin com P2SH](10_3_Running_a_Bitcoin_Script_with_P2SH.md). Por enquanto, precisamos apenas saber que alguns dados são necessários para podemos gastar nosso dinheiro.
|
||||||
|
|
||||||
|
O _descritor_ é a descrição padronizada para um endereço que encontramos na seção [§3.5: Compreendendo o Descritor](03_5_Understanding_the_Descriptor.md). Ele fornece uma maneira de importar esse endereço de volta para a outra máquina, usando o RPC ```importmulti```.
|
||||||
|
|
||||||
|
> :book: ***O que é um endereço P2SH?*** O P2SH significa Pay-To-Script-Hash. É um tipo de destinatário diferente de um endereço P2PKH padrão ou mesmo de um Bech32, usado para fundos cujo resgate é baseado em scripts de Bitcoin mais complexos. O ```bitcoin-cli``` usa o encapsulamento P2SH para ajudar a padronizar e simplificar os multisigs como "multisigs P2SH", assim como P2SH-SegWit estava usando o P2SH para padronizar os endereços SegWit e torná-los totalmente compatíveis com as versões antigas.
|
||||||
|
|
||||||
|
> :warning: **ATENÇÃO:** endereços P2SH multisig, como os criados pelo ```bitcoin-cli```, têm um limite para "m" e "n" nos multisigs com base no tamanho máximo do script de resgate, que atualmente é de 520 bytes. Praticamente, não vamos chegar a isso, a menos que estejamos nos excedendo em algo.
|
||||||
|
|
||||||
|
### Salvando Nosso Trabalho
|
||||||
|
|
||||||
|
Aqui está uma informação importante: nada sobre nosso multisig é salvo em nossa carteira usando essas técnicas básicas. Para resgatar o saldo enviado para este endereço multisig no futuro, precisaremos reter duas informações cruciais:
|
||||||
|
|
||||||
|
* Uma lista dos endereços Bitcoin usados no multisig, e;
|
||||||
|
* A saída ```redeemScript``` criada pelo comando ```createmultsig```.
|
||||||
|
|
||||||
|
Tecnicamente, o ```redeemScript``` pode ser recriado executando novamente o ```createmultisig``` com a lista completa de chaves públicas _na mesma ordem_ e com a contagem m-de-n correta. Mas, é melhor agarrar-se a ela e evitar qualquer tipo de estresse futuro.
|
||||||
|
|
||||||
|
### Observe a Ordem
|
||||||
|
|
||||||
|
Aqui está mais uma coisa que devemos tomar muito cuidado: _a ordem importa_. A ordem das chaves usadas para criar um multisig cria um hash único, ou seja, se colocarmos as chaves em uma ordem diferente, elas irão produzir um endereço diferente, conforme mostrado abaixo:
|
||||||
|
```
|
||||||
|
$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey1'","'$pubkey2'"]'''
|
||||||
|
{
|
||||||
|
"address": "2NFBQvz57UzKWDr2Vx5D667epVZifjGixkm",
|
||||||
|
"redeemScript": "52210342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da0321039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b352ae",
|
||||||
|
"descriptor": "sh(multi(2,0342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da03,039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3))#8l6hvjsk"
|
||||||
|
}
|
||||||
|
standup@btctest20:~$ bitcoin-cli -named createmultisig nrequired=2 keys='''["'$pubkey2'","'$pubkey1'"]'''
|
||||||
|
{
|
||||||
|
"address": "2N5bC4Yc5Pqept1y8nPRqvWmFSejkVeRb1k",
|
||||||
|
"redeemScript": "5221039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3210342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da0352ae",
|
||||||
|
"descriptor": "sh(multi(2,039cd6842869c1bfec13cfdbb7d8285bc4c501d413e6633e3ff75d9f13424d99b3,0342b306e410283065ffed38c3139a9bb8805b9f9fa6c16386e7ea96b1ba54da03))#audl88kg"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Mais notavelmente, cada ordem cria um _redeemScript_ diferente. Isso significa que se usamos essas técnicas básicas e não salvarmos o redemScript conforme as instruções, teremos que percorrer um número cada vez maior de variações para encontrar a correta quando tentarmos gastar os fundos!
|
||||||
|
|
||||||
|
O [BIP67](https://github.com/bitcoin/bips/blob/master/bip-0067.mediawiki) sugere uma maneira de ordenar lexicograficamente as chaves, de modo que sempre gerem as mesmas multisigs. A ColdCard e a Electrum estão entre as carteiras que já possuem suporte a isso. Claro, isso pode causar problemas por si só se não soubermos se um endereço multisig foi criado com chaves classificadas ou não classificadas. Mais uma vez, os [descritores](03_5_Understanding_the_Descriptor.md) vêm ao nosso resgate. Se um multisig não for classificado, ele será construído com a função ```multi```, e se for classificado, será construído com a função ```sortedmulti```.
|
||||||
|
|
||||||
|
Se olharmos o ```desc``` do multisig que criamos acima, veremos que o Bitcoin Core atualmente não classifica os multisigs:
|
||||||
|
```
|
||||||
|
"descriptor": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y"
|
||||||
|
```
|
||||||
|
Porém, se ele importa um endereço do tipo ```sortedmulti```, ele fará o processo correto, que é o ponto principal dos descritores!
|
||||||
|
|
||||||
|
> :warning: **AVISO DE VERSÃO:** O Bitcoin Core só entende a função do descritor ```sortedmulti``` após a versão 0.20.0. Podemos tentar acessar o descritor em uma versão anterior do Bitcoin Core e obteremos um erro como ```A function is needed within P2WSH```.
|
||||||
|
|
||||||
|
## Enviando para um Endereço Multisig
|
||||||
|
|
||||||
|
Se tivermos um multisig em um formato P2SH conveniente, como o gerado pelo ```bitcoin-cli```, podemos enviar como um endereço normal.
|
||||||
|
```
|
||||||
|
$ utxo_txid=$(bitcoin-cli listunspent | jq -r '.[0] | .txid')
|
||||||
|
$ utxo_vout=$(bitcoin-cli listunspent | jq -r '.[0] | .vout')
|
||||||
|
$ recipient="2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||||
|
|
||||||
|
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.000065}''')
|
||||||
|
$ bitcoin-cli -named decoderawtransaction hexstring=$rawtxhex
|
||||||
|
{
|
||||||
|
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||||
|
"hash": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||||
|
"version": 2,
|
||||||
|
"size": 83,
|
||||||
|
"vsize": 83,
|
||||||
|
"weight": 332,
|
||||||
|
"locktime": 0,
|
||||||
|
"vin": [
|
||||||
|
{
|
||||||
|
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||||
|
"vout": 0,
|
||||||
|
"scriptSig": {
|
||||||
|
"asm": "",
|
||||||
|
"hex": ""
|
||||||
|
},
|
||||||
|
"sequence": 4294967295
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vout": [
|
||||||
|
{
|
||||||
|
"value": 0.00006500,
|
||||||
|
"n": 0,
|
||||||
|
"scriptPubKey": {
|
||||||
|
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||||
|
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||||
|
"reqSigs": 1,
|
||||||
|
"type": "scripthash",
|
||||||
|
"addresses": [
|
||||||
|
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex | jq -r '.hex')
|
||||||
|
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||||
|
b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521
|
||||||
|
```
|
||||||
|
Como podemos ver, não houve nada de incomum na criação da transação e ela parece normal, embora com um endereço com um prefixo diferente do normal (```2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr```). Sem surpresa, como também não vimos diferença quando enviamos para endereços Bech32 pela primeira vez na seção [§4.6](04_6_Creating_a_Segwit_Transaction.md).
|
||||||
|
|
||||||
|
## Resumo: Enviando uma Transação Multisig
|
||||||
|
|
||||||
|
Os endereços multisig trancam os fundos usando várias chaves privadas, possivelmente exigindo todas essas chaves privadas para resgate e, possivelmente, exigindo apenas algumas do conjunto. Eles são fáceis de serem criados com o ```bitcoin-cli``` e são simples para serem enviados. Essa facilidade se deve em grande parte ao uso invisível de endereços P2SH (Pay-To-Script-Hash), um tópico extenso que já falamos duas vezes, com endereços P2SH-SegWit e agora com os multisigs, e um outro que receberá mais atenção no futuro.
|
||||||
|
|
||||||
|
> :fire: ***Qual é o poder das multi-assinaturas?*** As multi-assinaturas permitem a modelagem de uma variedade de arranjos financeiros, como corporações, parcerias, comitês e outros grupos. Um multisig 1-de-2 pode ser a conta bancária conjunta de um casal, enquanto um multisig 2-de-2 pode ser usado para grandes despesas por uma parceria de responsabilidade limitada. Os multisigs também constituem uma das bases dos Smart Contracts. Por exemplo, um negócio imobiliário pode ser fechado com um multisig 2-de-3, onde as assinaturas são enviadas pelo comprador, pelo vendedor e por um agente de custódia. Depois que o agente de custódia concorda que todas as condições foram atendidas, ele libera os fundos para o vendedor, ou, alternativamente, o comprador e o vendedor podem liberar os fundos em conjunto.
|
||||||
|
|
||||||
|
## O Que Vem Depois?
|
||||||
|
|
||||||
|
Vamos continuar "Expandindo Transações no Bitcoin com Multisigs" na seção [§6.2: Gastando uma Transação com Multisig](06_2_Spending_a_Transaction_to_a_Multisig.md).
|
229
pt/06_2_Spending_a_Transaction_to_a_Multisig.md
Normal file
229
pt/06_2_Spending_a_Transaction_to_a_Multisig.md
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
# 6.2: Gastando uma Transação com Multsig
|
||||||
|
|
||||||
|
A maneira clássica e complexa de gastar fundos enviados para um endereço com várias assinaturas usando o ```bitcoin-cli``` requer que suemos bastante a camisa.
|
||||||
|
|
||||||
|
## Encontrando os Fundos
|
||||||
|
|
||||||
|
Para começar, precisamos encontrar nossos fundos. Nosso computador não sabe procurá-los, porque não estão associados a nenhum endereço da nossa carteira. Podemos alertar o ```bitcoind``` para fazer isso usando o comando ```importaddress```:
|
||||||
|
```
|
||||||
|
$ bitcoin-cli -named importaddress address=2NAGfA4nW6nrZkD5je8tSiAcYB9xL2xYMCz
|
||||||
|
```
|
||||||
|
Se temos um node prunado (e provavelmente temos), ao invés desse jeito, precisaremos dizer não para verificar novamente:
|
||||||
|
```
|
||||||
|
$ bitcoin-cli -named importaddress address=2NAGfA4nW6nrZkD5je8tSiAcYB9xL2xYMCz rescan="false"
|
||||||
|
```
|
||||||
|
Se preferirmos, podemos importar o endereço usando nosso descritor (e esta é geralmente a melhor resposta, porque é mais padronizada):
|
||||||
|
```
|
||||||
|
$ bitcoin-cli importmulti '[{"desc": "sh(multi(2,02da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d191,02bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa3))#0pazcr4y", "timestamp": "now", "watchonly": true}]'
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
Depois, os fundos devem aparecer quando usarmos o comando ```listunspent```, porém, ainda não podemos gastar facilmente. Na verdade, nossa carteira pode alegar que não podemos gastá-los de forma alguma!
|
||||||
|
|
||||||
|
Se por algum motivo não puder incorporar o endereço da nossa carteira, podemos usar o comando ```gettransaction``` para obtermos mais informações (ou olharmos em um block explorer).
|
||||||
|
```
|
||||||
|
$ bitcoin-cli -named gettransaction txid=b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521 verbose=true
|
||||||
|
{
|
||||||
|
"amount": -0.00006500,
|
||||||
|
"fee": -0.00001000,
|
||||||
|
"confirmations": 3,
|
||||||
|
"blockhash": "0000000000000165b5f602920088a7e36b11214161d6aaebf5229e3ed4f10adc",
|
||||||
|
"blockheight": 1773282,
|
||||||
|
"blockindex": 9,
|
||||||
|
"blocktime": 1592959320,
|
||||||
|
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||||
|
"walletconflicts": [
|
||||||
|
],
|
||||||
|
"time": 1592958753,
|
||||||
|
"timereceived": 1592958753,
|
||||||
|
"bip125-replaceable": "no",
|
||||||
|
"details": [
|
||||||
|
{
|
||||||
|
"address": "2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr",
|
||||||
|
"category": "send",
|
||||||
|
"amount": -0.00006500,
|
||||||
|
"vout": 0,
|
||||||
|
"fee": -0.00001000,
|
||||||
|
"abandoned": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"hex": "020000000001011b95a6055174ec64b82ef05b6aefc38f34d0e57197e40281ecd8287b4260dec60000000000ffffffff01641900000000000017a914a5d106eb8ee51b23cf60d8bd98bc285695f233f38702473044022070275f81ac4129e1d167ef7e700739f2899ea4c7f1adef3a4da29436f14fb97e02207310d4ec449eba49f0fa404ae45b9c82431d883490c7a0ed882ad0b5d7a623d0012102883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb00000000",
|
||||||
|
"decoded": {
|
||||||
|
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||||
|
"hash": "bdf4e3bc5d354a5dfa5528f172480976321d989d7e5806ac14f1fe9b0b1c093a",
|
||||||
|
"version": 2,
|
||||||
|
"size": 192,
|
||||||
|
"vsize": 111,
|
||||||
|
"weight": 441,
|
||||||
|
"locktime": 0,
|
||||||
|
"vin": [
|
||||||
|
{
|
||||||
|
"txid": "c6de60427b28d8ec8102e49771e5d0348fc3ef6a5bf02eb864ec745105a6951b",
|
||||||
|
"vout": 0,
|
||||||
|
"scriptSig": {
|
||||||
|
"asm": "",
|
||||||
|
"hex": ""
|
||||||
|
},
|
||||||
|
"txinwitness": [
|
||||||
|
"3044022070275f81ac4129e1d167ef7e700739f2899ea4c7f1adef3a4da29436f14fb97e02207310d4ec449eba49f0fa404ae45b9c82431d883490c7a0ed882ad0b5d7a623d001",
|
||||||
|
"02883bb5463e37d55252d8b3d5c2141b007b37c8a7db6211f75c955acc5ea325eb"
|
||||||
|
],
|
||||||
|
"sequence": 4294967295
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"vout": [
|
||||||
|
{
|
||||||
|
"value": 0.00006500,
|
||||||
|
"n": 0,
|
||||||
|
"scriptPubKey": {
|
||||||
|
"asm": "OP_HASH160 a5d106eb8ee51b23cf60d8bd98bc285695f233f3 OP_EQUAL",
|
||||||
|
"hex": "a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387",
|
||||||
|
"reqSigs": 1,
|
||||||
|
"type": "scripthash",
|
||||||
|
"addresses": [
|
||||||
|
"2N8MytPW2ih27LctLjn6LfLFZZb1PFSsqBr"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configurando as Nossas Variáveis
|
||||||
|
|
||||||
|
Quando estivermos prontos para gastar os fundos recebidos por um endereço multisig, precisaremos coletar _muitos_ dados: muito mais do que precisamos quando fazemos uma transação usando um UTXO de um P2PKH normal ou SegWit. Isso ocorre em parte porque as informações sobre o endereço multisig não estão em nossa posse e em parte porque estamos gastando dinheiro que foi enviado para um endereço P2SH (Pay-To-Script-Hash) e isso é muito mais exigente.
|
||||||
|
|
||||||
|
No total, precisaremos coletar três coisas: informações estendidas sobre o UTXO; o redemScript e; todas as chaves privadas envolvidas. Obviamente, também iremos precisar de um novo endereço de destinatário. As chaves privadas precisam aguardar a etapa de assinatura, mas tudo pode ser feito agora.
|
||||||
|
|
||||||
|
### Acessando as Informações do UTXO
|
||||||
|
|
||||||
|
Para começar, vamos pegar o ```txid``` e o ```vout``` para a transação que desejamos gastar, como de costume. Nesse caso, os dados foram recuperados das informações ```gettransaction``` acima:
|
||||||
|
```
|
||||||
|
$ utxo_txid=b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521
|
||||||
|
$ utxo_vout=0
|
||||||
|
```
|
||||||
|
No entanto, precisamos também acessar um terceiro pedaço de informação sobre o UTXO, nosso ```scriptPubKey```/```hex```, que é o script que travou a transação. Novamente, podemos fazer isso observando os detalhes da transação:
|
||||||
|
```
|
||||||
|
$ utxo_spk=a914a5d106eb8ee51b23cf60d8bd98bc285695f233f387
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gravando o Script de Resgate
|
||||||
|
|
||||||
|
Felizmente, salvamos nosso ```redeemScript```. Agora devemos registrá-lo em uma variável.
|
||||||
|
|
||||||
|
O valor foi extraído da criação de endereço na seção anterior.
|
||||||
|
```
|
||||||
|
redeem_script="522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae"
|
||||||
|
```
|
||||||
|
### Decidindo o Destinatário
|
||||||
|
|
||||||
|
Vamos apenas enviar o dinheiro de volta para nós mesmos. Isso é útil porque libera os fundos do multisig, convertendo-os em uma transação P2PKH normal que pode ser posteriormente confirmada por uma única chave privada:
|
||||||
|
```
|
||||||
|
$ recipient=$(bitcoin-cli getrawchangeaddress)
|
||||||
|
```
|
||||||
|
## Criando Nossa Transação
|
||||||
|
|
||||||
|
Agora podemos criar nossa transação. Essa parte é parecida com as transações normais.
|
||||||
|
```
|
||||||
|
$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00005}''')
|
||||||
|
$ echo $rawtxhex
|
||||||
|
020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b10000000000ffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000
|
||||||
|
```
|
||||||
|
|
||||||
|
## Assinando Nossa Transação
|
||||||
|
|
||||||
|
Agora estamos prontos para assinar a transação. Este é um processo de várias etapas porque precisaremos fazer em várias máquinas, cada uma das quais contribuirá com suas próprias chaves privadas.
|
||||||
|
|
||||||
|
### Carregando a Primeira Chave Privada
|
||||||
|
|
||||||
|
Como essa transação não está fazendo uso total da nossa carteira, precisaremos acessar diretamente as chaves privadas. Começando com a ```máquina1```, onde devemos recuperar qualquer uma das chaves privadas do usuário que estavam envolvidas no multisig:
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named dumpprivkey address=$address1
|
||||||
|
cNPhhGjatADfhLD5gLfrR2JZKDE99Mn26NCbERsvnr24B3PcSbtR
|
||||||
|
```
|
||||||
|
> :warning: **ATENÇÃO:** Acessar diretamente as chaves privadas do shell é um comportamento muito perigoso e deve ser feito com extremo cuidado se estivermos usando dinheiro de verdade. No mínimo, é importante não salvar as informações em uma variável que possa ser acessada pela nossa máquina. Remover o histórico do shell é outro grande passo. No máximo, podemos evitar de fazer isso.
|
||||||
|
|
||||||
|
### Fazendo Nossa Primeira Assinatura
|
||||||
|
|
||||||
|
Agora podemos fazer nossa primeira assinatura com o comando ```signrawtransactionwithkey```. É aqui que as coisas ficam diferentes: precisaremos treinar o comando sobre como assinar. Podemos fazer isso adicionando as seguintes informações novas:
|
||||||
|
|
||||||
|
* Incluir um argumento ```prevtxs``` que tenha o ```txid```, o ```vout```, o ```scriptPubKey``` e o ```redeemScript``` que gravamos, cada um deles um par individual do valor-chave no objeto JSON.
|
||||||
|
* Incluir um argumento ```privkeys``` que lista as chaves privadas que pegamos nesta máquina.
|
||||||
|
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named signrawtransactionwithkey hexstring=$rawtxhex prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cNPhhGjatADfhLD5gLfrR2JZKDE99Mn26NCbERsvnr24B3PcSbtR"]'
|
||||||
|
{
|
||||||
|
"hex": "020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000",
|
||||||
|
"complete": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"txid": "b164388854f9701051809eed166d9f6cedba92327e4296bf8a265a5da94f6521",
|
||||||
|
"vout": 0,
|
||||||
|
"witness": [
|
||||||
|
],
|
||||||
|
"scriptSig": "0047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352ae",
|
||||||
|
"sequence": 4294967295,
|
||||||
|
"error": "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
Isso produz erros assustadores e mostra um status de ```failing```. Tudo bem. Podemos ver que a assinatura foi parcialmente bem-sucedida porque o ```hex``` ficou mais longo. Embora a transação tenha sido parcialmente assinada, ela não foi concluída porque precisa de mais assinaturas.
|
||||||
|
|
||||||
|
### Repetindo para os Outros Assinantes
|
||||||
|
|
||||||
|
Agora podemos passar a transação adiante, para ser assinada novamente por outros exigidos pelo multisig. Eles fazem isso executando o mesmo comando de assinatura que fizemos, porém: (1) com o ```hex``` maior que produzimos anteriormente (```bitcoin-cli -named signrawtransactionwithkey hexstring = $ rawtxhex prevtxs = '' '[{"txid": " '$ utxo_txid'", "vout": '$ utxo_vout', "scriptPubKey": " '$ utxo_spk'", "redeemScript": " '$ redeem_script'"}] '' 'privkeys =' [ "cMgb3KM8hPATCtgMKarKMiFesLft6eEw3DY6BB8d97fkeXeqQagw"] '| jq -r'. | .hex'```) e; (2) com sua própria chave privada.
|
||||||
|
|
||||||
|
> :information_source: **NOTA - M-DE-N VS N-DE-N:** Obviamente, se tivermos uma assinatura N de N (como a multisig 2-de-2 do exemplo), todas as partes precisarão assinar, mas se tivermos uma multi-assinatura m-de-n onde "m < n", a assinatura estará completa quando apenas alguns ("m") tiverem assinado.
|
||||||
|
|
||||||
|
Para fazer isso, primeiro eles acessam suas chaves privadas:
|
||||||
|
```
|
||||||
|
machine2$ bitcoin-cli -named dumpprivkey address=$address2
|
||||||
|
cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz
|
||||||
|
```
|
||||||
|
Depois, assinam o novo ```hex``` usando os mesmos valores ```prevtxs```:
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named signrawtransactionwithkey hexstring=020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000 prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz"]'
|
||||||
|
{
|
||||||
|
"hex": "020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000d90047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e301473044022000a402ec4549a65799688dd531d7b18b03c6379416cc8c29b92011987084e9f402205470e24781509c70e2410aaa6d827aa133d6df2c578e96a496b885584fb039200147522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000",
|
||||||
|
"complete": true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Por fim, podem precisar enviar uma ```hexstring``` ainda mais longa que eles tenham produzido para assinantes adicionais.
|
||||||
|
|
||||||
|
Mas, neste caso, podemos ver que a assinatura está `complete`!
|
||||||
|
|
||||||
|
## Enviando Nossa Transação
|
||||||
|
|
||||||
|
Quando terminarmos, devemos recorrer à metodologia ```JQ``` padrão para salvar nossa ```hexstring``` e, em seguida, enviá-la:
|
||||||
|
```
|
||||||
|
$ signedtx=$(bitcoin-cli -named signrawtransactionwithkey hexstring=020000000121654fa95d5a268abf96427e3292baed6c9f6d16ed9e80511070f954883864b100000000920047304402201c97b48215f261055e41b765ab025e77a849b349698ed742b305f2c845c69b3f022013a5142ef61db1ff425fbdcdeb3ea370aaff5265eee0956cff9aa97ad9a357e3010047522102da2f10746e9778dd57bd0276a4f84101c4e0a711f9cfd9f09cde55acbdd2d1912102bfde48be4aa8f4bf76c570e98a8d287f9be5638412ab38dede8e78df82f33fa352aeffffffff0188130000000000001600142c48d3401f6abed74f52df3f795c644b4398844600000000 prevtxs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout', "scriptPubKey": "'$utxo_spk'", "redeemScript": "'$redeem_script'" } ]''' privkeys='["cVhqpKhx2jgfLUWmyR22JnichoctJCHPtPERm11a2yxnVFKWEKyz"]' | jq -r .hex)
|
||||||
|
$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||||
|
99d2b5717fed8875a1ed3b2827dd60ae3089f9caa7c7c23d47635f6f5b397c04
|
||||||
|
```
|
||||||
|
|
||||||
|
## Compreendendo a Importância Desta Metodologia de Assinatura Expandida
|
||||||
|
|
||||||
|
Isto deu um belo trabalho e, como logo iremos aprender, existe uma tolice ao utilizar as chaves privadas, o redeem script e com a scriptpubkey pois eles não são realmente necessários para resgatar os endereços de multisg usando versões mais recentes do Bitcoin Core. Então, qual foi o ponto?
|
||||||
|
|
||||||
|
Esta metodologia de resgate mostra uma maneira padrão de assinar e reutilizar transações P2SH. Em suma, para resgatar fundos P2SH, uma ```signrawtransactionwithkey``` precisa:
|
||||||
|
|
||||||
|
1. Incluir o ```scriptPubKey```, que explica o quebra-cabeça criptográfico P2SH;
|
||||||
|
2. Incluir o ```redeemScript```, que resolve o quebra-cabeça criptográfico P2SH e apresenta um novo quebra-cabeça;
|
||||||
|
3. Ser executado em cada máquina que contém as chaves privadas necessárias;
|
||||||
|
4. Incluir as assinaturas relevantes, que resolvem o quebra-cabeça do redemScript.
|
||||||
|
|
||||||
|
Aqui, vimos essa metodologia usada para resgatar os fundos multisig. No futuro, também podemos usá-la para resgatar os fundos que foram trancados com outros scripts P2SH mais complexos, conforme explicado no Capítulo 9.
|
||||||
|
|
||||||
|
## Resumo: Gastando uma Transação com Multisig
|
||||||
|
|
||||||
|
Acontece que gastar dinheiro enviado para um endereço multisig pode dar um pouco de trabalho. Mas, contanto que tenhamos os endereços originais e nosso redemScript, podemos fazer isso assinando uma transação bruta com cada endereço diferente e fornecendo mais algumas informações ao longo do caminho.
|
||||||
|
|
||||||
|
## O Que Vem Depois?
|
||||||
|
|
||||||
|
Vamos continuar "Expandindo Transações no Bitcoin com Multisigs" na seção [§6.3: Enviando & Gastando um Multisig Automatizado](06_3_Sending_an_Automated_Multisig.md).
|
120
pt/06_3_Sending_an_Automated_Multisig.md
Normal file
120
pt/06_3_Sending_an_Automated_Multisig.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# 6.3: Enviando & Gastando um Multisig Automatizado
|
||||||
|
|
||||||
|
A técnica padrão para criar endereços multi-assinatura e gastar os fundos é complexa, mas é um exercício interessante para entender um pouco mais como funcionam e como podemos manipulá-los em um nível relativamente baixo. No entanto, o Bitcoin Core tornou os multisigs mais fáceis de serem manipulados nas novas versões.
|
||||||
|
|
||||||
|
> :warning: **AVISO DE VERSÃO:** O comando ```addmultisigaddress``` está disponível no Bitcoin Core v0.10 ou superior.
|
||||||
|
|
||||||
|
## Criando um Endereço Multisig em Nossa Carteira
|
||||||
|
|
||||||
|
Para tornar os fundos enviados para endereços multisig mais fáceis de serem gastos, só precisamos fazer algumas pré-configurações usando o comando ```addmultisigaddress```. Não é o que gostaríamos de fazer se estivéssemos escrevendo programas de carteiras que utilizam multisig, mas se estivesse apenas tentando receber alguns fundos, isso poderia evitar alguns problemas.
|
||||||
|
|
||||||
|
### Coletando as Chaves
|
||||||
|
|
||||||
|
Vamos começar criando os endereços P2PKH e recuperando as chaves públicas, como de costume, para cada usuário que fará parte do multisig:
|
||||||
|
```
|
||||||
|
machine1$ address3=$(bitcoin-cli getnewaddress)
|
||||||
|
machine1$ echo $address3
|
||||||
|
tb1q4ep2vmakpkkj6mflu94x5f94q662m0u5ad0t4w
|
||||||
|
machine1$ bitcoin-cli -named getaddressinfo address=$address3 | jq -r '. | .pubkey'
|
||||||
|
0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc
|
||||||
|
|
||||||
|
machine2$ address4=$(bitcoin-cli getnewaddress)
|
||||||
|
machine2$ echo $address4
|
||||||
|
tb1qa9v5h6zkhq8wh0etnv3ae9cdurkh085xufl3de
|
||||||
|
machine2$ bitcoin-cli -named getaddressinfo address=$address4 | jq -r '. | .pubkey'
|
||||||
|
02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f
|
||||||
|
```
|
||||||
|
|
||||||
|
### Criando o Endereço Multisig em Todos os Lugares
|
||||||
|
|
||||||
|
Em seguida, vamos criar o multisig em _cada máquina que contribuiu com assinaturas_ usando um novo comando, ```addmultisigaddress```, ao invés de ```createmultisig```. Este novo comando salva algumas das informações na nossa carteira, tornando muito mais fácil gastar o dinheiro no futuro.
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["'$address3'","02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f"]'''
|
||||||
|
{
|
||||||
|
"address": "tb1q9as46kupwcxancdx82gw65365svlzdwmjal4uxs23t3zz3rgg3wqpqlhex",
|
||||||
|
"redeemScript": "52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae",
|
||||||
|
"descriptor": "wsh(multi(2,[d6043800/0'/0'/15']0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc,[e9594be8]02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f))#wxn4tdju"
|
||||||
|
}
|
||||||
|
|
||||||
|
machine2$ bitcoin-cli -named addmultisigaddress nrequired=2 keys='''["0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc","'$address4'"]'''
|
||||||
|
{
|
||||||
|
"address": "tb1q9as46kupwcxancdx82gw65365svlzdwmjal4uxs23t3zz3rgg3wqpqlhex",
|
||||||
|
"redeemScript": "52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae",
|
||||||
|
"descriptor": "wsh(multi(2,[ae42a66f]0297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc,[fe6f2292/0'/0'/2']02a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f))#cc96c5n6"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Conforme observado na seção anterior, atualmente não importa se usamos endereços ou chaves públicas, então temos mostrado o outro mecanismo aqui, misturando os dois. Iremos obter o mesmo endereço multisig de qualquer maneira. No entanto, _devemos usar a mesma ordem sempre_. Portanto, é melhor que os membros do multisig verifiquem entre si a ordem dos dados para ter certeza de que todos obtiveram o mesmo resultado.
|
||||||
|
|
||||||
|
### Atente-se aos Fundos
|
||||||
|
|
||||||
|
Depois disso, os membros do multisig ainda precisarão executar o comando ```importaddress``` para observar os fundos recebidos no endereço multisig:
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named importaddress address=2Mzw7WBvh9RAQ4ssKqxyNyP7L9NAojLqSW8 rescan="false"
|
||||||
|
|
||||||
|
machine2$ bitcoin-cli -named importaddress address=2Mzw7WBvh9RAQ4ssKqxyNyP7L9NAojLqSW8 rescan="false"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gastando Novamente com uma Transação Automatizada
|
||||||
|
|
||||||
|
Posteriormente, poderemos receber os fundos no endereço multisig normalmente. O uso do ```addmultisigaddress``` é simplesmente uma questão burocrática por parte dos destinatários: um pouco de contabilidade para facilitar a vida deles quando desejarem gastar os saldos.
|
||||||
|
|
||||||
|
Mas, isso torna a vida muito mais fácil. Como as informações foram salvas na carteira, os assinantes poderão gastar os fundos enviados para o endereço com várias assinaturas exatamente como qualquer outro endereço, ao invés de assinar sempre em várias máquinas diferentes.
|
||||||
|
|
||||||
|
Podemos começar coletando as variáveis, mas não precisamos mais nos preocupar com o ```scriptPubKey``` ou com o ```redeemScript```.
|
||||||
|
|
||||||
|
Aqui está uma nova transação enviada para nosso novo endereço multisig:
|
||||||
|
```
|
||||||
|
machine1$ utxo_txid=b9f3c4756ef8159d6a66414a4317f865882ee04beb57a0f8349dafcc98f5acbc
|
||||||
|
machine1$ utxo_vout=0
|
||||||
|
machine1$ recipient=$(bitcoin-cli getrawchangeaddress)
|
||||||
|
```
|
||||||
|
Criamos uma transação bruta:
|
||||||
|
```
|
||||||
|
machine1$ rawtxhex=$(bitcoin-cli -named createrawtransaction inputs='''[ { "txid": "'$utxo_txid'", "vout": '$utxo_vout' } ]''' outputs='''{ "'$recipient'": 0.00005}''')
|
||||||
|
```
|
||||||
|
E depois, a assinamos:
|
||||||
|
```
|
||||||
|
machine1$ bitcoin-cli -named signrawtransactionwithwallet hexstring=$rawtxhex
|
||||||
|
{
|
||||||
|
"hex": "02000000000101bcacf598ccaf9d34f8a057eb4be02e8865f817434a41666a9d15f86e75c4f3b90000000000ffffffff0188130000000000001600144f93c831ec739166ea425984170f4dc6bac75829040047304402205f84d40ba16ff49e60a7fc9228ef5917473aae1ab667dad01e113ca0fef3008b02201a50da2c65f38798aea94bcbd5bbf065bc1e38de44bacee69d525dcddcc11bba01004752210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae00000000",
|
||||||
|
"complete": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"txid": "b9f3c4756ef8159d6a66414a4317f865882ee04beb57a0f8349dafcc98f5acbc",
|
||||||
|
"vout": 0,
|
||||||
|
"witness": [
|
||||||
|
"",
|
||||||
|
"304402205f84d40ba16ff49e60a7fc9228ef5917473aae1ab667dad01e113ca0fef3008b02201a50da2c65f38798aea94bcbd5bbf065bc1e38de44bacee69d525dcddcc11bba01",
|
||||||
|
"",
|
||||||
|
"52210297e681bff16cd4600138449e2527db4b2f83955c691a1b84254ecffddb9bfbfc2102a0d96e16458ff0c90db4826f86408f2cfa0e960514c0db547ff152d3e567738f52ae"
|
||||||
|
],
|
||||||
|
"scriptSig": "",
|
||||||
|
"sequence": 4294967295,
|
||||||
|
"error": "CHECK(MULTI)SIG failing with non-zero signature (possibly need more signatures)"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
Observe que não precisamos mais dar ajuda extra ao comando ```signrawtransactionwithkey```, porque todas as informações extras já estavam em nossa carteira. Mais importante, não tornamos nossas chaves privadas vulneráveis ao manipulá-las diretamente. Ao invés disso, o processo é _exatamente_ o mesmo que gastar um UTXO normal, exceto que a transação não foi totalmente assinada no final.
|
||||||
|
|
||||||
|
### Assinando em Outras Máquinas
|
||||||
|
|
||||||
|
A etapa final é exportar o ```hex``` parcialmente assinado para a outra máquina e assinar a transação novamente:
|
||||||
|
```
|
||||||
|
machine2$ signedtx=$(bitcoin-cli -named signrawtransactionwithwallet hexstring=02000000014ecda61c45f488e35c613a7c4ae26335a8d7bfd0a942f026d0fb1050e744a67d000000009100473044022025decef887fe2e3eb1c4b3edaa155e5755102d1570716f1467bb0b518b777ddf022017e97f8853af8acab4853ccf502213b7ff4cc3bd9502941369905371545de28d0147522102e7356952f4bb1daf475c04b95a2f7e0d9a12cf5b5c48a25b2303783d91849ba421030186d2b55de166389aefe209f508ce1fbd79966d9ac417adef74b7c1b5e0777652aeffffffff0130e1be07000000001976a9148dfbf103e48df7d1993448aa387dc31a2ebd522d88ac00000000 | jq -r '.hex')
|
||||||
|
```
|
||||||
|
Quando todos os assinantes confirmaram a assinatura, estaremos prontos para enviar a transação para a rede:
|
||||||
|
```
|
||||||
|
machine2$ bitcoin-cli -named sendrawtransaction hexstring=$signedtx
|
||||||
|
3ce88839ac6165aeadcfb188c490e1b850468eff571b4ca78fac64342751510d
|
||||||
|
```
|
||||||
|
Tal como acontece com o atalho discutido na seção [§4.5: Enviando Moedas com Transações Brutas Automatizadas](04_5_Sending_Coins_with_Automated_Raw_Transactions.md), o resultado é muito mais fácil, mas perdemos certo controle no processo.
|
||||||
|
|
||||||
|
## Resumo: Enviando & Gastando um Multisig Automatizado
|
||||||
|
|
||||||
|
Existe uma maneira mais fácil de gastar fundos enviados para os nossos endereços multisig que simplesmente requerem o uso do comando ```addmultisigaddress``` quando criamos nosso endereço. Ele não demonstra as complexidades do gasto do P2SH e não nos dará um controle abrangente, mas se queremos apenas receber nossas moedas, este pode ser o melhor caminho.
|
||||||
|
|
||||||
|
## O Que Vem Depois?
|
||||||
|
|
||||||
|
Saiba mais sobre "Expandindo Transações no Bitcoin com Multisigs" no [Capítulo 7: Expandindo Transações no Bitcoin com PSBTs](07_0_Expanding_Bitcoin_Transactions_PSBTs.md).
|
Loading…
x
Reference in New Issue
Block a user