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

news2024/9/24 11:32:24

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

一、区块与区块链结构

Block.py

import hashlib
from datetime import datetime


class Block:
    """
        区块链结构:
            prev_hash:      父区块哈希值
            data:           区块内容
            timestamp:      区块创建时间
            hash:           区块哈希值
    """
    def __init__(self, data, prev_hash):
        # 将传入的父区块哈希值和数据保存到变量中
        self.prev_hash = prev_hash
        self.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 Block


class 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 time


class Block:
    """
        区块链结构:
            prev_hash:      父区块哈希值
            data:           区块内容
            timestamp:      区块创建时间
            hash:           区块哈希值
            nonce:          随机数
    """
    def __init__(self, data, prev_hash):
        # 将传入的父区块哈希值和数据保存到变量中
        self.prev_hash = prev_hash
        self.data = data

        # 获得当前的时间
        self.timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

        # 设置随机数、哈希初始值为 None
        self.nonce = None
        self.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 = difficult

    def mine(self):
        """
        挖矿函数
        :return:
        """
        i = 0
        prefix = '0' * self.difficulty

        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.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 = digest
                return self.block
            i += 1

    def 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.difficulty
        return 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, ProofOfWork


class 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, VerifyingKey


class Wallet:
    """
        钱包
    """

    def __init__(self):
        """
            钱包初始化时基于椭圆曲线生成一个唯一的秘钥对,代表区块链上一个唯一的账户
        """
        # 生成私钥
        self._private_key = SigningKey.generate(curve=SECP256k1)
        # 基于私钥生成公钥
        self._public_key = self._private_key.get_verifying_key()

    @property
    def address(self):
        """
            这里通过公钥生成地址
        """
        h = sha256(self._public_key.to_pem())
        # 地址先由公钥进行哈希算法,再进行 Base64 计算而成
        return base64.b64encode(h.digest())

    @property
    def 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 json


class Transaction:
    """
        交易的结构
    """

    def __init__(self, sender, recipient, amount):
        """
            初始化交易,设置交易的发送方、接收方和交易数量
        """
        # 交易发送者的公钥
        self.pubkey = None
        # 交易的数字签名
        self.signature = None

        if 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 s


class 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, TransactionEncoder


class 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和哈希的初始值为None
        self.nonce = None
        self.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 = block
        self.miner = miner

        # 定义工作量难度,默认为5,表示有效的哈希值以5个“0”开头
        self.difficulty = difficult

        # 添加挖矿奖励
        self.reward_amount = 1

    def mine(self):
        """
            挖矿函数
        """
        i = 0
        prefix = '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 = i
                self.block.hash = digest
                return self.block
            i += 1

    def 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.difficulty
        return digest.startswith(prefix)

更新 BlockChain.py

from Block import Block, ProofOfWork
from Transaction import Transaction
from Wallet import Wallet, verify_sign


class 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 = 0
            print(f"区块链高度为:{height}")
            print(f"父区块为:{block.prev_hash}")
            print(f"区块内容为:{block.transactions}")
            print(f"区块哈希值为:{block.hash}")
            height += 1
            print()

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

# 传入用户和区块链,返回用户的“余额”
def get_balance(user, blockchain):
    balance = 0
    for block in blockchain.blocks:
        for t in block.transactions:
            if t.sender == user.address.decode():
                balance -= t.amount
            elif t.recipient == user.address.decode():
                balance += t.amount
    return 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.coloradmin.cn/o/1248467.html

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

相关文章

智能头盔天眼摄像头、单兵执法记录仪等配合MESH自组网在应急指挥调度中的应用

智能头盔、天眼摄像头、头盔记录仪、头盔摄像头、单兵执法记录仪等配合MESH自组网在应急指挥调度中的应用。 20人背负单兵自组网(带手咪)到训练场,戴头盔,头盔上放头盔式摄像头,大功率自组网设置在制高点,…

改进YOLOv8 | YOLOv5系列:RFAConv续作,即插即用具有任意采样形状和任意数目参数的卷积核AKCOnv

RFAConv续作,构建具有任意采样形状的卷积AKConv 一、论文yolov5加入的方式论文 源代码 一、论文 基于卷积运算的神经网络在深度学习领域取得了显著的成果,但标准卷积运算存在两个固有缺陷:一方面,卷积运算被限制在一个局部窗口,不能从其他位置捕获信息,并且其采样形状是…

五种多目标优化算法(MOJS、NSGA3、MOGWO、NSWOA、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 (1)多目标水母搜索算法MOJS 多目标优化算法:多目标水母搜索算法MOJS(提供MATLAB代码)_水母算法-CSDN博客 (2)NSGA3 NSGA-III求解微电网多目标优化调度(M…

c语言数字转圈

数字转圈 题干输入整数 N(1≤N≤9),输出如下 N 阶方阵。 若输入5显示如下方阵: * 1** 2** 3** 4** 5* *16**17**18**19** 6* *15**24**25**20** 7* *14**23**22**21** 8* *13**12**11**10** 9*输入样例3输出样例* 1*…

腾讯云云服务器旗舰新品SA5重磅首发

近日,腾讯云云服务器CVM再升级,极具性价比的云服务器旗舰新机型SA5重磅发布,搭载第四代AMD EPYC处理器(Bergamo), 相比云服务器SA3实例,整机性能最大提升120%以上。 温馨提醒:购买腾…

【Java 进阶篇】Jedis 操作 String:Redis中的基础数据类型

在Redis中,String是最基础的数据类型之一,而Jedis作为Java开发者与Redis交互的利器,提供了丰富的API来操作String。本文将深入介绍Jedis如何操作Redis中的String类型数据,通过生动的代码示例和详细的解释,让你轻松掌握…

基于白鲸算法优化概率神经网络PNN的分类预测 - 附代码

基于白鲸算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于白鲸算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于白鲸优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要:针对PNN神经网络的光滑…

【电子通识】什么是物料清单BOM(Bill of Material))

BOM (Bill of Materials)是我们常说的物料清单。BOM是制造业管理的重点之一,用于记载产品组成所需要的全部物料(Items)。物料需求的计算是从最终产品开始,层层往下推算出部件,组件,零件和原材料的需求量。这…

MindStudio学习一 整体介绍

一场景介绍 二 安装介绍 1.LINUX 采用无昇腾硬件采用linux 分部署 2.WINDOWS 3.linux下安装整体步骤 3.1安装依赖 3.2 安装步骤 1.gcc cmake 等依赖 2.python3.7.5 3.pip 安装依赖 4.安装JDK 5.安装 Ascend-cann-toolkit 6.解压安装Mindstudio 7.进入bin路径 ./…

Cortex-M与RISC-V区别

环境 Cortex-M以STM32H750为代表,RISC-V以芯来为代表 RTOS版本为RT-Thread 4.1.1 寄存器 RISC-V 常用汇编 RISC-V 关于STORE x4, 4(sp)这种寄存器前面带数字的写法,其意思为将x4的值存入sp4这个地址,即前面的数字表示偏移的意思 反之LOA…

基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码

基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于广义正态分布算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于广义正态分布优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xf…

【LM358AD运放方波振荡器可控输出幅值】2022-2-25

缘由仿真如何缩小方波振荡电路方波幅值?-有问必答-CSDN问答

再生式收音机踩坑记

下载《A Simple Regen Radio for Beginners》这篇文章也有好几年了,一直没有动手,上周末抽空做了一个,结果相当令人沮丧,一个台也收不到,用示波器测量三极管振荡波形,只有在调节再生电位器R2过程中&#xf…

构造命题公式的真值表

构造命题公式的真值表 1:实验类型:验证性2:实验目的:3:逻辑联结词的定义方法4:命题公式的表示方法5:【实验内容】 1:实验类型:验证性 2:实验目的&#xff1a…

C语言——从终端(键盘)将 5 个整数输入到数组 a 中,然后将 a 逆序复制到数组 b 中,并输出 b 中 各元素的值。

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int i;int a[5];int b[5];printf("输入5个整数&#xff1a;\n");for(i0;i<5;i){scanf("%d",&a[i]);}printf("数组b的元素值为&#xff1a;\n");for(i4;i>0;i--…

[原创](免改BIOS)使用Clover升级旧电脑-(高阶玩法)让固态硬盘内置Win11 PE启动系统

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XXQQ: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、Delphi…

[工业自动化-25]:IDEC和泉RU2S-24D/RU4S-24D继电器的使用说明和接线方式

目录 一、外观 1.1 继电器整体&#xff1a; 1.2 继电器主体&#xff1a; 1.3 底座&#xff1a; 二、RU系列通用继电器介绍 2.1 总体 2.2 性能规格 2.3 锁存杆 2.4 信号定义与连线 - 2S系列 &#xff08;1&#xff09;24V输入 &#xff08;2&#xff09;第一路输出 …

系统优化软件Bitsum Process Lasso Pro v12.4,供大家学习研究参考

1、自动或手动调整进程优先级;将不需要抑制的进程添加到排除列表; 2、设置动态提升前台运行的进程/线程的优先级 3、设置进程黑名单,禁止无用进程(机制为启动即结束,而非拦截其启动)。 4、优化I/O优先级以及电源模式自动化。 5、ProBalance功能。翻译成中文是“进程平衡…

【TypeScript】常见数据结构与算法(二):链表

文章目录 链表结构&#xff08;LinkedList&#xff09;链表以及数组的缺点数组链表的优势 什么是链表?封装链表相关方法源码链表常见面试题237-删除链表中的节点206 - 反转链表 数组和链表的复杂度对比 链表结构&#xff08;LinkedList&#xff09; 链表以及数组的缺点 链表…

跳转应用市场详情页market

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、概览三、跳转到各大厂商应…