区块链入门项目

1、代码

文件名称:blockchain.py

"""
{
 一个块有序号
 有时间戳

 交易记录
 工作量证明
 上一个区块的hash值
    "index":0,
    "timestampe":"",
    "transactions":[
        {
        "sender":'',#发送者
        "recipient":'',#接受者
        "amount":5,#金额
         }],
    "proof":'',
    "previous_hash":'',
}
"""
import hashlib
from argparse import ArgumentParser
from time import time

import json
from urllib.parse import urlparse
from uuid import uuid4

import requests
from flask import Flask, jsonify, request


class Blockchain:
    def __init__(self):
        self.chain=[]#每个元素就是一个区块
        self.current_tansactions=[]#每个元素就是一个交易实体
        #创世纪区块
        self.new_block(proof=100,previous_hash=1)
        #节点
        self.nodes=set()#set是集合

    def register_node(self,address:str):#注册节点
        parsed_url=urlparse(address)#节点地址,URLPARse是地址解析
        self.nodes.add(parsed_url.netloc)#添加到node,只取netloc
    @property#属性
    def last_bock(self):#获取最后一块
        return self.chain[-1]
    
    def new_block(self,proof,previous_hash=None):#新加一个快
        block={
            'index':len(self.chain)+1,
            'timestamp':time(),
            'transcations':self.current_tansactions,
            'proof':proof,
            'previous_hash':previous_hash or self.hash(self.chain[-1])

        }
        #因为交易已经打包成区块,所以,就要把交易值清空
        self.current_tansactions=[]
        self.chain.append(block)#在链条里面加入新区块
        return block


    def new_transaction(self,sender,recipient,amount)->int:#新交易
        #->一般出现在定义函数后面,为函数增加元数据,描述函数的返回类型
        #交易包含发送/接受/金额
        self.current_tansactions.append(
            {#获取一个json数据
                'sender':sender,
                'recipient':recipient,
                'amount':amount
            }
        )
        return self.last_bock['index']+1

    @staticmethod#静态方法
    def hash(block):
        #block是一个json,我们需要对block进行改造
        block_string=json.dumps(block,sort_keys=True).encode()#字符排序
        return hashlib.sha256(block_string).hexdigest()



    def proof_of_work(self,last_proof:int)->int:#这个last_proof需要传参,也就是
        #挖矿时候的,可以尝试的随机值
        #产生一个工作量证明的值
        proof=0
        while self.valid_proof(last_proof,proof) is False:#valid_proof是不断去验证是否满足
            #是否满足四个0开头的工作量
            proof+=1
        #print(proof)
        return proof
    def valid_proof(self,last_proof:int,proof:int)->bool:
        guess=f'{last_proof}{proof}'.encode()#用这两个值去生成hash值
        guess_hash=hashlib.sha256(guess).hexdigest()
        #print(guess_hash)
        if guess_hash[0:4]=='0000':#直到这个hash值满足条件:四个0开头
            return True
        else:
            return False

    #共识机制,是解决冲突的方法
    def resolve_conflicts(self)->bool:
        neighbours=self.nodes#nodes information
        max_length=len(self.chain)#自身的链条长度
        new_chain=None
        for node in neighbours:#遍历链条,看哪条链条最长
            response=requests.get(f'http://{node}/chain')#在路由chain,就可以获取chain和length
            if response.status_code==200:
                length=response.json()['length']
                chain=response.json()['chain']
                if length>max_length  and self.valid_chain(chain):
                    max_length=length#如果链条更长,就选择
                    #还要判断链条是否是有效链条,在valid_chain
                    new_chain=chain#换成新链条
        if new_chain:
            self.chain=new_chain
            return True
        return False

    def valid_chain(self,chain)->bool:
        last_block=chain[0]
        current_index=1#
        while current_index<len(chain):#遍历链条,依次去计算hash
            block=chain[current_index]
            if block['previous_hash']!=self.hash(last_block):#hash验证
                return False#验证失败,返回false
            if not self.valid_proof(last_block['proof'],block['proof']):
                return False
                #工作量证明是四个0开头如果不满足,也是假的
            last_block=block
            current_index +=1
        return True



# #检验hash
# test = Blockchain()
# test.proof_of_work(100)


