Mastering Bitcoin

Mastering Bitcoin


10. Minería y Consenso » Minando el Bloque » Objetivo de Dificultad y Recálculo de Dificultad.

Página 73 de 98

Minando el Bloque

Ahora que el nodo de Jing ha construido un bloque candidato, es hora de que la plataforma minera de hardware de Jing «mine» el bloque, para encontrar una solución al algoritmo de prueba de trabajo que haga que el bloque sea válido. A lo largo de este libro hemos estudiado las funciones hash criptográficas, tal como se usan en varios aspectos del sistema bitcoin. La función hash SHA256 es la función que se utiliza en el proceso de minería de bitcoin.

En los términos más simples, la minería es el proceso de hacer hash de la cabecera del bloque de manera repetitiva, cambiando un parámetro, hasta que el hash resultante coincida con un objetivo específico. El resultado de la función hash no puede determinarse de antemano, ni se puede crear un patrón que vaya a producir un valor hash específico. Esta característica de las funciones de hash significa que la única manera de producir un hash resultante que coincida con un objetivo específico es intentarlo una y otra vez, modificando aleatoriamente la entrada hasta que el hash resultante que se desea aparezca por casualidad.

Algoritmo de Prueba De Trabajo

Un algoritmo de hash toma una entrada de datos de longitud arbitraria y produce un resultado determinista de longitud fija, una huella digital de la entrada. Para cualquier entrada específica, el hash resultante será siempre el mismo y puede ser calculado y verificado fácilmente por cualquier persona aplicando el mismo algoritmo de hash. La característica clave de un algoritmo de hash criptográfico es que es prácticamente imposible encontrar dos entradas diferentes que produzcan la misma huella digital. Como corolario, también es prácticamente imposible seleccionar una entrada de tal forma que produzca una huella digital deseada. La única manera es intentar con entradas de manera aleatoria.

Con SHA256, la salida es siempre de 256 bits de longitud, independientemente del tamaño de la entrada. En el ejemplo sha256, vamos a utilizar el intérprete de Python para calcular el hash SHA256 de la frase: «I am Satoshi Nakamoto».

Ejemplo SHA256:

$ python

Python 2.7.1

>>> import hashlib

>>> print hashlib.sha256("I am Satoshi Nakamoto").hexdigest() 5d7c7ba21cbbcd75d14800b100252d5b428e5b1213d27c385bc141ca6b47989e

El ejemplo SHA256 muestra el resultado de calcular el hash de «I am Satoshi Nakamoto»

5d7c7ba21cbbcd75d14800b100252d5b428e5b1213d27c385bc141ca6b47989e. Este número de 256 bits es el hash o digest de la frase y depende de todos y cada uno de los elementos de frase. Si se añade una sola letra, signo de puntuación, o cualquier otro carácter, producirá un hash diferente.

Por tanto, si cambiamos la frase, deberíamos ver hashes completamente diferentes. Vamos a comprobarlo añadiendo un número al final de nuestra frase, usando el script simple de Python en SHA256. Un script para generar muchos hashes iterando un nonce.

Ejemplo 8. SHA256 Un script para generar muchos hashes iterando un

# example of iterating a nonce in a hashing algorithm's input

import hashlib

text = "I am Satoshi Nakamoto"

# iterate nonce from 0 to 19

for nonce in xrange(20):

# add the nonce to the end of the text

input = text + str(nonce)

# calculate the SHA-256 hash of the input (text+nonce)

hash = hashlib.sha256(input).hexdigest()

# show the input and hash result

print input, '=>', hash

La ejecución de este script producirá los hashes de varias frases. Se ha añadido un número al final de las frases para hacerlas diferentes entre sí. Incrementando el número, podemos obtener diferentes hashes, como se muestra en Salida SHA256 de un script para generar muchos hashes iterando un .

Ejemplo 9. Salida SHA256 de un script para generar muchos hashes iterando un

$ python hash_example.py

