Original article: How to Create Your Own Cryptocurrency Using Python

Con el auge actual de las criptomonedas, blockchain está creando un gran revuelo en el mundo de la tecnología. Esta tecnología ha atraído tanta atención principalmente por su capacidad para garantizar la seguridad, hacer cumplir la descentralización y acelerar los procesos en varias industrias, especialmente en la industria financiera.

Esencialmente, una cadena de bloques (blockchain) es una base de datos pública que documenta y auténtica irreversiblemente la posesión y transmisión de activos digitales. Las monedas digitales, como Bitcoin y Ethereum, se basan en este concepto. Blockchain es una tecnología emocionante que puedes utilizar para transformar las capacidades de tus aplicaciones.

Últimamente, hemos visto gobiernos, organizaciones e individuos que utilizan la tecnología blockchain para crear sus propias criptomonedas y evitar quedarse atrás. En particular, cuando Facebook propuso su propia criptomoneda, llamada Libra, el anuncio agitó muchas aguas en todo el mundo.

¿Qué pasaría si también pudieras hacer lo mismo y crear tu propia versión de una criptomoneda?

Pensé en esto y decidí desarrollar un algoritmo que crea una criptografía.

Decidí llamar a la criptomoneda fccCoin.

En este tutorial, voy a ilustrar el proceso paso a paso que utilicé para crear la moneda digital (utilicé los conceptos orientados a objetos del lenguaje de programación Python).

Este es el modelo básico del algoritmo de cadena de bloques para crear fccCoin:

class Block:

    def __init__():

    #primera clase bloque

        pass
    
    def calculate_hash():
    
    #calcula el hash criptográfico de cada bloque    
    
class BlockChain:
    
    def __init__(self):
     # método constructor
    pass
    
    def construct_genesis(self):
        # construye el bloque inicial
        pass

    def construct_block(self, proof_no, prev_hash):
        # construye un nuevo bloque y lo agrega a la cadena
        pass

    @staticmethod
    def check_validity():
        # comprueba si la cadena de bloques es válida
        pass

    def new_data(self, sender, recipient, quantity):
        # agrega una nueva transacción a los datos de las transacciones
        pass

    @staticmethod
    def construct_proof_of_work(prev_proof):
        # protege la cadena de bloques de ataques
        pass
   
    @property
    def last_block(self):
        # devuelve el último bloque de la cadena
        return self.chain[-1]

Ahora, déjame explicarte lo que está sucediendo...

1. Construyendo la primera clase Block

Una cadena de bloques se compone de varios bloques que se unen entre sí (eso suena familiar, ¿verdad?).

El encadenamiento de bloques se lleva a cabo de tal manera que si se manipula un bloque, el resto de la cadena se vuelve inválido.

Al aplicar el concepto anterior, creé la siguiente clase Block inicial:

import hashlib
import time

class Block:

    def __init__(self, index, proof_no, prev_hash, data, timestamp=None):
        self.index = index
        self.proof_no = proof_no
        self.prev_hash = prev_hash
        self.data = data
        self.timestamp = timestamp or time.time()

    @property
    def calculate_hash(self):
        block_of_string = "{}{}{}{}{}".format(self.index, self.proof_no,
                                              self.prev_hash, self.data,
                                              self.timestamp)

        return hashlib.sha256(block_of_string.encode()).hexdigest()

    def __repr__(self):
        return "{} - {} - {} - {} - {}".format(self.index, self.proof_no,
                                               self.prev_hash, self.data,
                                               self.timestamp)


Como puedes ver en el código anterior, definí la función __init__(), que se ejecutará cuando se inicie la clase Block, como en cualquier otra clase de Python.

Proporcioné los siguientes parámetros a la función de iniciación:

  • self—se refiere a la instancia de la clase Block, que permite acceder a los métodos y atributos asociados a la clase;
  • index—realiza un seguimiento de la posición del bloque dentro de la cadena de bloques;
  • proof_no—este es el número producido durante la creación de un nuevo bloque (llamado minería);
  • prev_hash—se refiere al hash del bloque anterior dentro de la cadena;
  • data—esto brinda un registro de todas las transacciones completadas, como la cantidad comprada;
  • timestamp—esto coloca una marca de tiempo para las transacciones.

