Uma Introdução ao Bitcoin Script
P√°gina Inicial
Artigos
Uma Introdução ao Bitcoin Script

Uma Introdução ao Bitcoin Script

Avançado
Publicado em Jul 10, 2020Atualizado em Jan 18, 2022
13m

Introdução

O Bitcoin costuma ser chamado tamb√©m de dinheiro program√°vel. Suas propriedades digitais permitem aos usu√°rios um alto grau de flexibilidade quando se trata de definir condi√ß√Ķes em rela√ß√£o ao gasto dos fundos.¬†
Quando falamos sobre Bitcoin, tamb√©m falamos de carteiras e moedas. Mas tamb√©m podemos pensar em carteiras como chaves, moedas como cheques e a blockchain como uma sequ√™ncia de muitas fileiras de cofres trancados. Cada cofre possui uma ranhura estreita, de modo que qualquer pessoa pode depositar cheques ou visualizar seu conte√ļdo. No entanto, somente o portador da chave tem acesso ao interior do cofre.

Quando o portador da chave deseja enviar dinheiro a outra pessoa, ele destranca o cofre. Ele faz um novo cheque que faz referência ao anterior (que é então destruído) e o tranca em outro cofre, que o destinatário pode abrir. Depois disso, um novo destinatário pode repetir o processo.

Neste artigo, discutiremos sobre o Script, a linguagem de programação interpretada por nodes (nós) na rede Bitcoin. O Script é o que governa o mecanismo de bloqueio/desbloqueio mencionado no exemplo dos cofres.


Como funciona o Bitcoin?

Ainda sobre nossa analogia acima, podemos dizer que existem duas partes em cada transa√ß√£o ‚Äď uma chave e uma fechadura. Voc√™ usa sua chave para abrir o cofre que cont√©m o cheque a ser enviado. Em seguida, adiciona um novo cheque a um novo cofre, com um cadeado diferente. Para usar o novo cheque, ser√° necess√°ria uma outra chave.
Simples assim. Podemos encontrar algumas varia√ß√Ķes nos tipos de fechaduras de cada sistema. Alguns cofres podem exigir que voc√™ forne√ßa m√ļltiplas chaves. Outros, que voc√™ prove que sabe um segredo. Existem diversas condi√ß√Ķes que podem ser definidas.¬†
Nossa chave é o que chamamos de scriptSig. A fechadura é a scriptPubKey. Se examinarmos esses componentes, veremos que eles são, na verdade, bits de dados e blocos de códigos. Quando combinados, eles criam um pequeno programa.

Quando você faz uma transação, está transmitindo essa combinação para a rede. Cada node que a recebe, fará uma verificação do programa, que informa se a transação é válida ou não. Caso não seja válida, a transação será descartada e você não poderá gastar os fundos bloqueados.

Os cheques (moedas) que voc√™ mant√©m s√£o chamados de unspent transaction outputs (UTXOs), ou seja, outputs (sa√≠das) de transa√ß√Ķes n√£o gastas. Os fundos podem ser usados por qualquer pessoa que forne√ßa a chave correspondente √† fechadura. Mais especificamente, a chave √© o scriptSig e a fechadura √© o scriptPubKey.
Se os UTXOs estiverem em sua carteira, eles provavelmente ter√£o uma condi√ß√£o que diz somente a pessoa capaz de provar a propriedade desta chave p√ļblica pode desbloquear esses fundos. Para desbloque√°-los, voc√™ fornece um scriptSig que inclui uma assinatura digital, usando a chave privada associada √† chave p√ļblica especificada no scriptPubKey. Tudo isso ficar√° mais claro em breve.


Entendendo o stack do Bitcoin

O Script √© conhecido como uma linguagem stack-based. Isso significa que, quando lemos um conjunto de instru√ß√Ķes, as colocamos no que pode ser considerado uma coluna vertical. Por exemplo, a lista A, B, C pode ser organizada em uma pilha (stack) com A na parte inferior e C no topo. Quando recebemos determinadas instru√ß√Ķes, operamos em um ou mais elementos, come√ßando do topo do stack.


Elementos A, B e C sendo adicionados e ‚Äúretirados‚ÄĚ do stack.


Podemos distinguir entre os dados (como assinaturas, hashes e chaves p√ļblicas) e as instru√ß√Ķes (ou opcodes). As instru√ß√Ķes removem dados e fazem algo com eles. Temos abaixo um exemplo muito simples de um script:
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
Em vermelho, temos os dados e em azul, os opcodes. Lemos da esquerda para a direita, então primeiro colocamos a string <xyz> no stack (na pilha). O próximo é o opcode <md5 hasher>. Este não existe no sistema Bitcoin, mas digamos que ele remove o elemento do topo do stack (<xyz>) e faz o hash usando o algoritmo MD5. Em seguida, o output (saída) é adicionado de volta ao stack. O output aqui é d16fb36f0911f878998c136191af705e.
Que coincidência! Nosso próximo elemento a ser adicionado é <d16fb36f0911f878998c136191af705e>, então agora nosso stack tem dois elementos idênticos. Por fim, o <check if equal> destaca dois elementos do topo e verifica se eles são iguais. Se forem, ele adiciona <1> ao stack. Caso contrário, ele adiciona <0>. 
Chegamos ao final da nossa lista de instru√ß√Ķes. Nosso script poderia ter falhado de duas maneiras ‚Äď se o elemento restante fosse zero, ou se um dos operadores provocasse uma falha devido a condi√ß√Ķes n√£o atendidas. No exemplo, n√£o t√≠nhamos nenhum operador desse tipo e obtivemos um elemento resultante diferente de zero (<1>), ent√£o o script do exemplo √© v√°lido. Essas regras tamb√©m se aplicam a transa√ß√Ķes reais de Bitcoin.

Esse foi apenas um programa imagin√°rio. Vejamos alguns exemplos reais.


Pay-to-Pubkey (P2PK)

O script Pay-to-Pubkey (P2PK) √© incrivelmente simples. Envolve o bloqueio e v√≠nculo de fundos a uma chave p√ļblica espec√≠fica. Se quiser receber fundos atrav√©s deste m√©todo, dever√° fornecer ao remetente sua chave p√ļblica, em vez de um endere√ßo Bitcoin.¬†

A primeira transação entre Satoshi Nakamoto e Hal Finney em 2009 foi com script P2PK. Essa estrutura era muito usada nos primeiros dias do Bitcoin, mas atualmente, foi substituída em larga escala pelo Pay-to-Pubkey-Hash (P2PKH). 
O script de bloqueio para uma transa√ß√£o P2PK segue o formato <public key>¬†OP_CHECKSIG. Muito simples. Voc√™ deve ter imaginado que o OP_CHECKSIG verifica se h√° uma assinatura correspondente √† chave p√ļblica fornecida. Sendo assim, nosso scriptSig ser√° um <signature> simples. Lembre-se de que o scriptSig √© a chave da fechadura.



Uma assinatura √© adicionada ao stack, seguida por uma chave p√ļblica. O OP_CHECKSIG extrai os dois e verifica a assinatura em rela√ß√£o √† chave p√ļblica. Se forem correspondentes, um <1> ser√° adicionado ao stack. Caso contr√°rio, se adiciona um <0>.

Por motivos que explicaremos na próxima seção, o P2PK não é muito utilizado atualmente.


Pay-to-Pubkey-Hash (P2PKH)

O script Pay-to-Pubkey-Hash (P2PKH) é o tipo de transação mais comum atualmente. A menos que você esteja fazendo o download de um software antigo, é bem provável que sua carteira irá usar esse tipo, por padrão.

O scriptPubKey do P2PKH é o seguinte:

OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG

Antes de introduzirmos o scriptSig, vamos analisar a função dos novos opcodes:


OP_DUP

O OP_DUP extrai o primeiro elemento e o duplica. Em seguida, ele adiciona ambos de volta ao stack. O objetivo desta etapa √© criar uma c√≥pia com a qual seja poss√≠vel realizar opera√ß√Ķes, sem modificar o elemento original.


OP_HASH160

Esse script extrai o primeiro elemento e faz hash duas vezes com ele. A primeira etapa faz hash com o algoritmo SHA-256. Em seguida, é feito outro hash com o output (saída) do SHA-256, usando o algoritmo RIPEMD-160. O output resultante é adicionado de volta ao stack.


OP_EQUALVERIFY

O OP_EQUALVERIFY combina dois outros operadores ‚Äď OP_EQUAL e OP_VERIFY. O operador OP_EQUAL extrai dois elementos e verifica se eles s√£o id√™nticos. Se forem, ele adiciona 1 ao stack. Caso contr√°rio, adiciona um 0. O OP_VERIFY verifica se o elemento superior e √© True (ou seja, diferente de zero). Se n√£o for, a transa√ß√£o falhar√°. Combinando os dois operadores, o OP_EQUALVERIFY provoca a falha da transa√ß√£o caso os dois elementos do topo do stack n√£o sejam correspondentes.

Desta vez, o scriptSig ser√° o seguinte:

<signature> <public key>

√Č necess√°rio fornecer uma assinatura e a chave p√ļblica correspondente para desbloquear os outputs (sa√≠das) P2PKH.



O GIF acima representa o que acontece. N√£o √© muito diferente de um script P2PK. Estamos apenas adicionando uma etapa extra para verificar se a chave p√ļblica corresponde ao hash no script.

Entretanto, devemos fazer uma observa√ß√£o. Em um script de bloqueio P2PKH, a chave p√ļblica n√£o √© vis√≠vel ‚Äď s√≥ √© poss√≠vel ver seu hash. Se usarmos um explorer de blockchain e analisarmos um output P2PKH que n√£o foi gasto, n√£o ser√° poss√≠vel determinar a chave p√ļblica. Ela s√≥ √© revelada quando o receptor decide transferir os fundos.
Isso tem algumas vantagens. A primeira √© que o hash da chave p√ļblica √© mais f√°cil de transmitir do que uma chave p√ļblica completa. Satoshi o lan√ßou em 2009 por esse exato motivo. O hash de chave p√ļblica √© o que hoje conhecemos como endere√ßo Bitcoin.
A segunda vantagem √© que os hashes de chave p√ļblica podem fornecer uma camada adicional de seguran√ßa contra a computadores qu√Ęnticos. Como a chave p√ļblica n√£o √© conhecida at√© que os fundos sejam gastos, √© ainda mais dif√≠cil de se descobrir a chave privada. Seria necess√°rio reverter as duas etapas de hashing (RIPEMD-160 e SHA-256) para obt√™-la.



Pay-to-Script-Hash (P2SH)

O Pay-to-Script-Hash (P2SH) representa um desenvolvimento muito interessante para o Bitcoin. Ele permite que o remetente bloqueie fundos no hash de um script ‚Äď n√£o √© necess√°rio saber o que o script realmente faz. Usaremos o seguinte hash SHA-256 como exemplo:

e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1

Voc√™ n√£o precisa saber o input do hash para bloquear fundos nele. No entanto, quem gasta os fundos, precisa fornecer o script usado para fazer o hash e precisa satisfazer as condi√ß√Ķes desse script.

O hash acima foi criado do seguinte script:

<multiply by 2> <4> <check if equal>

Se você quiser gastar as moedas vinculadas a esse scriptPubKey, não basta fornecer os comandos. Você também precisa de um scriptSig que faça com que o script concluído seja avaliado como True. Neste exemplo, é um elemento que você <multiply by 2> (multiplica por dois) para dar um resultado de <4>. Claro, isso significa que nosso scriptSig é apenas <2>.

