LinuxParty
Cuando leí el documento escrito por Phu Minh, tenía curiosidad por aprender diferentes conceptos sobre blockchain. Una vez que comencé a leer el código, quise emparejarlo con Python para comprender también las diferencias con JavaScript.
¿Qué es un blockchain?
Antes de realizar cualquier codificación, debemos entender qué es un blockchain (cadena de bloques). Técnicamente, un blockchain en su mínimo es únicamente una lista que contiene objetos que poseen información básica como marca de tiempo, transacciones, hash, ... Sus datos deben ser inmutables e imposibles de piratear. Las plataformas modernas como Ethereum, Cardano, Polkadot, ... tienen cosas mucho más complejas, pero nos mantendremos simple y fácil en este artículo.
El objetivo de esta publicación es encontrar las diferencias entre ambos lenguajes y servir como el apéndice de Python de la publicación original .
Aunque el documento original proviene de un ejemplo de Python, quería tener una coincidencia exacta con el "JavaScript" código para comparar.
También ajustemos el código "python" en las 60 líneas prometidas.
Blockchain
Aunque la idea es imitar toda la publicación y usar las mismas secciones para seguir el código,
Para la definición de Blockchain, prefiero lo siguiente:
Blockchain es un sistema de registro de información de una manera que hace que sea difícil o imposible cambiar, piratear o engañar.
Configuración
Estamos usando Python para este proyecto, así que asegúrese de instalarlo si no lo ha hecho.
Como he dicho, un bloque es solo un objeto que tiene algo de información, por lo que deberíamos tener una clase Block como esta:
class Block: def __init__(self, timestamp=None, data=None): self.timestamp = timestamp or time() # this.data should contain information like transactions. self.data = [] if data is None else data
La definición de clase es bastante similar en ambos lenguajes. En Python, usamos en "self" en lugar de "this" e init es un método "constructor"
Los comentarios también son similares en ambos lenguajes. En Python, usamos "#" para comentar frente a "//" en javascript.
Para el algoritmo "sha256" , usaré la biblioteca hashlib frente al paquete "crypto" en javascript.
from hashlib import sha256 class Block: def __init__(self, timestamp=None, data=None): self.timestamp = timestamp or time() self.data = [] if data is None else data self.hash = self.getHash() self.prevHash = None # previous block's hash def getHash(self): hash = sha256() hash.update(str(self.prevHash).encode('utf-8')) hash.update(str(self.timestamp).encode('utf-8')) hash.update(str(self.data).encode('utf-8')) return hash.hexdigest()
En el método getHash, a partir de un hash vacío, lo actualizamos con el resto de componentes. El hash es el resultado de la concatenación del hash anterior, la marca de tiempo y los datos. Todo ello con el ".encode('utf-8')" para convertir la cadena a bytes.
El blockchain
Pasemos a la clase blockchain.
class Blockchain: def __init__(self): # This property will contain all the blocks. self.chain = []
Nuevamente, la definición de clase es similar en ambos lenguajes.
Para crear el bloque génesis, simplemente llamamos al bloque con la marca de tiempo actual usando time. Para hacer eso, necesitamos importar la biblioteca de tiempo.
La conversión de cadenas se realiza con en "str" lugar de "toString" .
from time import time class Blockchain: def __init__(self): # Create our genesis block self.chain = [Block(str(int(time())))]
Y el método para obtener el último bloque es similar. Usamos "len" para obtener la longitud de la cadena en lugar de "length" en javascript.
def getLastBlock(self): return self.chain[len(self.chain) - 1]
Para agregar el bloque a la cadena de bloques, simplemente llamamos al método "addBlock". El código es casi el mismo excepto el "append" ( "push" en javascript).
def addBlock(self, block): # Since we are adding a new block, prevHash will be the hash of the old latest block block.prevHash = self.getLastBlock().hash # Since now prevHash has a value, we must reset the block's hash block.hash = block.getHash() self.chain.append(block)
Validación
En el método de validación, comenzamos a usar "range" como una gran diferencia. Además, debido a que no usamos constantes en Python, solo usamos variables normales.
Para el condicional, python usa en "or" lugar de "||" en javascript.
def isValid(self): # Iterate over the chain, we need to set i to 1 because there are nothing before the genesis block, so we start at the second block. for i in range(1, len(self.chain)): currentBlock = self.chain[i] prevBlock = self.chain[i - 1] # Check validation if (currentBlock.hash != currentBlock.getHash() or prevBlock hash != currentBlock.prevHash): return False return True
Prueba de trabajo
Podemos implementar este sistema agregando un método "mine" y una propiedad "nonce" a nuestro bloque. Tenga cuidado porque "nonce" debe declararse antes de llamar al método "self.getHash()". Si no, obtendrá el error "AttributeError: 'Block' object has no attribute 'nonce'" .
class Block: def __init__(self, timestamp=None, data=None): self.timestamp = timestamp or time() self.data = [] if data is None else data self.prevHash = None # previous block's hash self.nonce = 0 self.hash = self.getHash() # Our hash function. def getHash(self): hash = sha256() hash.update(str(self.prevHash).encode('utf-8')) hash.update(str(self.timestamp).encode('utf-8')) hash.update(str(self.data).encode('utf-8')) hash.update(str(self.nonce).encode('utf-8')) return hash.hexdigest() def mine(self, difficulty): # Basically, it loops until our hash starts with # the string 0...000 with length of <difficulty>. while self.hash[:difficulty] != '0' * difficulty: # We increases our nonce so that we can get a whole different hash. self.nonce += 1 # Update our new hash with the new nonce value. self.hash = self.getHash()
Para crear la propiedad de dificultad:
self.difficulty = 1
Y el método "addBlock" :
def addBlock(self, block): block.prevHash = self.getLastBlock().hash block.hash = block.getHash() block.mine(self.difficulty) self.chain.append(block)
Probando la cadena
Primero, importe el módulo y use la clase "Blockchain" de la misma manera usando el objeto JeChain:
from blockchain import Block from blockchain import Blockchain from time import time JeChain = Blockchain() # Add a new block JeChain.addBlock(Block(str(int(time())), ({"from": "John", "to": "Bob", "amount": 100}))) # (This is just a fun example, real cryptocurrencies often have some more steps to implement). # Prints out the updated chain print(JeChain)
Debería verse así:
[ { "data": [], "timestamp": "1636153236", "nonce": 0, "hash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678", "prevHash": null }, { "data": { "from": "John", "to": "Bob", "amount": 100 }, "timestamp": "1636153236", "nonce": 14, "hash": "038f82c6e6605acfcad4ade04e454eaa1cfa3d17f8c2980f1ee474eefb9613e9", "prevHash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678" } ]
pero solo después de agregar el método "__repr__" a la clase Blockchain:
import json def __repr__(self): return json.dumps([{'data': item.data, 'timestamp': item.timestamp, 'nonce': item.nonce, 'hash': item.hash, 'prevHash': item.prevHash} for item in self.chain], indent=4)
Bonificación actualizada: dificultad y tiempo de bloqueo
Para el blockTime solo:
self.blockTime = 30000
Eche un vistazo al ternario utilizado para el sistema de dificultad. En Python, el operador ternario es "(if_test_is_false, if_test_is_true)[test]" , lo que resulta en:
def addBlock(self, block): block.prevHash = self.getLastBlock().hash block.hash = block.getHash() block.mine(self.difficulty) self.chain.append(block) self.difficulty += (-1, 1)[int(time()) - int(self.getLastBlock().timestamp) < self.blockTime]
El código final de Python (sin el formato adecuado) en 60 líneas es:
# -*- coding: utf-8 -*- from hashlib import sha256 import json from time import time class Block: def __init__(self, timestamp=None, data=None): self.timestamp = timestamp or time() self.data = [] if data is None else data self.prevHash = None self.nonce = 0 self.hash = self.getHash() def getHash(self): hash = sha256() hash.update(str(self.prevHash).encode('utf-8')) hash.update(str(self.timestamp).encode('utf-8')) hash.update(str(self.data).encode('utf-8')) hash.update(str(self.nonce).encode('utf-8')) return hash.hexdigest() def mine(self, difficulty): while self.hash[:difficulty] != '0' * difficulty: self.nonce += 1 self.hash = self.getHash() class Blockchain: def __init__(self): self.chain = [Block(str(int(time())))] self.difficulty = 1 self.blockTime = 30000 def getLastBlock(self): return self.chain[len(self.chain) - 1] def addBlock(self, block): block.prevHash = self.getLastBlock().hash block.hash = block.getHash() block.mine(self.difficulty) self.chain.append(block) self.difficulty += (-1, 1)[int(time()) - int(self.getLastBlock().timestamp) < self.blockTime] def isValid(self): for i in range(1, len(self.chain)): currentBlock = self.chain[i] prevBlock = self.chain[i - 1] if (currentBlock.hash != currentBlock.getHash() or prevBlock.hash != currentBlock.prevHash): return False return True def __repr__(self): return json.dumps([{'data': item.data, 'timestamp': item.timestamp, 'nonce': item.nonce, 'hash': item.hash, 'prevHash': item.prevHash} for item in self.chain], indent=4)
¡Esperamos que disfrutes y aprendas con ambas publicaciones!
Otros artículos sobre BlockChain:
- Creando un Blockchain en 60 líneas de Python
- Parte 1, Blockchain en Linux - Introducción y criptomoneda
- Parte 2, Blockchain en Linux - Configurar una red Blockchain y aprovechar la tecnología
- Cómo instalar Blockchain en Ubuntu
- Crear tu propia criptomoneda, usando tu blockchain
- Desmitificando Blockchains
-
Programación
- Thomas E. Kurtz, coinventor de BASIC, muere a los 96 años
- Profesor de informática del MIT prueba el impacto de la IA en la formación de programadores
- Lanzamiento del IDE de código abierto Qt Creator 14 con soporte para complementos basados en Lua
- Plantillas para Joomla - Episodio 1: Plantillas, marcos y clubes o no...
- Este es el mejor libro que he visto para aprender a programar en Python en castellano desde cero, gratis y online
- ¿Deberían los niños seguir aprendiendo a programar en la era de la IA?
- La 'obsolescencia' de VBScript confirmada por Microsoft y su eventual eliminación de Windows
- El Gran Debate: ¿Deberían los Modelos de Inteligencia Artificial Ser de Código Abierto?
- El lenguaje de programación BASIC cumple 60 años
- El CEO de Nvidia dice que los niños no deberían aprender a programar
- 40 años de Turbo Pascal: recuerdos del dinosaurio codificador que revolucionó los IDE
- Los lenguajes de programación más populares y dónde aprenderlos.
- Top 5 de los principales lenguajes de programación para desarrollar aplicaciones de escritorio Linux
- Qt Creator 12 lanzado con complementos de grabación de pantalla y Explorador de compiladores
- 10 sitios web para practicar problemas de programación