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开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...
随机推荐
- mariaDB 安装/卸载+启动/关闭 服务
1.设置环境变量 无论是用户环境变量还是系统环境变量 2.启动服务 进入根目录 名字根据 --install 后的 参数来决定 叫MariaDB,MySQL 都可以 mysqld.exe --inst ...
- How to Enabling and Diabling VxDMP devices for use with Oracle ASM
Enable DMP support for ASM to make DMP devices visible to ASM as available disks To make DMP devices ...
- java 多线程系列基础篇(八)之join()、start()、run()方法
1. join()介绍 join() 定义在Thread.java中.join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行.这句话可能有点晦涩,我们还是通过例子去理解: // 主线程 ...
- sql server导入excel等数据
1.首先打开并登陆sql server数据库 2.选择要将表导入的数据库,右击选择任务-->导入数据 3.在弹出的窗口中选择下一步 4.在弹出的窗口中选择数据源,也就是从哪种文件导入,sql s ...
- Android基础学习:Android环境搭建
在3年前,自学过Android的一些基础知识,但是那个时候Linux等其他的知识结构比较薄弱,理解得不是很深刻,后来因项目变动的原因,没有再搞Android相关的东西了.时过境迁,还是因为项目变动,重 ...
- ionic 页面乱码
是文本编辑器的问题.文本编辑器保存时默认保存成Encoding:ANSI编码格式,保存成utf-8就好了
- CentOS 7 下设置DNS
在CentOS 7下,手工设置 /etc/resolv.conf 里的DNS,过了一会,发现被系统重新覆盖或者清除了.和CentOS 6下的设置DNS方法不同,有几种方式: 1.使用全新的命令行工具 ...
- Win32编程中如何处理控制台消息
这篇文章讨论如何处理所有的控制台消息. 第一步,首先要安装一个事件钩子,也就是说要建立一个回调函数.调用Win32 API,原型如下: BOOL SetConsoleCtrlHandler(PHAND ...
- java中怎么把String转化为字符数组呢?
我想让用户输入一组字符串,然后将这个字符串的每一个赋给一个char.即,abcde char ch[]=new char[5]; ch[0]=a;ch[1]=b;..... 解决方案如下图所示: St ...
- poj3734 Blocks
传送门 题目大意 有n个方块,有1,2,3,4四种颜色对其进行染色,求1,2颜色的方块个数均为偶数的方案数对10007取模的值. 分析 我们假设1表示这个颜色个数是奇数,0表示是偶数,所以对于所有状态 ...