Script, el lenguaje de contratos inteligentes de Bitcoin
Bitcoin cuenta con un lenguaje para programar contratos inteligentes llamado Script, es utilizado en los mecanismos de bloqueo y desbloqueo que estudiamos en el Post de Transacciones. Script es un lenguaje de programación que no es “touring complete”, lo que quiere decir, que no utiliza sets de instrucciones complejas de ciclos y recursivas (que pueden llamarse a si mismas), este lenguaje esta basado en una estructura de pila (stack). Los stacks funcionan bajo un mecanismo de ultimas entradas, primeras salidas y asemejan una pila de libros en donde para acceder al elemento del fondo, primero tenemos que retirar los libros que se encuentran por encima. En la siguiente animación podemos ver el comportamiento de un stack.
Animación Stack
Script procesa las instrucciones, una por una, iniciando por la izquierda. Existen dos tipos de instrucciones: a) elementos y b) operaciones. Los elementos representan datos, típicamente llaves o firmas, cuando el Script se va procesando, como comentamos, de izquierda a derecha, y se encuentra un elemento, inmediatamente es empujado(hacer push) al interior del stack. Si por el contrario, lo que se procesa es un operador (denominados OP_CODEs), se ejecuta esa operación en particular. Existen distintos tipos de operaciones, todas ellas actúan sobre los datos, consumen de cero a n elementos del stack, y pueden, a su vez, hacer push de cero o varios elementos al stack. Al final de la ejecución del Script, el valor del tope del stack no debe ser cero para que el Script sea asumido como válido.
Revisemos y procesemos un ejemplo simple de un Script:
Asumamos que queremos un Script que cumpla con la siguiente ecuación:
5 + 2 = 7
el Script correspondiente sería:
5 2 OP_ADD 7 OP_EQUAL
Describamos el procesamiento del Script:
Iniciamos de izquierda a derecha:
-
procesamos el elemento 5 y lo enviamos al stack
-
procesamos el elemento 2 y lo enviamos al stack
-
procesamos el OP_CODE OP_ADD que lo que hace es tomar(hacer pop) los 2 elementos en el tope del stack, por lo que hace pop de 2 y después pop de 5, en ese orden, justamente asi funciona un stack, hacemos pop primero del último número del que insertamos al stack. A continuación procede a sumarlos y pone el resultado(hacer push) 7 en el tope del stack.
-
es el turno del operador OP_EQUAL, que lo que requiere es hacer pop de los dos elementos en el tope del stack, que son 7 y 7, los compara para ver si son iguales y hace un push de un cero si son distintos y un push de un uno si son iguales, en este caso se hace un push de un uno (1) porque ambos números son iguales.
-
Fin exitoso del Script
Veamos como usa Bitcoin los Scripts para bloquear/desbloquear salidas.
Como lo vimos en el Post de Transacciones, estas bloquean una salida con el mecanismo de bloqueo ScriptPubkey. Para poder ser utilizada, esta salida tiene que ser incorporada por una entrada que publique el mecanismo de desbloqueo en su ScriptSig, ambos mecanismos son Scripts. Los nombres ScriptPubkey, ScriptSig vienen de los inicios de Bitcoin en donde las Transacciones, en particular nos referimos a las salidas de las mismas, estaban basadas en la firma de la transacción y se colocaba la llave pública en el ScriptPubkey (por eso el nombre ScriptPubkey), para demostrar que se poseía la llave privada correspondiente. Posteriormente la salidas se desbloquean con entradas que contienen la firma de la transacción, con la misma llave privada que creó la salida de la transacción anterior que está utilizando. Por lo tanto si el creador de la nueva transacción puede crear un ScriptSig con la firma que utiliza la llave pública de la salida de la transacción anterior, entonces esa nueva entrada es considerada válida.
Tipos de salidas
Existen varios tipos de salidas que se han desarrollado con la evolución del software de Bitcoin:
Tipo | Descripción |
---|---|
P2PK | Pay to Public Key |
P2PKH | Pay to Public Key Hash |
P2SH | Pay to Script Hash |
P2WPKH | Pay to Witness Public Key Hash |
P2WSH | Pay to Witness Script Hash |
P2SH P2WPKH | Pay to Script Hash, Pay to Witness Public Key Hash |
P2SH P2WSH | Pay to Script Hash, Pay to Witness Script Hash |
P2TR | Pay to Taproot |
En este Post veremos las 2 primeras, en un Post posterior veremos Script avanzado. En lo que respecta a P2PK, este tipo de transacción ya no se recomienda porque ahora existen Transacciones mas eficientes y seguras, sin embargo veremos un ejemplo. Las salidas P2PKH es a lo que se le suele llamar una dirección legacy, el tema de direcciones lo veremos en un Post especial ya que es muy importante entender de donde salen las direcciones en Bitcoin y los tipos que existen.
P2PK Pay to Public Key
A este tipo de salida se le llama P2PK, Pago a una llave pública.
ScriptPubKey de la salida de la transacción anterior:
<Public Key> <OP_CHECKSIG>
ScriptSig de la entrada de la transacción que pretende gastar la salida de la transacción anterior:
<Signature>
Lo que hace el software de Bitcoin es poner ambos Scripts juntos pero en orden inverso para poderlos procesar(de hecho Bitcoin procesa primero cada Script por separado por temas de seguridad, pero para simplificarlo aquí lo veremos todo en un paso):
<Signature> <Public Key> <OP_CHECKSIG>
Después procede a ejecutar el script.
Iniciamos de izquierda a derecha:
- hacemos push al stack de la firma
<Signature>
- hacemos push al stack de la llave pública
<PubKey>
- procesamos el OP_CODE
OP_CHECKSIG
que lo que necesita es tomar los 2 últimos elementos del stack, a continuación procede a verificar la firma y si es correcta hace un push de un uno (1) al stack - fin exitoso del Script
Si el script es exitoso, la transacción se considera válida y el monto en bitcoin quedará asegurado con un nuevo ScriptPubkey en las salida correspondiente.
En la siguiente animación podemos ver el procesamiento del Script.
Animación Script P2PK
P2PKH Pay to Public Key Hash
El pago a un hash de llave pública P2PKH, surgió como una evolución natural del protocolo para hacer mas eficientes y seguras las Transacciones. Las llaves públicas consumen muchos Bytes y al estar en el ScriptPubkey son públicas lo que representaba un riesgo de seguridad mas alto. Básicamente, en el ScriptPubkey, la llave pública ya no se utiliza, si no un hash de dicha llave. Una diferencia importante a notar es que la llave pública se ha movido al ScriptSig. Veamos a detalle ambos Scripts.
ScriptPubkey
OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
ScriptSig
<signature> <public key>
Si combinamos los 2 Script nos quedaría lo siguiente, los vamos a poner uno en cada línea para facilitar su lectura:
<signature>
<public key>
OP_DUP
OP_HASH160
<pubKeyHash>
OP_EQUALVERIFY
OP_CHECKSIG
Describamos el procesamiento del Script:
- se hace un push al stack de la firma
<signature>
- se hace un push al stack de la llave pública
<public key>
- se procesa la operación
OP_DUP
, esta operación consulta el elemento tope del stack(no le hace un pop en este caso), lo duplica y hace un push al stack - la operación
OP_HASH160
toma (hace el pop) el último elemento del stack y realiza la operaciónhash160
del elemento y hace un push del resultado - se hace un push del
<pubKeyHash>
- la operación OP_EQUALVERIFY hace 2 pops,compara los 2 elementos y termina el Script si son distintos, o bien continúa normalmente si son iguales
- la operación OP_CHECKSIG hace pop de 2 elementos del stack, la llave pública y la firma, y valida que la firma sea la correcta, finalmente hace un push de uno (1) si la firma es valida o cero (0) si la firma es invalida
- El Script finaliza con el último valor del stack, determinando si fue un éxito o hubo un fallo
En la siguiente animación podemos ver el procesamiento del Script.
Animación Script P2PKH
Ahora ya entendemos como funciona Script para bloquear y desbloquear Transacciones de dos distintos tipos: P2PK y P2PKH. Sabemos que P2PK prácticamente ha quedado en desuso y que a las salidas P2PKH se les denomina Legacy. En un Post mas adelante hablaremos de Segregated Witness y su impacto en los nuevos tipos de salidas. No dudes en escribirme en Twitter para cualquier duda o comentario.