构建区块链
前言
小编认为学习区块链如何工作的最快方法是建立一个区块链。虽然网上有很多教程或视频,小编也一一浏览过,但是觉得那些示例效果…小编喜欢边做边学,小编希望在看过这篇文章之后您将拥有一个运行正常的区块链,并对它们的工作原理有扎实的了解。
请记住!!!区块链是一个不变的顺序记录链,称为块。它们可以包含事务,文件或您真正喜欢的任何数据。但是重要的是,它们使用哈希值链接在一起。
前期准备
pip install Flask==0.12.2 requests==2.18.4
开始流程
步骤1:建立区块链
打开你最喜欢的文本编辑器或IDE,我个人❤️ PyCharm。创建一个新文件,名为blockchain.py(代表区块链)。
创建一个区块链类
小编在这里创建一个 Blockchain类,其构造函数创建一个初始的空列表(用于存储我们的区块链),并创建另一个用于存储事务。
class Blockchain(object):
def __init__(self):
self.chain = []
self.current_transactions = []
def new_block(self):
# Creates a new Block and adds it to the chain
pass
def new_transaction(self):
# Adds a new transaction to the list of transactions
pass
@staticmethod
def hash(block):
# Hashes a Block
pass
@property
def last_block(self):
# Returns the last Block in the chain
pass
Blockchain类负责管理链。它将存储事务,并具有一些用于将新块添加到链中的辅助方法。
块看起来像什么?
每个Block都有一个索引,一个时间戳(以Unix时间表示),一个事务列表,一个证明以及前一个Block的哈希值。
这是单个块的外观示例:
block = {
'index': 1,
'timestamp': 1506057125.900785,
'transactions': [
{
'sender': "8527147fe1f5426f9dd545de4b27ee00",
'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
'amount': 5,
}
],
'proof': 324984774000,
'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
链的概念应该很明显每个新块本身都包含前一个块的哈希。这是至关重要的,因为这是赋予区块链不变性的原因:如果攻击者破坏了链中较早的区块,则所有后续区块将包含不正确的哈希。这么有意义吗?如果不是做,则需要花一些时间让它沉没-这是区块链背后的核心思想。
将交易添加到区块
将交易添加到区块,我们需要一种将交易添加到区块的方法。我们的new_transaction() 方法对此负责,这很简单:
class Blockchain(object):
...
def new_transaction(self, sender, recipient, amount):
"""
Creates a new transaction to go into the next mined Block
:param sender: <str> Address of the Sender
:param recipient: <str> Address of the Recipient
:param amount: <int> Amount
:return: <int> The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
new_transaction()将交易添加到列表中,它返回交易将添加到的区块的索引给下一个要开采的区块。以后,这对于提交事务的用户很有用。
创建新块
当我们的 Blockchain实例化后,我们需要使用创世块(没有前任的块)为它播种。我们还需要向我们的创始区块添加“证明”,这是挖掘(或工作证明)的结果。除了在我们的构造函数中创建的块之外,我们还将充实用于new_block(), new_transaction() 和 hash():
import hashlib
import json
from time import time
class Blockchain(object):
def __init__(self):
self.current_transactions = []
self.chain = []
# Create the genesis block
self.new_block(previous_hash=1, proof=100)
def new_block(self, proof, previous_hash=None):
"""
Create a new Block in the Blockchain
:param proof: <int> The proof given by the Proof of Work algorithm
:param previous_hash: (Optional) <str> Hash of previous Block
:return: <dict> New Block
"""
block = {
'index': len(self.chain) + 1,
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof,
'previous_hash': previous_hash or self.hash(self.chain[-1]),
}
# Reset the current list of transactions
self.current_transactions = []
self.chain.append(block)
return block
def new_transaction(self, sender, recipient, amount):
"""
Creates a new transaction to go into the next mined Block
:param sender: <str> Address of the Sender
:param recipient: <str> Address of the Recipient
:param amount: <int> Amount
:return: <int> The index of the Block that will hold this transaction
"""
self.current_transactions.append({
'sender': sender,
'recipient': recipient,
'amount': amount,
})
return self.last_block['index'] + 1
@property
def last_block(self):
return self.chain[-1]
@staticmethod
def hash(block):
"""
Creates a SHA-256 hash of a Block
:param block: <dict> Block
:return: <str>
"""
# We must make sure that the Dictionary is Ordered, or we'll have inconsistent hashes
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
代表区块链几乎完成了。但是在这一点上,您一点想知道如何创建,开采新块。
了解工作量证明
工作量证明算法(PoW)是在区块链上创建或挖掘新区块的方式。PoW的目标是发现可以解决问题的数字。从数字上来说, 该数字必须很难找到,但要易于被网络上的任何人验证。这是工作量证明的核心思想。
我们将看一个非常简单的示例来帮助解决这个问题。
让我们决定某个整数x乘以另一个y 的哈希必须以0结尾。hash(x * y) = ac23dc…0。对于这个简化的示例,让我们修复x = 5。在Python中实现:
from hashlib import sha256
x = 5
y = 0 # We don't know what y should be yet...
while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":
y += 1
print(f'The solution is y = {y}')
解出是 y = 21。由于产生的哈希值以0结尾:
hash(5 * 21) = 1253e9373e...5e3600155e860
在比币中,工作量证明算法称为Hashcash。而且与我们上面的基本示例并没有太大不同。这是矿工竞相解决以创建新区块的算法。通常,难度由字符串中搜索的字符数决定。然后,通过在交易中获得硬币,矿工将获得奖励,以奖励他们的解决方案。
实施基本的工作证明
让我们为区块链实现类似的算法。我们的规则将类似于上面的示例:
找出一个数字 p ,该数字与前一个块的解决方案进行哈希运算时,会导致4个前导0被生产。
import hashlib
import json
from time import time
from uuid import uuid4
class Blockchain(object):
...
def proof_of_work(self, last_proof):
"""
Simple Proof of Work Algorithm:
- Find a number p' such that hash(pp') contains leading 4 zeroes, where p is the previous p'
- p is the previous proof, and p' is the new proof
:param last_proof: <int>
:return: <int>
"""
proof = 0
while self.valid_proof(last_proof, proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(last_proof, proof):
"""
Validates the Proof: Does hash(last_proof, proof) contain 4 leading zeroes?
:param last_proof: <int> Previous Proof
:param proof: <int> Current Proof
:return: <bool> True if correct, False if not.
"""
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
要调整算法的难度,我们可以修改前导零的数量。但是4就足够了。您会发现,添加单个前导零将使找到解决方案所需的时间产生巨大差异。