Blog
Hasta ahora tenemos solamente creada la clase que se encargará de instanciar los clientes, ahora vamos a crear la clase Transacciones
esta clase es la que creará la transacción para que los clientes puedan enviarse la criptomonedas entre ellos, entonces vamos a proceder a crear dicha clase.
En primer lugar la clase cliente contendrá un constructor, ya que esta clase debe recibir el cliente que realiza la transacción que en pocas palabras es quien envía el dinero, también deberá recibir el cliente que recibirá el dinero además el importe de la transacción y por último la fecha en que se hizo la transacción:
def __init__(self, cliente_envia, cliente_recibe, importe): self.cliente_envia = cliente_envia self.cliente_recibe = cliente_recibe self.importe = importe self.fecha = datetime.datetime.now()
Este constructor lo que hace es crear el objeto transacción con los valores correspondientes de una transacción, ahora vamos a proceder a crear un método al que llamaremos diccionario
, este método se encargará de transformar los 4 valores que recibe en el contructor a un diccionario, con la única finalidad de guardar los datos de la transacción en una variable, algo realmente útil:
def dicionario(self): if self.cliente_envia == "Genesis": identidad = "Genesis" else: identidad = self.cliente_envia.identidad return collections.OrderedDict({'cliente_envia ': identidad, 'cliente_recibe': self.cliente_recibe, 'importe': self.importe, 'fecha': self.fecha})
El bloque Génesis
El bloque Génesis contiene la primera transacción iniciada por el creador del blockchain, la identidad de esta persona puede mantenerse en secreto como en el caso de Bitcoins. Entonces cuando se crea esta primera transacción, el creador puede enviar su identidad como Génesis. Por lo tanto, al crear el diccionario, verificamos si el remitente es Génesis, de ser así, simplemente asignamos a la variable de identidad el valor de Genesis; de lo contrario, asignamos la identidad del remitente a la variable identidad.
Finalmente firmaremos el diccionario creado utilizando la clave privada del remitente y lo haremos con el algoritmo SHA, luego de esto la firma generada se decodifica para obtenerla en representación ASCII para así poder imprimirla y almacenarla en nuestro blockchain, para firmar dicho diccionario debemos crear una nueva clase a la que llamaremos firmar_transaccion
:
def firmar_transaccion(self): clave_privada = self.cliente_envia._clave_privada firma = PKCS1_v1_5.new(clave_privada) h = SHA.new(str(self.diccionario()).encode('utf8')) return binascii.hexlify(firma.sign(h)).decode('ascii')
Tenemos lista nuestra clase de transacciones, solo falta probarla para asegurarnos de que funciona correctamente, para eso lo que vamos a hacer es instanciar una transacción, para ellos vamos a instancia a dos clientes y los enviaremos a ambos a la transacción y luego comprobaremos los métodos diccionario
y firmar_diccionarios
, probemos primero con el método diccionario:
Juan = Cliente() Jose = Cliente() t = Transaccion( Juan, Jose.identidad, 5.0 ) diccionario = t.diccionario() print (diccionario)
Al correr el código podremos ver los valores que recibe el constructor de la clase en forma de diccionario:
λ python blockchain.py OrderedDict([('cliente_envia','30819f300d06092a864886f70d010101050003818d003081890281810095a0a53e40ca4ed9e32b205ed2f2069812ca82ff46d3b0b671d86d6adf5c935157d4659fdf01bdde20d63f0738282597d7203c5cfc7a128e0bbdcd8533eef9e695ead30c197df7a61412cef4d92549a8dd6b348444160961b4f9a1968758c2495bfa831cb357c848192afd3bbecfb45f746021ce2d1b64208f8b4d062e5d58fb0203010001'),('recipient', '30819f300d06092a864886f70d010101050003818d0030818902818100bd4207cb4ccf7c64caae27589e6db09b22919ab2bacaaf4389647dd7e61a5e4c0b25132a96307355c85907d5b112e694f6a7d9a71eec5e9b36869cf25a7f83138d34d9f43291d98ebc5a0b5660bee93543e7162ce13710f959f946c215b8551177aa094f6e409350589bb9fefe5a5b9ec040f5dd1a42a4b06ccccbc2fd1320b10203010001'), ('importe', 5.0), ('time', datetime.datetime(2020, 3, 25, 18, 12, 55, 494400))])
Estos son los datos de nuestra transacción, incluso podremos obtener su valor haciendo uso de la sintaxis para diccionarios, por ejemplo si quisiera ver solamente por cuanto es el importe de la transacción, fácilmente podría indicarlo pasandole la clave a la variable diccionario de la siguiente manera:
print(diccionario['importe'])
Ejecutando nuevamente obtendría el importe:
λ python blockchain.py 5.0
Muy bien, ahora vamos a probarlo con el método que firma nuestra transacción:
Juan = Cliente() Jose = Cliente() t = Transaccion( Juan, Jose.identidad, 5.0 ) firma = t.firmar_transaccion() print (firma)
Al correr nuestro código deberíamos de obtener la clave privada del cliente que envío la transacción en codificación ASCII, deberíamos de obtener algo como esto:
λ python blockchain.py 73a686ae6dddac591b222428ea317eb268a98bcd2138df41e19663de0987dc72cf756a4228521c157b027ec004763254e04432f2d66fb44ef16399ad67b3bde023af4f5614e60d0eaf43f07fc5f4cbe6810101aae149cee5b1951f3a9a674267fe6996f5dc5bfc0bdbdc303bfae976de4008e01e2e37699a46aa929ed92dd457
Con esto ya hemos creado la clase que se encarga de manejar las transacciones, pero hasta ahora nuestra red blockchain solo permite una transacción para luego poder realizar otra. Es importante destacar que esto siempre será así, pero lo que si podemos hacer es recibir más transacciones y agregarlas a una cola de espera, también vamos a crear una función que nos permita ver las transacciones que hay en cola y lo haremos con ayuda de una función a la que llamaremos mostrar_transacciones_en_cola.
Esta función además de agregar las transacciones que se encuentra en la lista de espera, también formateará la manera en como se representa en nuestra consola de python a la hora de ejecutar nuestro código, esto con la finalidad de ver los datos de una forma más ordenada, pasemos a crear nuestra función:
def mostrar_transacciones_en_cola(transacciones_en_cola): dict = transaction.diccionario() print("Cliente que envia: " + dict['sender']) print('-----') print("Cliente que recibe: " + dict['recipient']) print('-----') print("Importe: " + str(dict['value'])) print('-----') print("Fecha: " + str(dict['fecha'])) print('-----')
Ahora que ya tenemos la función que tomará las transacciones de la lista de espera, debemos crear dicha lista. Como no estamos usando una base de datos lo ideal es crear una variable global, donde registramos cada una de las transacciones que se vayan creando y así nuestra función pueda tomarlas, entonces vamos a proceder a crearla para ello solo debemos escribirla al inicio de nuestro script, precisamente entre los import de librerías y nuestra clase Cliente, a esta variable la llamaremos:
transacciones_en_cola = []
Voy a crear dos clientes más y hasta ahora mi lista de clientes es esta:
Juan = Cliente() Jose = Cliente() Luis = Cliente() Miguel = Cliente()
Ya con estos pequeños cambios, nuestra red blockchain puede recibir muchas transacciones a la vez (esto es tal cual como debería de ser), ahora lo que sigue es instanciar más transacciones:
t1 = Transaccion( Juan, Jose.identity, 15.0 ) t1.firmar_transaccion() transacciones_en_cola.append(t1)
En esta nueva transacción, el cliente Juan
envía al cliente José
un total de 15.0 Unipy luego de instanciar la transacción la firmamos con el propio método de la clase, una vez firmada la agregamos a la lista en cola con ayuda de la función propia de python .append()
Vamos a proceder a instanciar más transacciones y registrarlas en la lista de espera:
t1 = Transaccion( Juan, Jose.identidad, 15.0 ) t1.firmar_transaccion() transacciones_en_cola.append(t1) t2 = Transaccion( Luis, Miguel.identidad, 6.0 ) t2.firmar_transaccion() transacciones_en_cola.append(t2) t3 = Transaccion( Miguel, Juan.identidad, 2.0 ) t3.firmar_transaccion() transacciones_en_cola.append(t3) t4 = Transaccion( Miguel, Jose.identidad, 4.0 ) t4.firmar_transaccion() transacciones_en_cola.append(t4) t5 = Transaccion( Juan, Miguel.identidad, 7.0 ) t5.firmar_transaccion() transacciones_en_cola.append(t5) t6 = Transaccion( Miguel, Luis.identidad, 100.0 ) t6.firmar_transaccion() transacciones_en_cola.append(t6) t7 = Transaccion( Jose, Miguel.identidad, 23.0 ) t7.firmar_transaccion() transacciones_en_cola.append(t7) t8 = Transaccion( Luis, Juan.identidad, 65.0 ) t8.firmar_transaccion() transacciones_en_cola.append(t8) t9 = Transaccion( Jose, Juan.identidad, 324.0 ) t9.firmar_transaccion() transacciones_en_cola.append(t9) print(len(transacciones_en_cola))
Hemos agregado un total de nueve transacciones, pero con la función len()
voy a decir a python que me diga cuantas transacciones hay registradas en la cola de espera si ejecutamos este código obtendriamos lo siguiente:
λ python blockchain.py 9
Efectivamente python me dice que hay nueve transacciones esperando por ser procesadas, entonces ya nos hemos asegurado de agregar algunas transacciones a la lista de espera, ahora debemos hacer uso de la función mostrar_transacciones_en_cola
para hacerlo debemos iterar dichas transacciones en cola y luego pasarle cada transacción a nuestra función:
for transaccion in transacciones_en_cola: mostrar_transacciones_en_cola(transaccion) print('--------------')
Este es nuestro código hasta este punto, así es como debería de ir todo:
class Cliente(): def __init__(self): random = Crypto.Random.new().read self._clave_privada = RSA.generate(1024, random) self._clave_publica = self._clave_privada.publickey() self._signer = PKCS1_v1_5.new(self._clave_privada) @property def identidad(self): return binascii.hexlify(self._clave_publica.exportKey(format='DER')).decode('ascii') class Transaccion(): def __init__(self, cliente_envia, cliente_recibe, importe): self.cliente_envia = cliente_envia self.cliente_recibe = cliente_recibe self.importe = importe self.fecha = datetime.datetime.now() def diccionario(self): if self.cliente_envia == "Genesis": identidad = "Genesis" else: identidad = self.cliente_envia.identidad return collections.OrderedDict({'cliente_envia': identidad, 'cliente_recibe': self.cliente_recibe, 'importe': self.importe, 'fecha': self.fecha}) def firmar_transaccion(self): clave_privada = self.cliente_envia._clave_privada firma = PKCS1_v1_5.new(clave_privada) h = SHA.new(str(self.diccionario()).encode('utf8')) return binascii.hexlify(firma.sign(h)).decode('ascii') def mostrar_transacciones_en_cola(transacciones_en_cola): # for transaction in transacciones_en_cola: dict = transacciones_en_cola.diccionario() print("Cliente que envia: " + dict['cliente_envia']) print('-----') print("Cliente que recibe: " + dict['cliente_recibe']) print('-----') print("Importe: " + str(dict['importe'])) print('-----') print("Fecha: " + str(dict['fecha'])) print('-----') Juan = Cliente() Jose = Cliente() Luis = Cliente() Miguel = Cliente() t1 = Transaccion( Juan, Jose.identidad, 15.0 ) t1.firmar_transaccion() transacciones_en_cola.append(t1) t2 = Transaccion( Luis, Miguel.identidad, 6.0 ) t2.firmar_transaccion() transacciones_en_cola.append(t2) t3 = Transaccion( Miguel, Juan.identidad, 2.0 ) t3.firmar_transaccion() transacciones_en_cola.append(t3) t4 = Transaccion( Miguel, Jose.identidad, 4.0 ) t4.firmar_transaccion() transacciones_en_cola.append(t4) t5 = Transaccion( Juan, Miguel.identidad, 7.0 ) t5.firmar_transaccion() transacciones_en_cola.append(t5) t6 = Transaccion( Miguel, Luis.identidad, 100.0 ) t6.firmar_transaccion() transacciones_en_cola.append(t6) t7 = Transaccion( Jose, Miguel.identidad, 23.0 ) t7.firmar_transaccion() transacciones_en_cola.append(t7) t8 = Transaccion( Luis, Juan.identidad, 65.0 ) t8.firmar_transaccion() transacciones_en_cola.append(t8) t9 = Transaccion( Jose, Juan.identidad, 324.0 ) t9.firmar_transaccion() transacciones_en_cola.append(t9) for transaccion in transacciones_en_cola: mostrar_transacciones_en_cola(transaccion) print('--------------')
Ahora si ejecutamos el script deberíamos de tener una lectura con la información de las transacciones en cola:
λ python blockchain.py Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100b6570a15656f067debe871799c1e969dd809a17a2d810d9d1c3eb357dc38cb286b07c5a491a5a9be8833558105de826c3ffc8ba82b2ec6cbd11f4478af1bebd643508fe05b8d07bb192eb22229b417b5967b59f26ba434fa7aa27e06fb1d274f3ddcd286312117d9b49678449cafd709bd86cf64868a630bf695f538be92a0150203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100ded60b70e326a535a8ca4edbb0e871a4888629c40d208b573ad91a9eb54529f3d3530dc23b8f4d457eae975227bca65e8328bae8519a35b9c63ea5f7b2692ad42dec188dd8f767c1a3bbb350d20e03f7c210db93772390afea4e5803582bd694121cb1d93cbdd688abb2339e7d976e65854fae77bca6a7ec4ef1508f7a428f570203010001 ----- Importe: 15.0 ----- Fecha: 2020-03-25 19:59:59.715727 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d003081890281810090167ad6ffedd2c443b0f75ad384a2cb4e7eee83f32d063bbb5ea1ea0f77044a029a382a6f324296abf2d4f0fb22274a54d7710d06e9b01b17f1576953ad4e2ebe32f5e34945dd48ed4447cb556e31f5ca01ca76aedd3f787a0065b7b6d84bcf6edf2f56ad1af16fd5d4656983fb38d60dbb48d8f05785459e3065a60e622d050203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Importe: 6.0 ----- Fecha: 2020-03-25 19:59:59.721728 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100b6570a15656f067debe871799c1e969dd809a17a2d810d9d1c3eb357dc38cb286b07c5a491a5a9be8833558105de826c3ffc8ba82b2ec6cbd11f4478af1bebd643508fe05b8d07bb192eb22229b417b5967b59f26ba434fa7aa27e06fb1d274f3ddcd286312117d9b49678449cafd709bd86cf64868a630bf695f538be92a0150203010001 ----- Importe: 2.0 ----- Fecha: 2020-03-25 19:59:59.725728 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100ded60b70e326a535a8ca4edbb0e871a4888629c40d208b573ad91a9eb54529f3d3530dc23b8f4d457eae975227bca65e8328bae8519a35b9c63ea5f7b2692ad42dec188dd8f767c1a3bbb350d20e03f7c210db93772390afea4e5803582bd694121cb1d93cbdd688abb2339e7d976e65854fae77bca6a7ec4ef1508f7a428f570203010001 ----- Importe: 4.0 ----- Fecha: 2020-03-25 19:59:59.730229 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100b6570a15656f067debe871799c1e969dd809a17a2d810d9d1c3eb357dc38cb286b07c5a491a5a9be8833558105de826c3ffc8ba82b2ec6cbd11f4478af1bebd643508fe05b8d07bb192eb22229b417b5967b59f26ba434fa7aa27e06fb1d274f3ddcd286312117d9b49678449cafd709bd86cf64868a630bf695f538be92a0150203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Importe: 7.0 ----- Fecha: 2020-03-25 19:59:59.734229 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d003081890281810090167ad6ffedd2c443b0f75ad384a2cb4e7eee83f32d063bbb5ea1ea0f77044a029a382a6f324296abf2d4f0fb22274a54d7710d06e9b01b17f1576953ad4e2ebe32f5e34945dd48ed4447cb556e31f5ca01ca76aedd3f787a0065b7b6d84bcf6edf2f56ad1af16fd5d4656983fb38d60dbb48d8f05785459e3065a60e622d050203010001 ----- Importe: 100.0 ----- Fecha: 2020-03-25 19:59:59.738233 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100ded60b70e326a535a8ca4edbb0e871a4888629c40d208b573ad91a9eb54529f3d3530dc23b8f4d457eae975227bca65e8328bae8519a35b9c63ea5f7b2692ad42dec188dd8f767c1a3bbb350d20e03f7c210db93772390afea4e5803582bd694121cb1d93cbdd688abb2339e7d976e65854fae77bca6a7ec4ef1508f7a428f570203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100bf4458bc88212c345961f60afaef8f161792696b3dfc432088378cf9497f1b03d6491e17183a46823106d2738f1b90525bc028849938ba1c0bad821c3644e44ecd5a3e8ef0da18678224f468e863eddcab90733b4c172e4eb044b05bd703f7fbd461493e1aae2314994847cdc91370bf1f3dc0132f2200a57b721f954d6a4fbf0203010001 ----- Importe: 23.0 ----- Fecha: 2020-03-25 19:59:59.742230 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d003081890281810090167ad6ffedd2c443b0f75ad384a2cb4e7eee83f32d063bbb5ea1ea0f77044a029a382a6f324296abf2d4f0fb22274a54d7710d06e9b01b17f1576953ad4e2ebe32f5e34945dd48ed4447cb556e31f5ca01ca76aedd3f787a0065b7b6d84bcf6edf2f56ad1af16fd5d4656983fb38d60dbb48d8f05785459e3065a60e622d050203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100b6570a15656f067debe871799c1e969dd809a17a2d810d9d1c3eb357dc38cb286b07c5a491a5a9be8833558105de826c3ffc8ba82b2ec6cbd11f4478af1bebd643508fe05b8d07bb192eb22229b417b5967b59f26ba434fa7aa27e06fb1d274f3ddcd286312117d9b49678449cafd709bd86cf64868a630bf695f538be92a0150203010001 ----- Importe: 65.0 ----- Fecha: 2020-03-25 19:59:59.746230 ----- -------------- Cliente que envia: 30819f300d06092a864886f70d010101050003818d0030818902818100ded60b70e326a535a8ca4edbb0e871a4888629c40d208b573ad91a9eb54529f3d3530dc23b8f4d457eae975227bca65e8328bae8519a35b9c63ea5f7b2692ad42dec188dd8f767c1a3bbb350d20e03f7c210db93772390afea4e5803582bd694121cb1d93cbdd688abb2339e7d976e65854fae77bca6a7ec4ef1508f7a428f570203010001 ----- Cliente que recibe: 30819f300d06092a864886f70d010101050003818d0030818902818100b6570a15656f067debe871799c1e969dd809a17a2d810d9d1c3eb357dc38cb286b07c5a491a5a9be8833558105de826c3ffc8ba82b2ec6cbd11f4478af1bebd643508fe05b8d07bb192eb22229b417b5967b59f26ba434fa7aa27e06fb1d274f3ddcd286312117d9b49678449cafd709bd86cf64868a630bf695f538be92a0150203010001 ----- Importe: 324.0 ----- Fecha: 2020-03-25 19:59:59.750731 ----- --------------
Ahora todo se ve más ordenado, podemos ver cada una de las transacciones que agregamos anteriormente a la lista de espera, por otro lado hasta ahora hemos aprendido cómo crear clientes, permitirles realizar transacciones y mantener una cola de las transacciones pendientes que se van a extraer para que luego sean procesadas.
➡ ¡Enhorabuena si has llegado hasta aquí! Continúa aprendiendo con nuestro Curso de Blockchain: