首先这是说明一下这是Tiny熊老师的教程https://www.cnblogs.com/tinyxiong

另外还要说明一下,暑假指导老师让我们做一些关于区块链的应用。这里只是涉及极其简单的模拟,主要是记录这些天自己学习的知识。

什么是区块链?

下面简单说一下区块链是什么,做个比喻,区块就像一个人,区块链好比一群人。怎么才能让一群人联系起来哪,就必须让他们之间有一定的关系和联系。比如,第一个人有100块钱,存入银行。银行给了他一张“凭证”,但是这张凭证被第二个人拿走了,第三个人的凭证被第四个。。。。

如此一来这么多人就被联系起来。咱们这次实现的简单的区块链就是本区块带有上一区块的哈希。

先简单定义一下区块的内容:

  1. # {
  2. # "index": 1, 区块的块号
  3. # "timestamp": "", 时间戳
  4. # "transactions": [ 交易内容
  5. # {
  6. # "sender": "",
  7. # "recipient": "",
  8. # "amount": 5,
  9. # }
  10. # ],
  11. # "proof": "", 工作量证明
  12. # "previous_hash":"" 上一个区块的hash
  13. #
  14. # }

本次才用的是Python Flask框架,使用云端MongoDB ,https://cloud.mongodb.com/注册申请这里就不详细说了。

简单说一下需要准备的有,PyCharm , pip , Python 3.7。

使用PyCharm 创建一个PyThon虚拟环境 。点击Create New Project 。选择文件夹,默认选项就是在本文件夹安装虚拟环境。

然后就是各种包

  1. import hashlib # hash 算法
  2. import json # josn
  3. from time import time # 时间戳
  4. from uuid import uuid4 # uuid为本机生成ID
  5. from flask import Flask, jsonify, request
  6. import pymongo

我们设想一下,数据要保存在什么地方才能在下次启动程序的时候继续按照上一次结束的数据进行下一次的运算。因此我们需要使用数据库保存我们需要保存的数据。所以我们要先连接数据库。

  1. # **User**:**password** 这是你创建集群的用户和密码
    client = pymongo.MongoClient('mongodb+srv://**User**:**password**@iec-pj8qn.mongodb.net/MainSite')
  2. db = client.MainSite #
  3. collection = db.blockchain

现在数据库已经连接上了,但是问题来了。我们怎么取出最底层的文档哪?下面我们需要一个循环遍历集合的最大值,回想一下我们定义的区块结构。里面定义的 index:1 。 每次新增一个区块,第二个区块的index = 2 . 一次增加下去。这样遍历的最大值,也可以说是遍历的次数就是我们需要寻找的index:last

,也就是最后一次被插入的数据。MongoDB 在没有给定特定的_id 字段时,自己会生成一个类似与时间戳的字段。这不是我们需要的,我们在取出数据的时候要把他剔除。

  1. class value:
  2. # 取出文档的数据再次组合并存储在current[] 列表里
  3. def value(self, index1, hash1, proof, transactions1, timestamp) -> list:
  4. current = []
  5. json_value = {
  6. 'index': index1,
  7. 'previous_hash': hash1,
  8. 'proof': proof,
  9. 'transactions': transactions1,
  10. 'timestamp': timestamp
  11. }
  12. current.append(json_value)
  13. return current
  14. class counting: # 循环遍历集合最大值
  15. def count(self):
  16. last_count = 0
  17. for x in collection.find(): # collection.find() 集合的所有文档
  18. last_count = last_count + 1
  19. return last_count
  20.  
  21. last1 = counting() # 调用counting类
  22. last = last1.count()
  23. print(last)
  24. result = collection.find_one({"index": last}) # 搜索到最后一个文档
  25. value = value() # 创建value对象
  26. chain0 = value.value(result['index'],
  27. result['previous_hash'],
  28. result['proof'],
  29. result['transactions'],
  30. result['timestamp']) # dict 转 list
  31. print(chain0)
  32. print(type(chain0))
  33.  
  34. client.close() # 连接断开

现在我们已经获取都最近一次插入的数据。我们现在就可以插入创始区块了:

  1. {
  2. "index": 1,
  3. "previous_hash": 1,
  4. "proof": 100,
  5. "timestamp": 1541940889.5927348,
  6. "transactions": []
  7. }

把这段josn插入MongoDB , 或许你可以在网页插入或者在本地下载一个 MongoDB Shell 这个云端MongoDB 有提示怎么下载,这里我就不多说了。如果不明白MongoDB 的用法请去 菜鸟教程

把创始区块插入集合,启动一下。出现你插入的数据,说明你已经成功的连接数据库。

下面我们来看一大段代码:

  1. class Blockchain:
  2.  
  3. def __init__(self): # 构造函数,初始区块链,当前交易,生成创始区块
  4. self.chain = [] # 真正的区块链
  5. self.chain.append(chain0[0]) # 每次连接取最后一个集合文档作为本次的启动创世区块
  6. self.current_transactions = []
  7. # self.new_block(proof=100, previous_hash=1) # 如果没有用到数据库,调用构造函数,自行创建一个创世区块
  8.  
  9. def new_block(self, proof, previous_hash=None, last_index=None): # 新建区块 工作量证明,前一个区块Hash
  10. # 定义交易区块实体
  11. block = {
  12. 'index': last_index + 1,
  13. 'timestamp': time(),
  14. 'transactions': self.current_transactions, # 当前交易
  15. 'proof': proof,
  16. 'previous_hash': previous_hash or self.hash(self.last_block)
  17. }
  18. self.current_transactions = [] # 清空当前交易
  19. self.chain.append(block) # 区块链添加新区块
  20. return block
  21.  
  22. def new_transactions(self, sender, recipient, amount) -> int: # 新的交易
  23. self.current_transactions.append( # 当前交易添加数据
  24. {
  25. 'sender': sender,
  26. 'recipient': recipient,
  27. 'amount': amount
  28. }
  29. )
  30.  
  31. return self.last_block['index'] + 1 # 最后一个区块的 index+1
  32.  
  33. @staticmethod
  34. def hash(block): # 区块hash算法
  35. block_string = json.dumps(block, sort_keys=True).encode()
  36. return hashlib.sha256(block_string).hexdigest()
  37.  
  38. @property
  39. def last_block(self): # 最后一个区块# 取出的最后一个区块类型总是 list
  40. long = len(self.chain)
  41. print(long)
  42. if long > 1:
  43. last_block = self.chain[-1]
  44. print('++++++++++++++++++++++++')
  45. print(last_block)
  46. print(type(last_block))
  47. print(last_block['index'])
  48. temp_json = {
  49. 'index': last_block['index'],
  50. 'previous_hash': last_block['previous_hash'],
  51. 'proof': last_block['proof'],
  52. 'transactions': last_block['transactions'],
  53. 'timestamp': last_block['timestamp']
  54. }
  55. print(temp_json)
  56. self.chain.append(temp_json)
  57. print(self.chain)
  58. print(type(self.chain[-1]))
  59. return self.chain[-1]
  60.  
  61. def proof_of_work(self, last_proof: int) -> int: # 工作量证明
  62. proof = 0
  63. while self.valid_proof(last_proof, proof) is False: # 循环检测合格hash
  64. proof += 1
  65. # print(proof)
  66. return proof
  67.  
  68. def valid_proof(self, last_proof: int, proof: int) -> bool: # 有效工作量证明
  69. guess = f'{last_proof}{proof}'.encode()
  70. guess_hash = hashlib.sha256(guess).hexdigest() # 哈希后得到摘要
  71. # print(guess_hash)
  72. if guess_hash[0:4] == "": # 工作量证明条件
  73. return True
  74. else:
  75. return False

上面的类,基本上都有注释,并且时我测试时的断点也有保留,更清晰的了解数据的类型和数值。我就不一一口述了。简单的说一下就是 交易方法def new_transactions, 和 新建块的打包计算def new_block

计算hash def hash(block):  有效工作量证明def hash(block) 。

本地文件夹创建static 文件夹  加入index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>index</title>
  6. </head>
  7. <body>
  8. <p>Hello BlockChain</p>
  9. <form action="transactions" method="post">
  10. sender:<input type="text" name="sender">
  11. recipient:<input type="text" name="recipient">
  12. amount:<input type="text" name="amount">
  13. <input type="submit" value="submit">
  14. </form>
  15.  
  16. </body>
  17. </html>

下面开始使用我们的Flask框架

  1. app = Flask(__name__, static_url_path='') # 参数的意思是为静态html文件,添加路径

Flask框架

  1. app = Flask(__name__, static_url_path='') # 参数的意思是为静态html文件,添加路径
    blockchain = Blockchain() # 创建对象
  2.  
  3. node_identifier = str(uuid4()).replace('-', '') # 使用uuid生成本结点ID,replace()替换'-'
  1.  
  2. @app.route('/', methods=['GET'])
  3. def index():
  4. return app.send_static_file('index.html')
  5.  
  6. @app.route('/transactions', methods=['POST'])
  7. def new_transaction(): # 新的交易
  8. print(request)
  9. sender = request.form['sender'] # 取出 Form 里的值
  10. print(sender)
  11. recipient = request.form['recipient']
  12. print(recipient)
  13. amount = request.form['amount']
  14. print(amount)
  15.  
  16. values = [sender, recipient, amount]
  17. index = blockchain.new_transactions(values[0], # 调用函数
  18. values[1],
  19. values[2])
  20. response = {"message": f'Transaction will be added to Block {index}'}
  21. return jsonify(response), 201
  22.  
  23. @app.route('/mine', methods=['GET'])
  24. def mine(): # 交易打包,挖矿
  25. last_block = blockchain.last_block
  26. print("=======================")
  27. print(type(last_block))
  28. print(last_block)
  29. last_proof = last_block['proof']
  30. print(last_proof)
  31. last_index = last_block['index']
  32. print(last_index)
  33.  
  34. proof = blockchain.proof_of_work(last_proof) # 工作量证明 也就是挖矿
  35.  
  36. blockchain.new_transactions(sender="", # 给本结点的奖励
  37. recipient=node_identifier,
  38. amount=1)
  39.  
  40. block = blockchain.new_block(proof, None, last_index) # 打包区块
  41. client = pymongo.MongoClient('mongodb+srv://**user**:**password**@iec-pj8qn.mongodb.net/MainSite')
  42. db = client.MainSite
  43. collection = db.blockchain
  44. collection.insert_one(block) # 把打包好的区块添加到数据库。
  45. client.close()
  46. response = {
  47. "message": "New Block Forged",
  48. "index": block['index'],
  49. "transactions": block['transactions'],
  50. "proof": block['proof'],
  51. "previous_hash": block['previous_hash']
  52. }
  53.  
  54. return jsonify(response), 200
  55.  
  56. @app.route('/chain', methods=['GET'])
  57. def full_chain(): # 返回区块链
  58. response = {
  59. 'chain': blockchain.chain,
  60. 'length': len(blockchain.chain)
  61. }
  62. return jsonify(response), 200
  63.  
  64. if __name__ == '__main__': # 当 block chain.py 作为模块时不执行下面函数
  65. app.run(host='127.0.0.1', port=3000)

把所有的代码块合在一起就是本次区块链模拟器的全部内容了,这只是单节点,单保存的链,只是更好的去理解区块链的结构,还有比如共识机制和选择链我们还没有去完成。

对了 说一下用法:

打开http://127.0.0.1:3000/

提交后: http://127.0.0.1:3000/mine

之后打开 PowerShell

结束。

