用 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库而不是crypto
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()
在 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
之外,代码几乎相同。append
push
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
方法和属性来实现这个系统。需要注意的是,必须在调用方法之前声明。否则会报错。nonce
nonce
self.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