El segundo método de la clase, calculate_hash, generará el hash de los bloques utilizando los valores anteriores. El módulo SHA-256 se importa al proyecto para ayudar a obtener los hash de los bloques.

Una vez que los valores se hayan ingresado en el algoritmo hash criptográfico, la función devolverá una cadena de 256 bits que representa el contenido del bloque.

Así es como se logra la seguridad en las cadenas de bloques: cada bloque tendrá un hash y ese hash se basará en el hash del bloque anterior.

Como tal, si alguien intenta comprometer cualquier bloque de la cadena, los otros bloques tendrán hashes no válidos, lo que provocará la interrupción de toda la red de la cadena de bloques.

En última instancia, un bloque se verá así:

{
    "index": 2,
    "proof": 21,
    "prev_hash": "6e27587e8a27d6fe376d4fd9b4edc96c8890346579e5cbf558252b24a8257823",
    "transactions": [
        {'sender': '0', 'recipient': 'Quincy Larson', 'quantity': 1}
    ],
    "timestamp": 1521646442.4096143
}

2. Construyendo la clase Blockchain

La idea principal de una cadena de bloques, tal como su nombre lo indica, consiste en "encadenar" varios bloques entre sí.

Por lo tanto, voy a construir una clase Blockchain que será útil para administrar el funcionamiento de toda la cadena. Aquí es donde se desarrollará la mayor parte de la acción.

La clase Blockchain tendrá varios métodos auxiliares para completar varias tareas en la cadena de bloques.

Permíteme explicar el papel de cada uno de los métodos en la clase.

a. Método constructor

Este método garantiza que se cree una instancia de la cadena de bloques.

class BlockChain:

    def __init__(self):
        self.chain = []
        self.current_data = []
        self.nodes = set()
        self.construct_genesis()

Estos son los roles de sus atributos:

  • self.chain —esta variable mantiene todos los bloques;
  • self.current_data —esta variable mantiene todas las transacciones completadas en el bloque;
  • self.construct_genesis() —este método se encargará de construir el bloque inicial.

b. Construyendo el bloque de génesis

La cadena de bloques requiere un método construct_genesis para construir el bloque inicial en la cadena. En la convención de la cadena de bloques, este bloque es especial porque simboliza el inicio de la cadena de bloques.

En este caso, construyámoslo simplemente pasando algunos valores predeterminados al método construct_block.

Le di a proof_no y prev_hash un valor de cero, aunque puedes proporcionar cualquier valor que desees.

def construct_genesis(self):
    self.construct_block(proof_no=0, prev_hash=0)


def construct_block(self, proof_no, prev_hash):
    block = Block(
        index=len(self.chain),
        proof_no=proof_no,
        prev_hash=prev_hash,
        data=self.current_data)
    self.current_data = []

    self.chain.append(block)
    return block

C. Construyendo nuevos bloques.

El método construct_block se utiliza para crear nuevos bloques en la cadena de bloques.

Esto es lo que está ocurriendo con los diversos atributos de este método:

  • index—esto representa la longitud de la cadena de bloques;
  • proof_nor & prev_hash —el método que llama los pasa;
  • data — contiene un registro de todas las transacciones que no están incluidas en ningún bloque del nodo;
  • self.current_data: se usa para restablecer la lista de transacciones en el nodo. Si se ha construido un bloque y se le han asignado transacciones, la lista se restablece para garantizar que se agreguen transacciones futuras a esta lista. Y, este proceso se llevará a cabo continuamente;
  • self.chain.append()— este método une bloques recién construidos a la cadena;
  • return: por último, se devuelve un objeto de bloque construido.

d. Comprobación de validez


El método check_validity es importante para evaluar la integridad de la cadena de bloques y garantizar que no haya anomalías.

Como se mencionó anteriormente, los hashes son esenciales para la seguridad de la cadena de bloques, ya que incluso el más mínimo cambio en el objeto conducirá a la generación de un hash completamente nuevo.

