6 ProgramingBitcoin (1) .En - Es

Descargar como docx, pdf o txt
Descargar como docx, pdf o txt
Está en la página 1de 39

CAPÍTULO 6

Guión

La capacidad de bloquear y desbloquear monedas es el mecanismo por el cual


transferimos bitcoin. Bloquear es dar algunos bitcoins a alguna entidad. Desbloquear
es gastar algunos bitcoins que has recibido.
En este capítulo examinamos este mecanismo de bloqueo / desbloqueo, que a
menudo se denomina contrato inteligente. Criptografía de curva elíptica (Capítulo 3)
es utilizado por Script para validar que una transacción fue autorizada correctamente
(Capítulo 5) El script esencialmente permite peo-Para demostrar que tienen derecho a
gastar ciertos UTXO. Sin embargo, nos estamos adelantando un poco, así que
comencemos con el funcionamiento del Script y avancemos desde allí.

Mecánica del guión


Si está confundido acerca de qué es un contrato inteligente, no se preocupe.
"Contrato inteligente" es una forma elegante de decir "programable", y el "lenguaje
de contrato inteligente" es simplemente un lenguaje de programación. En Bitcoin,
Script es el lenguaje de contrato inteligente, o el profesional- lenguaje de gramática
utilizado para expresar las condiciones bajo las cuales se pueden gastar bitcoins.
Bitcoin tiene el equivalente digital de un contrato en Script. Script es un lan basado
en pila-calibre similar a Forth. Está limitado intencionalmente en el sentido de que
evita ciertas peleas-Tures. Específicamente, Script evita cualquier mecanismo para
bucles y, por lo tanto, no se completa con Turing.

103
Por qué Bitcoin no se está completando
La integridad de Turing en un lenguaje de programación
esencialmente significa que el programa tiene la capacidad de
bucle. Los bucles son una estafa útil- estructura en la programación,
por lo que puede que se pregunte en este momento por qué Script
no tiene la capacidad de bucle.
Hay muchas razones para esto, pero comencemos con el programa
exe-precaución Cualquiera puede crear un programa Script que
ejecute cada nodo completo de la red. Si el script se completara con
Turing, sería posible que el ciclo continuara ejecutándose para
siempre. Esto provocaría que los nodos de validación ingresen y
nunca salgan de ese bucle. Esta sería una manera fácil de atacar la
red a través de lo que se llamaría un ataque de denegación de
servicio (DoS). ¡Un solo programa de Script con un bucle infinito
podría eliminar Bitcoin! Este sería un gran sistema-vulnerabilidad
temática, y la protección contra esta vulnerabilidad es una de las
principales razones por las cuales se evita la integridad de Turing.
Ethereum, que tiene la integridad de Turing en su lenguaje de
contrato inteligente, Solidity, maneja este problema al obligar a los
contratos a pagar la ejecución del programa con algo llamado "gas".
Un bucle infinito agotará cualquier gas que haya en el contrato
porque, por definición- Además, se ejecutará un número infinito de
veces.
Otra razón para evitar la integridad de Turing es porque los
contratos inteligentes con la integridad de Turing son muy difíciles
de analizar. Las condiciones de ejecución de un contrato inteligente
completo de Turing son muy diferentes- es difícil de enumerar y,
por lo tanto, es fácil crear comportamientos no deseados-ior,
causando errores. Los errores en un contrato inteligente significan
que las monedas son vulnerables a ser gastadas involuntariamente,
lo que significa que la estafa-Los participantes del tracto podrían
perder dinero. Tales errores no son solo teóricos- cal: este fue el
principal problema en la DAO (Organización Autónoma
Descentralizada), un contrato inteligente completo de Turing que
terminó con la bifurcación dura Ethereum Classic.

Las transacciones asignan bitcoins a un script de bloqueo. El script de bloqueo es lo


que se especifica en el campo ScriptPubKey (consulteCapítulo 5) Puede pensar en
esto como una caja de seguridad donde se deposita algo de dinero que solo puede
abrir una llave en particular. El dinero dentro, por supuesto, solo puede ser accedido
por el propietario que tiene la clave.
El desbloqueo de la caja de seguridad se realiza en el campo ScriptSig (ver Capítulo
5); Esto demuestra la propiedad de la caja cerrada, que autoriza el gasto de los
fondos.
104 El | Capítulo 6: Guión
Cómo funciona el script
El script es un lenguaje de programación y, como la mayoría de los lenguajes de
programación, es profesional-cesa un comando a la vez. Los comandos operan en
una pila de elementos. Hay dos tipos posibles de comandos: elementos y
operaciones.
Los elementos son datos. Técnicamente, procesar un elemento empuja ese elemento
a la pila. Los elementos son cadenas de bytes de longitud 1 a 520. Un elemento típico
podría ser una firma DER o una clave pública SEC (Figura 6-1.)

Figura 6-1. Elementos

Las operaciones hacen algo a los datos (Figura 6-2.) Consumen cero o más ele-
Ments de la pila de procesamiento y empujar cero o más elementos de nuevo a la
pila.

Figura 6-2. Operaciones

