Python 模拟简单区块链
首先这是说明一下这是Tiny熊老师的教程https://www.cnblogs.com/tinyxiong
另外还要说明一下,暑假指导老师让我们做一些关于区块链的应用。这里只是涉及极其简单的模拟,主要是记录这些天自己学习的知识。
什么是区块链?
下面简单说一下区块链是什么,做个比喻,区块就像一个人,区块链好比一群人。怎么才能让一群人联系起来哪,就必须让他们之间有一定的关系和联系。比如,第一个人有100块钱,存入银行。银行给了他一张“凭证”,但是这张凭证被第二个人拿走了,第三个人的凭证被第四个。。。。
如此一来这么多人就被联系起来。咱们这次实现的简单的区块链就是本区块带有上一区块的哈希。
先简单定义一下区块的内容:
# {
# "index": 1, 区块的块号
# "timestamp": "", 时间戳
# "transactions": [ 交易内容
# {
# "sender": "",
# "recipient": "",
# "amount": 5,
# }
# ],
# "proof": "", 工作量证明
# "previous_hash":"" 上一个区块的hash
#
# }
本次才用的是Python Flask框架,使用云端MongoDB ,https://cloud.mongodb.com/注册申请这里就不详细说了。
简单说一下需要准备的有,PyCharm , pip , Python 3.7。
使用PyCharm 创建一个PyThon虚拟环境 。点击Create New Project 。选择文件夹,默认选项就是在本文件夹安装虚拟环境。
然后就是各种包
import hashlib # hash 算法
import json # josn
from time import time # 时间戳
from uuid import uuid4 # uuid为本机生成ID
from flask import Flask, jsonify, request
import pymongo
我们设想一下,数据要保存在什么地方才能在下次启动程序的时候继续按照上一次结束的数据进行下一次的运算。因此我们需要使用数据库保存我们需要保存的数据。所以我们要先连接数据库。
# **User**:**password** 这是你创建集群的用户和密码
client = pymongo.MongoClient('mongodb+srv://**User**:**password**@iec-pj8qn.mongodb.net/MainSite')
db = client.MainSite #
collection = db.blockchain
现在数据库已经连接上了,但是问题来了。我们怎么取出最底层的文档哪?下面我们需要一个循环遍历集合的最大值,回想一下我们定义的区块结构。里面定义的 index:1 。 每次新增一个区块,第二个区块的index = 2 . 一次增加下去。这样遍历的最大值,也可以说是遍历的次数就是我们需要寻找的index:last
,也就是最后一次被插入的数据。MongoDB 在没有给定特定的_id 字段时,自己会生成一个类似与时间戳的字段。这不是我们需要的,我们在取出数据的时候要把他剔除。
class value:
# 取出文档的数据再次组合并存储在current[] 列表里
def value(self, index1, hash1, proof, transactions1, timestamp) -> list:
current = []
json_value = {
'index': index1,
'previous_hash': hash1,
'proof': proof,
'transactions': transactions1,
'timestamp': timestamp
}
current.append(json_value)
return current
class counting: # 循环遍历集合最大值
def count(self):
last_count = 0
for x in collection.find(): # collection.find() 集合的所有文档
last_count = last_count + 1
return last_count last1 = counting() # 调用counting类
last = last1.count()
print(last)
result = collection.find_one({"index": last}) # 搜索到最后一个文档
value = value() # 创建value对象
chain0 = value.value(result['index'],
result['previous_hash'],
result['proof'],
result['transactions'],
result['timestamp']) # dict 转 list
print(chain0)
print(type(chain0)) client.close() # 连接断开
现在我们已经获取都最近一次插入的数据。我们现在就可以插入创始区块了:
{
"index": 1,
"previous_hash": 1,
"proof": 100,
"timestamp": 1541940889.5927348,
"transactions": []
}
把这段josn插入MongoDB , 或许你可以在网页插入或者在本地下载一个 MongoDB Shell 这个云端MongoDB 有提示怎么下载,这里我就不多说了。如果不明白MongoDB 的用法请去 菜鸟教程
把创始区块插入集合,启动一下。出现你插入的数据,说明你已经成功的连接数据库。
下面我们来看一大段代码:
class Blockchain: def __init__(self): # 构造函数,初始区块链,当前交易,生成创始区块
self.chain = [] # 真正的区块链
self.chain.append(chain0[0]) # 每次连接取最后一个集合文档作为本次的启动创世区块
self.current_transactions = []
# self.new_block(proof=100, previous_hash=1) # 如果没有用到数据库,调用构造函数,自行创建一个创世区块 def new_block(self, proof, previous_hash=None, last_index=None): # 新建区块 工作量证明,前一个区块Hash
# 定义交易区块实体
block = {
'index': last_index + 1,
'timestamp': time(),
'transactions': self.current_transactions, # 当前交易
'proof': proof,
'previous_hash': previous_hash or self.hash(self.last_block)
}
self.current_transactions = [] # 清空当前交易
self.chain.append(block) # 区块链添加新区块
return block def new_transactions(self, sender, recipient, amount) -> int: # 新的交易
self.current_transactions.append( # 当前交易添加数据
{
'sender': sender,
'recipient': recipient,
'amount': amount
}
) return self.last_block['index'] + 1 # 最后一个区块的 index+1 @staticmethod
def hash(block): # 区块hash算法
block_string = json.dumps(block, sort_keys=True).encode()
return hashlib.sha256(block_string).hexdigest() @property
def last_block(self): # 最后一个区块# 取出的最后一个区块类型总是 list
long = len(self.chain)
print(long)
if long > 1:
last_block = self.chain[-1]
print('++++++++++++++++++++++++')
print(last_block)
print(type(last_block))
print(last_block['index'])
temp_json = {
'index': last_block['index'],
'previous_hash': last_block['previous_hash'],
'proof': last_block['proof'],
'transactions': last_block['transactions'],
'timestamp': last_block['timestamp']
}
print(temp_json)
self.chain.append(temp_json)
print(self.chain)
print(type(self.chain[-1]))
return self.chain[-1] def proof_of_work(self, last_proof: int) -> int: # 工作量证明
proof = 0
while self.valid_proof(last_proof, proof) is False: # 循环检测合格hash
proof += 1
# print(proof)
return proof def valid_proof(self, last_proof: int, proof: int) -> bool: # 有效工作量证明
guess = f'{last_proof}{proof}'.encode()
guess_hash = hashlib.sha256(guess).hexdigest() # 哈希后得到摘要
# print(guess_hash)
if guess_hash[0:4] == "": # 工作量证明条件
return True
else:
return False
上面的类,基本上都有注释,并且时我测试时的断点也有保留,更清晰的了解数据的类型和数值。我就不一一口述了。简单的说一下就是 交易方法def new_transactions, 和 新建块的打包计算def new_block
计算hash def hash(block): 有效工作量证明def hash(block) 。
本地文件夹创建static 文件夹 加入index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<p>Hello BlockChain</p>
<form action="transactions" method="post">
sender:<input type="text" name="sender">
recipient:<input type="text" name="recipient">
amount:<input type="text" name="amount">
<input type="submit" value="submit">
</form> </body>
</html>
下面开始使用我们的Flask框架
app = Flask(__name__, static_url_path='') # 参数的意思是为静态html文件,添加路径
Flask框架
app = Flask(__name__, static_url_path='') # 参数的意思是为静态html文件,添加路径
blockchain = Blockchain() # 创建对象 node_identifier = str(uuid4()).replace('-', '') # 使用uuid生成本结点ID,replace()替换'-'
@app.route('/', methods=['GET'])
def index():
return app.send_static_file('index.html') @app.route('/transactions', methods=['POST'])
def new_transaction(): # 新的交易
print(request)
sender = request.form['sender'] # 取出 Form 里的值
print(sender)
recipient = request.form['recipient']
print(recipient)
amount = request.form['amount']
print(amount) values = [sender, recipient, amount]
index = blockchain.new_transactions(values[0], # 调用函数
values[1],
values[2])
response = {"message": f'Transaction will be added to Block {index}'}
return jsonify(response), 201 @app.route('/mine', methods=['GET'])
def mine(): # 交易打包,挖矿
last_block = blockchain.last_block
print("=======================")
print(type(last_block))
print(last_block)
last_proof = last_block['proof']
print(last_proof)
last_index = last_block['index']
print(last_index) proof = blockchain.proof_of_work(last_proof) # 工作量证明 也就是挖矿 blockchain.new_transactions(sender="", # 给本结点的奖励
recipient=node_identifier,
amount=1) block = blockchain.new_block(proof, None, last_index) # 打包区块
client = pymongo.MongoClient('mongodb+srv://**user**:**password**@iec-pj8qn.mongodb.net/MainSite')
db = client.MainSite
collection = db.blockchain
collection.insert_one(block) # 把打包好的区块添加到数据库。
client.close()
response = {
"message": "New Block Forged",
"index": block['index'],
"transactions": block['transactions'],
"proof": block['proof'],
"previous_hash": block['previous_hash']
} return jsonify(response), 200 @app.route('/chain', methods=['GET'])
def full_chain(): # 返回区块链
response = {
'chain': blockchain.chain,
'length': len(blockchain.chain)
}
return jsonify(response), 200 if __name__ == '__main__': # 当 block chain.py 作为模块时不执行下面函数
app.run(host='127.0.0.1', port=3000)
把所有的代码块合在一起就是本次区块链模拟器的全部内容了,这只是单节点,单保存的链,只是更好的去理解区块链的结构,还有比如共识机制和选择链我们还没有去完成。
对了 说一下用法:
提交后: http://127.0.0.1:3000/mine
之后打开 PowerShell
结束。
Python 模拟简单区块链的更多相关文章
- 用Python从零开始创建区块链
本文主要内容翻译自Learn Blockchains by Building One 本文原始链接,转载请注明出处. 作者认为最快的学习区块链的方式是自己创建一个,本文就跟随作者用Python来创建一 ...
- 用 Python 撸一个区块链
本文翻译自 Daniel van Flymen 的文章 Learn Blockchains by Building One 略有删改.原文地址:https://hackernoon.com/learn ...
- 基于java实现的简单区块链
技术:maven3.0.5 + jdk1.8 概述 区块链是分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.所谓共识机制是区块链系统中实现不同节点之间建立信任.获取权益的 ...
- 51行代码实现简单的PHP区块链
本文原始地址:php区块链demo 今年区块链特别火,我也很火啊.我火什么呢.前几年,公众平台出现,还得花时间去学去看,后来小程序出现,又得花时间精力去学去看.现在比特币.以太坊等去中心化货币带起了区 ...
- 孤荷凌寒自学python第103天认识区块链017
[主要内容] 今天继续分析从github上获取的开源代码怎么实现简单区块链的入门知识,共用时间25分钟. (此外整理作笔记花费了约34分钟) 详细学习过程见文末学习过程屏幕录像. 今天所作的工作是进一 ...
- Python实现一条基于POS算法的区块链
区块链中的共识算法 在比特币公链架构解析中,就曾提到过为了实现去中介化的设计,比特币设计了一套共识协议,并通过此协议来保证系统的稳定性和防攻击性. 并且我们知道,截止目前使用最广泛,也是最被大家接受的 ...
- 用spring boot 2从零开始创建区块链
区块链这么火的技术,大java怎能落后,所以有了本文,主要代码参考自 Learn Blockchains by Building One , 中文翻译:用Python从零开始创建区块链 . 一.区块链 ...
- 区块链入门到实战(27)之以太坊(Ethereum) – 智能合约开发
智能合约的优点 与传统合同相比,智能合约有一些显著优点: 不需要中间人 费用低 代码就是规则 区块链网络中有多个备份,不用担心丢失 避免人工错误 无需信任,就可履行协议 匿名履行协议 以太坊(Ethe ...
- JavaScript开发区块链只需200行代码
用JavaScript开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...
随机推荐
- Rails的静态资源管理(一)——Asset Pipeline是什么
官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...
- mybatis如何防止sql注入(1)
sql注入大家都不陌生,是一种常见的攻击方式,攻击者在界面的表单信息或url上输入一些奇怪的sql片段,例如“or ‘1’=‘1’”这样的语句,有可能入侵参数校验不足的应用程序.所以在我们的应用中需要 ...
- 触摸事件MultiTouch Events
备注: userInteractionEnabled = NO hidden = YES alpha = 0.0~0.01 //如果上面三个属性被设置了则无法接收触摸事件 1.- (void)t ...
- 前端seo小结,网页代码优化
seo的目的:提高网站流量 search engine optimization 搜索引擎优化seo search engine marketing 搜索引擎营销sem 权重10个等级 等级越大,权重 ...
- office 2010打开doc文档报错:Word 在尝试打开文件时遇到错误
今天在百度文库中下载了几个文档,下载后发现无法打开.出现以下的提示框. 那么,使用多年office的我,这点小问题当然难不倒我啦. 这个问题是由于系统安全设置所导致的 ,所有我们只需要处理这个安全设置 ...
- Linux 查看一个端口的连接数
netstat -antp|grep -i "80" |wc -l 譬如查看80端口的连接数
- Python之路:面向对象及相关
其他相关 一.isinstance(obj, cls) 检查是否obj是否是类 cls 的对象 class Foo(object): pass obj = Foo() isinstan ...
- Swing绘图API
----------------siwuxie095 工程名:TestSwingPaintAPI 包名:com.siwuxie095.swing ...
- __call()和__callStatic()方法
__call() 当对象访问不存在的方法时,__call()方法会被自动调用__callStatic() 当对象访问不存在的静态方法时,__callStatic()方法会被自动调用 这两个方法在PHP ...
- 业务逻辑:shiro框架的功能实现
思路:分别在web.xml配置过滤器以及在applicationContext.xml去配置 实现步骤:1.在pom.xml里引入shiro的坐标 2.在web.xml里配置shiro过滤器 3.在a ...