I am Satoshi Nakamoto0 => a80a81401765c8eddee25df36728d732…

I am Satoshi Nakamoto1 => f7bc9a6304a4647bb41241a677b5345f…

I am Satoshi Nakamoto2 => ea758a8134b115298a1583ffb80ae629…

I am Satoshi Nakamoto3 => bfa9779618ff072c903d773de30c99bd…

I am Satoshi Nakamoto4 => bce8564de9a83c18c31944a66bde992f…

I am Satoshi Nakamoto5 => eb362c3cf3479be0a97a20163589038e…

I am Satoshi Nakamoto6 => 4a2fd48e3be420d0d28e202360cfbaba…

I am Satoshi Nakamoto7 => 790b5a1349a5f2b909bf74d0d166b17a…

I am Satoshi Nakamoto8 => 702c45e5b15aa54b625d68dd947f1597…

I am Satoshi Nakamoto9 => 7007cf7dd40f5e933cd89fff5b791ff0…

I am Satoshi Nakamoto10 => c2f38c81992f4614206a21537bd634a…

I am Satoshi Nakamoto11 => 7045da6ed8a914690f087690e1e8d66…

I am Satoshi Nakamoto12 => 60f01db30c1a0d4cbce2b4b22e88b9b…

I am Satoshi Nakamoto13 => 0ebc56d59a34f5082aaef3d66b37a66…

I am Satoshi Nakamoto14 => 27ead1ca85da66981fd9da01a8c6816…

I am Satoshi Nakamoto15 => 394809fb809c5f83ce97ab554a2812c…

I am Satoshi Nakamoto16 => 8fa4992219df33f50834465d3047429…

I am Satoshi Nakamoto17 => dca9b8b4f8d8e1521fa4eaa46f4f0cd…

I am Satoshi Nakamoto18 => 9989a401b2a3a318b01e9ca9a22b0f3…

I am Satoshi Nakamoto19 => cda56022ecb5b67b2bc93a2d764e75f…

Cada frase produce un hash resultante completamente diferente. Parecen completamente al azar, pero si replica los valores exactos de este ejemplo en cualquier computadora con Python, obtendrá exactamente los mismos hashes.

El número que se ha utilizado como variable en este escenario se llama nonce. El nonce se utiliza para variar la salida de una función criptográfica, en este caso para variar la huella digital SHA256 de la frase.

Como ejemplo de este algoritmo, vamos a establecer un objetivo arbitrario: encontrar una frase que produzca un hash hexadecimal que comience con un cero. Afortunadamente, ¡esto no es difícil! Salida SHA256 de un script para generar muchos hashes iterando un nonce muestra que la frase «I am Satoshi Nakamoto13» produce el hash:

0ebc56d59a34f5082aaef3d66b37a661696c2b618e62432727216ba9531041a5

Que se ajusta a nuestros criterios. Se necesitaron 13 intentos para encontrarlo. En términos de probabilidades, si la salida de la función hash se distribuye uniformemente deberíamos encontrar un resultado con un 0 como prefijo hexadecimal una vez de cada 16 hashes (uno de cada 16 dígitos hexadecimales 0 a F). En términos numéricos, eso significaría encontrar un valor hash que sea menor que:

0x1000000000000000000000000000000000000000000000000000000000000000

A este umbral, lo llamamos objetivo, y la intención es encontrar un hash que sea numéricamente menor que el objetivo.

Si disminuimos el objetivo, la tarea de encontrar un hash que sea menor que el objetivo se vuelve más y más difícil.

Por hacer una analogía, imagine un juego donde los jugadores tiran un par de dados en repetidas ocasiones, tratando sacar un valor por debajo de un objetivo especificado. En la primera ronda, el objetivo es 12. Si obtiene cualquier valor distinto de un doble seis, usted gana. En la siguiente ronda el objetivo es 11. Los jugadores deben obtener un 10 o menos para ganar, de nuevo una tarea fácil.