Una operación típica es OP_DUP (Figura 6-3), que duplicará el elemento superior
(con- sumando 0) y empuje el nuevo elemento a la pila (empujando 1).

Figura 6-3. OP_DUP duplica el elemento superior

Después de evaluar todos los comandos, el elemento superior de la pila debe ser
distinto de cero para que el script se resuelva como válido. No tener elementos en la
pila o el elemento superior siendo 0 se resolvería como no válido. Resolver como
inválido significa que la transacción que incluye el script de desbloqueo no se acepta
en la red.

Operaciones de ejemplo
Hay muchas otras operaciones además de OP_DUP. OP_HASH160 (Figura 6-4) hace
un sha256 seguido de un ripemd160 (también conocido como hash160) al elemento
superior de la pila (con-sumando 1) y empuja un nuevo elemento a la pila
(empujando 1). Tenga en cuenta en el diagrama quey = hash160 (x).
Cómo funciona el script
El |
105
Figura 6-4. OP_HASH160 hace un sha256 seguido de ripemd160 al elemento
superior

Otra operación muy importante es OP_CHECKSIG (Figura 6-5) OP_CHECKSIG estafa-


suma dos elementos de la pila, el primero es la clave pública y el segundo una firma,
y examina si la firma es buena para la clave pública. Si es así, OP_CHECKSIG empuja
un 1 a la pila; de lo contrario, empuja un 0 a la pila.

Figura 6-5. OP_CHECKSIG comprueba si la firma de la clave pública es válida o


no

Codificación de códigos de operación


Ahora podemos codificar OP_DUP, dado una pila. OP_DUP simplemente duplica el
elemento superior de la pila:
def op_dup(apilar):
Si Len(apilar) < 1:
regreso Falso
apilar.adjuntar(apilar[-1])
regreso Cierto
...
OP_CODE_FUNCTIONS = {
...
118: op_dup,
...
}

Tenemos que tener al menos un elemento para duplicar; de lo contrario, no


podemos ejecutar este código de operación.

Así es como duplicamos el elemento superior de la pila.

118 = 0x76, que es el código para OP_DUP.


Tenga en cuenta que devolvemos un booleano con este código de operación, como
una forma de saber si la operación fue exitosa. Una operación fallida falla
automáticamente la evaluación del script.
Aquí hay otro, para OP_HASH256. Este código de operación consumirá el elemento
superior, por- forme una operación hash256 en él y empuje el resultado a la pila:
106 El | Capítulo 6: Guión
def op_hash256(apilar):
Si Len(apilar) < 1:
regreso Falso
elemento = apilar.popular()
apilar.adjuntar(hash256(elemento))
regreso Cierto
...
OP_CODE_FUNCTIONS = {
...
170: op_hash256,
...
}

Ejercicio 1
Escribe el op_hash160 función.

Analizando los campos del script


Tanto ScriptPubKey como ScriptSig se analizan de la misma manera. Si el byte está
entre0x01 y 0x4b (cuyo valor llamamos norte), leemos el siguiente norte bytes
como elemento. Otro- sabiamente, el byte representa una operación, que tenemos
que buscar. Aquí hay algunas operaciones- aciones y sus códigos de bytes:

• 0x00 - OP_0
• 0x51 - OP_1
• 0x60 - OP_16
• 0x76 - OP_DUP
• 0x93 - OP_ADD
• 0xa9 - OP_HASH160
• 0xac - OP_CHECKSIG

Analizando los campos del


script El |
107
Elementos de más de 75 bytes
Tal vez se pregunte qué sucedería si tuviera un elemento con una
longitud mayor que 0x4b(75 en decimal). Hay tres códigos de
operación específicos para manejar tales
elementos:OP_PUSHDATA1, OP_PUSHDATA2y OP_PUSHDATA4.
OP_PUSHDATA1 significa que el el siguiente byte contiene
cuántos bytes necesitamos leer para el ele- ment. OP_PUSHDATA2
significa que los siguientes 2 bytes contienen cuántos bytes
necesitamos leer para el elemento. OP_PUSHDATA4 significa que
los siguientes 4 bytes contienen cuántos bytes necesitamos leer para
el elemento.
Hablando en términos prácticos, esto significa que si tenemos un
elemento que está entre 76 y 255 bytes inclusive, usamos
OP_PUSHDATA1 <1 byte longitud del elemento>
<elemento>. Para cualquier cosa entre 256 bytes y 520 bytes
inclusive, utilizamos OP_PUSHDATA2 <2 bytes
longitud del elemento en little-endian> <elemento>.
Ninguna- No se permite en la red algo superior a 520 bytes, por lo que
OP_PUSHDATA4 aunque es innecesario OP_PUSHDATA4 <4 bytes
longitud del elemento en little-endian, pero valor
menor o igual a 520> <elemento>Sigue siendo legal.
Es posible codificar un número por debajo de 76 usando
OP_PUSHDATA1 o un número inferior a 256 usando
OP_PUSHDATA2 o incluso cualquier número por debajo de 521
usando OP_PUSHDATA4. Sin embargo, estas se consideran
transacciones no estándar, lo que significa que la mayoría de los
nodos de Bitcoin (en particular- principalmente aquellos que
ejecutan el software Bitcoin Core) no los retransmitirán.

