目前大多数对于区块链的文章都是停留在概念性的描述,大肆宣扬其颠覆性,本文则反其道行之,以一个程序员的视角,通过300行代码,快速实现了一个区块链原型。虽然没有覆盖区块链的全部内容(如Merkle树),但对于理解区块链的核心技术仍大有裨益。
—-译者注
能够点进这篇文章,说明你也像我一样对加密货币的兴起十分激动,并想了解加密货币的支撑技术—区块链是如何工作的。
但理解区块链并不那么轻松,至少对我来说如此。我看了很多相关的视频和教程,却沮丧地发现实例真是太少了。
我喜欢通过实践学习。这种方式使我在代码层面思考问题,并发现关键所在。如果你和我一样,那么在本文结尾你将构建一个功能完备的区块链并对其工作机制有深刻的理解。
写在开始之前。。。
首先,区块链是一系列称作区块(Block)的结构顺序链接而成的不可改变的记录。块中可以包含交易记录、文件或者其他任何你想存储的数据。需要注意的是块与块之间通过hash值链接。如果你不清楚hash是什么,请参考What Are Hash Functions。
本文适合哪些人看?你应该懂得一些基本的Python知识,同时也应该对HTTP请求有所理解,因为我们的区块链是运行在HTTP协议之上的。
我需要准备什么?请确保Python3.6及以上版本和pip工具已经安装。还需要安装Flask和requests
库。
pip install Flask==0.12.2 requests==2.18.4
对了,你还需要一个HTTP客户端,比如Postman或者cURL,当然,其他的也可以。
最终的代码哪里可以获取?点击这里
第一步:构建区块链
创建一个新的Python文件,名为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
类负责管理整个区块链,它会存储交易并为新增区块等操作提供辅助方法。下面,我们来实现这些方法。
区块是什么
每个区块都有一个索引(index),一个时间戳(timestamp),一系列交易,一个工作量证明(稍后详述)和前置区块的哈希值。下面是单个区块的一个简单实例:
block = {
'index': 1,
'timestamp': 1506057125.900785,
'transactions': [
{
'sender': "8527147fe1f5426f9dd545de4b27ee00",
'recipient': "a77f5cdfa2934df3954a5c7c7da5df1f",
'amount': 5,
}
],
'proof': 324984774000,
'previous_hash': "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
}
显而易见,所有的区块会构成一条链—因为每个区块都保存了前一区块的hash值。这就是区块链不可篡改的重要原因:如果攻击者损坏了某一区块,那么后面所有的区块都会作废。
如果你不明白上面的话,请花一些时间理解,因为这是区块链的核心思想。
向区块添加交易
我们需要一个方法来向区块中添加交易记录,这里命名为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
类初始化的时候,我们需要产生一个创世区块(genesis block,即没有前置区块的区块)作为区块链的第一个区块。我们还需要添加一个proof
字段在创世区块中作为挖矿的结果(或者说本次工作量的证明),我们将在后文继续讨论挖矿。
除了产生创世区块,我们还需要完成一些其他辅助方法(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)