Digamos que un par de rondas más tarde, el objetivo se ha reducido a 5. Ahora, más de la mitad de los lanzamientos de dados sumarían más de 5 y por lo tanto serían jugadas perdedoras. Cuanto menor sea el objetivo, se necesitarán exponencialmente más lanzamientos de dados para ganar. Finalmente, cuando el objetivo sea 2 (el mínimo posible), sólo un lanzamiento de cada 36, o el 2% de ellos, producirá un resultado ganador. En Salida SHA256 de un script para generar muchos hashes iterando un nonce, el «nonce» ganador es 13 y este resultado puede ser confirmado independientemente por cualquier persona. Cualquiera puede añadir el número 13 como sufijo a la frase «I am Satoshi Nakamoto» y calcular el hash, verificando que es menor que el objetivo. El resultado exitoso es también una prueba de trabajo, porque prueba que hicimos el trabajo para encontrar el nonce. Si bien solo se necesita un cálculo de hash para verificar, nos tomó 13 cálculos de hash para encontrar un nonce que funcionara. Si tuviéramos un objetivo menor (mayor dificultad) se necesitarían muchos más cálculos de hash para encontrar un nonce adecuado, pero solo un cálculo de hash para que cualquiera pueda verificarlo. Por otra parte, al conocer el objetivo, cualquiera puede estimar la dificultad mediante el uso de estadísticas y por lo tanto saber la cantidad de trabajo que se necesitó para encontrar ese nonce.

La prueba de trabajo de Bitcoin es muy similar al desafío que se muestra en Salida SHA256 de un script para generar muchos hashes iterando un nonce. El minero construye un bloque candidato lleno de transacciones. A continuación, el minero calcula el hash de la cabecera de este bloque y ve si es más pequeño que el objetivo actual. Si el hash no es menor que el objetivo, el minero modificará el nonce (por lo general incrementando solo por uno) y lo intentará de nuevo. Para la dificultad actual en la red bitcoin, los mineros tienen que intentar trillones de veces antes de encontrar un nonce que produzca un hash de cabecera de bloque lo suficientemente bajo.

Un algoritmo muy simplificado de prueba de trabajo se implementa en Python en Implementación de prueba de trabajo simplificada.

Ejemplo 10. Implementación de prueba de trabajo simplificada

#!/usr/bin/env python

# example of proof-of-work algorithm

import hashlib

import time

max_nonce = 2 ** 32 # 4 billion

def proof_of_work(header, difficulty_bits):

# calculate the difficulty target

target = 2 ** (256-difficulty_bits)

for nonce in xrange(max_nonce):

hash_result = hashlib.sha256(str(header)+str(nonce)).hexdigest()

# check if this is a valid result, below the target

if long(hash_result, 16) < target:

print "Success with nonce %d" % nonce

print "Hash is %s" % hash_result

return (hash_result,nonce)

print "Failed after %d (max_nonce) tries" % nonce

return nonce

if __name__ == '__main__':

nonce = 0

hash_result = ''

# difficulty from 0 to 31 bits

for difficulty_bits in xrange(32):

difficulty = 2 ** difficulty_bits

print "Difficulty: %ld (%d bits)" % (difficulty, difficulty_bits) print "Starting search…"

# checkpoint the current time

start_time = time.time()

# make a new block which includes the hash from the previous block

# we fake a block of transactions - just a string

new_block = 'test block with transactions' + hash_result

# find a valid nonce for the new block

(hash_result, nonce) = proof_of_work(new_block, difficulty_bits)

# checkpoint how long it took to find a result

end_time = time.time()

elapsed_time = end_time - start_time

print "Elapsed Time: %.4f seconds" % elapsed_time

if elapsed_time > 0:

# estimate the hashes per second

hash_power = float(long(nonce)/elapsed_time)

print "Hashing Power: %ld hashes per second" % hash_power