Hay muchos más códigos de operación, que están codificados en op.py, y la lista
completa se puede encontrar en https://en.bitcoin.it/wiki/Script.

Codificación de un analizador de scripts y


serializador
Ahora que sabemos cómo funciona el Script, podemos escribir un analizador de
script:
clase Guión:

def __en eso__(yo, cmds=Ninguna):


Si cmds es Ninguna:
yo.cmds = []
más:
yo.cmds = cmds
...
@classmethod
def analizar gramaticalmente(cls, s):
longitud = read_varint(s)
cmds = []
contar = 0 0
mientras contar < longitud:

108 El | Capítulo 6: Guión


Actual = s.leer(1)
contar + = 1
byte actual = Actual[0 0]
Si byte actual > = 1 y byte actual <= 75:
norte = byte actual
cmds.adjuntar(s.leer(norte))
contar + = norte
elif byte actual == 76:
longitud de datos = little_endian_to_int(s.leer(1))
cmds.adjuntar(s.leer(longitud de datos))
contar + = longitud de datos + 1
elif byte actual == 77:
longitud de datos = little_endian_to_int(s.leer(2))
cmds.adjuntar(s.leer(longitud de datos))
contar + = longitud de datos + 2
más:
op_code = byte actual
cmds.adjuntar(op_code)
Si contar ! = longitud:
aumento Error de sintaxis('error al analizar el script')
regreso cls(cmds)

Cada comando es un código de operación para ser ejecutado o un elemento para


ser empujado a la pila.

La serialización del script siempre comienza con la longitud del script completo.

Analizamos hasta que se consuma la cantidad correcta de bytes.

El byte determina si tenemos un código de operación o elemento.

Esto convierte el byte en un entero en Python.

Para un número entre 1 y 75 inclusive, sabemos el próximo norte Los bytes son
un elemento.

76 es OP_PUSHDATA1, por lo que el siguiente byte nos dice cuántos bytes leer.

77 es OP_PUSHDATA2, por lo que los siguientes dos bytes nos dicen cuántos
bytes leer.

Tenemos un código de operación que almacenamos.

El script debería haber consumido exactamente la longitud de bytes que


esperábamos; otro- sabio, planteamos un error.
Analizando los campos del
script El |
109
De manera similar, podemos escribir un serializador de script:
clase Guión:
...
def raw_serialize(yo):
resultado = si''
para cmd en yo.cmds:
Si tipo(cmd) == En t:
resultado + = int_to_little_endian(cmd, 1)
más:
longitud = Len(cmd)
Si longitud < 75:
resultado + = int_to_little_endian(longitud, 1)
elif longitud > 75 y longitud < 0x100:
resultado + = int_to_little_endian(76, 1)
resultado + = int_to_little_endian(longitud, 1)
elif longitud > = 0x100 y longitud <= 520:

resultado + =
int_to_little_endian(77, 1) resultado + =
int_to_little_endian(longitud, 2)
más:
aumento ValueError('demasiado largo un cmd')
resultado + = cmd
regreso resultado

def publicar por fascículos(yo):


resultado = yo.raw_serialize()
total = Len(resultado)
regreso encode_varint(total) + resultado

Si el comando es un entero, sabemos que es un código de operación.

Si la longitud es entre 1 y 75 inclusive, codificamos la longitud como un solo


byte.

Para cualquier elemento con longitud de 76 a 255, ponemos OP_PUSHDATA1


primero, luego codifique la longitud como un solo byte, seguido del elemento.

Para un elemento con una longitud de 256 a 520, ponemos OP_PUSHDATA2


primero, luego codifique la longitud como dos bytes en little endian, seguido del
elemento.

Cualquier elemento de más de 520 bytes no se puede serializar.

La serialización del script comienza con la longitud del script completo.


Tenga en cuenta que tanto el analizador como el serializador se usaron en Capítulo 5,
para análisis / serial- izing los campos ScriptSig y ScriptPubKey.
110 El | Capítulo 6: Guión
Combinando los campos de script
los GuiónEl objeto representa el conjunto de comandos que requiere evaluación.
Para evaluar un script, necesitamos combinar los campos ScriptPubKey y ScriptSig.
La caja de seguridad (ScriptPubKey) y el mecanismo de desbloqueo (ScriptSig) están
en diferentes transacciones-iones Específicamente, la caja de seguridad es donde se
reciben los bitcoins, y el script de desbloqueo es donde se gastan los bitcoins. La
entrada en la transacción de gasto apunta a la transacción de recepción.
Esencialmente, tenemos una situación comoFigura 6-6.

Figura 6-6. Combinando ScriptPubKey y ScriptSig

Dado que ScriptSig desbloquea un ScriptPubKey, necesitamos un mecanismo


mediante el cual se combinen los dos scripts. Para evaluar los dos juntos, tomamos
los comandos de ScriptSig y ScriptPubKey y los combinamos como enFigura 6-6.
Los comandos de ScriptSig van por encima de todos los comandos de ScriptPubKey.
Las instrucciones se procesan de una en una hasta que no quedan comandos para
procesar (o el script falla).

Codificación del conjunto de instrucciones


