Learning-Bitcoin-from-the-C.../pt/09_4_Scripting_a_P2PKH.md
2021-09-21 11:00:40 -03:00

23 KiB

9.4: Programando um P2PKH

Os endereços P2PKH estão desaparecendo rapidamente devido ao advento do Segwit, porém, são importantes para entender o Bitcoin, e especialmente para entender os scripts do Bitcoin. Vamos dar uma olhada rápida como os scripts nativos do Segwit (P2WPKH) funcionam na próxima seção.

Entendendo o Script de Desbloqueio

Dissemos que quando os fundos são enviados para um endereço de bitcoin, eles estão bloqueados juntamente com a chave privada associada a esse endereço. Isso é gerenciado através do scriptPubKey de uma transação P2PKH, que é projetado de forma que requer que o destinatário tenha a chave privada associada ao endereço bitcoin do tipo P2PKH. Para ser preciso, o destinatário deve fornecer tanto a chave pública ligada à chave privada quanto uma assinatura gerada pela chave privada.

Vamos dar uma olhada novamente na transação que criamos na seção §9.1:

$ bitcoin-cli -named decoderawtransaction hexstring=$signedtx
{
  "txid": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
  "hash": "34151dac704d94a269cd33f80be34c122152edc9bfbb9323852966bf0ce937ed",
  "version": 2,
  "size": 191,
  "vsize": 191,
  "weight": 764,
  "locktime": 0,
  "vin": [
    {
      "txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
      "vout": 0,
      "scriptSig": {
        "asm": "304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b",
        "hex": "47304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c01210315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b"
      },
      "sequence": 4294967295
    }
  ],
  "vout": [
    {
      "value": 0.00090000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 06b5c6ba5330cdf738a2ce91152bfd0e71f9ec39 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a91406b5c6ba5330cdf738a2ce91152bfd0e71f9ec3988ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mg8S7F1gY3ivV9M9GrWwe6ziWvK2MFquCf"
        ]
      }
    }
  ]
}

Podemos ver que o script de desbloqueio do scriptSig tem dois valores, uma <signature> (e um [ALL]) e uma <pubkey>:

304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c[ALL] 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b

Isso é tudo que um script de desbloqueio é! (No caso de um endereço P2PKH).

Entendendo o Script de Bloqueio

Lembre-se de que cada script de desbloqueio desbloqueia um UTXO anterior. No exemplo acima, o vin revela que é realmente desbloqueado o vout 0 da txid bb4362dec15e67d366088f5493c789f22fbb4a6049f22fb4a604e767dae1f6a631687E2784aa.

Podemos examinar esse UTXO usando o comando gettransaction.

$ bitcoin-cli gettransaction "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa"
{
  "amount": 0.00095000,
  "confirmations": 12,
  "blockhash": "0000000075a4c1519da5e671b15064734c42784eab723530a6ace83ca1e66d3f",
  "blockheight": 1780789,
  "blockindex": 132,
  "blocktime": 1594841768,
  "txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
  "walletconflicts": [
  ],
  "time": 1594841108,
  "timereceived": 1594841108,
  "bip125-replaceable": "no",
  "details": [
    {
      "address": "mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9",
      "category": "receive",
      "amount": 0.00095000,
      "label": "",
      "vout": 0
    }
  ],
  "hex": "020000000001011efcc3bf9950ac2ea08c53b43a0f8cc21e4b5564e205f996f7cadb7d13bb79470000000017160014c4ea10874ae77d957e170bd43f2ee828a8e3bc71feffffff0218730100000000001976a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac713b10000000000017a914b780fc2e945bea71b9ee2d8d2901f00914a25fbd8702473044022025ee4fd38e6865125f7c315406c0b3a8139d482e3be333727d38868baa656d3d02204b35d9b5812cb85894541da611d5cec14c374ae7a7b8ba14bb44495747b571530121033cae26cb3fa063c95e2c55a94bd04ab9cf173104555efe448b1bfc3a68c8f873342c1b00"
}

Mas como podemos observar, não recebemos o scriptPubKey com o gettransaction. Precisamos dar um passo adicional para recuperar essa informação, examinando as informações da transação bruta (que é o hex) com o Decoderawtransaction:

$ hex=$(bitcoin-cli gettransaction "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa" | jq -r '.hex')
$ bitcoin-cli decoderawtransaction $hex
{
  "txid": "bb4362dec15e67d366088f5493c789f22fb4a604e767dae1f6a631687e2784aa",
  "hash": "6866490b16a92d68179e1cf04380fd08f16ec80bf66469af8d5e78ae624ff202",
  "version": 2,
  "size": 249,
  "vsize": 168,
  "weight": 669,
  "locktime": 1780788,
  "vin": [
    {
      "txid": "4779bb137ddbcaf796f905e264554b1ec28c0f3ab4538ca02eac5099bfc3fc1e",
      "vout": 0,
      "scriptSig": {
        "asm": "0014c4ea10874ae77d957e170bd43f2ee828a8e3bc71",
        "hex": "160014c4ea10874ae77d957e170bd43f2ee828a8e3bc71"
      },
      "txinwitness": [
        "3044022025ee4fd38e6865125f7c315406c0b3a8139d482e3be333727d38868baa656d3d02204b35d9b5812cb85894541da611d5cec14c374ae7a7b8ba14bb44495747b5715301",
        "033cae26cb3fa063c95e2c55a94bd04ab9cf173104555efe448b1bfc3a68c8f873"
      ],
      "sequence": 4294967294
    }
  ],
  "vout": [
    {
      "value": 0.00095000,
      "n": 0,
      "scriptPubKey": {
        "asm": "OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG",
        "hex": "76a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac",
        "reqSigs": 1,
        "type": "pubkeyhash",
        "addresses": [
          "mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9"
        ]
      }
    },
    {
      "value": 0.01063793,
      "n": 1,
      "scriptPubKey": {
        "asm": "OP_HASH160 b780fc2e945bea71b9ee2d8d2901f00914a25fbd OP_EQUAL",
        "hex": "a914b780fc2e945bea71b9ee2d8d2901f00914a25fbd87",
        "reqSigs": 1,
        "type": "scripthash",
        "addresses": [
          "2N9yWARt5E3TQsX2RjsauxSZaEZVhinAS4h"
        ]
      }
    }
  ]
}

Podemos olhar agora para o vout 0 e ver que ele foi bloqueado com o scriptPubKey no OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG. Essa é a metodologia de bloqueio padrão usada para um endereço P2PKH mais antigo com o <pubKeyHash> preso no meio.

Executando-o demonstrará seu funcionamento.

Executando um Script P2PKH

Quando desbloqueamos um UTXO do tipo P2PKH, efetivamente concatenamos os scripts de desbloqueio e de bloqueio. Para um endereço P2PKH, como o exemplo que usamos neste capítulo, isso produz o seguinte:

Script: <signature> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

Com essas informações juntas, podemos examinar como um UTXO P2PKH é desbloqueado.

Primeiro, colocamos as constantes iniciais na pilha, depois fazemos uma cópia do pubKey com o OP_DUP:

Script: <signature> <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Stack: [ ]

Script: <pubKey> OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Stack: [ <signature> ]

Script: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Stack: [ <signature> <pubKey> ]

Script: OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKey> OP_DUP
Stack: [ <signature> <pubKey> <pubKey> ]

Por que duplicar? Porque é necessário verificar os dois elementos de desbloqueio, a chave pública e a assinatura.

Em seguida, o OP_HASH160 retira o <pubKey> fora da pilha, cria um hash e coloca o resultado de volta nela.

Script: <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKey> OP_HASH160
Stack: [ <signature> <pubKey> <pubKeyHash> ]

Então, colocamos o <pubKeyHash> que estava no script de bloqueio na pilha:

Script: OP_EQUALVERIFY OP_CHECKSIG
Stack: [ <signature> <pubKey> <pubKeyHash> <pubKeyHash> ]

O OP_EQUALVERIFY é efetivamente dois opcodes: OP_EQUAL, que retira dois itens da pilha e coloca True ou False de volta baseado na comparação de ambos elementos; e o OP_VERIFY que retira o resultado e imediatamente marca a transação como inválida se for False. (No capítulo 12 falaremos mais sobre o uso de OP_VERIFY como condicional.)

Assumindo que os dois <pubKeyHash> são iguais, teremos o seguinte resultado:

Script: OP_CHECKSIG
Running: <pubKeyHash> <pubKeyHash> OP_EQUALVERIFY
Stack: [ <signature> <pubKey> ]

Neste momento, provamos que a <pubkey> fornecida no scriptSig leva ao endereço Bitcoin em questão, então sabemos que o redentor conhecia a chave púbica. Mas, ele também precisa provar o conhecimento da chave privada, o que é feito com os OP_CHECKSIG, que confirmam que a assinatura do script de desbloqueio corresponde a essa chave pública.

Script:
Running: <signature> <pubKey> OP_CHECKSIG
Stack: [ True ]

O script agora termina e, se foi bem sucedido, a transação é permitida para gastar o UTXO em questão novamente.

Usando o btcdeb em um Exemplo P2PKH

Testando transações de bitcoin reais com o btcdeb é um pouco mais complicado, porque precisamos conhecer a chave pública e uma assinatura para fazer todo o trabalho, e gerar o último é um pouco difícil. No entanto, uma maneira de testar as coisas é deixar o Bitcoin fazer o trabalho para nós, gerando uma transação que possa desbloquear um UTXO. Isso é o que fizemos acima, geramos a transação para gastar o UTXO criado pelo bitcoin-cli para calcular a <signature> e a <pubKey>. Podemos analisar as informações da transação bruta do UTXO para conhecer o script de bloqueio, incluindo o <pubKeyHash>.

Podemos montar o script de bloqueio, a assinatura e a pubkey usando o btcdeb, mostrando como pode ser simples um script P2PKH .

$ btcdeb '[304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b OP_DUP OP_HASH160 41d83eaffbf80f82dee4c152de59a38ffd0b6021 OP_EQUALVERIFY OP_CHECKSIG]'
btcdeb 0.2.19 -- type `btcdeb -h` for start up options
unknown key ID 41d83eaffbf80f82dee4c152de59a38ffd0b6021: returning fake key
valid script
7 op script loaded. type `help` for usage information
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b... | 
0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b | 
OP_DUP                                                             |
OP_HASH160                                                         |
41d83eaffbf80f82dee4c152de59a38ffd0b6021                           | 
OP_EQUALVERIFY                                                     | 
OP_CHECKSIG                                                        | 
                                                                   | 
                                                                   | 
#0000 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c

Colocamos a <signature> e a <pubKey> dentro da pilha:

btcdeb> step
    <> PUSH stack 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b92cbab7d1022066f273178febc7a37568e2e9f4dec980a2e9a95441abe838c7ef64c39d85849c
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
OP_DUP                                                             | 
OP_HASH160                                                         | 
41d83eaffbf80f82dee4c152de59a38ffd0b6021                           |  
OP_EQUALVERIFY                                                     |  
OP_CHECKSIG                                                        |     
                                                                   |   
                                                                   | 
                                                                   | 
                                                                   | 
                                                                   | 
#0001 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
btcdeb> step
    <> PUSH stack 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
OP_DUP                                                             | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
OP_HASH160                                                         | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
41d83eaffbf80f82dee4c152de59a38ffd0b6021                           | 
OP_EQUALVERIFY                                                     |
OP_CHECKSIG                                                        |  
                                                                   |   
                                                                   |    
                                                                   | 
                                                                   |
                                                                   | 
                                                                   | 
                                                               | 

Usamos o OP_DUP e o OP_HASH na <pubKey>:

#0002 OP_DUP
btcdeb> step
    <> PUSH stack 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
OP_HASH160                                                         | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
41d83eaffbf80f82dee4c152de59a38ffd0b6021                           | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
OP_EQUALVERIFY                                                     | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
OP_CHECKSIG                                                        | 
                                                                   | 
                                                                   |   
                                                                   |  
                                                                   |   
                                                                   |   
                                                                   | 
                                                                   | 
                                                                   |
                                                                   | 
#0003 OP_HASH160
btcdeb> step
    <> POP  stack
    <> PUSH stack 41d83eaffbf80f82dee4c152de59a38ffd0b6021
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
41d83eaffbf80f82dee4c152de59a38ffd0b6021                           |                           41d83eaffbf80f82dee4c152de59a38ffd0b6021
OP_EQUALVERIFY                                                     | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
OP_CHECKSIG                                                        | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
                                                                   | 
                                                                   | 
                                                                   |   
                                                                   |    
                                                                   |    
                                                                   |     
                                                                   | 
                                                                   | 
                                                                   | 
                                                                   | 

