# 12.1: Usando scripts condicionales Hay un aspecto final del Scripting de Bitcoin que es crucial para desbloquear su verdadero poder: los condicionales le permiten crear varias rutas de ejecución. # Entienda VERIFY Ya ha visto un condicional en los scripts: `OP_VERIFY` (0x69). Quita el elemento superior de la pila y comprueba si es verdadero; si no, finaliza la ejecución del script. Verify generalmente se incorpora a otros códigos de operación. Ya ha visto `OP_EQUALVERIFY` (0xad),` OP_CHECKLOCKTIMEVERIFY` (0xb1) y `OP_CHECKSEQUENCEVERIFY` (0xb2). Cada uno de estos códigos de operación realiza su acción principal (comparar igualdad, verificar tiempo de bloqueo o secuencia de verificación) y luego realiza una verificación. Los otros códigos de operación de verificación que no ha visto son: `OP_NUMEQUALVERIFY` (0x9d),` OP_CHECKSIGVERIFY` (0xad) y `OP_CHECKMULTISIGVERIFY` (0xaf). Entonces, ¿cómo es `OP_VERIFY` un condicional? Es el tipo de condicional más poderoso. Usando `OP_VERIFY`, _si_ una condición es verdadera, el Script continúa ejecutándose, _de lo contrario_ el script finaliza. Así es como verifica las condiciones que son absolutamente necesarias para que un script tenga éxito. Por ejemplo, el script P2PKH (`OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG`) tiene dos condiciones requeridas: (1) que la clave pública proporcionada coincide con el hash de clave pública; y (2) que la firma proporcionada coincida con esa clave pública. Un `OP_EQUALVERIFY` se usa para la comparación de la clave pública luego del hash y el hash de la clave pública porque es una condición absolutamente necesaria. No _desea_ que el script continúe si eso falla. Puede notar que no hay `OP_VERIFY` al final de este script (o de la mayoría de estos), a pesar de que también se requiere la condición final. Eso es porque Bitcoin efectivamente hace un `OP_VERIFY` al final de cada Script, para asegurar que el resultado final de la pila sea verdadero. No _desea_ hacer un `OP_VERIFY` antes del final del script, ¡porque necesita dejar algo en la pila para ser probado! ## Comprenda if / then El otro condicional importante en Bitcoin Script es el clásico `OP_IF` (0x63) /` OP_ELSE` (0x67) / `OP_ENDIF` (0x68). Este es un control de flujo típico: si `OP_IF` detecta una declaración verdadera, ejecuta el bloque debajo de ella; de lo contrario, si hay un `OP_ELSE`, lo ejecuta; y `OP_ENDIF` marca el final del bloque final. > :warning: **ADVERTENCIA:** Estos condicionales también son técnicamente códigos de operación, pero al igual que con los números pequeños, > dejaremos el prefijo `OP_` desactivado para mayor brevedad y claridad. Por lo tanto, escribiremos `IF`,`ELSE` y `ENDIF` en lugar de` OP_IF`, `OP_ELSE` y `OP_ENDIF`. ### Comprenda el ordenamiento de if / then Hay dos grandes inconvenientes para los condicionales. Hacen que sea más difícil leer y evaluar los scripts si no se tiene cuidado. Primero, el condicional `IF` verifica la verdad de lo que está _ antes de él_ (es decir, lo que está en la pila), no lo que está después. En segundo lugar, el condicional `IF` tiende a estar en el script de bloqueo y lo que está comprobando tiende a estar en el script de desbloqueo. Por supuesto, podría decirse, así es como funciona Bitcoin Script. Los condicionales usan la notación polaca inversa y adoptan el paradigma estándar de desbloqueo / bloqueo, al igual que _todo lo demás_ en el scripting de Bitcoin. Todo eso es cierto, pero también va en contra de la forma estándar en que leemos los condicionales IF / ELSE en otros lenguajes de programación; por lo tanto, es fácil leer inconscientemente los condicionales de Bitcoin incorrectamente. Considere el siguiente código: `IF OP_DUP OP_HASH160 ELSE OP_DUP OP_HASH160 ENDIF OP_EQUALVERIFY OP_CHECKSIG`. Mirar condicionales en notación de prefijo puede llevarlo a leer esto como: ``` IF (OP_DUP) THEN OP_HASH160 OP_PUSHDATA ELSE OP_DUP OP_HASH160 OP_PUSHDATA ENDIF OP_EQUALVERIFY OP_CHECKSIG ``` Entonces, podría pensar, si el `OP_DUP` es exitoso, entonces podemos hacer el primer bloque, de lo contrario, el segundo. ¡Pero eso no tiene ningún sentido! ¡¿Por qué el `OP_DUP` no tendría éxito ?! Y, de hecho, no tiene ningún sentido, porque accidentalmente leemos la declaración usando la notación incorrecta. La lectura correcta de esto es: ``` IF OP_DUP OP_HASH160 OP_PUSHDATA ELSE OP_DUP OP_HASH160 OP_PUSHDATA ENDIF OP_EQUALVERIFY OP_CHECKSIG ``` La declaración que se evaluará como "Verdadero" o "Falso" se coloca en la _pila_ antes de ejecutar el "IF", luego se ejecuta el bloque de código correcto en función de ese resultado. Este código de ejemplo en particular está destinado a ser una firma múltiple 1 de 2 de un pobre hombre. El propietario de `` pondría ` True` en su script de desbloqueo, mientras que el propietario de` `pondría` False` en su script de desbloqueo. Ese final de "Verdadero" o "Falso" es lo que marca la declaración `IF` / `ELSE`. Le dice al script con qué hash de clave pública se debe verificar, luego el `OP_EQUALVERIFY` y el `OP_CHECKSIG` al final hacen el trabajo real. ### Ejecute un If / Then multifirma Con un conocimiento básico de los condicionales de Bitcoin en la mano, ahora estamos listos para ejecutar un script. Lo haremos creando una ligera variante de la firma múltiple 1 de 2 de nuestro pobre hombre, donde nuestros usuarios no tienen que recordar si son "Verdaderos" o "Falsos". En cambio, si es necesario, el script verifica ambos hash de clave pública, requiriendo que solo uno tenga éxito: ``` OP_DUP OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF ``` ¡Recuerde su notación polaca inversa! ¡Esa declaración `IF` se refiere al` OP_EQUAL` previo, no al `OP_CHECKSIG` siguiente! #### Ejecute la rama verdadera Así es como se ejecuta realmente si se desbloquea con ` `: ``` Script: OP_DUP OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` Primero, colocamos constantes en la pila: ``` Script: OP_DUP OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` Luego ejecutamos los primeros comandos obvios, `OP_DUP` y` OP_HASH160` y colocamos otra constante en la pila: ``` Script: OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_DUP Stack: [ ] Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_HASH160 Stack: [ ] Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` A continuación, ejecutamos el `OP_EQUAL`, que es lo que va a alimentar el `IF`: ``` Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_EQUAL Stack: [ True ] ``` Ahora se ejecuta el `IF`, y como hay un` Verdadero`, solo se ejecuta el primer bloque, eliminando el resto: ``` Script: OP_CHECKSIG Running: True IF Stack: [ ] ``` Y el `OP_CHECKSIG` terminará siendo`True` también: ``` Script: Running: OP_CHECKSIG Stack: [ True ] ``` #### Ejecute la rama falsa Así es como se ejecuta realmente si se desbloquea con ` `: ``` Script: OP_DUP OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` Primero, colocamos constantes en la pila: ``` Script: OP_DUP OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` Luego ejecutamos los primeros comandos obvios, `OP_DUP` y` OP_HASH160` y colocamos otra constante en la pila: ``` Script: OP_HASH160 OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_DUP Stack: [ ] Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_HASH160 Stack: [ ] Script: OP_EQUAL IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Stack: [ ] ``` A continuación, ejecutamos el `OP_EQUAL`, que es lo que va a alimentar el `IF`: ``` Script: IF OP_CHECKSIG ELSE OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG ENDIF Running: OP_EQUAL Stack: [ False ] ``` ¡Hey! El resultado fue `False` porque` `no es igual a` `. Ahora, cuando se ejecuta `IF`, se reduce el codigo a solo la declaración `ELSE`: ``` Script: OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG Running: False IF Stack: [ ] ``` Luego, repasamos todas las galimatías nuevamente comenzando con otro `OP_DUP`, pero eventualmente probando contra el otro` pubKeyHash`: ``` Script: OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG Running: OP_DUP Stack: [ ] Script: OP_EQUALVERIFY OP_CHECKSIG Running: OP_HASH160 Stack: [ ] Script: OP_EQUALVERIFY OP_CHECKSIG Stack: [ ] Script:OP_CHECKSIG Running: OP_EQUALVERIFY Stack: [ ] Script: Running: OP_CHECKSIG Stack: [ True ] ``` Esto probablemente no sea tan eficiente como un verdadero multisig de Bitcoin, pero es un buen ejemplo de cómo los resultados introducidos en la pila por pruebas anteriores pueden usarse para alimentar condicionales futuros. En este caso, es el fallo de la primera firma lo que le dice al condicional que debe ir a comprobar la segunda. ## Entienda otras condiciones Hay algunos otros condicionales importantes. El grande es `OP_NOTIF` (0x64), que es lo opuesto a`OP_IF`: ejecuta el siguiente bloque si el elemento superior es `False`. Se puede colocar un `ELSE` con él, que como de costumbre se ejecuta si no se ejecuta el primer bloque. Aún termina con `OP_ENDIF`. También hay un `OP_IFDUP` (0x73), que duplica el elemento de la pila superior solo si no es 0. Estas opciones se utilizan con mucha menos frecuencia que la construcción principal `IF` /` ELSE` / `ENDIF`. ## Resumen: Usando scripts condicionales Los condicionales en Bitcoin Script le permiten detener el script (usando `OP_VERIFY`) o elegir diferentes ramas de ejecución (usando`OP_IF`). Sin embargo, leer `OP_IF` puede ser un poco complicado. Recuerde que es el elemento empujado a la pila _antes_ de que se ejecute `OP_IF` el que controla su ejecución; ese elemento generalmente será parte del script de desbloqueo (o bien, un resultado directo de los elementos del script de desbloqueo). > :fire: **¿Cuál es el poder de los condicionales?** Los condicionales de script son el último bloque de construcción principal en los scripts de Bitcoin. Son lo que se requiere para convertir scripts de Bitcoin simples y estáticos en scripts de Bitcoin complejos y dinámicos que pueden evaluarse de manera diferente en función de diferentes momentos, diferentes circunstancias o diferentes entradas de usuario. > En otras palabras, son la base final de los contratos inteligentes. ## ¿Que sigue? Continúe "Expandiendo los scripts de Bitcoin" con [§12.2: Usando Otros Comandos de Scripting](12_2_Usando_Otros_Comandos_de_Scripting.md).