Por lo tanto, este método check_validity usa declaraciones if para verificar si el hash de cada bloque es correcto.

También verifica si cada bloque apunta al bloque anterior correcto, comparando el valor de sus hashes. Si todo es correcto, devuelve verdadero; de lo contrario, devuelve falso.

@staticmethod
def check_validity(block, prev_block):
    if prev_block.index + 1 != block.index:
        return False

    elif prev_block.calculate_hash != block.prev_hash:
        return False

    elif not BlockChain.verifying_proof(block.proof_no, prev_block.proof_no):
        return False

    elif block.timestamp <= prev_block.timestamp:
        return False

    return True

e. Adición de datos de transacciones

El método new_data se utiliza para agregar los datos de las transacciones a un bloque. Es un método muy simple: acepta tres parámetros (detalles del remitente, detalles del destinatario y cantidad) y agrega los datos de la transacción a la lista self.current_data.

Cada vez que se crea un nuevo bloque, esta lista se asigna a ese bloque y se restablece una vez más, como se explica en el método construct_block .

Una vez que se han agregado los datos de la transacción a la lista, se devuelve el índice del siguiente bloque que se creará.

Este índice se calcula sumando 1 al índice del bloque actual (que es el último de la cadena de bloques). Los datos ayudarán al usuario a enviar la transacción en el futuro.

def new_data(self, sender, recipient, quantity):
    self.current_data.append({
        'sender': sender,
        'recipient': recipient,
        'quantity': quantity
    })
    return True

f. Agregar prueba de trabajo

La prueba de trabajo es un concepto que evita el abuso de la cadena de bloques. Simplemente, su objetivo es identificar un número que resuelva un problema después de realizar una cierta cantidad de trabajo de cómputo.

Si el nivel de dificultad para identificar el número es alto, se desalienta el spam y la manipulación de la cadena de bloques.

En este caso, usaremos un algoritmo simple que disuade a las personas de minar bloques o crear bloques fácilmente.

@staticmethod
def proof_of_work(last_proof):
    '''this simple algorithm identifies a number f' such that hash(ff') contain 4 leading zeroes
         f is the previous f'
         f' is the new proof
        '''
    proof_no = 0
    while BlockChain.verifying_proof(proof_no, last_proof) is False:
        proof_no += 1

    return proof_no


@staticmethod
def verifying_proof(last_proof, proof):
    #verifying the proof: does hash(last_proof, proof) contain 4 leading zeroes?

    guess = f'{last_proof}{proof}'.encode()
    guess_hash = hashlib.sha256(guess).hexdigest()
    return guess_hash[:4] == "0000"

g. Conseguir el último bloque

Por último, el método latest_block es un método auxiliar que ayuda a obtener el último bloque de la cadena de bloques. Recuerde que el último bloque es en realidad el bloque actual de la cadena.

@property
    def latest_block(self):
        return self.chain[-1]

Sumemos todo junto

Aquí está el código completo para crear la criptomoneda fccCoin .

También puedes obtener el código en este repositorio de GitHub.

import hashlib
import time


class Block:

    def __init__(self, index, proof_no, prev_hash, data, timestamp=None):
        self.index = index
        self.proof_no = proof_no
        self.prev_hash = prev_hash
        self.data = data
        self.timestamp = timestamp or time.time()

    @property
    def calculate_hash(self):
        block_of_string = "{}{}{}{}{}".format(self.index, self.proof_no,
                                              self.prev_hash, self.data,
                                              self.timestamp)

        return hashlib.sha256(block_of_string.encode()).hexdigest()

    def __repr__(self):
        return "{} - {} - {} - {} - {}".format(self.index, self.proof_no,
                                               self.prev_hash, self.data,
                                               self.timestamp)