combinado
La evaluación de un script requiere que tomemos ScriptSig y ScriptPubKey, com-
agruparlos en un solo conjunto de comandos y ejecutar los comandos. Para hacer
esto, requerimos una forma de combinar los scripts:
clase Guión:
...
def __añadir__(yo, otro):
regreso Guión(yo.cmds + otro.cmds)

Estamos combinando el conjunto de comandos para crear un nuevo, combinado


Guión objeto.
Usaremos esta capacidad para combinar scripts para evaluación más adelante en este
capítulo.

Guiones estándar
Hay muchos tipos de scripts estándar en Bitcoin, incluidos los siguientes:
Combinando los campos de script
El |
111
p2pk
Pay-to-pubkey
p2pkh
Pay-to-pubkey-hash
p2sh
Pago a hash de script
p2wpkh
Pagar-a-testigo-pubkey-hash
p2wsh
Pagar-a-testigo-script-hash
Las direcciones son plantillas de script conocidas como estas. Las carteras saben
interpretar vari-ous tipos de direcciones (p2pkh, p2sh, p2wpkh) y cree los
ScriptPubKeys apropiados. Todos los ejemplos aquí tienen un tipo particular de
formato de dirección (Base58, Bech32) para que las billeteras puedan pagarles.
Para mostrar exactamente cómo funciona todo esto, comenzaremos con uno de los
scripts originales, pay-to-pubkey.

p2pk
Pay-to-pubkey (p2pk) se usó principalmente durante los primeros días de Bitcoin. La
mayoría de las monedas que se cree que pertenecen a Satoshi están en UTXO p2pk,
es decir, salidas de transacciones cuyas ScriptPubKeys tienen la forma p2pk. Hay
algunas limitaciones que discutiremos en“Problemas con p2pk” en la página 118,
pero primero, veamos cómo funciona p2pk.
De nuevo en Capítulo 3, aprendimos sobre la firma y verificación de ECDSA. Para
verificar una firma ECDSA, necesitamos el mensaje, z, la clave pública, P, y la
firma, r y s. En p2pk, los bitcoins se envían a una clave pública, y el propietario de la
clave privada puede desbloquear o gastar los bitcoins creando una firma. El
ScriptPubKey de una transacción- ción pone los bitcoins asignados bajo el control
del propietario de la clave privada.
Especificar adónde van los bitcoins es el trabajo de ScriptPubKey: esta es la caja de
seguridad que recibe los bitcoins. El p2pk ScriptPubKey se parece aFigura 6-7.

Figura 6-7. Pay-to-pubkey (p2pk) ScriptPubKey

112 El | Capítulo 6: Guión


Nota la OP_CHECKSIG, ya que eso será muy importante. ScriptSig es la parte que
desbloquea los bitcoins recibidos. El pubkey se puede comprimir o descomprimir,
aunque al principio de la historia de Bitcoin cuando p2pk era más prominente, el- el
formato presionado fue el único que se usó (ver Capítulo 4)
Para p2pk, el ScriptSig requerido para desbloquear el ScriptPubKey correspondiente
es el sig- naturaleza seguida de un solo byte sighash, como se muestra en Figura 6-8.

Figura 6-8. Pago a pubkey (p2pk) ScriptSig

ScriptPubKey y ScriptSig se combinan para crear un conjunto de comandos que se


parece a Figura 6-9.

Figura 6-9. p2pk combinado

Las dos columnas en Figura 6-10.son comandos de script y la pila de elementos. Al


final del procesamiento, el elemento superior de la pila debe ser distinto de cero para
ser considerado un ScriptSig válido. Los comandos de script se procesan uno a la
vez. EnFigura 6-10., comenzamos con los comandos combinados en Figura 6-9.

Figura 6-10. inicio p2pk

El primer comando es la firma, que es un elemento. Estos son datos que se envían a
la pila (Figura 6-11.)

p2pk El |
113
Figura 6-11. p2pk paso 1

El segundo comando es la clave pública, que también es un elemento. Nuevamente,


estos son datos que se envían a la pila (Figura 6-12.)

Figura 6-12. p2pk paso 2

OP_CHECKSIG consume dos comandos de pila (pubkey y firma) y determina si son


válidos para esta transacción. OP_CHECKSIG empujará un 1 a la pila si el sig-la
naturaleza es válida, y un 0 si no. Suponiendo que la firma es válida para esta clave
pública, tenemos la situación que se muestra enFigura 6-13.

Figura 6-13. p2pk paso 3

Hemos terminado de procesar todos los comandos de Script y hemos terminado con
un solo elemento en la pila. Dado que el elemento superior no es cero (1
definitivamente no es 0), este script es válido.
Si esta transacción tenía una firma no válida, el resultado de OP_CHECKSIG sería 0,
finalizando el procesamiento de nuestro script (como se muestra en Figura 6-14.)

114 El | Capítulo 6: Guión


Figura 6-14. final de p2pk

Si el elemento superior es 0, el script combinado no es válido y una transacción con


