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)
Deja una respuesta