Mediante la ejecución de este código, puede establecer la dificultad que desee (en bits, cuántos de los primeros bits deben ser cero) y ver cuánto tiempo se necesita para encontrar una solución en su equipo. En Ejecutando el ejemplo de prueba de trabajo para diversas dificultades, se puede ver cómo funciona en un ordenador portátil normal.

Ejemplo 11. Ejecutando el ejemplo de prueba de trabajo para diversas dificultades

$ python proof-of-work-example.py*

Dificultad: 1 (0 bits)

[…]

Dificultad: 8 (3 bits)

Empezando la búsqueda …

Encontrado con nonce 9

Hash es 1c1c105e65b47142f028a8f93ddf3dabb9260491bc64474738133ce5256cb3c1

Tiempo transcurrido: 0,0004 segundos

Poder de Hashing: 25065 hashes por segundo

Dificultad: 16 (4 bits)

Empezando la búsqueda …

Encontrado con nonce 25

Hash es 0f7becfd3bcd1a82e06663c97176add89e7cae0268de46f94e7e11bc3863e148

Tiempo transcurrido: 0,0005 segundos

Poder de Hashing: 52507 hashes por segundo

Dificultad: 32 (5 bits)

Empezando la búsqueda …

Encontrado con nonce 36

Hash es 029ae6e5004302a120630adcbb808452346ab1cf0b94c5189ba8bac1d47e7903

Tiempo transcurrido: 0,0006 segundos

Poder de Hashing: 58164 hashes por segundo

[…]

Dificultad: 4194304 (22 bits)

Empezando la búsqueda …

Encontrado con nonce 1759164

Hash es 0000008bb8f0e731f0496b8e530da984e85fb3cd2bd81882fe8ba3610b6cefc3

Tiempo transcurrido: 13,3201 segundos

Poder de Hashing: 132068 hashes por segundo

Dificultad: 8388608 (23 bits)

Empezando la búsqueda …

Encontrado con nonce 14214729

Hash es 000001408cf12dbd20fcba6372a223e098d58786c6ff93488a9f74f5df4df0a3

Tiempo transcurrido: 110.1507 segundos

Poder de Hashing: 129048 hashes por segundo

Dificultad: 16777216 (24 bits)

Empezando la búsqueda …

Encontrado con nonce 24586379

Hash es 0000002c3d6b370fccd699708d1b7cb4a94388595171366b944d68b2acce8b95

Tiempo transcurrido: 195.2991 segundos

Poder de Hashing: 125890 hashes por segundo

[…]

Dificultad: 67108864 (26 bits)

Empezando la búsqueda …

Encontrado con nonce 84561291

Hash es 0000001f0ea21e676b6dde5ad429b9d131a9f2b000802ab2f169cbca22b1e21a Tiempo transcurrido: 665.0949 segundos

Poder de Hashing: 127141 hashes por segundo

Como se puede ver, el aumento de la dificultad por 1 bit provoca un aumento exponencial en el tiempo que se tarda en encontrar una solución. Si piensa en todo el espacio de números de 256 bits, cada vez que añade un bit más a cero, se reduce el espacio de búsqueda a la mitad. En Ejecutando el ejemplo de prueba de trabajo para diversas dificultades, se necesitan 84 millones de intentos de hash para encontrar un nonce que produzca un hash con sus primeros 26 bits a cero. Incluso a una velocidad de más de 120.000 hashes por segundo, aún se requerirían 10 minutos en un portátil de consumo para encontrar esta solución.

En el momento de escribir esto, la red está tratando de encontrar un bloque cuyo hash de cabecera sea inferior a:

000000000000004c296e6376db3a241271f43fd3f5de7ba18986e517a243baa7

Como se puede ver, hay un montón de ceros al comienzo de ese hash, lo que significa que el rango aceptable de valores hash es mucho menor, por lo tanto, es más difícil encontrar un hash válido. Tomará en promedio más de 150 billones de cálculos de hash por segundo a la red para descubrir el siguiente bloque. Esto puede parecer una tarea imposible, pero afortunadamente la red está tramitando 100 petahashes por segundo (PH/seg) de potencia de procesamiento, lo que le hará capaz de encontrar, en promedio, un bloque cada 10 minutos.