este ScriptSig en la entrada no es válida.
El script combinado se validará si la firma es válida, pero fallará si la firma no es
válida. ScriptSig solo desbloqueará ScriptPubKey si la firma es válida para esa clave
pública. En otras palabras, solo alguien con conocimiento de la clave privada puede
producir un ScriptSig válido.
Por cierto, podemos ver de dónde obtuvo su nombre ScriptPubKey. La clave pública
en- el formato SEC presionado es el comando principal en ScriptPubKey para p2pk
(el otro comando es OP_CHECKSIG) Del mismo modo, ScriptSig se nombra como tal
porque ScriptSig para p2pk tiene la firma DER.

Evaluación de script de codificación


Ahora codificaremos una forma de evaluar los scripts. Esto requiere que revisemos
cada com-mand y evaluar si el script es válido. Lo que queremos poder hacer es esto:
> desde guión importar Guión
> z = 0x7c076ff316692a3d7eb3c3bb0f8b1488cf72e1afcd929e29307032997a838a3d
> segundo =
bytes.fromhex('04887387e452b8eacc4acfde10d9aaf7f6d9a0f975aabb10d006e \
4da568744d06c61de6d95231cd89026e286df3b6ae4a894a3378e393e93a0f45b666329a0ae34 ')
> sig = bytes.fromhex('3045022000eff69ef2b1bd93a66ed5219add4fb51e11a840f4048 \
76325a1e8ffe0529a2c022100c7207fee197d27c618aea621406f6bf5ef6fca38681d82b2f06fd \
dbdce6feab601 ')
> script_pubkey = Guión([segundo, 0xac])
> script_sig = Guión([sig])
> script_combinado = script_sig + script_pubkey
> impresión(script_combinado.evaluar(z))
Cierto

El p2pk ScriptPubkey es el pubkey de formato SEC seguido de OP_CHECKSIG,


cual es 0xac o 172.

Podemos hacer esto debido a la __añadir__ método que acabamos de crear.

Queremos evaluar los comandos y ver si el script valida.

