Criptografía

Wallet: creación de una criptomoneda (6ª Parte)

En las entradas anteriores se ha construido una cadena de bloques y sobre este una criptomoneda moneda. Para implementar la criptomoneda ha sido necesario definir unas transacciones y un proceso de validación para las mismas. Este proceso es demasiado complejo para que un usuario lo pueda realizar correctamente de forma manual. Para solucionar este problema se suelen crear las carteras (Wallet). El objetivo de estas es crear una interfaz más abstracta para el usuario final.

Algunas de las tareas que han de poder realizase con un Wallet de forma sencilla son:

  • Crear una nueva dirección con el par de claves privada y publica
  • Consultar el balance disponible en el Wallet
  • Enviar dinero a otras cuentas

Definición del constructor del Wallet

La clase con la que se implemente la cartera ha de disponer de la siguiente información:

  • La clave privad
  • La clave pública
  • Las transacciones no gastadas

Basándose en esta información se puede definir el siguiente constructor.

class Wallet:
    def __init__(self, private=None, blockchain=None):
        if private is None:
            sk = SigningKey.generate()
            self.private = sk.to_string().hex()
            self.public = sk.get_verifying_key().to_string().hex()
        else:
            self.private = private
            self.public = generate_public_key(private)

        self.unspent = None
        self.blockchain = blockchain

Se puede observar que tiene dos parámetros de entrada opcionales: la clave privada y la cadena de bloques. Tal como se puede apreciar en el código la clave pública se puede obtener a partir de la clave privada. En el caso de que no se indique una clave privada el constructor generara un nuevo para de claves. Las transacciones no gastadas se pueden obtener a partir de la cadena de bloques utilizando el siguiente método:

def __update_unspent(self):
    if self.blockchain is not None:
        self.unspent = self.blockchain.get_unspent_list()

Obtención del balance

Uno de los datos más importantes para los usuarios es la situación del balance. Para obtener este valor se ha de recorrer las transacciones no gastadas de la cuenta y sumar el resultado. En el objeto Wallet se puede definir el siguiente método para realizar esta tarea.

def get_balance(self):
    self.__update_unspent()

    if self.unspent is None:
        return 0
    else:
        return self.unspent.address_amount(self.public)

Generación de una transferencia

En la entrada anterior se pudo ver la complejidad que lleva crear una transacción. Para ello es necesario obtener las transacciones no gastadas, agrupar las necesarias para hacer la transacción, transferir el remanente a la propia cuenta y firmar la operación. Una vez realizado esto se ha de enviar la transacción a la cadena de bloques para que se agregue en el siguiente bloque.

Para un usuario final este proceso ha de ser tan sencillo como indicar la cuenta de destino y la cantidad a transferir. Estos pasos se implementan en el siguiente método:

def generate_transaction_to(self, account, amount):
    # Update unspent list
    self.__update_unspent()

    # Validate if there are enough balance
    if self.get_balance() < amount:
        return None

    # Get the unspent transaction
    user_transactions = self.unspent.address_transactions(self.public)

    # Generate the input accounts
    inputs = []
    used_from_balance = 0

    for transaction in user_transactions:
        used_from_balance += transaction.amount
        inputs.append(InputTransaction(transaction.hash_id, transaction.index))

        if used_from_balance >= amount:
            break

    # Calculate the quantity to keep in balance
    keep_in_balance = used_from_balance - amount

    # Calculate output transfers
    if keep_in_balance == 0:
        outputs = OutputTransaction(account, amount)
    else:
        outputs = [OutputTransaction(account, amount), OutputTransaction(self.public, keep_in_balance)]

    # Generate transaction and sign
    transaction = Transaction(inputs, outputs, self.private)

    return transaction

Conclusiones

En esta entrada se ha construido una clase Wallet que permite abstraer la complejidad de las transacciones para un usuario final. La definición de este objeto es clave para conseguir una criptomoneda que pueda ser utilizada por los usuarios finales.

El código completo que se ha utilizado en esta serie se puede encontrar en el siguiente repositorio de GitHub.

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…

2 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…

4 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.