最近在纠结以后的研究方向,就先看了看云链。即一种云计算+区块链+物联网设备的架构模式。虽然还是雨里雾里,还是决定先把区块链的编程落实一下。
0x00 系统环境
本次使用的为Python3.6.5 需要用到的库包括hashlib,flask(0.12.2),time
0x01 区块链结构
这个部分看了一些的资料,慢慢理清了结构。所谓区块链就是一条链(chain),在python里用一个很长的链表list表示。列表里每一项分别为一个交易记录(transactions)。而每个交易记录里又包括这个交易的各种信息:交易的标号(index),交易创建的时间(timestamp),交易内容(transactions),工作证明/挖矿(proof),前一个块的哈希值(previous_hash)。再其中,交易内容又包括:接收者(recepient),发送者(sender),交易金额(amount)。这样看起来太复杂了,用一个图来呈现一下吧。
0x02 区块链逻辑
整个区块链根据结构可以大致分为几个模块:
1.区块链的初始化 2.新块(block)的建立 3.新交易的建立(transactions) 4.工作证明算法
① 首先是区块链的建立,之前介绍了区块链在python中就是一个很长的列表,其中存放了一个一个的节点(block)。
初始化区块链很简单,就是申请一个新的列表。
class Blockchain(object):
def __init__(self):
self.chain = []
② 有了链以后我们就可以添加节点(block)了。区块链的每个节点是用来记录每次的交易记录的,其中包括了节点序号、时间等参数。在python中节点用一个字典表示,分别记录各个参数。
class Blockchain(object):
def __init__(self):
self.chain = []
self.current_transactions = []
self.new_block(previous_hash=1, proof=100) # 创建初始区块
def new_block(self, proof, previous_hash=None):
block = {
'index': len(self.chain) + 1, # 序号
'timestamp': time(),
'transactions': self.current_transactions,
'proof': proof, # 工作证明(挖矿)
'previous_hash': previous_hash or self.hash(self.chain[-1]), # 前一个哈希
}
self.current_transactions = []
self.chain.append(block)
return block
这里注意,创建了新的节点,就要清空当前的交易记录,以方便记录下一个节点的交易记录。这个current_transactions也是一个列表,用来记录当前节点的交易记录。接下来详细介绍。
③ 交易记录是一个列表,里面存放一个个的字典,来存放当前块的每笔交易。每个块可以存放多个交易记录。接下来为创建新记录的函数 以及计算哈希值的函数。
def new_transaction(self,recepient,sender,amount): # 创建新的交易
self.current_transactions.append({
'sender':sender, # 接收者
'recepient':recepient, # 发送者
'amount':amount, # 金额
})
return self.last_block['index'] + 1
@staticmethod
def hash(block):
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest()
@property # 直接获取return的值
def last_block(self):
return self.chain[-1]
④ 最后是工作证明,也被称作为挖矿。
使用工作量证明(PoW)算法,来证明是如何在区块链上创建或挖掘新的区块。PoW 的目标是计算出一个符合特定条件的数字,这个数字对于所有人而言必须在计算上非常困难,但易于验证。这是工作证明背后的核心思想。
我们将看到一个简单的例子帮助你理解:
假设一个整数 x 乘以另一个整数 y 的积的 Hash 值必须以 0 结尾,即 hash(x * y) = ac23dc...0。设 x = 5,求 y ?用 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。因为,生成的 Hash 值结尾必须为 0。
hash(5 * 21) = 1253e9373e...5e3600155e860
在比特币中,工作量证明算法被称为 Hashcash ,它和上面的问题很相似,只不过计算难度非常大。这就是矿工们为了争夺创建区块的权利而争相计算的问题。 通常,计算难度与目标字符串需要满足的特定字符的数量成正比,矿工算出结果后,就会获得一定数量的比特币奖励(通过交易)。
验证结果,当然非常容易。
让我们来实现一个相似 PoW 算法。规则类似上面的例子:
找到一个数字 P ,使得它与前一个区块的 proof 拼接成的字符串的 Hash 值以 4 个零开头。
def proof_of_work(self, last_proof):
proof = 0
while self.valid_proof(proof, last_proof) is False:
proof += 1
return proof
@staticmethod
def valid_proof(proof, last_proof):
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest()
return guess_hash[:4] == "0000"
0x03 区块链实验
我们采用python的flask框架,将我们写好的区块链放在服务器上运行。先附上代码
def main():
app = Flask(__name__)
node_identifier = str(uuid4()).replace('-', '')
blockchain = Blockchain()
@app.route('/mine', methods=['GET'])
def mine():
last_block = blockchain.last_block
last_proof = last_block['proof']
proof = blockchain.proof_of_work(last_proof)
blockchain.new_transaction(
sender = '0',
recepient = node_identifier,
amount = 1,
)
last_hash = blockchain.hash(last_block)
block = blockchain.new_block(proof, last_hash)
response = {
'message':'New Blcok Forged',
'index': block['index'],
'transactions': block['transactions'],
'proof': block['proof'],
'previous_hash': block['previous_hash'],
}
return jsonify(response), 200
@app.route('/transactions/new', methods=['POST'])
def new_transaction():
values = request.get_json()
required = ['sender','recepient','amount']
if not all(k in values for k in required):
return 'Missing values', 400
index = blockchain.new_transaction(values['recepient'], values['sender'], values['amount'])
response = {'message':f'transactions have been added to {index}'}
return jsonify(response), 201
@app.route('/chain', methods=['GET'])
def full_chain():
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain),
}
return jsonify(response), 200
# return f'<h1>{response}</h1>'
app.run(host = '0.0.0.0', port=5000)
其中,通过访问 http://localhost:5000/mine 新建一个区块的页面,通过请求,创建一个新的区块,其中交易金额为1,即通过挖矿,我们找到了一个新的区块,系统(sender=0)奖励给我们(recepient=node_identifier)一个币。这就是整个挖矿的逻辑实现。如下
然后,http://ocalhost:5000/transactions/new 我们可以添加一笔交易记录。
最后,http://ocalhost:5000/chain 我们可以请求到整个链。
随着创建的节点的增多,我们查看到的链就越长。
关于单条连的学习就到此为止,由于区块链是在整个网络上 各个设备之间都存在的架构。接下来将进入到多台设备的学习中。