p2pk El |
115
Este es el método que usaremos para el conjunto de comandos combinados
(combinación de ScriptPubKey de la transacción anterior y ScriptSig de la
transacción actual):
desde op importar OP_CODE_FUNCTIONS, OP_CODE_NAMES
...
clase Guión:
...
def evaluar(yo, z):
cmds = yo.cmds[:]
apilar = []
altstack = []
mientras Len(cmds) > 0 0:
cmd = cmds.popular(0 0)
Si tipo(cmd) == En t:
operación = OP_CODE_FUNCTIONS[cmd]
Si cmd en (99, 100):
Si no operación(apilar, cmds):
LOGGER.informacion('mala operación:
{}'.formato(OP_CODE_NAMES[cmd]))
regreso Falso
elif cmd en (107, 108):
Si no operación(apilar, altstack):
LOGGER.informacion('mala operación:
{}'.formato(OP_CODE_NAMES[cmd]))
regreso Falso
elif cmd en (172, 173, 174, 175):
Si no operación(apilar, z):
LOGGER.informacion('mala operación:
{}'.formato(OP_CODE_NAMES[cmd]))
regreso Falso
más:
Si no operación(apilar):
LOGGER.informacion('mala operación:
{}'.formato(OP_CODE_NAMES[cmd]))
regreso Falso
más:
apilar.adjuntar(cmd)
Si Len(apilar) == 0 0:
regreso Falso
Si apilar.popular() == si'':
regreso Falso
regreso Cierto

Como la lista de comandos cambiará, hacemos una copia.

Ejecutamos hasta que la lista de comandos esté vacía.

La función que ejecuta el código de operación está en el OP_CODE_FUNCTIONS


matriz (por ejemplo, OP_DUP, OP_CHECKSIG, etc.)

99 y 100 son OP_IF y OP_NOTIF, respectivamente. Requieren manipulación de


lacmds matriz basada en el elemento superior de la pila.
116 El | Capítulo 6: Guión
107 y 108 son OP_TOALTSTACK y OP_FROMALTSTACK, respectivamente.
Mueven elementos de la pila hacia / desde una pila "alternativa", que
llamamosaltstack.

172, 173, 174 y 175 son OP_CHECKSIG, OP_CHECKSIGVERIFY,


OP_CHECKMULTI SIGy OP_CHECKMULTISIGVERIFY, que requieren el hash de
la firma, z, desde Capítulo 3 para validación de firma.

Si el comando no es un código de operación, es un elemento, entonces


empujamos ese elemento a la pila.

Si la pila está vacía al final del procesamiento de todos los comandos, fallamos el
script al devolver Falso.

Si el elemento superior de la pila es una cadena de bytes vacía (que es cómo la


pila almacena un 0), entonces también fallamos el script al devolver Falso.

Cualquier otro resultado significa que el script ha validado.

Hacer que la evaluación de guiones sea segura


El código que se muestra aquí es un poco engañoso, ya que el script
combinado no se ejecuta exactamente de esta manera. El ScriptSig
se evalúa sepa- raly desde ScriptPubKey para no permitir que las
operaciones desde ScriptSig afecten los comandos ScriptPubKey.
Específicamente, la pila después de que todos los comandos
ScriptSig son evaluados- ated se almacena y luego los comandos
ScriptPubkey se evalúan por sí mismos con la pila desde la primera
ejecución.

Elementos de pila debajo del capó


Puede ser confuso que los elementos de la pila a veces sean números como 0 o 1 y otras
veces cadenas de bytes como una firma DER o SEC pubkey. Debajo del capó, todos son
bytes, pero algunos se interpretan como números para ciertos códigos de operación. Por
ejemplo, 1 se almacena en la pila como 01 byte, 2 se almacena como el 02 byte, 999
como el e703byte, y así sucesivamente. Cualquier cadena de bytes se interpreta como un
número little-endian para códigos de operación aritméticos. El entero 0 no se almacena
como el00 byte, pero como la cadena de bytes vacía.
El código en op.py puede aclarar lo que está sucediendo:
def encode_num(num):
Si num == 0 0:
regreso si''
abs_num = abdominales(num)
negativo = num < 0 0
resultado = bytearray()
p2pk El |
117
mientras abs_num:
resultado.adjuntar(abs_num Y 0xff)
abs_num >> = 8
Si resultado[-1] Y 0x80:
Si negativo:
resultado.adjuntar(0x80)
más:
resultado.adjuntar(0 0)
elif negativo:
resultado[-1] | = 0x80
regreso bytes(resultado)

def decode_num(elemento):
Si elemento == si'':
regreso 0 0
big_endian = elemento[::-1]
Si big_endian[0 0] Y 0x80:
negativo = Cierto
resultado = big_endian[0 0] Y 0x7f
más:
negativo = Falso
resultado = big_endian[0 0]
para C en big_endian[1:]:
resultado << = 8
resultado + = C
Si negativo:
regreso -resultado
más:
regreso resultado

def op_0(apilar):
apilar.adjuntar(encode_num(0 0))
regreso Cierto

Los números que se envían a la pila se codifican en bytes y se decodifican a partir de


bytes cuando se necesita el valor numérico.

Ejercicio 2
Escribe el op_checksig funcionar en op.py.

Problemas con p2pk


Pay-to-pubkey es intuitivo en el sentido de que hay una clave pública a la que
cualquiera puede enviar bitcoins y una firma que solo puede ser producida por el
propietario de la clave privada. Esto funciona bien, pero hay algunos problemas.

118 El | Capítulo 6: Guión


Primero, las claves públicas son largas. Sabemos deCapítulo 4que los puntos
públicos secp256k1 son 33 bytes en SEC comprimido y 65 bytes en formato SEC sin
comprimir. Unfortu-Naturalmente, los humanos no pueden interpretar 33 o 65 bytes
sin formato fácilmente. La mayoría de las codificaciones de caracteres no representan
ciertos rangos de bytes, ya que son caracteres de control, líneas nuevas o similares.
El formato SEC generalmente se codifica en hexadecimal, duplicando la longitud (el
hexadecimal codifica 4 bits por carácter en lugar de 8). Esto hace que la compresión
y la descompresión- formatos SEC presionados de 66 y 130 caracteres,
respectivamente, que es más grande que la mayoría de los identificadores (su nombre
de usuario en un sitio web, por ejemplo, suele ser inferior a 20 caracteres -ters). Para
agravar esto, las primeras transacciones de Bitcoin no usaron la versión comprimida-
sions, por lo que las direcciones hexadecimales tenían 130 caracteres cada una. Esto
no es divertido ni fácil de transcribir, y mucho menos comunicarse por voz.
Dicho esto, los casos de uso originales para p2pk fueron para pagos de IP a IP y
minería-pone. Para los pagos de IP a IP, las direcciones IP fueron consultadas por sus
claves públicas; commu-La indicación de las claves públicas se hacía de máquina a
máquina, lo que significaba que la comunicación humana no era necesariamente un
problema. El uso para salidas de minería tampoco requiere comunicación humana.
Por cierto, este sistema de pago de IP a IP se eliminó gradualmente porque no es
seguro y propenso a ataques de intermediarios.

¿Por qué Satoshi usó el formato SEC sin comprimir?


Parece que el formato SEC sin comprimir no tiene sentido para Bitcoin dado que el
espacio en bloque es muy importante. Entonces, ¿por qué lo usó Satoshi? Satoshi
estaba usando la biblioteca OpenSSL para hacer las conversiones de formato SEC, y
la biblioteca OpenSSL en el momento en que Satoshi escribió Bitcoin (alrededor de
2008) no documentó muy bien el formato comprimido. Se especula que es por eso
que Satoshi usó el formato SEC sin comprimir.
Cuando Pieter Wuille descubrió que el formato SEC comprimido existía en
OpenSSL, más personas comenzaron a usar el formato SEC comprimido en Bitcoin.

En segundo lugar, la longitud de las claves públicas causa un problema más sutil:
dado que deben mantenerse e indexarse para ver si las salidas son gastables, el
conjunto UTXO se hace más grande. Esto requiere más recursos por parte de los
nodos completos.
Tercero, debido a que estamos almacenando las claves públicas en el campo
ScriptPubKey, todos las conocen. Eso significa que si algún día se rompe el ECDSA,
estos resultados podrían ser robados. Por ejemplo, la computación cuántica tiene el
potencial de reducir significativamente los tiempos de cálculo para RSA y ECDSA,
por lo que tener algo más además de pro-Proteger estos resultados sería más seguro.
Sin embargo, esta no es una amenaza muy grande ya que ECDSA se usa en muchas
aplicaciones además de Bitcoin y romperlo también afectaría todas esas cosas.
Problemas con p2pk El
| 119
Resolviendo los problemas con p2pkh
Pay-to-pubkey-hash (p2pkh) es un formato de script alternativo que tiene dos claves
avanzadas- tages sobre p2pk:

1. Las direcciones son más cortas.


2. También está protegido por sha256 y ripemd160.

Las direcciones son más cortas porque usa el algoritmo hash sha256 y ripemd160-
Ritmos Hacemos ambos sucesivamente y lo llamamos hash160. El resultado de
hash160 es 160 bits o 20 bytes, que se codifican en una dirección.
El resultado es lo que puede haber visto en la red Bitcoin y codificado en Capítulo 4:
1PMycacnJaSqwwJqjawXBErnLsZ7RkXUAs

Esta dirección codifica dentro de 20 bytes que se ven así en hexadecimal:


f54a5851e9372b87810a8e60cdd2e7cfd80b6e31

Estos 20 bytes son el resultado de realizar una operación hash160 en esta clave
pública SEC (comprimida):
0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352

Dado que p2pkh es más corto y más seguro, el uso de p2pk disminuyó
significativamente después de 2010, aunque todavía es totalmente compatible hoy en
día.

p2pkh
Pay-to-pubkey-hash se usó durante los primeros días de Bitcoin, aunque no tanto
como p2pk.
El p2pkh ScriptPubKey, o script de bloqueo, se ve como Figura 6-15.

Figura 6-15. Pay-to-pubkey-hash (p2pkh) ScriptPubKey

Como p2pk, OP_CHECKSIG está aquí y OP_HASH160hace una aparición. A diferencia de


p2pk, la clave de acceso SEC no está aquí, pero sí un hash de 20 bytes. También hay un
nuevo código de operación aquí:
OP_EQUALVERIFY.
120 El | Capítulo 6: Guión
La secuencia de comandos p2pkh, o secuencia de comandos de desbloqueo, se ve
como Figura 6-16.

Figura 6-16. ScriptSig de pago a pubkey-hash (p2pkh)

Al igual que p2pk, el ScriptSig tiene la firma DER. A diferencia de p2pk, el


ScriptSig también tiene la SEC pubkey. La principal diferencia entre p2pk y p2pkh
ScriptSigs es que la clave de acceso SEC se ha movido de ScriptPubKey a ScriptSig.
ScriptPubKey y ScriptSig se combinan para formar una lista de comandos que se
parece a Figura 6-17.

Figura 6-17. p2pkh combinado

En este punto, el script se procesa un comando a la vez. Empezamos con el com-


mands como combinado en Figura 6-18.

Resolviendo los problemas con p2pkh


El |
121
Figura 6-18. inicio p2pkh

Los dos primeros comandos son elementos, por lo que se envían a la pila (Figura 6-
19.)

Figura 6-19. p2pkh paso 1

OP_DUP duplica el elemento superior, por lo que la clave pública se duplica (Figura
6-20.)

Figura 6-20. p2pkh paso 2

OP_HASH160 toma el elemento superior y realiza la operación hash160 en él


(sha256 seguido de ripemd160), creando un hash de 20 bytes (Figura 6-21.)

122 El | Capítulo 6: Guión


Figura 6-21. p2pkh paso 3

El hash de 20 bytes es un elemento y se inserta en la pila (Figura 6-22.)

Figura 6-22. p2pkh paso 4

Ahora estamos en OP_EQUALVERIFY. Este código de operación consume los dos


elementos superiores y comprueba si son iguales. Si son iguales, el script continúa su
ejecución. Si no son iguales, el script se detiene inmediatamente y falla. Suponemos
aquí que son iguales, lideran- ing a Figura 6-23..

Figura 6-23. p2pkh paso 5

Resolviendo los problemas con p2pkh


El |
123
Ahora estamos exactamente donde estábamos durante el OP_CHECKSIG parte del
procesamiento p2pk.
Una vez más, asumimos que la firma es válida (Figura 6-24.)

Figura 6-24. final p2pkh

Hay dos formas en que este script puede fallar. Si ScriptSig proporciona una clave
pública que no tiene hash160 al hash de 20 bytes en ScriptPubKey, el script fallará
enOP_EQUAL VERIFICAR (Figura 6-22.) La otra condición de falla es si el ScriptSig
tiene una clave pública ese hash160s al hash de 20 bytes en ScriptPubKey, pero tiene
una firma no válida. Eso terminaría la evaluación combinada del script con un 0,
terminando en falla.
Es por eso que llamamos a este tipo de script pay-to-pubkey-hash. ScriptPubKey
tiene el hash160 de 20 bytes de la clave pública y no la clave pública en sí. Estamos
bloqueando poco- monedas a un hash de la clave pública, y el gastador es
responsable de revelar el pub- clave clave como parte de la construcción de
ScriptSig.
Las principales ventajas son que ScriptPubKey es más corto (solo 25 bytes) y un
ladrón no solo tendría que resolver el problema de registro discreto en ECDSA, sino
también encontrar una forma de encontrar imágenes previas de ripemd160 y sha256.

Las secuencias de comandos se


pueden construir arbitrariamente
Tenga en cuenta que un script puede ser cualquier programa arbitrario. El script es un
lenguaje de contrato inteligente y puede bloquear bitcoins de muchas maneras
diferentes.Figura 6-25 es un ejemplo de ScriptPub- Llave.

Figura 6-25. Ejemplo ScriptPubKey

Figura 6-26. es un ScriptSig que desbloqueará el ScriptPubKey de Figura 6-25.

Figura 6-26. ScriptSig de ejemplo


124 El | Capítulo 6: Guión
El guión combinado se muestra en Figura 6-27..

Figura 6-27. Ejemplo combinado

La evaluación del script comenzará como se muestra en Figura 6-28..

Figura 6-28. Ejemplo de inicio

OP_4 empujará un 4 a la pila (Figura 6-29.)

Figura 6-29. Ejemplo paso 1

OP_5 también empujará un 5 a la pila (Figura 6-30)

Las secuencias de comandos se pueden


construir arbitrariamente El |
125
Figura 6-30. Ejemplo paso 2

OP_ADD consumirá los dos elementos superiores de la pila, los agregará y empujará
la suma de la pila (Figura 6-31)

Figura 6-31. Ejemplo paso 3

OP_9 empujará un 9 a la pila (Figura 6-32)

Figura 6-32. Ejemplo paso 4

OP_EQUAL consumirá dos elementos y empujará un 1 si son iguales y un 0 si no


(Figura 6-33.)

Figura 6-33. Fin de ejemplo

126 El | Capítulo 6: Guión


Tenga en cuenta que el ScriptSig aquí no es particularmente difícil de entender y no
contiene sig-naturaleza. Como resultado, el ScriptPubKey es vulnerable a ser tomado
por cualquiera que pueda resolverlo. Piense en este ScriptPubKey como una caja de
seguridad con un bloqueo muy endeble en el que cualquiera puede entrar. Es por esta
razón que la mayoría de las transacciones que requieren firma requieren- ment en el
ScriptSig.
Una vez que se ha gastado un UTXO, incluido en un bloque y asegurado mediante
prueba de trabajo, las monedas se bloquean en un ScriptPubKey diferente y ya no se
pueden gastar tan fácilmente. Algunos- alguien que intente gastar monedas ya
gastadas tendría que proporcionar una prueba de trabajo, que es costosa (ver Capítulo
9)

Ejercicio 3
Cree un ScriptSig que pueda desbloquear este ScriptPubKey:
767695935687

Tenga en cuenta que OP_MUL multiplica los dos elementos superiores de la pila.

• 56 = OP_6
• 76 = OP_DUP
• 87 = OP_EQUAL
• 93 = OP_ADD
• 95 = OP_MUL

Utilidad de scripts
El ejercicio anterior fue un poco tramposo, ya que OP_MUL ya no está permitido en Bit-
red de monedas. La versión 0.3.5 de Bitcoin deshabilitó muchos códigos de operación
diferentes (cualquier cosa que tuviera incluso un poco de potencial para crear
vulnerabilidades en la red).
Esto es igual de bueno, ya que la mayor parte de la funcionalidad en Script no se usa
mucho. Desde el punto de vista del mantenimiento del software, esta no es una gran
situación ya que el código debe mantenerse a pesar de su falta de uso. Simplificando
y deshaciéndose de cierta capa- Las capacidades pueden verse como una forma de
hacer que Bitcoin sea más seguro.
Esto está en marcado contraste con otros proyectos, que intentan expandir sus
lenguajes de contratos inteligentes, a menudo aumentando la superficie de ataque
junto con nuevas características.

Ejercicio 4
Descubre qué está haciendo este script:
6e879169a77ca787
Las secuencias de comandos se pueden
construir arbitrariamente El |
127
• 69 = OP_VERIFY
• 6e = OP_2DUP
• 7c = OP_SWAP
• 87 = OP_EQUAL
• 91 = OP_NOT
• a7 = OP_SHA1

Utilizar el Script.parse método y busque lo que hacen varios códigos de


operación en https: // en.bitcoin.it/wiki/Script.

Piñata SHA-1
En 2013, Peter Todd creó un guión muy similar al del Ejercicio 4 y puso algunos
bitcoins para crear un incentivo económico para que las personas encuentren hash
colli-Sions. Las donaciones alcanzaron 2.49153717 BTC, y cuando Google
realmente encontró uncolisión de hash para SHA-1 en febrero de 2017, Este script
fue redimido rápidamente. los La salida de la transacción fue de 2.48 BTC, que era
de 2,848.88 USD en ese momento.
Peter creó más piñatas para sha256, hash256 y hash160, que agregan incentivos
económicos para encontrar colisiones para estas funciones de hash.

Conclusión
Hemos cubierto Script y cómo funciona. Ahora podemos proceder a la creación y
vali- fecha de las transacciones.

128 El | Capítulo 6: Guión

También podría gustarte