#利用这个server,与其他用户节点进行交互,不然就是只做好了一个块
#用flask映射webserver
app=Flask(__name__)
blockchain=Blockchain()
#
node_identifier=str(uuid4()).replace('-','')
#实例化区块链
#映射到某个函数
@app.route('/index',methods=['GET'])
def index():
    return "hello BlockChain"

#新交易,交易的地址/金额返回
@app.route('/transactions/new',methods=['POST'])
def new_transaction():
    values=request.get_json()#需要获取一个客户传递过来的表单信息
    if values==None:#如果用户没有传参
        return 'missing values',400
    required=["sender",'recipient','amount']#检查三个字段
    if not all(k in values for k in required):#如果有字段没有在其中,就是错误的
        return "missing values",400
    #用传送过来的三个信息,建立一个新的交易
    #把交易添加到当前交易的数组
    #返回的是一个index
    index =blockchain.new_transaction(values['sender'],
                                      values['recipient'],
                                      values['amount'])
    #提示用户我们添加一个交易
    # 交易完成之后,需要挖矿才能让链条变长
    response={'message':f'transation will be added to block{index}'}
    return jsonify(response),201


@app.route('/mine',methods=['GET'])
def mine():
    last_block=blockchain.last_bock
    last_proof=last_block['proof']
    #计算工作量证明
    proof=blockchain.proof_of_work(last_proof)
    #新的交易,是给挖矿者的
    blockchain.new_transaction(sender='0',
                               recipient=node_identifier,#这个节点地址是随机生成的
                               amount=1
                               )
    block=blockchain.new_block(proof,None)#hash值输入none,它会自己去计算那个hash值
    response={
        'message':'new block forged',
        'index':block['index'],
        'time':time(),
        'transactions':block['transcations'],
        'proof':block['proof'],
        'previous_hash':block['previous_hash']
    }
    return jsonify(response),200

@app.route('/chain',methods=['GET'])
def full_chain():
    #区块链信息
    #把当前的区块链信息返回给请求者
    response={
        'chain':blockchain.chain,
        'length':len(blockchain.chain)
    }
    #把json结构换成字符串
    return jsonify(response),200

#节点注册
@app.route('/nodes/register',methods=['POST'])
def register_nodes():
    #发送方需要发送一个信息,格式如下:
    # {
    #     "nodes": ["http://127.0.0.2:5000"]
    # }
    values=request.get_json()
    nodes=values.get('nodes')
    if nodes is None:
        return "error: please supply a valid list of nodes",400
    for node in nodes:
        blockchain.register_node(node)
    response={
        'message':'new nodes have been added',
        'total_nodes':list(blockchain.nodes)
    }
    return jsonify(response),201

#调用解决冲突的方法
@app.route('/nodes/resolve',methods=['GET'])
def consenseus():
    replaced=blockchain.resolve_conflicts()
    if replaced:
        response={
            'message':'our chain is replaced',
            'new_chain':blockchain.chain
        }
    else:
        response = {
            'message': 'our chain is authoritative',
            'chain': blockchain.chain
        }
    return jsonify(response),200

if __name__ =='__main__':
    #设置不同端口,到不同的节点,在终端利用代码运行:
    ##python blockchain.py -p 5001
    #就可以换到所需端口的节点
    parser=ArgumentParser()#解析命令行参数
    #让端口成为参数
    parser.add_argument('-p','--port',default=5000,type=int,help='port to listen to ')
    args=parser.parse_args()#解析
    port =args.port#拿到参数
    #映射到端口
    app.run(host='0.0.0.0',port=port)

2、运行环境

使用pycharm和anaconda进行开发
利用conda新建一个python3.6的虚拟环境
以下为需要特殊安装的包

conda create -n python36 python=3.6
pip install flask==0.12.2
pip install werkzeug ==0.16.0
pip install requests==2.18.4

3、测试工具

Postman,安装,直接下载安装包,解压缩即可
可以看其他安装教程,是一个tar.gz后缀的文件
直接点开postman:

在这里插入图片描述

点开workspace,如图,直接打开就行,在右边可以输入链接
在这里插入图片描述

4、运行python文件时,打开两个终端

在这里插入图片描述在这里插入图片描述

5、进行测试

输入如图所示的链接,进行测试
可以参考代码进行分析
在这里插入图片描述其中post传参值如下:
发送者,接受者的名字等可以自行更改
在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值