|
| 1 | +# 12.1: Usando Condicionais no Script |
| 2 | + |
| 3 | +Há um aspecto importante na criação de Script de Bitcoin que é crucial para expandir o seu verdadeiro poder. Os condicionais permitem que criemos vários caminhos de execução. |
| 4 | + |
| 5 | +## Entendendo as Verificações |
| 6 | + |
| 7 | +Já vimos um condicional dentro do script, o ```op_verify``` (0x69). Ele retira o item superior na pilha e verifica se é verdade. Se não for, _ele termina a execução do script_. |
| 8 | + |
| 9 | +A verificação é geralmente incorporada em outros opcodes. Já vimos o ```OP_EQUALVERIFY``` (0xad), o ```OP_CHECKLOCKTIMEVERIFY``` (0xb1) e o ```OP_CHECKSEQUENCEVERIFY``` (0xb2). Cada um desses opcodes faz nossa ação central (equal, checklocktime ou checksequence) e então faz uma verificação posteriormente. Os outros opcodes de verificação que ainda não vimos são: ```OP_NUMEQUALVERIFY``` (0x9d), ```OP_CHECKSIGVERIFY``` (0xad), e ```OP_CHECKMULTISIGVERIFY``` (0xaf). |
| 10 | + |
| 11 | +Então, como o ```OP_VERIFY``` é um condicional? É o tipo mais poderoso de condicional. Usando o ```OP_VERIFY```, _se_ uma condição é verdadeira, o script continua executando, _senão_ o script pára a execução. É assim que verificamos as condições que são absolutamente necessárias para que um script tenha sucesso. Por exemplo, o script P2PKH (```OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG```) tem duas condições necessárias: (1) a chave pública fornecida precisa corresponder ao hash da chave pública e; (2) a assinatura fornecida precisa corresponder à essa chave pública. Um ```OP_EQUALVERIFY``` é usado para a comparação do hash da chave pública e a chave pública do hash porque é uma condição absolutamente necessária. Não _queremos_ que o script continue caso isto falhe. |
| 12 | + |
| 13 | +Podemos notar que não há ```OP_VERIFY``` no final deste script (ou da maioria dos demais), apesar da condição final também ser necessária. Isso porque o Bitcoin efetivamente faz um ```OP_VERIFY``` no final de cada script, para garantir que o resultado final da pilha seja verdadeiro. Não podemos fazer um ```OP_VERIFY``` antes do final do script, porque precisamos deixar algo na pilha para ser testado! |
| 14 | + |
| 15 | +## Compreendendo o If/Then (Se/Então) |
| 16 | + |
| 17 | +O outro condicional principal no script do Bitcoin é o clássico ```OP_IF``` (0x63) / ```OP_ELSE``` (0x67) / ```OP_ENDIF``` (0x68). Este é o controle típico de fluxo: se o ```OP_IF``` detectar uma afirmação verdadeira, ele executa o bloco abaixo dele, caso contrário, se houver um ```OP_ELSE```, ele o executa; e o ```OP_ENDIF``` marca o final do bloco. |
| 18 | + |
| 19 | +> :warning: **AVISO:** Estes condicionais tecnicamente são opcodes também, mas como são pequenos números, vamos deixar o prefixo do ```OP_``` desligado para manter a brevidade e a clareza. Assim, vamos escrever ```IF```, ```ELSE```, e ```ENDIF``` ao invés de ```OP_IF```, ```OP_ELSE```, e ```OP_ENDIF```. |
| 20 | +
|
| 21 | +### Compreendendo a Ordem do If/Then |
| 22 | + |
| 23 | +Existem duas grandes sacadas nos condicionais. Eles dificultam a leitura e determinam os scripts se não tivermos cuidado. |
| 24 | + |
| 25 | +Primeiro, o condicional ```IF``` verifica a verdade do que é _antes dele_ (em outras palavras, o que está na pilha), e não o que está depois dele. |
| 26 | + |
| 27 | +Segundo, o condicional ```IF``` tende a estar no script de bloqueio e o que é verificado tende a estar no script de desbloqueio. |
| 28 | + |
| 29 | +Claro, podemos dizer, é assim que funciona o Script do Bitcoin. Condicionais usam notação polonesa reversa e adotam o paradigma padrão de desbloqueio/bloqueio, assim como todos os scripts do bitcoin. Isso é tudo verdade, mas também é o contrário da maneira padrão de ler-se condicionais IF/ELSE em outras linguagens de programação. Assim, é fácil lermos errado, inconscientemente, os condicionais do Bitcoin. |
| 30 | + |
| 31 | +Vamos observar o seguinte código: `IF OP_DUP OP_HASH160 <pubKeyHashA> ELSE OP_DUP OP_HASH160 <pubKeyHashB> ENDIF OP_EQUALVERIFY OP_CHECKSIG`. |
| 32 | + |
| 33 | +Olhando para os condicionais na notação do prefixo podemos ler isso da seguinte maneira: |
| 34 | +``` |
| 35 | +IF (OP_DUP) THEN |
| 36 | + OP_HASH160 |
| 37 | + OP_PUSHDATA <pubKeyHashA> |
| 38 | +ELSE |
| 39 | + OP_DUP |
| 40 | + OP_HASH160 |
| 41 | + OP_PUSHDATA <pubKeyHashB> |
| 42 | +ENDIF |
| 43 | + OP_EQUALVERIFY |
| 44 | + OP_CHECKSIG |
| 45 | +``` |
| 46 | +Então, podemos pensar, se o ```OP_DUP``` é verdadeiro, então nós vamos fazer o primeiro bloco, senão, o segundo. Mas isso não faz sentido! Por que o ```OP_DUP``` não executaria com sucesso?! |
| 47 | + |
| 48 | +E, de fato, não faz nenhum sentido, porque acidentalmente lemos a declaração usando a notação errada. A leitura correta é: |
| 49 | +``` |
| 50 | +IF |
| 51 | + OP_DUP |
| 52 | + OP_HASH160 |
| 53 | + OP_PUSHDATA <pubKeyHashA> |
| 54 | +ELSE |
| 55 | + OP_DUP |
| 56 | + OP_HASH160 |
| 57 | + OP_PUSHDATA <pubKeyHashB> |
| 58 | +ENDIF |
| 59 | + OP_EQUALVERIFY |
| 60 | + OP_CHECKSIG |
| 61 | +``` |
| 62 | +A declaração que avaliará para ```True``` ou ```False``` é colocada na pilha _antes_ de executar o ```IF```, então o bloco correto do código será executado com base naquele resultado. |
| 63 | + |
| 64 | +Este exemplo específico de código é destinado a um simples multisig 1-de-2. O proprietário da ```<privKeyA>``` colocaria ```<signatureA> <pubKeyA> TRUE``` no script de desbloqueio, enquanto o proprietário da ```<privKeyB>``` colocaria ```<signatureB> <pubKeyB> FALSE``` no script de desbloqueio. Aquele que for rastreado como ```TRUE``` ou ```FALSE``` é o que é verificado pela instrução ```IF```/```ELSE```. Ele conta ao script qual o hash da chave pública é para verificar, então o ```OP_EQUALVERIFY``` e o ```OP_CHECKSIG``` no final fazem o verdadeiro trabalho. |
| 65 | + |
| 66 | +### Executando um If/Then com Multisig |
| 67 | + |
| 68 | +Com uma compreensão central dos condicionais do Bitcoin, estamos prontos para executar scripts os utilizando. Nós vamos começar criando uma ligeira variante do multisig 1-de-2 do exemplo, onde nossos usuários não precisam lembrar se eles são ```TRUE``` ou ```FALSE```. Ao invés disso, se necessário, o script verifica os hashes de chave pública, apenas exigindo um único sucesso: |
| 69 | +``` |
| 70 | +OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL |
| 71 | +IF |
| 72 | + OP_CHECKSIG |
| 73 | +ELSE |
| 74 | + OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG |
| 75 | +ENDIF |
| 76 | +``` |
| 77 | +Precisamos lembrar da notação polonesa reversa! Aquela instrução ```IF``` está se referindo ao ```OP_EQUAL``` antes dela, não ao `OP_CHECKSIG` posterior! |
| 78 | + |
| 79 | +#### Executando a Parte Verdadeira |
| 80 | + |
| 81 | +Veja como é executado se desbloquearmos com ```<signatureA> <pubKeyA>```: |
| 82 | +``` |
| 83 | +Script: <signatureA> <pubKeyA> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 84 | +Stack: [ ] |
| 85 | +``` |
| 86 | +Primeiro, colocamos as constantes na pilha: |
| 87 | +``` |
| 88 | +Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 89 | +Stack: [ <signatureA> <pubKeyA> ] |
| 90 | +``` |
| 91 | +Em seguida, nós executamos os primeiros comandos óbvios, ```OP_DUP``` e ```OP_HASH160```, e colocamos outra constante: |
| 92 | +``` |
| 93 | +Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 94 | +Running: <pubKeyA> OP_DUP |
| 95 | +Stack: [ <signatureA> <pubKeyA> <pubKeyA> ] |
| 96 | +
|
| 97 | +Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 98 | +Running: <pubKeyA> OP_HASH160 |
| 99 | +Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> ] |
| 100 | +
|
| 101 | +Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 102 | +Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> <pubKeyHashA> ] |
| 103 | +``` |
| 104 | +Em seguida, executamos o ```OP_EQUAL```, que é o que vai alimentar o ```IF```: |
| 105 | +``` |
| 106 | +Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 107 | +Running: <pubKeyHashA> <pubKeyHashA> OP_EQUAL |
| 108 | +Stack: [ <signatureA> <pubKeyA> True ] |
| 109 | +``` |
| 110 | +Agora, o ```IF``` executa, e desde que haja um ```TRUE```, ele só executa o primeiro bloco, eliminando todo o resto: |
| 111 | +``` |
| 112 | +Script: OP_CHECKSIG |
| 113 | +Running: True IF |
| 114 | +Stack: [ <signatureA> <pubKeyA> ] |
| 115 | +``` |
| 116 | +E o ```OP_CHECKSIG``` acabará sendo ```TRUE``` também: |
| 117 | +``` |
| 118 | +Script: |
| 119 | +Running: <signatureA> <pubKeyA> OP_CHECKSIG |
| 120 | +Stack: [ True ] |
| 121 | +``` |
| 122 | + |
| 123 | +#### Executando a Parte Falsa |
| 124 | + |
| 125 | +Veja como ele iria executar se fôssemos desbloquear com ```<signatureB> <pubKeyB>```: |
| 126 | +``` |
| 127 | +Script: <signatureB> <pubKeyB> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 128 | +Stack: [ ] |
| 129 | +``` |
| 130 | +Primeiro, colocamos as constantes na pilha: |
| 131 | +``` |
| 132 | +Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 133 | +Stack: [ <signatureB> <pubKeyB> ] |
| 134 | +``` |
| 135 | +Em seguida, executamos os primeiros comandos óbvios, ```OP_DUP``` e ```OP_HASH160```, e adicionamos outra constante: |
| 136 | +``` |
| 137 | +Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 138 | +Running: <pubKeyB> OP_DUP |
| 139 | +Stack: [ <signatureB> <pubKeyB> <pubKeyB> ] |
| 140 | +
|
| 141 | +Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 142 | +Running: <pubKeyB> OP_HASH160 |
| 143 | +Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ] |
| 144 | +
|
| 145 | +Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 146 | +Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashA> ] |
| 147 | +``` |
| 148 | +Em seguida, executamos o ```OP_EQUAL```, que é o que vai alimentar o ```IF```: |
| 149 | +``` |
| 150 | +Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF |
| 151 | +Running: <pubKeyHashB> <pubKeyHashA> OP_EQUAL |
| 152 | +Stack: [ <signatureB> <pubKeyB> False ] |
| 153 | +``` |
| 154 | +Uhul! O resultado foi ```FALSE``` porque o ```<pubKeyHashB>``` não é igual ao ```<pubKeyHashA>```. Agora, quando o ```IF``` for executado, ele vai pular para a instrução ```ELSE```: |
| 155 | +``` |
| 156 | +Script: OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG |
| 157 | +Running: False IF |
| 158 | +Stack: [ <signatureB> <pubKeyB> ] |
| 159 | +``` |
| 160 | +Depois, passamos por todo o imbróglio, começando com outro ```OP_DUP```, mas eventualmente o testando usando outro ```pubKeyHash```: |
| 161 | +``` |
| 162 | +Script: OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG |
| 163 | +Running: <pubKeyB> OP_DUP |
| 164 | +Stack: [ <signatureB> <pubKeyB> <pubKeyB> ] |
| 165 | +
|
| 166 | +Script: <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG |
| 167 | +Running: <pubKeyB> OP_HASH160 |
| 168 | +Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ] |
| 169 | +
|
| 170 | +Script: OP_EQUALVERIFY OP_CHECKSIG |
| 171 | +Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashB> ] |
| 172 | +
|
| 173 | +Script:OP_CHECKSIG |
| 174 | +Running: <pubKeyHashB> <pubKeyHashB> OP_EQUALVERIFY |
| 175 | +Stack: [ <signatureB> <pubKeyB> ] |
| 176 | +
|
| 177 | +Script: |
| 178 | +Running: <signatureB> <pubKeyB> OP_CHECKSIG |
| 179 | +Stack: [ True ] |
| 180 | +``` |
| 181 | +Isso provavelmente não é tão eficiente quanto um verdadeiro multisig do Bitcoin, mas é um bom exemplo de como os resultados adicionados à pilha devido a testes anteriores podem ser usados para alimentar condicionais futuros. Neste caso, é o fracasso da primeira assinatura que diz ao condicional que deve ir verificar a segunda. |
| 182 | + |
| 183 | +## Entendendo os Demais Condicionais |
| 184 | + |
| 185 | +Existem alguns outros condicionais para ser analisados. O maior deles é o ```OP_NOTIF``` (0x64), que é o oposto de ```OP_IF```. Ele executa o próximo bloco se o item superior for ```FALSE```. Um ```ELSE``` pode ser colocado junto, que como usual é executado se o primeiro bloco não for executado. Podemos ainda terminar com o ```OP_ENDIF```. |
| 186 | + |
| 187 | +Há também um ```OP_IFDUP``` (0x73), que duplica o item de pilha superior somente se o resultado não for 0. |
| 188 | + |
| 189 | +Essas opções são usadas com muito menos frequência do que a construção usando ```IF```/```ELSE```/```ENDIF```. |
| 190 | + |
| 191 | +## Resumo: Usando Condicionais no Script |
| 192 | + |
| 193 | +Os condicionais no script do Bitcoin permitem parar o script (usando o ```OP_VERIFY```) ou escolher diferentes ramos de execução (usando ```OP_IF```). No entanto, ler o ```OP_IF``` pode ser um pouco complicado. Precisamos lembrar de que é o item adicionado à pilha _antes_ do operador ```OP_IF``` ser executado que controla a sua execução. Esse item normalmente fará parte do script de desbloqueio (ou será um resultado direto de itens do script de desbloqueio). |
| 194 | + |
| 195 | +> :fire: ***Qual é o poder dos condicionais?*** Os condicionais do script são o principal bloco de construção no Bitcoin Script. Eles transformam os scripts simples e estáticos do Bitcoin em scripts de Bitcoin complexos e dinâmicos que podem avaliar de maneira diferente com base em diferentes momentos, diferentes circunstâncias ou diferentes entradas de usuário. Em outras palavras, eles são o último pilar dos contratos inteligentes. |
| 196 | +
|
| 197 | +## O Que Vem Depois? |
| 198 | + |
| 199 | +Vamos continuar "Expandindo os Scripts do Bitcoin" na seção [§12.2: Usando Outros Comandos no Script](12_2_using_other_script_commands.md). |
0 commit comments