LinuxParty

NUESTRO SITIO necesita la publicidad para costear hosting y el dominio. Por favor considera deshabilitar tu AdBlock en nuestro sitio. También puedes hacernos una donación entrando en linuxparty.es, en la columna de la derecha.
Inicio desactivadoInicio desactivadoInicio desactivadoInicio desactivadoInicio desactivado
 

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:

Pin It

Escribir un comentario


Código de seguridad
Refescar



Redes:



 

Suscribete / Newsletter

Suscribete a nuestras Newsletter y periódicamente recibirás un resumen de las noticias publicadas.

Donar a LinuxParty

Probablemente te niegues, pero.. ¿Podrías ayudarnos con una donación?


Tutorial de Linux

Filtro por Categorías