用 60 行 Python 代码创建区块链
当我阅读Phu Minh撰写的文档时,我对学习区块链的不同概念感到好奇。当我开始阅读代码时,我想将其与 Python 进行匹配,以了解它与 JavaScript 的区别。
这篇文章的目的是找出两种语言之间的差异,并作为原始文章的Python附录。
尽管原始文档来自Python示例,但我希望与要比较的代码完全匹配JavaScript。
我们也将python代码放入承诺的 60 行内。
区块链
虽然我们的想法是模仿整个帖子并使用相同的部分来遵循代码,
对于区块链的定义,我倾向于以下说法:
区块链是一种以难以或不可能被更改、黑客攻击或欺骗的方式记录信息的系统。
设置
我们在这个项目中使用 Python,因此如果您还没有安装它,请务必安装它。
正如我所说,块只是一个包含一些信息的对象,所以我们应该有一个像这样的 Block 类:
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
两种语言中的类定义非常相似。在 Python 中,我们使用self而不是 ,this并且init是一个constructor方法。
两种语言的注释也类似。在 Python 中,我们使用 ,#而//在 JavaScript 中则使用 。
对于该sha256算法,我将使用hashlib库而不是cryptojavascript 中的包。
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()
在 getHash 方法中,我们从一个空的哈希值开始,用其余部分更新它。新的哈希值是前一个哈希值、时间戳和数据串联的结果。然后使用.encode('utf-8')将字符串转换为字节。
区块链
让我们转到区块链课程。
class Blockchain:
    def __init__(self):
        # This property will contain all the blocks.
        self.chain = []
再次,两种语言中的类定义相似。
要创建创世区块,我们只需使用 time 调用带有当前时间戳的区块即可。为此,我们需要导入 time 库。
字符串转换是用str而不是 完成的toString。
from time import time
class Blockchain:
    def __init__(self):
        # Create our genesis block
        self.chain = [Block(str(int(time())))]
获取最新区块的方法也类似,只不过我们用javascript来len获取链的长度。length
    def getLastBlock(self):
        return self.chain[len(self.chain) - 1]
要将区块添加到区块链,我们只需调用该方法即可。除了(JavaScript 代码)addBlock之外,代码几乎相同。appendpush
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)
验证
在验证方法中,我们开始使用range一个很大的区别。另外,由于我们在 Python 中不使用常量,所以我们只使用普通变量。
对于条件,python 使用or而不是||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
工作量证明
我们可以通过在代码块中添加mine方法和属性来实现这个系统。需要注意的是,必须在调用方法之前声明。否则会报错。noncenonceself.getHash()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()
要创建难度属性:
self.difficulty = 1
以及addBlock方法:
    def addBlock(self, block):
        block.prevHash = self.getLastBlock().hash
        block.hash = block.getHash()
        block.mine(self.difficulty)
        self.chain.append(block)
测试链条
首先,导入模块并以Blockchain相同的方式使用 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)
它看起来应该是这样的:
[
    {
        "data": [],
        "timestamp": "1636153236",
        "nonce": 0,
        "hash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678",
        "prevHash": null
    },
    {
        "data": {
            "from": "John",
            "to": "Bob",
            "amount": 100
        },
        "timestamp": "1636153236",
        "nonce": 14,
        "hash": "038f82c6e6605acfcad4ade04e454eaa1cfa3d17f8c2980f1ee474eefb9613e9",
        "prevHash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678"
    }
]
但只有在将__repr__方法添加到 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)
更新奖励:难度和区块时间
对于 blockTime 来说:
self.blockTime = 30000
看一下难度系统使用的三元运算符。在 Python 中,三元运算符是(if_test_is_false, if_test_is_true)[test],结果如下:
    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]
最终的 Python 代码(没有正确格式)共 60 行,内容如下:
# -*- 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)
希望您能喜欢这两篇文章并学到东西!
文章来源:https://dev.to/imjoseangel/creating-a-blockchain-in-60-lines-of-python-2hlc 后端开发教程 - Java、Spring Boot 实战 - msg200.com
            后端开发教程 - Java、Spring Boot 实战 - msg200.com