Python 模拟简单区块链的更多相关文章

  1. 用Python从零开始创建区块链

    本文主要内容翻译自Learn Blockchains by Building One 本文原始链接,转载请注明出处. 作者认为最快的学习区块链的方式是自己创建一个,本文就跟随作者用Python来创建一 ...

  2. 用 Python 撸一个区块链

    本文翻译自 Daniel van Flymen 的文章 Learn Blockchains by Building One 略有删改.原文地址:https://hackernoon.com/learn ...

  3. 基于java实现的简单区块链

    技术:maven3.0.5 + jdk1.8   概述 区块链是分布式数据存储.点对点传输.共识机制.加密算法等计算机技术的新型应用模式.所谓共识机制是区块链系统中实现不同节点之间建立信任.获取权益的 ...

  4. 51行代码实现简单的PHP区块链

    本文原始地址:php区块链demo 今年区块链特别火,我也很火啊.我火什么呢.前几年,公众平台出现,还得花时间去学去看,后来小程序出现,又得花时间精力去学去看.现在比特币.以太坊等去中心化货币带起了区 ...

  5. 孤荷凌寒自学python第103天认识区块链017

    [主要内容] 今天继续分析从github上获取的开源代码怎么实现简单区块链的入门知识,共用时间25分钟. (此外整理作笔记花费了约34分钟) 详细学习过程见文末学习过程屏幕录像. 今天所作的工作是进一 ...

  6. Python实现一条基于POS算法的区块链

    区块链中的共识算法 在比特币公链架构解析中,就曾提到过为了实现去中介化的设计,比特币设计了一套共识协议,并通过此协议来保证系统的稳定性和防攻击性. 并且我们知道,截止目前使用最广泛,也是最被大家接受的 ...

  7. 用spring boot 2从零开始创建区块链

    区块链这么火的技术,大java怎能落后,所以有了本文,主要代码参考自 Learn Blockchains by Building One , 中文翻译:用Python从零开始创建区块链 . 一.区块链 ...

  8. 区块链入门到实战(27)之以太坊(Ethereum) – 智能合约开发

    智能合约的优点 与传统合同相比,智能合约有一些显著优点: 不需要中间人 费用低 代码就是规则 区块链网络中有多个备份,不用担心丢失 避免人工错误 无需信任,就可履行协议 匿名履行协议 以太坊(Ethe ...

  9. JavaScript开发区块链只需200行代码

    用JavaScript开发实现一个简单区块链.通过这一开发过程,你将理解区块链技术是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录. 然而,在通常情况下,当 ...

随机推荐

  1. LAMP 3.2 mysql登陆

    mysql 服务启动时,不仅会监听 IP:Port,还会监听一个 socket,我们安装的 mysql 是监听在/tmp/mysql.sock.如果 php 是在本地,那么 php 和 mysql 通 ...

  2. DAY18-Django之form表单

    构建一个表单 假设你想在你的网站上创建一个简单的表单,以获得用户的名字.你需要类似这样的模板: <form action="/your-name/" method=" ...

  3. DAY15-Django模板语言

    Django模板系统 官方文档 你可能已经注意到我们在例子视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python代码之中. def current_datetime(reque ...

  4. springboot启动异常java.lang.NoSuchFieldError: DEFAULT_INCOMPATIBLE_IMPROVEMENTS

    解决办法一 yml或者Properties文件中配置 spring.freemarker.check-template-location=false 解决办法二 @SpringBootApplicat ...

  5. javaScript之节点操作

    javaScript程序员避免不了要操作页面中的DOM,除了经常使用的: appendChild()向childNodes列表的末尾添加一个节点. insertBefore(),接受两个参数,要插入的 ...

  6. linux进程的软中断通信

    linux进程的软中断通信 要求 实现软中断通信的程序 使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上发出的中断信号(即按delete键),当父进程接收到这两个 ...

  7. android 中context的具体作用和意义

    context在android中是非常重要的一个类,此类一般用于activity之中 从字面意思来看,这是环境变量,内部实现了一些方法,但是此类也可以看做是一个句柄,用来唯一标示activity 举个 ...

  8. oracle语法练习汇总

    全是自己一个一个敲出来的啊 啊 啊 --(1)查询20号部门的所有员工信息. --(2)查询所有工种为CLERK的员工的工号.员工名和部门名. select e.empno,e.ename,d.dna ...

  9. IO流对文件的读取操作

    /*1. 在当前项目的根目录下有一个名为“info.txt”的文件,里面存放的内容如下(可手动创建录入,不需要使用IO流): 2. 利用IO流的知识读取info.txt文件的内容, 在控制台上打印大写 ...

  10. SDUT 3400 数据结构实验之排序三:bucket sort

    数据结构实验之排序三:bucket sort Time Limit: 150MS Memory Limit: 65536KB Submit Statistic Problem Description ...