Representación de la Dificultad

En el bloque 277.316, vimos que el bloque contiene el objetivo de dificultad, en una notación denominada «bits de dificultad» o simplemente «bits», que en el bloque 277.316 tiene el valor de 0x1903a30c. Esta notación expresa el objetivo de dificultad en un formato de coeficiente/exponente, con los dos primeros dígitos hexadecimales para el exponente y los siguientes seis dígitos hexadecimales como el coeficiente. En este bloque, por lo tanto, el exponente es 0x19 y el coeficiente es 0x03a30c.

La fórmula para calcular el objetivo de dificultad a partir de esta representación es:

objetivo = coeficiente * 2

(8 * (exponente – 3))

Usando esa fórmula, y el valor de los bits de dificultad 0x1903a30c, obtenemos:

objetivo = 0x03a30c * 2(0x08 * (0x19 - 0x03))

==> objetivo= 0x03a30c * 2(0x08 * 0x16)

==> objetivo = 0x03a30c * 20xB0

que en decimal es:

==> objetivo = 238.348 * 2^176^

==> objetivo =

22.829.202.948.393.929.850.749.706.076.701.368.331.072.452.018.388.575.715.328

Cambiando de nuevo a hexadecimal:

==> objetivo = 0x0000000000000003A30C00000000000000000000000000000000000000000000

Esto significa que un bloque válido para la altura 277.316 es uno que tenga un hash de cabecera de bloque que sea menor que el objetivo. En binario, ese número tendría al menos los primeros 60 bits puestos a cero. Con este nivel de dificultad, un solo minero procesando un billón de hashes por segundo (1 tera-hash por segundo o 1 TH/seg) solo podría encontrar una solución una vez cada 8496 bloques o una vez cada 59 días, en promedio.

Objetivo de Dificultad y Recálculo de Dificultad.

Como hemos visto, el objetivo determina la dificultad y por lo tanto afecta a cuánto tiempo se tarda en encontrar una solución al algoritmo de prueba de trabajo. Esto lleva a la pregunta obvia: ¿Por qué es la dificultad ajustable, qué se ajusta, y cómo?

Los bloques de Bitcoin se generan cada 10 minutos, de promedio. Este es el latido del bitcoin y sostiene la frecuencia de emisión de la moneda y la velocidad de la liquidación de las transacciones. Tiene que permanecer constante no solo en el corto plazo, sino a lo largo de muchas décadas. Durante este tiempo, se espera que la potencia de los ordenadores seguirá aumentando a un ritmo rápido. Además, el número de participantes en la minería y los ordenadores que utilizan están también en constante cambio. Para mantener el tiempo de generación de bloque en 10 minutos, la dificultad de la minería debe ajustarse para tener en cuenta estos cambios. De hecho, la dificultad es un parámetro dinámico que se ajusta periódicamente para cumplir con un objetivo de bloque de 10 minutos. En términos simples, el objetivo de dificultad se ajusta a la potencia de minería que hace que el intervalo entre bloques sea de 10 minutos.

Entonces, ¿Cómo se hace un ajuste de este tipo en una red completamente descentralizada? El recálculo de la dificultad se produce en cada nodo completo de forma automática e independiente.

Cada 2016 bloques, todos los nodos recalculan el objetivo de dificultad de la prueba de trabajo. La ecuación para recalcular el objetivo de dificultad mide el tiempo que se tardó en encontrar los últimos 2016 bloques y lo compara con el tiempo esperado de 20160 minutos (dos semanas sobre la base de un bloque de tiempo deseado de 10 minutos). Se calcula el cociente entre el intervalo de tiempo real y el intervalo de tiempo deseado y se hace el ajuste correspondiente (arriba o abajo) a la dificultad. En términos simples: Si la red está encontrando bloques más rápido que cada 10 minutos, la dificultad aumenta. Si la extracción de bloques es más lenta de lo esperado, la dificultad disminuye.

