Criptografía

Dificultad de minado: creación de una criptomoneda (3º Parte)

En la entrada anterior se ha introducido el concepto de prueba de esfuerzo. Para que un usuario pueda agregar un nuevo bloque a la cadena este ha de resolver un problema, lo que se conoce como minado. De este modo, la dificultad de minado se puede utilizar para fijar el tiempo promedio entre bloques.

Gestionando la prueba de esfuerzo

El tiempo medio necesario para añadir un nuevo bloque a la cadena de bloques es el que se tarda en resolver la prueba de esfuerzo. De este modo, si aumenta la potencia de cálculo se reduce el tiempo, mientras que si se reduce aumentara el tiempo entre bloques. Generalmente interesa que el tiempo entre bloques sea constante. Para conseguir esto, simplemente se ha de medir el entre bloques e ir ajustando la dificultad de minado según sea menor o mayor de lo deseado.

Implementación en la cadena de bloques

En la cadena de bloques se han de incluir dos nuevas propiedades para poder gestionar el tiempo que se desde que transcurran entre la inclusión de dos bloques. La primera es el tiempo deseado (block_interval) y la segunda es cada cúantos bloques se reevaluará la dificultad de la prueba de esfuerzo (difficulty_interval).

Para la tarea de agregar un nuevo bloque a la cadena de bloques y gestionar el intervalo entre bloques se creará el método next_block. Este método se le introducirán los datos, se evaluará la dificultad actualizándola cuando sea necesario, se minará el bloque y se agregara a la cadena. Será necesario comprobar también que la fecha del nuevo bloque es posterior a la del ultimo existente en la cadena de bloques. Este proceso se puede ver en el siguiente código:

class BlockChain:
    def __init__(self, block):
        self.block_interval = 120
        self.difficulty_interval = 2
        
        self.chain = [block]

    def add_block(self, block):
        self.chain.append(block)
    
    def next_block(self, data, timestamp, mining = True):
        if self.chain[-1].timestamp > timestamp:
            return
        
        difficulty = self.chain[-1].difficulty
        
        if len(self.chain) > self.difficulty_interval and len(self.chain) % self.difficulty_interval == 0:
            interval = self.chain[-1].timestamp - self.chain[-self.difficulty_interval-1].timestamp
            interval = interval.total_seconds() / self.difficulty_interval

            if interval > self.block_interval:
                difficulty = difficulty - 1
            elif interval < self.block_interval:
                difficulty = difficulty + 1
                
        block = Block(self.chain[-1].index + 1, data, self.chain[-1].hash, timestamp, difficulty)
        
        if mining:
            block.mining()
            
        self.add_block(block)
        
    def is_valid(self):
        if self.chain:
            for step in range(len(self.chain) - 1, 0, -1):
                if not self.chain[step].is_valid():
                    return False
                elif self.chain[step].previous_hash != self.chain[step - 1].hash:
                    return False
                elif self.chain[step].index != self.chain[step - 1].index + 1:
                    return False

            return True

        return False

Para poder probar el código con facilidad se ha utilizado valores bajos para la frecuencia y el tiempo entre evaluaciones. Concretamente se ha indicado que el intervalo promedio en el que se desea que se añada un bloque es de 120 segundos (block_interval = 120) y que la evaluación se realizará cada 2 bloques (difficulty_interval = 2).

El comportamiento se puede ver en la siguiente pieza de código en la que inicialmente se generan los bloques cada minuto, por lo que la dificultad se vera reducida cada dos bloques. Posteriormente los bloques se agregarán cada 3 minutos, de modo que se reducirá cada dos bloques

from datetime import datetime

block = Block(0, None, None, datetime(2000, 1, 1, 0, 0, 0))
block.mining()

blockchain = BlockChain(block)

for minutes in range(1, 10):
    blockchain.next_block(None, datetime(2000, 1, 1, 0, minutes, 0))

for minutes in range(11, 40, 3):
    blockchain.next_block(None, datetime(2000, 1, 1, 0, minutes, 0))
    
print('Increase', blockchain.chain[3].difficulty, 'to', blockchain.chain[4].difficulty)
print('Increase', blockchain.chain[5].difficulty, 'to', blockchain.chain[6].difficulty)
print('Decrease', blockchain.chain[11].difficulty, 'to', blockchain.chain[12].difficulty)
print('Decrease', blockchain.chain[13].difficulty, 'to', blockchain.chain[14].difficulty)

Imágenes: Pixabay (mmi9)

¿Te ha parecido de utilidad el contenido?

Daniel Rodríguez

Share
Published by
Daniel Rodríguez

Recent Posts

Data Lake y Data Warehouse: diferencias, usos y cómo se complementan en la era del dato

En la era del dato, las organizaciones se enfrentan al reto de gestionar volúmenes masivos…

3 días ago

Documentar tu API de Express con TypeScript usando OpenAPI (Swagger)

En la serie Creación de una API REST con Express y TypeScript construimos una API…

5 días ago

Curiosidad: El sesgo de supervivencia, o por qué prestar atención sólo a los que “llegaron” puede engañarte

Durante la Segunda Guerra Mundial, la Fuerza Aérea de Estados Unidos quería reforzar sus aviones…

1 semana ago

Cómo abrir una ventana de Chrome con tamaño y posición específicos desde la línea de comandos en Windows

En muchas situaciones —ya sea para grabar un tutorial, tomar capturas de pantalla profesionales, probar…

2 semanas ago

La Paradoja del Cumpleaños, o por qué no es tan raro compartir fecha de nacimiento

Imagínate en una sala con un grupo de personas, por ejemplo, en una oficina, un…

2 semanas ago

Programador de tareas de Windows: Guía definitiva para automatizar tu trabajo (BAT, PowerShell y Python)

En el trabajo diario con ordenadores, es común encontrarse con tareas repetitivas: realizar copias de…

3 semanas ago

This website uses cookies.