python区块链简单模拟【05】

news2025/2/7 19:49:10

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

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           #  服务器地址,本地电脑都设为localhost
        self.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  套接字sock
        sock.bind((self.host, self.port))                             #绑定主机,端口号到套接字sock
        NODE_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: # 若读取不到新的数据则退出
                break
            data.append(buf)
            if len(buf) < 1024:   # 若读取到的数据长度小于规定长度,说明数据读取完成,退出
                break
        t = 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' * DIFFICULTY
        return 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 = 1024
        if 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("接收完毕,接空")
                    break
                
                data.append(buf)
                if len(buf) < 1024:
                    print("太短了,完毕")
                    break
            sock.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 = 0
        for block in self.blockchain.blocks:
            for t in block.transactions:
                if t.sender == self.wallet.address.decode():
                    balance -= t.amount
                elif t.recipient == self.wallet.address.decode():
                    balance += t.amount
        print("当前拥有%.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") 
# 初始化节点1

node1 = 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.coloradmin.cn/o/1336321.html

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

相关文章

目标检测-Two Stage-RCNN

文章目录 前言一、R-CNN的网络结构及步骤二、RCNN的创新点候选区域法特征提取-CNN网络 总结 前言 在前文&#xff1a;目标检测之序章-类别、必读论文和算法对比&#xff08;实时更新&#xff09;已经提到传统的目标检测算法的基本流程&#xff1a; 图像预处理 > 寻找候选区…

手术麻醉临床信息系统源码,客户端可以接入监护仪、麻醉机、呼吸机

一、手术麻醉临床信息管理系统介绍 1、手术麻醉临床信息管理系统是数字化手段应用于手术过程中的重要组成部分&#xff0c;用数字形式获取并存储手术相关信息&#xff0c;既便捷又高效。既然是管理系统&#xff0c;那就是一整套流程&#xff0c;管理患者手术、麻醉的申请、审批…

NVIDIA Jetson Nano 2GB 系列文章(9):调节 CSI 图像质量

NVIDIA英伟达中国 ​在本系列上一篇文章中&#xff0c;我们为大家展示了如何执行常见机器视觉应用。在本篇文章中&#xff0c;我们将带领大家调节 CSI 图像质量。 前面两篇文章在 Jetson Nano 2GB 上使用 CSI 摄像头做了几个实验&#xff0c;效果很不错&#xff0c;并且很容易…

分布式系统架构设计之分布式通信机制

二、分布式通信机制&#xff1a;保障系统正常运行基石 在分布式系统中&#xff0c;各个组件之间的通信是保障系统正常运行的基石&#xff0c;直接影响到系统的性能、可扩展性以及整体的可维护性。接下来我们就一起看看通信在分布式系统中的重要性&#xff0c;以及一些常用的技…

java八股 redis

Redis篇-01-redis开篇_哔哩哔哩_bilibili 1.缓存穿透 2.缓存击穿 逻辑过期里的互斥锁是为了保证只有一个线程去缓存重建 3.缓存雪崩 4.双写一致性 4.1要求一致性&#xff08;延迟双删/互斥锁&#xff09; 延迟双删无法保证强一致性 那么前两步删缓和更新数据库哪个先呢&#xf…

kubernetes(k8s) Yaml 文件详解

YAML格式&#xff1a;用于配置和管理&#xff0c;YAML是一种简洁的非标记性语言&#xff0c;内容格式人性化&#xff0c;较易读。 1、查看API 资源版本标签 kubectl api-versions 2、编写资源配置清单 kubectl create -f nginx-test.yaml --validatefalse 2.3 查看创建的po…

【Python可视化系列】一文教会你绘制美观的热力图(理论+源码)

一、问题 前文相关回顾&#xff1a; 【Python可视化系列】一文彻底教会你绘制美观的折线图&#xff08;理论源码&#xff09; 【Python可视化系列】一文教会你绘制美观的柱状图&#xff08;理论源码&#xff09; 【Python可视化系列】一文教会你绘制美观的直方图&#xff08;理…

docker部署kafka zookeeper模式集群

单机模式链接&#xff1a;https://blog.csdn.net/wsdhla/article/details/133032238 kraft集群模式链接&#xff1a;部署Kafka_kafka 部署-CSDN博客 zookeeper选举机制举例&#xff1a; 目前有5台服务器&#xff0c;每台服务器均没有数据&#xff0c;它们的编号分别是1,2,3,4,5…

鸿蒙开发(二)- 鸿蒙DevEco开发环境搭建