La ecuación se puede resumir como:

Nueva Dificultad = Dificultad Antigua * (Tiempo Real de 2016 Últimos Bloques / 20160 minutos)

Recalculando la dificultad de la prueba de trabajo — CalculateNextWorkRequired() en pow.cpp muestra el código utilizado en el cliente Bitcoin Core.

Ejemplo 12. Recalculando la dificultad de la prueba de trabajo — CalculateNextWorkRequired() en pow.cpp

// Etapa de ajuste de límite

int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime; LogPrintf(" nActualTimespan = %d before bounds\n", nActualTimespan); if (nActualTimespan < params.nPowTargetTimespan/4)

nActualTimespan = params.nPowTargetTimespan/4;

if (nActualTimespan > params.nPowTargetTimespan*4)

nActualTimespan = params.nPowTargetTimespan*4;

// Recálculo

const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);

arith_uint256 bnNew;

arith_uint256 bnOld;

bnNew.SetCompact(pindexLast->nBits);

bnOld = bnNew;

bnNew *= nActualTimespan;

bnNew /= params.nPowTargetTimespan;

if (bnNew > bnPowLimit)

bnNew = bnPowLimit;

Aunque la calibración de la dificultad sucede cada 2016 bloques, debido a un error de desvío-por-uno en el cliente original Bitcoin Core, el tiempo total se obtiene de los 2015 bloques anteriores (no 2016 como debería ser), lo que resulta en un sesgo en el recálculo hacia una mayor dificultad en 0,05%.

Los parámetros Interval (2016 bloques) y TargetTimespan (dos semanas como 1.209.600 segundos) se definen en chainparams.cpp.

Para evitar la volatilidad extrema en la dificultad, el ajuste de recálculo debe ser inferior a un factor de cuatro (4) por ciclo. Si el ajuste de dificultad requerida es mayor que un factor de cuatro, se ajustará por el máximo y no más. Cualquier otro ajuste se llevará a cabo en el siguiente período de recálculo porque el desequilibrio persistirá a través de los siguientes 2016 bloques. Por lo tanto, las grandes discrepancias entre la potencia de hash y la dificultad podrían tardar varios ciclos de 2016 bloques en equilibrarse.

La dificultad de encontrar un bloque bitcoin es aproximadamente «10 minutos de procesamiento» para toda la red, tomando como base el tiempo que se tardó en encontrar los 2016 bloques anteriores, ajustado cada 2016 bloques.

Tenga en cuenta que el objetivo de dificultad es independiente del número de transacciones o del valor de las transacciones.

Esto significa que la cantidad de potencia de hash y por tanto la electricidad gastada para asegurar bitcoin también es completamente independiente del número de transacciones.

Bitcoin puede tramitar más transacciones, lograr una adopción más amplia, y permanecer seguro sin aumentar la potencia de hash desde el nivel actual. El aumento de la potencia de hash es una representación de las fuerzas del mercado a medida que nuevos mineros entran en el mercado para competir por la recompensa. Mientras exista una potencia de hash suficiente bajo el control de mineros honestos en la búsqueda de la recompensa, se prevendrán los ataques de «toma de control» y, por lo tanto, será suficiente para asegurar bitcoin.

El objetivo de dificultad está estrechamente relacionado con el coste de la electricidad y el tipo de cambio de bitcoin con la moneda utilizada para pagar la electricidad. Los sistemas de minería de alto rendimiento han alcanzado prácticamente la máxima eficiencia que le permite la generación actual de fabricación de silicio, convirtiendo la electricidad en la mayor potencia de hash posible. El principal factor que influye en el mercado de la minería es el precio de un kilovatio-hora en bitcoin, ya que determina la rentabilidad de la minería y por lo tanto los incentivos para entrar o salir del mercado minero.

Ir a la siguiente página

Report Page