用 60 行 Python 代码创建区块链

2025-05-24

用 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
Enter fullscreen mode Exit fullscreen mode

两种语言中的类定义非常相似。在 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()
Enter fullscreen mode Exit fullscreen mode

在 getHash 方法中,我们从一个空的哈希值开始,用其余部分更新它。新的哈希值是前一个哈希值、时间戳和数据串联的结果。然后使用.encode('utf-8')将字符串转换为字节。

区块链

让我们转到区块链课程。

class Blockchain:
    def __init__(self):
        # This property will contain all the blocks.
        self.chain = []
Enter fullscreen mode Exit fullscreen mode

再次,两种语言中的类定义相似。

要创建创世区块,我们只需使用 time 调用带有当前时间戳的区块即可。为此,我们需要导入 time 库。

字符串转换是用str而不是 完成的toString

from time import time

class Blockchain:
    def __init__(self):
        # Create our genesis block
        self.chain = [Block(str(int(time())))]
Enter fullscreen mode Exit fullscreen mode

获取最新区块的方法也类似,只不过我们用javascript来len获取链的长度。length

    def getLastBlock(self):
        return self.chain[len(self.chain) - 1]
Enter fullscreen mode Exit fullscreen mode

要将区块添加到区块链,我们只需调用该方法即可。除了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)
Enter fullscreen mode Exit fullscreen mode

验证

在验证方法中,我们开始使用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
Enter fullscreen mode Exit fullscreen mode

工作量证明

我们可以通过在代码块中添加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()
Enter fullscreen mode Exit fullscreen mode

要创建难度属性:

self.difficulty = 1
Enter fullscreen mode Exit fullscreen mode

以及addBlock方法:

    def addBlock(self, block):
        block.prevHash = self.getLastBlock().hash
        block.hash = block.getHash()
        block.mine(self.difficulty)
        self.chain.append(block)
Enter fullscreen mode Exit fullscreen mode

测试链条

首先,导入模块并以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)
Enter fullscreen mode Exit fullscreen mode

它看起来应该是这样的:

[
    {
        "data": [],
        "timestamp": "1636153236",
        "nonce": 0,
        "hash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678",
        "prevHash": null
    },
    {
        "data": {
            "from": "John",
            "to": "Bob",
            "amount": 100
        },
        "timestamp": "1636153236",
        "nonce": 14,
        "hash": "038f82c6e6605acfcad4ade04e454eaa1cfa3d17f8c2980f1ee474eefb9613e9",
        "prevHash": "4caa5f684eb3871cb0eea217a6d043896b3775f047e699d92bd29d0285541678"
    }
]
Enter fullscreen mode Exit fullscreen mode

但只有在将__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)
Enter fullscreen mode Exit fullscreen mode

更新奖励:难度和区块时间

对于 blockTime 来说:

self.blockTime = 30000
Enter fullscreen mode Exit fullscreen mode

看一下难度系统使用的三元运算符。在 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]
Enter fullscreen mode Exit fullscreen mode

最终的 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)
Enter fullscreen mode Exit fullscreen mode

希望您能喜欢这两篇文章并学到东西!

文章来源:https://dev.to/imjoseangel/creating-a-blockchain-in-60-lines-of-python-2hlc
PREV
实践 Web 开发的资源
NEXT
如何在 Node.js + React on Redis 中构建事件管理应用程序