class BlockChain:

    def __init__(self):
        self.chain = []
        self.current_data = []
        self.nodes = set()
        self.construct_genesis()

    def construct_genesis(self):
        self.construct_block(proof_no=0, prev_hash=0)

    def construct_block(self, proof_no, prev_hash):
        block = Block(
            index=len(self.chain),
            proof_no=proof_no,
            prev_hash=prev_hash,
            data=self.current_data)
        self.current_data = []

        self.chain.append(block)
        return block

    @staticmethod
    def check_validity(block, prev_block):
        if prev_block.index + 1 != block.index:
            return False

        elif prev_block.calculate_hash != block.prev_hash:
            return False

        elif not BlockChain.verifying_proof(block.proof_no,
                                            prev_block.proof_no):
            return False

        elif block.timestamp <= prev_block.timestamp:
            return False

        return True

    def new_data(self, sender, recipient, quantity):
        self.current_data.append({
            'sender': sender,
            'recipient': recipient,
            'quantity': quantity
        })
        return True

    @staticmethod
    def proof_of_work(last_proof):
        '''this simple algorithm identifies a number f' such that hash(ff') contain 4 leading zeroes
         f is the previous f'
         f' is the new proof
        '''
        proof_no = 0
        while BlockChain.verifying_proof(proof_no, last_proof) is False:
            proof_no += 1

        return proof_no

    @staticmethod
    def verifying_proof(last_proof, proof):
        #verifying the proof: does hash(last_proof, proof) contain 4 leading zeroes?

        guess = f'{last_proof}{proof}'.encode()
        guess_hash = hashlib.sha256(guess).hexdigest()
        return guess_hash[:4] == "0000"

    @property
    def latest_block(self):
        return self.chain[-1]

    def block_mining(self, details_miner):

        self.new_data(
            sender="0",  #it implies that this node has created a new block
            receiver=details_miner,
            quantity=
            1,  #creating a new block (or identifying the proof number) is awarded with 1
        )

        last_block = self.latest_block

        last_proof_no = last_block.proof_no
        proof_no = self.proof_of_work(last_proof_no)

        last_hash = last_block.calculate_hash
        block = self.construct_block(proof_no, last_hash)

        return vars(block)

    def create_node(self, address):
        self.nodes.add(address)
        return True

    @staticmethod
    def obtain_block_object(block_data):
        #obtains block object from the block data

        return Block(
            block_data['index'],
            block_data['proof_no'],
            block_data['prev_hash'],
            block_data['data'],
            timestamp=block_data['timestamp'])


Ahora, probemos nuestro código para ver si funciona.

blockchain = BlockChain()

print("***Mining fccCoin about to start***")
print(blockchain.chain)

last_block = blockchain.latest_block
last_proof_no = last_block.proof_no
proof_no = blockchain.proof_of_work(last_proof_no)

blockchain.new_data(
    sender="0",  #it implies that this node has created a new block
    recipient="Quincy Larson",  #let's send Quincy some coins!
    quantity=
    1,  #creating a new block (or identifying the proof number) is awarded with 1
)

last_hash = last_block.calculate_hash
block = blockchain.construct_block(proof_no, last_hash)

print("***Mining fccCoin has been successful***")
print(blockchain.chain)

¡Funcionó!

Aquí está el resultado del proceso de minería:

***Mining fccCoin about to start***
[0 - 0 - 0 - [] - 1566930640.2707076]
***Mining fccCoin has been successful***
[0 - 0 - 0 - [] - 1566930640.2707076, 1 - 88914 - a8d45cb77cddeac750a9439d629f394da442672e56edfe05827b5e41f4ba0138 - [{'sender': '0', 'recipient': 'Quincy Larson', 'quantity': 1}] - 1566930640.5363243]

Conclusión

¡Ahí tienes!

Así es como podrías crear tu propia cadena de bloques usando Python.

Permíteme decir que este tutorial solo demuestra los conceptos básicos para mojarse los pies en la innovadora tecnología blockchain.

Si esta moneda se implementara tal como está, no podría satisfacer las demandas actuales del mercado de una criptomoneda estable, segura y fácil de usar.

Por lo tanto, aún se puede mejorar agregando características adicionales para mejorar sus capacidades para extraer y enviar transacciones financieras.

No obstante, es un buen punto de partida si decides dar a conocer tu nombre en el asombroso mundo de las criptomonedas.

Si tienes algún comentario o pregunta, por favor publícalo a continuación.

¡Feliz (cripto) codificación!