上篇说到&#xff0c;鸿蒙开发目前势头旺盛&#xff0c;头部大厂正在如火如荼地进行着&#xff0c;华为也对外宣称已经跟多个厂商达成合作。目前看来&#xff0c;对于前端或客户端开发人员来说&#xff0c;掌握下鸿蒙开发还是有些必要性的。如果你之前是从事Android开发的&…

【计算机网络】—— 奈氏准则和香农定理

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 失真 - 信号的变化 ​编辑影像失真的因素&#xff1a; ​编辑信道带宽&#xff1a; 码间串扰…

通过 Bytebase API 做数据库 Schema 变更

Bytebase 是一款数据库 DevOps 和 CI/CD 工具&#xff0c;适用于开发人员、DBA 和平台工程团队。 它提供了一个直观的图形用户界面来管理数据库 Schema 变更。另一方面&#xff0c;一些团队可能希望将 Bytebase 集成到现有的内部 DevOps 研发平台中。这需要调用 Bytebase API。…

内存管理--bss data txt数据段与stm32的ZI-data RW-data RO-data Code数据段的关系

目录 前沿 1 数据在内存中的位置 1.1 堆栈在内存中的位置 1.2 全局变量和局部变量在内存中的位置 1.2.1 全局变量在内存中的位置 1.2.2 局部变量在内存中的位置 1.3 static变量在内存中的位置 1.4 malloc赋值的变量存放在内存中的位置 1.5 代码在内存中的位置 2 ZI-d…

udp广播的例子

以下是一个使用C语言描述广播发送和接收的简单示例&#xff1a; 发送端&#xff08;广播发送&#xff09;&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #inclu…

如何使用Docker将.Net6项目部署到Linux服务器(二)

目录 二 安装Redis 2.1 基本安装 2.1.1 下载Redis 2.1.2 解压并安装Redis 2.1.3 编译Redis 2.1.3 配置config文件 2.1.4 配置redis服务 2.1.5 关闭redis服务 2.2 Docker安装 2.2.1 拉取镜像 2.2.2 查看镜像 2.2.2 创建挂载目录 2.2.3 创建配置文件 2.2.4 创建容器…

几种串口扩展电路

一、IIC串口扩展电路 LCT200 是一款可以通过 I2C 接口通讯&#xff0c;拓展 2 路独立串口的通讯芯片&#xff0c;同时也支持通过 2 路串口读写 I2C 接口的数据。LCT200 的封装为 TSSOP-20。 主要功能&#xff1a;⚫ 通过对 I2C 接口读写实现拓展 2 路独立串口功能 ⚫ 通过读写…

Linux学习教程(第十八章 SELinux管理)

第十八章 SELinux管理 root 用户实在是一个超人&#xff0c;它在 Linux 系统当中就是无所不能的&#xff0c;而且读、写和执行权限对 root 用户完全没有作用。root 用户的存在极大地方便了 Linux 的管理&#xff0c;但是也造成了一定的安全隐患。 大家想象一下&#xff0c;如果…

LabVIEW与PID在温度测控系统中的应用

LabVIEW与PID在温度测控系统中的应用 本案例介绍LabVIEW在温度控制系统中的应用&#xff0c;特别是结合PID算法。项目使用abVIEW作为主要开发工具&#xff0c;配合NI PCI-7831R数据采集和控制设备&#xff0c;实现了高效的温度调节。 系统的核心在于LabVIEW的FPGA模块&#x…

编译opencv和opencv_contrib

1 下载源码 下载opencv源码https://github.com/opencv/opencv 下载opencv源码https://github.com/opencv/opencv_contrib 2 开始编译 构建需要下载ffmpeg的包&#xff0c;cmake构建时会自动下载&#xff0c;但是比较满&#xff0c;这里可以从下面链接直接下载 https://downloa…

怎么判断台灯是否护眼?分享适合考研使用的护眼台灯

虽然台灯是家家户户都会有的一盏照明设备&#xff0c;但是很多人并不是了解自家台灯是好是坏&#xff0c;能不能护眼等等。其实台灯是非常有讲究的&#xff0c;如果长期使用一些不合格、劣质的台灯&#xff0c;会让我们在不知不觉中造成视力损伤&#xff0c;从而导致近视。 也…

中后缀表达式

一、利用后缀表达式进行计算 1&#xff09;解题思路 如果当前字符串是操作数&#xff0c;就将该操作数入栈&#xff1b;如果当前字符串是操作符&#xff0c;就取栈顶的两个操作数进行运算&#xff08;注意&#xff1a;第一个出栈的数为计算时的右操作数&#xff1b;第二个出栈…