【Python】实现一个简单的区块链系统

本文章利用 Python 实现一个简单的功能较为完善的区块链系统(包括区块链结构、账户、钱包、转账),采用的共识机制是 POW。

一、区块与区块链结构

Block.py

import hashlib
from datetime import datetimeclass Block:"""区块链结构:prev_hash:      父区块哈希值data:           区块内容timestamp:      区块创建时间hash:           区块哈希值"""def __init__(self, data, prev_hash):# 将传入的父区块哈希值和数据保存到变量中self.prev_hash = prev_hashself.data = data# 获得当前的时间self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 计算区块哈希值# 获取哈希对象message = hashlib.sha256()# 先将数据内容转为字符串并进行编码,再将它们哈希# 注意:update() 方法现在只接受 bytes 类型的数据,不接收 str 类型message.update(str(self.prev_hash).encode('utf-8'))message.update(str(self.prev_hash).encode('utf-8'))message.update(str(self.prev_hash).encode('utf-8'))# update() 更新 hash 对象,连续的调用该方法相当于连续的追加更新# 返回字符串类型的消息摘要self.hash = message.hexdigest()

 BlockChain.py

from Block import Blockclass BlockChain:"""区块链结构体blocks:         包含区块的列表"""def __init__(self):self.blocks = []def add_block(self, block):"""添加区块:param block::return:"""self.blocks.append(block)# 新建区块
genesis_block = Block(data="创世区块", prev_hash="")
new_block1 = Block(data="张三转给李四一个比特币", prev_hash=genesis_block.hash)
new_block2 = Block(data="张三转给王五三个比特币", prev_hash=genesis_block.hash)# 新建一个区块链对象
blockChain = BlockChain()
# 将刚才新建的区块加入区块链
blockChain.add_block(genesis_block)
blockChain.add_block(new_block1)
blockChain.add_block(new_block2)# 打印区块链信息
print("区块链包含区块个数为:%d\n" % len(blockChain.blocks))
blockHeight = 0
for block in blockChain.blocks:print(f"本区块高度为:{blockHeight}")print(f"父区块哈希:{block.prev_hash}")print(f"区块内容:{block.data}")print(f"区块哈希:{block.hash}")print()blockHeight += 1

 测试结果 

二、加入工作量证明(POW)

将工作量证明加入到 Block.py 中

import hashlib
from datetime import datetime
from time import timeclass Block:"""区块链结构:prev_hash:      父区块哈希值data:           区块内容timestamp:      区块创建时间hash:           区块哈希值nonce:          随机数"""def __init__(self, data, prev_hash):# 将传入的父区块哈希值和数据保存到变量中self.prev_hash = prev_hashself.data = data# 获得当前的时间self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 设置随机数、哈希初始值为 Noneself.nonce = Noneself.hash = None# 类的 __repr__() 方法定义了实例化对象的输出信息def __repr__(self):return f"区块内容:{self.data}\n区块哈希值:{self.hash}"class ProofOfWork:"""工作量证明:block:          区块difficulty:     难度值"""def __init__(self, block, difficult=5):self.block = block# 定义出块难度,默认为 5,表示有效哈希值以 5 个零开头self.difficulty = difficultdef mine(self):"""挖矿函数:return:"""i = 0prefix = '0' * self.difficultywhile True:message = hashlib.sha256()message.update(str(self.block.prev_hash).encode('utf-8'))message.update(str(self.block.data).encode('utf-8'))message.update(str(self.block.timestamp).encode('utf-8'))message.update(str(i).encode('utf-8'))# digest() 返回摘要,作为二进制数据字符串值# hexdigest() 返回摘要,作为十六进制数据字符串值digest = message.hexdigest()# str.startswith(prefix) 检测字符串是否是以 prefix(字符串)开头,返回布尔值if digest.startswith(prefix):# 幸运数字self.block.nonce = i# 区块哈希值为十六进制数据字符串摘要self.block.hash = digestreturn self.blocki += 1def validate(self):"""验证有效性:return:"""message = hashlib.sha256()message.update(str(self.block.prev_hash).encode('utf-8'))message.update(str(self.block.data).encode('utf-8'))message.update(str(self.block.timestamp).encode('utf-8'))message.update(str(self.block.nonce).encode('utf-8'))digest = message.hexdigest()prefix = '0' * self.difficultyreturn digest.startswith(prefix)# ++++++++测试++++++++
# 定义一个区块
b = Block(data="测试", prev_hash="")# 定义一个工作量证明
w = ProofOfWork(b)# 开始时间
start_time = time()
# 挖矿,并统计函数执行时间
print("+++开始挖矿+++")
valid_block = w.mine()
# 结束时间
end_time = time()
print(f"挖矿花费时间:{end_time - start_time}秒")# 验证区块
print(f"区块哈希值是否符合规则:{w.validate()}")
print(f"区块哈希值为:{b.hash}")

测试结果

更新 BlockChain.py

from Block import Block, ProofOfWorkclass BlockChain:"""区块链结构体blocks:         包含区块的列表"""def __init__(self):self.blocks = []def add_block(self, block):"""添加区块:param block::return:"""self.blocks.append(block)# 新建一个区块链对象
blockChain = BlockChain()# 新建区块
block1 = Block(data="创世区块", prev_hash="")
w1 = ProofOfWork(block1)
genesis_block = w1.mine()
blockChain.add_block(genesis_block)block2 = Block(data="张三转给李四一个比特币", prev_hash=genesis_block.hash)
w2 = ProofOfWork(block2)
block = w2.mine()
blockChain.add_block(block)block3 = Block(data="张三转给王五三个比特币", prev_hash=block.hash)
w3 = ProofOfWork(block3)
block = w3.mine()
blockChain.add_block(block)# 打印区块链信息
print("区块链包含区块个数为:%d\n" % len(blockChain.blocks))
blockHeight = 0
for block in blockChain.blocks:print(f"本区块高度为:{blockHeight}")print(f"父区块哈希:{block.prev_hash}")print(f"区块内容:{block.data}")print(f"区块哈希:{block.hash}")print()blockHeight += 1

 测试结果

三、实现钱包、账户、交易功能

 实现钱包、账户、交易功能要先安装非对称加密算法库 ecdsa。如果网速慢,引用下面这个网站

-i https://pypi.tuna.tsinghua.edu.cn/simple

添加钱包、账户功能 Wallet.py

import base64
import binascii
from hashlib import sha256
# 导入椭圆曲线算法
from ecdsa import SigningKey, SECP256k1, VerifyingKeyclass Wallet:"""钱包"""def __init__(self):"""钱包初始化时基于椭圆曲线生成一个唯一的秘钥对,代表区块链上一个唯一的账户"""# 生成私钥self._private_key = SigningKey.generate(curve=SECP256k1)# 基于私钥生成公钥self._public_key = self._private_key.get_verifying_key()@propertydef address(self):"""这里通过公钥生成地址"""h = sha256(self._public_key.to_pem())# 地址先由公钥进行哈希算法,再进行 Base64 计算而成return base64.b64encode(h.digest())@propertydef pubkey(self):"""返回公钥字符串"""return self._public_key.to_pem()def sign(self, message):"""生成数字签名"""h = sha256(message.encode('utf8'))# 利用私钥生成签名# 签名生成的是一串二进制字符串,为了便于查看,这里转换为 ASCII 字符串进行输出return binascii.hexlify(self._private_key.sign(h.digest()))def verify_sign(pubkey, message, signature):"""验证签名"""verifier = VerifyingKey.from_pem(pubkey)h = sha256(message.encode('utf8'))return verifier.verify(binascii.unhexlify(signature), h.digest())

实现转账功能 Transaction.py

import jsonclass Transaction:"""交易的结构"""def __init__(self, sender, recipient, amount):"""初始化交易,设置交易的发送方、接收方和交易数量"""# 交易发送者的公钥self.pubkey = None# 交易的数字签名self.signature = Noneif isinstance(sender, bytes):sender = sender.decode('utf-8')self.sender = sender        # 发送方if isinstance(recipient, bytes):recipient = recipient.decode('utf-8')self.recipient = recipient  # 接收方self.amount = amount        # 交易数量def set_sign(self, signature, pubkey):"""为了便于验证这个交易的可靠性,需要发送方输入他的公钥和签名"""self.signature = signature  # 签名self.pubkey = pubkey  # 发送方公钥def __repr__(self):"""交易大致可分为两种,一是挖矿所得,而是转账交易挖矿所得无发送方,以此进行区分显示不同内容"""if self.sender:s = f"从{self.sender}转自{self.recipient}{self.amount}个加密货币"elif self.recipient:s = f"{self.recipient}挖矿所得{self.amount}个加密货币"else:s = "error"return sclass TransactionEncoder(json.JSONEncoder):"""定义Json的编码类,用来序列化Transaction"""def default(self, obj):if isinstance(obj, Transaction):return obj.__dict__else:return json.JSONEncoder.default(self, obj)# return super(TransactionEncoder, self).default(obj)

更新 Block.py

import hashlib
import json
from datetime import datetime
from Transaction import Transaction, TransactionEncoderclass Block:"""区块结构prev_hash:      父区块哈希值transactions:   交易对timestamp:      区块创建时间hash:           区块哈希值Nonce:          随机数"""def __init__(self, transactions, prev_hash):# 将传入的父哈希值和数据保存到类变量中self.prev_hash = prev_hash# 交易列表self.transactions = transactions# 获取当前时间self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")# 设置Nonce和哈希的初始值为Noneself.nonce = Noneself.hash = None# 类的 __repr__() 方法定义了实例化对象的输出信息def __repr__(self):return f"区块内容:{self.transactions}\n区块哈希值:{self.hash}"class ProofOfWork:"""工作量证明block:          区块difficulty:     难度值"""def __init__(self, block, miner, difficult=5):self.block = blockself.miner = miner# 定义工作量难度,默认为5,表示有效的哈希值以5个“0”开头self.difficulty = difficult# 添加挖矿奖励self.reward_amount = 1def mine(self):"""挖矿函数"""i = 0prefix = '0' * self.difficulty# 设置挖矿自动生成交易信息,添加挖矿奖励t = Transaction(sender="",recipient=self.miner.address,amount=self.reward_amount,)sig = self.miner.sign(json.dumps(t, cls=TransactionEncoder))t.set_sign(sig, self.miner.pubkey)self.block.transactions.append(t)while True:message = hashlib.sha256()message.update(str(self.block.prev_hash).encode('utf-8'))# 更新区块中的交易数据# message.update(str(self.block.data).encode('utf-8'))message.update(str(self.block.transactions).encode('utf-8'))message.update(str(self.block.timestamp).encode('utf-8'))message.update(str(i).encode("utf-8"))digest = message.hexdigest()if digest.startswith(prefix):self.block.nonce = iself.block.hash = digestreturn self.blocki += 1def validate(self):"""验证有效性"""message = hashlib.sha256()message.update(str(self.block.prev_hash).encode('utf-8'))# 更新区块中的交易数据# message.update(str(self.block.data).encode('utf-8'))message.update(json.dumps(self.block.transactions).encode('utf-8'))message.update(str(self.block.timestamp).encode('utf-8'))message.update(str(self.block.nonce).encode('utf-8'))digest = message.hexdigest()prefix = '0' * self.difficultyreturn digest.startswith(prefix)

更新 BlockChain.py

from Block import Block, ProofOfWork
from Transaction import Transaction
from Wallet import Wallet, verify_signclass BlockChain:"""区块链结构体blocks:        包含的区块列表"""def __init__(self):self.blocks = []def add_block(self, block):"""添加区块"""self.blocks.append(block)def print_list(self):print(f"区块链包含个数为:{len(self.blocks)}")for block in self.blocks:height = 0print(f"区块链高度为:{height}")print(f"父区块为:{block.prev_hash}")print(f"区块内容为:{block.transactions}")print(f"区块哈希值为:{block.hash}")height += 1print()

为了方便我们对区块链进行操作,我们可以在 BlockChain.py 中补充一些方法

# 传入用户和区块链,返回用户的“余额”
def get_balance(user, blockchain):balance = 0for block in blockchain.blocks:for t in block.transactions:if t.sender == user.address.decode():balance -= t.amountelif t.recipient == user.address.decode():balance += t.amountreturn balance# user生成创世区块(新建区块链),并添加到区块链中
def generate_genesis_block(user):blockchain = BlockChain()new_block = Block(transactions=[], prev_hash="")w = ProofOfWork(new_block, user)genesis_block = w.mine()blockchain.add_block(genesis_block)# 返回创世区块return blockchain# 用户之间进行交易并记入交易列表
def add_transaction(sender, recipient, amount):# 新建交易new_transaction = Transaction(sender=sender.address,recipient=recipient.address,amount=amount)# 生成数字签名sig = sender.sign(str(new_transaction))# 传入付款方的公钥和签名new_transaction.set_sign(sig, sender.pubkey)return new_transaction# 验证交易,若验证成功则加入交易列表
def verify_new_transaction(new_transaction, transactions):if verify_sign(new_transaction.pubkey,str(new_transaction),new_transaction.signature):# 验证交易签名没问题,加入交易列表print("交易验证成功")transactions.append(new_transaction)else:print("交易验证失败")# 矿工将全部验证成功的交易列表打包出块
def generate_block(miner, transactions, blockchain):new_block = Block(transactions=transactions,prev_hash=blockchain.blocks[len(blockchain.blocks) - 1].hash)print("生成新的区块...")# 挖矿w = ProofOfWork(new_block, miner)block = w.mine()print("将新区块添加到区块链中")blockchain.add_block(block)

进行测试

# 新建交易列表
transactions = []# 创建 3 个用户
alice = Wallet()
tom = Wallet()
bob = Wallet()print("alice创建创世区块...")
blockchain = generate_genesis_block(alice)
print()print(f"alice 的余额为{get_balance(alice, blockchain)}个比特币")
print(f"tom 的余额为{get_balance(tom, blockchain)}个比特币")
print(f"bob 的余额为{get_balance(bob, blockchain)}个比特币")
print()# 打印区块链信息
blockchain.print_list()print("新增交易:alice 转账 0.5 比特币给 tom")
nt = add_transaction(alice, tom, 0.5)
print()
verify_new_transaction(nt, transactions)
print(f"矿工 bob 将全部验证成功的交易列表打包出块...")
generate_block(bob, transactions, blockchain)
print("添加完成\n")# 打印区块链信息
blockchain.print_list()

测试结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/182873.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux常用命令——ls 命令详解

文章目录 在Linux操作系统中,ls 命令是最常用且基础的命令之一。它用于列出目录内容,展示文件和目录的信息。本文将详细介绍ls 命令的各个参数及其含义,并通过实例演示它们的用法。 ls命令概述 ls 命令的基本格式为 ls [选项] [文件或目录]…

VirtualBox 7.0.8(虚拟机软件)

VirtualBox是一款开源的虚拟机软件,它是使用Qt编写,在Sun被Oracle收购后正式更名成Oracle VM VirtualBox。它可以在VirtualBox上安装并且执行Solaris、Windows、DOS、Linux、OS/2 Warp、BSD等系统作为客户端操作系统。使用者可以在VirtualBox上安装并且运…

stm32 计数模式

计数模式 但是对于通用定时器而言,计数器的计数模式不止向上计数这一种。上文基本定时器中计数器的计数模式都是向上计数的模式。 向上计数模式:计数器从0开始,向上自增,计到和自动重装寄存器的目标值相等时,计数器清…

C语言、c++史上最全最全爱心代码大全,彩色闪动、字符填充,附源码

第一种&#xff1a;红色爱心代码 直接上代码&#xff1a; #include<stdio.h> #include<Windows.h> int main() {system(" color 0c");//设计程序颜色 printf("遇见你是一件很开心的事情,爱你哟&#xff01;&#xff01;&#xff01;\n");//打…

面试阿里测开岗失败后,被面试官在朋友圈吐槽了......

前一阵子有个徒弟向我诉苦&#xff0c;说自己在参加某大厂测试面试的时候被面试官怼得哑口无言&#xff0c;场面让他一度十分尴尬 印象最深的就是下面几个问题&#xff1a; 根据你以前的工作经验和学习到的测试技术&#xff0c;说说你对质量保证的理解&#xff1f; 非关系型…

【数据结构】栈和队列---C语言版

栈和队列 一、栈的概念二、栈的实现三、栈的应用四、队列的概念五、队列的实现 一、栈的概念 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守…

【古月居《ros入门21讲》学习笔记】08_发布者Publisher的编程实现

目录 说明&#xff1a; 1. 话题模型 图示 说明 2. 实现过程&#xff08;C&#xff09; 创建功能包 创建发布者代码&#xff08;C&#xff09; 配置发布者代码编译规则 编译并运行 编译 运行 3. 实现过程&#xff08;Python&#xff09; 创建发布者代码&#xff08;…

解决tomcat 启动 , 中文乱码问题

解决tomcat 启动 , 中文乱码问题. 第一步找到server.xml, 找到连接器, 添加 URIEncoding"UTF-8" 注意是英文的引号. 第二步, 找到 logging.properties , 在其中找到 第三步,启动服务, 观察现象,亲测有效.

Django快速搭建静态网页

Django的快速搭建 这个是例子 这个是一个目录 项目名称&#xff1a;项目似乎被命名为DJ0928&#xff0c;这是Django项目的根目录。 文件都是Django项目的核心配置文件。 settings.py 包含了项目的配置设置。urls.py 定义了项目的URL路由。wsgi.py 和 asgi.py 分别用于Web服务器…

【Qt之QSqlRelationalDelegate】描述及使用

描述 QSqlRelationalDelegate类提供了一个委托&#xff0c;用于显示和编辑来自QSqlRelationalTableModel的数据。 与默认委托不同&#xff0c;QSqlRelationalDelegate为作为其他表的外键的字段提供了一个组合框。 要使用该类&#xff0c;只需在带有QSqlRelationalDelegate实例…

macbook电脑运行缓慢和卡顿内存怎么清理了?

假如你还在为“你的系统内存不足”的提示所困扰&#xff0c;或者你的Mac电脑突然运行缓慢和卡顿&#xff0c;那么你一般需要认真了解一下macbook内存怎么清理了? MacBook是功能强大的电脑&#xff0c;这点毫无疑问&#xff0c;但是它仍旧会随着时间推移变得运行缓慢。值得庆幸…

二叉树OJ题之二

今天我们一起来看一道判断一棵树是否为对称二叉树的题&#xff0c;力扣101题&#xff0c; https://leetcode.cn/problems/symmetric-tree/ 我们首先先来分析这道题&#xff0c;要判断这道题是否对称&#xff0c;我们首先需要判断的是这颗树根节点的左右子树是否对称&#xff0…

VSCODE+QEMU+WSL调试RISCV代码(SBI、kernel)

前言 最近在对RISC-V架构比较感兴趣&#xff0c;正好手头有《RISC-V体系结构编程与实践》的书籍&#xff0c;就打算跟随笨叔将这块的知识学习起来&#xff0c;最开始当然是需要搭建一个基础的实验平台&#xff0c;本来笨叔是贴心的提供了VMare的环境&#xff0c;奈何天生叛逆的…

消息中间件——RabbitMQ(七)高级特性 2

前言 上一篇消息中间件——RabbitMQ&#xff08;七&#xff09;高级特性 1中我们介绍了消息如何保障100%的投递成功&#xff1f;,幂等性概念详解,在海量订单产生的业务高峰期&#xff0c;如何避免消息的重复消费的问题&#xff1f;,Confirm确认消息、Return返回消息。这篇我们…

作为用户,推荐算法真的是最优解么?

前言 众所周知&#xff0c;随着互联网技术的发展&#xff0c;推荐算法也越来越普及。无论是购物网站、社交媒体平台还是在线影视平台&#xff0c;推荐算法已成为用户获取相关信息的主要途径。据悉&#xff0c;近期GitHub决定结合算法推荐&#xff0c;将“Following”和“For Yo…

uniapp打包ios有时间 uniapp打包次数

我们经常用的解决方案有,分包,将图片上传到服务器上,减少插件引入。但是还有一个方案好多刚入门uniapp的人都给忽略了,就是在源码视图中配置,开启分包优化。 1.分包 目前微信小程序可以分8个包,每个包的最大存储是2M,也就是说你文件总体的大小不能超过16M,每个包的大…

刷题学习记录

[SWPUCTF 2021 新生赛]sql 进入环境 查看源码&#xff0c;发现是get传参且参数为wllm fuzz测试&#xff0c;发现空格&#xff0c;&#xff0c;and被过滤了 同样的也可以用python脚本进行fuzz测试 import requests fuzz{length ,,handler,like,select,sleep,database,delete,h…

【MySQL】常用内置函数:数值函数 / 字符串函数 / 日期函数 / 其他函数

文章目录 数值函数round()&#xff1a;四舍五入ceiling()&#xff1a;上限函数floor()&#xff1a;地板函数abs()&#xff1a;计算绝对值rand()&#xff1a;生成0-1的随机浮点数 字符串函数length()&#xff1a;获取字符串中的字符数upper() / lower()&#xff1a;将字符串转化…

ThinkPHP的方法接收json数据问题

第一次接触到前后端分离开发&#xff0c;需要在后端接收前端ajax提交的json数据&#xff0c;开发基于ThinkPHP3.2.3框架。于是一开始习惯性的直接用I()方法接收到前端发送的json数据&#xff0c;然后用json_decode()解析发现结果为空&#xff01;但是打印出还未解析的值却打印得…

MySQL事务日志

文章目录 1. redo日志 1. redo日志 口述&#xff1a;redo log 日志其实保证了ACID中的持久性&#xff0c;就是说当事务commit后&#xff0c;那么相应的修改呀更新这些操作其实都会记录到redo log中&#xff0c;其实这里的操作还是区别于redis中的aof中&#xff0c;它不是具体的…