python区块链简单模拟【05】

新增内容:构建去中心化网络

import socket      #套接字,利用三元组【ip地址,协议,端口】可以进行网络间通信
import threading   #线程
import pickle# 定义一个全局列表保存所有节点
NODE_LIST = []class Node(threading.Thread):  #继承与线程def __init__(self, name, port, host="localhost"):threading.Thread.__init__(self, name=name)self.host = host           #  服务器地址,本地电脑都设为localhostself.port = port           # 每个节点对应一个唯一的端口号self.name = name           # 唯一的节点名称self.wallet = Wallet()self.blockchain = None    # 用来存储一个区块链副本  账本def run(self):"""节点运行"""self.init_blockchain()    # 初始化区块链# 在指定端口进行监听sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)      #获取TCP/ip  套接字socksock.bind((self.host, self.port))                             #绑定主机,端口号到套接字sockNODE_LIST.append({"name": self.name,"host": self.host,"port": self.port})sock.listen(10)                                            #开始TCP监听print(self.name, "运行中...")while True:       # 不断处理其他节点发送的请求connection,address = sock.accept()                    #被动接受TCP客户的连接,(阻塞式)等待连接的到来try:print(self.name, "处理请求内容...")self.handle_request(connection)except socket.timeout:  print('超时!')except Exception as e:print(e, )connection.close()def handle_request(self, connection):data = []while True:    # 不断读取请求数据直至读取完成buf = connection.recv(1024)  if not buf: # 若读取不到新的数据则退出breakdata.append(buf)if len(buf) < 1024:   # 若读取到的数据长度小于规定长度,说明数据读取完成,退出breakt = pickle.loads(b''.join(data)) #从pickle格式的文件中读取数据并转换为Python的类型。print("数据接受完成,判断数据的  类 :交易,区块,初始化" )if isinstance(t, Transaction):  # 如果t是新交易类  消息print("处理交易请求...")if verify_sign(t.pubkey, str(t), t.signature):   #验证交易,公钥验证签名# 验证交易签名没问题,生成一个新的区块print(self.name, "验证交易成功")new_block = Block(transactions=[t], prev_hash="")print(self.name, "生成新的区块...")w = ProofOfWork(new_block, self.wallet)block = w.mine()                              #挖矿,挖到正确的区块哈希值,此处block就是新的区块,主要是找到了符合要求的nonce值print(self.name, "将新区块添加到区块链中")self.blockchain.add_block(block)print(self.name, "将新区块广播到网络中...")self.broadcast_new_block(block)else:print(self.name, "交易验证失败!")   #签名不对elif isinstance(t, Block):   #如果t是新区块类  消息print("处理新区块请求...")if self.verify_block(t):  print(self.name, "区块验证成功")  self.blockchain.add_block(t)print(self.name, "添加新区块成功")else:print(self.name, "区块验证失败!")else:  # 如果不是新区块消息,默认为初始化消息类型,返回本地区块链内容print("是我是我,我是初始化,我要返回我的区块链信息")connection.send(pickle.dumps(self.blockchain))def verify_block(self, block):"""验证区块有效性   是否是符合难度的区块哈希值,找到了正确的nonce值"""message = hashlib.sha256()message.update(str(block.prev_hash).encode('utf-8'))# 更新区块中的交易数据# message.update(str(self.block.data).encode('utf-8'))message.update(str(block.transactions).encode('utf-8'))message.update(str(block.timestamp).encode('utf-8'))message.update(str(block.nonce).encode('utf-8'))digest = message.hexdigest()prefix = '0' * DIFFICULTYreturn digest.startswith(prefix)def broadcast_new_block(self, block):"""将新生成的区块广播到网络中其他节点"""for node in NODE_LIST:     #遍历节点中的每一个节点,把新的区块广播给除了自己的所有节点host =node['host']port = node['port']if host == self.host and port == self.port:print(self.name, "忽略自身节点")else:print(self.name, "广播新区块至 %s" % (node['name']))sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.connect((host, port))    # 连接到网络中的节点sock.send(pickle.dumps(block))   # 发送新区块sock.close()          # 发送完成后关闭连接def init_blockchain(self):"""初始化当前节点的区块链"""#PER_BYTE = 1024if NODE_LIST:                # 若当前网络中已存在其他节点,则从第一个节点从获取区块链信息host = NODE_LIST[0]['host']port = NODE_LIST[0]['port']name = NODE_LIST[0]["name"]print(self.name, "发送初始化请求 %s" % (name))print("开始让节点1发送请求")sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    #获取TCP/ip套接字sock.connect((host, port))    # 连接到网络中的第一个节点sock.send(pickle.dumps('INIT'))   # 发送初始化请求   pickle.dumps将Python数据转换为pickle格式的bytes字串print("请求成功")data = []print("开始接受节点1的connect返回的信息")while True:          # 读取区块链信息,直至完全获取后退出buf = sock.recv(1024)print("接收中")if not buf:print("接收完毕,接空")breakdata.append(buf)if len(buf) < 1024:print("太短了,完毕")breaksock.close()   # 获取完成后关闭连接# 将获取的区块链信息赋值到当前节点self.blockchain = pickle.loads(b''.join(data))print(self.name, "初始化完成.")else:# 如果是网络中的第一个节点,初始化一个创世区块block = Block(transactions=[], prev_hash="")w = ProofOfWork(block, self.wallet)genesis_block = w.mine()self.blockchain = BlockChain()self.blockchain.add_block(genesis_block)print("生成创世区块")def submit_transaction(self, transaction):   #遍历节点中的每一个节点,把新的交易广播给除了自己的所有节点for node in NODE_LIST:host =node['host']port = node['port']if host == self.host and port == self.port:print(self.name, "忽略自身节点")else:print(self.name, "广播新区块至 %s:%s" % (self.host, self.port))sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  sock.connect((node["host"], node["port"]))  sock.send(pickle.dumps(transaction)) sock.close()def get_balance(self):balance = 0for block in self.blockchain.blocks:for t in block.transactions:if t.sender == self.wallet.address.decode():balance -= t.amountelif t.recipient == self.wallet.address.decode():balance += t.amountprint("当前拥有%.1f个加密货币" % (balance))def print_blockchain(self):print("区块链包含区块个数: %d\n" % len(self.blockchain.blocks))for block in self.blockchain.blocks:print("上个区块哈希:%s" % block.prev_hash)print("区块内容:%s" % block.transactions)print("区块哈希:%s" % block.hash)print("\n") 
# 初始化节点1node1 = Node("节点1", 8000)
node1.start()   #启动线程  调用 start() 方法是用来启动线程的,轮到该线程执行时,会自动调用 run();直接调用 run() 方法
node1.print_blockchain()  #输出区块信息