Na realidade, o scriptPubKey para um output P2SH seria:

OP_HASH160 <redeemScript hash> OP_EQUAL

N√£o h√° novos operadores aqui. Mas, temos o <redeemScript hash> como um novo elemento. Como o nome sugere, √© um hash do script que precisamos fornecer para resgatar fundos (chamado de redeemScript). O scriptSig mudar√° dependendo do redeemScript. Geralmente, no entanto, voc√™ perceber√° que se trata de uma combina√ß√£o de assinaturas e das chaves p√ļblicas anexadas, seguido pelo (obrigat√≥rio) redeemScript:

<signature> <public key> <redeemScript>

Nossa avaliação é um pouco diferente da execução de stack que vimos até agora. São duas etapas. A primeira simplesmente verifica se você forneceu o hash correto. 



Você verá que não fazemos nada com os elementos que precedem o redeemScript. Eles não são usados neste momento. Chegamos ao final deste miniprograma e o elemento do topo é diferente de zero. Isso significa que ele é válido.

Mas ainda n√£o terminamos. Os nodes da rede reconhecem esta estrutura como P2SH, ent√£o os elementos do scriptSig est√£o em modeo de espera, em outro stack. √Č neste momento que a assinatura e a chave p√ļblica ser√£o utilizadas.
At√© agora, tratamos o redeemScript como um elemento. Mas agora, o interpretaremos como instru√ß√Ķes. Vamos usar o exemplo de um script de bloqueio P2PKH, para o qual devemos fornecer <signature> e <public key> que correspondem a um <public key hash> dentro do <redeemScript>.



Depois que o redeemScript for expandido, podemos ver que temos uma situação exatamente igual a uma transação P2PKH normal. A partir deste ponto, realizamos o procedimento usual.

Demonstramos aqui o que é chamado de script P2SH(P2PKH), mas é improvável que você encontre um desses por aí. Nada o impede de fazer um, mas ele não oferece benefícios adicionais e acaba ocupando mais espaço em um bloco (e portanto, custa mais).

Geralmente, o P2SH √© √ļtil para coisas como transa√ß√Ķes compat√≠veis com multisignature ou SegWit¬†. Muitas vezes, transa√ß√Ķes multisig s√£o muito grandes, pois podem exigir v√°rias chaves. Antes da implementa√ß√£o do Pay-to-Script-Hash, o remetente precisava listar todas as chaves p√ļblicas poss√≠veis em seu script de bloqueio.¬†

Mas com o P2SH, n√£o importa qu√£o complexas sejam as condi√ß√Ķes de gasto. O hash do redeemScript ter√° sempre um tamanho fixo. Os custos s√£o, portanto, repassados ao(s) usu√°rio(s) que desejam desbloquear o script de bloqueio.

A compatibilidade SegWit √© outro caso em que o P2SH √© √ļtil (veremos na pr√≥xima se√ß√£o, detalhes sobre a estrutura da transa√ß√£o). O SegWit foi um soft fork que resultou em uma mudan√ßa nos formatos de bloco/transa√ß√£o. Por ser um opt-in upgrade (atualiza√ß√£o opcional), nem todo software de carteira reconhece essas altera√ß√Ķes.

Isso n√£o importa se os clientes agruparem o hash de script SegWit no P2SH. Como acontece com todas as transa√ß√Ķes deste tipo, n√£o √© necess√°rio saber qual √© o redeemScript de desbloqueio.¬†


Transa√ß√Ķes SegWit (P2WPKH e P2WSH)

Para uma introdução mais abrangente sobre SegWit, consulte o Guia para iniciantes sobre Segregated Witness (SegWit).
Para entender o formato da transação no SegWit, você só precisa saber que não temos mais somente um scriptSig e um scriptPubKey. Agora, temos também um novo campo chamado witness (testemunha). Os dados utilizados para manter o scriptSig são movidos para o witness, portanto, o scriptSig fica vazio.

