Merge pull request #386 from KoreaComK/chapter12

Chapter 12 Translated by @koreacomk need review
This commit is contained in:
Shannon Appelcline 2021-08-10 08:32:23 -10:00 committed by GitHub
commit e84a30cb58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 304 additions and 0 deletions

View File

@ -0,0 +1,20 @@
# Capítulo 12: Expandindo os Scripts do Bitcoin
Ainda há um pouco mais sobre os Scripts do Bitcoin que precisamos saber. As condicionais fornecem acesso total ao controle de fluxo, enquanto uma variedade de outros opcodes podem expandir nossas possibilidades.
## Objetivos Deste Capítulo
Depois de trabalhar neste capítulo, um desenvolvedor será capaz de:
* Decidir como usar os condicionais no script;
* Decidir como usar outros opcodes no script.
Os objetivos secundários do capítulo incluem a capacidade de:
* Compreender toda a gama de possibilidades de programação;
* Identificar como aprender mais sobre os opcodes.
## Tabela de Conteúdo
* [Seção 1: Usando Condicionais no Script](12_1_Using_Script_Conditionals.md)
* [Seção 2: Usando Outros Comandos no Script](12_2_Using_Other_Script_Commands.md)

View File

@ -0,0 +1,199 @@
# 12.1: Usando Condicionais no Script
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.
## Entendendo as Verificações
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_.
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).
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.
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!
## Compreendendo o If/Then (Se/Então)
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.
> :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```.
### Compreendendo a Ordem do If/Then
Existem duas grandes sacadas nos condicionais. Eles dificultam a leitura e determinam os scripts se não tivermos cuidado.
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.
Segundo, o condicional ```IF``` tende a estar no script de bloqueio e o que é verificado tende a estar no script de desbloqueio.
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.
Vamos observar o seguinte código: `IF OP_DUP OP_HASH160 <pubKeyHashA> ELSE OP_DUP OP_HASH160 <pubKeyHashB> ENDIF OP_EQUALVERIFY OP_CHECKSIG`.
Olhando para os condicionais na notação do prefixo podemos ler isso da seguinte maneira:
```
IF (OP_DUP) THEN
OP_HASH160
OP_PUSHDATA <pubKeyHashA>
ELSE
OP_DUP
OP_HASH160
OP_PUSHDATA <pubKeyHashB>
ENDIF
OP_EQUALVERIFY
OP_CHECKSIG
```
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?!
E, de fato, não faz nenhum sentido, porque acidentalmente lemos a declaração usando a notação errada. A leitura correta é:
```
IF
OP_DUP
OP_HASH160
OP_PUSHDATA <pubKeyHashA>
ELSE
OP_DUP
OP_HASH160
OP_PUSHDATA <pubKeyHashB>
ENDIF
OP_EQUALVERIFY
OP_CHECKSIG
```
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.
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.
### Executando um If/Then com Multisig
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:
```
OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL
IF
OP_CHECKSIG
ELSE
OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
ENDIF
```
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!
#### Executando a Parte Verdadeira
Veja como é executado se desbloquearmos com ```<signatureA> <pubKeyA>```:
```
Script: <signatureA> <pubKeyA> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ ]
```
Primeiro, colocamos as constantes na pilha:
```
Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ <signatureA> <pubKeyA> ]
```
Em seguida, nós executamos os primeiros comandos óbvios, ```OP_DUP``` e ```OP_HASH160```, e colocamos outra constante:
```
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyA> OP_DUP
Stack: [ <signatureA> <pubKeyA> <pubKeyA> ]
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyA> OP_HASH160
Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> ]
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ <signatureA> <pubKeyA> <pubKeyHashA> <pubKeyHashA> ]
```
Em seguida, executamos o ```OP_EQUAL```, que é o que vai alimentar o ```IF```:
```
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyHashA> <pubKeyHashA> OP_EQUAL
Stack: [ <signatureA> <pubKeyA> True ]
```
Agora, o ```IF``` executa, e desde que haja um ```TRUE```, ele só executa o primeiro bloco, eliminando todo o resto:
```
Script: OP_CHECKSIG
Running: True IF
Stack: [ <signatureA> <pubKeyA> ]
```
E o ```OP_CHECKSIG``` acabará sendo ```TRUE``` também:
```
Script:
Running: <signatureA> <pubKeyA> OP_CHECKSIG
Stack: [ True ]
```
#### Executando a Parte Falsa
Veja como ele iria executar se fôssemos desbloquear com ```<signatureB> <pubKeyB>```:
```
Script: <signatureB> <pubKeyB> OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ ]
```
Primeiro, colocamos as constantes na pilha:
```
Script: OP_DUP OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ <signatureB> <pubKeyB> ]
```
Em seguida, executamos os primeiros comandos óbvios, ```OP_DUP``` e ```OP_HASH160```, e adicionamos outra constante:
```
Script: OP_HASH160 <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyB> OP_DUP
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
Script: <pubKeyHashA> OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyB> OP_HASH160
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashA> ]
```
Em seguida, executamos o ```OP_EQUAL```, que é o que vai alimentar o ```IF```:
```
Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG ENDIF
Running: <pubKeyHashB> <pubKeyHashA> OP_EQUAL
Stack: [ <signatureB> <pubKeyB> False ]
```
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```:
```
Script: OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: False IF
Stack: [ <signatureB> <pubKeyB> ]
```
Depois, passamos por todo o imbróglio, começando com outro ```OP_DUP```, mas eventualmente o testando usando outro ```pubKeyHash```:
```
Script: OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKeyB> OP_DUP
Stack: [ <signatureB> <pubKeyB> <pubKeyB> ]
Script: <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
Running: <pubKeyB> OP_HASH160
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> ]
Script: OP_EQUALVERIFY OP_CHECKSIG
Stack: [ <signatureB> <pubKeyB> <pubKeyHashB> <pubKeyHashB> ]
Script:OP_CHECKSIG
Running: <pubKeyHashB> <pubKeyHashB> OP_EQUALVERIFY
Stack: [ <signatureB> <pubKeyB> ]
Script:
Running: <signatureB> <pubKeyB> OP_CHECKSIG
Stack: [ True ]
```
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.
## Entendendo os Demais Condicionais
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```.
Há também um ```OP_IFDUP``` (0x73), que duplica o item de pilha superior somente se o resultado não for 0.
Essas opções são usadas com muito menos frequência do que a construção usando ```IF```/```ELSE```/```ENDIF```.
## Resumo: Usando Condicionais no Script
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).
> :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.
## O Que Vem Depois?
Vamos continuar "Expandindo os Scripts do Bitcoin" na seção [§12.2: Usando Outros Comandos no Script](12_2_using_other_script_commands.md).

View File

@ -0,0 +1,85 @@
# 12.2: Usando Outros Comandos no Script
Provavelmente já temos em mãos a maioria dos opcodes do Bitcoin Script que iremos usar na maioria dos nossos scripts. No entanto, o Bitcoin Script oferece muito mais opções, o que pode vir a ser exatamente o que precisamos para criar o instrumento financeiro dos nossos sonhos.
Devemos consultar a [página do script do Bitcoin](https://en.bitcoin.it/wiki/script) para termos uma lista mais completa de todos esses e muitos outros comandos. Esta seção destaca apenas os opcodes mais notáveis.
## Entendendo os Opcodes Aritméticos
Os opcodes aritméticos manipulam ou testam números.
Manipulam um número:
* OP_1ADD (0x8b) - Adiciona uma unidade;
* OP_1SUB (0x8C) - Subtrai uma unidade;
* OP_NEGATE (0x8f) - Inverte o sinal do número;
* OP_ABS (0x90) - Torna o número positivo;
* OP_NOT (0x91) - Troca 1 por 0, senão 0.
Veja também: ```OP_0NOTEQUAL``` (0x92).
Manipulam dois números matematicamente:
* OP_ADD (0x93) - Adiciona dois números;
* OP_SUB (0x94) - Subtrai dois números;
* OP_MIN (0xA3) - Retorna o menor entre dois números;
* OP_MAX (0xA4) - Retorna o maior entre dois números.
Manipulam dois números logicamente:
* OP_BOOLAND (0x9a) - 1 se ambos os números não são 0, senão 0;
* OP_BOOLOR (0x9B) - 1 se qualquer número não é 0, senão 0.
Testa dois números:
* OP_NUMEQUAL (0x9C) - 1 se ambos os números forem iguais, senão 0;
* OP_LESSTHAN (0x9f) - 1 se o primeiro número for menor que o segundo, senão 0;
* OP_GREATERTHAN (0xA0) - 1 se o primeiro número for maior que o segundo, senão 0;
* OP_LESSTHANOREQUAL (0xA1) - 1 se o primeiro número for menor ou igual ao segundo, senão 0;
* OP_GREATERTHANOREQUAL (0xA2) - 1 se o primeiro número for maior ou igual a segundo, senão 0.
Veja também: ```OP_NUMEQUALVERIFY``` (0x9d) e ```OP_NUMNOTEQUAL``` (0x9e)
Testa três números:
* OP_WITHIN (0xA5) - 1 se um número estiver no intervalo de dois outros números.
## Compreendendo os Opcodes de Pilha
Há um número chocante de opcodes de pilha, mas além de ```OP_DROP```, ```OP_DUP```, e às vezes ```OP_SWAP```, eles geralmente não serão necessários se tivermos cuidado com a ordem da pilha. No entanto, aqui estão alguns dos mais interessantes:
* OP_DEPTH (0x74) - Aumenta o tamanho da pilha;
* OP_DROP (0x75) - Retira o item superior da pilha;
* OP_DUP (0x76) - Duplica o item superior da pilha;
* OP_PICK (0x79) - Duplica o enésimo item da pilha começando pelo topo;
* OP_ROLL (0x7a) - Move o enésimo item para o topo da pilha;
* OP_SWAP(0x7C) - Troca os dois principais itens da pilha.
Veja também: `OP_TOALTSTACK` (0x6b), `OP_FROMALTSTACK` (0x6c), `OP_2DROP` (0x6d), `OP_2DUP` (0x6e), `OP_3DUP` (0x6f), `OP_2OVER` (0x70), `OP_2ROT` (0x71), `OP_2SWAP` (0x72), `OP_IFDUP` (0x73), `OP_NIP` (0x77), `OP_OVER` (0x78), `OP_ROT` (0x7b), e `OP_TUCK` (0x7d).
## Compreendendo os Opcodes Criptográficos
Finalmente, uma variedade de opcodes para dar suporte ao hashing e à verificação de assinatura:
Hash:
* OP_RIPEMD160 (0xa6) — RIPEMD-160;
* OP_SHA1 (0xa7) — SHA-1;
* OP_SHA256 (0xa8) - SHA-256;
* OP_HASH160 (0xa9) — SHA-256 + RIPEMD-160;
* OP_HASH256 (0xaa) — SHA-256 + SHA-256.
Verifica as assinaturas:
* OP_CHECKSIG (0xac) - Verifica uma assinatura;
* OP_CHECKMULTISIG (0xae) - Verifica um multisig m-de-n.
Veja também: `OP_CODESEPARATOR` (0xab), `OP_CHECKSIGVERIFY` (0xad), e `OP_CHECKMULTISIGVERIFY` (0xaf).
## Resumo: Usando Outros Comandos no Script
O Bitcoin Script inclui uma ampla gama de opcodes aritméticos, de pilha e criptográficos. A maioria desses opcodes adicionais provavelmente não serão tão comuns quanto os discutidos nas seções anteriores, mas, no entanto, estão disponíveis caso precisemos utilizá-los para escrever nosso script!
## O Que Vem Depois?
Vamos avançar "Expandindo os Scripts do Bitcoin" com o [Capítulo 13: Projetando Scripts Reais no Bitcoin](13_0_Designing_real_bitcoin_scripts.md).