在这里插入图片描述

node2 = Node("节点2", 8001)
node2.start() 
node2.print_blockchain()

在这里插入图片描述

node1.get_balance()
node2.get_balance()

在这里插入图片描述

#创建交易
new_transaction = Transaction(sender=node1.wallet.address,recipient=node2.wallet.address,amount=0.3
)
sig = node1.wallet.sign(str(new_transaction))  #私钥签名
new_transaction.set_sign(sig, node1.wallet.pubkey)#发送公钥,和签名,给验证者验证
node1.submit_transaction(new_transaction)    #广播交易

在这里插入图片描述node1.print_blockchain()

node2.print_blockchain()

在这里插入图片描述

node1.get_balance()
node2.get_balance()

在这里插入图片描述

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

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

相关文章

【Spring实战】05 CommandLineRunner

文章目录 1. 简介2. 用法1&#xff09;单个 CommandLineRunner2&#xff09;多个 CommandLineRunner 3. 优点4. 缺点总结 CommandLineRunner 是 Spring Boot 提供的一个接口&#xff0c;用于在 Spring Boot 应用程序启动后执行一些任务。通过实现 CommandLineRunner 接口&#…

目标追踪:使用ByteTrack进行目标检测和跟踪

BYTE算法是一种简单而有效的关联方法&#xff0c;通过关联几乎每个检测框而不仅仅是高分的检测框来跟踪对象。这篇博客的目标是介绍ByteTrack以及多目标跟踪&#xff08;MOT&#xff09;的技术。我们还将介绍在样本视频上使用ByteTrack跟踪运行YOLOv8目标检测。 多目标跟踪&…

【数据结构和算法】找到最高海拔

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…

2015年第四届数学建模国际赛小美赛C题科学能解决恐怖主义吗解题全过程文档及程序

2015年第四届数学建模国际赛小美赛 C题 科学能解决恐怖主义吗 原题再现&#xff1a; 为什么人们转向恐怖主义&#xff0c;特别是自杀性恐怖主义&#xff1f;主要原因是什么&#xff1f;这通常是大问题和小问题的结合&#xff0c;或者是一些人所说的“推拉”因素。更大的问题包…

Azure Machine Learning - Azure OpenAI GPT 3.5 Turbo 微调教程

本教程将引导你在Azure平台完成对 gpt-35-turbo-0613 模型的微调。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕&#xff0c;复旦机器人智能实验室成员&#xff0c;阿里云认证的资深架构师&…

【力扣题解】P226-翻转二叉树-Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【力扣题解】 文章目录 【力扣题解】P226-翻转二叉树-Java题解&#x1f30f;题目描述&#x1f4a1;题解&#x1f30f;总结…

Vue-Pinina基本教程

前言 官网地址&#xff1a;Pinia | The intuitive store for Vue.js (vuejs.org) 看以下内容&#xff0c;需要有vuex的基础&#xff0c;下面很多概念会直接省略&#xff0c;比如state、actions、getters用处含义等 1、什么是Pinina Pinia 是 Vue 的存储库&#xff0c;它允许您跨…

ZooKeeper Client API 安装及使用指北

下载 wget https://archive.apache.org/dist/zookeeper/zookeeper-3.5.4-beta/zookeeper-3.5.4-beta.tar.gz解压 tar -zxf zookeeper-3.5.4-beta.tar.gz安装 cd zookeeper-3.5.4-beta/src/c/ ./configure make sudo make install到 make 这一步大概率会出现报错&#xff1a;…

云计算1.0、云原生2.0、AI云计算3.0,是解除IT互联网人才35岁的危机之道?

互联网员工的“35岁”危机&#xff0c;算不上一个新鲜的话题。年轻人不断涌入大厂的同时&#xff0c;老员工的受挫与焦虑也在同步发生。 “员工35岁被裁”“高龄员工劝退”&#xff0c;论坛、新闻里一些案例&#xff0c;更是放大了互联网人的35岁危机感。处在上有老、下有小的…

如何进行块存储管理

目录 块存储概念 块存储&#xff08;云盘&#xff09;扩容 方式一&#xff1a;直接扩容现有云盘 方式二&#xff1a;创建一块新数据盘 方式三&#xff1a;在更换操作系统时&#xff0c;同时更换系统盘 块存储&#xff08;云盘&#xff09;变配 云盘变配操作步骤 块存储概…

创建maven项目后需要注意的事项

检查maven 检查Java Compiler 检查Project Structure

【Web】Ctfshow Thinkphp3.2.3代码审计(3)

web574 这题与web573的区别在于进find()前先进了where()处理 跟进where() 我们假设传个1&#xff0c;和id拼接 发现会进到is_string的判断里&#xff0c;让$options[where]array("_string">"1") 之后传入到find()&#xff0c;和web573一样也是以数组…