Caso voc√™ encontre endere√ßos que come√ßam com ‚Äėbc1‚Äô, s√£o o que chamamos de SegWit-nativos (diferente dos simplesmente compat√≠veis com SegWit, que come√ßam com ‚Äė3‚Äô, pois s√£o endere√ßos P2SH).


Pay-to-Witness-Pubkey-Hash (P2WPKH)

Pay-to-Witness-Pubkey-Hash (P2WPKH) é a versão SegWit do P2PKH. O witness será algo como:

<signature> <public key>

Você perceberá que este é igual ao scriptSig do P2PKH. Aqui, o scriptSig está vazio. Já o scriptPubKey será o seguinte:

<OP_0> <public key hash>

Parece um pouco estranho, n√£o √©? Onde est√£o os opcodes para permitir a compara√ß√£o da assinatura, da chave p√ļblica e do hash?

Não estamos mostrando operadores adicionais aqui, pois os nodes que recebem a transação sabem o que fazer com ela, com base no comprimento do <public key hash>. Eles calcularão o comprimento e entenderão que a execução deve ser feita da mesma forma que a boa e velha transação P2PKH.
Nodes n√£o atualizados n√£o sabem como interpretar a transa√ß√£o dessa maneira, mas isso n√£o importa. Sob as regras antigas, n√£o h√° witness, ent√£o √© feita a leitura de um scriptSig vazio e de outros dados. Os nodes avaliam essas informa√ß√Ķes e marcam como v√°lidas ‚Äď para os nodes, qualquer um pode gastar o output. √Č por isso que o SegWit √© considerado um soft fork compat√≠vel com vers√Ķes anteriores.


Pay-to-Witness-Script-Hash (P2WSH)

Pay-to-Witness-Script Hash (P2WSH) é o novo P2SH. Se você chegou até aqui, provavelmente é capaz de imaginar como será seu formato, mas iremos examiná-lo de qualquer forma. Nosso witness é o que normalmente colocamos no scriptSig. Um exemplo de P2WSH que envolve uma transação P2PKH seria:

<signature 1> <public key>

Aqui est√° nosso scriptPubKey:

<OP_0> <script hash>

As mesmas regras est√£o em vigor. Os nodes SegWit fazem a leitura do comprimento do hash do script e determinam que ser√° um output P2WSH, avaliado de forma semelhante ao P2SH. Enquanto isso, os nodes antigos consideram que se trata, simplesmente, de um output que qualquer um pode gastar.


Considera√ß√Ķes finais

Neste artigo, aprendemos um pouco sobre a construção de blocos de Bitcoin. Vamos fazer um breve resumo:


Tipo de ScriptDescrição

Pay-to-Pubkey (P2PK)

Bloqueia fundos vinculados a uma determinada chave p√ļblica

Pay-to-Pubkey-Hash (P2PKH)

Bloqueia fundos vinculados a um determinado hash de chave p√ļblica (como um endere√ßo)

Pay-to-Script-Hash (P2SH)

Bloqueia fundos vinculados ao hash de um script que o destinat√°rio pode fornecer

Pay-to-Witness-Pubkey-Hash (P2WPKH)

Vers√£o SegWit do P2PK

Pay-to-Witness-Script-Hash (P2WSH)

Vers√£o SegWit do P2SH


Depois de aprender mais sobre o sistema Bitcoin, voc√™ come√ßa a entender por que ele tem tanto potencial. As transa√ß√Ķes podem ser feitas por muitos componentes diferentes. Ao manipular esses blocos de constru√ß√£o, os usu√°rios t√™m uma flexibilidade muito grande quando se trata de definir as condi√ß√Ķes sobre como e quando os fundos podem ser gastos.