mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-07 16:06:26 +00:00
Review 12_1
This commit is contained in:
parent
e612796ff8
commit
a0e422b75e
@ -1,32 +1,32 @@
|
||||
# 12.1: Usando condicionais no script
|
||||
# 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_.
|
||||
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 checkscence) 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).
|
||||
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 para 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 a 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 venha a falhar.
|
||||
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 (ou da maioria dos demais) script, apesar da condição final também ser necessária. Isso porque o Bitcoin efetivamente faz um ```OP_VERIFY``` no final de cada roteiro, 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!
|
||||
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!
|
||||
|
||||
## Entendendo o If/Then (Se/Então)
|
||||
## 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 do fluxo: Se o ```OP_IF``` detectar uma afirmação verdadeira, executa o bloco abaixo dele, caso contrário, se houver um ```OP_ELSE```, executa-o e; o ```OP_ENDIF``` marca o final do bloco.
|
||||
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```.
|
||||
|
||||
### Entendendo a Ordem do If/Then
|
||||
### 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 ```IF``` condicional verifica a verdade do que é _antes dele_ (em outras palavras, o que está na pilha), não o que está depois dele.
|
||||
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 ```IF``` condicional tende a estar no script de bloqueio e o que é verificado tende a estar no script de desbloqueio.
|
||||
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 vai ao contrário da maneira padrão que lemos IF/ELSE condicionais em outras linguagens de programação. Assim, é fácil lermos inconscientemente errado os condicionais do Bitcoin.
|
||||
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`.
|
||||
|
||||
@ -43,7 +43,7 @@ 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 daria verdadeiro?!
|
||||
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 é:
|
||||
```
|
||||
@ -59,13 +59,13 @@ 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 nesse resultado.
|
||||
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 uma 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.
|
||||
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 utilizando-os. Nós vamos começar, criando uma ligeira variante da 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:
|
||||
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
|
||||
@ -74,7 +74,7 @@ ELSE
|
||||
OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CHECKSIG
|
||||
ENDIF
|
||||
```
|
||||
Precisamos lembrar da notação polonesa reversa! Aquela instrução ```IF``` está referindo-se ao ```OP_EQUAL``` antes dela, não ao `OP_CHECKSIG` posterior!
|
||||
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
|
||||
|
||||
@ -88,7 +88,7 @@ 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:
|
||||
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
|
||||
@ -107,7 +107,7 @@ Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 <pubKeyHashB> OP_EQUALVERIFY OP_CH
|
||||
Running: <pubKeyHashA> <pubKeyHashA> OP_EQUAL
|
||||
Stack: [ <signatureA> <pubKeyA> True ]
|
||||
```
|
||||
Agora, o ```IF``` executa, e desde que seja um ```TRUE```, ele só executa o primeiro bloco, eliminando todo o resto:
|
||||
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
|
||||
@ -122,7 +122,7 @@ Stack: [ True ]
|
||||
|
||||
#### Executando a Parte Falsa
|
||||
|
||||
Veja como ele iria executar se fossemos desbloquear com ```<signatureB> <pubKeyB>```:
|
||||
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: [ ]
|
||||
@ -132,7 +132,7 @@ 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:
|
||||
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
|
||||
@ -178,7 +178,7 @@ 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 a pilha devido a testes anteriores podem ser usados para alimentar futuros condicionais. Neste caso, é o fracasso da primeira assinatura que diz a condicional que deve ir verificar a segunda.
|
||||
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
|
||||
|
||||
@ -188,12 +188,12 @@ Há também um ```OP_IFDUP``` (0x73), que duplica o item de pilha superior somen
|
||||
|
||||
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
|
||||
## Resumo: Usando Condicionais no Script
|
||||
|
||||
Os condicionais no script do Bitcoin permitem deter o script (usando o ```OP_VERIFY```) ou para escolher diferentes ramos de execução (usando ```OP_IF```). No entanto, a ler o ```OP_IF``` pode ser um pouco complicado. Precisamos lembrar de que é o item adicionado a 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).
|
||||
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 script do Bitcoin. 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.
|
||||
> :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).
|
||||
Vamos continuar "Expandindo os Scripts do Bitcoin" na seção [§12.2: Usando Outros Comandos no Script](12_2_using_other_script_commands.md).
|
Loading…
x
Reference in New Issue
Block a user