Depois colocamos o <pubKeyHash> do script de bloqueio na pilha e o verificamos:

#0004 41d83eaffbf80f82dee4c152de59a38ffd0b6021
btcdeb> step
    <> PUSH stack 41d83eaffbf80f82dee4c152de59a38ffd0b6021
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
OP_EQUALVERIFY                                                     |                           41d83eaffbf80f82dee4c152de59a38ffd0b6021
OP_CHECKSIG                                                        |                           41d83eaffbf80f82dee4c152de59a38ffd0b6021
                                                                   | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
                                                                   | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
                                                                   | 
                                                                   | 
                                                                   |  
                                                                   |  
                                                                   |  
                                                                   |       
                                                                   |   
                                                                   | 
                                                                   |
                                                                   | 
#0005 OP_EQUALVERIFY
btcdeb> step
    <> POP  stack
    <> POP  stack
    <> PUSH stack 01
    <> POP  stack
script                                                             |                                                             stack 
-------------------------------------------------------------------+-------------------------------------------------------------------
OP_CHECKSIG                                                        | 0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b
                                                                   | 304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c9dfba68b...
                                                                   | 
                                                                   | and_v(
                                                                   |     sig(304402201cc39005b076cb06534cd084fcc522e7bf937c4c9654c1c...
                                                                   |     and_v(
                                                                   |         pk(0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3...
                                                                   |         c:pk_h(030500000000000000000000000000000000000000000000...
                                                                   |     )
                                                                   | 
                                                                   | )
                                                                   | 
      

E nesse ponto, tudo o que é necessário é o OP_CHECKSIG:

#0006 OP_CHECKSIG
btcdeb> step
error: Signature is found in scriptCode

Infelizmente, esta verificação pode ou não estar funcionando no momento do teste devido a caprichos do Bitcoin Core e do btcdeb.

Como mostramos, um P2PKH é bastante simples. Nossa proteção vem através da força de sua criptografia.

Como Procurar uma PubKey e uma Assinatura Manualmente

E se quiséssemos gerar a <signature> e a <PubKey>, informações necessárias para desbloquear um UTXO, sem usar o bitcoin-cli para criar uma transação?

Acontece que é muito fácil obtermos uma <pubKey>. Nós precisamos usar o getaddressinfo para examinar o endereço onde o UTXO está:

$ bitcoin-cli getaddressinfo mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9
{
  "address": "mmX7GUoXq2wVcbnrnFJrGKsGR14fXiGbD9",
  "scriptPubKey": "76a91441d83eaffbf80f82dee4c152de59a38ffd0b602188ac",
  "ismine": true,
  "solvable": true,
  "desc": "pkh([f004311c/0'/0'/2']0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b)#t3g5mjk9",
  "iswatchonly": false,
  "isscript": false,
  "iswitness": false,
  "pubkey": "0315a0aeb37634a71ede72d903acae4c6efa77f3423dcbcd6de3e13d9fd989438b",
  "iscompressed": true,
  "ischange": false,
  "timestamp": 1594835792,
  "hdkeypath": "m/0'/0'/2'",
  "hdseedid": "f058372260f71fea37f7ecab9e4c5dc25dc11eac",
  "hdmasterfingerprint": "f004311c",
  "labels": [
    ""
  ]
}

Descobrir essa assinatura, no entanto, requer que entendamos os meandros de como as transações do Bitcoin são criadas. Portanto, vamos deixar isso como sendo um estudo avançado para você leitor: criando uma transação de bitcoin-cli para "resolver" o UTXO é a melhor solução para isso neste momento.

Resumo: Programando um P2PKH

Enviar para um endereço P2PKH foi relativamente fácil quando estávamos usando o bitcoin-cli. Examinando o script do Bitcoin subjacente nos revela as funções criptográficas que estavam implícitas no financiamento da transação: como o UTXO foi desbloqueado com uma assinatura e uma chave pública.

O Que Vem Depois?

Vamos continuar "Apresentando Scripts no Bitcoin" na seção §9.5: Programando um P2WPKH.